mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-20 10:22:18 +01:00
Use security deposit from offer. Use fixed estimated tx size for fee calculation
This commit is contained in:
parent
5fd2839e24
commit
5beb7e6a1b
@ -2,5 +2,5 @@ package io.bitsquare.app;
|
||||
|
||||
public class DevFlags {
|
||||
public static final boolean STRESS_TEST_MODE = false;
|
||||
public static final boolean DEV_MODE = STRESS_TEST_MODE || false;
|
||||
public static final boolean DEV_MODE = STRESS_TEST_MODE || true;
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
package io.bitsquare.btc;
|
||||
|
||||
import io.bitsquare.app.DevFlags;
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
public class FeePolicy {
|
||||
@ -60,10 +59,4 @@ public class FeePolicy {
|
||||
return NON_TRADE_FEE_PER_KB;
|
||||
}
|
||||
|
||||
|
||||
// TODO will be increased once we get higher limits
|
||||
// 0.01 BTC; about 4 EUR @ 400 EUR/BTC
|
||||
public static Coin getSecurityDeposit() {
|
||||
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(5_000) : Coin.valueOf(1_000_000);
|
||||
}
|
||||
}
|
||||
|
@ -1120,13 +1120,16 @@ public class TradeWalletService {
|
||||
}
|
||||
|
||||
private static void printTxWithInputs(String tracePrefix, Transaction tx) {
|
||||
log.info(tracePrefix + ": " + tx.toString());
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(tracePrefix).append(": ").append(tx.toString()).append("\n").append(tracePrefix);
|
||||
for (TransactionInput input : tx.getInputs()) {
|
||||
if (input.getConnectedOutput() != null)
|
||||
log.info(tracePrefix + " input value: " + input.getConnectedOutput().getValue().toFriendlyString());
|
||||
sb.append(" input value: ").append(input.getConnectedOutput().getValue().toFriendlyString());
|
||||
else
|
||||
log.info(tracePrefix + ": Transaction already has inputs but we don't have the connected outputs, so we don't know the value.");
|
||||
sb.append(": Transaction already has inputs but we don't have the connected outputs, so we don't know the value.");
|
||||
}
|
||||
sb.append("\n").append("Size: " + tx.bitcoinSerialize().length);
|
||||
log.info(sb.toString());
|
||||
}
|
||||
|
||||
private void signInput(Transaction transaction, TransactionInput input, int inputIndex) throws SigningException {
|
||||
|
@ -113,6 +113,7 @@ public class WalletService {
|
||||
AddressEntryList addressEntryList,
|
||||
UserAgent userAgent,
|
||||
Preferences preferences,
|
||||
|
||||
Socks5ProxyProvider socks5ProxyProvider,
|
||||
@Named(BtcOptionKeys.WALLET_DIR) File appDir) {
|
||||
this.regTestHost = regTestHost;
|
||||
|
@ -6,12 +6,12 @@ import org.slf4j.LoggerFactory;
|
||||
public class FeeData {
|
||||
private static final Logger log = LoggerFactory.getLogger(FeeData.class);
|
||||
|
||||
public final long txFee;
|
||||
public final long txFeePerByte;
|
||||
public final long createOfferFee;
|
||||
public final long takeOfferFee;
|
||||
|
||||
public FeeData(long txFee, long createOfferFee, long takeOfferFee) {
|
||||
this.txFee = txFee;
|
||||
public FeeData(long txFeePerByte, long createOfferFee, long takeOfferFee) {
|
||||
this.txFeePerByte = txFeePerByte;
|
||||
this.createOfferFee = createOfferFee;
|
||||
this.takeOfferFee = takeOfferFee;
|
||||
}
|
||||
|
@ -44,13 +44,13 @@ public class FeeService {
|
||||
public static final long MAX_TX_FEE = 200;
|
||||
public static final long DEFAULT_TX_FEE = 60;
|
||||
|
||||
public static final long MIN_CREATE_OFFER_FEE = 50_000;
|
||||
public static final long MIN_CREATE_OFFER_FEE = 10_000;
|
||||
public static final long MAX_CREATE_OFFER_FEE = 500_000;
|
||||
public static final long DEFAULT_CREATE_OFFER_FEE = 50_000;
|
||||
public static final long DEFAULT_CREATE_OFFER_FEE = 30_000;
|
||||
|
||||
public static final long MIN_TAKE_OFFER_FEE = 100_000;
|
||||
public static final long MIN_TAKE_OFFER_FEE = 10_000;
|
||||
public static final long MAX_TAKE_OFFER_FEE = 1000_000;
|
||||
public static final long DEFAULT_TAKE_OFFER_FEE = 100_000;
|
||||
public static final long DEFAULT_TAKE_OFFER_FEE = 80_000;
|
||||
|
||||
private final FeeProvider feeProvider;
|
||||
private final ProvidersRepository providersRepository;
|
||||
@ -104,15 +104,18 @@ public class FeeService {
|
||||
});
|
||||
}
|
||||
|
||||
public Coin getTxFee() {
|
||||
// feeData.txFee is sat/byte but we want satoshi / kb
|
||||
log.debug("getTxFee " + (feeData.txFee * 1000));
|
||||
return Coin.valueOf(feeData.txFee * 1000);
|
||||
public Coin getTxFee(int sizeInBytes) {
|
||||
return getTxFeePerByte().multiply(sizeInBytes);
|
||||
}
|
||||
|
||||
public Coin getTxFeePerByte() {
|
||||
log.debug("getTxFee " + (feeData.txFeePerByte));
|
||||
return Coin.valueOf(feeData.txFeePerByte);
|
||||
}
|
||||
|
||||
// TODO needed?
|
||||
public Coin getTxFeeForWithdrawal() {
|
||||
return getTxFee();
|
||||
return getTxFeePerByte();
|
||||
}
|
||||
|
||||
public Coin getCreateOfferFee() {
|
||||
|
@ -18,7 +18,6 @@
|
||||
package io.bitsquare.trade;
|
||||
|
||||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||
import io.bitsquare.common.handlers.ResultHandler;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
@ -61,7 +60,7 @@ public abstract class BuyerTrade extends Trade {
|
||||
public Coin getPayoutAmount() {
|
||||
checkNotNull(getTradeAmount(), "Invalid state: getTradeAmount() = null");
|
||||
|
||||
return FeePolicy.getSecurityDeposit().add(getTradeAmount());
|
||||
return getOffer().getSecurityDeposit().add(getTradeAmount());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -18,7 +18,6 @@
|
||||
package io.bitsquare.trade;
|
||||
|
||||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||
import io.bitsquare.common.handlers.ResultHandler;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
@ -58,7 +57,7 @@ public abstract class SellerTrade extends Trade {
|
||||
|
||||
@Override
|
||||
public Coin getPayoutAmount() {
|
||||
return FeePolicy.getSecurityDeposit();
|
||||
return getOffer().getSecurityDeposit();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -120,7 +120,10 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
// We use 2 type of prices: fixed price or price based on distance from market price
|
||||
private final boolean useMarketBasedPrice;
|
||||
// fiatPrice if fixed price is used (usePercentageBasedPrice = false), otherwise 0
|
||||
|
||||
//TODO add support for altcoin price or fix precision issue
|
||||
private final long fiatPrice;
|
||||
|
||||
// Distance form market price if percentage based price is used (usePercentageBasedPrice = true), otherwise 0.
|
||||
// E.g. 0.1 -> 10%. Can be negative as well. Depending on direction the marketPriceMargin is above or below the market price.
|
||||
// Positive values is always the usual case where you want a better price as the market.
|
||||
@ -140,12 +143,16 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
|
||||
// New properties from v. 0.5.0.0
|
||||
private final String versionNr;
|
||||
private final long blockHeightAtOfferCreation;
|
||||
private final long txFee;
|
||||
private final long createOfferFee;
|
||||
private final long takerFee;
|
||||
private final long securityDeposit;
|
||||
private final long maxTradeLimit;
|
||||
private final long maxTradePeriod;
|
||||
private final boolean useAutoClose;
|
||||
private final boolean useReOpenAfterAutoClose;
|
||||
private final long lowerClosePrice;
|
||||
private final long upperClosePrice;
|
||||
|
||||
// Reserved for possible future use to support private trades where the taker need to have an accessKey
|
||||
private final boolean isPrivateOffer;
|
||||
@ -196,15 +203,20 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
@Nullable ArrayList<String> acceptedBankIds,
|
||||
PriceFeedService priceFeedService,
|
||||
String versionNr,
|
||||
long blockHeightAtOfferCreation,
|
||||
long txFee,
|
||||
long createOfferFee,
|
||||
long takerFee,
|
||||
long securityDeposit,
|
||||
long maxTradeLimit,
|
||||
long maxTradePeriod,
|
||||
boolean useAutoClose,
|
||||
boolean useReOpenAfterAutoClose,
|
||||
long lowerClosePrice,
|
||||
long upperClosePrice,
|
||||
boolean isPrivateOffer,
|
||||
@Nullable String hashOfChallenge,
|
||||
@Nullable HashMap<String, String> extraDataMap) {
|
||||
|
||||
this.id = id;
|
||||
this.offererNodeAddress = offererNodeAddress;
|
||||
this.pubKeyRing = pubKeyRing;
|
||||
@ -224,12 +236,16 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
this.acceptedBankIds = acceptedBankIds;
|
||||
this.priceFeedService = priceFeedService;
|
||||
this.versionNr = versionNr;
|
||||
this.blockHeightAtOfferCreation = blockHeightAtOfferCreation;
|
||||
this.txFee = txFee;
|
||||
this.createOfferFee = createOfferFee;
|
||||
this.takerFee = takerFee;
|
||||
this.securityDeposit = securityDeposit;
|
||||
this.maxTradeLimit = maxTradeLimit;
|
||||
this.maxTradePeriod = maxTradePeriod;
|
||||
this.useAutoClose = useAutoClose;
|
||||
this.useReOpenAfterAutoClose = useReOpenAfterAutoClose;
|
||||
this.lowerClosePrice = lowerClosePrice;
|
||||
this.upperClosePrice = upperClosePrice;
|
||||
this.isPrivateOffer = isPrivateOffer;
|
||||
this.hashOfChallenge = hashOfChallenge;
|
||||
this.extraDataMap = extraDataMap;
|
||||
@ -261,6 +277,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
return offererNodeAddress;
|
||||
}
|
||||
|
||||
//TODO update with new properties
|
||||
public void validate() {
|
||||
checkNotNull(getAmount(), "Amount is null");
|
||||
checkNotNull(getArbitratorNodeAddresses(), "Arbitrator is null");
|
||||
@ -273,7 +290,6 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
checkNotNull(getPrice(), "Price is null");
|
||||
checkNotNull(getTxFee(), "txFee is null");
|
||||
checkNotNull(getCreateOfferFee(), "CreateOfferFee is null");
|
||||
checkNotNull(getTakerFee(), "TakerFee is null");
|
||||
checkNotNull(getVersionNr(), "VersionNr is null");
|
||||
checkNotNull(getSecurityDeposit(), "SecurityDeposit is null");
|
||||
checkNotNull(getMaxTradeLimit(), "MaxTradeLimit is null");
|
||||
@ -560,10 +576,6 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
return Coin.valueOf(createOfferFee);
|
||||
}
|
||||
|
||||
public Coin getTakerFee() {
|
||||
return Coin.valueOf(takerFee);
|
||||
}
|
||||
|
||||
public Coin getSecurityDeposit() {
|
||||
return Coin.valueOf(securityDeposit);
|
||||
}
|
||||
@ -576,6 +588,26 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
return maxTradePeriod;
|
||||
}
|
||||
|
||||
public long getBlockHeightAtOfferCreation() {
|
||||
return blockHeightAtOfferCreation;
|
||||
}
|
||||
|
||||
public boolean isUseAutoClose() {
|
||||
return useAutoClose;
|
||||
}
|
||||
|
||||
public boolean isUseReOpenAfterAutoClose() {
|
||||
return useReOpenAfterAutoClose;
|
||||
}
|
||||
|
||||
public long getLowerClosePrice() {
|
||||
return lowerClosePrice;
|
||||
}
|
||||
|
||||
public long getUpperClosePrice() {
|
||||
return upperClosePrice;
|
||||
}
|
||||
|
||||
public boolean isPrivateOffer() {
|
||||
return isPrivateOffer;
|
||||
}
|
||||
@ -590,6 +622,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
return extraDataMap;
|
||||
}
|
||||
|
||||
//TODO update with new properties
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@ -606,7 +639,6 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
if (minAmount != offer.minAmount) return false;
|
||||
if (txFee != offer.txFee) return false;
|
||||
if (createOfferFee != offer.createOfferFee) return false;
|
||||
if (takerFee != offer.takerFee) return false;
|
||||
if (securityDeposit != offer.securityDeposit) return false;
|
||||
if (maxTradePeriod != offer.maxTradePeriod) return false;
|
||||
if (maxTradeLimit != offer.maxTradeLimit) return false;
|
||||
@ -638,6 +670,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
|
||||
}
|
||||
|
||||
//TODO update with new properties
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
@ -666,7 +699,6 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
result = 31 * result + (versionNr != null ? versionNr.hashCode() : 0);
|
||||
result = 31 * result + (int) (txFee ^ (txFee >>> 32));
|
||||
result = 31 * result + (int) (createOfferFee ^ (createOfferFee >>> 32));
|
||||
result = 31 * result + (int) (takerFee ^ (takerFee >>> 32));
|
||||
result = 31 * result + (int) (securityDeposit ^ (securityDeposit >>> 32));
|
||||
result = 31 * result + (int) (maxTradePeriod ^ (maxTradePeriod >>> 32));
|
||||
result = 31 * result + (int) (maxTradeLimit ^ (maxTradeLimit >>> 32));
|
||||
@ -676,6 +708,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
return result;
|
||||
}
|
||||
|
||||
//TODO update with new properties
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Offer{" +
|
||||
@ -693,7 +726,6 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
|
||||
"\n\ttxFee=" + txFee +
|
||||
"\n\tcreateOfferFee=" + createOfferFee +
|
||||
"\n\ttakerFee=" + takerFee +
|
||||
"\n\tsecurityDeposit=" + securityDeposit +
|
||||
"\n\tmaxTradePeriod=" + maxTradePeriod +
|
||||
"\n\tmaxTradeLimit=" + maxTradeLimit +
|
||||
|
@ -23,6 +23,7 @@ import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.common.taskrunner.Task;
|
||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.trade.offer.Offer;
|
||||
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferModel;
|
||||
import io.bitsquare.trade.protocol.trade.ArbitrationSelectionRule;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
@ -40,6 +41,7 @@ public class CreateOfferFeeTx extends Task<PlaceOfferModel> {
|
||||
|
||||
@Override
|
||||
protected void run() {
|
||||
Offer offer = model.offer;
|
||||
try {
|
||||
runInterceptHook();
|
||||
|
||||
@ -48,26 +50,26 @@ public class CreateOfferFeeTx extends Task<PlaceOfferModel> {
|
||||
Arbitrator selectedArbitrator = model.user.getAcceptedArbitratorByAddress(selectedArbitratorNodeAddress);
|
||||
checkNotNull(selectedArbitrator, "selectedArbitrator must not be null at CreateOfferFeeTx");
|
||||
WalletService walletService = model.walletService;
|
||||
String id = model.offer.getId();
|
||||
String id = offer.getId();
|
||||
Transaction transaction = model.tradeWalletService.createTradingFeeTx(
|
||||
walletService.getOrCreateAddressEntry(id, AddressEntry.Context.OFFER_FUNDING).getAddress(),
|
||||
walletService.getOrCreateAddressEntry(id, AddressEntry.Context.RESERVED_FOR_TRADE).getAddress(),
|
||||
walletService.getOrCreateAddressEntry(AddressEntry.Context.AVAILABLE).getAddress(),
|
||||
model.reservedFundsForOffer,
|
||||
model.useSavingsWallet,
|
||||
model.offer.getCreateOfferFee(),
|
||||
model.offer.getTxFee(),
|
||||
offer.getCreateOfferFee(),
|
||||
offer.getTxFee(),
|
||||
selectedArbitrator.getBtcAddress());
|
||||
|
||||
// We assume there will be no tx malleability. We add a check later in case the published offer has a different hash.
|
||||
// As the txId is part of the offer and therefore change the hash data we need to be sure to have no
|
||||
// tx malleability
|
||||
model.offer.setOfferFeePaymentTxID(transaction.getHashAsString());
|
||||
offer.setOfferFeePaymentTxID(transaction.getHashAsString());
|
||||
model.setTransaction(transaction);
|
||||
|
||||
complete();
|
||||
} catch (Throwable t) {
|
||||
model.offer.setErrorMessage("An error occurred.\n" +
|
||||
offer.setErrorMessage("An error occurred.\n" +
|
||||
"Error message:\n"
|
||||
+ t.getMessage());
|
||||
failed(t);
|
||||
|
@ -18,7 +18,6 @@
|
||||
package io.bitsquare.trade.protocol.trade.tasks.buyer;
|
||||
|
||||
import io.bitsquare.btc.AddressEntry;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
|
||||
@ -41,7 +40,7 @@ public class SignAndFinalizePayoutTx extends TradeTask {
|
||||
try {
|
||||
runInterceptHook();
|
||||
checkNotNull(trade.getTradeAmount(), "trade.getTradeAmount() must not be null");
|
||||
Coin sellerPayoutAmount = FeePolicy.getSecurityDeposit();
|
||||
Coin sellerPayoutAmount = trade.getOffer().getSecurityDeposit();
|
||||
Coin buyerPayoutAmount = sellerPayoutAmount.add(trade.getTradeAmount());
|
||||
|
||||
Transaction transaction = processModel.getTradeWalletService().buyerSignsAndFinalizesPayoutTx(
|
||||
|
@ -18,7 +18,6 @@
|
||||
package io.bitsquare.trade.protocol.trade.tasks.buyer;
|
||||
|
||||
import io.bitsquare.btc.AddressEntry;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.btc.data.InputsAndChangeOutput;
|
||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||
import io.bitsquare.trade.Trade;
|
||||
@ -40,7 +39,7 @@ public class TakerCreatesDepositTxInputsAsBuyer extends TradeTask {
|
||||
runInterceptHook();
|
||||
Coin txFee = trade.getTxFee();
|
||||
Coin doubleTxFee = txFee.add(txFee);
|
||||
Coin takerInputAmount = FeePolicy.getSecurityDeposit().add(doubleTxFee);
|
||||
Coin takerInputAmount = trade.getOffer().getSecurityDeposit().add(doubleTxFee);
|
||||
InputsAndChangeOutput result = processModel.getTradeWalletService().takerCreatesDepositsTxInputs(
|
||||
takerInputAmount,
|
||||
txFee,
|
||||
|
@ -18,7 +18,6 @@
|
||||
package io.bitsquare.trade.protocol.trade.tasks.seller;
|
||||
|
||||
import io.bitsquare.btc.AddressEntry;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||
import io.bitsquare.trade.Trade;
|
||||
@ -42,7 +41,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 = trade.getOffer().getSecurityDeposit();
|
||||
Coin buyerPayoutAmount = sellerPayoutAmount.add(trade.getTradeAmount());
|
||||
|
||||
// We use the sellers LastBlockSeenHeight, which might be different to the buyers one.
|
||||
|
@ -18,7 +18,6 @@
|
||||
package io.bitsquare.trade.protocol.trade.tasks.seller;
|
||||
|
||||
import io.bitsquare.btc.AddressEntry;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.btc.data.InputsAndChangeOutput;
|
||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||
import io.bitsquare.trade.Trade;
|
||||
@ -41,7 +40,7 @@ public class TakerCreatesDepositTxInputsAsSeller extends TradeTask {
|
||||
if (trade.getTradeAmount() != null) {
|
||||
Coin txFee = trade.getTxFee();
|
||||
Coin doubleTxFee = txFee.add(txFee);
|
||||
Coin takerInputAmount = FeePolicy.getSecurityDeposit().add(doubleTxFee).add(trade.getTradeAmount());
|
||||
Coin takerInputAmount = trade.getOffer().getSecurityDeposit().add(doubleTxFee).add(trade.getTradeAmount());
|
||||
|
||||
InputsAndChangeOutput result = processModel.getTradeWalletService().takerCreatesDepositsTxInputs(takerInputAmount,
|
||||
txFee,
|
||||
|
@ -22,7 +22,6 @@ import io.bitsquare.app.DevFlags;
|
||||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.arbitration.Arbitrator;
|
||||
import io.bitsquare.btc.AddressEntry;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.btc.TradeWalletService;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.btc.blockchain.BlockchainService;
|
||||
@ -35,7 +34,6 @@ import io.bitsquare.gui.common.model.ActivatableDataModel;
|
||||
import io.bitsquare.gui.main.offer.createoffer.monetary.Price;
|
||||
import io.bitsquare.gui.main.offer.createoffer.monetary.Volume;
|
||||
import io.bitsquare.gui.main.overlays.notifications.Notification;
|
||||
import io.bitsquare.gui.main.overlays.popups.Popup;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.locale.CurrencyUtil;
|
||||
import io.bitsquare.locale.TradeCurrency;
|
||||
@ -79,7 +77,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||
private final BSFormatter formatter;
|
||||
private final String offerId;
|
||||
private final AddressEntry addressEntry;
|
||||
private Coin createOfferFeeAsCoin, takerFeeAsCoin;
|
||||
private Coin createOfferFeeAsCoin;
|
||||
private Coin txFeeAsCoin;
|
||||
private Coin securityDepositAsCoin;
|
||||
private final BalanceListener balanceListener;
|
||||
@ -147,6 +145,9 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||
|
||||
useMarketBasedPrice.set(preferences.getUsePercentageBasedPrice());
|
||||
|
||||
// TODO add ui for editing
|
||||
securityDepositAsCoin = Coin.valueOf(1_000_000);
|
||||
|
||||
balanceListener = new BalanceListener(getAddressEntry().getAddress()) {
|
||||
@Override
|
||||
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||
@ -184,21 +185,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||
addBindings();
|
||||
addListeners();
|
||||
|
||||
feeService.requestFees(() -> {
|
||||
//TODO update doubleTxFeeAsCoin and txFeeAsCoin in view with binding
|
||||
createOfferFeeAsCoin = feeService.getCreateOfferFee();
|
||||
takerFeeAsCoin = feeService.getTakeOfferFee();
|
||||
txFeeAsCoin = feeService.getTxFee();
|
||||
calculateTotalToPay();
|
||||
}, (errorMessage, throwable) -> new Popup<>().warning(errorMessage).show());
|
||||
|
||||
createOfferFeeAsCoin = feeService.getCreateOfferFee();
|
||||
takerFeeAsCoin = feeService.getTakeOfferFee();
|
||||
txFeeAsCoin = feeService.getTxFee();
|
||||
|
||||
// TODO
|
||||
securityDepositAsCoin = FeePolicy.getSecurityDeposit();
|
||||
|
||||
if (!preferences.getUseStickyMarketPrice() && isTabSelected)
|
||||
priceFeedService.setCurrencyCode(tradeCurrencyCode.get());
|
||||
|
||||
@ -235,6 +221,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// called before activate()
|
||||
boolean initWithData(Offer.Direction direction, TradeCurrency tradeCurrency) {
|
||||
this.direction = direction;
|
||||
|
||||
@ -260,6 +247,25 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||
if (!preferences.getUseStickyMarketPrice())
|
||||
priceFeedService.setCurrencyCode(tradeCurrencyCode.get());
|
||||
|
||||
// The offerer only pays the mining fee for the trade fee tx (not the mining fee for other trade txs).
|
||||
// A typical trade fee tx has about 226 bytes (if one input). We use 400 as a safe value.
|
||||
// We cannot use tx size calculation as we do not know initially how the input is funded. And we require the
|
||||
// fee for getting the funds needed.
|
||||
// So we use an estimated average size and risk that in some cases we might get a bit of delay if the actual required
|
||||
// fee would be larger.
|
||||
// As we use the best fee estimation (for 1 confirmation) that risk should not be too critical as long there are
|
||||
// not too many inputs.
|
||||
|
||||
// trade fee tx: 226 bytes (1 input) - 374 bytes (2 inputs)
|
||||
feeService.requestFees(() -> {
|
||||
createOfferFeeAsCoin = feeService.getCreateOfferFee();
|
||||
txFeeAsCoin = feeService.getTxFee(400);
|
||||
calculateTotalToPay();
|
||||
}, null);
|
||||
|
||||
createOfferFeeAsCoin = feeService.getCreateOfferFee();
|
||||
txFeeAsCoin = feeService.getTxFee(400);
|
||||
|
||||
calculateVolume();
|
||||
calculateTotalToPay();
|
||||
return true;
|
||||
@ -278,6 +284,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||
Offer createAndGetOffer() {
|
||||
long priceAsLong = price.get() != null && !useMarketBasedPrice.get() ? price.get().getValue() : 0L;
|
||||
// We use precision 8 in AltcoinPrice but in Offer we use Fiat with precision 4. Will be refactored once in a bigger update....
|
||||
// TODO use same precision for both in next release
|
||||
if (CurrencyUtil.isCryptoCurrency(tradeCurrencyCode.get()))
|
||||
priceAsLong = priceAsLong / 10000;
|
||||
|
||||
@ -312,10 +319,14 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||
long maxTradeLimit = paymentAccount.getPaymentMethod().getMaxTradeLimit().value;
|
||||
long maxTradePeriod = paymentAccount.getPaymentMethod().getMaxTradePeriod();
|
||||
|
||||
// reserved for future use cases
|
||||
boolean isPrivateOffer = false;
|
||||
String hashOfChallenge = null;
|
||||
HashMap<String, String> extraDataMap = null;
|
||||
|
||||
boolean useAutoClose = false;
|
||||
boolean useReOpenAfterAutoClose = false;
|
||||
long lowerClosePrice = 0;
|
||||
long upperClosePrice = 0;
|
||||
|
||||
return new Offer(offerId,
|
||||
p2PService.getAddress(),
|
||||
@ -337,12 +348,16 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||
priceFeedService,
|
||||
|
||||
Version.VERSION,
|
||||
walletService.getWallet().getLastBlockSeenHeight(),
|
||||
txFeeAsCoin.value,
|
||||
createOfferFeeAsCoin.value,
|
||||
takerFeeAsCoin.value,
|
||||
securityDepositAsCoin.value,
|
||||
maxTradeLimit,
|
||||
maxTradePeriod,
|
||||
useAutoClose,
|
||||
useReOpenAfterAutoClose,
|
||||
upperClosePrice,
|
||||
lowerClosePrice,
|
||||
isPrivateOffer,
|
||||
hashOfChallenge,
|
||||
extraDataMap);
|
||||
|
@ -21,7 +21,6 @@ import com.google.inject.Inject;
|
||||
import io.bitsquare.app.DevFlags;
|
||||
import io.bitsquare.arbitration.Arbitrator;
|
||||
import io.bitsquare.btc.AddressEntry;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.btc.TradeWalletService;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.btc.blockchain.BlockchainService;
|
||||
@ -162,7 +161,6 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||
void initWithData(Offer offer) {
|
||||
this.offer = offer;
|
||||
tradePrice = offer.getPrice();
|
||||
takerFeeAsCoin = offer.getTakerFee();
|
||||
addressEntry = walletService.getOrCreateAddressEntry(offer.getId(), AddressEntry.Context.OFFER_FUNDING);
|
||||
checkNotNull(addressEntry, "addressEntry must not be null");
|
||||
|
||||
@ -175,24 +173,39 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||
if (DevFlags.DEV_MODE)
|
||||
amountAsCoin.set(offer.getAmount());
|
||||
|
||||
securityDepositAsCoin = offer.getSecurityDeposit();
|
||||
|
||||
// Taker pays 2 times the tx fee because the mining fee might be different when offerer created the offer
|
||||
// and reserved his funds, so that would not work well with dynamic fees.
|
||||
// The mining fee for the takeOfferFee tx is deducted from the createOfferFee and not visible to the trader
|
||||
|
||||
// The taker pays the mining fee for the trade fee tx and the trade txs.
|
||||
// A typical trade fee tx has about 226 bytes (if one input). The trade txs has about 336-414 bytes.
|
||||
// We use 400 as a safe value.
|
||||
// We cannot use tx size calculation as we do not know initially how the input is funded. And we require the
|
||||
// fee for getting the funds needed.
|
||||
// So we use an estimated average size and risk that in some cases we might get a bit of delay if the actual required
|
||||
// fee would be larger.
|
||||
// As we use the best fee estimation (for 1 confirmation) that risk should not be too critical as long there are
|
||||
// not too many inputs. The trade txs have no risks as there cannot be more than about 414 bytes.
|
||||
// Only the trade fee tx carries a risk that it might be larger.
|
||||
|
||||
// trade fee tx: 226 bytes (1 input) - 374 bytes (2 inputs)
|
||||
// deposit tx: 336 bytes (1 MS output+ OP_RETURN) - 414 bytes (1 MS output + OP_RETURN + change in case of smaller trade amount)
|
||||
// payout tx: 371 bytes
|
||||
// disputed payout tx: 408 bytes
|
||||
feeService.requestFees(() -> {
|
||||
//TODO update doubleTxFeeAsCoin and txFeeAsCoin in view with binding
|
||||
takerFeeAsCoin = feeService.getTakeOfferFee();
|
||||
txFeeAsCoin = feeService.getTxFee();
|
||||
txFeeAsCoin = feeService.getTxFee(400);
|
||||
totalTxFeeAsCoin = txFeeAsCoin.multiply(3);
|
||||
calculateTotalToPay();
|
||||
}, (errorMessage, throwable) -> new Popup<>().warning(errorMessage).show());
|
||||
}, null);
|
||||
|
||||
takerFeeAsCoin = feeService.getTakeOfferFee();
|
||||
txFeeAsCoin = feeService.getTxFee();
|
||||
txFeeAsCoin = feeService.getTxFee(400);
|
||||
totalTxFeeAsCoin = txFeeAsCoin.multiply(3);
|
||||
|
||||
//TODO
|
||||
securityDepositAsCoin = FeePolicy.getSecurityDeposit();
|
||||
|
||||
calculateVolume();
|
||||
calculateTotalToPay();
|
||||
|
||||
|
@ -21,7 +21,6 @@ import io.bitsquare.arbitration.Dispute;
|
||||
import io.bitsquare.arbitration.DisputeManager;
|
||||
import io.bitsquare.arbitration.DisputeResult;
|
||||
import io.bitsquare.btc.AddressEntry;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.btc.TradeWalletService;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.btc.exceptions.TransactionVerificationException;
|
||||
@ -370,16 +369,18 @@ 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 tradeAmount = dispute.getContract().getTradeAmount();
|
||||
Contract contract = dispute.getContract();
|
||||
Coin securityDeposit = contract.offer.getSecurityDeposit();
|
||||
Coin tradeAmount = contract.getTradeAmount();
|
||||
Coin available = tradeAmount.add(securityDeposit).add(securityDeposit);
|
||||
Coin totalAmount = buyerAmount.add(sellerAmount).add(arbitratorAmount);
|
||||
return (totalAmount.compareTo(available) == 0);
|
||||
}
|
||||
|
||||
private void applyCustomAmounts(InputTextField inputTextField) {
|
||||
Coin securityDeposit = FeePolicy.getSecurityDeposit();
|
||||
Coin tradeAmount = dispute.getContract().getTradeAmount();
|
||||
Contract contract = dispute.getContract();
|
||||
Coin securityDeposit = contract.offer.getSecurityDeposit();
|
||||
Coin tradeAmount = contract.getTradeAmount();
|
||||
|
||||
Coin buyerAmount = formatter.parseToCoin(buyerPayoutAmountInputTextField.getText());
|
||||
Coin sellerAmount = formatter.parseToCoin(sellerPayoutAmountInputTextField.getText());
|
||||
@ -669,7 +670,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
||||
|
||||
private void calculatePayoutAmounts(DisputeResult.DisputeFeePolicy feePayment) {
|
||||
Contract contract = dispute.getContract();
|
||||
Coin refund = FeePolicy.getSecurityDeposit();
|
||||
Coin refund = contract.offer.getSecurityDeposit();
|
||||
Coin winnerRefund;
|
||||
Coin loserRefund;
|
||||
switch (feePayment) {
|
||||
|
@ -18,7 +18,6 @@
|
||||
package io.bitsquare.gui.main.overlays.windows;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.common.crypto.KeyRing;
|
||||
import io.bitsquare.common.util.Tuple3;
|
||||
import io.bitsquare.gui.Navigation;
|
||||
@ -264,7 +263,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(offer.getSecurityDeposit()));
|
||||
|
||||
if (paymentMethodCountryCode != null)
|
||||
addLabelTextField(gridPane, ++rowIndex, "Offerer's country of bank:",
|
||||
|
@ -18,7 +18,6 @@
|
||||
package io.bitsquare.gui.main.overlays.windows;
|
||||
|
||||
import io.bitsquare.arbitration.DisputeManager;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.gui.components.TextFieldWithCopyIcon;
|
||||
import io.bitsquare.gui.main.MainView;
|
||||
import io.bitsquare.gui.main.overlays.Overlay;
|
||||
@ -172,7 +171,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(offer.getSecurityDeposit()));
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "Selected arbitrator:", trade.getArbitratorNodeAddress().getFullAddress());
|
||||
|
||||
if (trade.getTradingPeerNodeAddress() != null)
|
||||
|
@ -19,7 +19,6 @@ package io.bitsquare.gui.main.portfolio.pendingtrades;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.common.Clock;
|
||||
import io.bitsquare.gui.common.model.ActivatableWithDataModel;
|
||||
import io.bitsquare.gui.common.model.ViewModel;
|
||||
@ -268,7 +267,10 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
}
|
||||
|
||||
public String getSecurityDeposit() {
|
||||
return formatter.formatCoinWithCode(FeePolicy.getSecurityDeposit());
|
||||
if (dataModel.getOffer() != null)
|
||||
return formatter.formatCoinWithCode(dataModel.getOffer().getSecurityDeposit());
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public boolean isBlockChainMethod() {
|
||||
|
@ -60,6 +60,10 @@ public class TradesChartsViewModelTest {
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
@ -288,6 +288,10 @@ public class OfferBookViewModelTest {
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user