Skip to content

Commit

Permalink
Merge pull request #6106 from xyzmaker123/6100-total-bsq-supply
Browse files Browse the repository at this point in the history
Show changes in BSQ Supply over time
  • Loading branch information
ripcurlx authored May 10, 2022
2 parents 72b56a2 + 28332b9 commit cc252f6
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 5 deletions.
20 changes: 19 additions & 1 deletion core/src/main/java/bisq/core/dao/state/DaoStateService.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import bisq.core.dao.state.model.blockchain.TxOutputKey;
import bisq.core.dao.state.model.blockchain.TxOutputType;
import bisq.core.dao.state.model.blockchain.TxType;
import bisq.core.dao.state.model.governance.BsqSupplyChange;
import bisq.core.dao.state.model.governance.Cycle;
import bisq.core.dao.state.model.governance.DecryptedBallotsWithMerits;
import bisq.core.dao.state.model.governance.EvaluatedProposal;
Expand All @@ -44,6 +45,7 @@
import javax.inject.Inject;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;
Expand Down Expand Up @@ -616,8 +618,12 @@ public void addIssuance(Issuance issuance) {
daoState.getIssuanceMap().put(issuance.getTxId(), issuance);
}

public Collection<Issuance> getIssuanceItems() {
return daoState.getIssuanceMap().values();
}

public Set<Issuance> getIssuanceSetForType(IssuanceType issuanceType) {
return daoState.getIssuanceMap().values().stream()
return getIssuanceItems().stream()
.filter(issuance -> issuance.getIssuanceType() == issuanceType)
.collect(Collectors.toSet());
}
Expand Down Expand Up @@ -1044,6 +1050,18 @@ public Set<TxOutput> getProofOfBurnOpReturnTxOutputs() {
return getTxOutputsByTxOutputType(TxOutputType.PROOF_OF_BURN_OP_RETURN_OUTPUT);
}

public Stream<BsqSupplyChange> getBsqSupplyChanges() {
Stream<BsqSupplyChange> issued = getIssuanceItems()
.stream()
.map(i -> new BsqSupplyChange(getBlockTime(i.getChainHeight()), i.getAmount()));

Stream<BsqSupplyChange> burned = getUnorderedTxStream()
.filter(tx -> tx.getTxType() == TxType.PROOF_OF_BURN || tx.getTxType() == TxType.PAY_TRADE_FEE)
.map(i -> new BsqSupplyChange(i.getTime(), -i.getBurntBsq()));

return Stream.concat(issued, burned);
}


///////////////////////////////////////////////////////////////////////////////////////////
// Listeners
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.core.dao.state.model.governance;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
public class BsqSupplyChange {
@Getter
long time;

@Getter
long value;
}
1 change: 1 addition & 0 deletions core/src/main/resources/i18n/displayStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2600,6 +2600,7 @@ dao.factsAndFigures.supply.compRequestIssueAmount=BSQ issued for compensation re
dao.factsAndFigures.supply.reimbursementAmount=BSQ issued for reimbursement requests
dao.factsAndFigures.supply.totalIssued=Total issued BSQ
dao.factsAndFigures.supply.totalBurned=Total burned BSQ
dao.factsAndFigures.supply.totalBsqSupply=Total BSQ supply
dao.factsAndFigures.supply.chart.tradeFee.toolTip={0}\n{1}
dao.factsAndFigures.supply.burnt=BSQ burnt

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.time.Instant;
import java.time.temporal.TemporalAdjuster;

import java.util.Comparator;
import java.util.Map;
import java.util.function.BinaryOperator;
import java.util.function.Predicate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public abstract class ChartView<T extends ChartViewModel<? extends ChartDataMode
private SplitPane timelineNavigation;
protected NumberAxis xAxis, yAxis;
protected LineChart<Number, Number> chart;
private HBox timelineLabels, legendBox2;
private HBox timelineLabels, legendBox2, legendBox3;
private final ToggleGroup timeIntervalToggleGroup = new ToggleGroup();

protected final Set<XYChart.Series<Number, Number>> activeSeries = new HashSet<>();
Expand Down Expand Up @@ -157,6 +157,11 @@ public void initialize() {
legendBox2 = initLegendsAndGetLegendBox(seriesForLegend2);
}

Collection<XYChart.Series<Number, Number>> seriesForLegend3 = getSeriesForLegend3();
if (seriesForLegend3 != null && !seriesForLegend3.isEmpty()) {
legendBox3 = initLegendsAndGetLegendBox(seriesForLegend3);
}

// Set active series/legends
defineAndAddActiveSeries();

