Merge branch 'master' into Development

# Conflicts:
#	common/pom.xml
#	common/src/main/java/io/bitsquare/app/Version.java
#	core/pom.xml
#	core/src/main/java/io/bitsquare/locale/CurrencyUtil.java
#	gui/pom.xml
#	jsocks/pom.xml
#	jtorctl/pom.xml
#	jtorproxy/pom.xml
#	network/pom.xml
#	package/linux/create_32bit_app.sh
#	package/linux/create_64bit_app.sh
#	package/mac/create_app.sh
#	package/windows/Bitsquare.iss
#	package/windows/create_32bit_app.bat
#	package/windows/create_app.bat
#	pom.xml
#	seednode/pom.xml
This commit is contained in:
Manfred Karrer 2016-05-05 13:30:18 +02:00
commit b9dfa0a7a7
53 changed files with 530 additions and 251 deletions

View file

@ -18,7 +18,7 @@ You can read about all of this and more in the [whitepaper](https://bitsquare.io
Status Status
------ ------
The software is Alpha version and still under heavy development. Bitsquare has releases the beta version on the 27th of April 2016 after 3 months testing on mainnet.
For the latest version checkout our [releases page](https://github.com/bitsquare/bitsquare/releases) at Github. For the latest version checkout our [releases page](https://github.com/bitsquare/bitsquare/releases) at Github.
Building from source Building from source

View file

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.3</version> <version>0.4.6</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View file

@ -30,7 +30,7 @@ public class Log {
private static SizeBasedTriggeringPolicy triggeringPolicy; private static SizeBasedTriggeringPolicy triggeringPolicy;
private static Logger logbackLogger; private static Logger logbackLogger;
public static void setup(String fileName, boolean useDetailedLogging) { public static void setup(String fileName) {
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
RollingFileAppender appender = new RollingFileAppender(); RollingFileAppender appender = new RollingFileAppender();
@ -60,8 +60,8 @@ public class Log {
appender.start(); appender.start();
logbackLogger = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); logbackLogger = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
logbackLogger.setLevel(useDetailedLogging ? Level.TRACE : Level.WARN);
logbackLogger.addAppender(appender); logbackLogger.addAppender(appender);
logbackLogger.setLevel(Level.INFO);
// log errors in separate file // log errors in separate file
// not working as expected still.... damn logback... // not working as expected still.... damn logback...
@ -80,6 +80,10 @@ public class Log {
logbackLogger.addAppender(errorAppender);*/ logbackLogger.addAppender(errorAppender);*/
} }
public static void setLevel(boolean useDetailedLogging) {
logbackLogger.setLevel(useDetailedLogging ? Level.TRACE : Level.WARN);
}
public static void traceCall() { public static void traceCall() {
if (LoggerFactory.getLogger(Log.class).isTraceEnabled()) { if (LoggerFactory.getLogger(Log.class).isTraceEnabled()) {
StackTraceElement stackTraceElement = new Throwable().getStackTrace()[1]; StackTraceElement stackTraceElement = new Throwable().getStackTrace()[1];

View file

@ -24,7 +24,7 @@ public class Version {
private static final Logger log = LoggerFactory.getLogger(Version.class); private static final Logger log = LoggerFactory.getLogger(Version.class);
// The application versions // The application versions
public static final String VERSION = "0.4.3"; public static final String VERSION = "0.4.6";
// The version nr. for the objects sent over the network. A change will break the serialization of old objects. // The version nr. for the objects sent over the network. A change will break the serialization of old objects.
// If objects are used for both network and database the network version is applied. // If objects are used for both network and database the network version is applied.
@ -81,6 +81,4 @@ public class Version {
", getP2PNetworkId()=" + getP2PMessageVersion() + ", getP2PNetworkId()=" + getP2PMessageVersion() +
'}'); '}');
} }
} }

View file

@ -30,10 +30,15 @@ import org.slf4j.LoggerFactory;
import java.awt.*; import java.awt.*;
import java.io.*; import java.io.*;
import java.lang.reflect.Field;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URLConnection; import java.net.URLConnection;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.security.Permission;
import java.security.PermissionCollection;
import java.util.Locale;
import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.concurrent.*; import java.util.concurrent.*;
@ -115,7 +120,49 @@ public class Utilities {
} }
private static String getOSName() { private static String getOSName() {
return System.getProperty("os.name").toLowerCase(); return System.getProperty("os.name").toLowerCase(Locale.US);
}
public static String getOSArchitecture() {
String osArch = System.getProperty("os.arch");
if (isWindows()) {
// See: Like always windows needs extra treatment
// https://stackoverflow.com/questions/20856694/how-to-find-the-os-bit-type
String arch = System.getenv("PROCESSOR_ARCHITECTURE");
String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432");
return arch.endsWith("64")
|| wow64Arch != null && wow64Arch.endsWith("64")
? "64" : "32";
} else if (isLinux()) {
return osArch.startsWith("i") ? "32" : "64";
} else {
return osArch.contains("64") ? "64" : osArch;
}
}
public static void printSysInfo() {
log.info("os.name: " + System.getProperty("os.name"));
log.info("os.version: " + System.getProperty("os.version"));
log.info("os.arch: " + System.getProperty("os.arch"));
log.info("sun.arch.data.model: " + getJVMArchitecture());
log.info("JRE: " + System.getProperty("java.runtime.version", "-") + " (" + System.getProperty("java.vendor", "-") + ")");
log.info("JVM: " + System.getProperty("java.vm.version", "-") + " (" + System.getProperty("java.vm.name", "-") + ")");
}
public static String getJVMArchitecture() {
return System.getProperty("sun.arch.data.model");
}
public static boolean isCorrectOSArchitecture() {
boolean result = getOSArchitecture().endsWith(getJVMArchitecture());
if (!result) {
log.warn("System.getProperty(\"os.arch\") " + System.getProperty("os.arch"));
log.warn("System.getenv(\"ProgramFiles(x86)\") " + System.getenv("ProgramFiles(x86)"));
log.warn("System.getenv(\"PROCESSOR_ARCHITECTURE\")" + System.getenv("PROCESSOR_ARCHITECTURE"));
log.warn("System.getenv(\"PROCESSOR_ARCHITEW6432\") " + System.getenv("PROCESSOR_ARCHITEW6432"));
log.warn("System.getProperty(\"sun.arch.data.model\") " + System.getProperty("sun.arch.data.model"));
}
return result;
} }
public static void openURI(URI uri) throws IOException { public static void openURI(URI uri) throws IOException {
@ -373,4 +420,42 @@ public class Utilities {
return false; return false;
} }
} }
// See: https://stackoverflow.com/questions/1179672/how-to-avoid-installing-unlimited-strength-jce-policy-files-when-deploying-an
public static void removeCryptographyRestrictions() {
if (!isRestrictedCryptography()) {
log.debug("Cryptography restrictions removal not needed");
return;
}
try {
final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");
final Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
isRestrictedField.setAccessible(true);
isRestrictedField.set(null, false);
final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
defaultPolicyField.setAccessible(true);
final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);
final Field perms = cryptoPermissions.getDeclaredField("perms");
perms.setAccessible(true);
((Map<?, ?>) perms.get(defaultPolicy)).clear();
final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
instance.setAccessible(true);
defaultPolicy.add((Permission) instance.get(null));
log.debug("Successfully removed cryptography restrictions");
} catch (Exception e) {
log.warn("Failed to remove cryptography restrictions", e);
}
}
public static boolean isRestrictedCryptography() {
// This simply matches the Oracle JRE, but not OpenJDK.
return "Java(TM) SE Runtime Environment".equals(System.getProperty("java.runtime.name"));
}
} }

View file

@ -6,7 +6,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.3</version> <version>0.4.6</version>
</parent> </parent>
<artifactId>core</artifactId> <artifactId>core</artifactId>

View file

