mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 07:07:43 +01:00
Add gettxfeerate, settxfeerate, unsettxfeerate implementations
This commit is contained in:
parent
abe7160608
commit
0b0f9f1120
5 changed files with 179 additions and 1 deletions
|
@ -31,6 +31,7 @@ import bisq.proto.grpc.GetPaymentAccountFormRequest;
|
|||
import bisq.proto.grpc.GetPaymentAccountsRequest;
|
||||
import bisq.proto.grpc.GetPaymentMethodsRequest;
|
||||
import bisq.proto.grpc.GetTradeRequest;
|
||||
import bisq.proto.grpc.GetTxFeeRateRequest;
|
||||
import bisq.proto.grpc.GetUnusedBsqAddressRequest;
|
||||
import bisq.proto.grpc.GetVersionRequest;
|
||||
import bisq.proto.grpc.KeepFundsRequest;
|
||||
|
@ -39,9 +40,11 @@ import bisq.proto.grpc.OfferInfo;
|
|||
import bisq.proto.grpc.RegisterDisputeAgentRequest;
|
||||
import bisq.proto.grpc.RemoveWalletPasswordRequest;
|
||||
import bisq.proto.grpc.SendBsqRequest;
|
||||
import bisq.proto.grpc.SetTxFeeRatePreferenceRequest;
|
||||
import bisq.proto.grpc.SetWalletPasswordRequest;
|
||||
import bisq.proto.grpc.TakeOfferRequest;
|
||||
import bisq.proto.grpc.UnlockWalletRequest;
|
||||
import bisq.proto.grpc.UnsetTxFeeRatePreferenceRequest;
|
||||
import bisq.proto.grpc.WithdrawFundsRequest;
|
||||
|
||||
import protobuf.PaymentAccount;
|
||||
|
@ -68,6 +71,7 @@ import java.util.List;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import static bisq.cli.CurrencyFormat.formatTxFeeRate;
|
||||
import static bisq.cli.CurrencyFormat.toSatoshis;
|
||||
import static bisq.cli.NegativeNumberOptions.hasNegativeNumberOptions;
|
||||
import static bisq.cli.TableFormat.*;
|
||||
|
@ -106,6 +110,9 @@ public class CliMain {
|
|||
getfundingaddresses,
|
||||
getunusedbsqaddress,
|
||||
sendbsq,
|
||||
gettxfeerate,
|
||||
settxfeerate,
|
||||
unsettxfeerate,
|
||||
lockwallet,
|
||||
unlockwallet,
|
||||
removewalletpassword,
|
||||
|
@ -266,6 +273,36 @@ public class CliMain {
|
|||
out.printf("%.2f BSQ sent to %s%n", amount, address);
|
||||
return;
|
||||
}
|
||||
case gettxfeerate: {
|
||||
var request = GetTxFeeRateRequest.newBuilder().build();
|
||||
var reply = walletsService.getTxFeeRate(request);
|
||||
out.println(formatTxFeeRate(reply.getTxFeeRateInfo()));
|
||||
return;
|
||||
}
|
||||
case settxfeerate: {
|
||||
if (nonOptionArgs.size() < 2)
|
||||
throw new IllegalArgumentException("no tx fee rate specified");
|
||||
|
||||
long txFeeRate;
|
||||
try {
|
||||
txFeeRate = Long.parseLong(nonOptionArgs.get(2));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(format("'%s' is not a number", nonOptionArgs.get(2)));
|
||||
}
|
||||
|
||||
var request = SetTxFeeRatePreferenceRequest.newBuilder()
|
||||
.setTxFeeRatePreference(txFeeRate)
|
||||
.build();
|
||||
var reply = walletsService.setTxFeeRatePreference(request);
|
||||
out.println(formatTxFeeRate(reply.getTxFeeRateInfo()));
|
||||
return;
|
||||
}
|
||||
case unsettxfeerate: {
|
||||
var request = UnsetTxFeeRatePreferenceRequest.newBuilder().build();
|
||||
var reply = walletsService.unsetTxFeeRatePreference(request);
|
||||
out.println(formatTxFeeRate(reply.getTxFeeRateInfo()));
|
||||
return;
|
||||
}
|
||||
case createoffer: {
|
||||
if (nonOptionArgs.size() < 9)
|
||||
throw new IllegalArgumentException("incorrect parameter count,"
|
||||
|
@ -626,6 +663,9 @@ public class CliMain {
|
|||
stream.format(rowFormat, "getfundingaddresses", "", "Get BTC funding addresses");
|
||||
stream.format(rowFormat, "getunusedbsqaddress", "", "Get unused BSQ address");
|
||||
stream.format(rowFormat, "sendbsq", "address, amount", "Send BSQ");
|
||||
stream.format(rowFormat, "gettxfeerate", "", "Get current tx fee rate in sats/byte");
|
||||
stream.format(rowFormat, "settxfeerate", "satoshis (per byte)", "Set custom tx fee rate in sats/byte");
|
||||
stream.format(rowFormat, "unsettxfeerate", "", "Unset custom tx fee rate");
|
||||
stream.format(rowFormat, "createoffer", "payment acct id, buy | sell, currency code, \\", "Create and place an offer");
|
||||
stream.format(rowFormat, "", "amount (btc), min amount, use mkt based price, \\", "");
|
||||
stream.format(rowFormat, "", "fixed price (btc) | mkt price margin (%), security deposit (%) \\", "");
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
package bisq.cli;
|
||||
|
||||
import bisq.proto.grpc.TxFeeRateInfo;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
@ -36,6 +38,7 @@ public class CurrencyFormat {
|
|||
|
||||
static final BigDecimal SATOSHI_DIVISOR = new BigDecimal(100000000);
|
||||
static final DecimalFormat BTC_FORMAT = new DecimalFormat("###,##0.00000000");
|
||||
static final DecimalFormat BTC_TX_FEE_FORMAT = new DecimalFormat("###,##0.00");
|
||||
|
||||
static final BigDecimal BSQ_SATOSHI_DIVISOR = new BigDecimal(100);
|
||||
static final DecimalFormat BSQ_FORMAT = new DecimalFormat("###,###,###,##0.00");
|
||||
|
@ -50,6 +53,23 @@ public class CurrencyFormat {
|
|||
return BSQ_FORMAT.format(BigDecimal.valueOf(sats).divide(BSQ_SATOSHI_DIVISOR));
|
||||
}
|
||||
|
||||
public static String formatTxFeeRate(TxFeeRateInfo txFeeRateInfo) {
|
||||
String stdTxFeeRate = formatTxFeeRate(txFeeRateInfo.getStdTxFeeRate());
|
||||
String customTxFeeRate = txFeeRateInfo.getCustomTxFeeRate() < 0
|
||||
? formatTxFeeRate(txFeeRateInfo.getCustomTxFeeRate())
|
||||
: null;
|
||||
|
||||
String formatString;
|
||||
if (customTxFeeRate == null)
|
||||
formatString = String.format("tx fee rate: %s sats/byte", stdTxFeeRate);
|
||||
else
|
||||
formatString = String.format("custom tx fee rate: %s sats/byte, network rate: %s sats/byte",
|
||||
customTxFeeRate,
|
||||
stdTxFeeRate);
|
||||
|
||||
return formatString;
|
||||
}
|
||||
|
||||
static String formatAmountRange(long minAmount, long amount) {
|
||||
return minAmount != amount
|
||||
? formatSatoshis(minAmount) + " - " + formatSatoshis(amount)
|
||||
|
@ -85,4 +105,9 @@ public class CurrencyFormat {
|
|||
throw new IllegalArgumentException(format("'%s' is not a number", btc));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
|
||||
private static String formatTxFeeRate(long sats) {
|
||||
return BTC_TX_FEE_FORMAT.format(BigDecimal.valueOf(sats).divide(SATOSHI_DIVISOR));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package bisq.core.api;
|
|||
|
||||
import bisq.core.api.model.AddressBalanceInfo;
|
||||
import bisq.core.api.model.BalancesInfo;
|
||||
import bisq.core.api.model.TxFeeRateInfo;
|
||||
import bisq.core.btc.wallet.TxBroadcaster;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.offer.Offer;
|
||||
|
@ -246,6 +247,18 @@ public class CoreApi {
|
|||
walletsService.sendBsq(address, amount, callback);
|
||||
}
|
||||
|
||||
public TxFeeRateInfo getTxFeeRate() {
|
||||
return walletsService.getTxFeeRate();
|
||||
}
|
||||
|
||||
public TxFeeRateInfo setTxFeeRatePreference(long txFeeRate) {
|
||||
return walletsService.setTxFeeRatePreference(txFeeRate);
|
||||
}
|
||||
|
||||
public TxFeeRateInfo unsetTxFeeRatePreference() {
|
||||
return walletsService.unsetTxFeeRatePreference();
|
||||
}
|
||||
|
||||
public void setWalletPassword(String password, String newPassword) {
|
||||
walletsService.setWalletPassword(password, newPassword);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import bisq.core.api.model.AddressBalanceInfo;
|
|||
import bisq.core.api.model.BalancesInfo;
|
||||
import bisq.core.api.model.BsqBalanceInfo;
|
||||
import bisq.core.api.model.BtcBalanceInfo;
|
||||
import bisq.core.api.model.TxFeeRateInfo;
|
||||
import bisq.core.btc.Balances;
|
||||
import bisq.core.btc.exceptions.BsqChangeBelowDustException;
|
||||
import bisq.core.btc.exceptions.TransactionVerificationException;
|
||||
|
@ -32,6 +33,8 @@ import bisq.core.btc.wallet.BsqWalletService;
|
|||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.btc.wallet.TxBroadcaster;
|
||||
import bisq.core.btc.wallet.WalletsManager;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.util.coin.BsqFormatter;
|
||||
|
||||
import bisq.common.Timer;
|
||||
|
@ -54,6 +57,8 @@ import org.bouncycastle.crypto.params.KeyParameter;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -74,6 +79,8 @@ class CoreWalletsService {
|
|||
private final BsqTransferService bsqTransferService;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final FeeService feeService;
|
||||
private final Preferences preferences;
|
||||
|
||||
@Nullable
|
||||
private Timer lockTimer;
|
||||
|
@ -87,13 +94,17 @@ class CoreWalletsService {
|
|||
BsqWalletService bsqWalletService,
|
||||
BsqTransferService bsqTransferService,
|
||||
BsqFormatter bsqFormatter,
|
||||
BtcWalletService btcWalletService) {
|
||||
BtcWalletService btcWalletService,
|
||||
FeeService feeService,
|
||||
Preferences preferences) {
|
||||
this.balances = balances;
|
||||
this.walletsManager = walletsManager;
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.bsqTransferService = bsqTransferService;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.feeService = feeService;
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -185,6 +196,37 @@ class CoreWalletsService {
|
|||
}
|
||||
}
|
||||
|
||||
TxFeeRateInfo getTxFeeRate() {
|
||||
try {
|
||||
CompletableFuture<Void> feeRequestFuture = CompletableFuture.runAsync(feeService::requestFees);
|
||||
feeRequestFuture.get(); // Block until async fee request is complete.
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
throw new IllegalStateException("could not request fees from fee service.", e);
|
||||
}
|
||||
|
||||
Coin stdTxFeeRate = feeService.getTxFeePerVbyte();
|
||||
Coin customTxFeeRate = preferences.isUseCustomWithdrawalTxFee()
|
||||
? Coin.valueOf(preferences.getWithdrawalTxFeeInVbytes())
|
||||
: Coin.NEGATIVE_SATOSHI;
|
||||
|
||||
return new TxFeeRateInfo(stdTxFeeRate.value, customTxFeeRate.value);
|
||||
}
|
||||
|
||||
TxFeeRateInfo setTxFeeRatePreference(long txFeeRate) {
|
||||
if (txFeeRate <= 0)
|
||||
throw new IllegalStateException("cannot create transactions without fees");
|
||||
|
||||
preferences.setUseCustomWithdrawalTxFee(true);
|
||||
Coin satsPerByte = Coin.valueOf(txFeeRate);
|
||||
preferences.setWithdrawalTxFeeInVbytes(satsPerByte.value);
|
||||
return getTxFeeRate();
|
||||
}
|
||||
|
||||
TxFeeRateInfo unsetTxFeeRatePreference() {
|
||||
preferences.setUseCustomWithdrawalTxFee(false);
|
||||
return getTxFeeRate();
|
||||
}
|
||||
|
||||
int getNumConfirmationsForMostRecentTransaction(String addressString) {
|
||||
Address address = getAddressEntry(addressString).getAddress();
|
||||
TransactionConfidence confidence = btcWalletService.getConfidenceForAddress(address);
|
||||
|
|
|
@ -19,6 +19,7 @@ package bisq.daemon.grpc;
|
|||
|
||||
import bisq.core.api.CoreApi;
|
||||
import bisq.core.api.model.AddressBalanceInfo;
|
||||
import bisq.core.api.model.TxFeeRateInfo;
|
||||
import bisq.core.btc.exceptions.TxBroadcastException;
|
||||
import bisq.core.btc.wallet.TxBroadcaster;
|
||||
|
||||
|
@ -28,6 +29,8 @@ import bisq.proto.grpc.GetBalancesReply;
|
|||
import bisq.proto.grpc.GetBalancesRequest;
|
||||
import bisq.proto.grpc.GetFundingAddressesReply;
|
||||
import bisq.proto.grpc.GetFundingAddressesRequest;
|
||||
import bisq.proto.grpc.GetTxFeeRateReply;
|
||||
import bisq.proto.grpc.GetTxFeeRateRequest;
|
||||
import bisq.proto.grpc.GetUnusedBsqAddressReply;
|
||||
import bisq.proto.grpc.GetUnusedBsqAddressRequest;
|
||||
import bisq.proto.grpc.LockWalletReply;
|
||||
|
@ -36,10 +39,14 @@ import bisq.proto.grpc.RemoveWalletPasswordReply;
|
|||
import bisq.proto.grpc.RemoveWalletPasswordRequest;
|
||||
import bisq.proto.grpc.SendBsqReply;
|
||||
import bisq.proto.grpc.SendBsqRequest;
|
||||
import bisq.proto.grpc.SetTxFeeRatePreferenceReply;
|
||||
import bisq.proto.grpc.SetTxFeeRatePreferenceRequest;
|
||||
import bisq.proto.grpc.SetWalletPasswordReply;
|
||||
import bisq.proto.grpc.SetWalletPasswordRequest;
|
||||
import bisq.proto.grpc.UnlockWalletReply;
|
||||
import bisq.proto.grpc.UnlockWalletRequest;
|
||||
import bisq.proto.grpc.UnsetTxFeeRatePreferenceReply;
|
||||
import bisq.proto.grpc.UnsetTxFeeRatePreferenceRequest;
|
||||
import bisq.proto.grpc.WalletsGrpc;
|
||||
|
||||
import io.grpc.Status;
|
||||
|
@ -163,6 +170,57 @@ class GrpcWalletsService extends WalletsGrpc.WalletsImplBase {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getTxFeeRate(GetTxFeeRateRequest req,
|
||||
StreamObserver<GetTxFeeRateReply> responseObserver) {
|
||||
try {
|
||||
TxFeeRateInfo txFeeRateInfo = coreApi.getTxFeeRate();
|
||||
var reply = GetTxFeeRateReply.newBuilder()
|
||||
.setTxFeeRateInfo(txFeeRateInfo.toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
} catch (IllegalStateException cause) {
|
||||
var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage()));
|
||||
responseObserver.onError(ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTxFeeRatePreference(SetTxFeeRatePreferenceRequest req,
|
||||
StreamObserver<SetTxFeeRatePreferenceReply> responseObserver) {
|
||||
try {
|
||||
TxFeeRateInfo txFeeRateInfo = coreApi.setTxFeeRatePreference(req.getTxFeeRatePreference());
|
||||
var reply = SetTxFeeRatePreferenceReply.newBuilder()
|
||||
.setTxFeeRateInfo(txFeeRateInfo.toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
} catch (IllegalStateException cause) {
|
||||
var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage()));
|
||||
responseObserver.onError(ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetTxFeeRatePreference(UnsetTxFeeRatePreferenceRequest req,
|
||||
StreamObserver<UnsetTxFeeRatePreferenceReply> responseObserver) {
|
||||
try {
|
||||
TxFeeRateInfo txFeeRateInfo = coreApi.unsetTxFeeRatePreference();
|
||||
var reply = UnsetTxFeeRatePreferenceReply.newBuilder()
|
||||
.setTxFeeRateInfo(txFeeRateInfo.toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
} catch (IllegalStateException cause) {
|
||||
var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage()));
|
||||
responseObserver.onError(ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWalletPassword(SetWalletPasswordRequest req,
|
||||
StreamObserver<SetWalletPasswordReply> responseObserver) {
|
||||
|
|
Loading…
Add table
Reference in a new issue