remove btc fee service
This commit is contained in:
parent
3314eac881
commit
31dfdd7710
@ -1,93 +0,0 @@
|
||||
package bisq.apitest.method.wallet;
|
||||
|
||||
import bisq.core.api.model.TxFeeRateInfo;
|
||||
|
||||
import io.grpc.StatusRuntimeException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInfo;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
|
||||
import static bisq.apitest.Scaffold.BitcoinCoreApp.bitcoind;
|
||||
import static bisq.apitest.config.HavenoAppConfig.alicedaemon;
|
||||
import static bisq.apitest.config.HavenoAppConfig.seednode;
|
||||
import static java.lang.String.format;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
|
||||
|
||||
|
||||
|
||||
import bisq.apitest.method.MethodTest;
|
||||
|
||||
@Disabled
|
||||
@Slf4j
|
||||
@TestMethodOrder(OrderAnnotation.class)
|
||||
public class BtcTxFeeRateTest extends MethodTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp() {
|
||||
startSupportingApps(false,
|
||||
true,
|
||||
bitcoind,
|
||||
seednode,
|
||||
alicedaemon);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
public void testGetTxFeeRate(final TestInfo testInfo) {
|
||||
var txFeeRateInfo = TxFeeRateInfo.fromProto(aliceClient.getTxFeeRate());
|
||||
log.debug("{} -> Fee rate with no preference: {}", testName(testInfo), txFeeRateInfo);
|
||||
|
||||
assertFalse(txFeeRateInfo.isUseCustomTxFeeRate());
|
||||
assertTrue(txFeeRateInfo.getFeeServiceRate() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void testSetInvalidTxFeeRateShouldThrowException(final TestInfo testInfo) {
|
||||
var currentTxFeeRateInfo = TxFeeRateInfo.fromProto(aliceClient.getTxFeeRate());
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () -> aliceClient.setTxFeeRate(1));
|
||||
String expectedExceptionMessage =
|
||||
format("INVALID_ARGUMENT: tx fee rate preference must be >= %d sats/byte",
|
||||
currentTxFeeRateInfo.getMinFeeServiceRate());
|
||||
assertEquals(expectedExceptionMessage, exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testSetValidTxFeeRate(final TestInfo testInfo) {
|
||||
var currentTxFeeRateInfo = TxFeeRateInfo.fromProto(aliceClient.getTxFeeRate());
|
||||
var customFeeRate = currentTxFeeRateInfo.getMinFeeServiceRate() + 5;
|
||||
var txFeeRateInfo = TxFeeRateInfo.fromProto(aliceClient.setTxFeeRate(customFeeRate));
|
||||
log.debug("{} -> Fee rates with custom preference: {}", testName(testInfo), txFeeRateInfo);
|
||||
|
||||
assertTrue(txFeeRateInfo.isUseCustomTxFeeRate());
|
||||
assertEquals(customFeeRate, txFeeRateInfo.getCustomTxFeeRate());
|
||||
assertTrue(txFeeRateInfo.getFeeServiceRate() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
public void testUnsetTxFeeRate(final TestInfo testInfo) {
|
||||
var txFeeRateInfo = TxFeeRateInfo.fromProto(aliceClient.unsetTxFeeRate());
|
||||
log.debug("{} -> Fee rate with no preference: {}", testName(testInfo), txFeeRateInfo);
|
||||
|
||||
assertFalse(txFeeRateInfo.isUseCustomTxFeeRate());
|
||||
assertTrue(txFeeRateInfo.getFeeServiceRate() > 0);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown() {
|
||||
tearDownScaffold();
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package bisq.apitest.method.wallet;
|
||||
|
||||
import bisq.proto.grpc.BtcBalanceInfo;
|
||||
import bisq.proto.grpc.TxInfo;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@ -96,49 +95,6 @@ public class BtcWalletTest extends MethodTest {
|
||||
new TableBuilder(BTC_BALANCE_TBL, btcBalanceInfo).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testAliceSendBTCToBob(TestInfo testInfo) {
|
||||
String bobsBtcAddress = bobClient.getUnusedBtcAddress();
|
||||
log.debug("Sending 5.5 BTC From Alice to Bob @ {}", bobsBtcAddress);
|
||||
|
||||
TxInfo txInfo = aliceClient.sendBtc(bobsBtcAddress,
|
||||
"5.50",
|
||||
"100",
|
||||
TX_MEMO);
|
||||
assertTrue(txInfo.getIsPending());
|
||||
|
||||
// Note that the memo is not set on the tx yet.
|
||||
assertTrue(txInfo.getMemo().isEmpty());
|
||||
genBtcBlocksThenWait(1, 1000);
|
||||
|
||||
// Fetch the tx and check for confirmation and memo.
|
||||
txInfo = aliceClient.getTransaction(txInfo.getTxId());
|
||||
assertFalse(txInfo.getIsPending());
|
||||
assertEquals(TX_MEMO, txInfo.getMemo());
|
||||
|
||||
BtcBalanceInfo alicesBalances = aliceClient.getBtcBalances();
|
||||
log.debug("{} Alice's BTC Balances:\n{}",
|
||||
testName(testInfo),
|
||||
new TableBuilder(BTC_BALANCE_TBL, alicesBalances).build());
|
||||
bisq.core.api.model.BtcBalanceInfo alicesExpectedBalances =
|
||||
bisq.core.api.model.BtcBalanceInfo.valueOf(700000000,
|
||||
0,
|
||||
700000000,
|
||||
0);
|
||||
verifyBtcBalances(alicesExpectedBalances, alicesBalances);
|
||||
|
||||
BtcBalanceInfo bobsBalances = bobClient.getBtcBalances();
|
||||
log.debug("{} Bob's BTC Balances:\n{}",
|
||||
testName(testInfo),
|
||||
new TableBuilder(BTC_BALANCE_TBL, bobsBalances).build());
|
||||
// The sendbtc tx weight and size randomly varies between two distinct values
|
||||
// (876 wu, 219 bytes, OR 880 wu, 220 bytes) from test run to test run, hence
|
||||
// the assertion of an available balance range [1549978000, 1549978100].
|
||||
assertTrue(bobsBalances.getAvailableBalance() >= 1549978000);
|
||||
assertTrue(bobsBalances.getAvailableBalance() <= 1549978100);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown() {
|
||||
tearDownScaffold();
|
||||
|
@ -36,7 +36,6 @@ import static bisq.apitest.config.HavenoAppConfig.seednode;
|
||||
|
||||
|
||||
import bisq.apitest.method.MethodTest;
|
||||
import bisq.apitest.method.wallet.BtcTxFeeRateTest;
|
||||
import bisq.apitest.method.wallet.BtcWalletTest;
|
||||
import bisq.apitest.method.wallet.WalletProtectionTest;
|
||||
|
||||
@ -66,7 +65,6 @@ public class WalletTest extends MethodTest {
|
||||
|
||||
btcWalletTest.testInitialBtcBalances(testInfo);
|
||||
btcWalletTest.testFundAlicesBtcWallet(testInfo);
|
||||
btcWalletTest.testAliceSendBTCToBob(testInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -86,17 +84,6 @@ public class WalletTest extends MethodTest {
|
||||
walletProtectionTest.testRemoveNewWalletPassword();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
public void testTxFeeRateMethods(final TestInfo testInfo) {
|
||||
BtcTxFeeRateTest test = new BtcTxFeeRateTest();
|
||||
|
||||
test.testGetTxFeeRate(testInfo);
|
||||
test.testSetInvalidTxFeeRateShouldThrowException(testInfo);
|
||||
test.testSetValidTxFeeRate(testInfo);
|
||||
test.testUnsetTxFeeRate(testInfo);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown() {
|
||||
tearDownScaffold();
|
||||
|
@ -41,7 +41,6 @@ import java.util.List;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import static bisq.cli.CurrencyFormat.formatInternalFiatPrice;
|
||||
import static bisq.cli.CurrencyFormat.formatTxFeeRateInfo;
|
||||
import static bisq.cli.CurrencyFormat.toSatoshis;
|
||||
import static bisq.cli.Method.*;
|
||||
import static bisq.cli.opts.OptLabel.*;
|
||||
@ -228,51 +227,7 @@ public class CliMain {
|
||||
|
||||
var memo = opts.getMemo();
|
||||
|
||||
var txInfo = client.sendBtc(address, amount, txFeeRate, memo);
|
||||
out.printf("%s btc sent to %s in tx %s%n",
|
||||
amount,
|
||||
address,
|
||||
txInfo.getTxId());
|
||||
return;
|
||||
}
|
||||
case gettxfeerate: {
|
||||
if (new SimpleMethodOptionParser(args).parse().isForHelp()) {
|
||||
out.println(client.getMethodHelp(method));
|
||||
return;
|
||||
}
|
||||
var txFeeRate = client.getTxFeeRate();
|
||||
out.println(formatTxFeeRateInfo(txFeeRate));
|
||||
return;
|
||||
}
|
||||
case settxfeerate: {
|
||||
var opts = new SetTxFeeRateOptionParser(args).parse();
|
||||
if (opts.isForHelp()) {
|
||||
out.println(client.getMethodHelp(method));
|
||||
return;
|
||||
}
|
||||
var txFeeRate = client.setTxFeeRate(toLong(opts.getFeeRate()));
|
||||
out.println(formatTxFeeRateInfo(txFeeRate));
|
||||
return;
|
||||
}
|
||||
case unsettxfeerate: {
|
||||
if (new SimpleMethodOptionParser(args).parse().isForHelp()) {
|
||||
out.println(client.getMethodHelp(method));
|
||||
return;
|
||||
}
|
||||
var txFeeRate = client.unsetTxFeeRate();
|
||||
out.println(formatTxFeeRateInfo(txFeeRate));
|
||||
return;
|
||||
}
|
||||
case gettransaction: {
|
||||
var opts = new GetTransactionOptionParser(args).parse();
|
||||
if (opts.isForHelp()) {
|
||||
out.println(client.getMethodHelp(method));
|
||||
return;
|
||||
}
|
||||
var txId = opts.getTxId();
|
||||
var tx = client.getTransaction(txId);
|
||||
new TableBuilder(TRANSACTION_TBL, tx).build().print(out);
|
||||
return;
|
||||
throw new RuntimeException("Send BTC not implemented");
|
||||
}
|
||||
case createoffer: {
|
||||
var opts = new CreateOfferOptionParser(args).parse();
|
||||
|
@ -17,8 +17,6 @@
|
||||
|
||||
package bisq.cli;
|
||||
|
||||
import bisq.proto.grpc.TxFeeRateInfo;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
@ -76,18 +74,6 @@ public class CurrencyFormat {
|
||||
return BSQ_FORMAT.format(new BigDecimal(sats).divide(BSQ_SATOSHI_DIVISOR));
|
||||
}
|
||||
|
||||
public static String formatTxFeeRateInfo(TxFeeRateInfo txFeeRateInfo) {
|
||||
if (txFeeRateInfo.getUseCustomTxFeeRate())
|
||||
return format("custom tx fee rate: %s sats/byte, network rate: %s sats/byte, min network rate: %s sats/byte",
|
||||
formatFeeSatoshis(txFeeRateInfo.getCustomTxFeeRate()),
|
||||
formatFeeSatoshis(txFeeRateInfo.getFeeServiceRate()),
|
||||
formatFeeSatoshis(txFeeRateInfo.getMinFeeServiceRate()));
|
||||
else
|
||||
return format("tx fee rate: %s sats/byte, min tx fee rate: %s sats/byte",
|
||||
formatFeeSatoshis(txFeeRateInfo.getFeeServiceRate()),
|
||||
formatFeeSatoshis(txFeeRateInfo.getMinFeeServiceRate()));
|
||||
}
|
||||
|
||||
public static String formatInternalFiatPrice(BigDecimal price) {
|
||||
INTERNAL_FIAT_DECIMAL_FORMAT.setMinimumFractionDigits(4);
|
||||
INTERNAL_FIAT_DECIMAL_FORMAT.setMaximumFractionDigits(4);
|
||||
|
@ -27,8 +27,6 @@ import bisq.proto.grpc.OfferInfo;
|
||||
import bisq.proto.grpc.RegisterDisputeAgentRequest;
|
||||
import bisq.proto.grpc.StopRequest;
|
||||
import bisq.proto.grpc.TradeInfo;
|
||||
import bisq.proto.grpc.TxFeeRateInfo;
|
||||
import bisq.proto.grpc.TxInfo;
|
||||
|
||||
import protobuf.PaymentAccount;
|
||||
import protobuf.PaymentAccountForm;
|
||||
@ -98,26 +96,6 @@ public final class GrpcClient {
|
||||
return walletsServiceRequest.getUnusedBtcAddress();
|
||||
}
|
||||
|
||||
public TxInfo sendBtc(String address, String amount, String txFeeRate, String memo) {
|
||||
return walletsServiceRequest.sendBtc(address, amount, txFeeRate, memo);
|
||||
}
|
||||
|
||||
public TxFeeRateInfo getTxFeeRate() {
|
||||
return walletsServiceRequest.getTxFeeRate();
|
||||
}
|
||||
|
||||
public TxFeeRateInfo setTxFeeRate(long txFeeRate) {
|
||||
return walletsServiceRequest.setTxFeeRate(txFeeRate);
|
||||
}
|
||||
|
||||
public TxFeeRateInfo unsetTxFeeRate() {
|
||||
return walletsServiceRequest.unsetTxFeeRate();
|
||||
}
|
||||
|
||||
public TxInfo getTransaction(String txId) {
|
||||
return walletsServiceRequest.getTransaction(txId);
|
||||
}
|
||||
|
||||
public OfferInfo createFixedPricedOffer(String direction,
|
||||
String currencyCode,
|
||||
long amount,
|
||||
|
@ -17,43 +17,10 @@
|
||||
|
||||
package bisq.cli;
|
||||
|
||||
import bisq.proto.grpc.TxInfo;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import static bisq.cli.ColumnHeaderConstants.*;
|
||||
import static bisq.cli.CurrencyFormat.formatSatoshis;
|
||||
import static com.google.common.base.Strings.padEnd;
|
||||
|
||||
@VisibleForTesting
|
||||
public class TransactionFormat {
|
||||
|
||||
public static String format(TxInfo txInfo) {
|
||||
String headerLine = padEnd(COL_HEADER_TX_ID, txInfo.getTxId().length(), ' ') + COL_HEADER_DELIMITER
|
||||
+ COL_HEADER_TX_IS_CONFIRMED + COL_HEADER_DELIMITER
|
||||
+ COL_HEADER_TX_INPUT_SUM + COL_HEADER_DELIMITER
|
||||
+ COL_HEADER_TX_OUTPUT_SUM + COL_HEADER_DELIMITER
|
||||
+ COL_HEADER_TX_FEE + COL_HEADER_DELIMITER
|
||||
+ COL_HEADER_TX_SIZE + COL_HEADER_DELIMITER
|
||||
+ (txInfo.getMemo().isEmpty() ? "" : COL_HEADER_TX_MEMO + COL_HEADER_DELIMITER)
|
||||
+ "\n";
|
||||
|
||||
String colDataFormat = "%-" + txInfo.getTxId().length() + "s"
|
||||
+ " %" + COL_HEADER_TX_IS_CONFIRMED.length() + "s"
|
||||
+ " %" + COL_HEADER_TX_INPUT_SUM.length() + "s"
|
||||
+ " %" + COL_HEADER_TX_OUTPUT_SUM.length() + "s"
|
||||
+ " %" + COL_HEADER_TX_FEE.length() + "s"
|
||||
+ " %" + COL_HEADER_TX_SIZE.length() + "s"
|
||||
+ " %s";
|
||||
|
||||
return headerLine
|
||||
+ String.format(colDataFormat,
|
||||
txInfo.getTxId(),
|
||||
txInfo.getIsPending() ? "NO" : "YES", // pending=true means not confirmed
|
||||
formatSatoshis(txInfo.getInputSum()),
|
||||
formatSatoshis(txInfo.getOutputSum()),
|
||||
formatSatoshis(txInfo.getFee()),
|
||||
txInfo.getSize(),
|
||||
txInfo.getMemo().isEmpty() ? "" : txInfo.getMemo());
|
||||
}
|
||||
}
|
||||
|
@ -23,18 +23,12 @@ import bisq.proto.grpc.BtcBalanceInfo;
|
||||
import bisq.proto.grpc.GetAddressBalanceRequest;
|
||||
import bisq.proto.grpc.GetBalancesRequest;
|
||||
import bisq.proto.grpc.GetFundingAddressesRequest;
|
||||
import bisq.proto.grpc.GetTransactionRequest;
|
||||
import bisq.proto.grpc.GetTxFeeRateRequest;
|
||||
import bisq.proto.grpc.LockWalletRequest;
|
||||
import bisq.proto.grpc.MarketPriceRequest;
|
||||
import bisq.proto.grpc.RemoveWalletPasswordRequest;
|
||||
import bisq.proto.grpc.SendBtcRequest;
|
||||
import bisq.proto.grpc.SetTxFeeRatePreferenceRequest;
|
||||
import bisq.proto.grpc.SetWalletPasswordRequest;
|
||||
import bisq.proto.grpc.TxFeeRateInfo;
|
||||
import bisq.proto.grpc.TxInfo;
|
||||
import bisq.proto.grpc.UnlockWalletRequest;
|
||||
import bisq.proto.grpc.UnsetTxFeeRatePreferenceRequest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -95,40 +89,6 @@ public class WalletsServiceRequest {
|
||||
.getAddress();
|
||||
}
|
||||
|
||||
public TxInfo sendBtc(String address, String amount, String txFeeRate, String memo) {
|
||||
var request = SendBtcRequest.newBuilder()
|
||||
.setAddress(address)
|
||||
.setAmount(amount)
|
||||
.setTxFeeRate(txFeeRate)
|
||||
.setMemo(memo)
|
||||
.build();
|
||||
return grpcStubs.walletsService.sendBtc(request).getTxInfo();
|
||||
}
|
||||
|
||||
public TxFeeRateInfo getTxFeeRate() {
|
||||
var request = GetTxFeeRateRequest.newBuilder().build();
|
||||
return grpcStubs.walletsService.getTxFeeRate(request).getTxFeeRateInfo();
|
||||
}
|
||||
|
||||
public TxFeeRateInfo setTxFeeRate(long txFeeRate) {
|
||||
var request = SetTxFeeRatePreferenceRequest.newBuilder()
|
||||
.setTxFeeRatePreference(txFeeRate)
|
||||
.build();
|
||||
return grpcStubs.walletsService.setTxFeeRatePreference(request).getTxFeeRateInfo();
|
||||
}
|
||||
|
||||
public TxFeeRateInfo unsetTxFeeRate() {
|
||||
var request = UnsetTxFeeRatePreferenceRequest.newBuilder().build();
|
||||
return grpcStubs.walletsService.unsetTxFeeRatePreference(request).getTxFeeRateInfo();
|
||||
}
|
||||
|
||||
public TxInfo getTransaction(String txId) {
|
||||
var request = GetTransactionRequest.newBuilder()
|
||||
.setTxId(txId)
|
||||
.build();
|
||||
return grpcStubs.walletsService.getTransaction(request).getTxInfo();
|
||||
}
|
||||
|
||||
public void lockWallet() {
|
||||
var request = LockWalletRequest.newBuilder().build();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
|
@ -17,8 +17,6 @@
|
||||
|
||||
package bisq.cli.table.builder;
|
||||
|
||||
import bisq.proto.grpc.TxInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@ -61,25 +59,22 @@ class TransactionTableBuilder extends AbstractTableBuilder {
|
||||
public Table build() {
|
||||
// TODO Add 'gettransactions' api method & show multiple tx in the console.
|
||||
// For now, a tx tbl is only one row.
|
||||
TxInfo tx = (TxInfo) protos.get(0);
|
||||
|
||||
// Declare the columns derived from tx info.
|
||||
|
||||
@Nullable
|
||||
Column<String> colMemo = tx.getMemo().isEmpty()
|
||||
? null
|
||||
: new StringColumn(COL_HEADER_TX_MEMO);
|
||||
Column<String> colMemo = null;
|
||||
|
||||
// Populate columns with tx info.
|
||||
|
||||
colTxId.addRow(tx.getTxId());
|
||||
colIsConfirmed.addRow(!tx.getIsPending());
|
||||
colInputSum.addRow(tx.getInputSum());
|
||||
colOutputSum.addRow(tx.getOutputSum());
|
||||
colTxFee.addRow(tx.getFee());
|
||||
colTxSize.addRow((long) tx.getSize());
|
||||
colTxId.addRow(null);
|
||||
colIsConfirmed.addRow(null);
|
||||
colInputSum.addRow(null);
|
||||
colOutputSum.addRow(null);
|
||||
colTxFee.addRow(null);
|
||||
colTxSize.addRow(null);
|
||||
if (colMemo != null)
|
||||
colMemo.addRow(tx.getMemo());
|
||||
colMemo.addRow(null);
|
||||
|
||||
// Define and return the table instance with populated columns.
|
||||
|
||||
|
@ -18,7 +18,6 @@ public class GetTransactionCliOutputDiffTest extends AbstractCliTest {
|
||||
throw new IllegalStateException("Need a single transaction-id program argument.");
|
||||
|
||||
GetTransactionCliOutputDiffTest test = new GetTransactionCliOutputDiffTest(args[0]);
|
||||
test.getTransaction();
|
||||
}
|
||||
|
||||
private final String transactionId;
|
||||
@ -27,15 +26,4 @@ public class GetTransactionCliOutputDiffTest extends AbstractCliTest {
|
||||
super();
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
private void getTransaction() {
|
||||
var tx = aliceClient.getTransaction(transactionId);
|
||||
// TransactionFormat class had been deprecated, then deleted on 17-Feb-2022, but
|
||||
// these diff tests can be useful for testing changes to the current tbl formatting api.
|
||||
// var oldTbl = TransactionFormat.format(tx);
|
||||
var newTbl = new TableBuilder(TRANSACTION_TBL, tx).build().toString();
|
||||
// printOldTbl(oldTbl);
|
||||
printNewTbl(newTbl);
|
||||
// checkDiffsIgnoreWhitespace(oldTbl, newTbl);
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ import bisq.core.api.model.MarketDepthInfo;
|
||||
import bisq.core.api.model.MarketPriceInfo;
|
||||
import bisq.core.api.model.PaymentAccountForm;
|
||||
import bisq.core.api.model.PaymentAccountFormField;
|
||||
import bisq.core.api.model.TxFeeRateInfo;
|
||||
import bisq.core.app.AppStartupState;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.offer.Offer;
|
||||
@ -315,24 +314,6 @@ public class CoreApi {
|
||||
walletsService.sendBtc(address, amount, txFeeRate, memo, callback);
|
||||
}
|
||||
|
||||
|
||||
public void getTxFeeRate(ResultHandler resultHandler) {
|
||||
walletsService.getTxFeeRate(resultHandler);
|
||||
}
|
||||
|
||||
public void setTxFeeRatePreference(long txFeeRate,
|
||||
ResultHandler resultHandler) {
|
||||
walletsService.setTxFeeRatePreference(txFeeRate, resultHandler);
|
||||
}
|
||||
|
||||
public void unsetTxFeeRatePreference(ResultHandler resultHandler) {
|
||||
walletsService.unsetTxFeeRatePreference(resultHandler);
|
||||
}
|
||||
|
||||
public TxFeeRateInfo getMostRecentTxFeeRateInfo() {
|
||||
return walletsService.getMostRecentTxFeeRateInfo();
|
||||
}
|
||||
|
||||
public Transaction getTransaction(String txId) {
|
||||
return walletsService.getTransaction(txId);
|
||||
}
|
||||
|
@ -103,12 +103,10 @@ class CoreTradesService {
|
||||
var useSavingsWallet = true;
|
||||
|
||||
// synchronize access to take offer model // TODO (woodser): to avoid synchronizing, don't use stateful model
|
||||
Coin txFeeFromFeeService; // TODO (woodser): remove this and other unused fields
|
||||
Coin takerFee;
|
||||
Coin fundsNeededForTrade;
|
||||
synchronized (takeOfferModel) {
|
||||
takeOfferModel.initModel(offer, paymentAccount, useSavingsWallet);
|
||||
txFeeFromFeeService = takeOfferModel.getTxFeeFromFeeService();
|
||||
takerFee = takeOfferModel.getTakerFee();
|
||||
fundsNeededForTrade = takeOfferModel.getFundsNeededForTrade();
|
||||
log.info("Initiating take {} offer, {}", offer.isBuyOffer() ? "buy" : "sell", takeOfferModel);
|
||||
@ -116,7 +114,6 @@ class CoreTradesService {
|
||||
|
||||
// take offer
|
||||
tradeManager.onTakeOffer(offer.getAmount(),
|
||||
txFeeFromFeeService,
|
||||
takerFee,
|
||||
fundsNeededForTrade,
|
||||
offer,
|
||||
@ -127,6 +124,7 @@ class CoreTradesService {
|
||||
errorMessageHandler
|
||||
);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorMessageHandler.handleErrorMessage(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ package bisq.core.api;
|
||||
import bisq.core.api.model.AddressBalanceInfo;
|
||||
import bisq.core.api.model.BalancesInfo;
|
||||
import bisq.core.api.model.BtcBalanceInfo;
|
||||
import bisq.core.api.model.TxFeeRateInfo;
|
||||
import bisq.core.api.model.XmrBalanceInfo;
|
||||
import bisq.core.app.AppStartupState;
|
||||
import bisq.core.btc.Balances;
|
||||
@ -31,15 +30,12 @@ import bisq.core.btc.setup.WalletsSetup;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.btc.wallet.WalletsManager;
|
||||
import bisq.core.btc.wallet.XmrWalletService;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import bisq.common.Timer;
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.Coin;
|
||||
@ -57,10 +53,6 @@ import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
|
||||
@ -97,8 +89,6 @@ class CoreWalletsService {
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final XmrWalletService xmrWalletService;
|
||||
private final CoinFormatter btcFormatter;
|
||||
private final FeeService feeService;
|
||||
private final Preferences preferences;
|
||||
|
||||
@Nullable
|
||||
private Timer lockTimer;
|
||||
@ -106,8 +96,6 @@ class CoreWalletsService {
|
||||
@Nullable
|
||||
private KeyParameter tempAesKey;
|
||||
|
||||
private final ListeningExecutorService executor = Utilities.getSingleThreadListeningExecutor("CoreWalletsService");
|
||||
|
||||
@Inject
|
||||
public CoreWalletsService(AppStartupState appStartupState,
|
||||
CoreContext coreContext,
|
||||
@ -118,7 +106,6 @@ class CoreWalletsService {
|
||||
BtcWalletService btcWalletService,
|
||||
XmrWalletService xmrWalletService,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
|
||||
FeeService feeService,
|
||||
Preferences preferences) {
|
||||
this.appStartupState = appStartupState;
|
||||
this.coreContext = coreContext;
|
||||
@ -129,8 +116,6 @@ class CoreWalletsService {
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.xmrWalletService = xmrWalletService;
|
||||
this.btcFormatter = btcFormatter;
|
||||
this.feeService = feeService;
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -311,58 +296,6 @@ class CoreWalletsService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void getTxFeeRate(ResultHandler resultHandler) {
|
||||
try {
|
||||
@SuppressWarnings({"unchecked", "Convert2MethodRef"})
|
||||
ListenableFuture<Void> future =
|
||||
(ListenableFuture<Void>) executor.submit(() -> feeService.requestFees());
|
||||
Futures.addCallback(future, new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Void ignored) {
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
log.error("", t);
|
||||
throw new IllegalStateException("could not request fees from fee service", t);
|
||||
}
|
||||
}, MoreExecutors.directExecutor());
|
||||
|
||||
} catch (Exception ex) {
|
||||
log.error("", ex);
|
||||
throw new IllegalStateException("could not request fees from fee service", ex);
|
||||
}
|
||||
}
|
||||
|
||||
void setTxFeeRatePreference(long txFeeRate,
|
||||
ResultHandler resultHandler) {
|
||||
long minFeePerVbyte = feeService.getMinFeePerVByte();
|
||||
if (txFeeRate < minFeePerVbyte)
|
||||
throw new IllegalStateException(
|
||||
format("tx fee rate preference must be >= %d sats/byte", minFeePerVbyte));
|
||||
|
||||
preferences.setUseCustomWithdrawalTxFee(true);
|
||||
Coin satsPerByte = Coin.valueOf(txFeeRate);
|
||||
preferences.setWithdrawalTxFeeInVbytes(satsPerByte.value);
|
||||
getTxFeeRate(resultHandler);
|
||||
}
|
||||
|
||||
void unsetTxFeeRatePreference(ResultHandler resultHandler) {
|
||||
preferences.setUseCustomWithdrawalTxFee(false);
|
||||
getTxFeeRate(resultHandler);
|
||||
}
|
||||
|
||||
TxFeeRateInfo getMostRecentTxFeeRateInfo() {
|
||||
return new TxFeeRateInfo(
|
||||
preferences.isUseCustomWithdrawalTxFee(),
|
||||
preferences.getWithdrawalTxFeeInVbytes(),
|
||||
feeService.getMinFeePerVByte(),
|
||||
feeService.getTxFeePerVbyte().value,
|
||||
feeService.getLastRequest());
|
||||
}
|
||||
|
||||
Transaction getTransaction(String txId) {
|
||||
if (txId.length() != 64)
|
||||
throw new IllegalArgumentException(format("%s is not a transaction id", txId));
|
||||
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* This file is part of Haveno.
|
||||
*
|
||||
* Haveno 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.
|
||||
*
|
||||
* Haveno 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 Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.core.api.model;
|
||||
|
||||
import bisq.common.Payload;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
@EqualsAndHashCode
|
||||
@Getter
|
||||
public class TxFeeRateInfo implements Payload {
|
||||
|
||||
private final boolean useCustomTxFeeRate;
|
||||
private final long customTxFeeRate;
|
||||
private final long minFeeServiceRate;
|
||||
private final long feeServiceRate;
|
||||
private final long lastFeeServiceRequestTs;
|
||||
|
||||
public TxFeeRateInfo(boolean useCustomTxFeeRate,
|
||||
long customTxFeeRate,
|
||||
long minFeeServiceRate,
|
||||
long feeServiceRate,
|
||||
long lastFeeServiceRequestTs) {
|
||||
this.useCustomTxFeeRate = useCustomTxFeeRate;
|
||||
this.customTxFeeRate = customTxFeeRate;
|
||||
this.minFeeServiceRate = minFeeServiceRate;
|
||||
this.feeServiceRate = feeServiceRate;
|
||||
this.lastFeeServiceRequestTs = lastFeeServiceRequestTs;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// PROTO BUFFER
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public bisq.proto.grpc.TxFeeRateInfo toProtoMessage() {
|
||||
return bisq.proto.grpc.TxFeeRateInfo.newBuilder()
|
||||
.setUseCustomTxFeeRate(useCustomTxFeeRate)
|
||||
.setCustomTxFeeRate(customTxFeeRate)
|
||||
.setMinFeeServiceRate(minFeeServiceRate)
|
||||
.setFeeServiceRate(feeServiceRate)
|
||||
.setLastFeeServiceRequestTs(lastFeeServiceRequestTs)
|
||||
.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static TxFeeRateInfo fromProto(bisq.proto.grpc.TxFeeRateInfo proto) {
|
||||
return new TxFeeRateInfo(proto.getUseCustomTxFeeRate(),
|
||||
proto.getCustomTxFeeRate(),
|
||||
proto.getMinFeeServiceRate(),
|
||||
proto.getFeeServiceRate(),
|
||||
proto.getLastFeeServiceRequestTs());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TxFeeRateInfo{" + "\n" +
|
||||
" useCustomTxFeeRate=" + useCustomTxFeeRate + "\n" +
|
||||
", customTxFeeRate=" + customTxFeeRate + " sats/byte" + "\n" +
|
||||
", minFeeServiceRate=" + minFeeServiceRate + " sats/byte" + "\n" +
|
||||
", feeServiceRate=" + feeServiceRate + " sats/byte" + "\n" +
|
||||
", lastFeeServiceRequestTs=" + lastFeeServiceRequestTs + "\n" +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -1,212 +0,0 @@
|
||||
/*
|
||||
* This file is part of Haveno.
|
||||
*
|
||||
* Haveno 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.
|
||||
*
|
||||
* Haveno 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 Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.core.api.model;
|
||||
|
||||
import bisq.common.Payload;
|
||||
|
||||
import org.bitcoinj.core.Sha256Hash;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@EqualsAndHashCode
|
||||
@Getter
|
||||
public class TxInfo implements Payload {
|
||||
|
||||
// The client cannot see an instance of an org.bitcoinj.core.Transaction. We use the
|
||||
// lighter weight TxInfo proto wrapper instead, containing just enough fields to
|
||||
// view some transaction details. A block explorer or bitcoin-core client can be
|
||||
// used to see more detail.
|
||||
|
||||
private final String txId;
|
||||
private final long inputSum;
|
||||
private final long outputSum;
|
||||
private final long fee;
|
||||
private final int size;
|
||||
private final boolean isPending;
|
||||
private final String memo;
|
||||
|
||||
public TxInfo(TxInfoBuilder builder) {
|
||||
this.txId = builder.txId;
|
||||
this.inputSum = builder.inputSum;
|
||||
this.outputSum = builder.outputSum;
|
||||
this.fee = builder.fee;
|
||||
this.size = builder.size;
|
||||
this.isPending = builder.isPending;
|
||||
this.memo = builder.memo;
|
||||
}
|
||||
|
||||
public static TxInfo toTxInfo(Transaction transaction) {
|
||||
if (transaction == null)
|
||||
throw new IllegalStateException("server created a null transaction");
|
||||
|
||||
if (transaction.getFee() != null)
|
||||
return new TxInfoBuilder()
|
||||
.withTxId(transaction.getTxId().toString())
|
||||
.withInputSum(transaction.getInputSum().value)
|
||||
.withOutputSum(transaction.getOutputSum().value)
|
||||
.withFee(transaction.getFee().value)
|
||||
.withSize(transaction.getMessageSize())
|
||||
.withIsPending(transaction.isPending())
|
||||
.withMemo(transaction.getMemo())
|
||||
.build();
|
||||
else
|
||||
return new TxInfoBuilder()
|
||||
.withTxId(transaction.getTxId().toString())
|
||||
.withInputSum(transaction.getInputSum().value)
|
||||
.withOutputSum(transaction.getOutputSum().value)
|
||||
// Do not set fee == null.
|
||||
.withSize(transaction.getMessageSize())
|
||||
.withIsPending(transaction.isPending())
|
||||
.withMemo(transaction.getMemo())
|
||||
.build();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// PROTO BUFFER
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public bisq.proto.grpc.TxInfo toProtoMessage() {
|
||||
return bisq.proto.grpc.TxInfo.newBuilder()
|
||||
.setTxId(txId)
|
||||
.setInputSum(inputSum)
|
||||
.setOutputSum(outputSum)
|
||||
.setFee(fee)
|
||||
.setSize(size)
|
||||
.setIsPending(isPending)
|
||||
.setMemo(memo == null ? "" : memo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static TxInfo fromProto(bisq.proto.grpc.TxInfo proto) {
|
||||
return new TxInfoBuilder()
|
||||
.withTxId(proto.getTxId())
|
||||
.withInputSum(proto.getInputSum())
|
||||
.withOutputSum(proto.getOutputSum())
|
||||
.withFee(proto.getFee())
|
||||
.withSize(proto.getSize())
|
||||
.withIsPending(proto.getIsPending())
|
||||
.withMemo(proto.getMemo())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static class TxInfoBuilder {
|
||||
private String txId;
|
||||
private long inputSum;
|
||||
private long outputSum;
|
||||
private long fee;
|
||||
private int size;
|
||||
private boolean isPending;
|
||||
private String memo;
|
||||
|
||||
public TxInfoBuilder withTxId(String txId) {
|
||||
this.txId = txId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TxInfoBuilder withInputSum(long inputSum) {
|
||||
this.inputSum = inputSum;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TxInfoBuilder withOutputSum(long outputSum) {
|
||||
this.outputSum = outputSum;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TxInfoBuilder withFee(long fee) {
|
||||
this.fee = fee;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TxInfoBuilder withSize(int size) {
|
||||
this.size = size;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TxInfoBuilder withIsPending(boolean isPending) {
|
||||
this.isPending = isPending;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TxInfoBuilder withMemo(String memo) {
|
||||
this.memo = memo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TxInfo build() {
|
||||
return new TxInfo(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TxInfo{" + "\n" +
|
||||
" txId='" + txId + '\'' + "\n" +
|
||||
", inputSum=" + inputSum + "\n" +
|
||||
", outputSum=" + outputSum + "\n" +
|
||||
", fee=" + fee + "\n" +
|
||||
", size=" + size + "\n" +
|
||||
", isPending=" + isPending + "\n" +
|
||||
", memo='" + memo + '\'' + "\n" +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static String getTransactionDetailString(Transaction tx) {
|
||||
if (tx == null)
|
||||
throw new IllegalArgumentException("Cannot print details for null transaction");
|
||||
|
||||
StringBuilder builder = new StringBuilder("Transaction " + requireNonNull(tx).getTxId() + ":").append("\n");
|
||||
|
||||
builder.append("\tisPending: ").append(tx.isPending()).append("\n");
|
||||
builder.append("\tfee: ").append(tx.getFee()).append("\n");
|
||||
builder.append("\tweight: ").append(tx.getWeight()).append("\n");
|
||||
builder.append("\tVsize: ").append(tx.getVsize()).append("\n");
|
||||
builder.append("\tinputSum: ").append(tx.getInputSum()).append("\n");
|
||||
builder.append("\toutputSum: ").append(tx.getOutputSum()).append("\n");
|
||||
|
||||
Map<Sha256Hash, Integer> appearsInHashes = tx.getAppearsInHashes();
|
||||
if (appearsInHashes != null)
|
||||
builder.append("\tappearsInHashes: yes, count: ").append(appearsInHashes.size()).append("\n");
|
||||
else
|
||||
builder.append("\tappearsInHashes: ").append("no").append("\n");
|
||||
|
||||
builder.append("\tanyOutputSpent: ").append(tx.isAnyOutputSpent()).append("\n");
|
||||
builder.append("\tupdateTime: ").append(tx.getUpdateTime()).append("\n");
|
||||
builder.append("\tincludedInBestChainAt: ").append(tx.getIncludedInBestChainAt()).append("\n");
|
||||
builder.append("\thasWitnesses: ").append(tx.hasWitnesses()).append("\n");
|
||||
builder.append("\tlockTime: ").append(tx.getLockTime()).append("\n");
|
||||
builder.append("\tversion: ").append(tx.getVersion()).append("\n");
|
||||
builder.append("\thasConfidence: ").append(tx.hasConfidence()).append("\n");
|
||||
builder.append("\tsigOpCount: ").append(tx.getSigOpCount()).append("\n");
|
||||
builder.append("\tisTimeLocked: ").append(tx.isTimeLocked()).append("\n");
|
||||
builder.append("\thasRelativeLockTime: ").append(tx.hasRelativeLockTime()).append("\n");
|
||||
builder.append("\tisOptInFullRBF: ").append(tx.isOptInFullRBF()).append("\n");
|
||||
builder.append("\tpurpose: ").append(tx.getPurpose()).append("\n");
|
||||
builder.append("\texchangeRate: ").append(tx.getExchangeRate()).append("\n");
|
||||
builder.append("\tmemo: ").append(tx.getMemo()).append("\n");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@ -33,7 +33,6 @@ import bisq.core.offer.OpenOfferManager;
|
||||
import bisq.core.offer.TriggerPriceService;
|
||||
import bisq.core.payment.AmazonGiftCardAccount;
|
||||
import bisq.core.payment.RevolutAccount;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.mempool.MempoolService;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.support.dispute.arbitration.ArbitrationManager;
|
||||
@ -88,7 +87,6 @@ public class DomainInitialisation {
|
||||
private final RefundAgentManager refundAgentManager;
|
||||
private final PrivateNotificationManager privateNotificationManager;
|
||||
private final P2PService p2PService;
|
||||
private final FeeService feeService;
|
||||
private final TradeStatisticsManager tradeStatisticsManager;
|
||||
private final AccountAgeWitnessService accountAgeWitnessService;
|
||||
private final SignedWitnessService signedWitnessService;
|
||||
@ -122,7 +120,6 @@ public class DomainInitialisation {
|
||||
RefundAgentManager refundAgentManager,
|
||||
PrivateNotificationManager privateNotificationManager,
|
||||
P2PService p2PService,
|
||||
FeeService feeService,
|
||||
TradeStatisticsManager tradeStatisticsManager,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
SignedWitnessService signedWitnessService,
|
||||
@ -154,7 +151,6 @@ public class DomainInitialisation {
|
||||
this.refundAgentManager = refundAgentManager;
|
||||
this.privateNotificationManager = privateNotificationManager;
|
||||
this.p2PService = p2PService;
|
||||
this.feeService = feeService;
|
||||
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||
this.signedWitnessService = signedWitnessService;
|
||||
@ -207,9 +203,6 @@ public class DomainInitialisation {
|
||||
|
||||
p2PService.onAllServicesInitialized();
|
||||
|
||||
feeService.onAllServicesInitialized();
|
||||
|
||||
|
||||
tradeStatisticsManager.onAllServicesInitialized();
|
||||
|
||||
accountAgeWitnessService.onAllServicesInitialized();
|
||||
|
@ -25,7 +25,6 @@ import bisq.core.btc.setup.WalletsSetup;
|
||||
import bisq.core.btc.wallet.WalletsManager;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.OpenOfferManager;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
@ -69,7 +68,6 @@ public class WalletAppSetup {
|
||||
private final WalletsManager walletsManager;
|
||||
private final WalletsSetup walletsSetup;
|
||||
private final CoreMoneroConnectionsService connectionService;
|
||||
private final FeeService feeService;
|
||||
private final Config config;
|
||||
private final Preferences preferences;
|
||||
|
||||
@ -94,14 +92,12 @@ public class WalletAppSetup {
|
||||
WalletsManager walletsManager,
|
||||
WalletsSetup walletsSetup,
|
||||
CoreMoneroConnectionsService connectionService,
|
||||
FeeService feeService,
|
||||
Config config,
|
||||
Preferences preferences) {
|
||||
this.coreContext = coreContext;
|
||||
this.walletsManager = walletsManager;
|
||||
this.walletsSetup = walletsSetup;
|
||||
this.connectionService = connectionService;
|
||||
this.feeService = feeService;
|
||||
this.config = config;
|
||||
this.preferences = preferences;
|
||||
this.useTorForBTC.set(preferences.getUseTorForBitcoinJ());
|
||||
@ -121,9 +117,8 @@ public class WalletAppSetup {
|
||||
ObjectProperty<Throwable> walletServiceException = new SimpleObjectProperty<>();
|
||||
btcInfoBinding = EasyBind.combine(connectionService.downloadPercentageProperty(), // TODO (woodser): update to XMR
|
||||
connectionService.chainHeightProperty(),
|
||||
feeService.feeUpdateCounterProperty(),
|
||||
walletServiceException,
|
||||
(downloadPercentage, chainHeight, feeUpdate, exception) -> {
|
||||
(downloadPercentage, chainHeight, exception) -> {
|
||||
String result;
|
||||
if (exception == null) {
|
||||
double percentage = (double) downloadPercentage;
|
||||
|
@ -29,7 +29,6 @@ import bisq.core.btc.wallet.TradeWalletService;
|
||||
import bisq.core.btc.wallet.XmrWalletService;
|
||||
import bisq.core.provider.ProvidersRepository;
|
||||
import bisq.core.provider.fee.FeeProvider;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
|
||||
import bisq.common.app.AppModule;
|
||||
@ -99,8 +98,6 @@ public class BitcoinModule extends AppModule {
|
||||
bind(ProvidersRepository.class).in(Singleton.class);
|
||||
bind(FeeProvider.class).in(Singleton.class);
|
||||
bind(PriceFeedService.class).in(Singleton.class);
|
||||
bind(FeeService.class).in(Singleton.class);
|
||||
bind(TxFeeEstimationService.class).in(Singleton.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,205 +0,0 @@
|
||||
/*
|
||||
* This file is part of Haveno.
|
||||
*
|
||||
* Haveno 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.
|
||||
*
|
||||
* Haveno 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 Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.core.btc;
|
||||
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.user.Preferences;
|
||||
|
||||
import bisq.common.util.Tuple2;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
/**
|
||||
* Util class for getting the estimated tx fee for maker or taker fee tx.
|
||||
*/
|
||||
@Slf4j
|
||||
public class TxFeeEstimationService {
|
||||
|
||||
// Size/vsize of typical trade txs
|
||||
// Real txs size/vsize may vary in 1 or 2 bytes from the estimated values.
|
||||
// Values calculated with https://gist.github.com/oscarguindzberg/3d1349cb65d9fd9af9de0feaa3fd27ac
|
||||
// legacy fee tx with 1 input, maker/taker fee paid in btc size/vsize = 258
|
||||
// legacy deposit tx without change size/vsize = 381
|
||||
// legacy deposit tx with change size/vsize = 414
|
||||
// legacy payout tx size/vsize = 337
|
||||
// legacy delayed payout tx size/vsize = 302
|
||||
// segwit fee tx with 1 input, maker/taker fee paid in btc vsize = 173
|
||||
// segwit deposit tx without change vsize = 232
|
||||
// segwit deposit tx with change vsize = 263
|
||||
// segwit payout tx vsize = 169
|
||||
// segwit delayed payout tx vsize = 139
|
||||
public static int TYPICAL_TX_WITH_1_INPUT_VSIZE = 175;
|
||||
private static int DEPOSIT_TX_VSIZE = 233;
|
||||
|
||||
private static int MAX_ITERATIONS = 10;
|
||||
|
||||
private final FeeService feeService;
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final Preferences preferences;
|
||||
|
||||
@Inject
|
||||
public TxFeeEstimationService(FeeService feeService,
|
||||
BtcWalletService btcWalletService,
|
||||
Preferences preferences) {
|
||||
|
||||
this.feeService = feeService;
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
public Tuple2<Coin, Integer> getEstimatedFeeAndTxVsizeForTaker(Coin fundsNeededForTrade, Coin tradeFee) {
|
||||
return getEstimatedFeeAndTxVsize(true,
|
||||
fundsNeededForTrade,
|
||||
tradeFee,
|
||||
feeService,
|
||||
btcWalletService,
|
||||
preferences);
|
||||
}
|
||||
|
||||
public Tuple2<Coin, Integer> getEstimatedFeeAndTxVsizeForMaker(Coin reservedFundsForOffer,
|
||||
Coin tradeFee) {
|
||||
return getEstimatedFeeAndTxVsize(false,
|
||||
reservedFundsForOffer,
|
||||
tradeFee,
|
||||
feeService,
|
||||
btcWalletService,
|
||||
preferences);
|
||||
}
|
||||
|
||||
private Tuple2<Coin, Integer> getEstimatedFeeAndTxVsize(boolean isTaker,
|
||||
Coin amount,
|
||||
Coin tradeFee,
|
||||
FeeService feeService,
|
||||
BtcWalletService btcWalletService,
|
||||
Preferences preferences) {
|
||||
Coin txFeePerVbyte = feeService.getTxFeePerVbyte();
|
||||
// We start with min taker fee vsize of 175
|
||||
int estimatedTxVsize = TYPICAL_TX_WITH_1_INPUT_VSIZE;
|
||||
try {
|
||||
estimatedTxVsize = getEstimatedTxVsize(List.of(tradeFee, amount), estimatedTxVsize, txFeePerVbyte, btcWalletService);
|
||||
} catch (InsufficientMoneyException e) {
|
||||
if (isTaker) {
|
||||
// If we cannot do the estimation, we use the vsize o the largest of our txs which is the deposit tx.
|
||||
estimatedTxVsize = DEPOSIT_TX_VSIZE;
|
||||
}
|
||||
log.info("We cannot do the fee estimation because there are not enough funds in the wallet. This is expected " +
|
||||
"if the user pays from an external wallet. In that case we use an estimated tx vsize of {} vbytes.", estimatedTxVsize);
|
||||
}
|
||||
|
||||
Coin txFee;
|
||||
int vsize;
|
||||
if (isTaker) {
|
||||
int averageVsize = (estimatedTxVsize + DEPOSIT_TX_VSIZE) / 2; // deposit tx has about 233 vbytes
|
||||
// We use at least the vsize of the deposit tx to not underpay it.
|
||||
vsize = Math.max(DEPOSIT_TX_VSIZE, averageVsize);
|
||||
txFee = txFeePerVbyte.multiply(vsize);
|
||||
log.info("Fee estimation resulted in a tx vsize of {} vbytes.\n" +
|
||||
"We use an average between the taker fee tx and the deposit tx (233 vbytes) which results in {} vbytes.\n" +
|
||||
"The deposit tx has 233 vbytes, we use that as our min value. Vsize for fee calculation is {} vbytes.\n" +
|
||||
"The tx fee of {} Sat", estimatedTxVsize, averageVsize, vsize, txFee.value);
|
||||
} else {
|
||||
vsize = estimatedTxVsize;
|
||||
txFee = txFeePerVbyte.multiply(vsize);
|
||||
log.info("Fee estimation resulted in a tx vsize of {} vbytes and a tx fee of {} Sat.", vsize, txFee.value);
|
||||
}
|
||||
|
||||
return new Tuple2<>(txFee, vsize);
|
||||
}
|
||||
|
||||
public Tuple2<Coin, Integer> getEstimatedFeeAndTxVsize(Coin amount,
|
||||
BtcWalletService btcWalletService) {
|
||||
Coin txFeePerVbyte = btcWalletService.getTxFeeForWithdrawalPerVbyte();
|
||||
// We start with min taker fee vsize of 175
|
||||
int estimatedTxVsize = TYPICAL_TX_WITH_1_INPUT_VSIZE;
|
||||
try {
|
||||
estimatedTxVsize = getEstimatedTxVsize(List.of(amount), estimatedTxVsize, txFeePerVbyte, btcWalletService);
|
||||
} catch (InsufficientMoneyException e) {
|
||||
log.info("We cannot do the fee estimation because there are not enough funds in the wallet. This is expected " +
|
||||
"if the user pays from an external wallet. In that case we use an estimated tx vsize of {} vbytes.", estimatedTxVsize);
|
||||
}
|
||||
|
||||
Coin txFee = txFeePerVbyte.multiply(estimatedTxVsize);
|
||||
log.info("Fee estimation resulted in a tx vsize of {} vbytes and a tx fee of {} Sat.", estimatedTxVsize, txFee.value);
|
||||
|
||||
return new Tuple2<>(txFee, estimatedTxVsize);
|
||||
}
|
||||
|
||||
// We start with the initialEstimatedTxVsize for a tx with 1 input (175) vbytes and get from BitcoinJ a tx back which
|
||||
// contains the required inputs to fund that tx (outputs + miner fee). The miner fee in that case is based on
|
||||
// the assumption that we only need 1 input. Once we receive back the real tx vsize from the tx BitcoinJ has created
|
||||
// with the required inputs we compare if the vsize is not more then 20% different to our assumed tx vsize. If we are inside
|
||||
// that tolerance we use that tx vsize for our fee estimation, if not (if there has been more then 1 inputs) we
|
||||
// apply the new fee based on the reported tx vsize and request again from BitcoinJ to fill that tx with the inputs
|
||||
// to be sufficiently funded. The algorithm how BitcoinJ selects utxos is complex and contains several aspects
|
||||
// (minimize fee, don't create too many tiny utxos,...). We treat that algorithm as an unknown and it is not
|
||||
// guaranteed that there are more inputs required if we increase the fee (it could be that there is a better
|
||||
// selection of inputs chosen if we have increased the fee and therefore less inputs and smaller tx vsize). As the increased fee might
|
||||
// change the number of inputs we need to repeat that process until we are inside of a certain tolerance. To avoid
|
||||
// potential endless loops we add a counter (we use 10, usually it takes just very few iterations).
|
||||
// Worst case would be that the last vsize we got reported is > 20% off to
|
||||
// the real tx vsize but as fee estimation is anyway a educated guess in the best case we don't worry too much.
|
||||
// If we have underpaid the tx might take longer to get confirmed.
|
||||
@VisibleForTesting
|
||||
static int getEstimatedTxVsize(List<Coin> outputValues,
|
||||
int initialEstimatedTxVsize,
|
||||
Coin txFeePerVbyte,
|
||||
BtcWalletService btcWalletService)
|
||||
throws InsufficientMoneyException {
|
||||
boolean isInTolerance;
|
||||
int estimatedTxVsize = initialEstimatedTxVsize;
|
||||
int realTxVsize;
|
||||
int counter = 0;
|
||||
do {
|
||||
Coin txFee = txFeePerVbyte.multiply(estimatedTxVsize);
|
||||
realTxVsize = btcWalletService.getEstimatedFeeTxVsize(outputValues, txFee);
|
||||
isInTolerance = isInTolerance(estimatedTxVsize, realTxVsize, 0.2);
|
||||
if (!isInTolerance) {
|
||||
estimatedTxVsize = realTxVsize;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
while (!isInTolerance && counter < MAX_ITERATIONS);
|
||||
if (!isInTolerance) {
|
||||
log.warn("We could not find a tx which satisfies our tolerance requirement of 20%. " +
|
||||
"realTxVsize={}, estimatedTxVsize={}",
|
||||
realTxVsize, estimatedTxVsize);
|
||||
}
|
||||
return estimatedTxVsize;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean isInTolerance(int estimatedVsize, int txVsize, double tolerance) {
|
||||
checkArgument(estimatedVsize > 0, "estimatedVsize must be positive");
|
||||
checkArgument(txVsize > 0, "txVsize must be positive");
|
||||
checkArgument(tolerance > 0, "tolerance must be positive");
|
||||
double deviation = Math.abs(1 - ((double) estimatedVsize / (double) txVsize));
|
||||
return deviation <= tolerance;
|
||||
}
|
||||
}
|
@ -25,7 +25,6 @@ import bisq.core.btc.model.AddressEntry;
|
||||
import bisq.core.btc.model.AddressEntryList;
|
||||
import bisq.core.btc.setup.WalletsSetup;
|
||||
import bisq.core.btc.wallet.http.MemPoolSpaceTxBroadcaster;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.user.Preferences;
|
||||
|
||||
import bisq.common.handlers.ErrorMessageHandler;
|
||||
@ -88,11 +87,9 @@ public class BtcWalletService extends WalletService {
|
||||
@Inject
|
||||
public BtcWalletService(WalletsSetup walletsSetup,
|
||||
AddressEntryList addressEntryList,
|
||||
Preferences preferences,
|
||||
FeeService feeService) {
|
||||
Preferences preferences) {
|
||||
super(walletsSetup,
|
||||
preferences,
|
||||
feeService);
|
||||
preferences);
|
||||
|
||||
this.addressEntryList = addressEntryList;
|
||||
|
||||
@ -574,6 +571,10 @@ public class BtcWalletService extends WalletService {
|
||||
// Withdrawal Fee calculation
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Coin getTxFeeForWithdrawalPerVbyte() {
|
||||
throw new RuntimeException("BTC fee estimation removed");
|
||||
}
|
||||
|
||||
public Transaction getFeeEstimationTransaction(String fromAddress,
|
||||
String toAddress,
|
||||
Coin amount,
|
||||
|
@ -24,7 +24,6 @@ import bisq.core.btc.listeners.BalanceListener;
|
||||
import bisq.core.btc.listeners.TxConfidenceListener;
|
||||
import bisq.core.btc.setup.WalletsSetup;
|
||||
import bisq.core.btc.wallet.http.MemPoolSpaceTxBroadcaster;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.user.Preferences;
|
||||
|
||||
import bisq.common.config.Config;
|
||||
@ -117,7 +116,6 @@ import monero.wallet.model.MoneroTxWallet;
|
||||
public abstract class WalletService {
|
||||
protected final WalletsSetup walletsSetup;
|
||||
protected final Preferences preferences;
|
||||
protected final FeeService feeService;
|
||||
protected final NetworkParameters params;
|
||||
private final BisqWalletListener walletEventListener = new BisqWalletListener();
|
||||
private final CopyOnWriteArraySet<AddressConfidenceListener> addressConfidenceListeners = new CopyOnWriteArraySet<>();
|
||||
@ -140,11 +138,9 @@ public abstract class WalletService {
|
||||
|
||||
@Inject
|
||||
WalletService(WalletsSetup walletsSetup,
|
||||
Preferences preferences,
|
||||
FeeService feeService) {
|
||||
Preferences preferences) {
|
||||
this.walletsSetup = walletsSetup;
|
||||
this.preferences = preferences;
|
||||
this.feeService = feeService;
|
||||
|
||||
params = walletsSetup.getParams();
|
||||
|
||||
@ -519,14 +515,6 @@ public abstract class WalletService {
|
||||
return getBalanceForAddress(getAddressFromOutput(output));
|
||||
}
|
||||
|
||||
public Coin getTxFeeForWithdrawalPerVbyte() {
|
||||
Coin fee = (preferences.isUseCustomWithdrawalTxFee()) ?
|
||||
Coin.valueOf(preferences.getWithdrawalTxFeeInVbytes()) :
|
||||
feeService.getTxFeePerVbyte();
|
||||
log.info("tx fee = " + fee.toFriendlyString());
|
||||
return fee;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Tx outputs
|
||||
@ -578,7 +566,6 @@ public abstract class WalletService {
|
||||
throws InsufficientMoneyException, AddressFormatException {
|
||||
SendRequest sendRequest = SendRequest.emptyWallet(Address.fromString(params, toAddress));
|
||||
sendRequest.fee = Coin.ZERO;
|
||||
sendRequest.feePerKb = getTxFeeForWithdrawalPerVbyte().multiply(1000);
|
||||
sendRequest.aesKey = aesKey;
|
||||
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
|
||||
printTx("empty btc wallet", sendResult.tx);
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
package bisq.core.offer;
|
||||
|
||||
import bisq.core.btc.TxFeeEstimationService;
|
||||
import bisq.core.btc.wallet.Restrictions;
|
||||
import bisq.core.btc.wallet.XmrWalletService;
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
@ -38,7 +37,6 @@ import bisq.network.p2p.P2PService;
|
||||
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.crypto.PubKeyRingProvider;
|
||||
import bisq.common.util.Tuple2;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
@ -59,7 +57,6 @@ import static bisq.core.payment.payload.PaymentMethod.HAL_CASH_ID;
|
||||
@Singleton
|
||||
public class CreateOfferService {
|
||||
private final OfferUtil offerUtil;
|
||||
private final TxFeeEstimationService txFeeEstimationService;
|
||||
private final PriceFeedService priceFeedService;
|
||||
private final P2PService p2PService;
|
||||
private final PubKeyRingProvider pubKeyRingProvider;
|
||||
@ -75,7 +72,6 @@ public class CreateOfferService {
|
||||
|
||||
@Inject
|
||||
public CreateOfferService(OfferUtil offerUtil,
|
||||
TxFeeEstimationService txFeeEstimationService,
|
||||
PriceFeedService priceFeedService,
|
||||
P2PService p2PService,
|
||||
PubKeyRingProvider pubKeyRingProvider,
|
||||
@ -84,7 +80,6 @@ public class CreateOfferService {
|
||||
TradeStatisticsManager tradeStatisticsManager,
|
||||
ArbitratorManager arbitratorManager) {
|
||||
this.offerUtil = offerUtil;
|
||||
this.txFeeEstimationService = txFeeEstimationService;
|
||||
this.priceFeedService = priceFeedService;
|
||||
this.p2PService = p2PService;
|
||||
this.pubKeyRingProvider = pubKeyRingProvider;
|
||||
@ -227,18 +222,6 @@ public class CreateOfferService {
|
||||
return offer;
|
||||
}
|
||||
|
||||
public Tuple2<Coin, Integer> getEstimatedFeeAndTxVsize(Coin amount,
|
||||
OfferDirection direction,
|
||||
double buyerSecurityDeposit,
|
||||
double sellerSecurityDeposit) {
|
||||
Coin reservedFundsForOffer = getReservedFundsForOffer(direction,
|
||||
amount,
|
||||
buyerSecurityDeposit,
|
||||
sellerSecurityDeposit);
|
||||
return txFeeEstimationService.getEstimatedFeeAndTxVsizeForMaker(reservedFundsForOffer,
|
||||
offerUtil.getMakerFee(amount));
|
||||
}
|
||||
|
||||
public Coin getReservedFundsForOffer(OfferDirection direction,
|
||||
Coin amount,
|
||||
double buyerSecurityDeposit,
|
||||
|
@ -27,9 +27,9 @@ import bisq.core.monetary.Volume;
|
||||
import bisq.core.payment.CashByMailAccount;
|
||||
import bisq.core.payment.F2FAccount;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.MarketPrice;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.statistics.ReferralIdService;
|
||||
import bisq.core.user.AutoConfirmSettings;
|
||||
import bisq.core.user.Preferences;
|
||||
@ -191,8 +191,8 @@ public class OfferUtil {
|
||||
@Nullable
|
||||
public Coin getTakerFee(@Nullable Coin amount) {
|
||||
if (amount != null) {
|
||||
Coin feePerBtc = CoinUtil.getFeePerBtc(FeeService.getTakerFeePerBtc(), amount);
|
||||
return CoinUtil.maxCoin(feePerBtc, FeeService.getMinTakerFee());
|
||||
Coin feePerBtc = CoinUtil.getFeePerBtc(HavenoUtils.getTakerFeePerBtc(), amount);
|
||||
return CoinUtil.maxCoin(feePerBtc, HavenoUtils.getMinTakerFee());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
|
||||
import bisq.common.taskrunner.Model;
|
||||
@ -37,8 +36,6 @@ import org.bitcoinj.core.Coin;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -60,7 +57,6 @@ public class TakeOfferModel implements Model {
|
||||
// Immutable
|
||||
private final AccountAgeWitnessService accountAgeWitnessService;
|
||||
private final XmrWalletService xmrWalletService;
|
||||
private final FeeService feeService;
|
||||
private final OfferUtil offerUtil;
|
||||
private final PriceFeedService priceFeedService;
|
||||
|
||||
@ -75,11 +71,6 @@ public class TakeOfferModel implements Model {
|
||||
private Coin securityDeposit;
|
||||
private boolean useSavingsWallet;
|
||||
|
||||
// Use an average of a typical trade fee tx with 1 input, deposit tx and payout tx.
|
||||
private final int feeTxVsize = 192; // (175+233+169)/3
|
||||
private Coin txFeePerVbyteFromFeeService;
|
||||
@Getter
|
||||
private Coin txFeeFromFeeService;
|
||||
@Getter
|
||||
private Coin takerFee;
|
||||
@Getter
|
||||
@ -98,12 +89,10 @@ public class TakeOfferModel implements Model {
|
||||
@Inject
|
||||
public TakeOfferModel(AccountAgeWitnessService accountAgeWitnessService,
|
||||
XmrWalletService xmrWalletService,
|
||||
FeeService feeService,
|
||||
OfferUtil offerUtil,
|
||||
PriceFeedService priceFeedService) {
|
||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||
this.xmrWalletService = xmrWalletService;
|
||||
this.feeService = feeService;
|
||||
this.offerUtil = offerUtil;
|
||||
this.priceFeedService = priceFeedService;
|
||||
}
|
||||
@ -124,7 +113,6 @@ public class TakeOfferModel implements Model {
|
||||
: offer.getSellerSecurityDeposit();
|
||||
this.takerFee = offerUtil.getTakerFee(amount);
|
||||
|
||||
calculateTxFees();
|
||||
calculateVolume();
|
||||
calculateTotalToPay();
|
||||
offer.resetState();
|
||||
@ -137,46 +125,12 @@ public class TakeOfferModel implements Model {
|
||||
// empty
|
||||
}
|
||||
|
||||
private void calculateTxFees() {
|
||||
// Taker pays 3 times the tx fee (taker fee, deposit, payout) because the mining
|
||||
// fee might be different when maker created the offer and reserved his funds.
|
||||
// Taker creates at least taker fee and deposit tx at nearly the same moment.
|
||||
// Just the payout will be later and still could lead to issues if the required
|
||||
// fee changed a lot in the meantime. using RBF and/or multiple batch-signed
|
||||
// payout tx with different fees might be an option but RBF is not supported yet
|
||||
// in BitcoinJ and batched txs would add more complexity to the trade protocol.
|
||||
|
||||
// A typical trade fee tx has about 175 vbytes (if one input). The trade txs has
|
||||
// about 169-263 vbytes. We use 192 as a average value.
|
||||
|
||||
// Fee calculations:
|
||||
// Trade fee tx: 175 vbytes (1 input)
|
||||
// Deposit tx: 233 vbytes (1 MS output+ OP_RETURN) - 263 vbytes
|
||||
// (1 MS output + OP_RETURN + change in case of smaller trade amount)
|
||||
// Payout tx: 169 vbytes
|
||||
// Disputed payout tx: 139 vbytes
|
||||
|
||||
txFeePerVbyteFromFeeService = getTxFeePerVbyte();
|
||||
txFeeFromFeeService = offerUtil.getTxFeeByVsize(txFeePerVbyteFromFeeService, feeTxVsize);
|
||||
log.info("{} txFeePerVbyte = {}", feeService.getClass().getSimpleName(), txFeePerVbyteFromFeeService);
|
||||
}
|
||||
|
||||
private Coin getTxFeePerVbyte() {
|
||||
try {
|
||||
CompletableFuture<Void> feeRequestFuture = CompletableFuture.runAsync(feeService::requestFees);
|
||||
feeRequestFuture.get(); // Block until async fee request is complete.
|
||||
return feeService.getTxFeePerVbyte();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
throw new IllegalStateException("Could not request fees from fee service.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateTotalToPay() {
|
||||
// Taker pays 2 times the tx fee because the mining fee might be different when
|
||||
// maker created the offer and reserved his funds, so that would not work well
|
||||
// with dynamic fees. The mining fee for the takeOfferFee tx is deducted from
|
||||
// the createOfferFee and not visible to the trader.
|
||||
Coin feeAndSecDeposit = getTotalTxFee().add(securityDeposit).add(takerFee);
|
||||
Coin feeAndSecDeposit = securityDeposit.add(takerFee);
|
||||
|
||||
totalToPayAsCoin = offer.isBuyOffer()
|
||||
? feeAndSecDeposit.add(amount)
|
||||
@ -212,35 +166,10 @@ public class TakeOfferModel implements Model {
|
||||
offer.getMirroredDirection());
|
||||
}
|
||||
|
||||
public Coin getTotalTxFee() {
|
||||
return txFeeFromFeeService.add(getTxFeeForDepositTx()).add(getTxFeeForPayoutTx());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Coin getFundsNeededForTrade() {
|
||||
// If taking a buy offer, taker needs to reserve the offer.amt too.
|
||||
return securityDeposit
|
||||
.add(getTxFeeForDepositTx())
|
||||
.add(getTxFeeForPayoutTx())
|
||||
.add(offer.isBuyOffer() ? amount : ZERO);
|
||||
}
|
||||
|
||||
private Coin getTxFeeForDepositTx() {
|
||||
// TODO fix with new trade protocol!
|
||||
// Unfortunately we cannot change that to the correct fees as it would break
|
||||
// backward compatibility. We still might find a way with offer version or app
|
||||
// version checks so lets keep that commented out code as that shows how it
|
||||
// should be.
|
||||
return txFeeFromFeeService;
|
||||
}
|
||||
|
||||
private Coin getTxFeeForPayoutTx() {
|
||||
// TODO fix with new trade protocol!
|
||||
// Unfortunately we cannot change that to the correct fees as it would break
|
||||
// backward compatibility. We still might find a way with offer version or app
|
||||
// version checks so lets keep that commented out code as that shows how it
|
||||
// should be.
|
||||
return txFeeFromFeeService;
|
||||
return securityDeposit.add(offer.isBuyOffer() ? amount : ZERO);
|
||||
}
|
||||
|
||||
private void validateModelInputs() {
|
||||
@ -264,8 +193,6 @@ public class TakeOfferModel implements Model {
|
||||
this.takerFee = null;
|
||||
this.totalAvailableBalance = null;
|
||||
this.totalToPayAsCoin = null;
|
||||
this.txFeeFromFeeService = null;
|
||||
this.txFeePerVbyteFromFeeService = null;
|
||||
this.useSavingsWallet = true;
|
||||
this.volume = null;
|
||||
}
|
||||
@ -281,9 +208,6 @@ public class TakeOfferModel implements Model {
|
||||
", addressEntry=" + addressEntry + "\n" +
|
||||
", amount=" + amount + "\n" +
|
||||
", securityDeposit=" + securityDeposit + "\n" +
|
||||
", feeTxVsize=" + feeTxVsize + "\n" +
|
||||
", txFeePerVbyteFromFeeService=" + txFeePerVbyteFromFeeService + "\n" +
|
||||
", txFeeFromFeeService=" + txFeeFromFeeService + "\n" +
|
||||
", takerFee=" + takerFee + "\n" +
|
||||
", totalToPayAsCoin=" + totalToPayAsCoin + "\n" +
|
||||
", missingCoin=" + missingCoin + "\n" +
|
||||
|
@ -1,191 +0,0 @@
|
||||
/*
|
||||
* This file is part of Haveno.
|
||||
*
|
||||
* Haveno 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.
|
||||
*
|
||||
* Haveno 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 Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.core.provider.fee;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.config.Config;
|
||||
import bisq.common.handlers.FaultHandler;
|
||||
import bisq.common.util.Tuple2;
|
||||
|
||||
import org.bitcoinj.utils.MonetaryFormat;
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.ReadOnlyIntegerProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import bisq.core.util.ParsingUtils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@Slf4j
|
||||
public class FeeService {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Static
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Miner fees are between 1-600 sat/vbyte. We try to stay on the safe side. BTC_DEFAULT_TX_FEE is only used if our
|
||||
// fee service would not deliver data.
|
||||
private static final long BTC_DEFAULT_TX_FEE = 50;
|
||||
private static final long MIN_PAUSE_BETWEEN_REQUESTS_IN_MIN = 2;
|
||||
private static final MonetaryFormat btcCoinFormat = Config.baseCurrencyNetworkParameters().getMonetaryFormat();
|
||||
|
||||
|
||||
public static Coin getMakerFeePerBtc() {
|
||||
return ParsingUtils.parseToCoin("0.001", btcCoinFormat);
|
||||
}
|
||||
|
||||
public static Coin getMinMakerFee() {
|
||||
return ParsingUtils.parseToCoin("0.00005", btcCoinFormat);
|
||||
}
|
||||
|
||||
public static Coin getTakerFeePerBtc() {
|
||||
return ParsingUtils.parseToCoin("0.003", btcCoinFormat);
|
||||
}
|
||||
|
||||
public static Coin getMinTakerFee() {
|
||||
return ParsingUtils.parseToCoin("0.00005", btcCoinFormat);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Class fields
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
private final FeeProvider feeProvider;
|
||||
private final IntegerProperty feeUpdateCounter = new SimpleIntegerProperty(0);
|
||||
private long txFeePerVbyte = BTC_DEFAULT_TX_FEE;
|
||||
private Map<String, Long> timeStampMap;
|
||||
@Getter
|
||||
private long lastRequest;
|
||||
@Getter
|
||||
private long minFeePerVByte;
|
||||
private long epochInSecondAtLastRequest;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public FeeService(FeeProvider feeProvider) {
|
||||
this.feeProvider = feeProvider;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void onAllServicesInitialized() {
|
||||
minFeePerVByte = Config.baseCurrencyNetwork().getDefaultMinFeePerVbyte();
|
||||
|
||||
requestFees();
|
||||
|
||||
// We update all 5 min.
|
||||
UserThread.runPeriodically(this::requestFees, 5, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
|
||||
public void requestFees() {
|
||||
requestFees(null, null);
|
||||
}
|
||||
|
||||
public void requestFees(Runnable resultHandler) {
|
||||
requestFees(resultHandler, null);
|
||||
}
|
||||
|
||||
public void requestFees(@Nullable Runnable resultHandler, @Nullable FaultHandler faultHandler) {
|
||||
long now = Instant.now().getEpochSecond();
|
||||
// We all requests only each 2 minutes
|
||||
if (now - lastRequest > MIN_PAUSE_BETWEEN_REQUESTS_IN_MIN * 60) {
|
||||
lastRequest = now;
|
||||
FeeRequest feeRequest = new FeeRequest();
|
||||
SettableFuture<Tuple2<Map<String, Long>, Map<String, Long>>> future = feeRequest.getFees(feeProvider);
|
||||
Futures.addCallback(future, new FutureCallback<Tuple2<Map<String, Long>, Map<String, Long>>>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Tuple2<Map<String, Long>, Map<String, Long>> result) {
|
||||
UserThread.execute(() -> {
|
||||
checkNotNull(result, "Result must not be null at getFees");
|
||||
timeStampMap = result.first;
|
||||
epochInSecondAtLastRequest = timeStampMap.get(Config.BTC_FEES_TS);
|
||||
final Map<String, Long> map = result.second;
|
||||
txFeePerVbyte = map.get(Config.BTC_TX_FEE);
|
||||
minFeePerVByte = map.get(Config.BTC_MIN_TX_FEE);
|
||||
|
||||
if (txFeePerVbyte < minFeePerVByte) {
|
||||
log.warn("The delivered fee of {} sat/vbyte is smaller than the min. default fee of {} sat/vbyte", txFeePerVbyte, minFeePerVByte);
|
||||
txFeePerVbyte = minFeePerVByte;
|
||||
}
|
||||
|
||||
feeUpdateCounter.set(feeUpdateCounter.get() + 1);
|
||||
log.info("BTC tx fee: txFeePerVbyte={} minFeePerVbyte={}", txFeePerVbyte, minFeePerVByte);
|
||||
if (resultHandler != null)
|
||||
resultHandler.run();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable throwable) {
|
||||
log.warn("Could not load fees. feeProvider={}, error={}", feeProvider.toString(), throwable.toString());
|
||||
if (faultHandler != null)
|
||||
UserThread.execute(() -> faultHandler.handleFault("Could not load fees", throwable));
|
||||
}
|
||||
}, MoreExecutors.directExecutor());
|
||||
} else {
|
||||
log.debug("We got a requestFees called again before min pause of {} minutes has passed.", MIN_PAUSE_BETWEEN_REQUESTS_IN_MIN);
|
||||
UserThread.execute(() -> {
|
||||
if (resultHandler != null)
|
||||
resultHandler.run();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Coin getTxFee(int vsizeInVbytes) {
|
||||
return getTxFeePerVbyte().multiply(vsizeInVbytes);
|
||||
}
|
||||
|
||||
public Coin getTxFeePerVbyte() {
|
||||
return Coin.valueOf(txFeePerVbyte);
|
||||
}
|
||||
|
||||
public ReadOnlyIntegerProperty feeUpdateCounterProperty() {
|
||||
return feeUpdateCounter;
|
||||
}
|
||||
|
||||
public boolean isFeeAvailable() {
|
||||
return feeUpdateCounter.get() > 0;
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@ import bisq.core.trade.messages.InitTradeRequest;
|
||||
import bisq.core.trade.messages.PaymentReceivedMessage;
|
||||
import bisq.core.trade.messages.PaymentSentMessage;
|
||||
import bisq.core.util.JsonUtil;
|
||||
import bisq.core.util.ParsingUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@ -39,7 +40,7 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import org.bitcoinj.utils.MonetaryFormat;
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
@ -96,11 +97,28 @@ public class HavenoUtils {
|
||||
return atomicUnitsToCentineros(xmrToAtomicUnits(xmr));
|
||||
}
|
||||
|
||||
private static final MonetaryFormat xmrCoinFormat = Config.baseCurrencyNetworkParameters().getMonetaryFormat();
|
||||
|
||||
|
||||
public static Coin getMakerFeePerBtc() {
|
||||
return ParsingUtils.parseToCoin("0.001", xmrCoinFormat);
|
||||
}
|
||||
|
||||
public static Coin getMinMakerFee() {
|
||||
return ParsingUtils.parseToCoin("0.00005", xmrCoinFormat);
|
||||
}
|
||||
|
||||
public static Coin getTakerFeePerBtc() {
|
||||
return ParsingUtils.parseToCoin("0.003", xmrCoinFormat);
|
||||
}
|
||||
|
||||
public static Coin getMinTakerFee() {
|
||||
return ParsingUtils.parseToCoin("0.00005", xmrCoinFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get address to collect trade fees.
|
||||
*
|
||||
* TODO: move to config constants?
|
||||
*
|
||||
* @return the address which collects trade fees
|
||||
*/
|
||||
public static String getTradeFeeAddress() {
|
||||
|
@ -29,7 +29,6 @@ import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.offer.OpenOfferManager;
|
||||
import bisq.core.offer.SignedOffer;
|
||||
import bisq.core.offer.availability.OfferAvailabilityModel;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
|
||||
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
|
||||
@ -458,8 +457,8 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
}
|
||||
|
||||
// compute expected taker fee
|
||||
Coin feePerBtc = CoinUtil.getFeePerBtc(FeeService.getTakerFeePerBtc(), Coin.valueOf(offer.getOfferPayload().getAmount()));
|
||||
Coin takerFee = CoinUtil.maxCoin(feePerBtc, FeeService.getMinTakerFee());
|
||||
Coin feePerBtc = CoinUtil.getFeePerBtc(HavenoUtils.getTakerFeePerBtc(), Coin.valueOf(offer.getOfferPayload().getAmount()));
|
||||
Coin takerFee = CoinUtil.maxCoin(feePerBtc, HavenoUtils.getMinTakerFee());
|
||||
|
||||
// create arbitrator trade
|
||||
trade = new ArbitratorTrade(offer,
|
||||
@ -691,7 +690,6 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
|
||||
// First we check if offer is still available then we create the trade with the protocol
|
||||
public void onTakeOffer(Coin amount,
|
||||
Coin txFee,
|
||||
Coin takerFee,
|
||||
Coin fundsNeededForTrade,
|
||||
Offer offer,
|
||||
|
@ -29,7 +29,6 @@ import bisq.core.locale.GlobalSettings;
|
||||
import bisq.core.locale.TradeCurrency;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.PaymentAccountUtil;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.xmr.MoneroNodeSettings;
|
||||
|
||||
import bisq.network.p2p.network.BridgeAddressProvider;
|
||||
@ -162,7 +161,6 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
||||
|
||||
private final PersistenceManager<PreferencesPayload> persistenceManager;
|
||||
private final Config config;
|
||||
private final FeeService feeService;
|
||||
private final LocalBitcoinNode localBitcoinNode;
|
||||
private final String btcNodesFromOptions;
|
||||
@Getter
|
||||
@ -175,13 +173,11 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
||||
@Inject
|
||||
public Preferences(PersistenceManager<PreferencesPayload> persistenceManager,
|
||||
Config config,
|
||||
FeeService feeService,
|
||||
LocalBitcoinNode localBitcoinNode,
|
||||
@Named(Config.BTC_NODES) String btcNodesFromOptions) {
|
||||
|
||||
this.persistenceManager = persistenceManager;
|
||||
this.config = config;
|
||||
this.feeService = feeService;
|
||||
this.localBitcoinNode = localBitcoinNode;
|
||||
this.btcNodesFromOptions = btcNodesFromOptions;
|
||||
|
||||
@ -837,11 +833,6 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
||||
return prefPayload.getBridgeAddresses();
|
||||
}
|
||||
|
||||
public long getWithdrawalTxFeeInVbytes() {
|
||||
return Math.max(prefPayload.getWithdrawalTxFeeInVbytes(),
|
||||
feeService.getMinFeePerVByte());
|
||||
}
|
||||
|
||||
public List<String> getDefaultXmrTxProofServices() {
|
||||
if (config.useLocalhostForP2P) {
|
||||
return XMR_TX_PROOF_SERVICES_CLEAR_NET;
|
||||
|
@ -20,8 +20,7 @@ package bisq.core.util.coin;
|
||||
import bisq.core.btc.wallet.Restrictions;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.monetary.Volume;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.common.util.MathUtils;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
@ -98,8 +97,8 @@ public class CoinUtil {
|
||||
@Nullable
|
||||
public static Coin getMakerFee(@Nullable Coin amount) {
|
||||
if (amount != null) {
|
||||
Coin feePerBtc = getFeePerBtc(FeeService.getMakerFeePerBtc(), amount);
|
||||
return maxCoin(feePerBtc, FeeService.getMinMakerFee());
|
||||
Coin feePerBtc = getFeePerBtc(HavenoUtils.getMakerFeePerBtc(), amount);
|
||||
return maxCoin(feePerBtc, HavenoUtils.getMinMakerFee());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -1,141 +0,0 @@
|
||||
/*
|
||||
* This file is part of Haveno.
|
||||
*
|
||||
* Haveno 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.
|
||||
*
|
||||
* Haveno 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 Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.core.btc;
|
||||
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class TxFeeEstimationServiceTest {
|
||||
|
||||
@Test
|
||||
public void testGetEstimatedTxVsize_withDefaultTxVsize() throws InsufficientMoneyException {
|
||||
List<Coin> outputValues = List.of(Coin.valueOf(2000), Coin.valueOf(3000));
|
||||
int initialEstimatedTxVsize;
|
||||
Coin txFeePerVbyte;
|
||||
BtcWalletService btcWalletService = mock(BtcWalletService.class);
|
||||
int result;
|
||||
int realTxVsize;
|
||||
Coin txFee;
|
||||
|
||||
initialEstimatedTxVsize = 175;
|
||||
txFeePerVbyte = Coin.valueOf(10);
|
||||
realTxVsize = 175;
|
||||
|
||||
txFee = txFeePerVbyte.multiply(initialEstimatedTxVsize);
|
||||
when(btcWalletService.getEstimatedFeeTxVsize(outputValues, txFee)).thenReturn(realTxVsize);
|
||||
result = TxFeeEstimationService.getEstimatedTxVsize(outputValues, initialEstimatedTxVsize, txFeePerVbyte, btcWalletService);
|
||||
assertEquals(175, result);
|
||||
}
|
||||
|
||||
// FIXME @Bernard could you have a look?
|
||||
@Test
|
||||
@Ignore
|
||||
public void testGetEstimatedTxVsize_withLargeTx() throws InsufficientMoneyException {
|
||||
List<Coin> outputValues = List.of(Coin.valueOf(2000), Coin.valueOf(3000));
|
||||
int initialEstimatedTxVsize;
|
||||
Coin txFeePerVbyte;
|
||||
BtcWalletService btcWalletService = mock(BtcWalletService.class);
|
||||
int result;
|
||||
int realTxVsize;
|
||||
Coin txFee;
|
||||
|
||||
initialEstimatedTxVsize = 175;
|
||||
txFeePerVbyte = Coin.valueOf(10);
|
||||
realTxVsize = 1750;
|
||||
|
||||
txFee = txFeePerVbyte.multiply(initialEstimatedTxVsize);
|
||||
when(btcWalletService.getEstimatedFeeTxVsize(outputValues, txFee)).thenReturn(realTxVsize);
|
||||
|
||||
// repeated calls to getEstimatedFeeTxVsize do not work (returns 0 at second call in loop which cause test to fail)
|
||||
result = TxFeeEstimationService.getEstimatedTxVsize(outputValues, initialEstimatedTxVsize, txFeePerVbyte, btcWalletService);
|
||||
assertEquals(1750, result);
|
||||
}
|
||||
|
||||
// FIXME @Bernard could you have a look?
|
||||
@Test
|
||||
@Ignore
|
||||
public void testGetEstimatedTxVsize_withSmallTx() throws InsufficientMoneyException {
|
||||
List<Coin> outputValues = List.of(Coin.valueOf(2000), Coin.valueOf(3000));
|
||||
int initialEstimatedTxVsize;
|
||||
Coin txFeePerVbyte;
|
||||
BtcWalletService btcWalletService = mock(BtcWalletService.class);
|
||||
int result;
|
||||
int realTxVsize;
|
||||
Coin txFee;
|
||||
|
||||
initialEstimatedTxVsize = 1750;
|
||||
txFeePerVbyte = Coin.valueOf(10);
|
||||
realTxVsize = 175;
|
||||
|
||||
txFee = txFeePerVbyte.multiply(initialEstimatedTxVsize);
|
||||
when(btcWalletService.getEstimatedFeeTxVsize(outputValues, txFee)).thenReturn(realTxVsize);
|
||||
result = TxFeeEstimationService.getEstimatedTxVsize(outputValues, initialEstimatedTxVsize, txFeePerVbyte, btcWalletService);
|
||||
assertEquals(175, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsInTolerance() {
|
||||
int estimatedSize;
|
||||
int txVsize;
|
||||
double tolerance;
|
||||
boolean result;
|
||||
|
||||
estimatedSize = 100;
|
||||
txVsize = 100;
|
||||
tolerance = 0.0001;
|
||||
result = TxFeeEstimationService.isInTolerance(estimatedSize, txVsize, tolerance);
|
||||
assertTrue(result);
|
||||
|
||||
estimatedSize = 100;
|
||||
txVsize = 200;
|
||||
tolerance = 0.2;
|
||||
result = TxFeeEstimationService.isInTolerance(estimatedSize, txVsize, tolerance);
|
||||
assertFalse(result);
|
||||
|
||||
estimatedSize = 120;
|
||||
txVsize = 100;
|
||||
tolerance = 0.2;
|
||||
result = TxFeeEstimationService.isInTolerance(estimatedSize, txVsize, tolerance);
|
||||
assertTrue(result);
|
||||
|
||||
estimatedSize = 200;
|
||||
txVsize = 100;
|
||||
tolerance = 1;
|
||||
result = TxFeeEstimationService.isInTolerance(estimatedSize, txVsize, tolerance);
|
||||
assertTrue(result);
|
||||
|
||||
estimatedSize = 201;
|
||||
txVsize = 100;
|
||||
tolerance = 1;
|
||||
result = TxFeeEstimationService.isInTolerance(estimatedSize, txVsize, tolerance);
|
||||
assertFalse(result);
|
||||
}
|
||||
}
|
@ -61,7 +61,7 @@ public class PreferencesTest {
|
||||
Config config = new Config();
|
||||
LocalBitcoinNode localBitcoinNode = new LocalBitcoinNode(config);
|
||||
preferences = new Preferences(
|
||||
persistenceManager, config, null, localBitcoinNode, null);
|
||||
persistenceManager, config, localBitcoinNode, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -20,7 +20,6 @@ package bisq.daemon.grpc;
|
||||
import bisq.common.UserThread;
|
||||
import bisq.core.api.CoreApi;
|
||||
import bisq.core.api.model.AddressBalanceInfo;
|
||||
import bisq.core.api.model.TxFeeRateInfo;
|
||||
|
||||
import bisq.proto.grpc.GetAddressBalanceReply;
|
||||
import bisq.proto.grpc.GetAddressBalanceRequest;
|
||||
@ -38,26 +37,17 @@ import bisq.proto.grpc.CreateXmrTxRequest;
|
||||
import bisq.proto.grpc.CreateXmrTxReply;
|
||||
import bisq.proto.grpc.RelayXmrTxRequest;
|
||||
import bisq.proto.grpc.RelayXmrTxReply;
|
||||
import bisq.proto.grpc.GetTransactionReply;
|
||||
import bisq.proto.grpc.GetTransactionRequest;
|
||||
import bisq.proto.grpc.GetTxFeeRateReply;
|
||||
import bisq.proto.grpc.GetTxFeeRateRequest;
|
||||
import bisq.proto.grpc.GetXmrSeedReply;
|
||||
import bisq.proto.grpc.GetXmrSeedRequest;
|
||||
import bisq.proto.grpc.LockWalletReply;
|
||||
import bisq.proto.grpc.LockWalletRequest;
|
||||
import bisq.proto.grpc.RemoveWalletPasswordReply;
|
||||
import bisq.proto.grpc.RemoveWalletPasswordRequest;
|
||||
import bisq.proto.grpc.SendBtcReply;
|
||||
import bisq.proto.grpc.SendBtcRequest;
|
||||
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 io.grpc.ServerInterceptor;
|
||||
import io.grpc.stub.StreamObserver;
|
||||
@ -79,7 +69,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static bisq.core.api.model.TxInfo.toTxInfo;
|
||||
import static bisq.core.api.model.XmrTx.toXmrTx;
|
||||
import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
|
||||
import static bisq.proto.grpc.WalletsGrpc.*;
|
||||
@ -247,110 +236,6 @@ class GrpcWalletsService extends WalletsImplBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBtc(SendBtcRequest req,
|
||||
StreamObserver<SendBtcReply> responseObserver) {
|
||||
try {
|
||||
coreApi.sendBtc(req.getAddress(),
|
||||
req.getAmount(),
|
||||
req.getTxFeeRate(),
|
||||
req.getMemo(),
|
||||
new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(Transaction tx) {
|
||||
if (tx != null) {
|
||||
log.info("Successfully published BTC tx: id {}, output sum {} sats, fee {} sats, size {} bytes",
|
||||
tx.getTxId().toString(),
|
||||
tx.getOutputSum(),
|
||||
tx.getFee(),
|
||||
tx.getMessageSize());
|
||||
var reply = SendBtcReply.newBuilder()
|
||||
.setTxInfo(toTxInfo(tx).toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
} else {
|
||||
throw new IllegalStateException("btc transaction is null");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
log.error("", t);
|
||||
throw new IllegalStateException(t);
|
||||
}
|
||||
});
|
||||
} catch (Throwable cause) {
|
||||
exceptionHandler.handleException(log, cause, responseObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getTxFeeRate(GetTxFeeRateRequest req,
|
||||
StreamObserver<GetTxFeeRateReply> responseObserver) {
|
||||
try {
|
||||
coreApi.getTxFeeRate(() -> {
|
||||
TxFeeRateInfo txFeeRateInfo = coreApi.getMostRecentTxFeeRateInfo();
|
||||
var reply = GetTxFeeRateReply.newBuilder()
|
||||
.setTxFeeRateInfo(txFeeRateInfo.toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
});
|
||||
} catch (Throwable cause) {
|
||||
exceptionHandler.handleException(log, cause, responseObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTxFeeRatePreference(SetTxFeeRatePreferenceRequest req,
|
||||
StreamObserver<SetTxFeeRatePreferenceReply> responseObserver) {
|
||||
try {
|
||||
coreApi.setTxFeeRatePreference(req.getTxFeeRatePreference(), () -> {
|
||||
TxFeeRateInfo txFeeRateInfo = coreApi.getMostRecentTxFeeRateInfo();
|
||||
var reply = SetTxFeeRatePreferenceReply.newBuilder()
|
||||
.setTxFeeRateInfo(txFeeRateInfo.toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
});
|
||||
} catch (Throwable cause) {
|
||||
exceptionHandler.handleException(log, cause, responseObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetTxFeeRatePreference(UnsetTxFeeRatePreferenceRequest req,
|
||||
StreamObserver<UnsetTxFeeRatePreferenceReply> responseObserver) {
|
||||
try {
|
||||
coreApi.unsetTxFeeRatePreference(() -> {
|
||||
TxFeeRateInfo txFeeRateInfo = coreApi.getMostRecentTxFeeRateInfo();
|
||||
var reply = UnsetTxFeeRatePreferenceReply.newBuilder()
|
||||
.setTxFeeRateInfo(txFeeRateInfo.toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
});
|
||||
} catch (Throwable cause) {
|
||||
exceptionHandler.handleException(log, cause, responseObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getTransaction(GetTransactionRequest req,
|
||||
StreamObserver<GetTransactionReply> responseObserver) {
|
||||
try {
|
||||
Transaction tx = coreApi.getTransaction(req.getTxId());
|
||||
var reply = GetTransactionReply.newBuilder()
|
||||
.setTxInfo(toTxInfo(tx).toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
} catch (Throwable cause) {
|
||||
exceptionHandler.handleException(log, cause, responseObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWalletPassword(SetWalletPasswordRequest req,
|
||||
StreamObserver<SetWalletPasswordReply> responseObserver) {
|
||||
@ -416,11 +301,6 @@ class GrpcWalletsService extends WalletsImplBase {
|
||||
put(getGetBalancesMethod().getFullMethodName(), new GrpcCallRateMeter(100, SECONDS)); // TODO: why do tests make so many calls to get balances?
|
||||
put(getGetAddressBalanceMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
|
||||
put(getGetFundingAddressesMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
|
||||
put(getSendBtcMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
|
||||
put(getGetTxFeeRateMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
|
||||
put(getSetTxFeeRatePreferenceMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
|
||||
put(getUnsetTxFeeRatePreferenceMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
|
||||
put(getGetTransactionMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
|
||||
|
||||
// Trying to set or remove a wallet password several times before the 1st attempt has time to
|
||||
// persist the change to disk may corrupt the wallet, so allow only 1 attempt per 5 seconds.
|
||||
|
@ -59,7 +59,6 @@ import bisq.core.payment.RevolutAccount;
|
||||
import bisq.core.presentation.BalancePresentation;
|
||||
import bisq.core.presentation.SupportTicketsPresentation;
|
||||
import bisq.core.presentation.TradePresentation;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.user.DontShowAgainLookup;
|
||||
@ -173,7 +172,6 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener
|
||||
WalletPasswordWindow walletPasswordWindow,
|
||||
NotificationCenter notificationCenter,
|
||||
TacWindow tacWindow,
|
||||
FeeService feeService,
|
||||
PriceFeedService priceFeedService,
|
||||
Config config,
|
||||
LocalBitcoinNode localBitcoinNode,
|
||||
@ -210,7 +208,6 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener
|
||||
|
||||
TxIdTextField.setXmrWalletService(xmrWalletService);
|
||||
|
||||
GUIUtil.setFeeService(feeService);
|
||||
GUIUtil.setPreferences(preferences);
|
||||
|
||||
setupHandlers();
|
||||
|
@ -31,7 +31,6 @@ import bisq.core.btc.model.XmrAddressEntry;
|
||||
import bisq.core.btc.setup.WalletsSetup;
|
||||
import bisq.core.btc.wallet.XmrWalletService;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.TradeManager;
|
||||
@ -97,8 +96,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
WalletsSetup walletsSetup,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
|
||||
BtcAddressValidator btcAddressValidator,
|
||||
WalletPasswordWindow walletPasswordWindow,
|
||||
FeeService feeService) {
|
||||
WalletPasswordWindow walletPasswordWindow) {
|
||||
this.xmrWalletService = xmrWalletService;
|
||||
this.tradeManager = tradeManager;
|
||||
this.p2PService = p2PService;
|
||||
|
@ -22,7 +22,6 @@ import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.account.witness.AccountAgeWitnessService;
|
||||
import bisq.core.btc.TxFeeEstimationService;
|
||||
import bisq.core.btc.listeners.XmrBalanceListener;
|
||||
import bisq.core.btc.model.XmrAddressEntry;
|
||||
import bisq.core.btc.wallet.Restrictions;
|
||||
@ -37,7 +36,6 @@ import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.offer.OpenOfferManager;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.handlers.TransactionResultHandler;
|
||||
import bisq.core.trade.statistics.TradeStatistics3;
|
||||
@ -104,7 +102,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
protected final PriceFeedService priceFeedService;
|
||||
final String shortOfferId;
|
||||
private final AccountAgeWitnessService accountAgeWitnessService;
|
||||
private final FeeService feeService;
|
||||
private final CoinFormatter btcFormatter;
|
||||
private final Navigation navigation;
|
||||
private final String offerId;
|
||||
@ -132,7 +129,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
private Coin txFeeFromFeeService = Coin.ZERO;
|
||||
@Getter
|
||||
private boolean marketPriceAvailable;
|
||||
private int feeTxVsize = TxFeeEstimationService.TYPICAL_TX_WITH_1_INPUT_VSIZE;
|
||||
protected boolean allowAmountUpdate = true;
|
||||
private final TradeStatisticsManager tradeStatisticsManager;
|
||||
|
||||
@ -157,7 +153,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
P2PService p2PService,
|
||||
PriceFeedService priceFeedService,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
FeeService feeService,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
|
||||
TradeStatisticsManager tradeStatisticsManager,
|
||||
Navigation navigation) {
|
||||
@ -171,7 +166,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||
this.p2PService = p2PService;
|
||||
this.priceFeedService = priceFeedService;
|
||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||
this.feeService = feeService;
|
||||
this.btcFormatter = btcFormatter;
|
||||
this.navigation = navigation;
|
||||
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||
|
@ -44,9 +44,9 @@ import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.payment.validation.BtcValidator;
|
||||
import bisq.core.payment.validation.FiatVolumeValidator;
|
||||
import bisq.core.payment.validation.SecurityDepositValidator;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.MarketPrice;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.ParsingUtils;
|
||||
@ -999,7 +999,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
||||
dataModel.getMakerFeeInBtc(),
|
||||
dataModel.getAmount().get(),
|
||||
btcFormatter,
|
||||
FeeService.getMinMakerFee());
|
||||
HavenoUtils.getMinMakerFee());
|
||||
}
|
||||
|
||||
public String getMakerFeePercentage() {
|
||||
|
@ -25,7 +25,6 @@ import bisq.core.offer.CreateOfferService;
|
||||
import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.offer.OpenOfferManager;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||
import bisq.core.user.Preferences;
|
||||
@ -58,7 +57,6 @@ class CreateOfferDataModel extends MutableOfferDataModel {
|
||||
P2PService p2PService,
|
||||
PriceFeedService priceFeedService,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
FeeService feeService,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
|
||||
TradeStatisticsManager tradeStatisticsManager,
|
||||
Navigation navigation) {
|
||||
@ -71,7 +69,6 @@ class CreateOfferDataModel extends MutableOfferDataModel {
|
||||
p2PService,
|
||||
priceFeedService,
|
||||
accountAgeWitnessService,
|
||||
feeService,
|
||||
btcFormatter,
|
||||
tradeStatisticsManager,
|
||||
navigation);
|
||||
|
@ -39,9 +39,9 @@ import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.PaymentAccountUtil;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.mempool.MempoolService;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.trade.handlers.TradeResultHandler;
|
||||
import bisq.core.user.Preferences;
|
||||
@ -86,7 +86,6 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
private final TradeManager tradeManager;
|
||||
private final OfferBook offerBook;
|
||||
private final User user;
|
||||
private final FeeService feeService;
|
||||
private final MempoolService mempoolService;
|
||||
private final FilterManager filterManager;
|
||||
final Preferences preferences;
|
||||
@ -95,9 +94,7 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
private final Navigation navigation;
|
||||
private final P2PService p2PService;
|
||||
|
||||
private Coin txFeeFromFeeService;
|
||||
private Coin securityDeposit;
|
||||
// Coin feeFromFundingTx = Coin.NEGATIVE_SATOSHI;
|
||||
|
||||
private Offer offer;
|
||||
|
||||
@ -110,10 +107,6 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
private PaymentAccount paymentAccount;
|
||||
private boolean isTabSelected;
|
||||
Price tradePrice;
|
||||
// Use an average of a typical trade fee tx with 1 input, deposit tx and payout tx.
|
||||
private int feeTxVsize = 192; // (175+233+169)/3
|
||||
private boolean freezeFee;
|
||||
private Coin txFeePerVbyteFromFeeService;
|
||||
@Getter
|
||||
protected final IntegerProperty mempoolStatus = new SimpleIntegerProperty();
|
||||
@Getter
|
||||
@ -130,7 +123,7 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
OfferBook offerBook,
|
||||
OfferUtil offerUtil,
|
||||
XmrWalletService xmrWalletService,
|
||||
User user, FeeService feeService,
|
||||
User user,
|
||||
MempoolService mempoolService,
|
||||
FilterManager filterManager,
|
||||
Preferences preferences,
|
||||
@ -144,7 +137,6 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
this.tradeManager = tradeManager;
|
||||
this.offerBook = offerBook;
|
||||
this.user = user;
|
||||
this.feeService = feeService;
|
||||
this.mempoolService = mempoolService;
|
||||
this.filterManager = filterManager;
|
||||
this.preferences = preferences;
|
||||
@ -212,39 +204,6 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
getBuyerSecurityDeposit() :
|
||||
getSellerSecurityDeposit();
|
||||
|
||||
// Taker pays 3 times the tx fee (taker fee, deposit, payout) because the mining fee might be different when maker created the offer
|
||||
// and reserved his funds. Taker creates at least taker fee and deposit tx at nearly the same moment. Just the payout will
|
||||
// be later and still could lead to issues if the required fee changed a lot in the meantime. using RBF and/or
|
||||
// multiple batch-signed payout tx with different fees might be an option but RBF is not supported yet in BitcoinJ
|
||||
// and batched txs would add more complexity to the trade protocol.
|
||||
|
||||
// A typical trade fee tx has about 175 vbytes (if one input). The trade txs has about 169-263 vbytes.
|
||||
// We use 192 as average value.
|
||||
|
||||
// trade fee tx: 175 vbytes (1 input)
|
||||
// deposit tx: 233 vbytes (1 MS output+ OP_RETURN) - 263 vbytes (1 MS output + OP_RETURN + change in case of smaller trade amount)
|
||||
// payout tx: 169 vbytes
|
||||
// disputed payout tx: 139 vbytes
|
||||
|
||||
// Set the default values (in rare cases if the fee request was not done yet we get the hard coded default values)
|
||||
// But the "take offer" happens usually after that so we should have already the value from the estimation service.
|
||||
txFeePerVbyteFromFeeService = feeService.getTxFeePerVbyte();
|
||||
txFeeFromFeeService = getTxFeeByVsize(feeTxVsize);
|
||||
|
||||
// We request to get the actual estimated fee
|
||||
log.info("Start requestTxFee: txFeeFromFeeService={}", txFeeFromFeeService);
|
||||
feeService.requestFees(() -> {
|
||||
if (!freezeFee) {
|
||||
txFeePerVbyteFromFeeService = feeService.getTxFeePerVbyte();
|
||||
txFeeFromFeeService = getTxFeeByVsize(feeTxVsize);
|
||||
calculateTotalToPay();
|
||||
log.info("Completed requestTxFee: txFeeFromFeeService={}", txFeeFromFeeService);
|
||||
} else {
|
||||
log.debug("We received the tx fee response after we have shown the funding screen and ignore that " +
|
||||
"to avoid that the total funds to pay changes due changed tx fees.");
|
||||
}
|
||||
});
|
||||
|
||||
mempoolStatus.setValue(-1);
|
||||
mempoolService.validateOfferMakerTx(offer.getOfferPayload(), (txValidator -> {
|
||||
mempoolStatus.setValue(txValidator.isFail() ? 0 : 1);
|
||||
@ -271,7 +230,6 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
|
||||
// We don't want that the fee gets updated anymore after we show the funding screen.
|
||||
void onShowPayFundsScreen() {
|
||||
freezeFee = true;
|
||||
calculateTotalToPay();
|
||||
}
|
||||
|
||||
@ -303,7 +261,6 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
// errorMessageHandler is used only in the check availability phase. As soon we have a trade we write the error msg in the trade object as we want to
|
||||
// have it persisted as well.
|
||||
void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||
checkNotNull(txFeeFromFeeService, "txFeeFromFeeService must not be null");
|
||||
checkNotNull(getTakerFee(), "takerFee must not be null");
|
||||
|
||||
Coin fundsNeededForTrade = getFundsNeededForTrade();
|
||||
@ -324,7 +281,6 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
new Popup().warning(Res.get("offerbook.warning.offerWasAlreadyUsedInTrade")).show();
|
||||
} else {
|
||||
tradeManager.onTakeOffer(amount.get(),
|
||||
txFeeFromFeeService,
|
||||
getTakerFee(),
|
||||
fundsNeededForTrade,
|
||||
offer,
|
||||
@ -481,8 +437,8 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
Coin amount = this.amount.get();
|
||||
if (amount != null) {
|
||||
// TODO write unit test for that
|
||||
Coin feePerBtc = CoinUtil.getFeePerBtc(FeeService.getTakerFeePerBtc(), amount);
|
||||
return CoinUtil.maxCoin(feePerBtc, FeeService.getMinTakerFee());
|
||||
Coin feePerBtc = CoinUtil.getFeePerBtc(HavenoUtils.getTakerFeePerBtc(), amount);
|
||||
return CoinUtil.maxCoin(feePerBtc, HavenoUtils.getMinTakerFee());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -493,18 +449,6 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
xmrWalletService.resetAddressEntriesForOpenOffer(offer.getId());
|
||||
}
|
||||
|
||||
// We use the sum of the vsize of the trade fee and the deposit tx to get an average.
|
||||
// Miners will take the trade fee tx if the total fee of both dependent txs are good enough.
|
||||
// With that we avoid that we overpay in case that the trade fee has many inputs and we would apply that fee for the
|
||||
// other 2 txs as well. We still might overpay a bit for the payout tx.
|
||||
private int getAverageVsize(int txVsize) {
|
||||
return (txVsize + 233) / 2;
|
||||
}
|
||||
|
||||
private Coin getTxFeeByVsize(int vsizeInVbytes) {
|
||||
return txFeePerVbyteFromFeeService.multiply(getAverageVsize(vsizeInVbytes));
|
||||
}
|
||||
|
||||
/* private void setFeeFromFundingTx(Coin fee) {
|
||||
feeFromFundingTx = fee;
|
||||
isFeeFromFundingTxSufficient.set(feeFromFundingTx.compareTo(FeePolicy.getMinRequiredFeeForFundingTx()) >= 0);
|
||||
@ -557,23 +501,7 @@ class TakeOfferDataModel extends OfferDataModel {
|
||||
|
||||
@NotNull
|
||||
private Coin getFundsNeededForTrade() {
|
||||
return getSecurityDeposit().add(getTxFeeForDepositTx()).add(getTxFeeForPayoutTx());
|
||||
}
|
||||
|
||||
private Coin getTxFeeForDepositTx() {
|
||||
//TODO fix with new trade protocol!
|
||||
// Unfortunately we cannot change that to the correct fees as it would break backward compatibility
|
||||
// We still might find a way with offer version or app version checks so lets keep that commented out
|
||||
// code as that shows how it should be.
|
||||
return txFeeFromFeeService; //feeService.getTxFee(233);
|
||||
}
|
||||
|
||||
private Coin getTxFeeForPayoutTx() {
|
||||
//TODO fix with new trade protocol!
|
||||
// Unfortunately we cannot change that to the correct fees as it would break backward compatibility
|
||||
// We still might find a way with offer version or app version checks so lets keep that commented out
|
||||
// code as that shows how it should be.
|
||||
return txFeeFromFeeService; //feeService.getTxFee(169);
|
||||
return getSecurityDeposit();
|
||||
}
|
||||
|
||||
public XmrAddressEntry getAddressEntry() {
|
||||
|
@ -38,7 +38,7 @@ import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.payment.validation.BtcValidator;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.VolumeUtil;
|
||||
@ -692,7 +692,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
dataModel.getTakerFeeInBtc(),
|
||||
dataModel.getAmount().get(),
|
||||
btcFormatter,
|
||||
FeeService.getMinMakerFee());
|
||||
HavenoUtils.getMinMakerFee());
|
||||
}
|
||||
|
||||
public String getTakerFeePercentage() {
|
||||
|
@ -31,7 +31,6 @@ import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.offer.OpenOfferManager;
|
||||
import bisq.core.offer.CreateOfferService;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||
import bisq.core.user.Preferences;
|
||||
@ -65,7 +64,6 @@ class DuplicateOfferDataModel extends MutableOfferDataModel {
|
||||
P2PService p2PService,
|
||||
PriceFeedService priceFeedService,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
FeeService feeService,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
|
||||
TradeStatisticsManager tradeStatisticsManager,
|
||||
Navigation navigation) {
|
||||
@ -79,7 +77,6 @@ class DuplicateOfferDataModel extends MutableOfferDataModel {
|
||||
p2PService,
|
||||
priceFeedService,
|
||||
accountAgeWitnessService,
|
||||
feeService,
|
||||
btcFormatter,
|
||||
tradeStatisticsManager,
|
||||
navigation);
|
||||
|
@ -35,7 +35,6 @@ import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.offer.OpenOfferManager;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.proto.persistable.CorePersistenceProtoResolver;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||
import bisq.core.user.Preferences;
|
||||
@ -72,7 +71,6 @@ class EditOfferDataModel extends MutableOfferDataModel {
|
||||
P2PService p2PService,
|
||||
PriceFeedService priceFeedService,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
FeeService feeService,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
|
||||
CorePersistenceProtoResolver corePersistenceProtoResolver,
|
||||
TradeStatisticsManager tradeStatisticsManager,
|
||||
@ -87,7 +85,6 @@ class EditOfferDataModel extends MutableOfferDataModel {
|
||||
p2PService,
|
||||
priceFeedService,
|
||||
accountAgeWitnessService,
|
||||
feeService,
|
||||
btcFormatter,
|
||||
tradeStatisticsManager,
|
||||
navigation);
|
||||
|
@ -28,12 +28,12 @@ import bisq.core.btc.wallet.Restrictions;
|
||||
import bisq.core.network.MessageState;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.mempool.MempoolService;
|
||||
import bisq.core.trade.ArbitratorTrade;
|
||||
import bisq.core.trade.BuyerTrade;
|
||||
import bisq.core.trade.ClosedTradableManager;
|
||||
import bisq.core.trade.Contract;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.SellerTrade;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.TradeUtil;
|
||||
@ -338,8 +338,8 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
Coin tradeFeeInBTC = dataModel.getTradeFeeInBTC();
|
||||
|
||||
Coin minTradeFee = dataModel.isMaker() ?
|
||||
FeeService.getMinMakerFee() :
|
||||
FeeService.getMinTakerFee();
|
||||
HavenoUtils.getMinMakerFee() :
|
||||
HavenoUtils.getMinTakerFee();
|
||||
|
||||
String percentage = GUIUtil.getPercentageOfTradeAmount(tradeFeeInBTC, trade.getAmount(),
|
||||
minTradeFee);
|
||||
|
@ -25,7 +25,6 @@ import bisq.core.btc.wallet.XmrWalletService;
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.locale.TradeCurrency;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.MarketPrice;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.user.Preferences;
|
||||
@ -88,17 +87,13 @@ public class MarketPricePresentation {
|
||||
@Inject
|
||||
public MarketPricePresentation(XmrWalletService xmrWalletService,
|
||||
PriceFeedService priceFeedService,
|
||||
Preferences preferences,
|
||||
FeeService feeService) {
|
||||
Preferences preferences) {
|
||||
this.priceFeedService = priceFeedService;
|
||||
this.preferences = preferences;
|
||||
|
||||
TxIdTextField.setPreferences(preferences);
|
||||
|
||||
// TODO
|
||||
TxIdTextField.setXmrWalletService(xmrWalletService);
|
||||
|
||||
GUIUtil.setFeeService(feeService);
|
||||
}
|
||||
|
||||
public void setup() {
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
package bisq.desktop.main.settings.preferences;
|
||||
|
||||
import bisq.desktop.app.HavenoApp;
|
||||
import bisq.desktop.common.view.ActivatableViewAndModel;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.AutoTooltipButton;
|
||||
@ -44,7 +43,6 @@ import bisq.core.locale.TradeCurrency;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.payment.validation.BtcValidator;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.user.User;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
@ -121,14 +119,13 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
notifyOnPreReleaseToggle;
|
||||
private int gridRow = 0;
|
||||
private int displayCurrenciesGridRowIndex = 0;
|
||||
private InputTextField transactionFeeInputTextField, ignoreTradersListInputTextField, ignoreDustThresholdInputTextField,
|
||||
private InputTextField ignoreTradersListInputTextField, ignoreDustThresholdInputTextField,
|
||||
autoConfRequiredConfirmationsTf, autoConfServiceAddressTf, autoConfTradeLimitTf, /*referralIdInputTextField,*/
|
||||
rpcUserTextField, blockNotifyPortTextField;
|
||||
private PasswordTextField rpcPwTextField;
|
||||
|
||||
private ChangeListener<Boolean> transactionFeeFocusedListener, autoConfServiceAddressFocusOutListener, autoConfRequiredConfirmationsFocusOutListener;
|
||||
private ChangeListener<Boolean> autoConfServiceAddressFocusOutListener, autoConfRequiredConfirmationsFocusOutListener;
|
||||
private final Preferences preferences;
|
||||
private final FeeService feeService;
|
||||
//private final ReferralIdService referralIdService;
|
||||
private final FilterManager filterManager;
|
||||
private final File storageDir;
|
||||
@ -150,8 +147,6 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
rpcUserListener, rpcPwListener, blockNotifyPortListener,
|
||||
autoConfTradeLimitListener, autoConfServiceAddressListener;
|
||||
private ChangeListener<Boolean> deviationFocusedListener;
|
||||
private ChangeListener<Boolean> useCustomFeeCheckboxListener;
|
||||
private ChangeListener<Number> transactionFeeChangeListener;
|
||||
private final boolean displayStandbyModeFeature;
|
||||
private ChangeListener<Filter> filterChangeListener;
|
||||
|
||||
@ -163,7 +158,6 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
@Inject
|
||||
public PreferencesView(PreferencesViewModel model,
|
||||
Preferences preferences,
|
||||
FeeService feeService,
|
||||
FilterManager filterManager,
|
||||
Config config,
|
||||
User user,
|
||||
@ -173,7 +167,6 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
this.user = user;
|
||||
this.formatter = formatter;
|
||||
this.preferences = preferences;
|
||||
this.feeService = feeService;
|
||||
this.filterManager = filterManager;
|
||||
this.storageDir = storageDir;
|
||||
this.displayStandbyModeFeature = Utilities.isLinux() || Utilities.isOSX() || Utilities.isWindows();
|
||||
@ -238,56 +231,6 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
btcExplorerTextField = btcExp.first;
|
||||
editCustomBtcExplorer = btcExp.second;
|
||||
|
||||
Tuple3<Label, InputTextField, ToggleButton> tuple = addTopLabelInputTextFieldSlideToggleButton(root, ++gridRow,
|
||||
Res.get("setting.preferences.txFee"), Res.get("setting.preferences.useCustomValue"));
|
||||
transactionFeeInputTextField = tuple.second;
|
||||
useCustomFee = tuple.third;
|
||||
|
||||
useCustomFeeCheckboxListener = (observable, oldValue, newValue) -> {
|
||||
preferences.setUseCustomWithdrawalTxFee(newValue);
|
||||
transactionFeeInputTextField.setEditable(newValue);
|
||||
if (!newValue) {
|
||||
transactionFeeInputTextField.setText(String.valueOf(feeService.getTxFeePerVbyte().value));
|
||||
try {
|
||||
preferences.setWithdrawalTxFeeInVbytes(feeService.getTxFeePerVbyte().value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
preferences.setUseCustomWithdrawalTxFee(newValue);
|
||||
};
|
||||
|
||||
transactionFeeFocusedListener = (o, oldValue, newValue) -> {
|
||||
if (oldValue && !newValue) {
|
||||
String estimatedFee = String.valueOf(feeService.getTxFeePerVbyte().value);
|
||||
try {
|
||||
int withdrawalTxFeePerVbyte = Integer.parseInt(transactionFeeInputTextField.getText());
|
||||
final long minFeePerVbyte = feeService.getMinFeePerVByte();
|
||||
if (withdrawalTxFeePerVbyte < minFeePerVbyte) {
|
||||
new Popup().warning(Res.get("setting.preferences.txFeeMin", minFeePerVbyte)).show();
|
||||
transactionFeeInputTextField.setText(estimatedFee);
|
||||
} else if (withdrawalTxFeePerVbyte > 5000) {
|
||||
new Popup().warning(Res.get("setting.preferences.txFeeTooLarge")).show();
|
||||
transactionFeeInputTextField.setText(estimatedFee);
|
||||
} else {
|
||||
preferences.setWithdrawalTxFeeInVbytes(withdrawalTxFeePerVbyte);
|
||||
}
|
||||
} catch (NumberFormatException t) {
|
||||
log.error(t.toString());
|
||||
t.printStackTrace();
|
||||
new Popup().warning(Res.get("validation.integerOnly")).show();
|
||||
transactionFeeInputTextField.setText(estimatedFee);
|
||||
} catch (Throwable t) {
|
||||
log.error(t.toString());
|
||||
t.printStackTrace();
|
||||
new Popup().warning(Res.get("validation.inputError", t.getMessage())).show();
|
||||
transactionFeeInputTextField.setText(estimatedFee);
|
||||
}
|
||||
}
|
||||
};
|
||||
transactionFeeChangeListener = (observable, oldValue, newValue) -> transactionFeeInputTextField.setText(String.valueOf(feeService.getTxFeePerVbyte().value));
|
||||
|
||||
// deviation
|
||||
deviationInputTextField = addInputTextField(root, ++gridRow,
|
||||
Res.get("setting.preferences.deviation"));
|
||||
@ -693,15 +636,6 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void activateGeneralOptions() {
|
||||
boolean useCustomWithdrawalTxFee = preferences.isUseCustomWithdrawalTxFee();
|
||||
useCustomFee.setSelected(useCustomWithdrawalTxFee);
|
||||
|
||||
transactionFeeInputTextField.setEditable(useCustomWithdrawalTxFee);
|
||||
if (!useCustomWithdrawalTxFee) {
|
||||
transactionFeeInputTextField.setText(String.valueOf(feeService.getTxFeePerVbyte().value));
|
||||
feeService.feeUpdateCounterProperty().addListener(transactionFeeChangeListener);
|
||||
}
|
||||
transactionFeeInputTextField.setText(String.valueOf(getTxFeeForWithdrawalPerVbyte()));
|
||||
ignoreTradersListInputTextField.setText(String.join(", ", preferences.getIgnoreTradersList()));
|
||||
/* referralIdService.getOptionalReferralId().ifPresent(referralId -> referralIdInputTextField.setText(referralId));
|
||||
referralIdInputTextField.setPromptText(Res.get("setting.preferences.refererId.prompt"));*/
|
||||
@ -764,21 +698,11 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
deviationInputTextField.textProperty().addListener(deviationListener);
|
||||
deviationInputTextField.focusedProperty().addListener(deviationFocusedListener);
|
||||
|
||||
transactionFeeInputTextField.focusedProperty().addListener(transactionFeeFocusedListener);
|
||||
ignoreTradersListInputTextField.textProperty().addListener(ignoreTradersListListener);
|
||||
useCustomFee.selectedProperty().addListener(useCustomFeeCheckboxListener);
|
||||
//referralIdInputTextField.textProperty().addListener(referralIdListener);
|
||||
ignoreDustThresholdInputTextField.textProperty().addListener(ignoreDustThresholdListener);
|
||||
}
|
||||
|
||||
private Coin getTxFeeForWithdrawalPerVbyte() {
|
||||
Coin fee = (preferences.isUseCustomWithdrawalTxFee()) ?
|
||||
Coin.valueOf(preferences.getWithdrawalTxFeeInVbytes()) :
|
||||
feeService.getTxFeePerVbyte();
|
||||
log.info("tx fee = " + fee.toFriendlyString());
|
||||
return fee;
|
||||
}
|
||||
|
||||
private void activateDisplayCurrencies() {
|
||||
preferredTradeCurrencyComboBox.setItems(tradeCurrencies);
|
||||
preferredTradeCurrencyComboBox.getSelectionModel().select(preferences.getPreferredTradeCurrency());
|
||||
@ -897,11 +821,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
editCustomBtcExplorer.setOnAction(null);
|
||||
deviationInputTextField.textProperty().removeListener(deviationListener);
|
||||
deviationInputTextField.focusedProperty().removeListener(deviationFocusedListener);
|
||||
transactionFeeInputTextField.focusedProperty().removeListener(transactionFeeFocusedListener);
|
||||
if (transactionFeeChangeListener != null)
|
||||
feeService.feeUpdateCounterProperty().removeListener(transactionFeeChangeListener);
|
||||
ignoreTradersListInputTextField.textProperty().removeListener(ignoreTradersListListener);
|
||||
useCustomFee.selectedProperty().removeListener(useCustomFeeCheckboxListener);
|
||||
//referralIdInputTextField.textProperty().removeListener(referralIdListener);
|
||||
ignoreDustThresholdInputTextField.textProperty().removeListener(ignoreDustThresholdListener);
|
||||
}
|
||||
|
@ -41,7 +41,6 @@ import bisq.core.locale.TradeCurrency;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.PaymentAccountList;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.trade.HavenoUtils;
|
||||
import bisq.core.trade.txproof.AssetTxProofResult;
|
||||
import bisq.core.user.DontShowAgainLookup;
|
||||
@ -160,15 +159,10 @@ public class GUIUtil {
|
||||
public final static int AMOUNT_DECIMALS_WITH_ZEROS = 3;
|
||||
public final static int AMOUNT_DECIMALS = 4;
|
||||
|
||||
private static FeeService feeService;
|
||||
private static Preferences preferences;
|
||||
|
||||
public static TradeCurrency TOP_ALTCOIN = CurrencyUtil.getTradeCurrency("ETH").get();
|
||||
|
||||
public static void setFeeService(FeeService feeService) {
|
||||
GUIUtil.feeService = feeService;
|
||||
}
|
||||
|
||||
public static void setPreferences(Preferences preferences) {
|
||||
GUIUtil.preferences = preferences;
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.payment.ClearXchangeAccount;
|
||||
import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.RevolutAccount;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||
import bisq.core.user.Preferences;
|
||||
@ -50,7 +49,6 @@ public class CreateOfferDataModelTest {
|
||||
XmrAddressEntry addressEntry = mock(XmrAddressEntry.class);
|
||||
XmrWalletService btcWalletService = mock(XmrWalletService.class);
|
||||
PriceFeedService priceFeedService = mock(PriceFeedService.class);
|
||||
FeeService feeService = mock(FeeService.class);
|
||||
CreateOfferService createOfferService = mock(CreateOfferService.class);
|
||||
preferences = mock(Preferences.class);
|
||||
offerUtil = mock(OfferUtil.class);
|
||||
@ -72,7 +70,6 @@ public class CreateOfferDataModelTest {
|
||||
null,
|
||||
priceFeedService,
|
||||
null,
|
||||
feeService,
|
||||
null,
|
||||
tradeStats,
|
||||
null);
|
||||
|
@ -32,7 +32,6 @@ import bisq.core.payment.PaymentAccount;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.payment.validation.BtcValidator;
|
||||
import bisq.core.payment.validation.SecurityDepositValidator;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.MarketPrice;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||
@ -84,7 +83,6 @@ public class CreateOfferViewModelTest {
|
||||
final AltcoinValidator altcoinValidator = new AltcoinValidator();
|
||||
final FiatPriceValidator fiatPriceValidator = new FiatPriceValidator();
|
||||
|
||||
FeeService feeService = mock(FeeService.class);
|
||||
XmrAddressEntry addressEntry = mock(XmrAddressEntry.class);
|
||||
XmrWalletService xmrWalletService = mock(XmrWalletService.class);
|
||||
PriceFeedService priceFeedService = mock(PriceFeedService.class);
|
||||
@ -105,7 +103,6 @@ public class CreateOfferViewModelTest {
|
||||
12684.0450,
|
||||
Instant.now().getEpochSecond(),
|
||||
true));
|
||||
when(feeService.getTxFee(anyInt())).thenReturn(Coin.valueOf(1000L));
|
||||
when(user.findFirstPaymentAccountWithCurrency(any())).thenReturn(paymentAccount);
|
||||
when(paymentAccount.getPaymentMethod()).thenReturn(mock(PaymentMethod.class));
|
||||
when(user.getPaymentAccountsAsObservable()).thenReturn(FXCollections.observableSet());
|
||||
@ -124,7 +121,6 @@ public class CreateOfferViewModelTest {
|
||||
null,
|
||||
priceFeedService,
|
||||
accountAgeWitnessService,
|
||||
feeService,
|
||||
coinFormatter,
|
||||
tradeStats,
|
||||
null);
|
||||
|
@ -18,7 +18,6 @@
|
||||
package bisq.desktop.maker;
|
||||
|
||||
import bisq.core.btc.nodes.LocalBitcoinNode;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.user.Preferences;
|
||||
|
||||
import bisq.common.config.Config;
|
||||
@ -35,7 +34,6 @@ public class PreferenceMakers {
|
||||
|
||||
public static final Property<Preferences, PersistenceManager> storage = new Property<>();
|
||||
public static final Property<Preferences, Config> config = new Property<>();
|
||||
public static final Property<Preferences, FeeService> feeService = new Property<>();
|
||||
public static final Property<Preferences, LocalBitcoinNode> localBitcoinNode = new Property<>();
|
||||
public static final Property<Preferences, String> useTorFlagFromOptions = new Property<>();
|
||||
public static final Property<Preferences, String> referralID = new Property<>();
|
||||
@ -43,7 +41,6 @@ public class PreferenceMakers {
|
||||
public static final Instantiator<Preferences> Preferences = lookup -> new Preferences(
|
||||
lookup.valueOf(storage, new SameValueDonor<PersistenceManager>(null)),
|
||||
lookup.valueOf(config, new SameValueDonor<Config>(null)),
|
||||
lookup.valueOf(feeService, new SameValueDonor<FeeService>(null)),
|
||||
lookup.valueOf(localBitcoinNode, new SameValueDonor<LocalBitcoinNode>(null)),
|
||||
lookup.valueOf(useTorFlagFromOptions, new SameValueDonor<String>(null))
|
||||
);
|
||||
|
@ -874,27 +874,6 @@ message ContractInfo {
|
||||
string arbitrator_node_address = 100;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Transactions
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
message TxFeeRateInfo {
|
||||
bool use_custom_tx_fee_rate = 1;
|
||||
uint64 custom_tx_fee_rate = 2;
|
||||
uint64 fee_service_rate = 3;
|
||||
uint64 last_fee_service_request_ts = 4;
|
||||
uint64 min_fee_service_rate = 5;
|
||||
}
|
||||
|
||||
message TxInfo {
|
||||
string tx_id = 1;
|
||||
uint64 input_sum = 2;
|
||||
uint64 output_sum = 3;
|
||||
uint64 fee = 4;
|
||||
int32 size = 5;
|
||||
bool is_pending = 6;
|
||||
string memo = 7;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Wallets
|
||||
@ -917,16 +896,6 @@ service Wallets {
|
||||
}
|
||||
rpc GetAddressBalance (GetAddressBalanceRequest) returns (GetAddressBalanceReply) {
|
||||
}
|
||||
rpc SendBtc (SendBtcRequest) returns (SendBtcReply) {
|
||||
}
|
||||
rpc GetTxFeeRate (GetTxFeeRateRequest) returns (GetTxFeeRateReply) {
|
||||
}
|
||||
rpc SetTxFeeRatePreference (SetTxFeeRatePreferenceRequest) returns (SetTxFeeRatePreferenceReply) {
|
||||
}
|
||||
rpc UnsetTxFeeRatePreference (UnsetTxFeeRatePreferenceRequest) returns (UnsetTxFeeRatePreferenceReply) {
|
||||
}
|
||||
rpc GetTransaction (GetTransactionRequest) returns (GetTransactionReply) {
|
||||
}
|
||||
rpc GetFundingAddresses (GetFundingAddressesRequest) returns (GetFundingAddressesReply) {
|
||||
}
|
||||
rpc SetWalletPassword (SetWalletPasswordRequest) returns (SetWalletPasswordReply) {
|
||||
@ -1038,40 +1007,6 @@ message SendBtcRequest {
|
||||
string memo = 4;
|
||||
}
|
||||
|
||||
message SendBtcReply {
|
||||
TxInfo tx_info = 1;
|
||||
}
|
||||
|
||||
message GetTxFeeRateRequest {
|
||||
}
|
||||
|
||||
message GetTxFeeRateReply {
|
||||
TxFeeRateInfo tx_fee_rate_info = 1;
|
||||
}
|
||||
|
||||
message SetTxFeeRatePreferenceRequest {
|
||||
uint64 tx_fee_rate_preference = 1;
|
||||
}
|
||||
|
||||
message SetTxFeeRatePreferenceReply {
|
||||
TxFeeRateInfo tx_fee_rate_info = 1;
|
||||
}
|
||||
|
||||
message UnsetTxFeeRatePreferenceRequest {
|
||||
}
|
||||
|
||||
message UnsetTxFeeRatePreferenceReply {
|
||||
TxFeeRateInfo tx_fee_rate_info = 1;
|
||||
}
|
||||
|
||||
message GetTransactionRequest {
|
||||
string tx_id = 1;
|
||||
}
|
||||
|
||||
message GetTransactionReply {
|
||||
TxInfo tx_info = 1;
|
||||
}
|
||||
|
||||
message GetFundingAddressesRequest {
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user