Expand All @@ -176,6 +181,9 @@ public void initialize() {
if (legendBox2 != null) {
VBox.setMargin(legendBox2, new Insets(-20, rightPadding, 0, paddingLeft));
}
if (legendBox3 != null) {
VBox.setMargin(legendBox3, new Insets(-20, rightPadding, 0, paddingLeft));
}

if (model.getDividerPositions()[0] == 0 && model.getDividerPositions()[1] == 1) {
resetTimeNavigation();
Expand All @@ -192,6 +200,10 @@ public void initialize() {
VBox.setMargin(legendBox2, new Insets(-20, paddingRight, 0, paddingLeft));
timelineNavigationBox.getChildren().add(legendBox2);
}
if (legendBox3 != null) {
VBox.setMargin(legendBox3, new Insets(-20, paddingRight, 0, paddingLeft));
timelineNavigationBox.getChildren().add(legendBox3);
}
root.getChildren().addAll(timeIntervalBox, chart, timelineNavigationBox);

// Listeners
Expand Down Expand Up @@ -241,6 +253,7 @@ public void activate() {

addLegendToggleActionHandlers(getSeriesForLegend1());
addLegendToggleActionHandlers(getSeriesForLegend2());
addLegendToggleActionHandlers(getSeriesForLegend3());
addActionHandlersToDividers();
}

Expand All @@ -258,6 +271,7 @@ public void deactivate() {

removeLegendToggleActionHandlers(getSeriesForLegend1());
removeLegendToggleActionHandlers(getSeriesForLegend2());
removeLegendToggleActionHandlers(getSeriesForLegend3());
removeActionHandlersToDividers();

// clear data, reset states. We keep timeInterval state though
Expand Down Expand Up @@ -541,6 +555,10 @@ protected Collection<XYChart.Series<Number, Number>> getSeriesForLegend2() {
return null;
}

protected Collection<XYChart.Series<Number, Number>> getSeriesForLegend3() {
return null;
}

protected abstract void defineAndAddActiveSeries();

protected void activateSeries(XYChart.Series<Number, Number> series) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.blockchain.Tx;
import bisq.core.dao.state.model.governance.BsqSupplyChange;
import bisq.core.dao.state.model.governance.Issuance;
import bisq.core.dao.state.model.governance.IssuanceType;

Expand All @@ -30,13 +31,16 @@
import java.time.Instant;

import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import lombok.extern.slf4j.Slf4j;

Expand All @@ -45,7 +49,7 @@
public class DaoChartDataModel extends ChartDataModel {
private final DaoStateService daoStateService;
private final Function<Issuance, Long> blockTimeOfIssuanceFunction;
private Map<Long, Long> totalIssuedByInterval, compensationByInterval, reimbursementByInterval,
private Map<Long, Long> totalSupplyByInterval, totalIssuedByInterval, compensationByInterval, reimbursementByInterval,
totalBurnedByInterval, bsqTradeFeeByInterval, proofOfBurnByInterval;


Expand All @@ -68,6 +72,7 @@ public DaoChartDataModel(DaoStateService daoStateService) {

@Override
protected void invalidateCache() {
totalSupplyByInterval = null;
totalIssuedByInterval = null;
compensationByInterval = null;
reimbursementByInterval = null;
Expand Down Expand Up @@ -111,6 +116,19 @@ long getProofOfBurnAmount() {
// Data for chart
///////////////////////////////////////////////////////////////////////////////////////////

Map<Long, Long> getTotalSupplyByInterval() {
if (totalSupplyByInterval != null) {
return totalSupplyByInterval;
}

totalSupplyByInterval = getTotalBsqSupplyByInterval(
daoStateService.getBsqSupplyChanges(),
getDateFilter()
);

return totalSupplyByInterval;
}

Map<Long, Long> getTotalIssuedByInterval() {
if (totalIssuedByInterval != null) {
return totalIssuedByInterval;
Expand Down Expand Up @@ -179,6 +197,29 @@ Map<Long, Long> getProofOfBurnByInterval() {
// Aggregated collection data by interval
///////////////////////////////////////////////////////////////////////////////////////////

private Map<Long, Long> getTotalBsqSupplyByInterval(Stream<BsqSupplyChange> bsqSupplyChanges, Predicate<Long> dateFilter) {
AtomicLong supply = new AtomicLong(
DaoEconomyHistoricalData.TOTAL_SUPPLY_BY_CYCLE_DATE.get(1555340856L)
);

return bsqSupplyChanges
.collect(Collectors.groupingBy(tx -> toTimeInterval(Instant.ofEpochMilli(tx.getTime()))))
.entrySet()
.stream()
.sorted(Comparator.comparingLong(Map.Entry::getKey))
.map(e -> new BsqSupplyChange(
e.getKey(),
supply.addAndGet(e
.getValue()
.stream()
.mapToLong(BsqSupplyChange::getValue)
.sum()
))
)
.filter(t -> dateFilter.test(t.getTime()))
.collect(Collectors.toMap(BsqSupplyChange::getTime, BsqSupplyChange::getValue));
}

private Map<Long, Long> getIssuedBsqByInterval(Set<Issuance> issuanceSet, Predicate<Long> dateFilter) {
return issuanceSet.stream()
.collect(Collectors.groupingBy(issuance ->
Expand All @@ -199,7 +240,7 @@ private Map<Long, Long> getHistoricalIssuedBsqByInterval(Map<Long, Long> histori
.filter(e -> dateFilter.test(e.getKey()))
.collect(Collectors.toMap(e -> toTimeInterval(Instant.ofEpochSecond(e.getKey())),
Map.Entry::getValue,
(a, b) -> a + b));
Long::sum));
}

private Map<Long, Long> getBurntBsqByInterval(Collection<Tx> txs, Predicate<Long> dateFilter) {
Expand Down Expand Up @@ -236,6 +277,7 @@ private static class DaoEconomyHistoricalData {
// Key is start date of the cycle in epoch seconds, value is reimbursement amount
public final static Map<Long, Long> REIMBURSEMENTS_BY_CYCLE_DATE = new HashMap<>();
public final static Map<Long, Long> COMPENSATIONS_BY_CYCLE_DATE = new HashMap<>();
public final static Map<Long, Long> TOTAL_SUPPLY_BY_CYCLE_DATE = new HashMap<>();

static {
REIMBURSEMENTS_BY_CYCLE_DATE.put(1571349571L, 60760L);
Expand Down Expand Up @@ -271,6 +313,8 @@ private static class DaoEconomyHistoricalData {
COMPENSATIONS_BY_CYCLE_DATE.put(1599175867L, 6086442L);
COMPENSATIONS_BY_CYCLE_DATE.put(1601861442L, 5615973L);
COMPENSATIONS_BY_CYCLE_DATE.put(1604845863L, 7782667L);

TOTAL_SUPPLY_BY_CYCLE_DATE.put(1555340856L, 372540100L);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class DaoChartView extends ChartView<DaoChartViewModel> {
private final LongProperty proofOfBurnAmountProperty = new SimpleLongProperty();

private XYChart.Series<Number, Number> seriesBsqTradeFee, seriesProofOfBurn, seriesCompensation,
seriesReimbursement, seriesTotalIssued, seriesTotalBurned;
seriesReimbursement, seriesTotalSupply, seriesTotalIssued, seriesTotalBurned;


@Inject
Expand Down Expand Up @@ -90,6 +90,11 @@ protected Collection<XYChart.Series<Number, Number>> getSeriesForLegend2() {
return List.of(seriesTotalBurned, seriesBsqTradeFee, seriesProofOfBurn);
}

@Override
protected Collection<XYChart.Series<Number, Number>> getSeriesForLegend3() {
return List.of(seriesTotalSupply);
}


///////////////////////////////////////////////////////////////////////////////////////////
// Timeline navigation
Expand Down Expand Up @@ -130,6 +135,10 @@ protected void createSeries() {
seriesProofOfBurn = new XYChart.Series<>();
seriesProofOfBurn.setName(Res.get("dao.factsAndFigures.supply.proofOfBurn"));
seriesIndexMap.put(getSeriesId(seriesProofOfBurn), 5);

seriesTotalSupply = new XYChart.Series<>();
seriesTotalSupply.setName(Res.get("dao.factsAndFigures.supply.totalBsqSupply"));
seriesIndexMap.put(getSeriesId(seriesTotalSupply), 6);
}

@Override
Expand Down Expand Up @@ -176,6 +185,11 @@ protected CompletableFuture<Boolean> applyData() {
allFutures.add(task6Done);
applyProofOfBurn(task6Done);
}
if (activeSeries.contains(seriesTotalSupply)) {
CompletableFuture<Boolean> task6ADone = new CompletableFuture<>();
allFutures.add(task6ADone);
applyTotalSupply(task6ADone);
}

CompletableFuture<Boolean> task7Done = new CompletableFuture<>();
allFutures.add(task7Done);
Expand Down Expand Up @@ -216,6 +230,15 @@ protected CompletableFuture<Boolean> applyData() {
return CompletableFutureUtils.allOf(allFutures).thenApply(e -> true);
}

private void applyTotalSupply(CompletableFuture<Boolean> completeFuture) {
model.getTotalSupplyChartData()
.whenComplete((data, t) ->
mapToUserThread(() -> {
seriesTotalSupply.getData().setAll(data);
completeFuture.complete(true);
}));
}

private void applyTotalIssued(CompletableFuture<Boolean> completeFuture) {
model.getTotalIssuedChartData()
.whenComplete((data, t) ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ public DaoChartViewModel(DaoChartDataModel dataModel, BsqFormatter bsqFormatter)
// Chart data
///////////////////////////////////////////////////////////////////////////////////////////

CompletableFuture<List<XYChart.Data<Number, Number>>> getTotalSupplyChartData() {
return CompletableFuture.supplyAsync(() -> toChartData(dataModel.getTotalSupplyByInterval()));
}

CompletableFuture<List<XYChart.Data<Number, Number>>> getTotalIssuedChartData() {
return CompletableFuture.supplyAsync(() -> toChartData(dataModel.getTotalIssuedByInterval()));
}
Expand Down

0 comments on commit cc252f6

Please sign in to comment.