@ -67,6 +67,12 @@ public final class Alert implements StoragePayload {
return signatureAsBase64; return signatureAsBase64;
} }
public boolean isNewVersion() {
int versionNum = Integer.valueOf(Version.VERSION.replace(".", ""));
int alertVersionNum = Integer.valueOf(version.replace(".", ""));
return versionNum < alertVersionNum;
}
@Override @Override
public long getTTL() { public long getTTL() {
return TTL; return TTL;

View file

@ -60,16 +60,6 @@ public class FeePolicy {
return NON_TRADE_FEE_PER_KB; return NON_TRADE_FEE_PER_KB;
} }
// Some wallets don't support manual fees. Most use at least 0.0001 BTC (0.04 EUR @ 400 EUR/BTC)
// To avoid rejecting deposit tx with too low mining fees we reduce the min.
// required fee to 0.0001 BTC. There is a risk that the tx does not get fast into the blockchain but it seems it has less
// negative consequences as forcing the user to set a sufficiently high fee which is impossible in some wallets
// like in the old MultiBit wallet or Coinbase. Unfortunately there is no perfect solution for that problem.
public static Coin getMinRequiredFeeForFundingTx() {
return Coin.valueOf(10_000);
}
// 0.0005 BTC 0.05% of 1 BTC about 0.2 EUR @ 400 EUR/BTC // 0.0005 BTC 0.05% of 1 BTC about 0.2 EUR @ 400 EUR/BTC
public static Coin getCreateOfferFee() { public static Coin getCreateOfferFee() {
// We need to pay the quite high miner fee of 30_000 from the trading fee tx so 30_000 us our lower limit // We need to pay the quite high miner fee of 30_000 from the trading fee tx so 30_000 us our lower limit

View file

@ -24,7 +24,7 @@ public class Restrictions {
public static final Coin MIN_TRADE_AMOUNT = Coin.parseCoin("0.0001"); // 4 cent @ 400 EUR/BTC public static final Coin MIN_TRADE_AMOUNT = Coin.parseCoin("0.0001"); // 4 cent @ 400 EUR/BTC
public static boolean isAboveFixedTxFeeAndDust(Coin amount) { public static boolean isAboveFixedTxFeeForTradesAndDust(Coin amount) {
return amount != null && amount.compareTo(FeePolicy.getFixedTxFeeForTrades().add(Transaction.MIN_NONDUST_OUTPUT)) > 0; return amount != null && amount.compareTo(FeePolicy.getFixedTxFeeForTrades().add(Transaction.MIN_NONDUST_OUTPUT)) > 0;
} }

View file

@ -145,7 +145,7 @@ public class TradeWalletService {
boolean useSavingsWallet, Coin tradingFee, String feeReceiverAddresses) boolean useSavingsWallet, Coin tradingFee, String feeReceiverAddresses)
throws InsufficientMoneyException, AddressFormatException { throws InsufficientMoneyException, AddressFormatException {
Transaction tradingFeeTx = new Transaction(params); Transaction tradingFeeTx = new Transaction(params);
Preconditions.checkArgument(Restrictions.isAboveFixedTxFeeAndDust(tradingFee), Preconditions.checkArgument(Restrictions.isAboveFixedTxFeeForTradesAndDust(tradingFee),
"You cannot send an amount which are smaller than the fee + dust output."); "You cannot send an amount which are smaller than the fee + dust output.");
Coin outPutAmount = tradingFee.subtract(FeePolicy.getFixedTxFeeForTrades()); Coin outPutAmount = tradingFee.subtract(FeePolicy.getFixedTxFeeForTrades());
tradingFeeTx.addOutput(outPutAmount, new Address(params, feeReceiverAddresses)); tradingFeeTx.addOutput(outPutAmount, new Address(params, feeReceiverAddresses));

View file

@ -39,10 +39,7 @@ import org.bitcoinj.kits.WalletAppKit;
import org.bitcoinj.params.MainNetParams; import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.params.RegTestParams; import org.bitcoinj.params.RegTestParams;
import org.bitcoinj.params.TestNet3Params; import org.bitcoinj.params.TestNet3Params;
import org.bitcoinj.script.Script;
import org.bitcoinj.utils.Threading; import org.bitcoinj.utils.Threading;
import org.bitcoinj.wallet.CoinSelection;
import org.bitcoinj.wallet.CoinSelector;
import org.bitcoinj.wallet.DeterministicSeed; import org.bitcoinj.wallet.DeterministicSeed;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -98,6 +95,7 @@ public class WalletService {
public final BooleanProperty shutDownDone = new SimpleBooleanProperty(); public final BooleanProperty shutDownDone = new SimpleBooleanProperty();
private final Storage<Long> storage; private final Storage<Long> storage;
private final Long bloomFilterTweak; private final Long bloomFilterTweak;
private KeyParameter aesKey;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -340,6 +338,10 @@ public class WalletService {
} }
} }
public void setAesKey(KeyParameter aesKey) {
this.aesKey = aesKey;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Listener // Listener
@ -574,22 +576,24 @@ public class WalletService {
public Coin getRequiredFee(String fromAddress, public Coin getRequiredFee(String fromAddress,
String toAddress, String toAddress,
Coin amount, Coin amount,
AddressEntry.Context context) throws AddressFormatException, AddressEntryException { AddressEntry.Context context)
throws AddressFormatException, AddressEntryException {
Optional<AddressEntry> addressEntry = findAddressEntry(fromAddress, context); Optional<AddressEntry> addressEntry = findAddressEntry(fromAddress, context);
if (!addressEntry.isPresent()) if (!addressEntry.isPresent())
throw new AddressEntryException("WithdrawFromAddress is not found in our wallet."); throw new AddressEntryException("WithdrawFromAddress is not found in our wallet.");
checkNotNull(addressEntry.get().getAddress(), "addressEntry.get().getAddress() must nto be null"); checkNotNull(addressEntry.get().getAddress(), "addressEntry.get().getAddress() must nto be null");
CoinSelector selector = new TradeWalletCoinSelector(params, addressEntry.get().getAddress()); return getFee(fromAddress,
return getFee(toAddress, toAddress,
amount, amount,
selector); context,
Coin.ZERO);
} }
public Coin getRequiredFeeForMultipleAddresses(Set<String> fromAddresses, public Coin getRequiredFeeForMultipleAddresses(Set<String> fromAddresses,
String toAddress, String toAddress,
Coin amount) throws AddressFormatException, Coin amount)
AddressEntryException { throws AddressFormatException, AddressEntryException {
Set<AddressEntry> addressEntries = fromAddresses.stream() Set<AddressEntry> addressEntries = fromAddresses.stream()
.map(address -> { .map(address -> {
Optional<AddressEntry> addressEntryOptional = findAddressEntry(address, AddressEntry.Context.AVAILABLE); Optional<AddressEntry> addressEntryOptional = findAddressEntry(address, AddressEntry.Context.AVAILABLE);
@ -606,63 +610,55 @@ public class WalletService {
.collect(Collectors.toSet()); .collect(Collectors.toSet());
if (addressEntries.isEmpty()) if (addressEntries.isEmpty())
throw new AddressEntryException("No Addresses for withdraw found in our wallet"); throw new AddressEntryException("No Addresses for withdraw found in our wallet");
return getFeeForMultipleAddresses(fromAddresses,
CoinSelector selector = new MultiAddressesCoinSelector(params, addressEntries); toAddress,
return getFee(toAddress,
amount, amount,
selector); Coin.ZERO);
} }
private Coin getFee(String toAddress,
Coin amount,
CoinSelector selector) throws AddressFormatException, AddressEntryException {
List<TransactionOutput> candidates = wallet.calculateAllSpendCandidates();
CoinSelection bestCoinSelection = selector.select(params.getMaxMoney(), candidates);
Transaction tx = new Transaction(params);
tx.addOutput(amount, new Address(params, toAddress));
if (!adjustOutputDownwardsForFee(tx, bestCoinSelection, Coin.ZERO, FeePolicy.getNonTradeFeePerKb()))
throw new Wallet.CouldNotAdjustDownwards();
Coin fee = amount.subtract(tx.getOutput(0).getValue()); private Coin getFee(String fromAddress,
log.info("Required fee " + fee); String toAddress,
Coin amount,
AddressEntry.Context context,
Coin fee) throws AddressEntryException, AddressFormatException {
try {
wallet.completeTx(getSendRequest(fromAddress, toAddress, amount, aesKey, context));
} catch (InsufficientMoneyException e) {
if (e.missing != null) {
log.trace("missing fee " + e.missing.toFriendlyString());
fee = fee.add(e.missing);
amount = amount.subtract(fee);
return getFee(fromAddress,
toAddress,
amount,
context,
fee);
}
}
log.trace("result fee " + fee.toFriendlyString());
return fee; return fee;
} }
private boolean adjustOutputDownwardsForFee(Transaction tx, CoinSelection coinSelection, Coin baseFee, Coin feePerKb) { private Coin getFeeForMultipleAddresses(Set<String> fromAddresses,
TransactionOutput output = tx.getOutput(0); String toAddress,
// Check if we need additional fee due to the transaction's size Coin amount,
int size = tx.bitcoinSerialize().length; Coin fee) throws AddressEntryException, AddressFormatException {
size += estimateBytesForSigning(coinSelection);
Coin fee = baseFee.add(feePerKb.multiply((size / 1000) + 1));
output.setValue(output.getValue().subtract(fee));
// Check if we need additional fee due to the output's value
if (output.getValue().compareTo(Coin.CENT) < 0 && fee.compareTo(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE) < 0)
output.setValue(output.getValue().subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.subtract(fee)));
return output.getMinNonDustValue().compareTo(output.getValue()) <= 0;
}
private int estimateBytesForSigning(CoinSelection selection) {
int size = 0;
for (TransactionOutput output : selection.gathered) {
try { try {
Script script = output.getScriptPubKey(); wallet.completeTx(getSendRequestForMultipleAddresses(fromAddresses, toAddress, amount, null, aesKey));
ECKey key = null; } catch (InsufficientMoneyException e) {
Script redeemScript = null; if (e.missing != null) {
if (script.isSentToAddress()) { log.trace("missing fee " + e.missing.toFriendlyString());
key = wallet.findKeyFromPubHash(script.getPubKeyHash()); fee = fee.add(e.missing);
checkNotNull(key, "Coin selection includes unspendable outputs"); amount = amount.subtract(fee);
} else if (script.isPayToScriptHash()) { return getFeeForMultipleAddresses(fromAddresses,
redeemScript = wallet.findRedeemDataFromScriptHash(script.getPubKeyHash()).redeemScript; toAddress,
checkNotNull(redeemScript, "Coin selection includes unspendable outputs"); amount,
} fee);
size += script.getNumberOfBytesRequiredToSpend(key, redeemScript);
} catch (ScriptException e) {
// If this happens it means an output script in a wallet tx could not be understood. That should never
// happen, if it does it means the wallet has got into an inconsistent state.
throw new IllegalStateException(e);
} }
} }
return size; log.trace("result fee " + fee.toFriendlyString());
return fee;
} }
@ -726,7 +722,7 @@ public class WalletService {
AddressEntryException, InsufficientMoneyException { AddressEntryException, InsufficientMoneyException {
Transaction tx = new Transaction(params); Transaction tx = new Transaction(params);
Preconditions.checkArgument(Restrictions.isAboveDust(amount), Preconditions.checkArgument(Restrictions.isAboveDust(amount),
"You cannot send an amount which are smaller than 546 satoshis."); "The amount is too low (dust limit).");
tx.addOutput(amount, new Address(params, toAddress)); tx.addOutput(amount, new Address(params, toAddress));
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx); Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
@ -751,7 +747,7 @@ public class WalletService {
AddressFormatException, AddressEntryException, InsufficientMoneyException { AddressFormatException, AddressEntryException, InsufficientMoneyException {
Transaction tx = new Transaction(params); Transaction tx = new Transaction(params);
Preconditions.checkArgument(Restrictions.isAboveDust(amount), Preconditions.checkArgument(Restrictions.isAboveDust(amount),
"You cannot send an amount which are smaller than 546 satoshis."); "The amount is too low (dust limit).");
tx.addOutput(amount, new Address(params, toAddress)); tx.addOutput(amount, new Address(params, toAddress));
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx); Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);

View file

@ -37,7 +37,7 @@ public class BankUtil {
countryCode = ""; countryCode = "";
switch (countryCode) { switch (countryCode) {
default: default:
return "Bank nr.(BIC/SWIFT):"; return "Bank nr. or BIC/SWIFT:";
} }
} }
@ -64,7 +64,7 @@ public class BankUtil {
countryCode = ""; countryCode = "";
switch (countryCode) { switch (countryCode) {
default: default:
return "Account nr.(IBAN):"; return "Account nr. or IBAN:";
} }
} }

View file

@ -68,21 +68,8 @@ public class CurrencyUtil {
return allSortedCryptoCurrencies; return allSortedCryptoCurrencies;
} }
public static List<CryptoCurrency> getMainCryptoCurrencies() { // Don't make a PR for adding a coin but follow the steps described here:
final List<CryptoCurrency> result = new ArrayList<>(); // https://forum.bitsquare.io/t/how-to-add-your-favorite-altcoin/
result.add(new CryptoCurrency("ETH", "Ethereum"));
result.add(new CryptoCurrency("LTC", "Litecoin"));
result.add(new CryptoCurrency("DASH", "Dash"));
result.add(new CryptoCurrency("SDC", "ShadowCash"));
result.add(new CryptoCurrency("NMC", "Namecoin"));
result.add(new CryptoCurrency("NBT", "NuBits"));
result.add(new CryptoCurrency("FAIR", "FairCoin"));
result.add(new CryptoCurrency("DOGE", "Dogecoin"));
result.add(new CryptoCurrency("NXT", "Nxt"));
result.add(new CryptoCurrency("BTS", "BitShares"));
return result;
}
public static List<CryptoCurrency> createAllSortedCryptoCurrenciesList() { public static List<CryptoCurrency> createAllSortedCryptoCurrenciesList() {
final List<CryptoCurrency> result = new ArrayList<>(); final List<CryptoCurrency> result = new ArrayList<>();
result.add(new CryptoCurrency("ETH", "Ethereum")); result.add(new CryptoCurrency("ETH", "Ethereum"));
@ -105,16 +92,46 @@ public class CurrencyUtil {
result.add(new CryptoCurrency("BTS", "BitShares")); result.add(new CryptoCurrency("BTS", "BitShares"));
result.add(new CryptoCurrency("XCP", "Counterparty")); result.add(new CryptoCurrency("XCP", "Counterparty"));
result.add(new CryptoCurrency("XRP", "Ripple")); result.add(new CryptoCurrency("XRP", "Ripple"));
result.add(new CryptoCurrency("XEM", "NEM"));
result.add(new CryptoCurrency("ANTI", "Anti"));
result.add(new CryptoCurrency("VPN", "VPNCoin"));
result.add(new CryptoCurrency("MAID", "MaidSafeCoin"));
result.add(new CryptoCurrency("YBC", "YbCoin"));
result.add(new CryptoCurrency("CLOAK", "CloakCoin"));
result.add(new CryptoCurrency("EGC", "EverGreenCoin"));
result.add(new CryptoCurrency("VRC", "VeriCoin"));
result.add(new CryptoCurrency("ESP", "Espers"));
result.add(new CryptoCurrency("XVG", "Verge"));
result.add(new CryptoCurrency("MYRC", "Myriadcoin"));
result.add(new CryptoCurrency("MXT", "MarteXcoin"));
result.add(new CryptoCurrency("GRS", "Groestlcoin"));
result.add(new CryptoCurrency("IOC", "I/O Coin"));
result.add(new CryptoCurrency("SIB", "Sibcoin"));
result.add(new CryptoCurrency("CRBIT", "Creditbit"));
result.add(new CryptoCurrency("BIGUP", "BigUp"));
result.add(new CryptoCurrency("XPTX", "PlatinumBar"));
// Unfortunately we cannot support CryptoNote coins yet as there is no way to proof the transaction. Payment ID helps only locate the tx but the
// arbitrator cannot see if the receiving key matches the receivers address. They might add support for exposing the tx key, but that is not
// implemented yet. To use the view key (also not available in GUI wallets) would reveal the complete wallet history for incoming payments, which is
// not acceptable from privacy point of view.
// result.add(new CryptoCurrency("XMR", "Monero")); // result.add(new CryptoCurrency("XMR", "Monero"));
// result.add(new CryptoCurrency("BCN", "Bytecoin")); // result.add(new CryptoCurrency("BCN", "Bytecoin"));
return result; return result;
} }
public static List<CryptoCurrency> getMainCryptoCurrencies() {
final List<CryptoCurrency> result = new ArrayList<>();
result.add(new CryptoCurrency("ETH", "Ethereum"));
result.add(new CryptoCurrency("LTC", "Litecoin"));
result.add(new CryptoCurrency("DASH", "Dash"));
result.add(new CryptoCurrency("SDC", "ShadowCash"));
result.add(new CryptoCurrency("NMC", "Namecoin"));
result.add(new CryptoCurrency("NBT", "NuBits"));
result.add(new CryptoCurrency("SC", "Siacoin"));
result.add(new CryptoCurrency("FAIR", "FairCoin"));
result.add(new CryptoCurrency("DOGE", "Dogecoin"));
result.add(new CryptoCurrency("NXT", "Nxt"));
result.add(new CryptoCurrency("BTS", "BitShares"));
return result;
}
/** /**
* @return Sorted list of SEPA currencies with EUR as first item * @return Sorted list of SEPA currencies with EUR as first item

View file

@ -371,7 +371,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
return null; return null;
} }
} else { } else {
log.warn("We don't have a market price.\n" + log.debug("We don't have a market price.\n" +
"That case could only happen if you don't have a price feed."); "That case could only happen if you don't have a price feed.");
return null; return null;
} }

View file

@ -28,21 +28,21 @@ public class RestrictionsTest {
@Test @Test
public void testIsMinSpendableAmount() { public void testIsMinSpendableAmount() {
Coin amount = null; Coin amount = null;
assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeAndDust(amount)); assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeForTradesAndDust(amount));
amount = Coin.ZERO; amount = Coin.ZERO;
assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeAndDust(amount)); assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeForTradesAndDust(amount));
amount = FeePolicy.getFixedTxFeeForTrades(); amount = FeePolicy.getFixedTxFeeForTrades();
assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeAndDust(amount)); assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeForTradesAndDust(amount));
amount = Transaction.MIN_NONDUST_OUTPUT; amount = Transaction.MIN_NONDUST_OUTPUT;
assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeAndDust(amount)); assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeForTradesAndDust(amount));
amount = FeePolicy.getFixedTxFeeForTrades().add(Transaction.MIN_NONDUST_OUTPUT); amount = FeePolicy.getFixedTxFeeForTrades().add(Transaction.MIN_NONDUST_OUTPUT);
assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeAndDust(amount)); assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeForTradesAndDust(amount));
amount = FeePolicy.getFixedTxFeeForTrades().add(Transaction.MIN_NONDUST_OUTPUT).add(Coin.valueOf(1)); amount = FeePolicy.getFixedTxFeeForTrades().add(Transaction.MIN_NONDUST_OUTPUT).add(Coin.valueOf(1));
assertTrue("tx unfunded, pending", Restrictions.isAboveFixedTxFeeAndDust(amount)); assertTrue("tx unfunded, pending", Restrictions.isAboveFixedTxFeeForTradesAndDust(amount));
} }
} }

View file

@ -12,15 +12,15 @@ For the impatient
What follows is explained in detail in the sections below, but for those who know their way around Java, git and Maven, here are the instructions in a nutshell: What follows is explained in detail in the sections below, but for those who know their way around Java, git and Maven, here are the instructions in a nutshell:
$ javac -version $ javac -version
javac 1.8.0_40 # must be 1.8.0_40 or better javac 1.8.0_66 # must be 1.8.0_66 or better
$ git clone https://github.com/bitsquare/bitcoinj.git $ git clone -b FixBloomFilters https://github.com/bitsquare/bitcoinj.git
$ cd bitcoinj $ cd bitcoinj
$ mvn install -DskipTests -Dmaven.javadoc.skip=true $ mvn clean install -DskipTests -Dmaven.javadoc.skip=true
$ git clone https://github.com/bitsquare/bitsquare.git $ git clone https://github.com/bitsquare/bitsquare.git
$ cd bitsquare $ cd bitsquare
$ mvn package $ mvn clean package -DskipTests
When the build completes, you will find an executable jar: `gui/target/shaded.jar`. When the build completes, you will find an executable jar: `gui/target/shaded.jar`.
To run it use: To run it use:
@ -34,16 +34,34 @@ Prerequisites
The only prerequisite for building Bitsquare is installing the Java Development Kit (JDK), version 8u40 or better (as well as maven and git). The only prerequisite for building Bitsquare is installing the Java Development Kit (JDK), version 8u40 or better (as well as maven and git).
In Debian/Ubuntu systems with OpenJDK you'll need OpenJFX as well, i.e. you'll need the `openjfx` package besides the `openjdk-8-jdk` package. In Debian/Ubuntu systems with OpenJDK you'll need OpenJFX as well, i.e. you'll need the `openjfx` package besides the `openjdk-8-jdk` package.
To check the version of Java you currently have installed: ##### 1. Check the version of Java you currently have installed
$ javac -version $ javac -version
javac 1.8.0_40 javac 1.8.0_66
If `javac` is not found, or your version is anything less than `1.8.0_40`, then you'll need to [download and install the latest JDK]( http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) for your platform. If `javac` is not found, or your version is anything less than `1.8.0_66`, then you'll need to [download and install the latest JDK]( http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) for your platform.
> _**TIP:** Here are [instructions](http://www.webupd8.org/2014/03/how-to-install-oracle-java-8-in-debian.html) for installing the JDK via `apt` on Debian/Ubuntu systems. > _**TIP:** Here are [instructions](http://www.webupd8.org/2014/03/how-to-install-oracle-java-8-in-debian.html) for installing the JDK via `apt` on Debian/Ubuntu systems.
> Bitsquare can be built with OpenJDK as well, but this hasn't been thoroughly tested yet._ > Bitsquare can be built with OpenJDK as well, but this hasn't been thoroughly tested yet._
##### 2. Enable unlimited Strength for cryptographic keys
Bitsquare uses 256 bit length keys which are still not permitted by default.
Get around that ridiculous fact by adding the missing [jars from Oracle](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html).
Please follow the steps described in the Readme file at the downloaded package.
You will get an error when building Bitsquare package if you don't have these.
##### 3. Copy the BountyCastle provider jar file
Copy the BountyCastle provider jar file (bcprov-jdk15on-1.53.jar) from you local maven repository (/home/.m2) to $JavaHome/jre/lib/ext/.
This prevent a "JCE cannot authenticate the provider BC" exception when starting the Bitsquare client.
##### 4. Edit the jre\lib\security\java.security file to add BouncyCastleProvider
Add org.bouncycastle.jce.provider.BouncyCastleProvider as last entry at: List of providers and their preference orders
E.g.:
security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider
Steps Steps
----- -----
@ -64,16 +82,16 @@ We remove Cartographer/HttpDiscovery support from in our [fork version 0.13.1.2]
Beside the Java serialisation issues here are [privacy concerns](http://bitcoin-development.narkive.com/hczWIAby/bitcoin-development-cartographer#post3) regarding Cartographer. Beside the Java serialisation issues here are [privacy concerns](http://bitcoin-development.narkive.com/hczWIAby/bitcoin-development-cartographer#post3) regarding Cartographer.
Beside that we fixed a few [flaws with the Bloom Filters](https://jonasnick.github.io/blog/2015/02/12/privacy-in-bitcoinj) in BitcoinJ. Beside that we fixed a few [flaws with the Bloom Filters](https://jonasnick.github.io/blog/2015/02/12/privacy-in-bitcoinj) in BitcoinJ.
$ git clone https://github.com/bitsquare/bitcoinj.git $ git clone -b FixBloomFilters https://github.com/bitsquare/bitcoinj.git
$ cd bitcoinj $ cd bitcoinj
$ mvn install -DskipTests -Dmaven.javadoc.skip=true $ mvn clean install -DskipTests -Dmaven.javadoc.skip=true
### 3. Build jar ### 3. Build jar
Bitsquare uses maven as a build system. Bitsquare uses maven as a build system.
$ cd bitsquare $ cd bitsquare
$ mvn package $ mvn clean package -DskipTests
### 4. Run ### 4. Run
@ -123,15 +141,6 @@ Here are example program arguments for using regtest and using the Tor network:
$ java -jar gui/target/shaded.jar --bitcoin.network=regtest node.port=4442 --devTest=true --app.name=Bitsquare-Tor-Regtest-Bob $ java -jar gui/target/shaded.jar --bitcoin.network=regtest node.port=4442 --devTest=true --app.name=Bitsquare-Tor-Regtest-Bob
### 7. Enable unlimited Strength for cryptographic keys
Bitsquare uses 256 bit length keys which are still not permitted by default.
Get around that ridiculous fact by adding the missing [jars from Oracle](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html).
Copy the BountyCastle provider jar file (bcprov-jdk15on-1.53.jar) from you local maven repository (/home/.m2) to $JavaHome/jre/lib/ext (to avoid getting
a "JCE cannot authenticate the provider BC" exception).
Problems? Problems?
--------- ---------

View file

@ -22,7 +22,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.3</version> <version>0.4.6</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View file

@ -54,7 +54,6 @@ import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.text.Font;
import javafx.stage.Modality; import javafx.stage.Modality;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.StageStyle; import javafx.stage.StageStyle;
@ -100,10 +99,12 @@ public class BitsquareApp extends Application {
@Override @Override
public void start(Stage primaryStage) throws IOException { public void start(Stage primaryStage) throws IOException {
String logPath = Paths.get(env.getProperty(BitsquareEnvironment.APP_DATA_DIR_KEY), "bitsquare").toString(); String logPath = Paths.get(env.getProperty(BitsquareEnvironment.APP_DATA_DIR_KEY), "bitsquare").toString();
Log.setup(logPath, !IS_RELEASE_VERSION);
log.info("Log files under: " + logPath);
Log.setup(logPath);
log.info("Log files under: " + logPath);
Version.printVersion(); Version.printVersion();
Utilities.printSysInfo();
Log.setLevel(!IS_RELEASE_VERSION);
UserThread.setExecutor(Platform::runLater); UserThread.setExecutor(Platform::runLater);
UserThread.setTimerClass(UITimer.class); UserThread.setTimerClass(UITimer.class);
@ -124,6 +125,8 @@ public class BitsquareApp extends Application {
Thread.setDefaultUncaughtExceptionHandler(handler); Thread.setDefaultUncaughtExceptionHandler(handler);
Thread.currentThread().setUncaughtExceptionHandler(handler); Thread.currentThread().setUncaughtExceptionHandler(handler);
if (Utilities.isRestrictedCryptography())
Utilities.removeCryptographyRestrictions();
Security.addProvider(new BouncyCastleProvider()); Security.addProvider(new BouncyCastleProvider());
BitsquareApp.primaryStage = primaryStage; BitsquareApp.primaryStage = primaryStage;
@ -158,7 +161,7 @@ public class BitsquareApp extends Application {
mainView.setPersistedFilesCorrupted(corruptedDatabaseFiles); mainView.setPersistedFilesCorrupted(corruptedDatabaseFiles);
});*/ });*/
scene = new Scene(mainView.getRoot(), 1150, 740); scene = new Scene(mainView.getRoot(), 1190, 740);
scene.getStylesheets().setAll( scene.getStylesheets().setAll(
"/io/bitsquare/gui/bitsquare.css", "/io/bitsquare/gui/bitsquare.css",
"/io/bitsquare/gui/images.css"); "/io/bitsquare/gui/images.css");
@ -190,7 +193,7 @@ public class BitsquareApp extends Application {
// configure the primary stage // configure the primary stage
primaryStage.setTitle(env.getRequiredProperty(APP_NAME_KEY)); primaryStage.setTitle(env.getRequiredProperty(APP_NAME_KEY));
primaryStage.setScene(scene); primaryStage.setScene(scene);
primaryStage.setMinWidth(1130); primaryStage.setMinWidth(1170);
primaryStage.setMinHeight(620); primaryStage.setMinHeight(620);
// on windows the title icon is also used as task bar icon in a larger size // on windows the title icon is also used as task bar icon in a larger size
@ -208,10 +211,18 @@ public class BitsquareApp extends Application {
// make the UI visible // make the UI visible
primaryStage.show(); primaryStage.show();
Font fon = Font.getDefault();
Font fonds = Font.getDefault();
//showDebugWindow(); if (!Utilities.isCorrectOSArchitecture()) {
String osArchitecture = Utilities.getOSArchitecture();
// We don't force a shutdown as the osArchitecture might in strange cases return a wrong value.
// Needs at least more testing on different machines...
new Popup<>().warning("You have probably the wrong version installed for the architecture of your computer.\n" +
"Your computers architecture is: " + osArchitecture + ".\n" +
"The Bitsquare binary you installed is: " + Utilities.getJVMArchitecture() + ".\n" +
"Please shut down and re-install the correct version (" + osArchitecture + ").")
.show();
}
} catch (Throwable throwable) { } catch (Throwable throwable) {
showErrorPopup(throwable, false); showErrorPopup(throwable, false);
} }
@ -220,8 +231,8 @@ public class BitsquareApp extends Application {
private void showSendAlertMessagePopup() { private void showSendAlertMessagePopup() {
AlertManager alertManager = injector.getInstance(AlertManager.class); AlertManager alertManager = injector.getInstance(AlertManager.class);
new SendAlertMessageWindow() new SendAlertMessageWindow()
.onAddAlertMessage((alert, privKeyString) -> alertManager.addAlertMessageIfKeyIsValid(alert, privKeyString)) .onAddAlertMessage(alertManager::addAlertMessageIfKeyIsValid)
.onRemoveAlertMessage(privKeyString -> alertManager.removeAlertMessageIfKeyIsValid(privKeyString)) .onRemoveAlertMessage(alertManager::removeAlertMessageIfKeyIsValid)
.show(); .show();
} }

View file

@ -128,7 +128,7 @@ public class SystemTray {
e1.printStackTrace(); e1.printStackTrace();
} }
}); });
exitItem.addActionListener(e -> onExit.run()); exitItem.addActionListener(e -> UserThread.execute(onExit::run));
} }
public void hideStage() { public void hideStage() {

View file

@ -152,7 +152,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
return type != null ? "Market price (" + type.name + ")" : ""; return type != null ? "Market price (" + type.name + ")" : "";
}, },
model.marketPriceCurrency, model.typeProperty)); model.marketPriceCurrency, model.typeProperty));
HBox.setMargin(marketPriceBox.third, new Insets(0, 20, 0, 0)); HBox.setMargin(marketPriceBox.third, new Insets(0, 0, 0, 0));
Tuple2<TextField, VBox> availableBalanceBox = getBalanceBox("Available balance"); Tuple2<TextField, VBox> availableBalanceBox = getBalanceBox("Available balance");
@ -243,7 +243,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
private Tuple2<TextField, VBox> getBalanceBox(String text) { private Tuple2<TextField, VBox> getBalanceBox(String text) {
TextField textField = new TextField(); TextField textField = new TextField();
textField.setEditable(false); textField.setEditable(false);
textField.setPrefWidth(120); textField.setPrefWidth(140);
textField.setMouseTransparent(true); textField.setMouseTransparent(true);
textField.setFocusTraversable(false); textField.setFocusTraversable(false);
textField.setStyle("-fx-alignment: center; -fx-background-color: white;"); textField.setStyle("-fx-alignment: center; -fx-background-color: white;");

View file

@ -81,6 +81,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.security.Security;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@ -443,6 +444,7 @@ public class MainViewModel implements ViewModel {
walletPasswordWindow walletPasswordWindow
.onAesKey(aesKey -> { .onAesKey(aesKey -> {
tradeWalletService.setAesKey(aesKey); tradeWalletService.setAesKey(aesKey);
walletService.setAesKey(aesKey);
walletInitialized.set(true); walletInitialized.set(true);
}) })
.hideCloseButton() .hideCloseButton()
@ -541,7 +543,7 @@ public class MainViewModel implements ViewModel {
log.error(msg); log.error(msg);
UserThread.execute(() -> new Popup<>().warning(msg) UserThread.execute(() -> new Popup<>().warning(msg)
.actionButtonText("Shut down") .actionButtonText("Shut down")
.onAction(() -> BitsquareApp.shutDownHandler.run()) .onAction(BitsquareApp.shutDownHandler::run)
.closeButtonText("Report bug at Github issues") .closeButtonText("Report bug at Github issues")
.onClose(() -> Utilities.openWebPage("https://github.com/bitsquare/bitsquare/issues")) .onClose(() -> Utilities.openWebPage("https://github.com/bitsquare/bitsquare/issues"))
.show()); .show());
@ -549,6 +551,15 @@ public class MainViewModel implements ViewModel {
} }
}; };
checkCryptoThread.start(); checkCryptoThread.start();
if (Security.getProvider("BC") == null) {
new Popup<>().warning("There is a problem with the crypto libraries. BountyCastle is not available.")
.actionButtonText("Shut down")
.onAction(BitsquareApp.shutDownHandler::run)
.closeButtonText("Report bug at Github issues")
.onClose(() -> Utilities.openWebPage("https://github.com/bitsquare/bitsquare/issues"))
.show();
}
} }
@ -813,12 +824,11 @@ public class MainViewModel implements ViewModel {
private void displayAlertIfPresent(Alert alert) { private void displayAlertIfPresent(Alert alert) {
boolean alreadyDisplayed = alert != null && alert.equals(user.getDisplayedAlert()); boolean alreadyDisplayed = alert != null && alert.equals(user.getDisplayedAlert());
user.setDisplayedAlert(alert); user.setDisplayedAlert(alert);
if (alert != null &&
if (alert != null && !alreadyDisplayed) { !alreadyDisplayed &&
if (!alert.isUpdateInfo || !alert.version.equals(Version.VERSION)) (!alert.isUpdateInfo || alert.isNewVersion()))
new DisplayAlertMessageWindow().alertMessage(alert).show(); new DisplayAlertMessageWindow().alertMessage(alert).show();
} }
}
private void swapPendingOfferFundingEntries() { private void swapPendingOfferFundingEntries() {
tradeManager.getAddressEntriesForAvailableBalanceStream() tradeManager.getAddressEntriesForAvailableBalanceStream()

View file

@ -87,6 +87,7 @@ public class BackupView extends ActivatableView<GridPane, Void> {
protected void activate() { protected void activate() {
selectBackupDir.setOnAction(e -> { selectBackupDir.setOnAction(e -> {
DirectoryChooser directoryChooser = new DirectoryChooser(); DirectoryChooser directoryChooser = new DirectoryChooser();
directoryChooser.setInitialDirectory(new File(System.getProperty("user.home")));
directoryChooser.setTitle("Select backup location"); directoryChooser.setTitle("Select backup location");
File dir = directoryChooser.showDialog(stage); File dir = directoryChooser.showDialog(stage);
if (dir != null) { if (dir != null) {

View file

@ -117,6 +117,7 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
if (wallet.checkAESKey(aesKey)) { if (wallet.checkAESKey(aesKey)) {
wallet.decrypt(aesKey); wallet.decrypt(aesKey);
tradeWalletService.setAesKey(null); tradeWalletService.setAesKey(null);
walletService.setAesKey(null);
new Popup() new Popup()
.feedback("Wallet successfully decrypted and password protection removed.") .feedback("Wallet successfully decrypted and password protection removed.")
.show(); .show();
@ -133,6 +134,7 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
wallet.encrypt(keyCrypterScrypt, aesKey); wallet.encrypt(keyCrypterScrypt, aesKey);
// we save the key for the trade wallet as we don't require passwords here // we save the key for the trade wallet as we don't require passwords here
tradeWalletService.setAesKey(aesKey); tradeWalletService.setAesKey(aesKey);
walletService.setAesKey(aesKey);
new Popup() new Popup()
.feedback("Wallet successfully encrypted and password protection enabled.") .feedback("Wallet successfully encrypted and password protection enabled.")
.show(); .show();

View file

@ -292,7 +292,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
private Coin getAmountAsCoin() { private Coin getAmountAsCoin() {
Coin senderAmount = formatter.parseToCoin(amountTextField.getText()); Coin senderAmount = formatter.parseToCoin(amountTextField.getText());
if (!Restrictions.isAboveFixedTxFeeAndDust(senderAmount)) { if (!Restrictions.isAboveFixedTxFeeForTradesAndDust(senderAmount)) {
senderAmount = Coin.ZERO; senderAmount = Coin.ZERO;
/* new Popup() /* new Popup()
.warning("The amount is lower than the transaction fee and the min. possible tx value (dust).") .warning("The amount is lower than the transaction fee and the min. possible tx value (dust).")

View file

@ -43,7 +43,7 @@ public class TransactionsListItem {
@Nullable @Nullable
private Tradable tradable; private Tradable tradable;
private String details; private String details;
private String addressString; private String addressString = "";
private String direction; private String direction;
private TxConfidenceListener txConfidenceListener; private TxConfidenceListener txConfidenceListener;
private boolean received; private boolean received;

View file

@ -41,17 +41,21 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList; import javafx.collections.transformation.SortedList;
import javafx.event.EventHandler;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.util.Callback; import javafx.util.Callback;
import org.bitcoinj.core.*; import org.bitcoinj.core.*;
import org.bitcoinj.script.Script; import org.bitcoinj.script.Script;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.List; import java.util.*;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -77,7 +81,8 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
private final DisputeManager disputeManager; private final DisputeManager disputeManager;
private final OfferDetailsWindow offerDetailsWindow; private final OfferDetailsWindow offerDetailsWindow;
private WalletEventListener walletEventListener; private WalletEventListener walletEventListener;
private EventHandler<KeyEvent> keyEventEventHandler;
private Scene scene;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, lifecycle // Constructor, lifecycle
@ -164,6 +169,33 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
updateList(); updateList();
} }
}; };
keyEventEventHandler = event -> {
if (new KeyCodeCombination(KeyCode.A, KeyCombination.SHORTCUT_DOWN).match(event)) {
Map<Long, List<Coin>> map = new HashMap<>();
observableList.stream().forEach(item -> {
Coin amountAsCoin = item.getAmountAsCoin();
List<Coin> list;
long key = amountAsCoin.getValue();
if (!map.containsKey(key)) {
list = new ArrayList<>();
map.put(key, list);
} else {
list = map.get(key);
}
list.add(amountAsCoin);
});
StringBuilder stringBuilder = new StringBuilder();
map.entrySet().stream().forEach(e -> {
stringBuilder.append("Nr. of transactions for amount ").
append(formatter.formatCoinWithCode(Coin.valueOf(e.getKey()))).
append(": ").
append(e.getValue().size()).
append("\n");
});
new Popup().headLine("Statistical info").information(stringBuilder.toString()).show();
}
};
} }
@Override @Override
@ -173,6 +205,10 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
updateList(); updateList();
walletService.getWallet().addEventListener(walletEventListener); walletService.getWallet().addEventListener(walletEventListener);
scene = root.getScene();
if (scene != null)
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
} }
@Override @Override
@ -180,6 +216,9 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
sortedList.comparatorProperty().unbind(); sortedList.comparatorProperty().unbind();
observableList.forEach(TransactionsListItem::cleanup); observableList.forEach(TransactionsListItem::cleanup);
walletService.getWallet().removeEventListener(walletEventListener); walletService.getWallet().removeEventListener(walletEventListener);
if (scene != null)
scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
} }

View file

@ -22,7 +22,6 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.app.BitsquareApp; import io.bitsquare.app.BitsquareApp;
import io.bitsquare.btc.AddressEntry; import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.AddressEntryException; import io.bitsquare.btc.AddressEntryException;
import io.bitsquare.btc.Restrictions;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.listeners.BalanceListener; import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.common.UserThread; import io.bitsquare.common.UserThread;
@ -40,8 +39,10 @@ import io.bitsquare.trade.TradeManager;
import io.bitsquare.trade.closed.ClosedTradableManager; import io.bitsquare.trade.closed.ClosedTradableManager;
import io.bitsquare.trade.failed.FailedTradesManager; import io.bitsquare.trade.failed.FailedTradesManager;
import io.bitsquare.user.Preferences; import io.bitsquare.user.Preferences;
import javafx.beans.binding.Bindings; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList; import javafx.collections.transformation.SortedList;
@ -50,10 +51,7 @@ import javafx.scene.control.*;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.util.Callback; import javafx.util.Callback;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.*;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.Transaction;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.spongycastle.crypto.params.KeyParameter; import org.spongycastle.crypto.params.KeyParameter;
@ -87,6 +85,10 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
private Set<WithdrawalListItem> selectedItems = new HashSet<>(); private Set<WithdrawalListItem> selectedItems = new HashSet<>();
private BalanceListener balanceListener; private BalanceListener balanceListener;
private Set<String> fromAddresses; private Set<String> fromAddresses;
private Coin amountOfSelectedItems = Coin.ZERO;
private ObjectProperty<Coin> senderAmountAsCoinProperty = new SimpleObjectProperty<>(Coin.ZERO);
private ChangeListener<String> amountListener;
private ChangeListener<Boolean> amountFocusListener;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -130,6 +132,23 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
updateList(); updateList();
} }
}; };
amountListener = (observable, oldValue, newValue) -> {
if (amountTextField.focusedProperty().get()) {
try {
senderAmountAsCoinProperty.set(formatter.parseToCoin(amountTextField.getText()));
} catch (Throwable t) {
log.error("Error at amountTextField input. " + t.toString());
}
}
};
amountFocusListener = (observable, oldValue, newValue) -> {
if (oldValue && !newValue) {
if (senderAmountAsCoinProperty.get().isPositive())
amountTextField.setText(formatter.formatCoin(senderAmountAsCoinProperty.get()));
else
amountTextField.setText("");
}
};
} }
@Override @Override
@ -140,17 +159,18 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
reset(); reset();
amountTextField.textProperty().addListener(amountListener);
amountTextField.focusedProperty().addListener(amountFocusListener);
walletService.addBalanceListener(balanceListener); walletService.addBalanceListener(balanceListener);
withdrawButton.disableProperty().bind(Bindings.createBooleanBinding(() -> !areInputsValid(),
amountTextField.textProperty(), withdrawToTextField.textProperty()));
} }
@Override @Override
protected void deactivate() { protected void deactivate() {
sortedList.comparatorProperty().unbind(); sortedList.comparatorProperty().unbind();
observableList.forEach(WithdrawalListItem::cleanup); observableList.forEach(WithdrawalListItem::cleanup);
withdrawButton.disableProperty().unbind();
walletService.removeBalanceListener(balanceListener); walletService.removeBalanceListener(balanceListener);
amountTextField.textProperty().removeListener(amountListener);
amountTextField.focusedProperty().removeListener(amountFocusListener);
} }
@ -160,8 +180,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
@FXML @FXML
public void onWithdraw() { public void onWithdraw() {
Coin senderAmount = formatter.parseToCoin(amountTextField.getText()); if (areInputsValid()) {
if (Restrictions.isAboveFixedTxFeeAndDust(senderAmount)) {
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() { FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
@Override @Override
public void onSuccess(@javax.annotation.Nullable Transaction transaction) { public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
@ -186,14 +205,18 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
} }
}; };
try { try {
// We need to use the max. amount (amountOfSelectedItems) as the senderAmount might be less then
// we have available and then the fee calculation would return 0
// TODO Get a proper fee calculation from BitcoinJ directly
Coin requiredFee = walletService.getRequiredFeeForMultipleAddresses(fromAddresses, Coin requiredFee = walletService.getRequiredFeeForMultipleAddresses(fromAddresses,
withdrawToTextField.getText(), senderAmount); withdrawToTextField.getText(), amountOfSelectedItems);
Coin receiverAmount = senderAmount.subtract(requiredFee); Coin receiverAmount = senderAmountAsCoinProperty.get().subtract(requiredFee);
if (receiverAmount.isPositive()) {
if (BitsquareApp.DEV_MODE) { if (BitsquareApp.DEV_MODE) {
doWithdraw(receiverAmount, callback); doWithdraw(receiverAmount, callback);
} else { } else {
new Popup().headLine("Confirm withdrawal request") new Popup().headLine("Confirm withdrawal request")
.confirmation("Sending: " + formatter.formatCoinWithCode(senderAmount) + "\n" + .confirmation("Sending: " + formatter.formatCoinWithCode(senderAmountAsCoinProperty.get()) + "\n" +
"From address: " + withdrawFromTextField.getText() + "\n" + "From address: " + withdrawFromTextField.getText() + "\n" +
"To receiving address: " + withdrawToTextField.getText() + ".\n" + "To receiving address: " + withdrawToTextField.getText() + ".\n" +
"Required transaction fee is: " + formatter.formatCoinWithCode(requiredFee) + "\n\n" + "Required transaction fee is: " + formatter.formatCoinWithCode(requiredFee) + "\n\n" +
@ -205,14 +228,15 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
.show(); .show();
} }
} else {
new Popup().warning("The amount you would like to send is too low as the bitcoin transaction fee will be deducted.\n" +
"Please use a higher amount.").show();
}
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
log.error(e.getMessage()); log.error(e.getMessage());
new Popup().error(e.getMessage()).show(); new Popup().warning(e.getMessage()).show();
} }
} else {
new Popup().warning("The amount to transfer is lower than the transaction fee and the min. possible tx value (dust).")
.show();
} }
} }
@ -227,10 +251,13 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
.collect(Collectors.toSet()); .collect(Collectors.toSet());
if (!selectedItems.isEmpty()) { if (!selectedItems.isEmpty()) {
Coin sum = Coin.valueOf(selectedItems.stream().mapToLong(e -> e.getBalance().getValue()).sum()); amountOfSelectedItems = Coin.valueOf(selectedItems.stream().mapToLong(e -> e.getBalance().getValue()).sum());
if (sum.isPositive()) { if (amountOfSelectedItems.isPositive()) {
amountTextField.setText(formatter.formatCoin(sum)); senderAmountAsCoinProperty.set(amountOfSelectedItems);
amountTextField.setText(formatter.formatCoin(amountOfSelectedItems));
} else { } else {
senderAmountAsCoinProperty.set(Coin.ZERO);
amountOfSelectedItems = Coin.ZERO;
amountTextField.setText(""); amountTextField.setText("");
withdrawFromTextField.setText(""); withdrawFromTextField.setText("");
} }
@ -298,11 +325,17 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
updateList(); updateList();
} catch (AddressFormatException e) { } catch (AddressFormatException e) {
new Popup().warning("The address is not correct. Please check the address format.").show(); new Popup().warning("The address is not correct. Please check the address format.").show();
} catch (Wallet.DustySendRequested e) {
new Popup().warning("The amount you would like to send is below the dust limit and would be rejected by the bitcoin network.\n" +
"Please use a higher amount.").show();
} catch (AddressEntryException e) { } catch (AddressEntryException e) {
new Popup().error(e.getMessage()).show(); new Popup().error(e.getMessage()).show();
} catch (InsufficientMoneyException e) { } catch (InsufficientMoneyException e) {
log.warn(e.getMessage()); log.warn(e.getMessage());
new Popup().warning("You don't have enough fund in your wallet.").show(); new Popup().warning("You don't have enough fund in your wallet.").show();
} catch (Throwable e) {
log.warn(e.getMessage());
new Popup().warning(e.getMessage()).show();
} }
} }
@ -315,6 +348,8 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
withdrawFromTextField.setPromptText("Select a source address from the table"); withdrawFromTextField.setPromptText("Select a source address from the table");
withdrawFromTextField.setTooltip(null); withdrawFromTextField.setTooltip(null);
amountOfSelectedItems = Coin.ZERO;
senderAmountAsCoinProperty.set(Coin.ZERO);
amountTextField.setText(""); amountTextField.setText("");
amountTextField.setPromptText("Set the amount to withdraw"); amountTextField.setPromptText("Set the amount to withdraw");
@ -338,9 +373,27 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
} }
private boolean areInputsValid() { private boolean areInputsValid() {
return btcAddressValidator.validate(withdrawToTextField.getText()).isValid && if (!senderAmountAsCoinProperty.get().isPositive()) {
amountTextField.getText().length() > 0 && new Popup().warning("Please fill in a valid value for the amount to send (max. 8 decimal places).").show();
Restrictions.isAboveFixedTxFeeAndDust(formatter.parseToCoin(amountTextField.getText())); return false;
}
if (!btcAddressValidator.validate(withdrawToTextField.getText()).isValid) {
new Popup().warning("Please fill in a valid receiver bitcoin address.").show();
return false;
}
if (!amountOfSelectedItems.isPositive()) {
new Popup().warning("You need to select a source address in the table above.").show();
return false;
}
if (senderAmountAsCoinProperty.get().compareTo(amountOfSelectedItems) > 0) {
new Popup().warning("Your amount exceeds the available amount for the selected address.\n" +
"Consider to select multiple addresses in the table above if you want to withdraw more.").show();
return false;
}
return true;
} }

View file

@ -27,10 +27,7 @@ import io.bitsquare.gui.main.offer.BuyOfferView;
import io.bitsquare.gui.main.offer.SellOfferView; import io.bitsquare.gui.main.offer.SellOfferView;
import io.bitsquare.gui.main.offer.offerbook.OfferBookListItem; import io.bitsquare.gui.main.offer.offerbook.OfferBookListItem;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.*;
import io.bitsquare.locale.CryptoCurrency;
import io.bitsquare.locale.FiatCurrency;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.trade.offer.Offer; import io.bitsquare.trade.offer.Offer;
import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
@ -69,6 +66,8 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
private Subscription tradeCurrencySubscriber; private Subscription tradeCurrencySubscriber;
private final StringProperty priceColumnLabel = new SimpleStringProperty(); private final StringProperty priceColumnLabel = new SimpleStringProperty();
private final StringProperty volumeColumnLabel = new SimpleStringProperty(); private final StringProperty volumeColumnLabel = new SimpleStringProperty();
private Button buyOfferButton;
private Button sellOfferButton;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -120,6 +119,8 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
Tuple3<TableView<Offer>, VBox, Button> tupleSell = getOfferTable(Offer.Direction.SELL); Tuple3<TableView<Offer>, VBox, Button> tupleSell = getOfferTable(Offer.Direction.SELL);
buyOfferTableView = tupleBuy.first; buyOfferTableView = tupleBuy.first;
sellOfferTableView = tupleSell.first; sellOfferTableView = tupleSell.first;
buyOfferButton = tupleBuy.third;
sellOfferButton = tupleSell.third;
HBox hBox = new HBox(); HBox hBox = new HBox();
hBox.setSpacing(30); hBox.setSpacing(30);
@ -135,19 +136,29 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
currencyComboBox.getSelectionModel().select(model.getTradeCurrency()); currencyComboBox.getSelectionModel().select(model.getTradeCurrency());
currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 25)); currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 25));
currencyComboBox.setOnAction(e -> { currencyComboBox.setOnAction(e -> {
model.onSetTradeCurrency(currencyComboBox.getSelectionModel().getSelectedItem()); TradeCurrency tradeCurrency = currencyComboBox.getSelectionModel().getSelectedItem();
model.onSetTradeCurrency(tradeCurrency);
updateChartData(); updateChartData();
}); });
model.getOfferBookListItems().addListener(changeListener); model.getOfferBookListItems().addListener(changeListener);
tradeCurrencySubscriber = EasyBind.subscribe(model.tradeCurrency, tradeCurrencySubscriber = EasyBind.subscribe(model.tradeCurrency,
newValue -> { tradeCurrency -> {
String code = newValue.getCode(); String code = tradeCurrency.getCode();
areaChart.setTitle("Offer book for " + newValue.getName()); String tradeCurrencyName = tradeCurrency.getName();
areaChart.setTitle("Offer book for " + tradeCurrencyName);
priceColumnLabel.set("Price (" + code + "/BTC)"); priceColumnLabel.set("Price (" + code + "/BTC)");
volumeColumnLabel.set("Volume (" + code + ")"); volumeColumnLabel.set("Volume (" + code + ")");
xAxis.setLabel(priceColumnLabel.get()); xAxis.setLabel(priceColumnLabel.get());
xAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(xAxis, "", "")); xAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(xAxis, "", ""));
if (CurrencyUtil.isCryptoCurrency(code)) {
buyOfferButton.setText("I want to sell bitcoin / buy " + tradeCurrencyName);
sellOfferButton.setText("I want to buy bitcoin / sell " + tradeCurrencyName);
} else {
buyOfferButton.setText("I want to sell bitcoin");
sellOfferButton.setText("I want to buy bitcoin");
}
}); });
buyOfferTableView.setItems(model.getTop3BuyOfferList()); buyOfferTableView.setItems(model.getTop3BuyOfferList());
@ -316,7 +327,7 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
placeholder.setWrapText(true); placeholder.setWrapText(true);
tableView.setPlaceholder(placeholder); tableView.setPlaceholder(placeholder);
Label titleLabel = new Label(direction.equals(Offer.Direction.BUY) ? "Top 3 offers for buying bitcoin (bid)" : "Top 3 offers for selling bitcoin (ask)"); Label titleLabel = new Label(direction.equals(Offer.Direction.BUY) ? "Top 3 bid offers" : "Top 3 ask offers");
titleLabel.setStyle("-fx-font-weight: bold; -fx-font-size: 16; -fx-alignment: center"); titleLabel.setStyle("-fx-font-weight: bold; -fx-font-size: 16; -fx-alignment: center");
UserThread.execute(() -> titleLabel.prefWidthProperty().bind(tableView.widthProperty())); UserThread.execute(() -> titleLabel.prefWidthProperty().bind(tableView.widthProperty()));
@ -355,10 +366,10 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis, "", "")); yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis, "", ""));
seriesBuy = new XYChart.Series(); seriesBuy = new XYChart.Series();
seriesBuy.setName("Offers for buying bitcoin "); seriesBuy.setName("Bid offers ");
seriesSell = new XYChart.Series(); seriesSell = new XYChart.Series();
seriesSell.setName("Offers for selling bitcoin "); seriesSell.setName("Ask offers");
areaChart = new AreaChart<>(xAxis, yAxis); areaChart = new AreaChart<>(xAxis, yAxis);
areaChart.setAnimated(false); areaChart.setAnimated(false);

View file

@ -889,8 +889,9 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
cancelButton2 = addButton(gridPane, ++gridRow, BSResources.get("shared.cancel")); cancelButton2 = addButton(gridPane, ++gridRow, BSResources.get("shared.cancel"));
cancelButton2.setOnAction(e -> { cancelButton2.setOnAction(e -> {
if (model.dataModel.isWalletFunded.get()) { if (model.dataModel.isWalletFunded.get()) {
new Popup().warning("You have already paid in the funds.\n" + new Popup().warning("You have already paid the funds.\n" +
"Are you sure you want to cancel.") "If you cancel now, your funds will be available immediately.\n" +
"Are you sure you want to cancel?")
.closeButtonText("No") .closeButtonText("No")
.actionButtonText("Yes, cancel") .actionButtonText("Yes, cancel")
.onAction(() -> { .onAction(() -> {

View file

@ -750,10 +750,11 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
boolean inputDataValid = isBtcInputValid(amount.get()).isValid && boolean inputDataValid = isBtcInputValid(amount.get()).isValid &&
isBtcInputValid(minAmount.get()).isValid && isBtcInputValid(minAmount.get()).isValid &&
isFiatInputValid(price.get()).isValid && isFiatInputValid(price.get()).isValid &&
dataModel.priceAsFiat.get() != null &&
dataModel.priceAsFiat.get().getValue() != 0 &&
isFiatInputValid(volume.get()).isValid && isFiatInputValid(volume.get()).isValid &&
dataModel.isMinAmountLessOrEqualAmount() && dataModel.isMinAmountLessOrEqualAmount();
!dataModel.useMarketBasedPrice.get() || dataModel.getMarketPriceMargin() != 0 &&
dataModel.useMarketBasedPrice.get() || (dataModel.priceAsFiat.get() != null && dataModel.priceAsFiat.get().getValue() != 0);
isNextButtonDisabled.set(!inputDataValid); isNextButtonDisabled.set(!inputDataValid);
// boolean notSufficientFees = dataModel.isWalletFunded.get() && dataModel.isMainNet.get() && !dataModel.isFeeFromFundingTxSufficient.get(); // boolean notSufficientFees = dataModel.isWalletFunded.get() && dataModel.isMainNet.get() && !dataModel.isFeeFromFundingTxSufficient.get();
//isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || notSufficientFees); //isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || notSufficientFees);

View file

@ -272,7 +272,8 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
String postFix = selectedTradeCurrency instanceof FiatCurrency || model.showAllTradeCurrenciesProperty.get() ? "" : String postFix = selectedTradeCurrency instanceof FiatCurrency || model.showAllTradeCurrenciesProperty.get() ? "" :
" (" + mirroredDirectionText + " " + selectedTradeCurrency.getName() + ")"; " (" + mirroredDirectionText + " " + selectedTradeCurrency.getName() + ")";
offerBookTitle.setText("Offers for " + directionText + " bitcoin" + postFix); // offerBookTitle.setText("Offers for " + directionText + " bitcoin" + postFix);
offerBookTitle.setText("Available offers");
createOfferButton.setText("Create new offer for " + directionText + " bitcoin" + postFix); createOfferButton.setText("Create new offer for " + directionText + " bitcoin" + postFix);
} }

View file

@ -778,8 +778,9 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
cancelButton2 = addButton(gridPane, ++gridRow, BSResources.get("shared.cancel")); cancelButton2 = addButton(gridPane, ++gridRow, BSResources.get("shared.cancel"));
cancelButton2.setOnAction(e -> { cancelButton2.setOnAction(e -> {
if (model.dataModel.isWalletFunded.get()) { if (model.dataModel.isWalletFunded.get()) {
new Popup().warning("You have already paid in the funds.\n" + new Popup().warning("You have already paid the funds.\n" +
"Are you sure you want to cancel.") "If you cancel now, your funds will be available immediately.\n" +
"Are you sure you want to cancel?")
.closeButtonText("No") .closeButtonText("No")
.actionButtonText("Yes, cancel") .actionButtonText("Yes, cancel")
.onAction(() -> { .onAction(() -> {

View file

@ -31,7 +31,7 @@ public class TacWindow extends Overlay<TacWindow> {
"arising from, out of or in connection with the software or the use or other dealings in the software.\n\n" + "arising from, out of or in connection with the software or the use or other dealings in the software.\n\n" +
"2. The user is responsible to use the software in compliance with local laws. Don't use Bitsquare if the usage of Bitcoin is not legal in your jurisdiction.\n\n" + "2. The user is responsible to use the software in compliance with local laws. Don't use Bitsquare if the usage of Bitcoin is not legal in your jurisdiction.\n\n" +
"3. Bitcoin market price is delivered by 3rd parties (BitcoinAverage, Poloniex). It is your responsibility to double check the price with other sources.\n\n" + "3. Bitcoin market price is delivered by 3rd parties (BitcoinAverage, Poloniex). It is your responsibility to double check the price with other sources.\n\n" +
"4. The user confirms that he has read and agreed to the rules regrading the dispute process:\n" + "4. The user confirms that he has read and agreed to the rules regarding the dispute process:\n" +
" - You must finalize trades within the maximum duration specified for each payment method.\n" + " - You must finalize trades within the maximum duration specified for each payment method.\n" +
" - You must enter the trade ID in the \"reason for payment\" text field when doing the fiat payment transfer.\n" + " - You must enter the trade ID in the \"reason for payment\" text field when doing the fiat payment transfer.\n" +
" - If the bank of the fiat sender charges fees the sender (bitcoin buyer) has to cover the fees.\n" + " - If the bank of the fiat sender charges fees the sender (bitcoin buyer) has to cover the fees.\n" +

View file

@ -183,7 +183,7 @@ public class BuyerStep5View extends TradeStepView {
} else { } else {
if (toAddresses.isEmpty()) { if (toAddresses.isEmpty()) {
validateWithdrawAddress(); validateWithdrawAddress();
} else if (Restrictions.isAboveFixedTxFeeAndDust(senderAmount)) { } else if (Restrictions.isAboveFixedTxFeeForTradesAndDust(senderAmount)) {
if (BitsquareApp.DEV_MODE) { if (BitsquareApp.DEV_MODE) {
doWithdrawal(receiverAmount); doWithdrawal(receiverAmount);

View file

@ -36,7 +36,6 @@ import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator; import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.Tooltip; import javafx.scene.control.Tooltip;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import org.apache.commons.lang3.StringUtils;
import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription; import org.fxmisc.easybind.Subscription;
@ -152,13 +151,11 @@ public class SellerStep3View extends TradeStepView {
} }
} }
TextFieldWithCopyIcon myPaymentDetailsTextField = addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, TextFieldWithCopyIcon myPaymentDetailsTextField = addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, myTitle, myPaymentDetails).second;
myTitle, StringUtils.abbreviate(myPaymentDetails, 56)).second;
myPaymentDetailsTextField.setMouseTransparent(false); myPaymentDetailsTextField.setMouseTransparent(false);
myPaymentDetailsTextField.setTooltip(new Tooltip(myPaymentDetails)); myPaymentDetailsTextField.setTooltip(new Tooltip(myPaymentDetails));
TextFieldWithCopyIcon peersPaymentDetailsTextField = addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, TextFieldWithCopyIcon peersPaymentDetailsTextField = addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, peersTitle, peersPaymentDetails).second;
peersTitle, StringUtils.abbreviate(peersPaymentDetails, 56)).second;
peersPaymentDetailsTextField.setMouseTransparent(false); peersPaymentDetailsTextField.setMouseTransparent(false);
peersPaymentDetailsTextField.setTooltip(new Tooltip(peersPaymentDetails)); peersPaymentDetailsTextField.setTooltip(new Tooltip(peersPaymentDetails));

View file

@ -74,7 +74,7 @@
<PropertyValueFactory property="onionAddress"/> <PropertyValueFactory property="onionAddress"/>
</cellValueFactory> </cellValueFactory>
</TableColumn> </TableColumn>
<TableColumn text="In/Out" fx:id="connectionTypeColumn" minWidth="70" maxWidth="80"> <TableColumn text="In/Out" fx:id="connectionTypeColumn" minWidth="80" maxWidth="90">
<cellValueFactory> <cellValueFactory>
<PropertyValueFactory property="connectionType"/> <PropertyValueFactory property="connectionType"/>
</cellValueFactory> </cellValueFactory>

View file

@ -53,7 +53,7 @@ public class BSFormatter {
// Input of a group separator (1,123,45) lead to an validation error. // Input of a group separator (1,123,45) lead to an validation error.
// Note: BtcFormat was intended to be used, but it lead to many problems (automatic format to mBit, // Note: BtcFormat was intended to be used, but it lead to many problems (automatic format to mBit,
// no way to remove grouping separator). It seems to be not optimal for user input formatting. // no way to remove grouping separator). It seems to be not optimal for user input formatting.
private MonetaryFormat coinFormat = MonetaryFormat.BTC.repeatOptionalDecimals(2, 2); private MonetaryFormat coinFormat = MonetaryFormat.BTC.minDecimals(2).repeatOptionalDecimals(1, 6);
// private String currencyCode = CurrencyUtil.getDefaultFiatCurrencyAsCode(); // private String currencyCode = CurrencyUtil.getDefaultFiatCurrencyAsCode();
@ -97,7 +97,7 @@ public class BSFormatter {
if (useMilliBit) if (useMilliBit)
return MonetaryFormat.MBTC; return MonetaryFormat.MBTC;
else else
return MonetaryFormat.BTC.repeatOptionalDecimals(2, 2); return MonetaryFormat.BTC.minDecimals(2).repeatOptionalDecimals(1, 6);
} }
/* public void setFiatCurrencyCode(String currencyCode) { /* public void setFiatCurrencyCode(String currencyCode) {

View file

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.3</version> <version>0.4.6</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View file

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.3</version> <version>0.4.6</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View file

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.3</version> <version>0.4.6</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View file

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.3</version> <version>0.4.6</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View file

@ -64,7 +64,7 @@ public class Connection implements MessageListener {
private static final int MAX_MSG_SIZE = 500 * 1024; // 500 kb private static final int MAX_MSG_SIZE = 500 * 1024; // 500 kb
//TODO decrease limits again after testing //TODO decrease limits again after testing
private static final int MSG_THROTTLE_PER_SEC = 50; // With MAX_MSG_SIZE of 100kb results in bandwidth of 5 mbit/sec private static final int MSG_THROTTLE_PER_SEC = 70; // With MAX_MSG_SIZE of 500kb results in bandwidth of 35 mbit/sec
private static final int MSG_THROTTLE_PER_10_SEC = 500; // With MAX_MSG_SIZE of 100kb results in bandwidth of 50 mbit/sec for 10 sec private static final int MSG_THROTTLE_PER_10_SEC = 500; // With MAX_MSG_SIZE of 100kb results in bandwidth of 50 mbit/sec for 10 sec
private static final int SOCKET_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(60); private static final int SOCKET_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(60);
@ -253,15 +253,15 @@ public class Connection implements MessageListener {
boolean violated = false; boolean violated = false;
//TODO remove serializable storage after network is tested stable //TODO remove serializable storage after network is tested stable
if (messageTimeStamps.size() >= MSG_THROTTLE_PER_SEC) { if (messageTimeStamps.size() >= MSG_THROTTLE_PER_SEC) {
// check if we got more than 10 (MSG_THROTTLE_PER_SEC) msg per sec. // check if we got more than 70 (MSG_THROTTLE_PER_SEC) msg per sec.
long compareValue = messageTimeStamps.get(messageTimeStamps.size() - MSG_THROTTLE_PER_SEC).first; long compareValue = messageTimeStamps.get(messageTimeStamps.size() - MSG_THROTTLE_PER_SEC).first;
// if duration < 1 sec we received too much messages // if duration < 1 sec we received too much messages
violated = now - compareValue < TimeUnit.SECONDS.toMillis(1); violated = now - compareValue < TimeUnit.SECONDS.toMillis(1);
if (violated) { if (violated) {
log.error("violatesThrottleLimit 1 "); log.error("violatesThrottleLimit MSG_THROTTLE_PER_SEC ");
log.error("elapsed " + (now - compareValue)); log.error("elapsed " + (now - compareValue));
log.error("messageTimeStamps: \n\t" + messageTimeStamps.stream() log.error("messageTimeStamps: \n\t" + messageTimeStamps.stream()
.map(e -> "\n\tts=" + e.first.toString() + " message=" + e.second.toString()) .map(e -> "\n\tts=" + e.first.toString() + " message=" + e.second.getClass().getName())
.collect(Collectors.toList()).toString()); .collect(Collectors.toList()).toString());
} }
} }
@ -274,10 +274,10 @@ public class Connection implements MessageListener {
violated = now - compareValue < TimeUnit.SECONDS.toMillis(10); violated = now - compareValue < TimeUnit.SECONDS.toMillis(10);
if (violated) { if (violated) {
log.error("violatesThrottleLimit 2 "); log.error("violatesThrottleLimit MSG_THROTTLE_PER_10_SEC ");
log.error("elapsed " + (now - compareValue)); log.error("elapsed " + (now - compareValue));
log.error("messageTimeStamps: \n\t" + messageTimeStamps.stream() log.error("messageTimeStamps: \n\t" + messageTimeStamps.stream()
.map(e -> "\n\tts=" + e.first.toString() + " message=" + e.second.toString()) .map(e -> "\n\tts=" + e.first.toString() + " message=" + e.second.getClass().getName())
.collect(Collectors.toList()).toString()); .collect(Collectors.toList()).toString());
} }
} }
@ -544,8 +544,12 @@ public class Connection implements MessageListener {
} else { } else {
// TODO sometimes we get StreamCorruptedException, OptionalDataException, IllegalStateException // TODO sometimes we get StreamCorruptedException, OptionalDataException, IllegalStateException
closeConnectionReason = CloseConnectionReason.UNKNOWN_EXCEPTION; closeConnectionReason = CloseConnectionReason.UNKNOWN_EXCEPTION;
log.warn("Unknown reason for exception at socket {}\n\tconnection={}\n\tException=", log.warn("Unknown reason for exception at socket {}\n\t" +
socket.toString(), this, e.toString()); "connection={}\n\t" +
"Exception=",
socket.toString(),
this,
e.toString());
e.printStackTrace(); e.printStackTrace();
} }

View file

@ -5,6 +5,7 @@ import io.bitsquare.app.Log;
import io.bitsquare.app.Version; import io.bitsquare.app.Version;
import io.bitsquare.common.Clock; import io.bitsquare.common.Clock;
import io.bitsquare.common.UserThread; import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.p2p.NodeAddress; import io.bitsquare.p2p.NodeAddress;
import io.bitsquare.p2p.P2PService; import io.bitsquare.p2p.P2PService;
import io.bitsquare.p2p.P2PServiceListener; import io.bitsquare.p2p.P2PServiceListener;
@ -120,8 +121,11 @@ public class SeedNode {
"Bitsquare_seed_node_" + String.valueOf(mySeedNodeAddress.getFullAddress().replace(":", "_"))); "Bitsquare_seed_node_" + String.valueOf(mySeedNodeAddress.getFullAddress().replace(":", "_")));
String logPath = Paths.get(appPath.toString(), "logs").toString(); String logPath = Paths.get(appPath.toString(), "logs").toString();
Log.setup(logPath, useDetailedLogging); Log.setup(logPath);
log.info("Log files under: " + logPath); log.info("Log files under: " + logPath);
Version.printVersion();
Utilities.printSysInfo();
Log.setLevel(useDetailedLogging);
SeedNodesRepository seedNodesRepository = new SeedNodesRepository(); SeedNodesRepository seedNodesRepository = new SeedNodesRepository();
if (progArgSeedNodes != null && !progArgSeedNodes.isEmpty()) { if (progArgSeedNodes != null && !progArgSeedNodes.isEmpty()) {

View file

@ -36,6 +36,7 @@ public class SeedNodesRepository {
new NodeAddress("uadzuib66jupaept.onion:8000"), new NodeAddress("uadzuib66jupaept.onion:8000"),
new NodeAddress("hbma455xxbqhcuqh.onion:8000"), new NodeAddress("hbma455xxbqhcuqh.onion:8000"),
new NodeAddress("wgthuiqn3aoiovbm.onion:8000"), new NodeAddress("wgthuiqn3aoiovbm.onion:8000"),
new NodeAddress("2zxtnprnx5wqr7a3.onion:8000"),
// testnet // testnet
new NodeAddress("znmy44wcstn2rkva.onion:8001"), new NodeAddress("znmy44wcstn2rkva.onion:8001"),

View file

@ -6,7 +6,7 @@ mkdir -p gui/deploy
set -e set -e
# Edit versions # Edit versions
fullVersion=0.4.3 fullVersion=0.4.6
jarFile="/home/bitsquare/Desktop/sf_vm_shared_ubuntu14_32bit/Bitsquare-$fullVersion.jar" jarFile="/home/bitsquare/Desktop/sf_vm_shared_ubuntu14_32bit/Bitsquare-$fullVersion.jar"
# Note: fakeroot needs to be installed on linux # Note: fakeroot needs to be installed on linux

View file

@ -6,7 +6,7 @@ mkdir -p gui/deploy
set -e set -e
# Edit versions # Edit versions
fullVersion=0.4.3 fullVersion=0.4.6
jarFile="/home/mk/Desktop/sf_vm_shared_ubuntu/Bitsquare-$fullVersion.jar" jarFile="/home/mk/Desktop/sf_vm_shared_ubuntu/Bitsquare-$fullVersion.jar"
# Note: fakeroot needs to be installed on linux # Note: fakeroot needs to be installed on linux
@ -34,6 +34,6 @@ rm gui/deploy/LICENSE
mv "gui/deploy/bundles/bitsquare-$fullVersion.deb" "gui/deploy/Bitsquare-$fullVersion.deb" mv "gui/deploy/bundles/bitsquare-$fullVersion.deb" "gui/deploy/Bitsquare-$fullVersion.deb"
rmdir gui/deploy/bundles rmdir gui/deploy/bundles
cp "gui/deploy/Bitsquare-$fullVersion.deb" "/home/mk/Desktop/sf_vm_shared_ubuntu/Bitsquare-64bit-$fullVersion.deb" cp "gui/deploy/Bitsquare-$fullVersion.deb" "/home/mk/Desktop/sf_vm_shared_ubuntu/Bitsquare-64bit-$fullVersion.deb"
cp "gui/deploy/Bitsquare-32bit-$fullVersion.deb" "/home/mk/Desktop/Bitsquare-64bit-$fullVersion.deb" cp "gui/deploy/Bitsquare-$fullVersion.deb" "/home/mk/Desktop/Bitsquare-64bit-$fullVersion.deb"
cd package/linux cd package/linux

View file

@ -5,7 +5,7 @@ mkdir -p gui/deploy
set -e set -e
fullVersion="0.4.3" fullVersion="0.4.6"
mvn clean package -DskipTests -Dmaven.javadoc.skip=true mvn clean package -DskipTests -Dmaven.javadoc.skip=true
@ -37,7 +37,10 @@ $JAVA_HOME/bin/javapackager \
rm "gui/deploy/Bitsquare.html" rm "gui/deploy/Bitsquare.html"
rm "gui/deploy/Bitsquare.jnlp" rm "gui/deploy/Bitsquare.jnlp"
mv "gui/deploy/bundles/Bitsquare.dmg" "gui/deploy/Bitsquare-$fullVersion.dmg" mv "gui/deploy/bundles/Bitsquare-$fullVersion.dmg" "gui/deploy/Bitsquare-$fullVersion.dmg"
rm gui/deploy/bundles rm -r "gui/deploy/bundles"
mv "gui/deploy/SeedNode.jar" "gui/deploy/SeedNode-$fullVersion.jar"
cd package/mac cd package/mac

34
package/mac/finalize.sh Normal file
View file

@ -0,0 +1,34 @@
#!/bin/bash
version="0.4.6"
target_dir="/Users/mk/Documents/__bitsquare/_releases/$version"
mac="Bitsquare-$version.dmg"
cp "/Users/mk/Documents/_intellij/bitsquare/gui/deploy/$mac" "$target_dir/"
cp "/Users/mk/Documents/_intellij/bitsquare/gui/deploy/SeedNode-$version.jar" "$target_dir/"
deb32="Bitsquare-32bit-$version.deb"
cp "/Users/mk/vm_shared_ubuntu14_32bit/$deb32" "$target_dir/"
deb64="Bitsquare-64bit-$version.deb"
cp "/Users/mk/vm_shared_ubuntu/$deb64" "$target_dir/"
exe="Bitsquare.exe"
win32="Bitsquare-32bit-$version.exe"
cp "/Users/mk/vm_shared_windows_32bit/bundles/$exe" "$target_dir/$win32"
win64="Bitsquare-64bit-$version.exe"
cp "/Users/mk/vm_shared_windows/bundles/$exe" "$target_dir/$win64"
cp "/Users/mk/vm_shared_windows/bundles/$exe" "/Users/mk/vm_shared_win10/$win64"
cd "$target_dir"
shasum -a 256 "$mac" "$deb64" "$deb32" "$win64" "$win32" > sha256_hashes.txt
gpg --local-user manfred@bitsquare.io --output signed_sha256_hashes.txt --clearsign sha256_hashes.txt
gpg --verify signed_sha256_hashes.txt
rm "$target_dir/sha256_hashes.txt"
open "$target_dir"

View file

@ -3,7 +3,7 @@
[Setup] [Setup]
AppId={{bitsquare}} AppId={{bitsquare}}
AppName=Bitsquare AppName=Bitsquare
AppVersion=0.4.3 AppVersion=0.4.6
AppVerName=Bitsquare AppVerName=Bitsquare
AppPublisher=Bitsquare AppPublisher=Bitsquare
AppComments=Bitsquare AppComments=Bitsquare

View file

@ -1,13 +1,13 @@
cd ..\..\ cd ..\..\
mkdir gui\deploy mkdir gui\deploy
:: edit iss file -> AppVersion=0.4.3 :: edit iss file -> AppVersion=0.4.6
:: Copy gui/deploy.Bitsquare.jar file from mac build to windows :: Copy gui/deploy.Bitsquare.jar file from mac build to windows
:: edit -> -BappVersion=0.4.3 and -srcfiles :: edit -> -BappVersion=0.4.6 and -srcfiles
:: 32 bit build :: 32 bit build
:: Needs Inno Setup 5 or later (http://www.jrsoftware.org/isdl.php) :: Needs Inno Setup 5 or later (http://www.jrsoftware.org/isdl.php)
call "C:\Program Files\Java\jdk1.8.0_77\bin\javapackager.exe" -deploy -BappVersion=0.4.3 -native exe -name Bitsquare -title Bitsquare -vendor Bitsquare -outdir "\\VBOXSVR\vm_shared_windows_32bit" -appclass io.bitsquare.app.BitsquareAppMain -srcfiles "\\VBOXSVR\vm_shared_windows_32bit\Bitsquare-0.4.3.jar" -outfile Bitsquare -Bruntime="C:\Program Files\Java\jdk1.8.0_77\jre" -BjvmProperties=-Djava.net.preferIPv4Stack=true call "C:\Program Files\Java\jdk1.8.0_92\bin\javapackager.exe" -deploy -BappVersion=0.4.6 -native exe -name Bitsquare -title Bitsquare -vendor Bitsquare -outdir "\\VBOXSVR\vm_shared_windows_32bit" -appclass io.bitsquare.app.BitsquareAppMain -srcfiles "\\VBOXSVR\vm_shared_windows_32bit\Bitsquare-0.4.6.jar" -outfile Bitsquare -Bruntime="C:\Program Files\Java\jdk1.8.0_92\jre" -BjvmProperties=-Djava.net.preferIPv4Stack=true
cd package\windows cd package\windows

View file

@ -1,13 +1,13 @@
cd ..\..\ cd ..\..\
mkdir gui\deploy mkdir gui\deploy
:: edit iss file -> AppVersion=0.4.3 :: edit iss file -> AppVersion=0.4.6
:: Copy gui/deploy.Bitsquare.jar file from mac build to windows :: Copy gui/deploy.Bitsquare.jar file from mac build to windows
:: edit -> -BappVersion=0.4.3 and -srcfiles :: edit -> -BappVersion=0.4.6 and -srcfiles
:: 64 bit build :: 64 bit build
:: Needs Inno Setup 5 or later (http://www.jrsoftware.org/isdl.php) :: Needs Inno Setup 5 or later (http://www.jrsoftware.org/isdl.php)
call "C:\Program Files\Java\jdk1.8.0_66\bin\javapackager.exe" -deploy -BappVersion=0.4.3 -native exe -name Bitsquare -title Bitsquare -vendor Bitsquare -outdir "\\VBOXSVR\vm_shared_windows" -appclass io.bitsquare.app.BitsquareAppMain -srcfiles "\\VBOXSVR\vm_shared_windows\Bitsquare-0.4.3.jar" -outfile Bitsquare -Bruntime="C:\Program Files\Java\jdk1.8.0_66\jre" -BjvmProperties=-Djava.net.preferIPv4Stack=true call "C:\Program Files\Java\jdk1.8.0_92\bin\javapackager.exe" -deploy -BappVersion=0.4.6 -native exe -name Bitsquare -title Bitsquare -vendor Bitsquare -outdir "\\VBOXSVR\vm_shared_windows" -appclass io.bitsquare.app.BitsquareAppMain -srcfiles "\\VBOXSVR\vm_shared_windows\Bitsquare-0.4.6.jar" -outfile Bitsquare -Bruntime="C:\Program Files\Java\jdk1.8.0_92\jre" -BjvmProperties=-Djava.net.preferIPv4Stack=true
cd package\windows cd package\windows

View file

@ -6,7 +6,7 @@
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>0.4.3</version> <version>0.4.6</version>
<description>Bitsquare - The decentralized bitcoin exchange</description> <description>Bitsquare - The decentralized bitcoin exchange</description>
<url>https://bitsquare.io</url> <url>https://bitsquare.io</url>

View file

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.3</version> <version>0.4.6</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>