Add offer as parameter to getSecurityDeposit and getFixedTxFeeForTrades calls if available to support trades between different protocol versions

This commit is contained in:
Manfred Karrer 2017-02-11 21:06:01 -05:00
parent 80ec899bad
commit f42628fcd8
16 changed files with 50 additions and 29 deletions

View File

@ -17,7 +17,7 @@
package io.bitsquare.btc;
import io.bitsquare.app.DevFlags;
import io.bitsquare.trade.offer.Offer;
import org.bitcoinj.core.Coin;
public class FeePolicy {
@ -44,8 +44,13 @@ public class FeePolicy {
// We use 0.0005 BTC (0.5 EUR @ 1000 EUR/BTC) which is for our tx sizes about 120-220 satoshi/byte
// We cannot make that user defined as it need to be the same for both users, so we can only change that in
// software updates
// TODO version check can be removed after DAO version
public static Coin getFixedTxFeeForTrades(Offer offer) {
return offer != null && offer.getProtocolVersion() == 1 ? Coin.valueOf(20_000) : getFixedTxFeeForTrades();
}
public static Coin getFixedTxFeeForTrades() {
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(5_000) : Coin.valueOf(50_000);
return Coin.valueOf(50_000);
}
// For non trade transactions (withdrawal) we use the default fee calculation
@ -54,7 +59,7 @@ public class FeePolicy {
// The BitcoinJ fee calculation use kb so a tx size < 1kb will still pay the fee for a kb tx.
// Our payout tx has about 370 bytes so we get a fee/kb value of about 90 satoshi/byte making it high priority
// Other payout transactions (E.g. arbitrators many collected transactions) will go with 30 satoshi/byte if > 1kb
private static Coin NON_TRADE_FEE_PER_KB = DevFlags.STRESS_TEST_MODE ? Coin.valueOf(5_000) : Coin.valueOf(30_000); // 0.0003 BTC about 0.3 EUR @ 1000 EUR/BTC
private static Coin NON_TRADE_FEE_PER_KB = Coin.valueOf(30_000); // 0.0003 BTC about 0.3 EUR @ 1000 EUR/BTC
public static void setNonTradeFeePerKb(Coin nonTradeFeePerKb) {
NON_TRADE_FEE_PER_KB = nonTradeFeePerKb;
@ -68,16 +73,23 @@ public class FeePolicy {
public static Coin getCreateOfferFee() {
// We need to pay the quite high miner fee of 50_000 from the trading fee tx so 30_000 is what
// the arbitrator receives
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(10_000) : Coin.valueOf(80_000);
return Coin.valueOf(80_000);
}
// 0.001 BTC 0.1% of 1 BTC about 1 EUR @ 1000 EUR/BTC
public static Coin getTakeOfferFee() {
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(10_000) : Coin.valueOf(100_000);
return Coin.valueOf(100_000);
}
// 0.03 BTC; about 30 EUR @ 1000 EUR/BTC
public static Coin getSecurityDeposit() {
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(5_000) : Coin.valueOf(3_000_000);
// TODO version check can be removed after DAO version
public static Coin getSecurityDeposit(Offer offer) {
return offer != null && offer.getProtocolVersion() == 1 ? Coin.valueOf(1_000_000) : getSecurityDeposit();
}
public static Coin getSecurityDeposit() {
return Coin.valueOf(3_000_000);
}
}

View File

@ -60,8 +60,7 @@ public abstract class BuyerTrade extends Trade {
@Override
public Coin getPayoutAmount() {
checkNotNull(getTradeAmount(), "Invalid state: getTradeAmount() = null");
return FeePolicy.getSecurityDeposit().add(getTradeAmount());
return FeePolicy.getSecurityDeposit(getOffer()).add(getTradeAmount());
}
///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -58,7 +58,7 @@ public abstract class SellerTrade extends Trade {
@Override
public Coin getPayoutAmount() {
return FeePolicy.getSecurityDeposit();
return FeePolicy.getSecurityDeposit(getOffer());
}
///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -24,6 +24,7 @@ import io.bitsquare.btc.data.PreparedDepositTxAndOffererInputs;
import io.bitsquare.common.crypto.Hash;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.offer.Offer;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
@ -43,8 +44,10 @@ public class OffererCreatesAndSignsDepositTxAsBuyer extends TradeTask {
try {
runInterceptHook();
checkNotNull(trade.getTradeAmount(), "trade.getTradeAmount() must not be null");
Coin buyerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades());
Coin msOutputAmount = buyerInputAmount.add(FeePolicy.getSecurityDeposit()).add(trade.getTradeAmount());
Offer offer = trade.getOffer();
Coin securityDeposit = FeePolicy.getSecurityDeposit(offer);
Coin buyerInputAmount = securityDeposit.add(FeePolicy.getFixedTxFeeForTrades(offer));
Coin msOutputAmount = buyerInputAmount.add(securityDeposit).add(trade.getTradeAmount());
log.debug("\n\n------------------------------------------------------------\n"
+ "Contract as json\n"
@ -56,7 +59,7 @@ public class OffererCreatesAndSignsDepositTxAsBuyer extends TradeTask {
WalletService walletService = processModel.getWalletService();
String id = processModel.getOffer().getId();
AddressEntry buyerMultiSigAddressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.MULTI_SIG);
buyerMultiSigAddressEntry.setLockedTradeAmount(buyerInputAmount.subtract(FeePolicy.getFixedTxFeeForTrades()));
buyerMultiSigAddressEntry.setLockedTradeAmount(buyerInputAmount.subtract(FeePolicy.getFixedTxFeeForTrades(offer)));
walletService.saveAddressEntryList();
PreparedDepositTxAndOffererInputs result = processModel.getTradeWalletService().offererCreatesAndSignsDepositTx(
true,

View File

@ -41,7 +41,8 @@ public class SignAndFinalizePayoutTx extends TradeTask {
try {
runInterceptHook();
checkNotNull(trade.getTradeAmount(), "trade.getTradeAmount() must not be null");
Coin sellerPayoutAmount = FeePolicy.getSecurityDeposit();
Coin sellerPayoutAmount = FeePolicy.getSecurityDeposit(trade.getOffer());
Coin buyerPayoutAmount = sellerPayoutAmount.add(trade.getTradeAmount());
Transaction transaction = processModel.getTradeWalletService().buyerSignsAndFinalizesPayoutTx(

View File

@ -58,7 +58,7 @@ public class SignAndPublishDepositTxAsBuyer extends TradeTask {
ArrayList<RawTransactionInput> buyerInputs = processModel.getRawTransactionInputs();
WalletService walletService = processModel.getWalletService();
AddressEntry buyerMultiSigAddressEntry = walletService.getOrCreateAddressEntry(processModel.getOffer().getId(), AddressEntry.Context.MULTI_SIG);
buyerMultiSigAddressEntry.setLockedTradeAmount(Coin.valueOf(buyerInputs.stream().mapToLong(input -> input.value).sum()).subtract(FeePolicy.getFixedTxFeeForTrades()));
buyerMultiSigAddressEntry.setLockedTradeAmount(Coin.valueOf(buyerInputs.stream().mapToLong(input -> input.value).sum()).subtract(FeePolicy.getFixedTxFeeForTrades(trade.getOffer())));
walletService.saveAddressEntryList();
TradingPeer tradingPeer = processModel.tradingPeer;
Transaction depositTx = processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(

View File

@ -22,6 +22,7 @@ import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.data.InputsAndChangeOutput;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.offer.Offer;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
@ -38,7 +39,8 @@ public class TakerCreatesDepositTxInputsAsBuyer extends TradeTask {
protected void run() {
try {
runInterceptHook();
Coin takerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades());
Offer offer = trade.getOffer();
Coin takerInputAmount = FeePolicy.getSecurityDeposit(offer).add(FeePolicy.getFixedTxFeeForTrades(offer));
InputsAndChangeOutput result = processModel.getTradeWalletService().takerCreatesDepositsTxInputs(
takerInputAmount,
processModel.getWalletService().getOrCreateAddressEntry(processModel.getOffer().getId(), AddressEntry.Context.RESERVED_FOR_TRADE),

View File

@ -24,6 +24,7 @@ import io.bitsquare.btc.data.PreparedDepositTxAndOffererInputs;
import io.bitsquare.common.crypto.Hash;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.offer.Offer;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
@ -43,8 +44,9 @@ public class OffererCreatesAndSignsDepositTxAsSeller extends TradeTask {
try {
runInterceptHook();
checkNotNull(trade.getTradeAmount(), "trade.getTradeAmount() must not be null");
Coin sellerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades()).add(trade.getTradeAmount());
Coin msOutputAmount = sellerInputAmount.add(FeePolicy.getSecurityDeposit());
Offer offer = trade.getOffer();
Coin sellerInputAmount = FeePolicy.getSecurityDeposit(offer).add(FeePolicy.getFixedTxFeeForTrades(offer)).add(trade.getTradeAmount());
Coin msOutputAmount = sellerInputAmount.add(FeePolicy.getSecurityDeposit(offer));
log.debug("\n\n------------------------------------------------------------\n"
+ "Contract as json\n"
@ -56,7 +58,7 @@ public class OffererCreatesAndSignsDepositTxAsSeller extends TradeTask {
WalletService walletService = processModel.getWalletService();
String id = processModel.getOffer().getId();
AddressEntry sellerMultiSigAddressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.MULTI_SIG);
sellerMultiSigAddressEntry.setLockedTradeAmount(sellerInputAmount.subtract(FeePolicy.getFixedTxFeeForTrades()));
sellerMultiSigAddressEntry.setLockedTradeAmount(sellerInputAmount.subtract(FeePolicy.getFixedTxFeeForTrades(offer)));
walletService.saveAddressEntryList();
PreparedDepositTxAndOffererInputs result = processModel.getTradeWalletService().offererCreatesAndSignsDepositTx(
false,

View File

@ -57,7 +57,7 @@ public class SignAndPublishDepositTxAsSeller extends TradeTask {
ArrayList<RawTransactionInput> sellerInputs = processModel.getRawTransactionInputs();
WalletService walletService = processModel.getWalletService();
AddressEntry sellerMultiSigAddressEntry = walletService.getOrCreateAddressEntry(processModel.getOffer().getId(), AddressEntry.Context.MULTI_SIG);
sellerMultiSigAddressEntry.setLockedTradeAmount(Coin.valueOf(sellerInputs.stream().mapToLong(input -> input.value).sum()).subtract(FeePolicy.getFixedTxFeeForTrades()));
sellerMultiSigAddressEntry.setLockedTradeAmount(Coin.valueOf(sellerInputs.stream().mapToLong(input -> input.value).sum()).subtract(FeePolicy.getFixedTxFeeForTrades(trade.getOffer())));
walletService.saveAddressEntryList();
TradingPeer tradingPeer = processModel.tradingPeer;
Transaction depositTx = processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(

View File

@ -42,7 +42,7 @@ public class SignPayoutTx extends TradeTask {
runInterceptHook();
checkNotNull(trade.getTradeAmount(), "trade.getTradeAmount() must not be null");
checkNotNull(trade.getDepositTx(), "trade.getDepositTx() must not be null");
Coin sellerPayoutAmount = FeePolicy.getSecurityDeposit();
Coin sellerPayoutAmount = FeePolicy.getSecurityDeposit(trade.getOffer());
Coin buyerPayoutAmount = sellerPayoutAmount.add(trade.getTradeAmount());
// We use the sellers LastBlockSeenHeight, which might be different to the buyers one.

View File

@ -22,6 +22,7 @@ import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.data.InputsAndChangeOutput;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.offer.Offer;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
@ -39,7 +40,8 @@ public class TakerCreatesDepositTxInputsAsSeller extends TradeTask {
try {
runInterceptHook();
if (trade.getTradeAmount() != null) {
Coin takerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades()).add(trade.getTradeAmount());
Offer offer = trade.getOffer();
Coin takerInputAmount = FeePolicy.getSecurityDeposit(offer).add(FeePolicy.getFixedTxFeeForTrades(offer)).add(trade.getTradeAmount());
InputsAndChangeOutput result = processModel.getTradeWalletService().takerCreatesDepositsTxInputs(takerInputAmount,
processModel.getWalletService().getOrCreateAddressEntry(processModel.getOffer().getId(), AddressEntry.Context.RESERVED_FOR_TRADE),

View File

@ -370,7 +370,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
Coin buyerAmount = formatter.parseToCoin(buyerPayoutAmountInputTextField.getText());
Coin sellerAmount = formatter.parseToCoin(sellerPayoutAmountInputTextField.getText());
Coin arbitratorAmount = formatter.parseToCoin(arbitratorPayoutAmountInputTextField.getText());
Coin securityDeposit = FeePolicy.getSecurityDeposit();
Coin securityDeposit = FeePolicy.getSecurityDeposit(dispute.getContract().offer);
Coin tradeAmount = dispute.getContract().getTradeAmount();
Coin available = tradeAmount.add(securityDeposit).add(securityDeposit);
Coin totalAmount = buyerAmount.add(sellerAmount).add(arbitratorAmount);
@ -378,7 +378,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
}
private void applyCustomAmounts(InputTextField inputTextField) {
Coin securityDeposit = FeePolicy.getSecurityDeposit();
Coin securityDeposit = FeePolicy.getSecurityDeposit(dispute.getContract().offer);
Coin tradeAmount = dispute.getContract().getTradeAmount();
Coin buyerAmount = formatter.parseToCoin(buyerPayoutAmountInputTextField.getText());
@ -669,7 +669,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
private void calculatePayoutAmounts(DisputeResult.DisputeFeePolicy feePayment) {
Contract contract = dispute.getContract();
Coin refund = FeePolicy.getSecurityDeposit();
Coin refund = FeePolicy.getSecurityDeposit(dispute.getContract().offer);
Coin winnerRefund;
Coin loserRefund;
switch (feePayment) {

View File

@ -264,7 +264,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
addLabelTextFieldWithCopyIcon(gridPane, rowIndex, "Offer ID:", offer.getId(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "Offerer's onion address:", offer.getOffererNodeAddress().getFullAddress());
addLabelTextField(gridPane, ++rowIndex, "Creation date:", formatter.formatDateTime(offer.getDate()));
addLabelTextField(gridPane, ++rowIndex, "Security deposit:", formatter.formatCoinWithCode(FeePolicy.getSecurityDeposit()));
addLabelTextField(gridPane, ++rowIndex, "Security deposit:", formatter.formatCoinWithCode(FeePolicy.getSecurityDeposit(offer)));
if (paymentMethodCountryCode != null)
addLabelTextField(gridPane, ++rowIndex, "Offerer's country of bank:",

View File

@ -172,7 +172,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
addTitledGroupBg(gridPane, ++rowIndex, rows, "Details", Layout.GROUP_DISTANCE);
addLabelTextFieldWithCopyIcon(gridPane, rowIndex, "Trade ID:", trade.getId(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
addLabelTextField(gridPane, ++rowIndex, "Trade date:", formatter.formatDateTime(trade.getDate()));
addLabelTextField(gridPane, ++rowIndex, "Security deposit:", formatter.formatCoinWithCode(FeePolicy.getSecurityDeposit()));
addLabelTextField(gridPane, ++rowIndex, "Security deposit:", formatter.formatCoinWithCode(FeePolicy.getSecurityDeposit(offer)));
addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "Selected arbitrator:", trade.getArbitratorNodeAddress().getFullAddress());
if (trade.getTradingPeerNodeAddress() != null)

View File

@ -215,7 +215,7 @@ public class PendingTradesDataModel extends ActivatableDataModel {
}
Coin getTotalFees() {
return FeePolicy.getFixedTxFeeForTrades().add(isOfferer() ? FeePolicy.getCreateOfferFee() : FeePolicy.getTakeOfferFee());
return FeePolicy.getFixedTxFeeForTrades(getOffer()).add(isOfferer() ? FeePolicy.getCreateOfferFee() : FeePolicy.getTakeOfferFee());
}
public String getCurrencyCode() {

View File

@ -268,7 +268,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
}
public String getSecurityDeposit() {
return formatter.formatCoinWithCode(FeePolicy.getSecurityDeposit());
return formatter.formatCoinWithCode(FeePolicy.getSecurityDeposit(dataModel.getOffer()));
}
public boolean isBlockChainMethod() {