remove btc fee service

This commit is contained in:
woodser 2022-12-09 13:20:23 +00:00
parent 3314eac881
commit 31dfdd7710
49 changed files with 66 additions and 1797 deletions

View file

@ -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();
}
}

View file

@ -1,7 +1,6 @@
package bisq.apitest.method.wallet; package bisq.apitest.method.wallet;
import bisq.proto.grpc.BtcBalanceInfo; import bisq.proto.grpc.BtcBalanceInfo;
import bisq.proto.grpc.TxInfo;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -96,49 +95,6 @@ public class BtcWalletTest extends MethodTest {
new TableBuilder(BTC_BALANCE_TBL, btcBalanceInfo).build()); 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 @AfterAll
public static void tearDown() { public static void tearDown() {
tearDownScaffold(); tearDownScaffold();

View file

@ -36,7 +36,6 @@ import static bisq.apitest.config.HavenoAppConfig.seednode;
import bisq.apitest.method.MethodTest; import bisq.apitest.method.MethodTest;
import bisq.apitest.method.wallet.BtcTxFeeRateTest;
import bisq.apitest.method.wallet.BtcWalletTest; import bisq.apitest.method.wallet.BtcWalletTest;
import bisq.apitest.method.wallet.WalletProtectionTest; import bisq.apitest.method.wallet.WalletProtectionTest;
@ -66,7 +65,6 @@ public class WalletTest extends MethodTest {
btcWalletTest.testInitialBtcBalances(testInfo); btcWalletTest.testInitialBtcBalances(testInfo);
btcWalletTest.testFundAlicesBtcWallet(testInfo); btcWalletTest.testFundAlicesBtcWallet(testInfo);
btcWalletTest.testAliceSendBTCToBob(testInfo);
} }
@Test @Test
@ -86,17 +84,6 @@ public class WalletTest extends MethodTest {
walletProtectionTest.testRemoveNewWalletPassword(); 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 @AfterAll
public static void tearDown() { public static void tearDown() {
tearDownScaffold(); tearDownScaffold();

View file

@ -41,7 +41,6 @@ import java.util.List;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static bisq.cli.CurrencyFormat.formatInternalFiatPrice; import static bisq.cli.CurrencyFormat.formatInternalFiatPrice;
import static bisq.cli.CurrencyFormat.formatTxFeeRateInfo;
import static bisq.cli.CurrencyFormat.toSatoshis; import static bisq.cli.CurrencyFormat.toSatoshis;
import static bisq.cli.Method.*; import static bisq.cli.Method.*;
import static bisq.cli.opts.OptLabel.*; import static bisq.cli.opts.OptLabel.*;
@ -228,51 +227,7 @@ public class CliMain {
var memo = opts.getMemo(); var memo = opts.getMemo();
var txInfo = client.sendBtc(address, amount, txFeeRate, memo); throw new RuntimeException("Send BTC not implemented");
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;
} }
case createoffer: { case createoffer: {
var opts = new CreateOfferOptionParser(args).parse(); var opts = new CreateOfferOptionParser(args).parse();

View file

@ -17,8 +17,6 @@
package bisq.cli; package bisq.cli;
import bisq.proto.grpc.TxFeeRateInfo;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import java.text.DecimalFormat; import java.text.DecimalFormat;
@ -76,18 +74,6 @@ public class CurrencyFormat {
return BSQ_FORMAT.format(new BigDecimal(sats).divide(BSQ_SATOSHI_DIVISOR)); 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) { public static String formatInternalFiatPrice(BigDecimal price) {
INTERNAL_FIAT_DECIMAL_FORMAT.setMinimumFractionDigits(4); INTERNAL_FIAT_DECIMAL_FORMAT.setMinimumFractionDigits(4);
INTERNAL_FIAT_DECIMAL_FORMAT.setMaximumFractionDigits(4); INTERNAL_FIAT_DECIMAL_FORMAT.setMaximumFractionDigits(4);

View file

@ -27,8 +27,6 @@ import bisq.proto.grpc.OfferInfo;
import bisq.proto.grpc.RegisterDisputeAgentRequest; import bisq.proto.grpc.RegisterDisputeAgentRequest;
import bisq.proto.grpc.StopRequest; import bisq.proto.grpc.StopRequest;
import bisq.proto.grpc.TradeInfo; import bisq.proto.grpc.TradeInfo;
import bisq.proto.grpc.TxFeeRateInfo;
import bisq.proto.grpc.TxInfo;
import protobuf.PaymentAccount; import protobuf.PaymentAccount;
import protobuf.PaymentAccountForm; import protobuf.PaymentAccountForm;
@ -98,26 +96,6 @@ public final class GrpcClient {
return walletsServiceRequest.getUnusedBtcAddress(); 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, public OfferInfo createFixedPricedOffer(String direction,
String currencyCode, String currencyCode,
long amount, long amount,

View file

@ -17,43 +17,10 @@
package bisq.cli; package bisq.cli;
import bisq.proto.grpc.TxInfo;
import com.google.common.annotations.VisibleForTesting; 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 @VisibleForTesting
public class TransactionFormat { 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());
}
} }

View file

@ -23,18 +23,12 @@ import bisq.proto.grpc.BtcBalanceInfo;
import bisq.proto.grpc.GetAddressBalanceRequest; import bisq.proto.grpc.GetAddressBalanceRequest;
import bisq.proto.grpc.GetBalancesRequest; import bisq.proto.grpc.GetBalancesRequest;
import bisq.proto.grpc.GetFundingAddressesRequest; import bisq.proto.grpc.GetFundingAddressesRequest;
import bisq.proto.grpc.GetTransactionRequest;
import bisq.proto.grpc.GetTxFeeRateRequest;
import bisq.proto.grpc.LockWalletRequest; import bisq.proto.grpc.LockWalletRequest;
import bisq.proto.grpc.MarketPriceRequest; import bisq.proto.grpc.MarketPriceRequest;
import bisq.proto.grpc.RemoveWalletPasswordRequest; import bisq.proto.grpc.RemoveWalletPasswordRequest;
import bisq.proto.grpc.SendBtcRequest; import bisq.proto.grpc.SendBtcRequest;
import bisq.proto.grpc.SetTxFeeRatePreferenceRequest;
import bisq.proto.grpc.SetWalletPasswordRequest; import bisq.proto.grpc.SetWalletPasswordRequest;
import bisq.proto.grpc.TxFeeRateInfo;
import bisq.proto.grpc.TxInfo;
import bisq.proto.grpc.UnlockWalletRequest; import bisq.proto.grpc.UnlockWalletRequest;
import bisq.proto.grpc.UnsetTxFeeRatePreferenceRequest;
import java.util.List; import java.util.List;
@ -95,40 +89,6 @@ public class WalletsServiceRequest {
.getAddress(); .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() { public void lockWallet() {
var request = LockWalletRequest.newBuilder().build(); var request = LockWalletRequest.newBuilder().build();
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored

View file

@ -17,8 +17,6 @@
package bisq.cli.table.builder; package bisq.cli.table.builder;
import bisq.proto.grpc.TxInfo;
import java.util.List; import java.util.List;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -61,25 +59,22 @@ class TransactionTableBuilder extends AbstractTableBuilder {
public Table build() { public Table build() {
// TODO Add 'gettransactions' api method & show multiple tx in the console. // TODO Add 'gettransactions' api method & show multiple tx in the console.
// For now, a tx tbl is only one row. // For now, a tx tbl is only one row.
TxInfo tx = (TxInfo) protos.get(0);
// Declare the columns derived from tx info. // Declare the columns derived from tx info.
@Nullable @Nullable
Column<String> colMemo = tx.getMemo().isEmpty() Column<String> colMemo = null;
? null
: new StringColumn(COL_HEADER_TX_MEMO);
// Populate columns with tx info. // Populate columns with tx info.
colTxId.addRow(tx.getTxId()); colTxId.addRow(null);
colIsConfirmed.addRow(!tx.getIsPending()); colIsConfirmed.addRow(null);
colInputSum.addRow(tx.getInputSum()); colInputSum.addRow(null);
colOutputSum.addRow(tx.getOutputSum()); colOutputSum.addRow(null);
colTxFee.addRow(tx.getFee()); colTxFee.addRow(null);
colTxSize.addRow((long) tx.getSize()); colTxSize.addRow(null);
if (colMemo != null) if (colMemo != null)
colMemo.addRow(tx.getMemo()); colMemo.addRow(null);
// Define and return the table instance with populated columns. // Define and return the table instance with populated columns.

View file

@ -18,7 +18,6 @@ public class GetTransactionCliOutputDiffTest extends AbstractCliTest {
throw new IllegalStateException("Need a single transaction-id program argument."); throw new IllegalStateException("Need a single transaction-id program argument.");
GetTransactionCliOutputDiffTest test = new GetTransactionCliOutputDiffTest(args[0]); GetTransactionCliOutputDiffTest test = new GetTransactionCliOutputDiffTest(args[0]);
test.getTransaction();
} }
private final String transactionId; private final String transactionId;
@ -27,15 +26,4 @@ public class GetTransactionCliOutputDiffTest extends AbstractCliTest {
super(); super();
this.transactionId = transactionId; 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);
}
} }

View file

@ -23,7 +23,6 @@ import bisq.core.api.model.MarketDepthInfo;
import bisq.core.api.model.MarketPriceInfo; import bisq.core.api.model.MarketPriceInfo;
import bisq.core.api.model.PaymentAccountForm; import bisq.core.api.model.PaymentAccountForm;
import bisq.core.api.model.PaymentAccountFormField; import bisq.core.api.model.PaymentAccountFormField;
import bisq.core.api.model.TxFeeRateInfo;
import bisq.core.app.AppStartupState; import bisq.core.app.AppStartupState;
import bisq.core.monetary.Price; import bisq.core.monetary.Price;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
@ -315,24 +314,6 @@ public class CoreApi {
walletsService.sendBtc(address, amount, txFeeRate, memo, callback); 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) { public Transaction getTransaction(String txId) {
return walletsService.getTransaction(txId); return walletsService.getTransaction(txId);
} }

View file

@ -103,12 +103,10 @@ class CoreTradesService {
var useSavingsWallet = true; var useSavingsWallet = true;
// synchronize access to take offer model // TODO (woodser): to avoid synchronizing, don't use stateful model // 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 takerFee;
Coin fundsNeededForTrade; Coin fundsNeededForTrade;
synchronized (takeOfferModel) { synchronized (takeOfferModel) {
takeOfferModel.initModel(offer, paymentAccount, useSavingsWallet); takeOfferModel.initModel(offer, paymentAccount, useSavingsWallet);
txFeeFromFeeService = takeOfferModel.getTxFeeFromFeeService();
takerFee = takeOfferModel.getTakerFee(); takerFee = takeOfferModel.getTakerFee();
fundsNeededForTrade = takeOfferModel.getFundsNeededForTrade(); fundsNeededForTrade = takeOfferModel.getFundsNeededForTrade();
log.info("Initiating take {} offer, {}", offer.isBuyOffer() ? "buy" : "sell", takeOfferModel); log.info("Initiating take {} offer, {}", offer.isBuyOffer() ? "buy" : "sell", takeOfferModel);
@ -116,7 +114,6 @@ class CoreTradesService {
// take offer // take offer
tradeManager.onTakeOffer(offer.getAmount(), tradeManager.onTakeOffer(offer.getAmount(),
txFeeFromFeeService,
takerFee, takerFee,
fundsNeededForTrade, fundsNeededForTrade,
offer, offer,
@ -127,6 +124,7 @@ class CoreTradesService {
errorMessageHandler errorMessageHandler
); );
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();
errorMessageHandler.handleErrorMessage(e.getMessage()); errorMessageHandler.handleErrorMessage(e.getMessage());
} }
} }

View file

@ -20,7 +20,6 @@ package bisq.core.api;
import bisq.core.api.model.AddressBalanceInfo; import bisq.core.api.model.AddressBalanceInfo;
import bisq.core.api.model.BalancesInfo; import bisq.core.api.model.BalancesInfo;
import bisq.core.api.model.BtcBalanceInfo; import bisq.core.api.model.BtcBalanceInfo;
import bisq.core.api.model.TxFeeRateInfo;
import bisq.core.api.model.XmrBalanceInfo; import bisq.core.api.model.XmrBalanceInfo;
import bisq.core.app.AppStartupState; import bisq.core.app.AppStartupState;
import bisq.core.btc.Balances; 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.BtcWalletService;
import bisq.core.btc.wallet.WalletsManager; import bisq.core.btc.wallet.WalletsManager;
import bisq.core.btc.wallet.XmrWalletService; import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.provider.fee.FeeService;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
import bisq.core.util.FormattingUtils; import bisq.core.util.FormattingUtils;
import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinFormatter;
import bisq.common.Timer; import bisq.common.Timer;
import bisq.common.UserThread; import bisq.common.UserThread;
import bisq.common.handlers.ResultHandler;
import bisq.common.util.Utilities;
import org.bitcoinj.core.Address; import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin; 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.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.FutureCallback; 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; import org.bouncycastle.crypto.params.KeyParameter;
@ -97,8 +89,6 @@ class CoreWalletsService {
private final BtcWalletService btcWalletService; private final BtcWalletService btcWalletService;
private final XmrWalletService xmrWalletService; private final XmrWalletService xmrWalletService;
private final CoinFormatter btcFormatter; private final CoinFormatter btcFormatter;
private final FeeService feeService;
private final Preferences preferences;
@Nullable @Nullable
private Timer lockTimer; private Timer lockTimer;
@ -106,8 +96,6 @@ class CoreWalletsService {
@Nullable @Nullable
private KeyParameter tempAesKey; private KeyParameter tempAesKey;
private final ListeningExecutorService executor = Utilities.getSingleThreadListeningExecutor("CoreWalletsService");
@Inject @Inject
public CoreWalletsService(AppStartupState appStartupState, public CoreWalletsService(AppStartupState appStartupState,
CoreContext coreContext, CoreContext coreContext,
@ -118,7 +106,6 @@ class CoreWalletsService {
BtcWalletService btcWalletService, BtcWalletService btcWalletService,
XmrWalletService xmrWalletService, XmrWalletService xmrWalletService,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
FeeService feeService,
Preferences preferences) { Preferences preferences) {
this.appStartupState = appStartupState; this.appStartupState = appStartupState;
this.coreContext = coreContext; this.coreContext = coreContext;
@ -129,8 +116,6 @@ class CoreWalletsService {
this.btcWalletService = btcWalletService; this.btcWalletService = btcWalletService;
this.xmrWalletService = xmrWalletService; this.xmrWalletService = xmrWalletService;
this.btcFormatter = btcFormatter; this.btcFormatter = btcFormatter;
this.feeService = feeService;
this.preferences = preferences;
} }
@Nullable @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) { Transaction getTransaction(String txId) {
if (txId.length() != 64) if (txId.length() != 64)
throw new IllegalArgumentException(format("%s is not a transaction id", txId)); throw new IllegalArgumentException(format("%s is not a transaction id", txId));

View file

@ -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" +
'}';
}
}

View file

@ -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();
}
}

View file

@ -33,7 +33,6 @@ import bisq.core.offer.OpenOfferManager;
import bisq.core.offer.TriggerPriceService; import bisq.core.offer.TriggerPriceService;
import bisq.core.payment.AmazonGiftCardAccount; import bisq.core.payment.AmazonGiftCardAccount;
import bisq.core.payment.RevolutAccount; import bisq.core.payment.RevolutAccount;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.mempool.MempoolService; import bisq.core.provider.mempool.MempoolService;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.support.dispute.arbitration.ArbitrationManager; import bisq.core.support.dispute.arbitration.ArbitrationManager;
@ -88,7 +87,6 @@ public class DomainInitialisation {
private final RefundAgentManager refundAgentManager; private final RefundAgentManager refundAgentManager;
private final PrivateNotificationManager privateNotificationManager; private final PrivateNotificationManager privateNotificationManager;
private final P2PService p2PService; private final P2PService p2PService;
private final FeeService feeService;
private final TradeStatisticsManager tradeStatisticsManager; private final TradeStatisticsManager tradeStatisticsManager;
private final AccountAgeWitnessService accountAgeWitnessService; private final AccountAgeWitnessService accountAgeWitnessService;
private final SignedWitnessService signedWitnessService; private final SignedWitnessService signedWitnessService;
@ -122,7 +120,6 @@ public class DomainInitialisation {
RefundAgentManager refundAgentManager, RefundAgentManager refundAgentManager,
PrivateNotificationManager privateNotificationManager, PrivateNotificationManager privateNotificationManager,
P2PService p2PService, P2PService p2PService,
FeeService feeService,
TradeStatisticsManager tradeStatisticsManager, TradeStatisticsManager tradeStatisticsManager,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
SignedWitnessService signedWitnessService, SignedWitnessService signedWitnessService,
@ -154,7 +151,6 @@ public class DomainInitialisation {
this.refundAgentManager = refundAgentManager; this.refundAgentManager = refundAgentManager;
this.privateNotificationManager = privateNotificationManager; this.privateNotificationManager = privateNotificationManager;
this.p2PService = p2PService; this.p2PService = p2PService;
this.feeService = feeService;
this.tradeStatisticsManager = tradeStatisticsManager; this.tradeStatisticsManager = tradeStatisticsManager;
this.accountAgeWitnessService = accountAgeWitnessService; this.accountAgeWitnessService = accountAgeWitnessService;
this.signedWitnessService = signedWitnessService; this.signedWitnessService = signedWitnessService;
@ -207,9 +203,6 @@ public class DomainInitialisation {
p2PService.onAllServicesInitialized(); p2PService.onAllServicesInitialized();
feeService.onAllServicesInitialized();
tradeStatisticsManager.onAllServicesInitialized(); tradeStatisticsManager.onAllServicesInitialized();
accountAgeWitnessService.onAllServicesInitialized(); accountAgeWitnessService.onAllServicesInitialized();

View file

@ -25,7 +25,6 @@ import bisq.core.btc.setup.WalletsSetup;
import bisq.core.btc.wallet.WalletsManager; import bisq.core.btc.wallet.WalletsManager;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.offer.OpenOfferManager; import bisq.core.offer.OpenOfferManager;
import bisq.core.provider.fee.FeeService;
import bisq.core.trade.TradeManager; import bisq.core.trade.TradeManager;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
import bisq.core.util.FormattingUtils; import bisq.core.util.FormattingUtils;
@ -69,7 +68,6 @@ public class WalletAppSetup {
private final WalletsManager walletsManager; private final WalletsManager walletsManager;
private final WalletsSetup walletsSetup; private final WalletsSetup walletsSetup;
private final CoreMoneroConnectionsService connectionService; private final CoreMoneroConnectionsService connectionService;
private final FeeService feeService;
private final Config config; private final Config config;
private final Preferences preferences; private final Preferences preferences;
@ -94,14 +92,12 @@ public class WalletAppSetup {
WalletsManager walletsManager, WalletsManager walletsManager,
WalletsSetup walletsSetup, WalletsSetup walletsSetup,
CoreMoneroConnectionsService connectionService, CoreMoneroConnectionsService connectionService,
FeeService feeService,
Config config, Config config,
Preferences preferences) { Preferences preferences) {
this.coreContext = coreContext; this.coreContext = coreContext;
this.walletsManager = walletsManager; this.walletsManager = walletsManager;
this.walletsSetup = walletsSetup; this.walletsSetup = walletsSetup;
this.connectionService = connectionService; this.connectionService = connectionService;
this.feeService = feeService;
this.config = config; this.config = config;
this.preferences = preferences; this.preferences = preferences;
this.useTorForBTC.set(preferences.getUseTorForBitcoinJ()); this.useTorForBTC.set(preferences.getUseTorForBitcoinJ());
@ -121,9 +117,8 @@ public class WalletAppSetup {
ObjectProperty<Throwable> walletServiceException = new SimpleObjectProperty<>(); ObjectProperty<Throwable> walletServiceException = new SimpleObjectProperty<>();
btcInfoBinding = EasyBind.combine(connectionService.downloadPercentageProperty(), // TODO (woodser): update to XMR btcInfoBinding = EasyBind.combine(connectionService.downloadPercentageProperty(), // TODO (woodser): update to XMR
connectionService.chainHeightProperty(), connectionService.chainHeightProperty(),
feeService.feeUpdateCounterProperty(),
walletServiceException, walletServiceException,
(downloadPercentage, chainHeight, feeUpdate, exception) -> { (downloadPercentage, chainHeight, exception) -> {
String result; String result;
if (exception == null) { if (exception == null) {
double percentage = (double) downloadPercentage; double percentage = (double) downloadPercentage;

View file

@ -29,7 +29,6 @@ import bisq.core.btc.wallet.TradeWalletService;
import bisq.core.btc.wallet.XmrWalletService; import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.provider.ProvidersRepository; import bisq.core.provider.ProvidersRepository;
import bisq.core.provider.fee.FeeProvider; import bisq.core.provider.fee.FeeProvider;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.common.app.AppModule; import bisq.common.app.AppModule;
@ -99,8 +98,6 @@ public class BitcoinModule extends AppModule {
bind(ProvidersRepository.class).in(Singleton.class); bind(ProvidersRepository.class).in(Singleton.class);
bind(FeeProvider.class).in(Singleton.class); bind(FeeProvider.class).in(Singleton.class);
bind(PriceFeedService.class).in(Singleton.class); bind(PriceFeedService.class).in(Singleton.class);
bind(FeeService.class).in(Singleton.class);
bind(TxFeeEstimationService.class).in(Singleton.class);
} }
} }

View file

@ -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;
}
}

View file

@ -25,7 +25,6 @@ import bisq.core.btc.model.AddressEntry;
import bisq.core.btc.model.AddressEntryList; import bisq.core.btc.model.AddressEntryList;
import bisq.core.btc.setup.WalletsSetup; import bisq.core.btc.setup.WalletsSetup;
import bisq.core.btc.wallet.http.MemPoolSpaceTxBroadcaster; import bisq.core.btc.wallet.http.MemPoolSpaceTxBroadcaster;
import bisq.core.provider.fee.FeeService;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
import bisq.common.handlers.ErrorMessageHandler; import bisq.common.handlers.ErrorMessageHandler;
@ -88,11 +87,9 @@ public class BtcWalletService extends WalletService {
@Inject @Inject
public BtcWalletService(WalletsSetup walletsSetup, public BtcWalletService(WalletsSetup walletsSetup,
AddressEntryList addressEntryList, AddressEntryList addressEntryList,
Preferences preferences, Preferences preferences) {
FeeService feeService) {
super(walletsSetup, super(walletsSetup,
preferences, preferences);
feeService);
this.addressEntryList = addressEntryList; this.addressEntryList = addressEntryList;
@ -574,6 +571,10 @@ public class BtcWalletService extends WalletService {
// Withdrawal Fee calculation // Withdrawal Fee calculation
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public Coin getTxFeeForWithdrawalPerVbyte() {
throw new RuntimeException("BTC fee estimation removed");
}
public Transaction getFeeEstimationTransaction(String fromAddress, public Transaction getFeeEstimationTransaction(String fromAddress,
String toAddress, String toAddress,
Coin amount, Coin amount,

View file

@ -24,7 +24,6 @@ import bisq.core.btc.listeners.BalanceListener;
import bisq.core.btc.listeners.TxConfidenceListener; import bisq.core.btc.listeners.TxConfidenceListener;
import bisq.core.btc.setup.WalletsSetup; import bisq.core.btc.setup.WalletsSetup;
import bisq.core.btc.wallet.http.MemPoolSpaceTxBroadcaster; import bisq.core.btc.wallet.http.MemPoolSpaceTxBroadcaster;
import bisq.core.provider.fee.FeeService;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
import bisq.common.config.Config; import bisq.common.config.Config;
@ -117,7 +116,6 @@ import monero.wallet.model.MoneroTxWallet;
public abstract class WalletService { public abstract class WalletService {
protected final WalletsSetup walletsSetup; protected final WalletsSetup walletsSetup;
protected final Preferences preferences; protected final Preferences preferences;
protected final FeeService feeService;
protected final NetworkParameters params; protected final NetworkParameters params;
private final BisqWalletListener walletEventListener = new BisqWalletListener(); private final BisqWalletListener walletEventListener = new BisqWalletListener();
private final CopyOnWriteArraySet<AddressConfidenceListener> addressConfidenceListeners = new CopyOnWriteArraySet<>(); private final CopyOnWriteArraySet<AddressConfidenceListener> addressConfidenceListeners = new CopyOnWriteArraySet<>();
@ -140,11 +138,9 @@ public abstract class WalletService {
@Inject @Inject
WalletService(WalletsSetup walletsSetup, WalletService(WalletsSetup walletsSetup,
Preferences preferences, Preferences preferences) {
FeeService feeService) {
this.walletsSetup = walletsSetup; this.walletsSetup = walletsSetup;
this.preferences = preferences; this.preferences = preferences;
this.feeService = feeService;
params = walletsSetup.getParams(); params = walletsSetup.getParams();
@ -519,14 +515,6 @@ public abstract class WalletService {
return getBalanceForAddress(getAddressFromOutput(output)); 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 // Tx outputs
@ -578,7 +566,6 @@ public abstract class WalletService {
throws InsufficientMoneyException, AddressFormatException { throws InsufficientMoneyException, AddressFormatException {
SendRequest sendRequest = SendRequest.emptyWallet(Address.fromString(params, toAddress)); SendRequest sendRequest = SendRequest.emptyWallet(Address.fromString(params, toAddress));
sendRequest.fee = Coin.ZERO; sendRequest.fee = Coin.ZERO;
sendRequest.feePerKb = getTxFeeForWithdrawalPerVbyte().multiply(1000);
sendRequest.aesKey = aesKey; sendRequest.aesKey = aesKey;
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest); Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
printTx("empty btc wallet", sendResult.tx); printTx("empty btc wallet", sendResult.tx);

View file

@ -17,7 +17,6 @@
package bisq.core.offer; package bisq.core.offer;
import bisq.core.btc.TxFeeEstimationService;
import bisq.core.btc.wallet.Restrictions; import bisq.core.btc.wallet.Restrictions;
import bisq.core.btc.wallet.XmrWalletService; import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.locale.CurrencyUtil; import bisq.core.locale.CurrencyUtil;
@ -38,7 +37,6 @@ import bisq.network.p2p.P2PService;
import bisq.common.app.Version; import bisq.common.app.Version;
import bisq.common.crypto.PubKeyRingProvider; import bisq.common.crypto.PubKeyRingProvider;
import bisq.common.util.Tuple2;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
@ -59,7 +57,6 @@ import static bisq.core.payment.payload.PaymentMethod.HAL_CASH_ID;
@Singleton @Singleton
public class CreateOfferService { public class CreateOfferService {
private final OfferUtil offerUtil; private final OfferUtil offerUtil;
private final TxFeeEstimationService txFeeEstimationService;
private final PriceFeedService priceFeedService; private final PriceFeedService priceFeedService;
private final P2PService p2PService; private final P2PService p2PService;
private final PubKeyRingProvider pubKeyRingProvider; private final PubKeyRingProvider pubKeyRingProvider;
@ -75,7 +72,6 @@ public class CreateOfferService {
@Inject @Inject
public CreateOfferService(OfferUtil offerUtil, public CreateOfferService(OfferUtil offerUtil,
TxFeeEstimationService txFeeEstimationService,
PriceFeedService priceFeedService, PriceFeedService priceFeedService,
P2PService p2PService, P2PService p2PService,
PubKeyRingProvider pubKeyRingProvider, PubKeyRingProvider pubKeyRingProvider,
@ -84,7 +80,6 @@ public class CreateOfferService {
TradeStatisticsManager tradeStatisticsManager, TradeStatisticsManager tradeStatisticsManager,
ArbitratorManager arbitratorManager) { ArbitratorManager arbitratorManager) {
this.offerUtil = offerUtil; this.offerUtil = offerUtil;
this.txFeeEstimationService = txFeeEstimationService;
this.priceFeedService = priceFeedService; this.priceFeedService = priceFeedService;
this.p2PService = p2PService; this.p2PService = p2PService;
this.pubKeyRingProvider = pubKeyRingProvider; this.pubKeyRingProvider = pubKeyRingProvider;
@ -227,18 +222,6 @@ public class CreateOfferService {
return offer; 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, public Coin getReservedFundsForOffer(OfferDirection direction,
Coin amount, Coin amount,
double buyerSecurityDeposit, double buyerSecurityDeposit,

View file

@ -27,9 +27,9 @@ import bisq.core.monetary.Volume;
import bisq.core.payment.CashByMailAccount; import bisq.core.payment.CashByMailAccount;
import bisq.core.payment.F2FAccount; import bisq.core.payment.F2FAccount;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.MarketPrice; import bisq.core.provider.price.MarketPrice;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.HavenoUtils;
import bisq.core.trade.statistics.ReferralIdService; import bisq.core.trade.statistics.ReferralIdService;
import bisq.core.user.AutoConfirmSettings; import bisq.core.user.AutoConfirmSettings;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
@ -191,8 +191,8 @@ public class OfferUtil {
@Nullable @Nullable
public Coin getTakerFee(@Nullable Coin amount) { public Coin getTakerFee(@Nullable Coin amount) {
if (amount != null) { if (amount != null) {
Coin feePerBtc = CoinUtil.getFeePerBtc(FeeService.getTakerFeePerBtc(), amount); Coin feePerBtc = CoinUtil.getFeePerBtc(HavenoUtils.getTakerFeePerBtc(), amount);
return CoinUtil.maxCoin(feePerBtc, FeeService.getMinTakerFee()); return CoinUtil.maxCoin(feePerBtc, HavenoUtils.getMinTakerFee());
} else { } else {
return null; return null;
} }

View file

@ -27,7 +27,6 @@ import bisq.core.offer.Offer;
import bisq.core.offer.OfferUtil; import bisq.core.offer.OfferUtil;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.common.taskrunner.Model; import bisq.common.taskrunner.Model;
@ -37,8 +36,6 @@ import org.bitcoinj.core.Coin;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -60,7 +57,6 @@ public class TakeOfferModel implements Model {
// Immutable // Immutable
private final AccountAgeWitnessService accountAgeWitnessService; private final AccountAgeWitnessService accountAgeWitnessService;
private final XmrWalletService xmrWalletService; private final XmrWalletService xmrWalletService;
private final FeeService feeService;
private final OfferUtil offerUtil; private final OfferUtil offerUtil;
private final PriceFeedService priceFeedService; private final PriceFeedService priceFeedService;
@ -75,11 +71,6 @@ public class TakeOfferModel implements Model {
private Coin securityDeposit; private Coin securityDeposit;
private boolean useSavingsWallet; 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 @Getter
private Coin takerFee; private Coin takerFee;
@Getter @Getter
@ -98,12 +89,10 @@ public class TakeOfferModel implements Model {
@Inject @Inject
public TakeOfferModel(AccountAgeWitnessService accountAgeWitnessService, public TakeOfferModel(AccountAgeWitnessService accountAgeWitnessService,
XmrWalletService xmrWalletService, XmrWalletService xmrWalletService,
FeeService feeService,
OfferUtil offerUtil, OfferUtil offerUtil,
PriceFeedService priceFeedService) { PriceFeedService priceFeedService) {
this.accountAgeWitnessService = accountAgeWitnessService; this.accountAgeWitnessService = accountAgeWitnessService;
this.xmrWalletService = xmrWalletService; this.xmrWalletService = xmrWalletService;
this.feeService = feeService;
this.offerUtil = offerUtil; this.offerUtil = offerUtil;
this.priceFeedService = priceFeedService; this.priceFeedService = priceFeedService;
} }
@ -124,7 +113,6 @@ public class TakeOfferModel implements Model {
: offer.getSellerSecurityDeposit(); : offer.getSellerSecurityDeposit();
this.takerFee = offerUtil.getTakerFee(amount); this.takerFee = offerUtil.getTakerFee(amount);
calculateTxFees();
calculateVolume(); calculateVolume();
calculateTotalToPay(); calculateTotalToPay();
offer.resetState(); offer.resetState();
@ -137,46 +125,12 @@ public class TakeOfferModel implements Model {
// empty // 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() { private void calculateTotalToPay() {
// Taker pays 2 times the tx fee because the mining fee might be different when // 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 // 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 // with dynamic fees. The mining fee for the takeOfferFee tx is deducted from
// the createOfferFee and not visible to the trader. // the createOfferFee and not visible to the trader.
Coin feeAndSecDeposit = getTotalTxFee().add(securityDeposit).add(takerFee); Coin feeAndSecDeposit = securityDeposit.add(takerFee);
totalToPayAsCoin = offer.isBuyOffer() totalToPayAsCoin = offer.isBuyOffer()
? feeAndSecDeposit.add(amount) ? feeAndSecDeposit.add(amount)
@ -212,35 +166,10 @@ public class TakeOfferModel implements Model {
offer.getMirroredDirection()); offer.getMirroredDirection());
} }
public Coin getTotalTxFee() {
return txFeeFromFeeService.add(getTxFeeForDepositTx()).add(getTxFeeForPayoutTx());
}
@NotNull @NotNull
public Coin getFundsNeededForTrade() { public Coin getFundsNeededForTrade() {
// If taking a buy offer, taker needs to reserve the offer.amt too. // If taking a buy offer, taker needs to reserve the offer.amt too.
return securityDeposit return securityDeposit.add(offer.isBuyOffer() ? amount : ZERO);
.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;
} }
private void validateModelInputs() { private void validateModelInputs() {
@ -264,8 +193,6 @@ public class TakeOfferModel implements Model {
this.takerFee = null; this.takerFee = null;
this.totalAvailableBalance = null; this.totalAvailableBalance = null;
this.totalToPayAsCoin = null; this.totalToPayAsCoin = null;
this.txFeeFromFeeService = null;
this.txFeePerVbyteFromFeeService = null;
this.useSavingsWallet = true; this.useSavingsWallet = true;
this.volume = null; this.volume = null;
} }
@ -281,9 +208,6 @@ public class TakeOfferModel implements Model {
", addressEntry=" + addressEntry + "\n" + ", addressEntry=" + addressEntry + "\n" +
", amount=" + amount + "\n" + ", amount=" + amount + "\n" +
", securityDeposit=" + securityDeposit + "\n" + ", securityDeposit=" + securityDeposit + "\n" +
", feeTxVsize=" + feeTxVsize + "\n" +
", txFeePerVbyteFromFeeService=" + txFeePerVbyteFromFeeService + "\n" +
", txFeeFromFeeService=" + txFeeFromFeeService + "\n" +
", takerFee=" + takerFee + "\n" + ", takerFee=" + takerFee + "\n" +
", totalToPayAsCoin=" + totalToPayAsCoin + "\n" + ", totalToPayAsCoin=" + totalToPayAsCoin + "\n" +
", missingCoin=" + missingCoin + "\n" + ", missingCoin=" + missingCoin + "\n" +

View file

@ -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;
}
}

View file

@ -27,6 +27,7 @@ import bisq.core.trade.messages.InitTradeRequest;
import bisq.core.trade.messages.PaymentReceivedMessage; import bisq.core.trade.messages.PaymentReceivedMessage;
import bisq.core.trade.messages.PaymentSentMessage; import bisq.core.trade.messages.PaymentSentMessage;
import bisq.core.util.JsonUtil; import bisq.core.util.JsonUtil;
import bisq.core.util.ParsingUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -39,7 +40,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.MonetaryFormat;
import com.google.common.base.CaseFormat; import com.google.common.base.CaseFormat;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
@ -95,12 +96,29 @@ public class HavenoUtils {
public static long xmrToCentineros(double xmr) { public static long xmrToCentineros(double xmr) {
return atomicUnitsToCentineros(xmrToAtomicUnits(xmr)); 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. * Get address to collect trade fees.
* *
* TODO: move to config constants?
*
* @return the address which collects trade fees * @return the address which collects trade fees
*/ */
public static String getTradeFeeAddress() { public static String getTradeFeeAddress() {

View file

@ -29,7 +29,6 @@ import bisq.core.offer.OpenOffer;
import bisq.core.offer.OpenOfferManager; import bisq.core.offer.OpenOfferManager;
import bisq.core.offer.SignedOffer; import bisq.core.offer.SignedOffer;
import bisq.core.offer.availability.OfferAvailabilityModel; import bisq.core.offer.availability.OfferAvailabilityModel;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator; import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager; import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
@ -458,8 +457,8 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
} }
// compute expected taker fee // compute expected taker fee
Coin feePerBtc = CoinUtil.getFeePerBtc(FeeService.getTakerFeePerBtc(), Coin.valueOf(offer.getOfferPayload().getAmount())); Coin feePerBtc = CoinUtil.getFeePerBtc(HavenoUtils.getTakerFeePerBtc(), Coin.valueOf(offer.getOfferPayload().getAmount()));
Coin takerFee = CoinUtil.maxCoin(feePerBtc, FeeService.getMinTakerFee()); Coin takerFee = CoinUtil.maxCoin(feePerBtc, HavenoUtils.getMinTakerFee());
// create arbitrator trade // create arbitrator trade
trade = new ArbitratorTrade(offer, 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 // First we check if offer is still available then we create the trade with the protocol
public void onTakeOffer(Coin amount, public void onTakeOffer(Coin amount,
Coin txFee,
Coin takerFee, Coin takerFee,
Coin fundsNeededForTrade, Coin fundsNeededForTrade,
Offer offer, Offer offer,

View file

@ -29,7 +29,6 @@ import bisq.core.locale.GlobalSettings;
import bisq.core.locale.TradeCurrency; import bisq.core.locale.TradeCurrency;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountUtil; import bisq.core.payment.PaymentAccountUtil;
import bisq.core.provider.fee.FeeService;
import bisq.core.xmr.MoneroNodeSettings; import bisq.core.xmr.MoneroNodeSettings;
import bisq.network.p2p.network.BridgeAddressProvider; import bisq.network.p2p.network.BridgeAddressProvider;
@ -162,7 +161,6 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
private final PersistenceManager<PreferencesPayload> persistenceManager; private final PersistenceManager<PreferencesPayload> persistenceManager;
private final Config config; private final Config config;
private final FeeService feeService;
private final LocalBitcoinNode localBitcoinNode; private final LocalBitcoinNode localBitcoinNode;
private final String btcNodesFromOptions; private final String btcNodesFromOptions;
@Getter @Getter
@ -175,13 +173,11 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
@Inject @Inject
public Preferences(PersistenceManager<PreferencesPayload> persistenceManager, public Preferences(PersistenceManager<PreferencesPayload> persistenceManager,
Config config, Config config,
FeeService feeService,
LocalBitcoinNode localBitcoinNode, LocalBitcoinNode localBitcoinNode,
@Named(Config.BTC_NODES) String btcNodesFromOptions) { @Named(Config.BTC_NODES) String btcNodesFromOptions) {
this.persistenceManager = persistenceManager; this.persistenceManager = persistenceManager;
this.config = config; this.config = config;
this.feeService = feeService;
this.localBitcoinNode = localBitcoinNode; this.localBitcoinNode = localBitcoinNode;
this.btcNodesFromOptions = btcNodesFromOptions; this.btcNodesFromOptions = btcNodesFromOptions;
@ -837,11 +833,6 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
return prefPayload.getBridgeAddresses(); return prefPayload.getBridgeAddresses();
} }
public long getWithdrawalTxFeeInVbytes() {
return Math.max(prefPayload.getWithdrawalTxFeeInVbytes(),
feeService.getMinFeePerVByte());
}
public List<String> getDefaultXmrTxProofServices() { public List<String> getDefaultXmrTxProofServices() {
if (config.useLocalhostForP2P) { if (config.useLocalhostForP2P) {
return XMR_TX_PROOF_SERVICES_CLEAR_NET; return XMR_TX_PROOF_SERVICES_CLEAR_NET;

View file

@ -20,8 +20,7 @@ package bisq.core.util.coin;
import bisq.core.btc.wallet.Restrictions; import bisq.core.btc.wallet.Restrictions;
import bisq.core.monetary.Price; import bisq.core.monetary.Price;
import bisq.core.monetary.Volume; import bisq.core.monetary.Volume;
import bisq.core.provider.fee.FeeService; import bisq.core.trade.HavenoUtils;
import bisq.common.util.MathUtils; import bisq.common.util.MathUtils;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
@ -98,8 +97,8 @@ public class CoinUtil {
@Nullable @Nullable
public static Coin getMakerFee(@Nullable Coin amount) { public static Coin getMakerFee(@Nullable Coin amount) {
if (amount != null) { if (amount != null) {
Coin feePerBtc = getFeePerBtc(FeeService.getMakerFeePerBtc(), amount); Coin feePerBtc = getFeePerBtc(HavenoUtils.getMakerFeePerBtc(), amount);
return maxCoin(feePerBtc, FeeService.getMinMakerFee()); return maxCoin(feePerBtc, HavenoUtils.getMinMakerFee());
} else { } else {
return null; return null;
} }

View file

@ -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);
}
}

View file

@ -61,7 +61,7 @@ public class PreferencesTest {
Config config = new Config(); Config config = new Config();
LocalBitcoinNode localBitcoinNode = new LocalBitcoinNode(config); LocalBitcoinNode localBitcoinNode = new LocalBitcoinNode(config);
preferences = new Preferences( preferences = new Preferences(
persistenceManager, config, null, localBitcoinNode, null); persistenceManager, config, localBitcoinNode, null);
} }
@Test @Test

View file

@ -20,7 +20,6 @@ package bisq.daemon.grpc;
import bisq.common.UserThread; import bisq.common.UserThread;
import bisq.core.api.CoreApi; import bisq.core.api.CoreApi;
import bisq.core.api.model.AddressBalanceInfo; import bisq.core.api.model.AddressBalanceInfo;
import bisq.core.api.model.TxFeeRateInfo;
import bisq.proto.grpc.GetAddressBalanceReply; import bisq.proto.grpc.GetAddressBalanceReply;
import bisq.proto.grpc.GetAddressBalanceRequest; import bisq.proto.grpc.GetAddressBalanceRequest;
@ -38,26 +37,17 @@ import bisq.proto.grpc.CreateXmrTxRequest;
import bisq.proto.grpc.CreateXmrTxReply; import bisq.proto.grpc.CreateXmrTxReply;
import bisq.proto.grpc.RelayXmrTxRequest; import bisq.proto.grpc.RelayXmrTxRequest;
import bisq.proto.grpc.RelayXmrTxReply; 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.GetXmrSeedReply;
import bisq.proto.grpc.GetXmrSeedRequest; import bisq.proto.grpc.GetXmrSeedRequest;
import bisq.proto.grpc.LockWalletReply; import bisq.proto.grpc.LockWalletReply;
import bisq.proto.grpc.LockWalletRequest; import bisq.proto.grpc.LockWalletRequest;
import bisq.proto.grpc.RemoveWalletPasswordReply; import bisq.proto.grpc.RemoveWalletPasswordReply;
import bisq.proto.grpc.RemoveWalletPasswordRequest; import bisq.proto.grpc.RemoveWalletPasswordRequest;
import bisq.proto.grpc.SendBtcReply;
import bisq.proto.grpc.SendBtcRequest; import bisq.proto.grpc.SendBtcRequest;
import bisq.proto.grpc.SetTxFeeRatePreferenceReply;
import bisq.proto.grpc.SetTxFeeRatePreferenceRequest;
import bisq.proto.grpc.SetWalletPasswordReply; import bisq.proto.grpc.SetWalletPasswordReply;
import bisq.proto.grpc.SetWalletPasswordRequest; import bisq.proto.grpc.SetWalletPasswordRequest;
import bisq.proto.grpc.UnlockWalletReply; import bisq.proto.grpc.UnlockWalletReply;
import bisq.proto.grpc.UnlockWalletRequest; import bisq.proto.grpc.UnlockWalletRequest;
import bisq.proto.grpc.UnsetTxFeeRatePreferenceReply;
import bisq.proto.grpc.UnsetTxFeeRatePreferenceRequest;
import io.grpc.ServerInterceptor; import io.grpc.ServerInterceptor;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
@ -79,7 +69,6 @@ import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import static bisq.core.api.model.TxInfo.toTxInfo;
import static bisq.core.api.model.XmrTx.toXmrTx; import static bisq.core.api.model.XmrTx.toXmrTx;
import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
import static bisq.proto.grpc.WalletsGrpc.*; 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 @Override
public void setWalletPassword(SetWalletPasswordRequest req, public void setWalletPassword(SetWalletPasswordRequest req,
StreamObserver<SetWalletPasswordReply> responseObserver) { 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(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(getGetAddressBalanceMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put(getGetFundingAddressesMethod().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 // 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. // persist the change to disk may corrupt the wallet, so allow only 1 attempt per 5 seconds.

View file

@ -59,7 +59,6 @@ import bisq.core.payment.RevolutAccount;
import bisq.core.presentation.BalancePresentation; import bisq.core.presentation.BalancePresentation;
import bisq.core.presentation.SupportTicketsPresentation; import bisq.core.presentation.SupportTicketsPresentation;
import bisq.core.presentation.TradePresentation; import bisq.core.presentation.TradePresentation;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.TradeManager; import bisq.core.trade.TradeManager;
import bisq.core.user.DontShowAgainLookup; import bisq.core.user.DontShowAgainLookup;
@ -173,7 +172,6 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener
WalletPasswordWindow walletPasswordWindow, WalletPasswordWindow walletPasswordWindow,
NotificationCenter notificationCenter, NotificationCenter notificationCenter,
TacWindow tacWindow, TacWindow tacWindow,
FeeService feeService,
PriceFeedService priceFeedService, PriceFeedService priceFeedService,
Config config, Config config,
LocalBitcoinNode localBitcoinNode, LocalBitcoinNode localBitcoinNode,
@ -210,7 +208,6 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener
TxIdTextField.setXmrWalletService(xmrWalletService); TxIdTextField.setXmrWalletService(xmrWalletService);
GUIUtil.setFeeService(feeService);
GUIUtil.setPreferences(preferences); GUIUtil.setPreferences(preferences);
setupHandlers(); setupHandlers();

View file

@ -31,7 +31,6 @@ import bisq.core.btc.model.XmrAddressEntry;
import bisq.core.btc.setup.WalletsSetup; import bisq.core.btc.setup.WalletsSetup;
import bisq.core.btc.wallet.XmrWalletService; import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.provider.fee.FeeService;
import bisq.core.trade.HavenoUtils; import bisq.core.trade.HavenoUtils;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.TradeManager; import bisq.core.trade.TradeManager;
@ -97,8 +96,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
WalletsSetup walletsSetup, WalletsSetup walletsSetup,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
BtcAddressValidator btcAddressValidator, BtcAddressValidator btcAddressValidator,
WalletPasswordWindow walletPasswordWindow, WalletPasswordWindow walletPasswordWindow) {
FeeService feeService) {
this.xmrWalletService = xmrWalletService; this.xmrWalletService = xmrWalletService;
this.tradeManager = tradeManager; this.tradeManager = tradeManager;
this.p2PService = p2PService; this.p2PService = p2PService;

View file

@ -22,7 +22,6 @@ import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil; import bisq.desktop.util.GUIUtil;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.btc.TxFeeEstimationService;
import bisq.core.btc.listeners.XmrBalanceListener; import bisq.core.btc.listeners.XmrBalanceListener;
import bisq.core.btc.model.XmrAddressEntry; import bisq.core.btc.model.XmrAddressEntry;
import bisq.core.btc.wallet.Restrictions; import bisq.core.btc.wallet.Restrictions;
@ -37,7 +36,6 @@ import bisq.core.offer.OfferDirection;
import bisq.core.offer.OfferUtil; import bisq.core.offer.OfferUtil;
import bisq.core.offer.OpenOfferManager; import bisq.core.offer.OpenOfferManager;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.handlers.TransactionResultHandler; import bisq.core.trade.handlers.TransactionResultHandler;
import bisq.core.trade.statistics.TradeStatistics3; import bisq.core.trade.statistics.TradeStatistics3;
@ -104,7 +102,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
protected final PriceFeedService priceFeedService; protected final PriceFeedService priceFeedService;
final String shortOfferId; final String shortOfferId;
private final AccountAgeWitnessService accountAgeWitnessService; private final AccountAgeWitnessService accountAgeWitnessService;
private final FeeService feeService;
private final CoinFormatter btcFormatter; private final CoinFormatter btcFormatter;
private final Navigation navigation; private final Navigation navigation;
private final String offerId; private final String offerId;
@ -132,7 +129,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
private Coin txFeeFromFeeService = Coin.ZERO; private Coin txFeeFromFeeService = Coin.ZERO;
@Getter @Getter
private boolean marketPriceAvailable; private boolean marketPriceAvailable;
private int feeTxVsize = TxFeeEstimationService.TYPICAL_TX_WITH_1_INPUT_VSIZE;
protected boolean allowAmountUpdate = true; protected boolean allowAmountUpdate = true;
private final TradeStatisticsManager tradeStatisticsManager; private final TradeStatisticsManager tradeStatisticsManager;
@ -157,7 +153,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
P2PService p2PService, P2PService p2PService,
PriceFeedService priceFeedService, PriceFeedService priceFeedService,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
FeeService feeService,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
TradeStatisticsManager tradeStatisticsManager, TradeStatisticsManager tradeStatisticsManager,
Navigation navigation) { Navigation navigation) {
@ -171,7 +166,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
this.p2PService = p2PService; this.p2PService = p2PService;
this.priceFeedService = priceFeedService; this.priceFeedService = priceFeedService;
this.accountAgeWitnessService = accountAgeWitnessService; this.accountAgeWitnessService = accountAgeWitnessService;
this.feeService = feeService;
this.btcFormatter = btcFormatter; this.btcFormatter = btcFormatter;
this.navigation = navigation; this.navigation = navigation;
this.tradeStatisticsManager = tradeStatisticsManager; this.tradeStatisticsManager = tradeStatisticsManager;

View file

@ -44,9 +44,9 @@ import bisq.core.payment.payload.PaymentMethod;
import bisq.core.payment.validation.BtcValidator; import bisq.core.payment.validation.BtcValidator;
import bisq.core.payment.validation.FiatVolumeValidator; import bisq.core.payment.validation.FiatVolumeValidator;
import bisq.core.payment.validation.SecurityDepositValidator; import bisq.core.payment.validation.SecurityDepositValidator;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.MarketPrice; import bisq.core.provider.price.MarketPrice;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.HavenoUtils;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
import bisq.core.util.FormattingUtils; import bisq.core.util.FormattingUtils;
import bisq.core.util.ParsingUtils; import bisq.core.util.ParsingUtils;
@ -999,7 +999,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
dataModel.getMakerFeeInBtc(), dataModel.getMakerFeeInBtc(),
dataModel.getAmount().get(), dataModel.getAmount().get(),
btcFormatter, btcFormatter,
FeeService.getMinMakerFee()); HavenoUtils.getMinMakerFee());
} }
public String getMakerFeePercentage() { public String getMakerFeePercentage() {

View file

@ -25,7 +25,6 @@ import bisq.core.offer.CreateOfferService;
import bisq.core.offer.OfferUtil; import bisq.core.offer.OfferUtil;
import bisq.core.offer.OpenOfferManager; import bisq.core.offer.OpenOfferManager;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.statistics.TradeStatisticsManager; import bisq.core.trade.statistics.TradeStatisticsManager;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
@ -58,7 +57,6 @@ class CreateOfferDataModel extends MutableOfferDataModel {
P2PService p2PService, P2PService p2PService,
PriceFeedService priceFeedService, PriceFeedService priceFeedService,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
FeeService feeService,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
TradeStatisticsManager tradeStatisticsManager, TradeStatisticsManager tradeStatisticsManager,
Navigation navigation) { Navigation navigation) {
@ -71,7 +69,6 @@ class CreateOfferDataModel extends MutableOfferDataModel {
p2PService, p2PService,
priceFeedService, priceFeedService,
accountAgeWitnessService, accountAgeWitnessService,
feeService,
btcFormatter, btcFormatter,
tradeStatisticsManager, tradeStatisticsManager,
navigation); navigation);

View file

@ -39,9 +39,9 @@ import bisq.core.offer.OfferUtil;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountUtil; import bisq.core.payment.PaymentAccountUtil;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.mempool.MempoolService; import bisq.core.provider.mempool.MempoolService;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.HavenoUtils;
import bisq.core.trade.TradeManager; import bisq.core.trade.TradeManager;
import bisq.core.trade.handlers.TradeResultHandler; import bisq.core.trade.handlers.TradeResultHandler;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
@ -86,7 +86,6 @@ class TakeOfferDataModel extends OfferDataModel {
private final TradeManager tradeManager; private final TradeManager tradeManager;
private final OfferBook offerBook; private final OfferBook offerBook;
private final User user; private final User user;
private final FeeService feeService;
private final MempoolService mempoolService; private final MempoolService mempoolService;
private final FilterManager filterManager; private final FilterManager filterManager;
final Preferences preferences; final Preferences preferences;
@ -95,9 +94,7 @@ class TakeOfferDataModel extends OfferDataModel {
private final Navigation navigation; private final Navigation navigation;
private final P2PService p2PService; private final P2PService p2PService;
private Coin txFeeFromFeeService;
private Coin securityDeposit; private Coin securityDeposit;
// Coin feeFromFundingTx = Coin.NEGATIVE_SATOSHI;
private Offer offer; private Offer offer;
@ -110,10 +107,6 @@ class TakeOfferDataModel extends OfferDataModel {
private PaymentAccount paymentAccount; private PaymentAccount paymentAccount;
private boolean isTabSelected; private boolean isTabSelected;
Price tradePrice; 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 @Getter
protected final IntegerProperty mempoolStatus = new SimpleIntegerProperty(); protected final IntegerProperty mempoolStatus = new SimpleIntegerProperty();
@Getter @Getter
@ -130,7 +123,7 @@ class TakeOfferDataModel extends OfferDataModel {
OfferBook offerBook, OfferBook offerBook,
OfferUtil offerUtil, OfferUtil offerUtil,
XmrWalletService xmrWalletService, XmrWalletService xmrWalletService,
User user, FeeService feeService, User user,
MempoolService mempoolService, MempoolService mempoolService,
FilterManager filterManager, FilterManager filterManager,
Preferences preferences, Preferences preferences,
@ -144,7 +137,6 @@ class TakeOfferDataModel extends OfferDataModel {
this.tradeManager = tradeManager; this.tradeManager = tradeManager;
this.offerBook = offerBook; this.offerBook = offerBook;
this.user = user; this.user = user;
this.feeService = feeService;
this.mempoolService = mempoolService; this.mempoolService = mempoolService;
this.filterManager = filterManager; this.filterManager = filterManager;
this.preferences = preferences; this.preferences = preferences;
@ -212,39 +204,6 @@ class TakeOfferDataModel extends OfferDataModel {
getBuyerSecurityDeposit() : getBuyerSecurityDeposit() :
getSellerSecurityDeposit(); 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); mempoolStatus.setValue(-1);
mempoolService.validateOfferMakerTx(offer.getOfferPayload(), (txValidator -> { mempoolService.validateOfferMakerTx(offer.getOfferPayload(), (txValidator -> {
mempoolStatus.setValue(txValidator.isFail() ? 0 : 1); 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. // We don't want that the fee gets updated anymore after we show the funding screen.
void onShowPayFundsScreen() { void onShowPayFundsScreen() {
freezeFee = true;
calculateTotalToPay(); 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 // 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. // have it persisted as well.
void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) { void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) {
checkNotNull(txFeeFromFeeService, "txFeeFromFeeService must not be null");
checkNotNull(getTakerFee(), "takerFee must not be null"); checkNotNull(getTakerFee(), "takerFee must not be null");
Coin fundsNeededForTrade = getFundsNeededForTrade(); Coin fundsNeededForTrade = getFundsNeededForTrade();
@ -324,7 +281,6 @@ class TakeOfferDataModel extends OfferDataModel {
new Popup().warning(Res.get("offerbook.warning.offerWasAlreadyUsedInTrade")).show(); new Popup().warning(Res.get("offerbook.warning.offerWasAlreadyUsedInTrade")).show();
} else { } else {
tradeManager.onTakeOffer(amount.get(), tradeManager.onTakeOffer(amount.get(),
txFeeFromFeeService,
getTakerFee(), getTakerFee(),
fundsNeededForTrade, fundsNeededForTrade,
offer, offer,
@ -481,8 +437,8 @@ class TakeOfferDataModel extends OfferDataModel {
Coin amount = this.amount.get(); Coin amount = this.amount.get();
if (amount != null) { if (amount != null) {
// TODO write unit test for that // TODO write unit test for that
Coin feePerBtc = CoinUtil.getFeePerBtc(FeeService.getTakerFeePerBtc(), amount); Coin feePerBtc = CoinUtil.getFeePerBtc(HavenoUtils.getTakerFeePerBtc(), amount);
return CoinUtil.maxCoin(feePerBtc, FeeService.getMinTakerFee()); return CoinUtil.maxCoin(feePerBtc, HavenoUtils.getMinTakerFee());
} else { } else {
return null; return null;
} }
@ -493,18 +449,6 @@ class TakeOfferDataModel extends OfferDataModel {
xmrWalletService.resetAddressEntriesForOpenOffer(offer.getId()); 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) { /* private void setFeeFromFundingTx(Coin fee) {
feeFromFundingTx = fee; feeFromFundingTx = fee;
isFeeFromFundingTxSufficient.set(feeFromFundingTx.compareTo(FeePolicy.getMinRequiredFeeForFundingTx()) >= 0); isFeeFromFundingTxSufficient.set(feeFromFundingTx.compareTo(FeePolicy.getMinRequiredFeeForFundingTx()) >= 0);
@ -557,23 +501,7 @@ class TakeOfferDataModel extends OfferDataModel {
@NotNull @NotNull
private Coin getFundsNeededForTrade() { private Coin getFundsNeededForTrade() {
return getSecurityDeposit().add(getTxFeeForDepositTx()).add(getTxFeeForPayoutTx()); return getSecurityDeposit();
}
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);
} }
public XmrAddressEntry getAddressEntry() { public XmrAddressEntry getAddressEntry() {

View file

@ -38,7 +38,7 @@ import bisq.core.offer.OfferUtil;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.payment.validation.BtcValidator; 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.trade.Trade;
import bisq.core.util.FormattingUtils; import bisq.core.util.FormattingUtils;
import bisq.core.util.VolumeUtil; import bisq.core.util.VolumeUtil;
@ -692,7 +692,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
dataModel.getTakerFeeInBtc(), dataModel.getTakerFeeInBtc(),
dataModel.getAmount().get(), dataModel.getAmount().get(),
btcFormatter, btcFormatter,
FeeService.getMinMakerFee()); HavenoUtils.getMinMakerFee());
} }
public String getTakerFeePercentage() { public String getTakerFeePercentage() {

View file

@ -31,7 +31,6 @@ import bisq.core.offer.OfferUtil;
import bisq.core.offer.OpenOfferManager; import bisq.core.offer.OpenOfferManager;
import bisq.core.offer.CreateOfferService; import bisq.core.offer.CreateOfferService;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.statistics.TradeStatisticsManager; import bisq.core.trade.statistics.TradeStatisticsManager;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
@ -65,7 +64,6 @@ class DuplicateOfferDataModel extends MutableOfferDataModel {
P2PService p2PService, P2PService p2PService,
PriceFeedService priceFeedService, PriceFeedService priceFeedService,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
FeeService feeService,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
TradeStatisticsManager tradeStatisticsManager, TradeStatisticsManager tradeStatisticsManager,
Navigation navigation) { Navigation navigation) {
@ -79,7 +77,6 @@ class DuplicateOfferDataModel extends MutableOfferDataModel {
p2PService, p2PService,
priceFeedService, priceFeedService,
accountAgeWitnessService, accountAgeWitnessService,
feeService,
btcFormatter, btcFormatter,
tradeStatisticsManager, tradeStatisticsManager,
navigation); navigation);

View file

@ -35,7 +35,6 @@ import bisq.core.offer.OpenOffer;
import bisq.core.offer.OpenOfferManager; import bisq.core.offer.OpenOfferManager;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.proto.persistable.CorePersistenceProtoResolver; import bisq.core.proto.persistable.CorePersistenceProtoResolver;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.statistics.TradeStatisticsManager; import bisq.core.trade.statistics.TradeStatisticsManager;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
@ -72,7 +71,6 @@ class EditOfferDataModel extends MutableOfferDataModel {
P2PService p2PService, P2PService p2PService,
PriceFeedService priceFeedService, PriceFeedService priceFeedService,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
FeeService feeService,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
CorePersistenceProtoResolver corePersistenceProtoResolver, CorePersistenceProtoResolver corePersistenceProtoResolver,
TradeStatisticsManager tradeStatisticsManager, TradeStatisticsManager tradeStatisticsManager,
@ -87,7 +85,6 @@ class EditOfferDataModel extends MutableOfferDataModel {
p2PService, p2PService,
priceFeedService, priceFeedService,
accountAgeWitnessService, accountAgeWitnessService,
feeService,
btcFormatter, btcFormatter,
tradeStatisticsManager, tradeStatisticsManager,
navigation); navigation);

View file

@ -28,12 +28,12 @@ import bisq.core.btc.wallet.Restrictions;
import bisq.core.network.MessageState; import bisq.core.network.MessageState;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.offer.OfferUtil; import bisq.core.offer.OfferUtil;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.mempool.MempoolService; import bisq.core.provider.mempool.MempoolService;
import bisq.core.trade.ArbitratorTrade; import bisq.core.trade.ArbitratorTrade;
import bisq.core.trade.BuyerTrade; import bisq.core.trade.BuyerTrade;
import bisq.core.trade.ClosedTradableManager; import bisq.core.trade.ClosedTradableManager;
import bisq.core.trade.Contract; import bisq.core.trade.Contract;
import bisq.core.trade.HavenoUtils;
import bisq.core.trade.SellerTrade; import bisq.core.trade.SellerTrade;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.TradeUtil; import bisq.core.trade.TradeUtil;
@ -338,8 +338,8 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
Coin tradeFeeInBTC = dataModel.getTradeFeeInBTC(); Coin tradeFeeInBTC = dataModel.getTradeFeeInBTC();
Coin minTradeFee = dataModel.isMaker() ? Coin minTradeFee = dataModel.isMaker() ?
FeeService.getMinMakerFee() : HavenoUtils.getMinMakerFee() :
FeeService.getMinTakerFee(); HavenoUtils.getMinTakerFee();
String percentage = GUIUtil.getPercentageOfTradeAmount(tradeFeeInBTC, trade.getAmount(), String percentage = GUIUtil.getPercentageOfTradeAmount(tradeFeeInBTC, trade.getAmount(),
minTradeFee); minTradeFee);

View file

@ -25,7 +25,6 @@ import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.locale.CurrencyUtil; import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency; import bisq.core.locale.TradeCurrency;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.MarketPrice; import bisq.core.provider.price.MarketPrice;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
@ -88,17 +87,13 @@ public class MarketPricePresentation {
@Inject @Inject
public MarketPricePresentation(XmrWalletService xmrWalletService, public MarketPricePresentation(XmrWalletService xmrWalletService,
PriceFeedService priceFeedService, PriceFeedService priceFeedService,
Preferences preferences, Preferences preferences) {
FeeService feeService) {
this.priceFeedService = priceFeedService; this.priceFeedService = priceFeedService;
this.preferences = preferences; this.preferences = preferences;
TxIdTextField.setPreferences(preferences); TxIdTextField.setPreferences(preferences);
// TODO
TxIdTextField.setXmrWalletService(xmrWalletService); TxIdTextField.setXmrWalletService(xmrWalletService);
GUIUtil.setFeeService(feeService);
} }
public void setup() { public void setup() {

View file

@ -17,7 +17,6 @@
package bisq.desktop.main.settings.preferences; package bisq.desktop.main.settings.preferences;
import bisq.desktop.app.HavenoApp;
import bisq.desktop.common.view.ActivatableViewAndModel; import bisq.desktop.common.view.ActivatableViewAndModel;
import bisq.desktop.common.view.FxmlView; import bisq.desktop.common.view.FxmlView;
import bisq.desktop.components.AutoTooltipButton; import bisq.desktop.components.AutoTooltipButton;
@ -44,7 +43,6 @@ import bisq.core.locale.TradeCurrency;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.payment.validation.BtcValidator; import bisq.core.payment.validation.BtcValidator;
import bisq.core.provider.fee.FeeService;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
import bisq.core.user.User; import bisq.core.user.User;
import bisq.core.util.FormattingUtils; import bisq.core.util.FormattingUtils;
@ -121,14 +119,13 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
notifyOnPreReleaseToggle; notifyOnPreReleaseToggle;
private int gridRow = 0; private int gridRow = 0;
private int displayCurrenciesGridRowIndex = 0; private int displayCurrenciesGridRowIndex = 0;
private InputTextField transactionFeeInputTextField, ignoreTradersListInputTextField, ignoreDustThresholdInputTextField, private InputTextField ignoreTradersListInputTextField, ignoreDustThresholdInputTextField,
autoConfRequiredConfirmationsTf, autoConfServiceAddressTf, autoConfTradeLimitTf, /*referralIdInputTextField,*/ autoConfRequiredConfirmationsTf, autoConfServiceAddressTf, autoConfTradeLimitTf, /*referralIdInputTextField,*/
rpcUserTextField, blockNotifyPortTextField; rpcUserTextField, blockNotifyPortTextField;
private PasswordTextField rpcPwTextField; private PasswordTextField rpcPwTextField;
private ChangeListener<Boolean> transactionFeeFocusedListener, autoConfServiceAddressFocusOutListener, autoConfRequiredConfirmationsFocusOutListener; private ChangeListener<Boolean> autoConfServiceAddressFocusOutListener, autoConfRequiredConfirmationsFocusOutListener;
private final Preferences preferences; private final Preferences preferences;
private final FeeService feeService;
//private final ReferralIdService referralIdService; //private final ReferralIdService referralIdService;
private final FilterManager filterManager; private final FilterManager filterManager;
private final File storageDir; private final File storageDir;
@ -150,8 +147,6 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
rpcUserListener, rpcPwListener, blockNotifyPortListener, rpcUserListener, rpcPwListener, blockNotifyPortListener,
autoConfTradeLimitListener, autoConfServiceAddressListener; autoConfTradeLimitListener, autoConfServiceAddressListener;
private ChangeListener<Boolean> deviationFocusedListener; private ChangeListener<Boolean> deviationFocusedListener;
private ChangeListener<Boolean> useCustomFeeCheckboxListener;
private ChangeListener<Number> transactionFeeChangeListener;
private final boolean displayStandbyModeFeature; private final boolean displayStandbyModeFeature;
private ChangeListener<Filter> filterChangeListener; private ChangeListener<Filter> filterChangeListener;
@ -163,7 +158,6 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
@Inject @Inject
public PreferencesView(PreferencesViewModel model, public PreferencesView(PreferencesViewModel model,
Preferences preferences, Preferences preferences,
FeeService feeService,
FilterManager filterManager, FilterManager filterManager,
Config config, Config config,
User user, User user,
@ -173,7 +167,6 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
this.user = user; this.user = user;
this.formatter = formatter; this.formatter = formatter;
this.preferences = preferences; this.preferences = preferences;
this.feeService = feeService;
this.filterManager = filterManager; this.filterManager = filterManager;
this.storageDir = storageDir; this.storageDir = storageDir;
this.displayStandbyModeFeature = Utilities.isLinux() || Utilities.isOSX() || Utilities.isWindows(); this.displayStandbyModeFeature = Utilities.isLinux() || Utilities.isOSX() || Utilities.isWindows();
@ -238,56 +231,6 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
btcExplorerTextField = btcExp.first; btcExplorerTextField = btcExp.first;
editCustomBtcExplorer = btcExp.second; 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 // deviation
deviationInputTextField = addInputTextField(root, ++gridRow, deviationInputTextField = addInputTextField(root, ++gridRow,
Res.get("setting.preferences.deviation")); Res.get("setting.preferences.deviation"));
@ -693,15 +636,6 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void activateGeneralOptions() { 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())); ignoreTradersListInputTextField.setText(String.join(", ", preferences.getIgnoreTradersList()));
/* referralIdService.getOptionalReferralId().ifPresent(referralId -> referralIdInputTextField.setText(referralId)); /* referralIdService.getOptionalReferralId().ifPresent(referralId -> referralIdInputTextField.setText(referralId));
referralIdInputTextField.setPromptText(Res.get("setting.preferences.refererId.prompt"));*/ referralIdInputTextField.setPromptText(Res.get("setting.preferences.refererId.prompt"));*/
@ -764,21 +698,11 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
deviationInputTextField.textProperty().addListener(deviationListener); deviationInputTextField.textProperty().addListener(deviationListener);
deviationInputTextField.focusedProperty().addListener(deviationFocusedListener); deviationInputTextField.focusedProperty().addListener(deviationFocusedListener);
transactionFeeInputTextField.focusedProperty().addListener(transactionFeeFocusedListener);
ignoreTradersListInputTextField.textProperty().addListener(ignoreTradersListListener); ignoreTradersListInputTextField.textProperty().addListener(ignoreTradersListListener);
useCustomFee.selectedProperty().addListener(useCustomFeeCheckboxListener);
//referralIdInputTextField.textProperty().addListener(referralIdListener); //referralIdInputTextField.textProperty().addListener(referralIdListener);
ignoreDustThresholdInputTextField.textProperty().addListener(ignoreDustThresholdListener); 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() { private void activateDisplayCurrencies() {
preferredTradeCurrencyComboBox.setItems(tradeCurrencies); preferredTradeCurrencyComboBox.setItems(tradeCurrencies);
preferredTradeCurrencyComboBox.getSelectionModel().select(preferences.getPreferredTradeCurrency()); preferredTradeCurrencyComboBox.getSelectionModel().select(preferences.getPreferredTradeCurrency());
@ -897,11 +821,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
editCustomBtcExplorer.setOnAction(null); editCustomBtcExplorer.setOnAction(null);
deviationInputTextField.textProperty().removeListener(deviationListener); deviationInputTextField.textProperty().removeListener(deviationListener);
deviationInputTextField.focusedProperty().removeListener(deviationFocusedListener); deviationInputTextField.focusedProperty().removeListener(deviationFocusedListener);
transactionFeeInputTextField.focusedProperty().removeListener(transactionFeeFocusedListener);
if (transactionFeeChangeListener != null)
feeService.feeUpdateCounterProperty().removeListener(transactionFeeChangeListener);
ignoreTradersListInputTextField.textProperty().removeListener(ignoreTradersListListener); ignoreTradersListInputTextField.textProperty().removeListener(ignoreTradersListListener);
useCustomFee.selectedProperty().removeListener(useCustomFeeCheckboxListener);
//referralIdInputTextField.textProperty().removeListener(referralIdListener); //referralIdInputTextField.textProperty().removeListener(referralIdListener);
ignoreDustThresholdInputTextField.textProperty().removeListener(ignoreDustThresholdListener); ignoreDustThresholdInputTextField.textProperty().removeListener(ignoreDustThresholdListener);
} }

View file

@ -41,7 +41,6 @@ import bisq.core.locale.TradeCurrency;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountList; import bisq.core.payment.PaymentAccountList;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.provider.fee.FeeService;
import bisq.core.trade.HavenoUtils; import bisq.core.trade.HavenoUtils;
import bisq.core.trade.txproof.AssetTxProofResult; import bisq.core.trade.txproof.AssetTxProofResult;
import bisq.core.user.DontShowAgainLookup; 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_WITH_ZEROS = 3;
public final static int AMOUNT_DECIMALS = 4; public final static int AMOUNT_DECIMALS = 4;
private static FeeService feeService;
private static Preferences preferences; private static Preferences preferences;
public static TradeCurrency TOP_ALTCOIN = CurrencyUtil.getTradeCurrency("ETH").get(); public static TradeCurrency TOP_ALTCOIN = CurrencyUtil.getTradeCurrency("ETH").get();
public static void setFeeService(FeeService feeService) {
GUIUtil.feeService = feeService;
}
public static void setPreferences(Preferences preferences) { public static void setPreferences(Preferences preferences) {
GUIUtil.preferences = preferences; GUIUtil.preferences = preferences;
} }

View file

@ -12,7 +12,6 @@ import bisq.core.offer.OfferUtil;
import bisq.core.payment.ClearXchangeAccount; import bisq.core.payment.ClearXchangeAccount;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.RevolutAccount; import bisq.core.payment.RevolutAccount;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.statistics.TradeStatisticsManager; import bisq.core.trade.statistics.TradeStatisticsManager;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
@ -50,7 +49,6 @@ public class CreateOfferDataModelTest {
XmrAddressEntry addressEntry = mock(XmrAddressEntry.class); XmrAddressEntry addressEntry = mock(XmrAddressEntry.class);
XmrWalletService btcWalletService = mock(XmrWalletService.class); XmrWalletService btcWalletService = mock(XmrWalletService.class);
PriceFeedService priceFeedService = mock(PriceFeedService.class); PriceFeedService priceFeedService = mock(PriceFeedService.class);
FeeService feeService = mock(FeeService.class);
CreateOfferService createOfferService = mock(CreateOfferService.class); CreateOfferService createOfferService = mock(CreateOfferService.class);
preferences = mock(Preferences.class); preferences = mock(Preferences.class);
offerUtil = mock(OfferUtil.class); offerUtil = mock(OfferUtil.class);
@ -72,7 +70,6 @@ public class CreateOfferDataModelTest {
null, null,
priceFeedService, priceFeedService,
null, null,
feeService,
null, null,
tradeStats, tradeStats,
null); null);

View file

@ -32,7 +32,6 @@ import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.payment.validation.BtcValidator; import bisq.core.payment.validation.BtcValidator;
import bisq.core.payment.validation.SecurityDepositValidator; import bisq.core.payment.validation.SecurityDepositValidator;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.MarketPrice; import bisq.core.provider.price.MarketPrice;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.statistics.TradeStatisticsManager; import bisq.core.trade.statistics.TradeStatisticsManager;
@ -84,7 +83,6 @@ public class CreateOfferViewModelTest {
final AltcoinValidator altcoinValidator = new AltcoinValidator(); final AltcoinValidator altcoinValidator = new AltcoinValidator();
final FiatPriceValidator fiatPriceValidator = new FiatPriceValidator(); final FiatPriceValidator fiatPriceValidator = new FiatPriceValidator();
FeeService feeService = mock(FeeService.class);
XmrAddressEntry addressEntry = mock(XmrAddressEntry.class); XmrAddressEntry addressEntry = mock(XmrAddressEntry.class);
XmrWalletService xmrWalletService = mock(XmrWalletService.class); XmrWalletService xmrWalletService = mock(XmrWalletService.class);
PriceFeedService priceFeedService = mock(PriceFeedService.class); PriceFeedService priceFeedService = mock(PriceFeedService.class);
@ -105,7 +103,6 @@ public class CreateOfferViewModelTest {
12684.0450, 12684.0450,
Instant.now().getEpochSecond(), Instant.now().getEpochSecond(),
true)); true));
when(feeService.getTxFee(anyInt())).thenReturn(Coin.valueOf(1000L));
when(user.findFirstPaymentAccountWithCurrency(any())).thenReturn(paymentAccount); when(user.findFirstPaymentAccountWithCurrency(any())).thenReturn(paymentAccount);
when(paymentAccount.getPaymentMethod()).thenReturn(mock(PaymentMethod.class)); when(paymentAccount.getPaymentMethod()).thenReturn(mock(PaymentMethod.class));
when(user.getPaymentAccountsAsObservable()).thenReturn(FXCollections.observableSet()); when(user.getPaymentAccountsAsObservable()).thenReturn(FXCollections.observableSet());
@ -124,7 +121,6 @@ public class CreateOfferViewModelTest {
null, null,
priceFeedService, priceFeedService,
accountAgeWitnessService, accountAgeWitnessService,
feeService,
coinFormatter, coinFormatter,
tradeStats, tradeStats,
null); null);

View file

@ -18,7 +18,6 @@
package bisq.desktop.maker; package bisq.desktop.maker;
import bisq.core.btc.nodes.LocalBitcoinNode; import bisq.core.btc.nodes.LocalBitcoinNode;
import bisq.core.provider.fee.FeeService;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
import bisq.common.config.Config; 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, PersistenceManager> storage = new Property<>();
public static final Property<Preferences, Config> config = 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, LocalBitcoinNode> localBitcoinNode = new Property<>();
public static final Property<Preferences, String> useTorFlagFromOptions = new Property<>(); public static final Property<Preferences, String> useTorFlagFromOptions = new Property<>();
public static final Property<Preferences, String> referralID = 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( public static final Instantiator<Preferences> Preferences = lookup -> new Preferences(
lookup.valueOf(storage, new SameValueDonor<PersistenceManager>(null)), lookup.valueOf(storage, new SameValueDonor<PersistenceManager>(null)),
lookup.valueOf(config, new SameValueDonor<Config>(null)), lookup.valueOf(config, new SameValueDonor<Config>(null)),
lookup.valueOf(feeService, new SameValueDonor<FeeService>(null)),
lookup.valueOf(localBitcoinNode, new SameValueDonor<LocalBitcoinNode>(null)), lookup.valueOf(localBitcoinNode, new SameValueDonor<LocalBitcoinNode>(null)),
lookup.valueOf(useTorFlagFromOptions, new SameValueDonor<String>(null)) lookup.valueOf(useTorFlagFromOptions, new SameValueDonor<String>(null))
); );

View file

@ -874,27 +874,6 @@ message ContractInfo {
string arbitrator_node_address = 100; 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 // Wallets
@ -917,16 +896,6 @@ service Wallets {
} }
rpc GetAddressBalance (GetAddressBalanceRequest) returns (GetAddressBalanceReply) { 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 GetFundingAddresses (GetFundingAddressesRequest) returns (GetFundingAddressesReply) {
} }
rpc SetWalletPassword (SetWalletPasswordRequest) returns (SetWalletPasswordReply) { rpc SetWalletPassword (SetWalletPasswordRequest) returns (SetWalletPasswordReply) {
@ -1038,40 +1007,6 @@ message SendBtcRequest {
string memo = 4; 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 { message GetFundingAddressesRequest {
} }