mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
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:
commit
b9dfa0a7a7
@ -18,7 +18,7 @@ You can read about all of this and more in the [whitepaper](https://bitsquare.io
|
||||
|
||||
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.
|
||||
|
||||
Building from source
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>io.bitsquare</groupId>
|
||||
<version>0.4.3</version>
|
||||
<version>0.4.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -30,7 +30,7 @@ public class Log {
|
||||
private static SizeBasedTriggeringPolicy triggeringPolicy;
|
||||
private static Logger logbackLogger;
|
||||
|
||||
public static void setup(String fileName, boolean useDetailedLogging) {
|
||||
public static void setup(String fileName) {
|
||||
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
|
||||
RollingFileAppender appender = new RollingFileAppender();
|
||||
@ -60,8 +60,8 @@ public class Log {
|
||||
appender.start();
|
||||
|
||||
logbackLogger = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
|
||||
logbackLogger.setLevel(useDetailedLogging ? Level.TRACE : Level.WARN);
|
||||
logbackLogger.addAppender(appender);
|
||||
logbackLogger.setLevel(Level.INFO);
|
||||
|
||||
// log errors in separate file
|
||||
// not working as expected still.... damn logback...
|
||||
@ -80,6 +80,10 @@ public class Log {
|
||||
logbackLogger.addAppender(errorAppender);*/
|
||||
}
|
||||
|
||||
public static void setLevel(boolean useDetailedLogging) {
|
||||
logbackLogger.setLevel(useDetailedLogging ? Level.TRACE : Level.WARN);
|
||||
}
|
||||
|
||||
public static void traceCall() {
|
||||
if (LoggerFactory.getLogger(Log.class).isTraceEnabled()) {
|
||||
StackTraceElement stackTraceElement = new Throwable().getStackTrace()[1];
|
||||
|
@ -24,7 +24,7 @@ public class Version {
|
||||
private static final Logger log = LoggerFactory.getLogger(Version.class);
|
||||
|
||||
// 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.
|
||||
// If objects are used for both network and database the network version is applied.
|
||||
@ -81,6 +81,4 @@ public class Version {
|
||||
", getP2PNetworkId()=" + getP2PMessageVersion() +
|
||||
'}');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -30,10 +30,15 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLConnection;
|
||||
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.concurrent.*;
|
||||
|
||||
@ -115,7 +120,49 @@ public class Utilities {
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -151,7 +198,7 @@ public class Utilities {
|
||||
throw new IOException("Failed to open directory: " + directory.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void openWebPage(String target) {
|
||||
try {
|
||||
openURI(new URI(target));
|
||||
@ -373,4 +420,42 @@ public class Utilities {
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>io.bitsquare</groupId>
|
||||
<version>0.4.3</version>
|
||||
<version>0.4.6</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>core</artifactId>
|
||||
|
@ -67,6 +67,12 @@ public final class Alert implements StoragePayload {
|
||||
return signatureAsBase64;
|
||||
}
|
||||
|
||||
public boolean isNewVersion() {
|
||||
int versionNum = Integer.valueOf(Version.VERSION.replace(".", ""));
|
||||
int alertVersionNum = Integer.valueOf(version.replace(".", ""));
|
||||
return versionNum < alertVersionNum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTTL() {
|
||||
return TTL;
|
||||
|
@ -60,16 +60,6 @@ public class FeePolicy {
|
||||
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
|
||||
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
|
||||
|
@ -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 boolean isAboveFixedTxFeeAndDust(Coin amount) {
|
||||
public static boolean isAboveFixedTxFeeForTradesAndDust(Coin amount) {
|
||||
return amount != null && amount.compareTo(FeePolicy.getFixedTxFeeForTrades().add(Transaction.MIN_NONDUST_OUTPUT)) > 0;
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,7 @@ public class TradeWalletService {
|
||||
boolean useSavingsWallet, Coin tradingFee, String feeReceiverAddresses)
|
||||
throws InsufficientMoneyException, AddressFormatException {
|
||||
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.");
|
||||
Coin outPutAmount = tradingFee.subtract(FeePolicy.getFixedTxFeeForTrades());
|
||||
tradingFeeTx.addOutput(outPutAmount, new Address(params, feeReceiverAddresses));
|
||||
|
@ -39,10 +39,7 @@ import org.bitcoinj.kits.WalletAppKit;
|
||||
import org.bitcoinj.params.MainNetParams;
|
||||
import org.bitcoinj.params.RegTestParams;
|
||||
import org.bitcoinj.params.TestNet3Params;
|
||||
import org.bitcoinj.script.Script;
|
||||
import org.bitcoinj.utils.Threading;
|
||||
import org.bitcoinj.wallet.CoinSelection;
|
||||
import org.bitcoinj.wallet.CoinSelector;
|
||||
import org.bitcoinj.wallet.DeterministicSeed;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
@ -98,6 +95,7 @@ public class WalletService {
|
||||
public final BooleanProperty shutDownDone = new SimpleBooleanProperty();
|
||||
private final Storage<Long> storage;
|
||||
private final Long bloomFilterTweak;
|
||||
private KeyParameter aesKey;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -340,6 +338,10 @@ public class WalletService {
|
||||
}
|
||||
}
|
||||
|
||||
public void setAesKey(KeyParameter aesKey) {
|
||||
this.aesKey = aesKey;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Listener
|
||||
@ -574,22 +576,24 @@ public class WalletService {
|
||||
public Coin getRequiredFee(String fromAddress,
|
||||
String toAddress,
|
||||
Coin amount,
|
||||
AddressEntry.Context context) throws AddressFormatException, AddressEntryException {
|
||||
AddressEntry.Context context)
|
||||
throws AddressFormatException, AddressEntryException {
|
||||
Optional<AddressEntry> addressEntry = findAddressEntry(fromAddress, context);
|
||||
if (!addressEntry.isPresent())
|
||||
throw new AddressEntryException("WithdrawFromAddress is not found in our wallet.");
|
||||
|
||||
checkNotNull(addressEntry.get().getAddress(), "addressEntry.get().getAddress() must nto be null");
|
||||
CoinSelector selector = new TradeWalletCoinSelector(params, addressEntry.get().getAddress());
|
||||
return getFee(toAddress,
|
||||
return getFee(fromAddress,
|
||||
toAddress,
|
||||
amount,
|
||||
selector);
|
||||
context,
|
||||
Coin.ZERO);
|
||||
}
|
||||
|
||||
public Coin getRequiredFeeForMultipleAddresses(Set<String> fromAddresses,
|
||||
String toAddress,
|
||||
Coin amount) throws AddressFormatException,
|
||||
AddressEntryException {
|
||||
Coin amount)
|
||||
throws AddressFormatException, AddressEntryException {
|
||||
Set<AddressEntry> addressEntries = fromAddresses.stream()
|
||||
.map(address -> {
|
||||
Optional<AddressEntry> addressEntryOptional = findAddressEntry(address, AddressEntry.Context.AVAILABLE);
|
||||
@ -606,63 +610,55 @@ public class WalletService {
|
||||
.collect(Collectors.toSet());
|
||||
if (addressEntries.isEmpty())
|
||||
throw new AddressEntryException("No Addresses for withdraw found in our wallet");
|
||||
|
||||
CoinSelector selector = new MultiAddressesCoinSelector(params, addressEntries);
|
||||
return getFee(toAddress,
|
||||
return getFeeForMultipleAddresses(fromAddresses,
|
||||
toAddress,
|
||||
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());
|
||||
log.info("Required fee " + fee);
|
||||
private Coin getFee(String fromAddress,
|
||||
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;
|
||||
}
|
||||
|
||||
private boolean adjustOutputDownwardsForFee(Transaction tx, CoinSelection coinSelection, Coin baseFee, Coin feePerKb) {
|
||||
TransactionOutput output = tx.getOutput(0);
|
||||
// Check if we need additional fee due to the transaction's size
|
||||
int size = tx.bitcoinSerialize().length;
|
||||
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 {
|
||||
Script script = output.getScriptPubKey();
|
||||
ECKey key = null;
|
||||
Script redeemScript = null;
|
||||
if (script.isSentToAddress()) {
|
||||
key = wallet.findKeyFromPubHash(script.getPubKeyHash());
|
||||
checkNotNull(key, "Coin selection includes unspendable outputs");
|
||||
} else if (script.isPayToScriptHash()) {
|
||||
redeemScript = wallet.findRedeemDataFromScriptHash(script.getPubKeyHash()).redeemScript;
|
||||
checkNotNull(redeemScript, "Coin selection includes unspendable outputs");
|
||||
}
|
||||
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);
|
||||
private Coin getFeeForMultipleAddresses(Set<String> fromAddresses,
|
||||
String toAddress,
|
||||
Coin amount,
|
||||
Coin fee) throws AddressEntryException, AddressFormatException {
|
||||
try {
|
||||
wallet.completeTx(getSendRequestForMultipleAddresses(fromAddresses, toAddress, amount, null, aesKey));
|
||||
} catch (InsufficientMoneyException e) {
|
||||
if (e.missing != null) {
|
||||
log.trace("missing fee " + e.missing.toFriendlyString());
|
||||
fee = fee.add(e.missing);
|
||||
amount = amount.subtract(fee);
|
||||
return getFeeForMultipleAddresses(fromAddresses,
|
||||
toAddress,
|
||||
amount,
|
||||
fee);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
log.trace("result fee " + fee.toFriendlyString());
|
||||
return fee;
|
||||
}
|
||||
|
||||
|
||||
@ -726,7 +722,7 @@ public class WalletService {
|
||||
AddressEntryException, InsufficientMoneyException {
|
||||
Transaction tx = new Transaction(params);
|
||||
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));
|
||||
|
||||
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
|
||||
@ -751,7 +747,7 @@ public class WalletService {
|
||||
AddressFormatException, AddressEntryException, InsufficientMoneyException {
|
||||
Transaction tx = new Transaction(params);
|
||||
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));
|
||||
|
||||
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
|
||||
|
@ -37,7 +37,7 @@ public class BankUtil {
|
||||
countryCode = "";
|
||||
switch (countryCode) {
|
||||
default:
|
||||
return "Bank nr.(BIC/SWIFT):";
|
||||
return "Bank nr. or BIC/SWIFT:";
|
||||
}
|
||||
|
||||
}
|
||||
@ -64,7 +64,7 @@ public class BankUtil {
|
||||
countryCode = "";
|
||||
switch (countryCode) {
|
||||
default:
|
||||
return "Account nr.(IBAN):";
|
||||
return "Account nr. or IBAN:";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,21 +68,8 @@ public class CurrencyUtil {
|
||||
return allSortedCryptoCurrencies;
|
||||
}
|
||||
|
||||
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("FAIR", "FairCoin"));
|
||||
result.add(new CryptoCurrency("DOGE", "Dogecoin"));
|
||||
result.add(new CryptoCurrency("NXT", "Nxt"));
|
||||
result.add(new CryptoCurrency("BTS", "BitShares"));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Don't make a PR for adding a coin but follow the steps described here:
|
||||
// https://forum.bitsquare.io/t/how-to-add-your-favorite-altcoin/
|
||||
public static List<CryptoCurrency> createAllSortedCryptoCurrenciesList() {
|
||||
final List<CryptoCurrency> result = new ArrayList<>();
|
||||
result.add(new CryptoCurrency("ETH", "Ethereum"));
|
||||
@ -105,16 +92,46 @@ public class CurrencyUtil {
|
||||
result.add(new CryptoCurrency("BTS", "BitShares"));
|
||||
result.add(new CryptoCurrency("XCP", "Counterparty"));
|
||||
result.add(new CryptoCurrency("XRP", "Ripple"));
|
||||
|
||||
// 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("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"));
|
||||
|
||||
// result.add(new CryptoCurrency("XMR", "Monero"));
|
||||
// result.add(new CryptoCurrency("BCN", "Bytecoin"));
|
||||
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
|
||||
|
@ -371,7 +371,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
return null;
|
||||
}
|
||||
} 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.");
|
||||
return null;
|
||||
}
|
||||
|
@ -28,21 +28,21 @@ public class RestrictionsTest {
|
||||
@Test
|
||||
public void testIsMinSpendableAmount() {
|
||||
Coin amount = null;
|
||||
assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeAndDust(amount));
|
||||
assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeForTradesAndDust(amount));
|
||||
|
||||
amount = Coin.ZERO;
|
||||
assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeAndDust(amount));
|
||||
assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeForTradesAndDust(amount));
|
||||
|
||||
amount = FeePolicy.getFixedTxFeeForTrades();
|
||||
assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeAndDust(amount));
|
||||
assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeForTradesAndDust(amount));
|
||||
|
||||
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);
|
||||
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));
|
||||
assertTrue("tx unfunded, pending", Restrictions.isAboveFixedTxFeeAndDust(amount));
|
||||
assertTrue("tx unfunded, pending", Restrictions.isAboveFixedTxFeeForTradesAndDust(amount));
|
||||
}
|
||||
}
|
||||
|
47
doc/build.md
47
doc/build.md
@ -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:
|
||||
|
||||
$ 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
|
||||
$ mvn install -DskipTests -Dmaven.javadoc.skip=true
|
||||
$ mvn clean install -DskipTests -Dmaven.javadoc.skip=true
|
||||
|
||||
$ git clone https://github.com/bitsquare/bitsquare.git
|
||||
$ cd bitsquare
|
||||
$ mvn package
|
||||
$ mvn clean package -DskipTests
|
||||
|
||||
When the build completes, you will find an executable jar: `gui/target/shaded.jar`.
|
||||
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).
|
||||
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 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.
|
||||
> 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
|
||||
-----
|
||||
@ -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 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
|
||||
$ mvn install -DskipTests -Dmaven.javadoc.skip=true
|
||||
$ mvn clean install -DskipTests -Dmaven.javadoc.skip=true
|
||||
|
||||
### 3. Build jar
|
||||
|
||||
Bitsquare uses maven as a build system.
|
||||
|
||||
$ cd bitsquare
|
||||
$ mvn package
|
||||
$ mvn clean package -DskipTests
|
||||
|
||||
### 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
|
||||
|
||||
|
||||
### 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?
|
||||
---------
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>io.bitsquare</groupId>
|
||||
<version>0.4.3</version>
|
||||
<version>0.4.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -54,7 +54,6 @@ import javafx.scene.input.KeyCombination;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.StageStyle;
|
||||
@ -100,10 +99,12 @@ public class BitsquareApp extends Application {
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws IOException {
|
||||
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();
|
||||
Utilities.printSysInfo();
|
||||
Log.setLevel(!IS_RELEASE_VERSION);
|
||||
|
||||
UserThread.setExecutor(Platform::runLater);
|
||||
UserThread.setTimerClass(UITimer.class);
|
||||
@ -124,6 +125,8 @@ public class BitsquareApp extends Application {
|
||||
Thread.setDefaultUncaughtExceptionHandler(handler);
|
||||
Thread.currentThread().setUncaughtExceptionHandler(handler);
|
||||
|
||||
if (Utilities.isRestrictedCryptography())
|
||||
Utilities.removeCryptographyRestrictions();
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
BitsquareApp.primaryStage = primaryStage;
|
||||
@ -158,7 +161,7 @@ public class BitsquareApp extends Application {
|
||||
mainView.setPersistedFilesCorrupted(corruptedDatabaseFiles);
|
||||
});*/
|
||||
|
||||
scene = new Scene(mainView.getRoot(), 1150, 740);
|
||||
scene = new Scene(mainView.getRoot(), 1190, 740);
|
||||
scene.getStylesheets().setAll(
|
||||
"/io/bitsquare/gui/bitsquare.css",
|
||||
"/io/bitsquare/gui/images.css");
|
||||
@ -190,7 +193,7 @@ public class BitsquareApp extends Application {
|
||||
// configure the primary stage
|
||||
primaryStage.setTitle(env.getRequiredProperty(APP_NAME_KEY));
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.setMinWidth(1130);
|
||||
primaryStage.setMinWidth(1170);
|
||||
primaryStage.setMinHeight(620);
|
||||
|
||||
// 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
|
||||
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) {
|
||||
showErrorPopup(throwable, false);
|
||||
}
|
||||
@ -220,8 +231,8 @@ public class BitsquareApp extends Application {
|
||||
private void showSendAlertMessagePopup() {
|
||||
AlertManager alertManager = injector.getInstance(AlertManager.class);
|
||||
new SendAlertMessageWindow()
|
||||
.onAddAlertMessage((alert, privKeyString) -> alertManager.addAlertMessageIfKeyIsValid(alert, privKeyString))
|
||||
.onRemoveAlertMessage(privKeyString -> alertManager.removeAlertMessageIfKeyIsValid(privKeyString))
|
||||
.onAddAlertMessage(alertManager::addAlertMessageIfKeyIsValid)
|
||||
.onRemoveAlertMessage(alertManager::removeAlertMessageIfKeyIsValid)
|
||||
.show();
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ public class SystemTray {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
});
|
||||
exitItem.addActionListener(e -> onExit.run());
|
||||
exitItem.addActionListener(e -> UserThread.execute(onExit::run));
|
||||
}
|
||||
|
||||
public void hideStage() {
|
||||
|
@ -152,7 +152,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||
return type != null ? "Market price (" + type.name + ")" : "";
|
||||
},
|
||||
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");
|
||||
@ -243,7 +243,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||
private Tuple2<TextField, VBox> getBalanceBox(String text) {
|
||||
TextField textField = new TextField();
|
||||
textField.setEditable(false);
|
||||
textField.setPrefWidth(120);
|
||||
textField.setPrefWidth(140);
|
||||
textField.setMouseTransparent(true);
|
||||
textField.setFocusTraversable(false);
|
||||
textField.setStyle("-fx-alignment: center; -fx-background-color: white;");
|
||||
|
@ -81,6 +81,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.security.Security;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
@ -443,6 +444,7 @@ public class MainViewModel implements ViewModel {
|
||||
walletPasswordWindow
|
||||
.onAesKey(aesKey -> {
|
||||
tradeWalletService.setAesKey(aesKey);
|
||||
walletService.setAesKey(aesKey);
|
||||
walletInitialized.set(true);
|
||||
})
|
||||
.hideCloseButton()
|
||||
@ -541,7 +543,7 @@ public class MainViewModel implements ViewModel {
|
||||
log.error(msg);
|
||||
UserThread.execute(() -> new Popup<>().warning(msg)
|
||||
.actionButtonText("Shut down")
|
||||
.onAction(() -> BitsquareApp.shutDownHandler.run())
|
||||
.onAction(BitsquareApp.shutDownHandler::run)
|
||||
.closeButtonText("Report bug at Github issues")
|
||||
.onClose(() -> Utilities.openWebPage("https://github.com/bitsquare/bitsquare/issues"))
|
||||
.show());
|
||||
@ -549,6 +551,15 @@ public class MainViewModel implements ViewModel {
|
||||
}
|
||||
};
|
||||
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,11 +824,10 @@ public class MainViewModel implements ViewModel {
|
||||
private void displayAlertIfPresent(Alert alert) {
|
||||
boolean alreadyDisplayed = alert != null && alert.equals(user.getDisplayedAlert());
|
||||
user.setDisplayedAlert(alert);
|
||||
|
||||
if (alert != null && !alreadyDisplayed) {
|
||||
if (!alert.isUpdateInfo || !alert.version.equals(Version.VERSION))
|
||||
new DisplayAlertMessageWindow().alertMessage(alert).show();
|
||||
}
|
||||
if (alert != null &&
|
||||
!alreadyDisplayed &&
|
||||
(!alert.isUpdateInfo || alert.isNewVersion()))
|
||||
new DisplayAlertMessageWindow().alertMessage(alert).show();
|
||||
}
|
||||
|
||||
private void swapPendingOfferFundingEntries() {
|
||||
|
@ -87,6 +87,7 @@ public class BackupView extends ActivatableView<GridPane, Void> {
|
||||
protected void activate() {
|
||||
selectBackupDir.setOnAction(e -> {
|
||||
DirectoryChooser directoryChooser = new DirectoryChooser();
|
||||
directoryChooser.setInitialDirectory(new File(System.getProperty("user.home")));
|
||||
directoryChooser.setTitle("Select backup location");
|
||||
File dir = directoryChooser.showDialog(stage);
|
||||
if (dir != null) {
|
||||
|
@ -117,6 +117,7 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
|
||||
if (wallet.checkAESKey(aesKey)) {
|
||||
wallet.decrypt(aesKey);
|
||||
tradeWalletService.setAesKey(null);
|
||||
walletService.setAesKey(null);
|
||||
new Popup()
|
||||
.feedback("Wallet successfully decrypted and password protection removed.")
|
||||
.show();
|
||||
@ -133,6 +134,7 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
|
||||
wallet.encrypt(keyCrypterScrypt, aesKey);
|
||||
// we save the key for the trade wallet as we don't require passwords here
|
||||
tradeWalletService.setAesKey(aesKey);
|
||||
walletService.setAesKey(aesKey);
|
||||
new Popup()
|
||||
.feedback("Wallet successfully encrypted and password protection enabled.")
|
||||
.show();
|
||||
|
@ -292,7 +292,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
||||
|
||||
private Coin getAmountAsCoin() {
|
||||
Coin senderAmount = formatter.parseToCoin(amountTextField.getText());
|
||||
if (!Restrictions.isAboveFixedTxFeeAndDust(senderAmount)) {
|
||||
if (!Restrictions.isAboveFixedTxFeeForTradesAndDust(senderAmount)) {
|
||||
senderAmount = Coin.ZERO;
|
||||
/* new Popup()
|
||||
.warning("The amount is lower than the transaction fee and the min. possible tx value (dust).")
|
||||
|
@ -43,7 +43,7 @@ public class TransactionsListItem {
|
||||
@Nullable
|
||||
private Tradable tradable;
|
||||
private String details;
|
||||
private String addressString;
|
||||
private String addressString = "";
|
||||
private String direction;
|
||||
private TxConfidenceListener txConfidenceListener;
|
||||
private boolean received;
|
||||
|
@ -41,17 +41,21 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
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.util.Callback;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.script.Script;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -77,7 +81,8 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
private final DisputeManager disputeManager;
|
||||
private final OfferDetailsWindow offerDetailsWindow;
|
||||
private WalletEventListener walletEventListener;
|
||||
|
||||
private EventHandler<KeyEvent> keyEventEventHandler;
|
||||
private Scene scene;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
@ -164,6 +169,33 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
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
|
||||
@ -173,6 +205,10 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
updateList();
|
||||
|
||||
walletService.getWallet().addEventListener(walletEventListener);
|
||||
|
||||
scene = root.getScene();
|
||||
if (scene != null)
|
||||
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -180,6 +216,9 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
sortedList.comparatorProperty().unbind();
|
||||
observableList.forEach(TransactionsListItem::cleanup);
|
||||
walletService.getWallet().removeEventListener(walletEventListener);
|
||||
|
||||
if (scene != null)
|
||||
scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,7 +22,6 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
import io.bitsquare.app.BitsquareApp;
|
||||
import io.bitsquare.btc.AddressEntry;
|
||||
import io.bitsquare.btc.AddressEntryException;
|
||||
import io.bitsquare.btc.Restrictions;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.btc.listeners.BalanceListener;
|
||||
import io.bitsquare.common.UserThread;
|
||||
@ -40,8 +39,10 @@ import io.bitsquare.trade.TradeManager;
|
||||
import io.bitsquare.trade.closed.ClosedTradableManager;
|
||||
import io.bitsquare.trade.failed.FailedTradesManager;
|
||||
import io.bitsquare.user.Preferences;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
@ -50,10 +51,7 @@ import javafx.scene.control.*;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.util.Callback;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bitcoinj.core.AddressFormatException;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.spongycastle.crypto.params.KeyParameter;
|
||||
|
||||
@ -87,6 +85,10 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
private Set<WithdrawalListItem> selectedItems = new HashSet<>();
|
||||
private BalanceListener balanceListener;
|
||||
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();
|
||||
}
|
||||
};
|
||||
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
|
||||
@ -140,17 +159,18 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
|
||||
reset();
|
||||
|
||||
amountTextField.textProperty().addListener(amountListener);
|
||||
amountTextField.focusedProperty().addListener(amountFocusListener);
|
||||
walletService.addBalanceListener(balanceListener);
|
||||
withdrawButton.disableProperty().bind(Bindings.createBooleanBinding(() -> !areInputsValid(),
|
||||
amountTextField.textProperty(), withdrawToTextField.textProperty()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
sortedList.comparatorProperty().unbind();
|
||||
observableList.forEach(WithdrawalListItem::cleanup);
|
||||
withdrawButton.disableProperty().unbind();
|
||||
walletService.removeBalanceListener(balanceListener);
|
||||
amountTextField.textProperty().removeListener(amountListener);
|
||||
amountTextField.focusedProperty().removeListener(amountFocusListener);
|
||||
}
|
||||
|
||||
|
||||
@ -160,8 +180,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
|
||||
@FXML
|
||||
public void onWithdraw() {
|
||||
Coin senderAmount = formatter.parseToCoin(amountTextField.getText());
|
||||
if (Restrictions.isAboveFixedTxFeeAndDust(senderAmount)) {
|
||||
if (areInputsValid()) {
|
||||
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
|
||||
@ -186,33 +205,38 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
}
|
||||
};
|
||||
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,
|
||||
withdrawToTextField.getText(), senderAmount);
|
||||
Coin receiverAmount = senderAmount.subtract(requiredFee);
|
||||
if (BitsquareApp.DEV_MODE) {
|
||||
doWithdraw(receiverAmount, callback);
|
||||
} else {
|
||||
new Popup().headLine("Confirm withdrawal request")
|
||||
.confirmation("Sending: " + formatter.formatCoinWithCode(senderAmount) + "\n" +
|
||||
"From address: " + withdrawFromTextField.getText() + "\n" +
|
||||
"To receiving address: " + withdrawToTextField.getText() + ".\n" +
|
||||
"Required transaction fee is: " + formatter.formatCoinWithCode(requiredFee) + "\n\n" +
|
||||
"The recipient will receive: " + formatter.formatCoinWithCode(receiverAmount) + "\n\n" +
|
||||
"Are you sure you want to withdraw that amount?")
|
||||
.actionButtonText("Yes")
|
||||
.onAction(() -> doWithdraw(receiverAmount, callback))
|
||||
.closeButtonText("Cancel")
|
||||
.show();
|
||||
withdrawToTextField.getText(), amountOfSelectedItems);
|
||||
Coin receiverAmount = senderAmountAsCoinProperty.get().subtract(requiredFee);
|
||||
if (receiverAmount.isPositive()) {
|
||||
if (BitsquareApp.DEV_MODE) {
|
||||
doWithdraw(receiverAmount, callback);
|
||||
} else {
|
||||
new Popup().headLine("Confirm withdrawal request")
|
||||
.confirmation("Sending: " + formatter.formatCoinWithCode(senderAmountAsCoinProperty.get()) + "\n" +
|
||||
"From address: " + withdrawFromTextField.getText() + "\n" +
|
||||
"To receiving address: " + withdrawToTextField.getText() + ".\n" +
|
||||
"Required transaction fee is: " + formatter.formatCoinWithCode(requiredFee) + "\n\n" +
|
||||
"The recipient will receive: " + formatter.formatCoinWithCode(receiverAmount) + "\n\n" +
|
||||
"Are you sure you want to withdraw that amount?")
|
||||
.actionButtonText("Yes")
|
||||
.onAction(() -> doWithdraw(receiverAmount, callback))
|
||||
.closeButtonText("Cancel")
|
||||
.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) {
|
||||
e.printStackTrace();
|
||||
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());
|
||||
|
||||
if (!selectedItems.isEmpty()) {
|
||||
Coin sum = Coin.valueOf(selectedItems.stream().mapToLong(e -> e.getBalance().getValue()).sum());
|
||||
if (sum.isPositive()) {
|
||||
amountTextField.setText(formatter.formatCoin(sum));
|
||||
amountOfSelectedItems = Coin.valueOf(selectedItems.stream().mapToLong(e -> e.getBalance().getValue()).sum());
|
||||
if (amountOfSelectedItems.isPositive()) {
|
||||
senderAmountAsCoinProperty.set(amountOfSelectedItems);
|
||||
amountTextField.setText(formatter.formatCoin(amountOfSelectedItems));
|
||||
} else {
|
||||
senderAmountAsCoinProperty.set(Coin.ZERO);
|
||||
amountOfSelectedItems = Coin.ZERO;
|
||||
amountTextField.setText("");
|
||||
withdrawFromTextField.setText("");
|
||||
}
|
||||
@ -298,11 +325,17 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
updateList();
|
||||
} catch (AddressFormatException e) {
|
||||
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) {
|
||||
new Popup().error(e.getMessage()).show();
|
||||
} catch (InsufficientMoneyException e) {
|
||||
log.warn(e.getMessage());
|
||||
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.setTooltip(null);
|
||||
|
||||
amountOfSelectedItems = Coin.ZERO;
|
||||
senderAmountAsCoinProperty.set(Coin.ZERO);
|
||||
amountTextField.setText("");
|
||||
amountTextField.setPromptText("Set the amount to withdraw");
|
||||
|
||||
@ -338,9 +373,27 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
}
|
||||
|
||||
private boolean areInputsValid() {
|
||||
return btcAddressValidator.validate(withdrawToTextField.getText()).isValid &&
|
||||
amountTextField.getText().length() > 0 &&
|
||||
Restrictions.isAboveFixedTxFeeAndDust(formatter.parseToCoin(amountTextField.getText()));
|
||||
if (!senderAmountAsCoinProperty.get().isPositive()) {
|
||||
new Popup().warning("Please fill in a valid value for the amount to send (max. 8 decimal places).").show();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -27,10 +27,7 @@ import io.bitsquare.gui.main.offer.BuyOfferView;
|
||||
import io.bitsquare.gui.main.offer.SellOfferView;
|
||||
import io.bitsquare.gui.main.offer.offerbook.OfferBookListItem;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.locale.BSResources;
|
||||
import io.bitsquare.locale.CryptoCurrency;
|
||||
import io.bitsquare.locale.FiatCurrency;
|
||||
import io.bitsquare.locale.TradeCurrency;
|
||||
import io.bitsquare.locale.*;
|
||||
import io.bitsquare.trade.offer.Offer;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
@ -69,6 +66,8 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
|
||||
private Subscription tradeCurrencySubscriber;
|
||||
private final StringProperty priceColumnLabel = 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);
|
||||
buyOfferTableView = tupleBuy.first;
|
||||
sellOfferTableView = tupleSell.first;
|
||||
buyOfferButton = tupleBuy.third;
|
||||
sellOfferButton = tupleSell.third;
|
||||
|
||||
HBox hBox = new HBox();
|
||||
hBox.setSpacing(30);
|
||||
@ -135,19 +136,29 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
|
||||
currencyComboBox.getSelectionModel().select(model.getTradeCurrency());
|
||||
currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 25));
|
||||
currencyComboBox.setOnAction(e -> {
|
||||
model.onSetTradeCurrency(currencyComboBox.getSelectionModel().getSelectedItem());
|
||||
TradeCurrency tradeCurrency = currencyComboBox.getSelectionModel().getSelectedItem();
|
||||
model.onSetTradeCurrency(tradeCurrency);
|
||||
updateChartData();
|
||||
});
|
||||
|
||||
model.getOfferBookListItems().addListener(changeListener);
|
||||
tradeCurrencySubscriber = EasyBind.subscribe(model.tradeCurrency,
|
||||
newValue -> {
|
||||
String code = newValue.getCode();
|
||||
areaChart.setTitle("Offer book for " + newValue.getName());
|
||||
tradeCurrency -> {
|
||||
String code = tradeCurrency.getCode();
|
||||
String tradeCurrencyName = tradeCurrency.getName();
|
||||
areaChart.setTitle("Offer book for " + tradeCurrencyName);
|
||||
priceColumnLabel.set("Price (" + code + "/BTC)");
|
||||
volumeColumnLabel.set("Volume (" + code + ")");
|
||||
xAxis.setLabel(priceColumnLabel.get());
|
||||
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());
|
||||
@ -316,7 +327,7 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
|
||||
placeholder.setWrapText(true);
|
||||
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");
|
||||
UserThread.execute(() -> titleLabel.prefWidthProperty().bind(tableView.widthProperty()));
|
||||
|
||||
@ -355,10 +366,10 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
|
||||
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis, "", ""));
|
||||
|
||||
seriesBuy = new XYChart.Series();
|
||||
seriesBuy.setName("Offers for buying bitcoin ");
|
||||
seriesBuy.setName("Bid offers ");
|
||||
|
||||
seriesSell = new XYChart.Series();
|
||||
seriesSell.setName("Offers for selling bitcoin ");
|
||||
seriesSell.setName("Ask offers");
|
||||
|
||||
areaChart = new AreaChart<>(xAxis, yAxis);
|
||||
areaChart.setAnimated(false);
|
||||
|
@ -889,8 +889,9 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
||||
cancelButton2 = addButton(gridPane, ++gridRow, BSResources.get("shared.cancel"));
|
||||
cancelButton2.setOnAction(e -> {
|
||||
if (model.dataModel.isWalletFunded.get()) {
|
||||
new Popup().warning("You have already paid in the funds.\n" +
|
||||
"Are you sure you want to cancel.")
|
||||
new Popup().warning("You have already paid the funds.\n" +
|
||||
"If you cancel now, your funds will be available immediately.\n" +
|
||||
"Are you sure you want to cancel?")
|
||||
.closeButtonText("No")
|
||||
.actionButtonText("Yes, cancel")
|
||||
.onAction(() -> {
|
||||
|
@ -493,9 +493,9 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||
calculateVolume();
|
||||
|
||||
// handle minAmount/amount relationship
|
||||
if (!dataModel.isMinAmountLessOrEqualAmount())
|
||||
if (!dataModel.isMinAmountLessOrEqualAmount())
|
||||
minAmount.set(amount.get());
|
||||
else
|
||||
else
|
||||
amountValidationResult.set(result);
|
||||
|
||||
if (minAmount.get() != null)
|
||||
@ -750,10 +750,11 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||
boolean inputDataValid = isBtcInputValid(amount.get()).isValid &&
|
||||
isBtcInputValid(minAmount.get()).isValid &&
|
||||
isFiatInputValid(price.get()).isValid &&
|
||||
dataModel.priceAsFiat.get() != null &&
|
||||
dataModel.priceAsFiat.get().getValue() != 0 &&
|
||||
isFiatInputValid(volume.get()).isValid &&
|
||||
dataModel.isMinAmountLessOrEqualAmount() &&
|
||||
!dataModel.useMarketBasedPrice.get() || dataModel.getMarketPriceMargin() != 0 &&
|
||||
dataModel.useMarketBasedPrice.get() || (dataModel.priceAsFiat.get() != null && dataModel.priceAsFiat.get().getValue() != 0);
|
||||
dataModel.isMinAmountLessOrEqualAmount();
|
||||
|
||||
isNextButtonDisabled.set(!inputDataValid);
|
||||
// boolean notSufficientFees = dataModel.isWalletFunded.get() && dataModel.isMainNet.get() && !dataModel.isFeeFromFundingTxSufficient.get();
|
||||
//isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || notSufficientFees);
|
||||
|
@ -272,7 +272,8 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
||||
String postFix = selectedTradeCurrency instanceof FiatCurrency || model.showAllTradeCurrenciesProperty.get() ? "" :
|
||||
" (" + 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);
|
||||
}
|
||||
|
||||
|
@ -778,8 +778,9 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||
cancelButton2 = addButton(gridPane, ++gridRow, BSResources.get("shared.cancel"));
|
||||
cancelButton2.setOnAction(e -> {
|
||||
if (model.dataModel.isWalletFunded.get()) {
|
||||
new Popup().warning("You have already paid in the funds.\n" +
|
||||
"Are you sure you want to cancel.")
|
||||
new Popup().warning("You have already paid the funds.\n" +
|
||||
"If you cancel now, your funds will be available immediately.\n" +
|
||||
"Are you sure you want to cancel?")
|
||||
.closeButtonText("No")
|
||||
.actionButtonText("Yes, cancel")
|
||||
.onAction(() -> {
|
||||
|
@ -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" +
|
||||
"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" +
|
||||
"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 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" +
|
||||
|
@ -183,7 +183,7 @@ public class BuyerStep5View extends TradeStepView {
|
||||
} else {
|
||||
if (toAddresses.isEmpty()) {
|
||||
validateWithdrawAddress();
|
||||
} else if (Restrictions.isAboveFixedTxFeeAndDust(senderAmount)) {
|
||||
} else if (Restrictions.isAboveFixedTxFeeForTradesAndDust(senderAmount)) {
|
||||
|
||||
if (BitsquareApp.DEV_MODE) {
|
||||
doWithdrawal(receiverAmount);
|
||||
|
@ -36,7 +36,6 @@ import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ProgressIndicator;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
import org.fxmisc.easybind.Subscription;
|
||||
|
||||
@ -152,13 +151,11 @@ public class SellerStep3View extends TradeStepView {
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithCopyIcon myPaymentDetailsTextField = addLabelTextFieldWithCopyIcon(gridPane, ++gridRow,
|
||||
myTitle, StringUtils.abbreviate(myPaymentDetails, 56)).second;
|
||||
TextFieldWithCopyIcon myPaymentDetailsTextField = addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, myTitle, myPaymentDetails).second;
|
||||
myPaymentDetailsTextField.setMouseTransparent(false);
|
||||
myPaymentDetailsTextField.setTooltip(new Tooltip(myPaymentDetails));
|
||||
|
||||
TextFieldWithCopyIcon peersPaymentDetailsTextField = addLabelTextFieldWithCopyIcon(gridPane, ++gridRow,
|
||||
peersTitle, StringUtils.abbreviate(peersPaymentDetails, 56)).second;
|
||||
TextFieldWithCopyIcon peersPaymentDetailsTextField = addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, peersTitle, peersPaymentDetails).second;
|
||||
peersPaymentDetailsTextField.setMouseTransparent(false);
|
||||
peersPaymentDetailsTextField.setTooltip(new Tooltip(peersPaymentDetails));
|
||||
|
||||
|
@ -74,7 +74,7 @@
|
||||
<PropertyValueFactory property="onionAddress"/>
|
||||
</cellValueFactory>
|
||||
</TableColumn>
|
||||
<TableColumn text="In/Out" fx:id="connectionTypeColumn" minWidth="70" maxWidth="80">
|
||||
<TableColumn text="In/Out" fx:id="connectionTypeColumn" minWidth="80" maxWidth="90">
|
||||
<cellValueFactory>
|
||||
<PropertyValueFactory property="connectionType"/>
|
||||
</cellValueFactory>
|
||||
|
@ -53,7 +53,7 @@ public class BSFormatter {
|
||||
// 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,
|
||||
// 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();
|
||||
|
||||
@ -97,7 +97,7 @@ public class BSFormatter {
|
||||
if (useMilliBit)
|
||||
return MonetaryFormat.MBTC;
|
||||
else
|
||||
return MonetaryFormat.BTC.repeatOptionalDecimals(2, 2);
|
||||
return MonetaryFormat.BTC.minDecimals(2).repeatOptionalDecimals(1, 6);
|
||||
}
|
||||
|
||||
/* public void setFiatCurrencyCode(String currencyCode) {
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>io.bitsquare</groupId>
|
||||
<version>0.4.3</version>
|
||||
<version>0.4.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>io.bitsquare</groupId>
|
||||
<version>0.4.3</version>
|
||||
<version>0.4.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>io.bitsquare</groupId>
|
||||
<version>0.4.3</version>
|
||||
<version>0.4.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>io.bitsquare</groupId>
|
||||
<version>0.4.3</version>
|
||||
<version>0.4.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -64,7 +64,7 @@ public class Connection implements MessageListener {
|
||||
|
||||
private static final int MAX_MSG_SIZE = 500 * 1024; // 500 kb
|
||||
//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 SOCKET_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(60);
|
||||
|
||||
@ -253,15 +253,15 @@ public class Connection implements MessageListener {
|
||||
boolean violated = false;
|
||||
//TODO remove serializable storage after network is tested stable
|
||||
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;
|
||||
// if duration < 1 sec we received too much messages
|
||||
violated = now - compareValue < TimeUnit.SECONDS.toMillis(1);
|
||||
if (violated) {
|
||||
log.error("violatesThrottleLimit 1 ");
|
||||
log.error("violatesThrottleLimit MSG_THROTTLE_PER_SEC ");
|
||||
log.error("elapsed " + (now - compareValue));
|
||||
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());
|
||||
}
|
||||
}
|
||||
@ -274,10 +274,10 @@ public class Connection implements MessageListener {
|
||||
violated = now - compareValue < TimeUnit.SECONDS.toMillis(10);
|
||||
|
||||
if (violated) {
|
||||
log.error("violatesThrottleLimit 2 ");
|
||||
log.error("violatesThrottleLimit MSG_THROTTLE_PER_10_SEC ");
|
||||
log.error("elapsed " + (now - compareValue));
|
||||
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());
|
||||
}
|
||||
}
|
||||
@ -544,8 +544,12 @@ public class Connection implements MessageListener {
|
||||
} else {
|
||||
// TODO sometimes we get StreamCorruptedException, OptionalDataException, IllegalStateException
|
||||
closeConnectionReason = CloseConnectionReason.UNKNOWN_EXCEPTION;
|
||||
log.warn("Unknown reason for exception at socket {}\n\tconnection={}\n\tException=",
|
||||
socket.toString(), this, e.toString());
|
||||
log.warn("Unknown reason for exception at socket {}\n\t" +
|
||||
"connection={}\n\t" +
|
||||
"Exception=",
|
||||
socket.toString(),
|
||||
this,
|
||||
e.toString());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import io.bitsquare.app.Log;
|
||||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.common.Clock;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.p2p.P2PService;
|
||||
import io.bitsquare.p2p.P2PServiceListener;
|
||||
@ -120,8 +121,11 @@ public class SeedNode {
|
||||
"Bitsquare_seed_node_" + String.valueOf(mySeedNodeAddress.getFullAddress().replace(":", "_")));
|
||||
|
||||
String logPath = Paths.get(appPath.toString(), "logs").toString();
|
||||
Log.setup(logPath, useDetailedLogging);
|
||||
Log.setup(logPath);
|
||||
log.info("Log files under: " + logPath);
|
||||
Version.printVersion();
|
||||
Utilities.printSysInfo();
|
||||
Log.setLevel(useDetailedLogging);
|
||||
|
||||
SeedNodesRepository seedNodesRepository = new SeedNodesRepository();
|
||||
if (progArgSeedNodes != null && !progArgSeedNodes.isEmpty()) {
|
||||
|
@ -36,6 +36,7 @@ public class SeedNodesRepository {
|
||||
new NodeAddress("uadzuib66jupaept.onion:8000"),
|
||||
new NodeAddress("hbma455xxbqhcuqh.onion:8000"),
|
||||
new NodeAddress("wgthuiqn3aoiovbm.onion:8000"),
|
||||
new NodeAddress("2zxtnprnx5wqr7a3.onion:8000"),
|
||||
|
||||
// testnet
|
||||
new NodeAddress("znmy44wcstn2rkva.onion:8001"),
|
||||
|
@ -6,7 +6,7 @@ mkdir -p gui/deploy
|
||||
set -e
|
||||
|
||||
# Edit versions
|
||||
fullVersion=0.4.3
|
||||
fullVersion=0.4.6
|
||||
jarFile="/home/bitsquare/Desktop/sf_vm_shared_ubuntu14_32bit/Bitsquare-$fullVersion.jar"
|
||||
|
||||
# Note: fakeroot needs to be installed on linux
|
||||
|
@ -6,7 +6,7 @@ mkdir -p gui/deploy
|
||||
set -e
|
||||
|
||||
# Edit versions
|
||||
fullVersion=0.4.3
|
||||
fullVersion=0.4.6
|
||||
jarFile="/home/mk/Desktop/sf_vm_shared_ubuntu/Bitsquare-$fullVersion.jar"
|
||||
|
||||
# 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"
|
||||
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-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
|
@ -5,7 +5,7 @@ mkdir -p gui/deploy
|
||||
|
||||
set -e
|
||||
|
||||
fullVersion="0.4.3"
|
||||
fullVersion="0.4.6"
|
||||
|
||||
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.jnlp"
|
||||
|
||||
mv "gui/deploy/bundles/Bitsquare.dmg" "gui/deploy/Bitsquare-$fullVersion.dmg"
|
||||
rm gui/deploy/bundles
|
||||
mv "gui/deploy/bundles/Bitsquare-$fullVersion.dmg" "gui/deploy/Bitsquare-$fullVersion.dmg"
|
||||
rm -r "gui/deploy/bundles"
|
||||
|
||||
mv "gui/deploy/SeedNode.jar" "gui/deploy/SeedNode-$fullVersion.jar"
|
||||
|
||||
|
||||
cd package/mac
|
34
package/mac/finalize.sh
Normal file
34
package/mac/finalize.sh
Normal 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"
|
@ -3,7 +3,7 @@
|
||||
[Setup]
|
||||
AppId={{bitsquare}}
|
||||
AppName=Bitsquare
|
||||
AppVersion=0.4.3
|
||||
AppVersion=0.4.6
|
||||
AppVerName=Bitsquare
|
||||
AppPublisher=Bitsquare
|
||||
AppComments=Bitsquare
|
||||
|
@ -1,13 +1,13 @@
|
||||
cd ..\..\
|
||||
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
|
||||
:: edit -> -BappVersion=0.4.3 and -srcfiles
|
||||
:: edit -> -BappVersion=0.4.6 and -srcfiles
|
||||
|
||||
:: 32 bit build
|
||||
:: 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
|
@ -1,13 +1,13 @@
|
||||
cd ..\..\
|
||||
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
|
||||
:: edit -> -BappVersion=0.4.3 and -srcfiles
|
||||
:: edit -> -BappVersion=0.4.6 and -srcfiles
|
||||
|
||||
:: 64 bit build
|
||||
:: 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
|
2
pom.xml
2
pom.xml
@ -6,7 +6,7 @@
|
||||
<groupId>io.bitsquare</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>0.4.3</version>
|
||||
<version>0.4.6</version>
|
||||
<description>Bitsquare - The decentralized bitcoin exchange</description>
|
||||
<url>https://bitsquare.io</url>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>io.bitsquare</groupId>
|
||||
<version>0.4.3</version>
|
||||
<version>0.4.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user