mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 01:41:11 +01:00
Add explorer endpoints and dtos
Signed-off-by: HenrikJannsen <boilingfrog@gmx.com>
This commit is contained in:
parent
9e0845e7f7
commit
bd9136fc97
261
restapi/src/main/java/bisq/restapi/DaoExplorerService.java
Normal file
261
restapi/src/main/java/bisq/restapi/DaoExplorerService.java
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi;
|
||||||
|
|
||||||
|
import bisq.core.dao.DaoFacade;
|
||||||
|
import bisq.core.dao.state.DaoStateListener;
|
||||||
|
import bisq.core.dao.state.DaoStateService;
|
||||||
|
import bisq.core.dao.state.model.blockchain.Block;
|
||||||
|
import bisq.core.dao.state.model.blockchain.PubKeyScript;
|
||||||
|
import bisq.core.dao.state.model.blockchain.Tx;
|
||||||
|
import bisq.core.dao.state.model.blockchain.TxOutput;
|
||||||
|
import bisq.core.dao.state.model.blockchain.TxOutputKey;
|
||||||
|
import bisq.core.dao.state.model.blockchain.TxType;
|
||||||
|
import bisq.core.provider.price.PriceFeedService;
|
||||||
|
|
||||||
|
import bisq.network.p2p.P2PService;
|
||||||
|
import bisq.network.p2p.P2PServiceListener;
|
||||||
|
|
||||||
|
import bisq.common.UserThread;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
import com.google.common.io.BaseEncoding;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import bisq.restapi.dto.JsonBlock;
|
||||||
|
import bisq.restapi.dto.JsonScriptPubKey;
|
||||||
|
import bisq.restapi.dto.JsonSpentInfo;
|
||||||
|
import bisq.restapi.dto.JsonTx;
|
||||||
|
import bisq.restapi.dto.JsonTxInput;
|
||||||
|
import bisq.restapi.dto.JsonTxOutput;
|
||||||
|
import bisq.restapi.dto.JsonTxOutputType;
|
||||||
|
import bisq.restapi.dto.JsonTxType;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Slf4j
|
||||||
|
public class DaoExplorerService {
|
||||||
|
private final DaoStateService daoStateService;
|
||||||
|
private final DaoFacade daoFacade;
|
||||||
|
private final DaoStateListener daoStateListener;
|
||||||
|
private final Map<String, Set<String>> txIdsByAddress = new HashMap<>();
|
||||||
|
@Setter
|
||||||
|
private int lastKnownBlockHeight = 0;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public DaoExplorerService(DaoStateService daoStateService,
|
||||||
|
DaoFacade daoFacade,
|
||||||
|
P2PService p2PService,
|
||||||
|
PriceFeedService priceFeedService) {
|
||||||
|
this.daoStateService = daoStateService;
|
||||||
|
this.daoFacade = daoFacade;
|
||||||
|
daoStateListener = new DaoStateListener() {
|
||||||
|
@Override
|
||||||
|
public void onParseBlockChainComplete() {
|
||||||
|
UserThread.execute(() -> updateTxIdsByAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDaoStateChanged(Block block) {
|
||||||
|
UserThread.execute(() -> updateTxIdsByAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
daoFacade.addBsqStateListener(daoStateListener);
|
||||||
|
|
||||||
|
p2PService.addP2PServiceListener(new P2PServiceListener() {
|
||||||
|
@Override
|
||||||
|
public void onDataReceived() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNoSeedNodeAvailable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNoPeersAvailable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpdatedDataReceived() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTorNodeReady() {
|
||||||
|
// We want to get early connected to the price relay so we call it already now
|
||||||
|
priceFeedService.setCurrencyCodeOnInit();
|
||||||
|
priceFeedService.initialRequestPriceFeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHiddenServicePublished() {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateTxIdsByAddress() {
|
||||||
|
Map<TxOutputKey, String> txIdByTxOutputKey = new HashMap<>();
|
||||||
|
txIdsByAddress.clear();
|
||||||
|
daoStateService.getUnorderedTxStream()
|
||||||
|
.forEach(tx -> {
|
||||||
|
tx.getTxOutputs().forEach(txOutput -> {
|
||||||
|
String address = txOutput.getAddress();
|
||||||
|
if (address != null && !address.isEmpty() && daoStateService.isBsqTxOutputType(txOutput)) {
|
||||||
|
Set<String> txIdSet = txIdsByAddress.getOrDefault(address, new HashSet<>());
|
||||||
|
String txId = tx.getId();
|
||||||
|
txIdSet.add(txId);
|
||||||
|
txIdsByAddress.put(address, txIdSet);
|
||||||
|
tx.getTxInputs().forEach(txInput -> {
|
||||||
|
txIdByTxOutputKey.put(txInput.getConnectedTxOutputKey(), txId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
log.info("txIdByTxOutputKey {}", txIdByTxOutputKey.size());
|
||||||
|
// todo check if needed
|
||||||
|
daoStateService.getUnorderedTxOutputStream()
|
||||||
|
.filter(daoStateService::isBsqTxOutputType)
|
||||||
|
.filter(txOutput -> Objects.nonNull(txOutput.getAddress()))
|
||||||
|
.forEach(txOutput -> {
|
||||||
|
String txId = txIdByTxOutputKey.get(txOutput.getKey());
|
||||||
|
if (txId != null) {
|
||||||
|
String address = txOutput.getAddress();
|
||||||
|
Set<String> txIdSet = txIdsByAddress.getOrDefault(address, new HashSet<>());
|
||||||
|
txIdSet.add(txId);
|
||||||
|
txIdsByAddress.put(address, txIdSet);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
log.info("result txIdByTxOutputKey {}", txIdByTxOutputKey.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonBlock getJsonBlock(Block block) {
|
||||||
|
List<JsonTx> jsonTxs = block.getTxs().stream()
|
||||||
|
.map(this::getJsonTx)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return new JsonBlock(block.getHeight(),
|
||||||
|
block.getTime(),
|
||||||
|
block.getHash(),
|
||||||
|
block.getPreviousBlockHash(),
|
||||||
|
jsonTxs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonTx getJsonTx(Tx tx) {
|
||||||
|
JsonTxType jsonTxType = getJsonTxType(tx);
|
||||||
|
String jsonTxTypeDisplayString = getJsonTxTypeDisplayString(jsonTxType);
|
||||||
|
return new JsonTx(tx.getId(),
|
||||||
|
tx.getBlockHeight(),
|
||||||
|
tx.getBlockHash(),
|
||||||
|
tx.getTime(),
|
||||||
|
getJsonTxInputs(tx),
|
||||||
|
getJsonTxOutputs(tx),
|
||||||
|
jsonTxType,
|
||||||
|
jsonTxTypeDisplayString,
|
||||||
|
tx.getBurntFee(),
|
||||||
|
tx.getInvalidatedBsq(),
|
||||||
|
tx.getUnlockBlockHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumAddresses() {
|
||||||
|
return txIdsByAddress.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<JsonTxInput> getJsonTxInputs(Tx tx) {
|
||||||
|
return tx.getTxInputs().stream()
|
||||||
|
.map(txInput -> {
|
||||||
|
Optional<TxOutput> optionalTxOutput = daoStateService.getConnectedTxOutput(txInput);
|
||||||
|
if (optionalTxOutput.isPresent()) {
|
||||||
|
TxOutput connectedTxOutput = optionalTxOutput.get();
|
||||||
|
boolean isBsqTxOutputType = daoStateService.isBsqTxOutputType(connectedTxOutput);
|
||||||
|
return new JsonTxInput(txInput.getConnectedTxOutputIndex(),
|
||||||
|
txInput.getConnectedTxOutputTxId(),
|
||||||
|
connectedTxOutput.getValue(),
|
||||||
|
isBsqTxOutputType,
|
||||||
|
connectedTxOutput.getAddress(),
|
||||||
|
tx.getTime());
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<JsonTxOutput> getJsonTxOutputs(Tx tx) {
|
||||||
|
JsonTxType jsonTxType = getJsonTxType(tx);
|
||||||
|
String jsonTxTypeDisplayString = getJsonTxTypeDisplayString(jsonTxType);
|
||||||
|
return tx.getTxOutputs().stream()
|
||||||
|
.map(txOutput -> {
|
||||||
|
boolean isBsqTxOutputType = daoStateService.isBsqTxOutputType(txOutput);
|
||||||
|
long bsqAmount = isBsqTxOutputType ? txOutput.getValue() : 0;
|
||||||
|
long btcAmount = !isBsqTxOutputType ? txOutput.getValue() : 0;
|
||||||
|
PubKeyScript pubKeyScript = txOutput.getPubKeyScript();
|
||||||
|
JsonScriptPubKey scriptPubKey = pubKeyScript != null ? new JsonScriptPubKey(pubKeyScript) : null;
|
||||||
|
JsonSpentInfo spentInfo = daoStateService.getSpentInfo(txOutput).map(JsonSpentInfo::new).orElse(null);
|
||||||
|
JsonTxOutputType txOutputType = JsonTxOutputType.valueOf(txOutput.getTxOutputType().name());
|
||||||
|
int lockTime = txOutput.getLockTime();
|
||||||
|
BaseEncoding HEX = BaseEncoding.base16().lowerCase();
|
||||||
|
String opReturn = txOutput.getOpReturnData() != null ? HEX.encode(txOutput.getOpReturnData()) : null;
|
||||||
|
boolean isUnspent = daoStateService.isUnspent(txOutput.getKey());
|
||||||
|
return new JsonTxOutput(tx.getId(),
|
||||||
|
txOutput.getIndex(),
|
||||||
|
bsqAmount,
|
||||||
|
btcAmount,
|
||||||
|
tx.getBlockHeight(),
|
||||||
|
isBsqTxOutputType,
|
||||||
|
tx.getBurntFee(),
|
||||||
|
tx.getInvalidatedBsq(),
|
||||||
|
txOutput.getAddress(),
|
||||||
|
scriptPubKey,
|
||||||
|
spentInfo,
|
||||||
|
tx.getTime(),
|
||||||
|
jsonTxType,
|
||||||
|
jsonTxTypeDisplayString,
|
||||||
|
txOutputType,
|
||||||
|
txOutputType.getDisplayString(),
|
||||||
|
opReturn,
|
||||||
|
lockTime,
|
||||||
|
isUnspent
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getJsonTxTypeDisplayString(JsonTxType jsonTxType) {
|
||||||
|
return jsonTxType != null ? jsonTxType.getDisplayString() : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonTxType getJsonTxType(Tx tx) {
|
||||||
|
TxType txType = tx.getTxType();
|
||||||
|
return txType != null ? JsonTxType.valueOf(txType.name()) : null;
|
||||||
|
}
|
||||||
|
}
|
@ -20,11 +20,16 @@ package bisq.restapi;
|
|||||||
|
|
||||||
import bisq.core.account.witness.AccountAgeWitnessService;
|
import bisq.core.account.witness.AccountAgeWitnessService;
|
||||||
import bisq.core.app.misc.ExecutableForAppWithP2p;
|
import bisq.core.app.misc.ExecutableForAppWithP2p;
|
||||||
|
import bisq.core.dao.DaoFacade;
|
||||||
import bisq.core.dao.SignVerifyService;
|
import bisq.core.dao.SignVerifyService;
|
||||||
import bisq.core.dao.governance.bond.reputation.BondedReputationRepository;
|
import bisq.core.dao.governance.bond.reputation.BondedReputationRepository;
|
||||||
import bisq.core.dao.governance.bond.role.BondedRolesRepository;
|
import bisq.core.dao.governance.bond.role.BondedRolesRepository;
|
||||||
|
import bisq.core.dao.governance.period.CycleService;
|
||||||
|
import bisq.core.dao.governance.proposal.ProposalService;
|
||||||
import bisq.core.dao.state.DaoStateService;
|
import bisq.core.dao.state.DaoStateService;
|
||||||
import bisq.core.dao.state.DaoStateSnapshotService;
|
import bisq.core.dao.state.DaoStateSnapshotService;
|
||||||
|
import bisq.core.offer.OfferBookService;
|
||||||
|
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||||
import bisq.core.user.Preferences;
|
import bisq.core.user.Preferences;
|
||||||
|
|
||||||
import bisq.common.app.Version;
|
import bisq.common.app.Version;
|
||||||
@ -47,6 +52,18 @@ public class RestApi extends ExecutableForAppWithP2p {
|
|||||||
private SignVerifyService signVerifyService;
|
private SignVerifyService signVerifyService;
|
||||||
private DaoStateSnapshotService daoStateSnapshotService;
|
private DaoStateSnapshotService daoStateSnapshotService;
|
||||||
private Preferences preferences;
|
private Preferences preferences;
|
||||||
|
@Getter
|
||||||
|
private DaoExplorerService daoExplorerService;
|
||||||
|
@Getter
|
||||||
|
private DaoFacade daoFacade;
|
||||||
|
@Getter
|
||||||
|
private ProposalService proposalService;
|
||||||
|
@Getter
|
||||||
|
private CycleService cycleService;
|
||||||
|
@Getter
|
||||||
|
private TradeStatisticsManager tradeStatisticsManager;
|
||||||
|
@Getter
|
||||||
|
private OfferBookService offerBookService;
|
||||||
|
|
||||||
public RestApi() {
|
public RestApi() {
|
||||||
super("Bisq Rest Api", "bisq_restapi", "bisq_restapi", Version.VERSION);
|
super("Bisq Rest Api", "bisq_restapi", "bisq_restapi", Version.VERSION);
|
||||||
@ -74,6 +91,12 @@ public class RestApi extends ExecutableForAppWithP2p {
|
|||||||
bondedRolesRepository = injector.getInstance(BondedRolesRepository.class);
|
bondedRolesRepository = injector.getInstance(BondedRolesRepository.class);
|
||||||
signVerifyService = injector.getInstance(SignVerifyService.class);
|
signVerifyService = injector.getInstance(SignVerifyService.class);
|
||||||
daoStateSnapshotService = injector.getInstance(DaoStateSnapshotService.class);
|
daoStateSnapshotService = injector.getInstance(DaoStateSnapshotService.class);
|
||||||
|
daoExplorerService = injector.getInstance(DaoExplorerService.class);
|
||||||
|
daoFacade = injector.getInstance(DaoFacade.class);
|
||||||
|
proposalService = injector.getInstance(ProposalService.class);
|
||||||
|
cycleService = injector.getInstance(CycleService.class);
|
||||||
|
tradeStatisticsManager = injector.getInstance(TradeStatisticsManager.class);
|
||||||
|
offerBookService = injector.getInstance(OfferBookService.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,6 +31,10 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import bisq.restapi.endpoints.AccountAgeApi;
|
import bisq.restapi.endpoints.AccountAgeApi;
|
||||||
import bisq.restapi.endpoints.BondedReputationApi;
|
import bisq.restapi.endpoints.BondedReputationApi;
|
||||||
import bisq.restapi.endpoints.BondedRoleVerificationApi;
|
import bisq.restapi.endpoints.BondedRoleVerificationApi;
|
||||||
|
import bisq.restapi.endpoints.ExplorerBlocksApi;
|
||||||
|
import bisq.restapi.endpoints.ExplorerDaoApi;
|
||||||
|
import bisq.restapi.endpoints.ExplorerMarketsApi;
|
||||||
|
import bisq.restapi.endpoints.ExplorerTransactionsApi;
|
||||||
import bisq.restapi.endpoints.ProofOfBurnApi;
|
import bisq.restapi.endpoints.ProofOfBurnApi;
|
||||||
import bisq.restapi.endpoints.SignedWitnessApi;
|
import bisq.restapi.endpoints.SignedWitnessApi;
|
||||||
import bisq.restapi.error.CustomExceptionMapper;
|
import bisq.restapi.error.CustomExceptionMapper;
|
||||||
@ -63,6 +67,10 @@ public class RestApiMain extends ResourceConfig {
|
|||||||
.register(BondedRoleVerificationApi.class)
|
.register(BondedRoleVerificationApi.class)
|
||||||
.register(AccountAgeApi.class)
|
.register(AccountAgeApi.class)
|
||||||
.register(SignedWitnessApi.class)
|
.register(SignedWitnessApi.class)
|
||||||
|
.register(ExplorerMarketsApi.class)
|
||||||
|
.register(ExplorerDaoApi.class)
|
||||||
|
.register(ExplorerBlocksApi.class)
|
||||||
|
.register(ExplorerTransactionsApi.class)
|
||||||
.register(SwaggerResolution.class);
|
.register(SwaggerResolution.class);
|
||||||
daoNodeApplication.startServer(config.daoNodeApiUrl, config.daoNodeApiPort);
|
daoNodeApplication.startServer(config.daoNodeApiUrl, config.daoNodeApiPort);
|
||||||
});
|
});
|
||||||
|
@ -19,7 +19,6 @@ package bisq.restapi.dto;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -30,7 +29,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||||||
* Need to be in sync with the Bisq 2 BondedReputationDto class.
|
* Need to be in sync with the Bisq 2 BondedReputationDto class.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@Slf4j
|
|
||||||
@ToString
|
@ToString
|
||||||
@Schema(title = "BondedReputation")
|
@Schema(title = "BondedReputation")
|
||||||
public class BondedReputationDto {
|
public class BondedReputationDto {
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
package bisq.restapi.dto;
|
package bisq.restapi.dto;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@ -30,6 +31,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||||||
* Need to be in sync with the Bisq 2 BondedRoleDto class.
|
* Need to be in sync with the Bisq 2 BondedRoleDto class.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
|
@ToString
|
||||||
@Schema(title = "BondedRoleVerification")
|
@Schema(title = "BondedRoleVerification")
|
||||||
public class BondedRoleVerificationDto {
|
public class BondedRoleVerificationDto {
|
||||||
@Nullable
|
@Nullable
|
||||||
|
14
restapi/src/main/java/bisq/restapi/dto/BsqStatsDto.java
Normal file
14
restapi/src/main/java/bisq/restapi/dto/BsqStatsDto.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package bisq.restapi.dto;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class BsqStatsDto {
|
||||||
|
long minted;
|
||||||
|
long burnt;
|
||||||
|
int addresses;
|
||||||
|
int unspent_txos;
|
||||||
|
int spent_txos;
|
||||||
|
int height;
|
||||||
|
int genesisHeight;
|
||||||
|
}
|
31
restapi/src/main/java/bisq/restapi/dto/JsonBlock.java
Normal file
31
restapi/src/main/java/bisq/restapi/dto/JsonBlock.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi.dto;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class JsonBlock {
|
||||||
|
int height;
|
||||||
|
long time; // in ms
|
||||||
|
String hash;
|
||||||
|
String previousBlockHash;
|
||||||
|
List<JsonTx> txs;
|
||||||
|
}
|
28
restapi/src/main/java/bisq/restapi/dto/JsonBlocks.java
Normal file
28
restapi/src/main/java/bisq/restapi/dto/JsonBlocks.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi.dto;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
class JsonBlocks {
|
||||||
|
int chainHeight;
|
||||||
|
List<JsonBlock> blocks;
|
||||||
|
}
|
28
restapi/src/main/java/bisq/restapi/dto/JsonCurrency.java
Normal file
28
restapi/src/main/java/bisq/restapi/dto/JsonCurrency.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi.dto;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class JsonCurrency {
|
||||||
|
String code;
|
||||||
|
String name;
|
||||||
|
int precision;
|
||||||
|
String _type; // "fiat" or "crypto"
|
||||||
|
}
|
31
restapi/src/main/java/bisq/restapi/dto/JsonDaoCycle.java
Normal file
31
restapi/src/main/java/bisq/restapi/dto/JsonDaoCycle.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi.dto;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class JsonDaoCycle {
|
||||||
|
int heightOfFirstBlock;
|
||||||
|
int cycleIndex;
|
||||||
|
long startDate; // in ms
|
||||||
|
int proposalCount;
|
||||||
|
long burnedAmount;
|
||||||
|
long issuedAmount;
|
||||||
|
Boolean inProgress;
|
||||||
|
}
|
29
restapi/src/main/java/bisq/restapi/dto/JsonOffer.java
Normal file
29
restapi/src/main/java/bisq/restapi/dto/JsonOffer.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package bisq.restapi.dto;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class JsonOffer {
|
||||||
|
String direction;
|
||||||
|
String currencyCode;
|
||||||
|
long minAmount;
|
||||||
|
long amount;
|
||||||
|
long price;
|
||||||
|
long date;
|
||||||
|
boolean useMarketBasedPrice;
|
||||||
|
double marketPriceMargin;
|
||||||
|
String paymentMethod;
|
||||||
|
String id;
|
||||||
|
String currencyPair;
|
||||||
|
String primaryMarketDirection;
|
||||||
|
String priceDisplayString;
|
||||||
|
String primaryMarketAmountDisplayString;
|
||||||
|
String primaryMarketMinAmountDisplayString;
|
||||||
|
String primaryMarketVolumeDisplayString;
|
||||||
|
String primaryMarketMinVolumeDisplayString;
|
||||||
|
long primaryMarketPrice;
|
||||||
|
long primaryMarketAmount;
|
||||||
|
long primaryMarketMinAmount;
|
||||||
|
long primaryMarketVolume;
|
||||||
|
long primaryMarketMinVolume;
|
||||||
|
}
|
43
restapi/src/main/java/bisq/restapi/dto/JsonScriptPubKey.java
Normal file
43
restapi/src/main/java/bisq/restapi/dto/JsonScriptPubKey.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi.dto;
|
||||||
|
|
||||||
|
import bisq.core.dao.state.model.blockchain.PubKeyScript;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Value
|
||||||
|
public class JsonScriptPubKey {
|
||||||
|
List<String> addresses;
|
||||||
|
String asm;
|
||||||
|
String hex;
|
||||||
|
int reqSigs;
|
||||||
|
String type;
|
||||||
|
|
||||||
|
public JsonScriptPubKey(PubKeyScript pubKeyScript) {
|
||||||
|
addresses = pubKeyScript.getAddresses();
|
||||||
|
asm = pubKeyScript.getAsm();
|
||||||
|
hex = pubKeyScript.getHex();
|
||||||
|
reqSigs = pubKeyScript.getReqSigs();
|
||||||
|
type = pubKeyScript.getScriptType().toString();
|
||||||
|
}
|
||||||
|
}
|
35
restapi/src/main/java/bisq/restapi/dto/JsonSpentInfo.java
Normal file
35
restapi/src/main/java/bisq/restapi/dto/JsonSpentInfo.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi.dto;
|
||||||
|
|
||||||
|
import bisq.core.dao.state.model.blockchain.SpentInfo;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class JsonSpentInfo {
|
||||||
|
long height;
|
||||||
|
int inputIndex;
|
||||||
|
String txId;
|
||||||
|
|
||||||
|
public JsonSpentInfo(SpentInfo spentInfo) {
|
||||||
|
height = spentInfo.getBlockHeight();
|
||||||
|
inputIndex = spentInfo.getInputIndex();
|
||||||
|
txId = spentInfo.getTxId();
|
||||||
|
}
|
||||||
|
}
|
34
restapi/src/main/java/bisq/restapi/dto/JsonTradeInfo.java
Normal file
34
restapi/src/main/java/bisq/restapi/dto/JsonTradeInfo.java
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi.dto;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
// equivalent of bisq.core.trade.statistics.TradeStatisticsForJson
|
||||||
|
@Value
|
||||||
|
public class JsonTradeInfo {
|
||||||
|
String currency;
|
||||||
|
long tradePrice;
|
||||||
|
long tradeAmount;
|
||||||
|
long tradeDate;
|
||||||
|
String paymentMethod;
|
||||||
|
String currencyPair;
|
||||||
|
long primaryMarketTradePrice;
|
||||||
|
long primaryMarketTradeAmount;
|
||||||
|
long primaryMarketTradeVolume;
|
||||||
|
}
|
86
restapi/src/main/java/bisq/restapi/dto/JsonTx.java
Normal file
86
restapi/src/main/java/bisq/restapi/dto/JsonTx.java
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi.dto;
|
||||||
|
|
||||||
|
import bisq.common.app.Version;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class JsonTx {
|
||||||
|
String txVersion = Version.BSQ_TX_VERSION;
|
||||||
|
String id;
|
||||||
|
int blockHeight;
|
||||||
|
String blockHash;
|
||||||
|
long time;
|
||||||
|
List<JsonTxInput> inputs;
|
||||||
|
List<JsonTxOutput> outputs;
|
||||||
|
JsonTxType txType;
|
||||||
|
String txTypeDisplayString;
|
||||||
|
long burntFee;
|
||||||
|
long invalidatedBsq;
|
||||||
|
// If not set it is -1. LockTime of 0 is a valid value.
|
||||||
|
int unlockBlockHeight;
|
||||||
|
|
||||||
|
public JsonTx(String id, int blockHeight, String blockHash, long time, List<JsonTxInput> inputs,
|
||||||
|
List<JsonTxOutput> outputs, JsonTxType txType, String txTypeDisplayString, long burntFee,
|
||||||
|
long invalidatedBsq, int unlockBlockHeight) {
|
||||||
|
this.id = id;
|
||||||
|
this.blockHeight = blockHeight;
|
||||||
|
this.blockHash = blockHash;
|
||||||
|
this.time = time;
|
||||||
|
this.inputs = inputs;
|
||||||
|
this.outputs = outputs;
|
||||||
|
this.txType = txType;
|
||||||
|
this.txTypeDisplayString = txTypeDisplayString;
|
||||||
|
this.burntFee = burntFee;
|
||||||
|
this.invalidatedBsq = invalidatedBsq;
|
||||||
|
this.unlockBlockHeight = unlockBlockHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enums must not be used directly for hashCode or equals as it delivers the Object.hashCode (internal address)!
|
||||||
|
// The equals and hashCode methods cannot be overwritten in Enums.
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof JsonTx)) return false;
|
||||||
|
if (!super.equals(o)) return false;
|
||||||
|
JsonTx jsonTx = (JsonTx) o;
|
||||||
|
return blockHeight == jsonTx.blockHeight &&
|
||||||
|
time == jsonTx.time &&
|
||||||
|
burntFee == jsonTx.burntFee &&
|
||||||
|
invalidatedBsq == jsonTx.invalidatedBsq &&
|
||||||
|
unlockBlockHeight == jsonTx.unlockBlockHeight &&
|
||||||
|
Objects.equals(txVersion, jsonTx.txVersion) &&
|
||||||
|
Objects.equals(id, jsonTx.id) &&
|
||||||
|
Objects.equals(blockHash, jsonTx.blockHash) &&
|
||||||
|
Objects.equals(inputs, jsonTx.inputs) &&
|
||||||
|
Objects.equals(outputs, jsonTx.outputs) &&
|
||||||
|
txType.name().equals(jsonTx.txType.name()) &&
|
||||||
|
Objects.equals(txTypeDisplayString, jsonTx.txTypeDisplayString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(super.hashCode(), txVersion, id, blockHeight, blockHash, time, inputs, outputs,
|
||||||
|
txType.name(), txTypeDisplayString, burntFee, invalidatedBsq, unlockBlockHeight);
|
||||||
|
}
|
||||||
|
}
|
33
restapi/src/main/java/bisq/restapi/dto/JsonTxInput.java
Normal file
33
restapi/src/main/java/bisq/restapi/dto/JsonTxInput.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi.dto;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
@Immutable
|
||||||
|
public class JsonTxInput {
|
||||||
|
int spendingTxOutputIndex; // connectedTxOutputIndex
|
||||||
|
String spendingTxId; // connectedTxOutputTxId
|
||||||
|
long bsqAmount;
|
||||||
|
Boolean isVerified; // isBsqTxOutputType
|
||||||
|
String address;
|
||||||
|
long time;
|
||||||
|
}
|
134
restapi/src/main/java/bisq/restapi/dto/JsonTxOutput.java
Normal file
134
restapi/src/main/java/bisq/restapi/dto/JsonTxOutput.java
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi.dto;
|
||||||
|
|
||||||
|
import bisq.common.app.Version;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class JsonTxOutput {
|
||||||
|
String txVersion = Version.BSQ_TX_VERSION;
|
||||||
|
String txId;
|
||||||
|
int index;
|
||||||
|
long bsqAmount;
|
||||||
|
long btcAmount;
|
||||||
|
int height;
|
||||||
|
Boolean isVerified; // isBsqTxOutputType
|
||||||
|
long burntFee;
|
||||||
|
long invalidatedBsq;
|
||||||
|
String address;
|
||||||
|
@Nullable
|
||||||
|
JsonScriptPubKey scriptPubKey;
|
||||||
|
@Nullable
|
||||||
|
JsonSpentInfo spentInfo;
|
||||||
|
long time;
|
||||||
|
JsonTxType txType;
|
||||||
|
String txTypeDisplayString;
|
||||||
|
JsonTxOutputType txOutputType;
|
||||||
|
String txOutputTypeDisplayString;
|
||||||
|
@Nullable
|
||||||
|
String opReturn;
|
||||||
|
int lockTime;
|
||||||
|
Boolean isUnspent;
|
||||||
|
|
||||||
|
public JsonTxOutput(String txId,
|
||||||
|
int index,
|
||||||
|
long bsqAmount,
|
||||||
|
long btcAmount,
|
||||||
|
int height,
|
||||||
|
boolean isVerified,
|
||||||
|
long burntFee,
|
||||||
|
long invalidatedBsq,
|
||||||
|
String address,
|
||||||
|
JsonScriptPubKey scriptPubKey,
|
||||||
|
JsonSpentInfo spentInfo,
|
||||||
|
long time,
|
||||||
|
JsonTxType txType,
|
||||||
|
String txTypeDisplayString,
|
||||||
|
JsonTxOutputType txOutputType,
|
||||||
|
String txOutputTypeDisplayString,
|
||||||
|
String opReturn,
|
||||||
|
int lockTime,
|
||||||
|
boolean isUnspent) {
|
||||||
|
this.txId = txId;
|
||||||
|
this.index = index;
|
||||||
|
this.bsqAmount = bsqAmount;
|
||||||
|
this.btcAmount = btcAmount;
|
||||||
|
this.height = height;
|
||||||
|
this.isVerified = isVerified;
|
||||||
|
this.burntFee = burntFee;
|
||||||
|
this.invalidatedBsq = invalidatedBsq;
|
||||||
|
this.address = address;
|
||||||
|
this.scriptPubKey = scriptPubKey;
|
||||||
|
this.spentInfo = spentInfo;
|
||||||
|
this.time = time;
|
||||||
|
this.txType = txType;
|
||||||
|
this.txTypeDisplayString = txTypeDisplayString;
|
||||||
|
this.txOutputType = txOutputType;
|
||||||
|
this.txOutputTypeDisplayString = txOutputTypeDisplayString;
|
||||||
|
this.opReturn = opReturn;
|
||||||
|
this.lockTime = lockTime;
|
||||||
|
this.isUnspent = isUnspent;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getId() {
|
||||||
|
return txId + ":" + index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enums must not be used directly for hashCode or equals as it delivers the Object.hashCode (internal address)!
|
||||||
|
// The equals and hashCode methods cannot be overwritten in Enums.
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof JsonTxOutput)) return false;
|
||||||
|
if (!super.equals(o)) return false;
|
||||||
|
JsonTxOutput that = (JsonTxOutput) o;
|
||||||
|
return index == that.index &&
|
||||||
|
bsqAmount == that.bsqAmount &&
|
||||||
|
btcAmount == that.btcAmount &&
|
||||||
|
height == that.height &&
|
||||||
|
isVerified == that.isVerified &&
|
||||||
|
burntFee == that.burntFee &&
|
||||||
|
invalidatedBsq == that.invalidatedBsq &&
|
||||||
|
time == that.time &&
|
||||||
|
lockTime == that.lockTime &&
|
||||||
|
isUnspent == that.isUnspent &&
|
||||||
|
Objects.equals(txVersion, that.txVersion) &&
|
||||||
|
Objects.equals(txId, that.txId) &&
|
||||||
|
Objects.equals(address, that.address) &&
|
||||||
|
Objects.equals(scriptPubKey, that.scriptPubKey) &&
|
||||||
|
Objects.equals(spentInfo, that.spentInfo) &&
|
||||||
|
txType.name().equals(that.txType.name()) &&
|
||||||
|
Objects.equals(txTypeDisplayString, that.txTypeDisplayString) &&
|
||||||
|
txOutputType == that.txOutputType &&
|
||||||
|
Objects.equals(txOutputTypeDisplayString, that.txOutputTypeDisplayString) &&
|
||||||
|
Objects.equals(opReturn, that.opReturn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(super.hashCode(), txVersion, txId, index, bsqAmount, btcAmount, height, isVerified,
|
||||||
|
burntFee, invalidatedBsq, address, scriptPubKey, spentInfo, time, txType.name(), txTypeDisplayString,
|
||||||
|
txOutputType, txOutputTypeDisplayString, opReturn, lockTime, isUnspent);
|
||||||
|
}
|
||||||
|
}
|
51
restapi/src/main/java/bisq/restapi/dto/JsonTxOutputType.java
Normal file
51
restapi/src/main/java/bisq/restapi/dto/JsonTxOutputType.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi.dto;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
// Need to be in sync with TxOutputType
|
||||||
|
public enum JsonTxOutputType {
|
||||||
|
UNDEFINED("Undefined"),
|
||||||
|
UNDEFINED_OUTPUT("Undefined output"),
|
||||||
|
GENESIS_OUTPUT("Genesis"),
|
||||||
|
BSQ_OUTPUT("BSQ"),
|
||||||
|
BTC_OUTPUT("BTC"),
|
||||||
|
PROPOSAL_OP_RETURN_OUTPUT("Proposal opReturn"),
|
||||||
|
COMP_REQ_OP_RETURN_OUTPUT("Compensation request opReturn"),
|
||||||
|
REIMBURSEMENT_OP_RETURN_OUTPUT("Reimbursement request opReturn"),
|
||||||
|
CONFISCATE_BOND_OP_RETURN_OUTPUT("Confiscate bond opReturn"),
|
||||||
|
ISSUANCE_CANDIDATE_OUTPUT("Issuance candidate"),
|
||||||
|
BLIND_VOTE_LOCK_STAKE_OUTPUT("Blind vote lock stake"),
|
||||||
|
BLIND_VOTE_OP_RETURN_OUTPUT("Blind vote opReturn"),
|
||||||
|
VOTE_REVEAL_UNLOCK_STAKE_OUTPUT("Vote reveal unlock stake"),
|
||||||
|
VOTE_REVEAL_OP_RETURN_OUTPUT("Vote reveal opReturn"),
|
||||||
|
ASSET_LISTING_FEE_OP_RETURN_OUTPUT("Asset listing fee OpReturn"),
|
||||||
|
PROOF_OF_BURN_OP_RETURN_OUTPUT("Proof of burn opReturn"),
|
||||||
|
LOCKUP_OUTPUT("Lockup"),
|
||||||
|
LOCKUP_OP_RETURN_OUTPUT("Lockup opReturn"),
|
||||||
|
UNLOCK_OUTPUT("Unlock"),
|
||||||
|
INVALID_OUTPUT("Invalid");
|
||||||
|
|
||||||
|
private final String displayString;
|
||||||
|
|
||||||
|
JsonTxOutputType(String displayString) {
|
||||||
|
this.displayString = displayString;
|
||||||
|
}
|
||||||
|
}
|
48
restapi/src/main/java/bisq/restapi/dto/JsonTxType.java
Normal file
48
restapi/src/main/java/bisq/restapi/dto/JsonTxType.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi.dto;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
// Need to be in sync with TxOutputType
|
||||||
|
public enum JsonTxType {
|
||||||
|
UNDEFINED("Undefined"),
|
||||||
|
UNDEFINED_TX_TYPE("Undefined tx type"),
|
||||||
|
UNVERIFIED("Unverified"),
|
||||||
|
INVALID("Invalid"),
|
||||||
|
GENESIS("Genesis"),
|
||||||
|
TRANSFER_BSQ("Transfer BSQ"),
|
||||||
|
PAY_TRADE_FEE("Pay trade fee"),
|
||||||
|
PROPOSAL("Proposal"),
|
||||||
|
COMPENSATION_REQUEST("Compensation request"),
|
||||||
|
REIMBURSEMENT_REQUEST("Reimbursement request"),
|
||||||
|
BLIND_VOTE("Blind vote"),
|
||||||
|
VOTE_REVEAL("Vote reveal"),
|
||||||
|
LOCKUP("Lockup"),
|
||||||
|
UNLOCK("Unlock"),
|
||||||
|
ASSET_LISTING_FEE("Asset listing fee"),
|
||||||
|
PROOF_OF_BURN("Proof of burn"),
|
||||||
|
IRREGULAR("Irregular");
|
||||||
|
|
||||||
|
private final String displayString;
|
||||||
|
|
||||||
|
JsonTxType(String displayString) {
|
||||||
|
this.displayString = displayString;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
package bisq.restapi.endpoints;
|
||||||
|
|
||||||
|
import bisq.core.dao.state.model.blockchain.Block;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import bisq.restapi.DaoExplorerService;
|
||||||
|
import bisq.restapi.RestApi;
|
||||||
|
import bisq.restapi.RestApiMain;
|
||||||
|
import bisq.restapi.dto.JsonBlock;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.PathParam;
|
||||||
|
import jakarta.ws.rs.Produces;
|
||||||
|
import jakarta.ws.rs.core.Application;
|
||||||
|
import jakarta.ws.rs.core.Context;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Path("/explorer/blocks")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Tag(name = "BLOCKS API")
|
||||||
|
public class ExplorerBlocksApi {
|
||||||
|
private final DaoExplorerService daoExplorerService;
|
||||||
|
private final RestApi restApi;
|
||||||
|
|
||||||
|
public ExplorerBlocksApi(@Context Application application) {
|
||||||
|
restApi = ((RestApiMain) application).getRestApi();
|
||||||
|
daoExplorerService = restApi.getDaoExplorerService();
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://localhost:8081/api/v1/explorer/blocks/get-bsq-block-by-height/139
|
||||||
|
@Operation(description = "Request BSQ block details")
|
||||||
|
@ApiResponse(responseCode = "200", description = "The BSQ block",
|
||||||
|
content = {@Content(mediaType = MediaType.APPLICATION_JSON,
|
||||||
|
schema = @Schema(allOf = JsonBlock.class))}
|
||||||
|
)
|
||||||
|
@GET
|
||||||
|
@Path("get-bsq-block-by-height/{block-height}")
|
||||||
|
public JsonBlock getBsqBlockByHeight(@Parameter(description = "Block Height") @PathParam("block-height") int blockHeight) {
|
||||||
|
List<Block> blocks = restApi.getDaoStateService().getBlocks();
|
||||||
|
Optional<JsonBlock> jsonBlock = checkNotNull(blocks.stream())
|
||||||
|
.filter(block -> block.getHeight() == blockHeight)
|
||||||
|
.map(this::getJsonBlock)
|
||||||
|
.findFirst();
|
||||||
|
if (jsonBlock.isPresent()) {
|
||||||
|
log.info("supplying block at height {} to client.", blockHeight);
|
||||||
|
return jsonBlock.get();
|
||||||
|
}
|
||||||
|
log.warn("block {} not found!", blockHeight);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//http://localhost:8081/api/v1/explorer/blocks/get-bsq-block-by-hash/2e90186bd0958e8d4821e0b2546e018d70e3b4f136af8676e3571ca2363ce7f8
|
||||||
|
@GET
|
||||||
|
@Path("get-bsq-block-by-hash/{block-hash}")
|
||||||
|
public JsonBlock getBsqBlockByHash(@Parameter(description = "Block Hash") @PathParam("block-hash") String hash) {
|
||||||
|
List<Block> blocks = restApi.getDaoStateService().getBlocks();
|
||||||
|
Optional<JsonBlock> jsonBlock = checkNotNull(blocks.stream())
|
||||||
|
.filter(block -> block.getHash().equalsIgnoreCase(hash))
|
||||||
|
.map(this::getJsonBlock)
|
||||||
|
.findFirst();
|
||||||
|
if (jsonBlock.isPresent()) {
|
||||||
|
log.info("supplying block {} to client.", hash);
|
||||||
|
return jsonBlock.get();
|
||||||
|
}
|
||||||
|
log.warn("block {} not found!", hash);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonBlock getJsonBlock(Block block) {
|
||||||
|
return daoExplorerService.getJsonBlock(block);
|
||||||
|
}
|
||||||
|
}
|
124
restapi/src/main/java/bisq/restapi/endpoints/ExplorerDaoApi.java
Normal file
124
restapi/src/main/java/bisq/restapi/endpoints/ExplorerDaoApi.java
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package bisq.restapi.endpoints;
|
||||||
|
|
||||||
|
import bisq.core.dao.DaoFacade;
|
||||||
|
import bisq.core.dao.governance.period.CycleService;
|
||||||
|
import bisq.core.dao.governance.proposal.ProposalService;
|
||||||
|
import bisq.core.dao.state.DaoStateService;
|
||||||
|
import bisq.core.dao.state.model.blockchain.Tx;
|
||||||
|
import bisq.core.dao.state.model.governance.Issuance;
|
||||||
|
import bisq.core.dao.state.model.governance.IssuanceType;
|
||||||
|
import bisq.core.dao.state.model.governance.Proposal;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import bisq.restapi.DaoExplorerService;
|
||||||
|
import bisq.restapi.RestApi;
|
||||||
|
import bisq.restapi.RestApiMain;
|
||||||
|
import bisq.restapi.dto.BsqStatsDto;
|
||||||
|
import bisq.restapi.dto.JsonDaoCycle;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.Produces;
|
||||||
|
import jakarta.ws.rs.core.Application;
|
||||||
|
import jakarta.ws.rs.core.Context;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Path("/explorer/dao")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Tag(name = "EXPLORER API")
|
||||||
|
public class ExplorerDaoApi {
|
||||||
|
private final RestApi restApi;
|
||||||
|
private final DaoStateService daoStateService;
|
||||||
|
private final DaoExplorerService daoExplorerService;
|
||||||
|
|
||||||
|
public ExplorerDaoApi(@Context Application application) {
|
||||||
|
restApi = ((RestApiMain) application).getRestApi();
|
||||||
|
daoStateService = restApi.getDaoStateService();
|
||||||
|
daoExplorerService = restApi.getDaoExplorerService();
|
||||||
|
}
|
||||||
|
|
||||||
|
//http://localhost:8081/api/v1/explorer/dao/get-bsq-stats
|
||||||
|
@GET
|
||||||
|
@Path("get-bsq-stats")
|
||||||
|
public BsqStatsDto getBsqStats() {
|
||||||
|
DaoFacade daoFacade = restApi.getDaoFacade();
|
||||||
|
if (daoExplorerService.getLastKnownBlockHeight() != daoFacade.getChainHeight()) {
|
||||||
|
log.info("we recalculate the BSQ address map {} / {}", daoExplorerService.getLastKnownBlockHeight(), daoFacade.getChainHeight());
|
||||||
|
daoExplorerService.updateTxIdsByAddress();
|
||||||
|
daoExplorerService.setLastKnownBlockHeight(daoFacade.getChainHeight());
|
||||||
|
}
|
||||||
|
DaoStateService daoStateService = restApi.getDaoStateService();
|
||||||
|
long genesisSupply = daoFacade.getGenesisTotalSupply().getValue();
|
||||||
|
long issuedByCompensations = daoStateService.getIssuanceSetForType(IssuanceType.COMPENSATION).stream().mapToLong(Issuance::getAmount).sum();
|
||||||
|
long issuedByReimbursements = daoStateService.getIssuanceSetForType(IssuanceType.REIMBURSEMENT).stream().mapToLong(Issuance::getAmount).sum();
|
||||||
|
long minted = genesisSupply + issuedByCompensations + issuedByReimbursements;
|
||||||
|
long burnt = daoStateService.getTotalAmountOfBurntBsq();
|
||||||
|
int unspentTxos = daoStateService.getUnspentTxOutputMap().size();
|
||||||
|
int spentTxos = daoStateService.getSpentInfoMap().size();
|
||||||
|
int numAddresses = daoExplorerService.getNumAddresses();
|
||||||
|
log.info("client requested BSQ stats, height={}", daoExplorerService.getLastKnownBlockHeight());
|
||||||
|
return new BsqStatsDto(minted, burnt, numAddresses, unspentTxos, spentTxos,
|
||||||
|
daoExplorerService.getLastKnownBlockHeight(), daoFacade.getGenesisBlockHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("query-dao-cycles")
|
||||||
|
public List<JsonDaoCycle> queryDaoCycles() {
|
||||||
|
Set<Integer> cyclesAdded = new HashSet<>();
|
||||||
|
List<JsonDaoCycle> result = new ArrayList<>();
|
||||||
|
ProposalService proposalService = restApi.getProposalService();
|
||||||
|
CycleService cycleService = restApi.getCycleService();
|
||||||
|
DaoFacade daoFacade = restApi.getDaoFacade();
|
||||||
|
// Creating our data structure is a bit expensive so we ensure to only create the CycleListItems once.
|
||||||
|
daoStateService.getCycles().stream()
|
||||||
|
.filter(cycle -> !cyclesAdded.contains(cycle.getHeightOfFirstBlock()))
|
||||||
|
.filter(cycle -> cycleService.getCycleIndex(cycle) >= 0) // change this if you only need the latest n cycles
|
||||||
|
.forEach(cycle -> {
|
||||||
|
long cycleStartTime = daoStateService.getBlockTimeAtBlockHeight(cycle.getHeightOfFirstBlock());
|
||||||
|
int cycleIndex = cycleService.getCycleIndex(cycle);
|
||||||
|
boolean isCycleInProgress = cycleService.isBlockHeightInCycle(daoFacade.getChainHeight(), cycle);
|
||||||
|
log.info("Cycle {} {}", cycleIndex, isCycleInProgress ? "pending" : "complete");
|
||||||
|
List<Proposal> proposalsForCycle = proposalService.getValidatedProposals().stream()
|
||||||
|
.filter(proposal -> cycleService.isTxInCycle(cycle, proposal.getTxId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
int tempProposalCount = 0;
|
||||||
|
if (isCycleInProgress) {
|
||||||
|
tempProposalCount = (int) proposalService.getTempProposalsAsArrayList().stream()
|
||||||
|
.filter(proposal -> cycleService.isTxInCycle(cycle, proposal.getTxId()))
|
||||||
|
.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
long burnedAmount = daoFacade.getBurntFeeTxs().stream()
|
||||||
|
.filter(e -> cycleService.isBlockHeightInCycle(e.getBlockHeight(), cycle))
|
||||||
|
.mapToLong(Tx::getBurntFee)
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
int proposalCount = proposalsForCycle.size() + tempProposalCount;
|
||||||
|
long issuedAmount = daoFacade.getIssuanceForCycle(cycle);
|
||||||
|
JsonDaoCycle resultsOfCycle = new JsonDaoCycle(
|
||||||
|
cycle.getHeightOfFirstBlock(),
|
||||||
|
cycleIndex + 1,
|
||||||
|
cycleStartTime,
|
||||||
|
proposalCount,
|
||||||
|
burnedAmount,
|
||||||
|
issuedAmount,
|
||||||
|
isCycleInProgress);
|
||||||
|
cyclesAdded.add(resultsOfCycle.getHeightOfFirstBlock());
|
||||||
|
result.add(resultsOfCycle);
|
||||||
|
});
|
||||||
|
result.sort(Comparator.comparing(e -> ((JsonDaoCycle) e).getCycleIndex()).reversed());
|
||||||
|
log.info("client requested dao cycles, returning {} records", result.size());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,142 @@
|
|||||||
|
package bisq.restapi.endpoints;
|
||||||
|
|
||||||
|
import bisq.core.locale.CurrencyUtil;
|
||||||
|
import bisq.core.locale.Res;
|
||||||
|
import bisq.core.trade.statistics.TradeStatistics3;
|
||||||
|
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||||
|
|
||||||
|
import bisq.common.util.MathUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import bisq.restapi.RestApi;
|
||||||
|
import bisq.restapi.RestApiMain;
|
||||||
|
import bisq.restapi.dto.JsonCurrency;
|
||||||
|
import bisq.restapi.dto.JsonOffer;
|
||||||
|
import bisq.restapi.dto.JsonTradeInfo;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.PathParam;
|
||||||
|
import jakarta.ws.rs.Produces;
|
||||||
|
import jakarta.ws.rs.core.Application;
|
||||||
|
import jakarta.ws.rs.core.Context;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Path("/explorer/markets")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Tag(name = "EXPLORER API")
|
||||||
|
public class ExplorerMarketsApi {
|
||||||
|
private static final long MONTH = TimeUnit.DAYS.toMillis(30);
|
||||||
|
|
||||||
|
private final RestApi restApi;
|
||||||
|
|
||||||
|
public ExplorerMarketsApi(@Context Application application) {
|
||||||
|
restApi = ((RestApiMain) application).getRestApi();
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://localhost:8081/api/v1/explorer/markets/get-currencies
|
||||||
|
@GET
|
||||||
|
@Path("get-currencies")
|
||||||
|
public List<JsonCurrency> getBisqCurrencies() {
|
||||||
|
ArrayList<JsonCurrency> fiatCurrencyList = CurrencyUtil.getMatureMarketCurrencies().stream()
|
||||||
|
.map(e -> new JsonCurrency(e.getCode(), e.getName(), 8, "fiat"))
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
ArrayList<JsonCurrency> cryptoCurrencyList = CurrencyUtil.getMainCryptoCurrencies().stream()
|
||||||
|
.map(e -> new JsonCurrency(e.getCode(), e.getName(), 8, "crypto"))
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
List<JsonCurrency> result = Stream.concat(fiatCurrencyList.stream(), cryptoCurrencyList.stream()).collect(Collectors.toList());
|
||||||
|
log.info("client requested currencies, returning {} currencies", result.size());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("get-offers")
|
||||||
|
public List<JsonOffer> getBisqOffers() {
|
||||||
|
List<JsonOffer> result = restApi.getOfferBookService().getOfferForJsonList().stream()
|
||||||
|
.map(offerForJson -> new JsonOffer(
|
||||||
|
offerForJson.direction.name(),
|
||||||
|
offerForJson.currencyCode,
|
||||||
|
offerForJson.minAmount,
|
||||||
|
offerForJson.amount,
|
||||||
|
offerForJson.price,
|
||||||
|
offerForJson.date,
|
||||||
|
offerForJson.useMarketBasedPrice,
|
||||||
|
offerForJson.marketPriceMargin,
|
||||||
|
offerForJson.paymentMethod,
|
||||||
|
offerForJson.id,
|
||||||
|
offerForJson.currencyPair,
|
||||||
|
offerForJson.direction.name(),
|
||||||
|
offerForJson.priceDisplayString,
|
||||||
|
offerForJson.primaryMarketAmountDisplayString,
|
||||||
|
offerForJson.primaryMarketMinAmountDisplayString,
|
||||||
|
offerForJson.primaryMarketVolumeDisplayString,
|
||||||
|
offerForJson.primaryMarketMinVolumeDisplayString,
|
||||||
|
offerForJson.primaryMarketPrice,
|
||||||
|
offerForJson.primaryMarketAmount,
|
||||||
|
offerForJson.primaryMarketMinAmount,
|
||||||
|
offerForJson.primaryMarketVolume,
|
||||||
|
offerForJson.primaryMarketMinVolume)
|
||||||
|
)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
log.info("client requested offers, returning {} offers", result.size());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("get-trades/{newestTimestamp}/{oldestTimestamp}")
|
||||||
|
public List<JsonTradeInfo> getBisqTrades(@PathParam("newestTimestamp") long newestTimestamp,
|
||||||
|
@PathParam("oldestTimestamp") long oldestTimestamp) {
|
||||||
|
log.info("newestTimestamp: {} oldestTimestamp: {}", newestTimestamp, oldestTimestamp);
|
||||||
|
|
||||||
|
long to = new Date().getTime();
|
||||||
|
long from = newestTimestamp > 0 ? newestTimestamp : to - MONTH; // 30 days default
|
||||||
|
TradeStatisticsManager tradeStatisticsManager = restApi.getTradeStatisticsManager();
|
||||||
|
ArrayList<JsonTradeInfo> result = new ArrayList<>();
|
||||||
|
List<TradeStatistics3> tradeStatisticsList = tradeStatisticsManager.getTradeStatisticsList(from, to);
|
||||||
|
log.info("requesting a fresh batch of trades {}", tradeStatisticsList.size());
|
||||||
|
if (tradeStatisticsList.size() < 200 && oldestTimestamp > 0) {
|
||||||
|
to = oldestTimestamp;
|
||||||
|
from = to - MONTH;
|
||||||
|
List<TradeStatistics3> additional = tradeStatisticsManager.getTradeStatisticsList(from, to);
|
||||||
|
tradeStatisticsList.addAll(additional);
|
||||||
|
log.info("requesting an additional older batch of trades {}", additional.size());
|
||||||
|
}
|
||||||
|
tradeStatisticsList.forEach(x -> {
|
||||||
|
try {
|
||||||
|
String currencyPair = Res.getBaseCurrencyCode() + "/" + x.getCurrency();
|
||||||
|
// we use precision 4 for fiat based price but on the markets api we use precision 8 so we scale up by 10000
|
||||||
|
long primaryMarketTradePrice = (long) MathUtils.scaleUpByPowerOf10(x.getTradePrice().getValue(), 4);
|
||||||
|
long primaryMarketTradeAmount = x.getAmount();
|
||||||
|
// we use precision 4 for fiat but on the markets api we use precision 8 so we scale up by 10000
|
||||||
|
long primaryMarketTradeVolume = x.getTradeVolume() != null ?
|
||||||
|
(long) MathUtils.scaleUpByPowerOf10(x.getTradeVolume().getValue(), 4) : 0;
|
||||||
|
|
||||||
|
if (CurrencyUtil.isCryptoCurrency(x.getCurrency())) {
|
||||||
|
currencyPair = x.getCurrency() + "/" + Res.getBaseCurrencyCode();
|
||||||
|
primaryMarketTradePrice = x.getTradePrice().getValue();
|
||||||
|
primaryMarketTradeAmount = x.getTradeVolume().getValue(); // getVolumeByAmount?
|
||||||
|
primaryMarketTradeVolume = x.getAmount();
|
||||||
|
}
|
||||||
|
JsonTradeInfo jsonTradeInfo = new JsonTradeInfo(x.getCurrency(), x.getPrice(), x.getAmount(),
|
||||||
|
x.getDateAsLong(), x.getPaymentMethodId(), currencyPair, primaryMarketTradePrice,
|
||||||
|
primaryMarketTradeAmount, primaryMarketTradeVolume);
|
||||||
|
result.add(jsonTradeInfo);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.error("Iterating tradeStatisticsList failed", t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
log.info("client requested trades, returning {} trades", result.size());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* 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.restapi.endpoints;
|
||||||
|
|
||||||
|
import bisq.core.dao.state.model.blockchain.BaseTx;
|
||||||
|
import bisq.core.dao.state.model.blockchain.Tx;
|
||||||
|
import bisq.core.dao.state.model.blockchain.TxType;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import bisq.restapi.DaoExplorerService;
|
||||||
|
import bisq.restapi.RestApi;
|
||||||
|
import bisq.restapi.RestApiMain;
|
||||||
|
import bisq.restapi.dto.JsonTx;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.PathParam;
|
||||||
|
import jakarta.ws.rs.Produces;
|
||||||
|
import jakarta.ws.rs.core.Application;
|
||||||
|
import jakarta.ws.rs.core.Context;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Path("/explorer/transactions")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Tag(name = "TRANSACTIONS API")
|
||||||
|
public class ExplorerTransactionsApi {
|
||||||
|
private final RestApi restApi;
|
||||||
|
private final DaoExplorerService daoExplorerService;
|
||||||
|
|
||||||
|
public ExplorerTransactionsApi(@Context Application application) {
|
||||||
|
restApi = ((RestApiMain) application).getRestApi();
|
||||||
|
daoExplorerService = restApi.getDaoExplorerService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("get-bsq-tx/{txid}")
|
||||||
|
public JsonTx getTx(@Parameter(description = "TxId")
|
||||||
|
@PathParam("txid") String txId) {
|
||||||
|
Optional<JsonTx> jsonTx = restApi.getDaoStateService().getUnorderedTxStream()
|
||||||
|
.filter(t -> t.getId().equals(txId))
|
||||||
|
.map(this::getJsonTx)
|
||||||
|
.findFirst();
|
||||||
|
if (jsonTx.isPresent()) {
|
||||||
|
log.info("supplying tx {} to client.", txId);
|
||||||
|
return jsonTx.get();
|
||||||
|
}
|
||||||
|
log.warn("txid {} not found!", txId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("get-bsq-tx-for-addr/{addr}")
|
||||||
|
public List<JsonTx> getBisqTxForAddr(@PathParam("addr") String address) {
|
||||||
|
Map<String, Set<String>> addressToTxIds = daoExplorerService.getTxIdsByAddress();
|
||||||
|
List<JsonTx> result = new ArrayList<>();
|
||||||
|
Set<String> strings = addressToTxIds.get(address);
|
||||||
|
strings.forEach(txId -> {
|
||||||
|
restApi.getDaoStateService().getTx(txId).stream()
|
||||||
|
.map(this::getJsonTx)
|
||||||
|
.forEach(result::add);
|
||||||
|
});
|
||||||
|
log.info("getBisqTxForAddr: returning {} items.", result.size());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("query-txs-paginated/{start}/{count}/{filters}")
|
||||||
|
public List<JsonTx> queryTxsPaginated(@PathParam("start") int start,
|
||||||
|
@PathParam("count") int count,
|
||||||
|
@PathParam("filters") String filters) {
|
||||||
|
log.info("filters: {}", filters);
|
||||||
|
List<JsonTx> jsonTxs = restApi.getDaoStateService().getUnorderedTxStream()
|
||||||
|
.sorted(Comparator.comparing(BaseTx::getTime).reversed())
|
||||||
|
.filter(tx -> hasMatchingTxType(tx, filters))
|
||||||
|
.skip(start)
|
||||||
|
.limit(count)
|
||||||
|
.map(this::getJsonTx)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
log.info("supplying {} jsonTxs to client from index {}", jsonTxs.size(), start);
|
||||||
|
return jsonTxs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasMatchingTxType(Tx tx, String filters) {
|
||||||
|
String[] filterTokens = filters.split("~");
|
||||||
|
if (filterTokens.length < 1 || filters.equalsIgnoreCase("~")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (String filter : filterTokens) {
|
||||||
|
try {
|
||||||
|
TxType txType = Enum.valueOf(TxType.class, filter);
|
||||||
|
if (tx.getTxType() == txType) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Could not resolve TxType Enum from " + filter, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonTx getJsonTx(Tx tx) {
|
||||||
|
return daoExplorerService.getJsonTx(tx);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user