mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 15:10:44 +01:00
Merge branch 'Development'
This commit is contained in:
commit
20571e03df
131 changed files with 2574 additions and 385 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -26,3 +26,5 @@ build
|
|||
desktop.ini
|
||||
*.bat
|
||||
!package/windows/*bit*.bat
|
||||
*/target/*
|
||||
*.class
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>io.bitsquare</groupId>
|
||||
<version>0.4.9.8</version>
|
||||
<version>0.4.9.9</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
|||
import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
|
||||
import ch.qos.logback.core.rolling.RollingFileAppender;
|
||||
import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
|
||||
import ch.qos.logback.core.util.FileSize;
|
||||
import io.bitsquare.common.util.Profiler;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -54,7 +55,7 @@ public class Log {
|
|||
rollingPolicy.start();
|
||||
|
||||
triggeringPolicy = new SizeBasedTriggeringPolicy();
|
||||
triggeringPolicy.setMaxFileSize("10MB");
|
||||
triggeringPolicy.setMaxFileSize(FileSize.valueOf("10MB"));
|
||||
triggeringPolicy.start();
|
||||
|
||||
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
|
||||
|
|
|
@ -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.9.8";
|
||||
public static final String VERSION = "0.4.9.9";
|
||||
|
||||
// The version no. 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.
|
||||
|
@ -43,7 +43,7 @@ public class Version {
|
|||
|
||||
// The version no. of the current protocol. The offer holds that version.
|
||||
// A taker will check the version of the offers to see if his version is compatible.
|
||||
public static final int TRADE_PROTOCOL_VERSION = 1;
|
||||
public static final int TRADE_PROTOCOL_VERSION = 2;
|
||||
private static int p2pMessageVersion;
|
||||
|
||||
public static int getP2PMessageVersion() {
|
||||
|
|
|
@ -26,6 +26,7 @@ import com.google.gson.*;
|
|||
import io.bitsquare.io.LookAheadObjectInputStream;
|
||||
import javafx.scene.input.Clipboard;
|
||||
import javafx.scene.input.ClipboardContent;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -420,4 +421,45 @@ public class Utilities {
|
|||
public static String toTruncatedString(Object message) {
|
||||
return toTruncatedString(message, 200);
|
||||
}
|
||||
|
||||
public static String getRandomPrefix(int minLength, int maxLength) {
|
||||
int length = minLength + new Random().nextInt(maxLength - minLength + 1);
|
||||
String result;
|
||||
switch (new Random().nextInt(3)) {
|
||||
case 0:
|
||||
result = RandomStringUtils.randomAlphabetic(length);
|
||||
break;
|
||||
case 1:
|
||||
result = RandomStringUtils.randomNumeric(length);
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
result = RandomStringUtils.randomAlphanumeric(length);
|
||||
}
|
||||
|
||||
switch (new Random().nextInt(3)) {
|
||||
case 0:
|
||||
result = result.toUpperCase();
|
||||
break;
|
||||
case 1:
|
||||
result = result.toLowerCase();
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String getShortId(String id) {
|
||||
return getShortId(id, "-");
|
||||
}
|
||||
|
||||
public static String getShortId(String id, String sep) {
|
||||
String[] chunks = id.split(sep);
|
||||
if (chunks.length > 0)
|
||||
return chunks[0];
|
||||
else
|
||||
return id.substring(0, Math.min(8, id.length()));
|
||||
}
|
||||
}
|
||||
|
|
25
core/pom.xml
25
core/pom.xml
|
@ -6,34 +6,11 @@
|
|||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>io.bitsquare</groupId>
|
||||
<version>0.4.9.8</version>
|
||||
<version>0.4.9.9</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>core</artifactId>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- <plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce</id>
|
||||
<configuration>
|
||||
<rules>
|
||||
<DependencyConvergence />
|
||||
</rules>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>-->
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.bitsquare</groupId>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package io.bitsquare.alert;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.common.crypto.Sig;
|
||||
import io.bitsquare.p2p.storage.payload.StoragePayload;
|
||||
|
@ -69,9 +70,14 @@ public final class Alert implements StoragePayload {
|
|||
}
|
||||
|
||||
public boolean isNewVersion() {
|
||||
return isNewVersion(Version.VERSION);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected boolean isNewVersion(String appVersion) {
|
||||
// Usually we use 3 digits (0.4.8) but to support also 4 digits in case of hotfixes (0.4.8.1) we
|
||||
// add a 0 at all 3 digit versions to allow correct comparison: 0.4.8 -> 480; 0.4.8.1 -> 481; 481 > 480
|
||||
String myVersionString = Version.VERSION.replace(".", "");
|
||||
String myVersionString = appVersion.replace(".", "");
|
||||
if (myVersionString.length() == 3)
|
||||
myVersionString += "0";
|
||||
int versionNum = Integer.valueOf(myVersionString);
|
||||
|
|
|
@ -62,7 +62,7 @@ public class BitsquareEnvironment extends StandardEnvironment {
|
|||
public static final String DEFAULT_USER_DATA_DIR = defaultUserDataDir();
|
||||
public static final String DEFAULT_APP_DATA_DIR = appDataDir(DEFAULT_USER_DATA_DIR, DEFAULT_APP_NAME);
|
||||
|
||||
public static final String LOG_LEVEL_DEFAULT = (DevFlags.STRESS_TEST_MODE || DevFlags.DEV_MODE) ? Level.TRACE.levelStr : Level.INFO.levelStr;
|
||||
public static final String LOG_LEVEL_DEFAULT = Level.INFO.levelStr;
|
||||
|
||||
static final String BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME = "bitsquareCommandLineProperties";
|
||||
static final String BITSQUARE_APP_DIR_PROPERTY_SOURCE_NAME = "bitsquareAppDirProperties";
|
||||
|
|
|
@ -93,6 +93,9 @@ public abstract class BitsquareExecutable {
|
|||
.withRequiredArg();
|
||||
parser.accepts(NetworkOptionKeys.SOCKS_5_PROXY_HTTP_ADDRESS, description("A proxy address to be used for Http requests (should be non-Tor). [host:port]", ""))
|
||||
.withRequiredArg();
|
||||
parser.accepts(NetworkOptionKeys.SOCKS5_DISCOVER_MODE, description("Specify discovery mode for Bitcoin nodes. One or more of: [ADDR, DNS, ONION, ALL]" +
|
||||
" (comma separated, they get OR'd together). Default value is ALL", "ALL"))
|
||||
.withRequiredArg();
|
||||
|
||||
parser.accepts(AppOptionKeys.USER_DATA_DIR_KEY, description("User data directory", DEFAULT_USER_DATA_DIR))
|
||||
.withRequiredArg();
|
||||
|
|
|
@ -83,8 +83,7 @@ public class ArbitratorManager {
|
|||
"02b517c0cbc3a49548f448ddf004ed695c5a1c52ec110be1bfd65fa0ca0761c94b",
|
||||
"03df837a3a0f3d858e82f3356b71d1285327f101f7c10b404abed2abc1c94e7169",
|
||||
"0203a90fb2ab698e524a5286f317a183a84327b8f8c3f7fa4a98fec9e1cefd6b72",
|
||||
"023c99cc073b851c892d8c43329ca3beb5d2213ee87111af49884e3ce66cbd5ba5",
|
||||
"0274f772a98d23e7a0251ab30d7121897b5aebd11a2f1e45ab654aa57503173245"
|
||||
"023c99cc073b851c892d8c43329ca3beb5d2213ee87111af49884e3ce66cbd5ba5"
|
||||
));
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ package io.bitsquare.arbitration;
|
|||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.arbitration.messages.DisputeCommunicationMessage;
|
||||
import io.bitsquare.common.crypto.PubKeyRing;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.common.wire.Payload;
|
||||
import io.bitsquare.storage.Storage;
|
||||
import io.bitsquare.trade.Contract;
|
||||
|
@ -195,7 +196,7 @@ public final class Dispute implements Payload {
|
|||
}
|
||||
|
||||
public String getShortTradeId() {
|
||||
return tradeId.substring(0, 8);
|
||||
return Utilities.getShortId(tradeId);
|
||||
}
|
||||
|
||||
public int getTraderId() {
|
||||
|
|
|
@ -19,6 +19,7 @@ package io.bitsquare.btc;
|
|||
|
||||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.common.persistance.Persistable;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
|
@ -136,7 +137,7 @@ public final class AddressEntry implements Persistable {
|
|||
// For display we usually only display the first 8 characters.
|
||||
@Nullable
|
||||
public String getShortOfferId() {
|
||||
return getOfferId() != null ? getOfferId().substring(0, Math.min(8, getOfferId().length())) : null;
|
||||
return offerId != null ? Utilities.getShortId(offerId) : null;
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
|
|
|
@ -25,26 +25,27 @@ public class FeePolicy {
|
|||
// With block getting filled up the needed fee to get fast into a black has become more expensive and less predictable.
|
||||
// To see current fees check out:
|
||||
// https://tradeblock.com/blockchain
|
||||
// http://www.cointape.com
|
||||
// https://jochen-hoenicke.de/queue/24h.html
|
||||
// https://bitcoinfees.21.co/
|
||||
// http://p2sh.info/dashboard/db/fee-estimation
|
||||
// https://bitcoinfees.github.io/#1d
|
||||
// Average values are 10-100 satoshis/byte in january 2016
|
||||
// Average values are 60-140 satoshis/byte in february 2017
|
||||
//
|
||||
// Our trade transactions have a fixed set of inputs and outputs making the size very predictable
|
||||
// (as long the user does not do multiple funding transactions)
|
||||
//
|
||||
// trade fee tx: 226 bytes // 88 satoshi/byte
|
||||
// deposit tx: 336 bytes // 59 satoshi/byte
|
||||
// payout tx: 371 bytes // 53 satoshi/byte
|
||||
// disputed payout tx: 408 bytes // 49 satoshi/byte
|
||||
// trade fee tx: 226 bytes // 221 satoshi/byte
|
||||
// deposit tx: 336 bytes // 148 satoshi/byte
|
||||
// payout tx: 371 bytes // 134 satoshi/byte
|
||||
// disputed payout tx: 408 bytes // 122 satoshi/byte
|
||||
|
||||
// We set a fixed fee to make the needed amounts in the trade predictable.
|
||||
// We use 0.0002 BTC (0.08 EUR @ 400 EUR/BTC) which is for our tx sizes about 50-90 satoshi/byte
|
||||
// We use 0.0005 BTC (0.5 EUR @ 1000 EUR/BTC) which is for our tx sizes about 120-220 satoshi/byte
|
||||
// We cannot make that user defined as it need to be the same for both users, so we can only change that in
|
||||
// software updates
|
||||
// TODO before Beta we should get a good future proof guess as a change causes incompatible versions
|
||||
public static Coin getFixedTxFeeForTrades() {
|
||||
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(5_000) : Coin.valueOf(20_000);
|
||||
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(5_000) : Coin.valueOf(50_000);
|
||||
}
|
||||
|
||||
// For non trade transactions (withdrawal) we use the default fee calculation
|
||||
|
@ -53,7 +54,7 @@ public class FeePolicy {
|
|||
// The BitcoinJ fee calculation use kb so a tx size < 1kb will still pay the fee for a kb tx.
|
||||
// Our payout tx has about 370 bytes so we get a fee/kb value of about 90 satoshi/byte making it high priority
|
||||
// Other payout transactions (E.g. arbitrators many collected transactions) will go with 30 satoshi/byte if > 1kb
|
||||
private static Coin NON_TRADE_FEE_PER_KB = DevFlags.STRESS_TEST_MODE ? Coin.valueOf(5_000) : Coin.valueOf(20_000); // 0.0002 BTC about 0.08 EUR @ 400 EUR/BTC
|
||||
private static Coin NON_TRADE_FEE_PER_KB = DevFlags.STRESS_TEST_MODE ? Coin.valueOf(5_000) : Coin.valueOf(30_000); // 0.0003 BTC about 0.3 EUR @ 1000 EUR/BTC
|
||||
|
||||
public static void setNonTradeFeePerKb(Coin nonTradeFeePerKb) {
|
||||
NON_TRADE_FEE_PER_KB = nonTradeFeePerKb;
|
||||
|
@ -63,22 +64,20 @@ public class FeePolicy {
|
|||
return NON_TRADE_FEE_PER_KB;
|
||||
}
|
||||
|
||||
// 0.0005 BTC 0.05% of 1 BTC about 0.2 EUR @ 400 EUR/BTC
|
||||
// 0.0008 BTC 0.08% of 1 BTC about 0.8 EUR @ 1000 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
|
||||
// The arbitrator receive only 0.0002 BTC - less than the miners
|
||||
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(10_000) : Coin.valueOf(50_000);
|
||||
// We need to pay the quite high miner fee of 50_000 from the trading fee tx so 30_000 is what
|
||||
// the arbitrator receives
|
||||
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(10_000) : Coin.valueOf(80_000);
|
||||
}
|
||||
|
||||
// 0.001 BTC 0.1% of 1 BTC about 0.4 EUR @ 400 EUR/BTC
|
||||
// 0.001 BTC 0.1% of 1 BTC about 1 EUR @ 1000 EUR/BTC
|
||||
public static Coin getTakeOfferFee() {
|
||||
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(10_000) : Coin.valueOf(100_000);
|
||||
}
|
||||
|
||||
|
||||
// TODO will be increased once we get higher limits
|
||||
// 0.01 BTC; about 4 EUR @ 400 EUR/BTC
|
||||
// 0.03 BTC; about 30 EUR @ 1000 EUR/BTC
|
||||
public static Coin getSecurityDeposit() {
|
||||
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(5_000) : Coin.valueOf(1_000_000);
|
||||
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(5_000) : Coin.valueOf(3_000_000);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -238,7 +238,7 @@ public class TradeWalletService {
|
|||
|
||||
verifyTransaction(dummyTX);
|
||||
|
||||
printTxWithInputs("dummyTX", dummyTX);
|
||||
//printTxWithInputs("dummyTX", dummyTX);
|
||||
|
||||
List<RawTransactionInput> rawTransactionInputList = dummyTX.getInputs().stream()
|
||||
.map(e -> {
|
||||
|
@ -407,7 +407,7 @@ public class TradeWalletService {
|
|||
|
||||
verifyTransaction(preparedDepositTx);
|
||||
|
||||
printTxWithInputs("preparedDepositTx", preparedDepositTx);
|
||||
//printTxWithInputs("preparedDepositTx", preparedDepositTx);
|
||||
|
||||
return new PreparedDepositTxAndOffererInputs(offererRawTransactionInputs, preparedDepositTx.bitcoinSerialize());
|
||||
}
|
||||
|
@ -428,15 +428,15 @@ public class TradeWalletService {
|
|||
* @throws TransactionVerificationException
|
||||
* @throws WalletException
|
||||
*/
|
||||
public void takerSignsAndPublishesDepositTx(boolean takerIsSeller,
|
||||
byte[] contractHash,
|
||||
byte[] offerersDepositTxSerialized,
|
||||
List<RawTransactionInput> buyerInputs,
|
||||
List<RawTransactionInput> sellerInputs,
|
||||
byte[] buyerPubKey,
|
||||
byte[] sellerPubKey,
|
||||
byte[] arbitratorPubKey,
|
||||
FutureCallback<Transaction> callback) throws SigningException, TransactionVerificationException,
|
||||
public Transaction takerSignsAndPublishesDepositTx(boolean takerIsSeller,
|
||||
byte[] contractHash,
|
||||
byte[] offerersDepositTxSerialized,
|
||||
List<RawTransactionInput> buyerInputs,
|
||||
List<RawTransactionInput> sellerInputs,
|
||||
byte[] buyerPubKey,
|
||||
byte[] sellerPubKey,
|
||||
byte[] arbitratorPubKey,
|
||||
FutureCallback<Transaction> callback) throws SigningException, TransactionVerificationException,
|
||||
WalletException {
|
||||
Transaction offerersDepositTx = new Transaction(params, offerersDepositTxSerialized);
|
||||
|
||||
|
@ -493,7 +493,7 @@ public class TradeWalletService {
|
|||
|
||||
// Add all outputs from offerersDepositTx to depositTx
|
||||
offerersDepositTx.getOutputs().forEach(depositTx::addOutput);
|
||||
printTxWithInputs("offerersDepositTx", offerersDepositTx);
|
||||
//printTxWithInputs("offerersDepositTx", offerersDepositTx);
|
||||
|
||||
// Sign inputs
|
||||
int start = takerIsSeller ? buyerInputs.size() : 0;
|
||||
|
@ -513,6 +513,8 @@ public class TradeWalletService {
|
|||
checkNotNull(walletAppKit);
|
||||
ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(depositTx).future();
|
||||
Futures.addCallback(broadcastComplete, callback);
|
||||
|
||||
return depositTx;
|
||||
}
|
||||
|
||||
|
||||
|
@ -575,7 +577,7 @@ public class TradeWalletService {
|
|||
|
||||
verifyTransaction(preparedPayoutTx);
|
||||
|
||||
printTxWithInputs("preparedPayoutTx", preparedPayoutTx);
|
||||
//printTxWithInputs("preparedPayoutTx", preparedPayoutTx);
|
||||
|
||||
return sellerSignature.encodeToDER();
|
||||
}
|
||||
|
@ -683,16 +685,16 @@ public class TradeWalletService {
|
|||
* @throws AddressFormatException
|
||||
* @throws TransactionVerificationException
|
||||
*/
|
||||
public byte[] signDisputedPayoutTx(byte[] depositTxSerialized,
|
||||
Coin buyerPayoutAmount,
|
||||
Coin sellerPayoutAmount,
|
||||
Coin arbitratorPayoutAmount,
|
||||
String buyerAddressString,
|
||||
String sellerAddressString,
|
||||
AddressEntry arbitratorAddressEntry,
|
||||
byte[] buyerPubKey,
|
||||
byte[] sellerPubKey,
|
||||
byte[] arbitratorPubKey)
|
||||
public byte[] arbitratorSignsDisputedPayoutTx(byte[] depositTxSerialized,
|
||||
Coin buyerPayoutAmount,
|
||||
Coin sellerPayoutAmount,
|
||||
Coin arbitratorPayoutAmount,
|
||||
String buyerAddressString,
|
||||
String sellerAddressString,
|
||||
AddressEntry arbitratorAddressEntry,
|
||||
byte[] buyerPubKey,
|
||||
byte[] sellerPubKey,
|
||||
byte[] arbitratorPubKey)
|
||||
throws AddressFormatException, TransactionVerificationException {
|
||||
Transaction depositTx = new Transaction(params, depositTxSerialized);
|
||||
log.trace("signDisputedPayoutTx called");
|
||||
|
@ -730,7 +732,7 @@ public class TradeWalletService {
|
|||
|
||||
verifyTransaction(preparedPayoutTx);
|
||||
|
||||
printTxWithInputs("preparedPayoutTx", preparedPayoutTx);
|
||||
//printTxWithInputs("preparedPayoutTx", preparedPayoutTx);
|
||||
|
||||
return arbitratorSignature.encodeToDER();
|
||||
}
|
||||
|
@ -827,6 +829,136 @@ public class TradeWalletService {
|
|||
}
|
||||
|
||||
|
||||
// Emergency payout tool. Used only in cased when the payput from the arbitrator does not work because some data
|
||||
// in the trade/dispute are messed up.
|
||||
public Transaction emergencySignAndPublishPayoutTx(String depositTxHex,
|
||||
Coin buyerPayoutAmount,
|
||||
Coin sellerPayoutAmount,
|
||||
Coin arbitratorPayoutAmount,
|
||||
String buyerAddressString,
|
||||
String sellerAddressString,
|
||||
String arbitratorAddressString,
|
||||
@Nullable String buyerPrivateKeyAsHex,
|
||||
@Nullable String sellerPrivateKeyAsHex,
|
||||
String arbitratorPrivateKeyAsHex,
|
||||
String buyerPubKeyAsHex,
|
||||
String sellerPubKeyAsHex,
|
||||
String arbitratorPubKeyAsHex,
|
||||
String P2SHMultiSigOutputScript,
|
||||
List<String> buyerPubKeys,
|
||||
List<String> sellerPubKeys,
|
||||
FutureCallback<Transaction> callback)
|
||||
throws AddressFormatException, TransactionVerificationException, WalletException {
|
||||
log.info("signAndPublishPayoutTx called");
|
||||
log.info("depositTxHex " + depositTxHex);
|
||||
log.info("buyerPayoutAmount " + buyerPayoutAmount.toFriendlyString());
|
||||
log.info("sellerPayoutAmount " + sellerPayoutAmount.toFriendlyString());
|
||||
log.info("arbitratorPayoutAmount " + arbitratorPayoutAmount.toFriendlyString());
|
||||
log.info("buyerAddressString " + buyerAddressString);
|
||||
log.info("sellerAddressString " + sellerAddressString);
|
||||
log.info("arbitratorAddressString " + arbitratorAddressString);
|
||||
log.info("buyerPrivateKeyAsHex (not displayed for security reasons)");
|
||||
log.info("sellerPrivateKeyAsHex (not displayed for security reasons)");
|
||||
log.info("arbitratorPrivateKeyAsHex (not displayed for security reasons)");
|
||||
log.info("buyerPubKeyAsHex " + buyerPubKeyAsHex);
|
||||
log.info("sellerPubKeyAsHex " + sellerPubKeyAsHex);
|
||||
log.info("arbitratorPubKeyAsHex " + arbitratorPubKeyAsHex);
|
||||
log.info("P2SHMultiSigOutputScript " + P2SHMultiSigOutputScript);
|
||||
log.info("buyerPubKeys " + buyerPubKeys);
|
||||
log.info("sellerPubKeys " + sellerPubKeys);
|
||||
|
||||
checkNotNull((buyerPrivateKeyAsHex != null || sellerPrivateKeyAsHex != null), "either buyerPrivateKeyAsHex or sellerPrivateKeyAsHex must not be null");
|
||||
|
||||
byte[] buyerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(buyerPubKeyAsHex)).getPubKey();
|
||||
byte[] sellerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(sellerPubKeyAsHex)).getPubKey();
|
||||
final byte[] arbitratorPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(arbitratorPubKeyAsHex)).getPubKey();
|
||||
|
||||
Script p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
|
||||
|
||||
if (!p2SHMultiSigOutputScript.toString().contains(P2SHMultiSigOutputScript)) {
|
||||
if (buyerPubKeys.isEmpty())
|
||||
buyerPubKeys.add(buyerPubKeyAsHex);
|
||||
if (sellerPubKeys.isEmpty())
|
||||
sellerPubKeys.add(sellerPubKeyAsHex);
|
||||
|
||||
boolean found = false;
|
||||
for (String b : buyerPubKeys) {
|
||||
if (found)
|
||||
break;
|
||||
byte[] bk = ECKey.fromPublicOnly(Utils.HEX.decode(b)).getPubKey();
|
||||
for (String s : sellerPubKeys) {
|
||||
byte[] sk = ECKey.fromPublicOnly(Utils.HEX.decode(s)).getPubKey();
|
||||
p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(bk, sk, arbitratorPubKey);
|
||||
if (p2SHMultiSigOutputScript.toString().contains(P2SHMultiSigOutputScript)) {
|
||||
log.info("Found buyers pub key " + b);
|
||||
log.info("Found sellers pub key " + s);
|
||||
buyerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(b)).getPubKey();
|
||||
sellerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(s)).getPubKey();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
log.warn("We did not find any matching pub keys for generating the required p2SHMultiSigOutputScript");
|
||||
}
|
||||
|
||||
Coin msOutput = buyerPayoutAmount.add(sellerPayoutAmount).add(arbitratorPayoutAmount).add(FeePolicy.getFixedTxFeeForTrades());
|
||||
TransactionOutput p2SHMultiSigOutput = new TransactionOutput(params, null, msOutput, p2SHMultiSigOutputScript.getProgram());
|
||||
Transaction depositTx = new Transaction(params);
|
||||
depositTx.addOutput(p2SHMultiSigOutput);
|
||||
|
||||
Transaction payoutTx = new Transaction(params);
|
||||
Sha256Hash spendTxHash = Sha256Hash.wrap(depositTxHex);
|
||||
payoutTx.addInput(new TransactionInput(params, depositTx, p2SHMultiSigOutputScript.getProgram(), new TransactionOutPoint(params, 0, spendTxHash), msOutput));
|
||||
|
||||
if (buyerPayoutAmount.isGreaterThan(Coin.ZERO))
|
||||
payoutTx.addOutput(buyerPayoutAmount, new Address(params, buyerAddressString));
|
||||
if (sellerPayoutAmount.isGreaterThan(Coin.ZERO))
|
||||
payoutTx.addOutput(sellerPayoutAmount, new Address(params, sellerAddressString));
|
||||
if (arbitratorPayoutAmount.isGreaterThan(Coin.ZERO))
|
||||
payoutTx.addOutput(arbitratorPayoutAmount, new Address(params, arbitratorAddressString));
|
||||
|
||||
// take care of sorting!
|
||||
Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
|
||||
Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
|
||||
|
||||
ECKey.ECDSASignature tradersSignature;
|
||||
if (buyerPrivateKeyAsHex != null && !buyerPrivateKeyAsHex.isEmpty()) {
|
||||
final ECKey buyerPrivateKey = ECKey.fromPrivate(Utils.HEX.decode(buyerPrivateKeyAsHex));
|
||||
checkNotNull(buyerPrivateKey, "buyerPrivateKey must not be null");
|
||||
tradersSignature = buyerPrivateKey.sign(sigHash, aesKey).toCanonicalised();
|
||||
} else {
|
||||
checkNotNull(sellerPrivateKeyAsHex, "sellerPrivateKeyAsHex must not be null");
|
||||
final ECKey sellerPrivateKey = ECKey.fromPrivate(Utils.HEX.decode(sellerPrivateKeyAsHex));
|
||||
checkNotNull(sellerPrivateKey, "sellerPrivateKey must not be null");
|
||||
tradersSignature = sellerPrivateKey.sign(sigHash, aesKey).toCanonicalised();
|
||||
}
|
||||
final ECKey key = ECKey.fromPrivate(Utils.HEX.decode(arbitratorPrivateKeyAsHex));
|
||||
checkNotNull(key, "key must not be null");
|
||||
ECKey.ECDSASignature arbitratorSignature = key.sign(sigHash, aesKey).toCanonicalised();
|
||||
|
||||
TransactionSignature tradersTxSig = new TransactionSignature(tradersSignature, Transaction.SigHash.ALL, false);
|
||||
TransactionSignature arbitratorTxSig = new TransactionSignature(arbitratorSignature, Transaction.SigHash.ALL, false);
|
||||
// Take care of order of signatures. See comment below at getMultiSigRedeemScript (sort order needed here: arbitrator, seller, buyer)
|
||||
Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(arbitratorTxSig, tradersTxSig), redeemScript);
|
||||
TransactionInput input = payoutTx.getInput(0);
|
||||
input.setScriptSig(inputScript);
|
||||
|
||||
printTxWithInputs("payoutTx", payoutTx);
|
||||
|
||||
verifyTransaction(payoutTx);
|
||||
checkWalletConsistency();
|
||||
|
||||
if (walletAppKit != null) {
|
||||
ListenableFuture<Transaction> future = walletAppKit.peerGroup().broadcastTransaction(payoutTx).future();
|
||||
Futures.addCallback(future, callback);
|
||||
}
|
||||
|
||||
return payoutTx;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -990,12 +1122,16 @@ public class TradeWalletService {
|
|||
}
|
||||
|
||||
private static void printTxWithInputs(String tracePrefix, Transaction tx) {
|
||||
log.trace(tracePrefix + ": " + tx.toString());
|
||||
long fee = tx.getFee() != null ? tx.getFee().value : 0;
|
||||
int size = tx.getMessageSize();
|
||||
log.info(tracePrefix + ": " + tx.toString() + "\nSize (Byte): " + size + "\nFee (Satoshi/Byte): "
|
||||
+ (fee / size));
|
||||
|
||||
for (TransactionInput input : tx.getInputs()) {
|
||||
if (input.getConnectedOutput() != null)
|
||||
log.trace(tracePrefix + " input value: " + input.getConnectedOutput().getValue().toFriendlyString());
|
||||
log.info(tracePrefix + " input value: " + input.getConnectedOutput().getValue().toFriendlyString());
|
||||
else
|
||||
log.trace(tracePrefix + ": Transaction already has inputs but we don't have the connected outputs, so we don't know the value.");
|
||||
log.info(tracePrefix + ": Transaction already has inputs but we don't have the connected outputs, so we don't know the value.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package io.bitsquare.btc;
|
||||
|
||||
import com.google.common.net.InetAddresses;
|
||||
import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.core.PeerGroup;
|
||||
|
@ -24,8 +25,10 @@ import org.bitcoinj.kits.WalletAppKit;
|
|||
import org.bitcoinj.net.BlockingClientManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class WalletAppKitBitSquare extends WalletAppKit {
|
||||
|
@ -44,25 +47,41 @@ public class WalletAppKitBitSquare extends WalletAppKit {
|
|||
}
|
||||
|
||||
protected PeerGroup createPeerGroup() throws TimeoutException {
|
||||
|
||||
// no proxy case.
|
||||
if (socks5Proxy == null) {
|
||||
if (socks5Proxy == null || isLocalHostFullNodeRunning()) {
|
||||
return super.createPeerGroup();
|
||||
} else {
|
||||
// proxy case.
|
||||
Proxy proxy = new Proxy(Proxy.Type.SOCKS,
|
||||
new InetSocketAddress(socks5Proxy.getInetAddress().getHostName(),
|
||||
socks5Proxy.getPort()));
|
||||
|
||||
int CONNECT_TIMEOUT_MSEC = 60 * 1000; // same value used in bitcoinj.
|
||||
ProxySocketFactory proxySocketFactory = new ProxySocketFactory(proxy);
|
||||
BlockingClientManager mgr = new BlockingClientManager(proxySocketFactory);
|
||||
PeerGroup peerGroup = new PeerGroup(params, vChain, mgr);
|
||||
|
||||
mgr.setConnectTimeoutMillis(CONNECT_TIMEOUT_MSEC);
|
||||
peerGroup.setConnectTimeoutMillis(CONNECT_TIMEOUT_MSEC);
|
||||
|
||||
return peerGroup;
|
||||
}
|
||||
}
|
||||
|
||||
// proxy case.
|
||||
Proxy proxy = new Proxy(Proxy.Type.SOCKS,
|
||||
new InetSocketAddress(socks5Proxy.getInetAddress().getHostName(),
|
||||
socks5Proxy.getPort()));
|
||||
|
||||
int CONNECT_TIMEOUT_MSEC = 60 * 1000; // same value used in bitcoinj.
|
||||
ProxySocketFactory proxySocketFactory = new ProxySocketFactory(proxy);
|
||||
BlockingClientManager mgr = new BlockingClientManager(proxySocketFactory);
|
||||
PeerGroup peerGroup = new PeerGroup(params, vChain, mgr);
|
||||
|
||||
mgr.setConnectTimeoutMillis(CONNECT_TIMEOUT_MSEC);
|
||||
peerGroup.setConnectTimeoutMillis(CONNECT_TIMEOUT_MSEC);
|
||||
|
||||
return peerGroup;
|
||||
private boolean isLocalHostFullNodeRunning() {
|
||||
// We check first if a local node is running, if so we connect direct without proxy.
|
||||
// Borrowed form PeerGroup.maybeCheckForLocalhostPeer()
|
||||
try {
|
||||
Socket socket = new Socket();
|
||||
socket.connect(new InetSocketAddress(InetAddresses.forString("127.0.0.1"), params.getPort()), PeerGroup.DEFAULT_CONNECT_TIMEOUT_MILLIS);
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ignore) {
|
||||
}
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
log.debug("Localhost peer not detected.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,15 +32,18 @@ import io.bitsquare.common.UserThread;
|
|||
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||
import io.bitsquare.common.handlers.ExceptionHandler;
|
||||
import io.bitsquare.common.handlers.ResultHandler;
|
||||
import io.bitsquare.network.DnsLookupTor;
|
||||
import io.bitsquare.network.NetworkOptionKeys;
|
||||
import io.bitsquare.network.Socks5MultiDiscovery;
|
||||
import io.bitsquare.network.Socks5ProxyProvider;
|
||||
import io.bitsquare.storage.FileUtil;
|
||||
import io.bitsquare.storage.Storage;
|
||||
import io.bitsquare.user.Preferences;
|
||||
import javafx.beans.property.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.crypto.DeterministicKey;
|
||||
import org.bitcoinj.crypto.KeyCrypterScrypt;
|
||||
import org.bitcoinj.net.discovery.SeedPeers;
|
||||
import org.bitcoinj.params.MainNetParams;
|
||||
import org.bitcoinj.params.RegTestParams;
|
||||
import org.bitcoinj.params.TestNet3Params;
|
||||
|
@ -92,6 +95,7 @@ public class WalletService {
|
|||
private final NetworkParameters params;
|
||||
private final File walletDir;
|
||||
private final UserAgent userAgent;
|
||||
private final int socks5DiscoverMode;
|
||||
|
||||
private WalletAppKitBitSquare walletAppKit;
|
||||
private Wallet wallet;
|
||||
|
@ -114,7 +118,8 @@ public class WalletService {
|
|||
UserAgent userAgent,
|
||||
Preferences preferences,
|
||||
Socks5ProxyProvider socks5ProxyProvider,
|
||||
@Named(BtcOptionKeys.WALLET_DIR) File appDir) {
|
||||
@Named(BtcOptionKeys.WALLET_DIR) File appDir,
|
||||
@Named(NetworkOptionKeys.SOCKS5_DISCOVER_MODE) String socks5DiscoverModeString) {
|
||||
this.regTestHost = regTestHost;
|
||||
this.tradeWalletService = tradeWalletService;
|
||||
this.addressEntryList = addressEntryList;
|
||||
|
@ -132,6 +137,27 @@ public class WalletService {
|
|||
bloomFilterTweak = new Random().nextLong();
|
||||
storage.queueUpForSave(bloomFilterTweak, 100);
|
||||
}
|
||||
|
||||
String[] socks5DiscoverModes = StringUtils.deleteWhitespace(socks5DiscoverModeString).split(",");
|
||||
int mode = 0;
|
||||
for (int i = 0; i < socks5DiscoverModes.length; i++) {
|
||||
switch (socks5DiscoverModes[i]) {
|
||||
case "ADDR":
|
||||
mode |= Socks5MultiDiscovery.SOCKS5_DISCOVER_ADDR;
|
||||
break;
|
||||
case "DNS":
|
||||
mode |= Socks5MultiDiscovery.SOCKS5_DISCOVER_DNS;
|
||||
break;
|
||||
case "ONION":
|
||||
mode |= Socks5MultiDiscovery.SOCKS5_DISCOVER_ONION;
|
||||
break;
|
||||
case "ALL":
|
||||
default:
|
||||
mode |= Socks5MultiDiscovery.SOCKS5_DISCOVER_ALL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
socks5DiscoverMode = mode;
|
||||
}
|
||||
|
||||
|
||||
|
@ -172,6 +198,7 @@ public class WalletService {
|
|||
|
||||
addressEntryList.onWalletReady(wallet);
|
||||
|
||||
|
||||
walletAppKit.peerGroup().addEventListener(new PeerEventListener() {
|
||||
@Override
|
||||
public void onPeersDiscovered(Set<PeerAddress> peerAddresses) {
|
||||
|
@ -265,9 +292,7 @@ public class WalletService {
|
|||
// Pass custom seed nodes if set in options
|
||||
if (!btcNodes.isEmpty()) {
|
||||
|
||||
// TODO: this parsing should be more robust,
|
||||
// give validation error if needed.
|
||||
String[] nodes = btcNodes.replace(", ", ",").split(",");
|
||||
String[] nodes = StringUtils.deleteWhitespace(btcNodes).split(",");
|
||||
List<PeerAddress> peerAddressList = new ArrayList<>();
|
||||
for (String node : nodes) {
|
||||
String[] parts = node.split(":");
|
||||
|
@ -278,19 +303,23 @@ public class WalletService {
|
|||
if (parts.length == 2) {
|
||||
// note: this will cause a DNS request if hostname used.
|
||||
// note: DNS requests are routed over socks5 proxy, if used.
|
||||
// fixme: .onion hostnames will fail! see comments in SeedPeersSocks5Dns
|
||||
// note: .onion hostnames will be unresolved.
|
||||
InetSocketAddress addr;
|
||||
if (socks5Proxy != null) {
|
||||
InetSocketAddress unresolved = InetSocketAddress.createUnresolved(parts[0], Integer.parseInt(parts[1]));
|
||||
// proxy remote DNS request happens here.
|
||||
addr = SeedPeersSocks5Dns.lookup(socks5Proxy, unresolved);
|
||||
try {
|
||||
// proxy remote DNS request happens here. blocking.
|
||||
addr = new InetSocketAddress(DnsLookupTor.lookup(socks5Proxy, parts[0]), Integer.parseInt(parts[1]));
|
||||
} catch (Exception e) {
|
||||
log.warn("Dns lookup failed for host: {}", parts[0]);
|
||||
addr = null;
|
||||
}
|
||||
} else {
|
||||
// DNS request happens here. if it fails, addr.isUnresolved() == true.
|
||||
addr = new InetSocketAddress(parts[0], Integer.parseInt(parts[1]));
|
||||
}
|
||||
// note: isUnresolved check should be removed once we fix PeerAddress
|
||||
if (addr != null && !addr.isUnresolved())
|
||||
if (addr != null && !addr.isUnresolved()) {
|
||||
peerAddressList.add(new PeerAddress(addr.getAddress(), addr.getPort()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (peerAddressList.size() > 0) {
|
||||
|
@ -342,9 +371,8 @@ public class WalletService {
|
|||
// could become outdated, so it is important that the user be able to
|
||||
// disable it, but should be made aware of the reduced privacy.
|
||||
if (socks5Proxy != null && !usePeerNodes) {
|
||||
// SeedPeersSocks5Dns should replace SeedPeers once working reliably.
|
||||
// SeedPeers uses hard coded stable addresses (from MainNetParams). It should be updated from time to time.
|
||||
walletAppKit.setDiscovery(new SeedPeers(params));
|
||||
walletAppKit.setDiscovery(new Socks5MultiDiscovery(socks5Proxy, params, socks5DiscoverMode));
|
||||
}
|
||||
|
||||
walletAppKit.setDownloadListener(downloadListener)
|
||||
|
@ -385,7 +413,9 @@ public class WalletService {
|
|||
return "BitcoinJ wallet:\n" +
|
||||
wallet.toString(includePrivKeys, true, true, walletAppKit.chain()) + "\n\n" +
|
||||
"Bitsquare address entry list:\n" +
|
||||
addressEntryListData.toString();
|
||||
addressEntryListData.toString() +
|
||||
"All pubkeys as hex:\n" +
|
||||
wallet.printAllPubKeysAsHex();
|
||||
}
|
||||
|
||||
public void restoreSeedWords(DeterministicSeed seed, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
|
||||
|
@ -1128,9 +1158,9 @@ public class WalletService {
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Inner classes
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Inner classes
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private static class DownloadListener extends DownloadProgressTracker {
|
||||
private final DoubleProperty percentage = new SimpleDoubleProperty(-1);
|
||||
|
|
|
@ -68,6 +68,8 @@ public class BankUtil {
|
|||
case "NZ":
|
||||
case "AU":
|
||||
case "SE":
|
||||
case "CL":
|
||||
case "NO":
|
||||
return false;
|
||||
case "CA":
|
||||
case "MX":
|
||||
|
@ -104,6 +106,7 @@ public class BankUtil {
|
|||
case "MX":
|
||||
case "HK":
|
||||
case "SE":
|
||||
case "NO":
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
|
@ -146,10 +149,14 @@ public class BankUtil {
|
|||
case "CA":
|
||||
case "HK":
|
||||
return "Account number:";
|
||||
case "NO":
|
||||
return "Kontonummer:";
|
||||
case "SE":
|
||||
return "Bankgiro number:";
|
||||
case "MX":
|
||||
return "CLABE:";
|
||||
case "CL":
|
||||
return "Cuenta:";
|
||||
default:
|
||||
return "Account no. (IBAN):";
|
||||
}
|
||||
|
@ -224,6 +231,7 @@ public class BankUtil {
|
|||
case "MX":
|
||||
case "HK":
|
||||
case "SE":
|
||||
case "NO":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
@ -137,6 +137,10 @@ public class CountryUtil {
|
|||
final Country country = new Country(locale.getCountry(), locale.getDisplayCountry(), region);
|
||||
allCountries.add(country);
|
||||
}
|
||||
|
||||
allCountries.add(new Country("GE", "Georgia", new Region("AS", getRegionName("AS"))));
|
||||
allCountries.add(new Country("BW", "Botswana", new Region("AF", getRegionName("AF"))));
|
||||
|
||||
final List<Country> allCountriesList = new ArrayList<>(allCountries);
|
||||
allCountriesList.sort((locale1, locale2) -> locale1.name.compareTo(locale2.name));
|
||||
return allCountriesList;
|
||||
|
@ -161,8 +165,8 @@ public class CountryUtil {
|
|||
|
||||
// other source of countries: https://developers.braintreepayments.com/reference/general/countries/java
|
||||
private static final String[] countryCodes = new String[]{"AE", "AL", "AR", "AT", "AU", "BA", "BE", "BG", "BH",
|
||||
"BO", "BR", "BY", "CA", "CH", "CL", "CN", "CO", "CR", "CS", "CU", "CY", "CZ", "DE", "DK", "DO", "DZ",
|
||||
"EC", "EE", "EG", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HR", "HU", "ID", "IE", "IL", "IN",
|
||||
"BO", "BR", "BW", "BY", "CA", "CH", "CL", "CN", "CO", "CR", "CS", "CU", "CY", "CZ", "DE", "DK", "DO", "DZ",
|
||||
"EC", "EE", "EG", "ES", "FI", "FR", "GE", "GB", "GR", "GT", "HK", "HN", "HR", "HU", "ID", "IE", "IL", "IN",
|
||||
"IQ", "IS", "IT", "JO", "JP", "KE", "KH", "KR", "KW", "KZ", "LB", "LT", "LU", "LV", "LY", "MA", "MD", "ME", "MK", "MT", "MX",
|
||||
"MY", "NI", "NL", "NO", "NZ", "OM", "PA", "PE", "PH", "PL", "PR", "PT", "PY", "QA", "RO", "RS", "RU",
|
||||
"SA", "SD", "SE", "SG", "SI", "SK", "SV", "SY", "TH", "TN", "TR", "TW", "UA", "US", "UY", "VE", "VN",
|
||||
|
@ -170,8 +174,8 @@ public class CountryUtil {
|
|||
|
||||
private static final List<String> countryCodeList = Arrays.asList(countryCodes);
|
||||
private static final String[] regionCodes = new String[]{"AS", "EU", "SA", "EU", "OC", "EU", "EU", "EU", "AS",
|
||||
"SA", "SA", "EU", "NA", "EU", "SA", "AS", "SA", "NA", "EU", "NA", "EU", "EU", "EU", "EU", "NA", "AF",
|
||||
"SA", "EU", "AF", "EU", "EU", "EU", "EU", "EU", "NA", "AS", "NA", "EU", "EU", "AS", "EU", "AS", "AS",
|
||||
"SA", "SA", "AF", "EU", "NA", "EU", "SA", "AS", "SA", "NA", "EU", "NA", "EU", "EU", "EU", "EU", "NA", "AF",
|
||||
"SA", "EU", "AF", "EU", "EU", "EU", "AS", "EU", "EU", "NA", "AS", "NA", "EU", "EU", "AS", "EU", "AS", "AS",
|
||||
"AS", "EU", "EU", "AS", "AS", "AF", "AS", "AS", "AS", "AS", "AS", "EU", "EU", "EU", "AF", "AF", "EU", "EU", "EU", "EU", "NA",
|
||||
"AS", "NA", "EU", "EU", "OC", "AS", "NA", "SA", "AS", "EU", "NA", "EU", "SA", "AS", "EU", "EU", "EU",
|
||||
"AS", "AF", "EU", "AS", "EU", "EU", "NA", "AS", "AS", "AF", "AS", "AS", "EU", "NA", "SA", "SA", "AS",
|
||||
|
|
|
@ -78,6 +78,7 @@ public class CurrencyUtil {
|
|||
result.add(new CryptoCurrency("AIB", "Advanced Internet Blocks"));
|
||||
result.add(new CryptoCurrency("ANC", "Anoncoin"));
|
||||
result.add(new CryptoCurrency("ANTI", "Anti"));
|
||||
result.add(new CryptoCurrency("ARCO", "AquariusCoin"));
|
||||
result.add(new CryptoCurrency("ARG", "Argentum"));
|
||||
result.add(new CryptoCurrency("REP", "Augur", true));
|
||||
result.add(new CryptoCurrency("BATL", "Battlestars"));
|
||||
|
@ -91,6 +92,7 @@ public class CurrencyUtil {
|
|||
result.add(new CryptoCurrency("BITNZD", "BitNZD", true));
|
||||
result.add(new CryptoCurrency("BITSEK", "BitSEK", true));
|
||||
result.add(new CryptoCurrency("BITSGD", "BitSGD", true));
|
||||
result.add(new CryptoCurrency("GBYTE", "Byte"));
|
||||
result.add(new CryptoCurrency("SYNQ", "BitSYNQ"));
|
||||
result.add(new CryptoCurrency("BTS", "BitShares"));
|
||||
result.add(new CryptoCurrency("BITUSD", "BitUSD", true));
|
||||
|
@ -103,7 +105,6 @@ public class CurrencyUtil {
|
|||
result.add(new CryptoCurrency("CRBIT", "Creditbit"));
|
||||
result.add(new CryptoCurrency("CRW", "Crown"));
|
||||
result.add(new CryptoCurrency("CBX", "Crypto Bullion"));
|
||||
result.add(new CryptoCurrency("DAO", "DAO", true));
|
||||
result.add(new CryptoCurrency("DNET", "DarkNet"));
|
||||
result.add(new CryptoCurrency("DIBC", "DIBCOIN"));
|
||||
result.add(new CryptoCurrency("DASH", "Dash"));
|
||||
|
@ -132,9 +133,11 @@ public class CurrencyUtil {
|
|||
result.add(new CryptoCurrency("HODL", "HOdlcoin"));
|
||||
result.add(new CryptoCurrency("HNC", "HunCoin"));
|
||||
result.add(new CryptoCurrency("IOC", "I/O Coin"));
|
||||
result.add(new CryptoCurrency("IOP", "Fermat"));
|
||||
result.add(new CryptoCurrency("JPYT", "JPY Tether"));
|
||||
result.add(new CryptoCurrency("JBS", "Jumbucks"));
|
||||
result.add(new CryptoCurrency("LBC", "LBRY Credits"));
|
||||
result.add(new CryptoCurrency("LTBC", "LTBcoin"));
|
||||
result.add(new CryptoCurrency("LSK", "Lisk"));
|
||||
result.add(new CryptoCurrency("LTC", "Litecoin"));
|
||||
result.add(new CryptoCurrency("MAID", "MaidSafeCoin"));
|
||||
|
@ -146,6 +149,7 @@ public class CurrencyUtil {
|
|||
result.add(new CryptoCurrency("XMY", "Myriadcoin"));
|
||||
result.add(new CryptoCurrency("NAV", "Nav Coin"));
|
||||
result.add(new CryptoCurrency("XEM", "NEM"));
|
||||
result.add(new CryptoCurrency("NEVA", "Nevacoin"));
|
||||
result.add(new CryptoCurrency("NMC", "Namecoin"));
|
||||
result.add(new CryptoCurrency("NBT", "NuBits"));
|
||||
result.add(new CryptoCurrency("NSR", "NuShares"));
|
||||
|
@ -156,6 +160,7 @@ public class CurrencyUtil {
|
|||
result.add(new CryptoCurrency("PASC", "Pascal Coin"));
|
||||
result.add(new CryptoCurrency("PPC", "Peercoin"));
|
||||
result.add(new CryptoCurrency("PINK", "Pinkcoin"));
|
||||
result.add(new CryptoCurrency("PIVX", "PIVX"));
|
||||
result.add(new CryptoCurrency("XPTX", "PlatinumBar"));
|
||||
result.add(new CryptoCurrency("PLU", "Plutons", true));
|
||||
result.add(new CryptoCurrency("POST", "PostCoin"));
|
||||
|
@ -165,6 +170,7 @@ public class CurrencyUtil {
|
|||
result.add(new CryptoCurrency("REALEST", "RealEst. Coin"));
|
||||
result.add(new CryptoCurrency("RDD", "ReddCoin"));
|
||||
result.add(new CryptoCurrency("XRP", "Ripple"));
|
||||
result.add(new CryptoCurrency("SFSC", "Safe FileSystem Coin"));
|
||||
result.add(new CryptoCurrency("STEEM", "STEEM"));
|
||||
result.add(new CryptoCurrency("SDC", "ShadowCash"));
|
||||
result.add(new CryptoCurrency("SHIFT", "Shift"));
|
||||
|
@ -177,6 +183,7 @@ public class CurrencyUtil {
|
|||
result.add(new CryptoCurrency("XLM", "Stellar Lumens"));
|
||||
result.add(new CryptoCurrency("SJCX", "StorjcoinX"));
|
||||
result.add(new CryptoCurrency("STRAT", "Stratis"));
|
||||
result.add(new CryptoCurrency("SWT", "Swarm City Token"));
|
||||
result.add(new CryptoCurrency("SYNX", "Syndicate"));
|
||||
result.add(new CryptoCurrency("AMP", "Synereo", true));
|
||||
result.add(new CryptoCurrency("TRI", "Triangles"));
|
||||
|
@ -188,6 +195,7 @@ public class CurrencyUtil {
|
|||
result.add(new CryptoCurrency("VRC", "VeriCoin"));
|
||||
result.add(new CryptoCurrency("WDC", "Worldcoin"));
|
||||
result.add(new CryptoCurrency("WAVES", "Waves"));
|
||||
result.add(new CryptoCurrency("XAUR", "Xaurum"));
|
||||
result.add(new CryptoCurrency("YACC", "YACCoin"));
|
||||
result.add(new CryptoCurrency("YBC", "YbCoin"));
|
||||
result.add(new CryptoCurrency("ZEC", "Zcash"));
|
||||
|
|
|
@ -195,8 +195,8 @@ public class TradeManager {
|
|||
private void initPendingTrades() {
|
||||
Log.traceCall();
|
||||
|
||||
List<Trade> toAdd = new ArrayList<>();
|
||||
List<Trade> toRemove = new ArrayList<>();
|
||||
List<Trade> addTradeToFailedTradesList = new ArrayList<>();
|
||||
List<Trade> removePreparedTradeList = new ArrayList<>();
|
||||
tradesForStatistics = new ArrayList<>();
|
||||
for (Trade trade : trades) {
|
||||
trade.setStorage(tradableListStorage);
|
||||
|
@ -206,16 +206,16 @@ public class TradeManager {
|
|||
trade.updateDepositTxFromWallet();
|
||||
tradesForStatistics.add(trade);
|
||||
} else if (trade.isTakerFeePaid()) {
|
||||
toAdd.add(trade);
|
||||
addTradeToFailedTradesList.add(trade);
|
||||
} else {
|
||||
toRemove.add(trade);
|
||||
removePreparedTradeList.add(trade);
|
||||
}
|
||||
}
|
||||
|
||||
for (Trade trade : toAdd)
|
||||
for (Trade trade : addTradeToFailedTradesList)
|
||||
addTradeToFailedTrades(trade);
|
||||
|
||||
for (Trade trade : toRemove)
|
||||
for (Trade trade : removePreparedTradeList)
|
||||
removePreparedTrade(trade);
|
||||
|
||||
for (Tradable tradable : closedTradableManager.getClosedTrades()) {
|
||||
|
|
|
@ -28,6 +28,7 @@ import io.bitsquare.common.handlers.ErrorMessageHandler;
|
|||
import io.bitsquare.common.handlers.ResultHandler;
|
||||
import io.bitsquare.common.util.JsonExclude;
|
||||
import io.bitsquare.common.util.MathUtils;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.locale.CurrencyUtil;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.p2p.storage.payload.RequiresOwnerIsOnlinePayload;
|
||||
|
@ -276,10 +277,6 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
|||
return getVolumeByAmount(getMinAmount());
|
||||
}
|
||||
|
||||
public String getReferenceText() {
|
||||
return getId().substring(0, Math.min(8, getId().length()));
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Availability
|
||||
|
@ -352,7 +349,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
|||
}
|
||||
|
||||
public String getShortId() {
|
||||
return getId().substring(0, Math.min(8, getId().length()));
|
||||
return Utilities.getShortId(id);
|
||||
}
|
||||
|
||||
public NodeAddress getOffererNodeAddress() {
|
||||
|
|
|
@ -168,7 +168,12 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
}
|
||||
|
||||
public void removeAllOpenOffers(@Nullable Runnable completeHandler) {
|
||||
removeOpenOffers(getOpenOffers(), completeHandler);
|
||||
}
|
||||
|
||||
public void removeOpenOffers(List<OpenOffer> openOffers, @Nullable Runnable completeHandler) {
|
||||
final int size = openOffers.size();
|
||||
// Copy list as we remove in the loop
|
||||
List<OpenOffer> openOffersList = new ArrayList<>(openOffers);
|
||||
openOffersList.forEach(openOffer -> removeOpenOffer(openOffer, () -> {
|
||||
}, errorMessage -> {
|
||||
|
@ -444,8 +449,20 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
final long maxDelay = (i + 2) * delay;
|
||||
final OpenOffer openOffer = openOffersList.get(i);
|
||||
UserThread.runAfterRandomDelay(() -> {
|
||||
if (openOffers.contains(openOffer) && openOffer.getId() != null)
|
||||
republishOffer(openOffer);
|
||||
if (openOffers.contains(openOffer)) {
|
||||
// The openOffer.getId().contains("_") check is because there was once a version
|
||||
// where we encoded the version nr in the offer id with a "_" as separator.
|
||||
// That caused several issues and was reverted. So if there are still old offers out with that
|
||||
// special offer ID format those must not be published as they cause failed taker attempts
|
||||
// with lost taker fee.
|
||||
String id = openOffer.getId();
|
||||
if (id != null && !id.contains("_"))
|
||||
republishOffer(openOffer);
|
||||
else
|
||||
log.warn("You have an offer with an invalid offer ID: offerID=" + id);
|
||||
}
|
||||
|
||||
|
||||
}, minDelay, maxDelay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -37,7 +37,7 @@ import static io.bitsquare.util.Validator.nonEmptyStringOf;
|
|||
public class OfferAvailabilityProtocol {
|
||||
private static final Logger log = LoggerFactory.getLogger(OfferAvailabilityProtocol.class);
|
||||
|
||||
private static final long TIMEOUT_SEC = 45;
|
||||
private static final long TIMEOUT_SEC = 60;
|
||||
|
||||
private final OfferAvailabilityModel model;
|
||||
private final ResultHandler resultHandler;
|
||||
|
|
|
@ -37,7 +37,7 @@ import static io.bitsquare.util.Validator.nonEmptyStringOf;
|
|||
|
||||
public abstract class TradeProtocol {
|
||||
private static final Logger log = LoggerFactory.getLogger(TradeProtocol.class);
|
||||
private static final long TIMEOUT_SEC = 60;
|
||||
private static final long TIMEOUT_SEC = 75;
|
||||
|
||||
protected final ProcessModel processModel;
|
||||
private final DecryptedDirectMessageListener decryptedDirectMessageListener;
|
||||
|
@ -110,7 +110,7 @@ public abstract class TradeProtocol {
|
|||
stopTimeout();
|
||||
|
||||
timeoutTimer = UserThread.runAfter(() -> {
|
||||
log.error("Timeout reached");
|
||||
log.error("Timeout reached. TradeID=" + trade.getId());
|
||||
trade.setErrorMessage("A timeout occurred.");
|
||||
cleanupTradable();
|
||||
cleanup();
|
||||
|
|
|
@ -61,7 +61,7 @@ public class SignAndPublishDepositTxAsBuyer extends TradeTask {
|
|||
buyerMultiSigAddressEntry.setLockedTradeAmount(Coin.valueOf(buyerInputs.stream().mapToLong(input -> input.value).sum()).subtract(FeePolicy.getFixedTxFeeForTrades()));
|
||||
walletService.saveAddressEntryList();
|
||||
TradingPeer tradingPeer = processModel.tradingPeer;
|
||||
processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(
|
||||
Transaction depositTx = processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(
|
||||
false,
|
||||
contractHash,
|
||||
processModel.getPreparedDepositTx(),
|
||||
|
@ -86,6 +86,7 @@ public class SignAndPublishDepositTxAsBuyer extends TradeTask {
|
|||
failed(t);
|
||||
}
|
||||
});
|
||||
trade.setDepositTx(depositTx);
|
||||
} catch (Throwable t) {
|
||||
failed(t);
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ public class SignAndPublishDepositTxAsSeller extends TradeTask {
|
|||
sellerMultiSigAddressEntry.setLockedTradeAmount(Coin.valueOf(sellerInputs.stream().mapToLong(input -> input.value).sum()).subtract(FeePolicy.getFixedTxFeeForTrades()));
|
||||
walletService.saveAddressEntryList();
|
||||
TradingPeer tradingPeer = processModel.tradingPeer;
|
||||
processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(
|
||||
Transaction depositTx = processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(
|
||||
true,
|
||||
contractHash,
|
||||
processModel.getPreparedDepositTx(),
|
||||
|
@ -85,6 +85,7 @@ public class SignAndPublishDepositTxAsSeller extends TradeTask {
|
|||
failed(t);
|
||||
}
|
||||
});
|
||||
trade.setDepositTx(depositTx);
|
||||
} catch (Throwable t) {
|
||||
failed(t);
|
||||
}
|
||||
|
|
50
core/src/test/java/io/bitsquare/alert/AlertTest.java
Normal file
50
core/src/test/java/io/bitsquare/alert/AlertTest.java
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.alert;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class AlertTest {
|
||||
private static final Logger log = LoggerFactory.getLogger(AlertTest.class);
|
||||
|
||||
@Test
|
||||
public void testIsNewVersion() {
|
||||
Alert alert = new Alert(null, true, "0.4.9.9.1");
|
||||
assertTrue(alert.isNewVersion("0.4.9.9"));
|
||||
assertTrue(alert.isNewVersion("0.4.9.8"));
|
||||
assertTrue(alert.isNewVersion("0.4.9"));
|
||||
assertTrue(alert.isNewVersion("0.4.9.9.0"));
|
||||
assertFalse(alert.isNewVersion("0.4.9.9.1"));
|
||||
|
||||
alert = new Alert(null, true, "0.4.9.9.2");
|
||||
assertTrue(alert.isNewVersion("0.4.9.9.1"));
|
||||
assertFalse(alert.isNewVersion("0.4.9.9.2"));
|
||||
assertTrue(alert.isNewVersion("0.4.9.8"));
|
||||
assertTrue(alert.isNewVersion("0.4.9"));
|
||||
|
||||
alert = new Alert(null, true, "0.4.9.9");
|
||||
assertTrue(alert.isNewVersion("0.4.9"));
|
||||
assertTrue(alert.isNewVersion("0.4.9.8"));
|
||||
assertFalse(alert.isNewVersion("0.4.9.9"));
|
||||
}
|
||||
}
|
|
@ -13,16 +13,16 @@ To contribute a patch, the workflow is as follows:
|
|||
Please do not make pull requests to the Master branch but always use the Development branch!
|
||||
|
||||
|
||||
Copyright
|
||||
Workflow for merging code
|
||||
---------
|
||||
|
||||
We are aiming to follow the principles and establish the workflow used at the Bitcoin Core project.
|
||||
Please check out the [Bitcoin Core documentation](https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md) for more info.
|
||||
The full workflow is not used yet as there are not enough dedicated developers, but as soon that situation changes we will move
|
||||
The full workflow is not used yet as there are not that many dedicated developers yet, but as soon that situation changes we will move
|
||||
to a model with ACK/NACK, code reviews and maintainer roles.
|
||||
|
||||
Copyright
|
||||
---------
|
||||
|
||||
By contributing to this repository, you agree to license your work under the AGPL license.
|
||||
Please include the license header into your files.
|
||||
Please include the Bitsquare license header into your files.
|
||||
|
|
|
@ -13,11 +13,13 @@ System requirements
|
|||
The prerequisite for building Bitsquare is installing the Java Development Kit (JDK), version 8u112 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.
|
||||
|
||||
$ sudo apt-get install openjdk-8-jdk maven libopenjfx-java
|
||||
|
||||
### 1. Check the version of Java you currently have installed
|
||||
|
||||
$ java -version
|
||||
|
||||
If `java` is not found, or your version is anything less than `1.8.0_112`, then follow the next steps, otherwise you can skip to step 2:
|
||||
If `java` is not found, or your version is anything less than `1.8.0_121`, then follow the next steps, otherwise you can skip to step 2:
|
||||
|
||||
#### 1.1 Debian based systems (Ubuntu)
|
||||
|
||||
|
|
|
@ -10,12 +10,12 @@ add-apt-repository ppa:webupd8team/java
|
|||
apt-get update
|
||||
apt-get -y install oracle-java8-installer git maven unzip
|
||||
|
||||
# Alternatively you can download the latest jdk and extract it to /usr/lib/jvm/jdk1.8.0_112
|
||||
# Alternatively you can download the latest jdk and extract it to $JAVA_HOME
|
||||
# wget http://download.oracle.com/otn-pub/java/jdk/8u112-b15/jdk-8u112-linux-x64.tar.gz --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie"
|
||||
# If you had an older java version installed set the new java version as default by those commands:
|
||||
apt-get install update-alternatives
|
||||
# update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk1.8.0_112/bin/java 2000
|
||||
# update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/jdk1.8.0_112/bin/javac 2000
|
||||
# update-alternatives --install /usr/bin/java java $JAVA_HOME/bin/java 2000
|
||||
# update-alternatives --install /usr/bin/javac javac $JAVA_HOME/bin/javac 2000
|
||||
# Test with java -version and javac- version if the version is correct. Otherwise check here:
|
||||
# sudo update-alternatives --config java
|
||||
# sudo update-alternatives --config javac
|
||||
|
@ -23,16 +23,15 @@ apt-get install update-alternatives
|
|||
|
||||
echo "Enable unlimited Strength for cryptographic keys"
|
||||
wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jce/8/jce_policy-8.zip
|
||||
apt-get install unzip
|
||||
#apt-get install unzip
|
||||
unzip jce_policy-8.zip
|
||||
cp UnlimitedJCEPolicyJDK8/US_export_policy.jar $JAVA_HOME/jre/lib/security/US_export_policy.jar
|
||||
cp UnlimitedJCEPolicyJDK8/local_policy.jar $JAVA_HOME/jre/lib/security/local_policy.jar
|
||||
sudo cp UnlimitedJCEPolicyJDK8/US_export_policy.jar $JAVA_HOME/jre/lib/security/US_export_policy.jar
|
||||
sudo cp UnlimitedJCEPolicyJDK8/local_policy.jar $JAVA_HOME/jre/lib/security/local_policy.jar
|
||||
|
||||
chmod 777 /usr/lib/jvm/jdk1.8.0_112/jre/lib/security/US_export_policy.jar
|
||||
chmod 777 /usr/lib/jvm/jdk1.8.0_112/jre/lib/security/local_policy.jar
|
||||
sudo chmod 777 $JAVA_HOME/jre/lib/security/US_export_policy.jar
|
||||
sudo chmod 777 $JAVA_HOME/jre/lib/security/local_policy.jar
|
||||
|
||||
rm -r UnlimitedJCEPolicyJDK8
|
||||
rm jce_policy-8.zip
|
||||
rm -r UnlimitedJCEPolicyJDK8 jce_policy-8.zip
|
||||
|
||||
echo "Install bitcoinj"
|
||||
cd ~
|
||||
|
@ -48,6 +47,6 @@ mvn clean package -DskipTests -Dmaven.javadoc.skip=true
|
|||
|
||||
echo "Add BountyCastle.jar"
|
||||
cd ~
|
||||
cp /root/.m2/repository/org/bouncycastle/bcprov-jdk15on/1.53/bcprov-jdk15on-1.53.jar $JAVA_HOME/jre/lib/ext/bcprov-jdk15on-1.53.jar
|
||||
sudo cp .m2/repository/org/bouncycastle/bcprov-jdk15on/1.53/bcprov-jdk15on-1.53.jar $JAVA_HOME/jre/lib/ext/bcprov-jdk15on-1.53.jar
|
||||
|
||||
|
||||
|
|
218
gui/pom.xml
218
gui/pom.xml
|
@ -22,7 +22,7 @@
|
|||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>io.bitsquare</groupId>
|
||||
<version>0.4.9.8</version>
|
||||
<version>0.4.9.9</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -89,24 +89,204 @@
|
|||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- <plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce</id>
|
||||
<configuration>
|
||||
<rules>
|
||||
<DependencyConvergence />
|
||||
</rules>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>-->
|
||||
<!-- Verify the dependency chain: see https://github.com/gary-rowe/BitcoinjEnforcerRules for
|
||||
more information on this.
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.4.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<DependencyConvergence/>
|
||||
<digestRule implementation="uk.co.froot.maven.enforcer.DigestRule">
|
||||
|
||||
<!-- Create a snapshot to build the list of URNs below -->
|
||||
<buildSnapshot>true</buildSnapshot>
|
||||
|
||||
<!-- List of required hashes -->
|
||||
<!-- Format is URN of groupId:artifactId:version:type:classifier:scope:hash -->
|
||||
<!-- classifier is "null" if not present -->
|
||||
<urns>
|
||||
<urn>
|
||||
aopalliance:aopalliance:1.0:jar:null:compile:0235ba8b489512805ac13a8f9ea77a1ca5ebe3e8
|
||||
</urn>
|
||||
<urn>
|
||||
ch.qos.logback:logback-classic:1.1.10:jar:null:compile:56d094f1fd93c2578e8138a83bb036c13abe5898
|
||||
</urn>
|
||||
<urn>
|
||||
ch.qos.logback:logback-core:1.1.10:jar:null:compile:ee683b13d3ca1cdc876cdf8a341c81d04976e1d6
|
||||
</urn>
|
||||
<urn>
|
||||
com.google.code.findbugs:jsr305:3.0.1:jar:null:compile:f7be08ec23c21485b9b5a1cf1654c2ec8c58168d
|
||||
</urn>
|
||||
<urn>
|
||||
com.google.code.gson:gson:2.2.4:jar:null:compile:a60a5e993c98c864010053cb901b7eab25306568
|
||||
</urn>
|
||||
<urn>
|
||||
com.google.guava:guava:18.0:jar:null:compile:cce0823396aa693798f8882e64213b1772032b09
|
||||
</urn>
|
||||
<urn>
|
||||
com.google.inject:guice:3.0:jar:null:compile:9d84f15fe35e2c716a02979fb62f50a29f38aefa
|
||||
</urn>
|
||||
<urn>
|
||||
com.google.protobuf:protobuf-java:2.5.0:jar:null:compile:a10732c76bfacdbd633a7eb0f7968b1059a65dfa
|
||||
</urn>
|
||||
<urn>
|
||||
com.google.zxing:core:2.0:jar:null:compile:001a5b8ccf93ca2fb7c40a94417f8485e3c8b4a6
|
||||
</urn>
|
||||
<urn>
|
||||
com.google.zxing:javase:2.0:jar:null:compile:d6384ed133a5d2ae38b9cdece13a56564f91066e
|
||||
</urn>
|
||||
<urn>
|
||||
com.googlecode.jcsv:jcsv:1.4.0:jar:null:compile:3b2dfd1ff251cdcf4745a7643a966f14d10e2532
|
||||
</urn>
|
||||
<urn>
|
||||
com.lambdaworks:scrypt:1.4.0:jar:null:compile:906506b74f30c8c20bccd9ed4a11112d8941fe87
|
||||
</urn>
|
||||
<urn>
|
||||
com.madgag.spongycastle:core:1.51.0.0:jar:null:compile:0f642963312ea0e615ad65f28adc5a5b3a2a0862
|
||||
</urn>
|
||||
<urn>
|
||||
com.squareup.okhttp:okhttp:2.2.0:jar:null:compile:959c454243581fdf730abfd4f4745441724bcf2c
|
||||
</urn>
|
||||
<urn>
|
||||
com.squareup.okio:okio:1.2.0:jar:null:compile:c0b52915a48fa91b1b94a28d4a2997bac5f524df
|
||||
</urn>
|
||||
<urn>
|
||||
commons-codec:commons-codec:1.9:jar:null:compile:9ce04e34240f674bc72680f8b843b1457383161a
|
||||
</urn>
|
||||
<urn>
|
||||
commons-io:commons-io:2.4:jar:null:compile:b1b6ea3b7e4aa4f492509a4952029cd8e48019ad
|
||||
</urn>
|
||||
<urn>
|
||||
commons-logging:commons-logging:1.1.3:jar:null:compile:f6f66e966c70a83ffbdb6f17a0919eaf7c8aca7f
|
||||
</urn>
|
||||
<urn>
|
||||
de.jensd:fontawesomefx:8.0.0:jar:null:compile:b42d82b8889fb77858d1f17e69dbdc24beb2ad25
|
||||
</urn>
|
||||
<urn>
|
||||
javax.inject:javax.inject:1:jar:null:compile:6975da39a7040257bd51d21a231b76c915872d38
|
||||
</urn>
|
||||
<urn>junit:junit:4.11:jar:null:test:4e031bb61df09069aeb2bffb4019e7a5034a4ee0
|
||||
</urn>
|
||||
<urn>
|
||||
net.bytebuddy:byte-buddy-agent:1.6.5:jar:null:test:1a1e2189a7dcca6e861a4d71ffbda621f74072d6
|
||||
</urn>
|
||||
<urn>
|
||||
net.bytebuddy:byte-buddy:1.6.5:jar:null:test:25cf61dea06b7402a91bd8435af4ecfc0dd5935b
|
||||
</urn>
|
||||
<urn>
|
||||
net.glxn:qrgen:1.3:jar:null:compile:e581726a5bffa3a5d624506ae145acbac3cc4a17
|
||||
</urn>
|
||||
<urn>
|
||||
net.jcip:jcip-annotations:1.0:jar:null:compile:afba4942caaeaf46aab0b976afd57cc7c181467e
|
||||
</urn>
|
||||
<urn>
|
||||
net.sf.jopt-simple:jopt-simple:4.8:jar:null:compile:457ac8fb446301588580604fa877cc56285ff74a
|
||||
</urn>
|
||||
<urn>
|
||||
org.apache.commons:commons-lang3:3.4:jar:null:compile:5fe28b9518e58819180a43a850fbc0dd24b7c050
|
||||
</urn>
|
||||
<urn>
|
||||
org.apache.httpcomponents:httpclient:4.5:jar:null:compile:a1e6cbb3cc2c5f210dd1310ff9fcb2c09c0d1438
|
||||
</urn>
|
||||
<urn>
|
||||
org.apache.httpcomponents:httpcore:4.4.1:jar:null:compile:f5aa318bda4c6c8d688c9d00b90681dcd82ce636
|
||||
</urn>
|
||||
<urn>
|
||||
org.apache.maven.plugins:maven-clean-plugin:2.5:maven-plugin:null:runtime:75653decaefa85ca8114ff3a4f869bb2ee6d605d
|
||||
</urn>
|
||||
<urn>
|
||||
org.apache.maven.plugins:maven-compiler-plugin:3.1:maven-plugin:null:runtime:9977a8d04e75609cf01badc4eb6a9c7198c4c5ea
|
||||
</urn>
|
||||
<urn>
|
||||
org.apache.maven.plugins:maven-deploy-plugin:2.7:maven-plugin:null:runtime:6dadfb75679ca010b41286794f737088ebfe12fd
|
||||
</urn>
|
||||
<urn>
|
||||
org.apache.maven.plugins:maven-enforcer-plugin:RELEASE:maven-plugin:null:runtime:e9bd7df541415bfe587ce082458f9a48bf9b55b4
|
||||
</urn>
|
||||
<urn>
|
||||
org.apache.maven.plugins:maven-install-plugin:2.4:maven-plugin:null:runtime:9d1316166fe4c313f56276935e08df11f45267c2
|
||||
</urn>
|
||||
<urn>
|
||||
org.apache.maven.plugins:maven-jar-plugin:2.4:maven-plugin:null:runtime:e3200bcf357b5c5e26df072d27df160546bb079a
|
||||
</urn>
|
||||
<urn>
|
||||
org.apache.maven.plugins:maven-resources-plugin:2.6:maven-plugin:null:runtime:dd093ff6a4b680eae7ae83b5ab04310249fc6590
|
||||
</urn>
|
||||
<urn>
|
||||
org.apache.maven.plugins:maven-shade-plugin:2.3:maven-plugin:null:runtime:d136adc7abccc9c12adcad6ae7a9bc51b2b7184b
|
||||
</urn>
|
||||
<urn>
|
||||
org.apache.maven.plugins:maven-site-plugin:3.3:maven-plugin:null:runtime:77ba1752b1ac4c4339d6f11554800960a56a4ae1
|
||||
</urn>
|
||||
<urn>
|
||||
org.apache.maven.plugins:maven-surefire-plugin:2.12.4:maven-plugin:null:runtime:2b435f7f77777d2e62354fdc690da3f1dc47a26b
|
||||
</urn>
|
||||
<urn>
|
||||
org.bitcoinj:orchid:1.1.1:jar:null:compile:7898329eae76ec6bfdf27081234bb222d5be09df
|
||||
</urn>
|
||||
<urn>
|
||||
org.bouncycastle:bcprov-jdk15on:1.53:jar:null:compile:9d3def2fa5a0d2ed0c1146e9945df10d29eb4ccb
|
||||
</urn>
|
||||
<urn>
|
||||
org.controlsfx:controlsfx:8.0.6_20:jar:null:compile:5a4ca2765419fe12af0f0c7c5a8129c53bb661d9
|
||||
</urn>
|
||||
<urn>
|
||||
org.fxmisc.easybind:easybind:1.0.3:jar:null:compile:336c8226dfa775c714bc8c3410a1565feffcfb34
|
||||
</urn>
|
||||
<urn>
|
||||
org.hamcrest:hamcrest-core:1.3:jar:null:test:42a25dc3219429f0e5d060061f71acb49bf010a0
|
||||
</urn>
|
||||
<urn>
|
||||
org.jetbrains:annotations:13.0:jar:null:compile:919f0dfe192fb4e063e7dacadee7f8bb9a2672a9
|
||||
</urn>
|
||||
<urn>
|
||||
org.mockito:mockito-core:2.7.5:jar:null:test:24f0d023df553036db3e0cf949d1c4748b84bd69
|
||||
</urn>
|
||||
<urn>
|
||||
org.objenesis:objenesis:2.5:jar:null:test:612ecb799912ccf77cba9b3ed8c813da086076e9
|
||||
</urn>
|
||||
<urn>
|
||||
org.slf4j:slf4j-api:1.7.22:jar:null:compile:a1c83373863cec7ae8d89dc1c5722d8cb6ec0309
|
||||
</urn>
|
||||
<urn>
|
||||
org.springframework:spring-core:4.1.1.RELEASE:jar:null:compile:4b0c607ba83c95ad9ea3defd40c35ae47c5df7d0
|
||||
</urn>
|
||||
<urn>
|
||||
org.springframework:spring-test:4.1.1.RELEASE:jar:null:test:406ce9c05253f7dd75ac3f31170c71cca7419d8a
|
||||
</urn>
|
||||
|
||||
<!-- A check for the rules themselves -->
|
||||
<urn>
|
||||
uk.co.froot.maven.enforcer:digest-enforcer-rules:0.0.1:jar:null:runtime:16a9e04f3fe4bb143c42782d07d5faf65b32106f
|
||||
</urn>
|
||||
|
||||
</urns>
|
||||
</digestRule>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
||||
<!-- Ensure we download the enforcer rules -->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>uk.co.froot.maven.enforcer</groupId>
|
||||
<artifactId>digest-enforcer-rules</artifactId>
|
||||
<version>0.0.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.google.inject.Guice;
|
|||
import com.google.inject.Injector;
|
||||
import io.bitsquare.alert.AlertManager;
|
||||
import io.bitsquare.arbitration.ArbitratorManager;
|
||||
import io.bitsquare.btc.TradeWalletService;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.common.CommonOptionKeys;
|
||||
import io.bitsquare.common.UserThread;
|
||||
|
@ -41,10 +42,7 @@ import io.bitsquare.gui.main.MainView;
|
|||
import io.bitsquare.gui.main.MainViewModel;
|
||||
import io.bitsquare.gui.main.debug.DebugView;
|
||||
import io.bitsquare.gui.main.overlays.popups.Popup;
|
||||
import io.bitsquare.gui.main.overlays.windows.EmptyWalletWindow;
|
||||
import io.bitsquare.gui.main.overlays.windows.FilterWindow;
|
||||
import io.bitsquare.gui.main.overlays.windows.SendAlertMessageWindow;
|
||||
import io.bitsquare.gui.main.overlays.windows.ShowWalletDataWindow;
|
||||
import io.bitsquare.gui.main.overlays.windows.*;
|
||||
import io.bitsquare.gui.util.ImageUtil;
|
||||
import io.bitsquare.p2p.P2PService;
|
||||
import io.bitsquare.storage.Storage;
|
||||
|
@ -129,6 +127,9 @@ public class BitsquareApp extends Application {
|
|||
if (throwable.getCause() != null && throwable.getCause().getCause() != null &&
|
||||
throwable.getCause().getCause() instanceof BlockStoreException) {
|
||||
log.error(throwable.getMessage());
|
||||
} else if (throwable instanceof ClassCastException &&
|
||||
"sun.awt.image.BufImgSurfaceData cannot be cast to sun.java2d.xr.XRSurfaceData".equals(throwable.getMessage())) {
|
||||
log.warn(throwable.getMessage());
|
||||
} else {
|
||||
log.error("Uncaught Exception from thread " + Thread.currentThread().getName());
|
||||
log.error("throwableMessage= " + throwable.getMessage());
|
||||
|
@ -197,27 +198,33 @@ public class BitsquareApp extends Application {
|
|||
stop();
|
||||
});
|
||||
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEvent -> {
|
||||
if (new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
if (new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN).match(keyEvent) || new KeyCodeCombination(KeyCode.W, KeyCombination.CONTROL_DOWN).match(keyEvent)) {
|
||||
stop();
|
||||
} else if (new KeyCodeCombination(KeyCode.Q, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.Q, KeyCombination.SHORTCUT_DOWN).match(keyEvent) || new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN).match(keyEvent)) {
|
||||
stop();
|
||||
} else if (new KeyCodeCombination(KeyCode.E, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.E, KeyCombination.SHORTCUT_DOWN).match(keyEvent) || new KeyCodeCombination(KeyCode.E, KeyCombination.CONTROL_DOWN).match(keyEvent)) {
|
||||
showEmptyWalletPopup();
|
||||
} else if (new KeyCodeCombination(KeyCode.M, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.M, KeyCombination.ALT_DOWN).match(keyEvent)) {
|
||||
showSendAlertMessagePopup();
|
||||
} else if (new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.F, KeyCombination.ALT_DOWN).match(keyEvent)) {
|
||||
showFilterPopup();
|
||||
} else if (new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.F, KeyCombination.ALT_DOWN).match(keyEvent)) {
|
||||
showFPSWindow();
|
||||
} else if (new KeyCodeCombination(KeyCode.J, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.J, KeyCombination.ALT_DOWN).match(keyEvent)) {
|
||||
WalletService walletService = injector.getInstance(WalletService.class);
|
||||
if (walletService.getWallet() != null)
|
||||
new ShowWalletDataWindow(walletService).information("Wallet raw data").show();
|
||||
else
|
||||
new Popup<>().warning("The wallet is not initialized yet").show();
|
||||
} else if (DevFlags.DEV_MODE) {
|
||||
if (new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN).match(keyEvent))
|
||||
showDebugWindow();
|
||||
} else if (new KeyCodeCombination(KeyCode.G, KeyCombination.ALT_DOWN).match(keyEvent)) {
|
||||
TradeWalletService tradeWalletService = injector.getInstance(TradeWalletService.class);
|
||||
WalletService walletService = injector.getInstance(WalletService.class);
|
||||
if (walletService.getWallet() != null)
|
||||
new SpendFromDepositTxWindow(tradeWalletService).information("Emergency wallet tool").show();
|
||||
else
|
||||
new Popup<>().warning("The wallet is not initialized yet").show();
|
||||
} else if (DevFlags.DEV_MODE && new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
showDebugWindow();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -256,9 +263,14 @@ public class BitsquareApp extends Application {
|
|||
|
||||
UserThread.runPeriodically(() -> Profiler.printSystemLoad(log), LOG_MEMORY_PERIOD_MIN, TimeUnit.MINUTES);
|
||||
|
||||
} catch (Throwable throwable) {
|
||||
} catch (
|
||||
Throwable throwable
|
||||
)
|
||||
|
||||
{
|
||||
showErrorPopup(throwable, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void showSendAlertMessagePopup() {
|
||||
|
|
|
@ -119,6 +119,7 @@ public class CryptoCurrencyForm extends PaymentMethodForm {
|
|||
|
||||
@Override
|
||||
public void updateAllInputsValid() {
|
||||
altCoinAddressValidator.setCurrencyCode(cryptoCurrencyAccount.getSelectedTradeCurrency().getCode());
|
||||
allInputsValid.set(isAccountNameValid()
|
||||
&& altCoinAddressValidator.validate(cryptoCurrencyAccount.getAddress()).isValid
|
||||
&& cryptoCurrencyAccount.getSingleTradeCurrency() != null);
|
||||
|
|
|
@ -46,7 +46,7 @@ public class InteracETransferForm extends PaymentMethodForm {
|
|||
|
||||
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
|
||||
addLabelTextField(gridPane, ++gridRow, "Account holder name:", ((InteracETransferAccountContractData) paymentAccountContractData).getHolderName());
|
||||
addLabelTextField(gridPane, ++gridRow, "Email:", ((InteracETransferAccountContractData) paymentAccountContractData).getEmail());
|
||||
addLabelTextField(gridPane, ++gridRow, "Email or mobile nr:", ((InteracETransferAccountContractData) paymentAccountContractData).getEmail());
|
||||
addLabelTextField(gridPane, ++gridRow, "Secret question:", ((InteracETransferAccountContractData) paymentAccountContractData).getQuestion());
|
||||
addLabelTextField(gridPane, ++gridRow, "Answer:", ((InteracETransferAccountContractData) paymentAccountContractData).getAnswer());
|
||||
return gridRow;
|
||||
|
@ -69,7 +69,7 @@ public class InteracETransferForm extends PaymentMethodForm {
|
|||
updateFromInputs();
|
||||
});
|
||||
|
||||
mobileNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Email:").second;
|
||||
mobileNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Email or mobile nr:").second;
|
||||
mobileNrInputTextField.setValidator(interacETransferValidator);
|
||||
mobileNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
|
||||
interacETransferAccount.setEmail(newValue);
|
||||
|
@ -77,14 +77,14 @@ public class InteracETransferForm extends PaymentMethodForm {
|
|||
});
|
||||
|
||||
questionInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Secret question:").second;
|
||||
questionInputTextField.setValidator(interacETransferValidator);
|
||||
questionInputTextField.setValidator(inputValidator);
|
||||
questionInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
|
||||
interacETransferAccount.setQuestion(newValue);
|
||||
updateFromInputs();
|
||||
});
|
||||
|
||||
answerInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Answer:").second;
|
||||
answerInputTextField.setValidator(interacETransferValidator);
|
||||
answerInputTextField.setValidator(inputValidator);
|
||||
answerInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
|
||||
interacETransferAccount.setAnswer(newValue);
|
||||
updateFromInputs();
|
||||
|
|
|
@ -237,8 +237,7 @@ public class MainViewModel implements ViewModel {
|
|||
}
|
||||
|
||||
private void initializeAllServices() {*/
|
||||
|
||||
log.error("initializeAllServices");
|
||||
|
||||
Log.traceCall();
|
||||
|
||||
UserThread.runAfter(tacWindow::showIfNeeded, 2);
|
||||
|
@ -638,6 +637,30 @@ public class MainViewModel implements ViewModel {
|
|||
.show();
|
||||
}
|
||||
});
|
||||
|
||||
checkIfOpenOffersMatchTradeProtocolVersion();
|
||||
}
|
||||
|
||||
private void checkIfOpenOffersMatchTradeProtocolVersion() {
|
||||
List<OpenOffer> outDatedOffers = openOfferManager.getOpenOffers()
|
||||
.stream()
|
||||
.filter(e -> e.getOffer().getProtocolVersion() != Version.TRADE_PROTOCOL_VERSION)
|
||||
.collect(Collectors.toList());
|
||||
if (!outDatedOffers.isEmpty()) {
|
||||
new Popup<>()
|
||||
.warning("You have open offers which have been created with an older version of Bitsquare.\n" +
|
||||
"Please remove those offers as they are not valid anymore.\n\n" +
|
||||
"Offers (ID): " +
|
||||
outDatedOffers.stream()
|
||||
.map(e -> e.getId() + "\n")
|
||||
.collect(Collectors.toList()).toString()
|
||||
.replace("[", "").replace("]", ""))
|
||||
.actionButtonText("Remove outdated offer(s)")
|
||||
.onAction(() -> openOfferManager.removeOpenOffers(outDatedOffers, null))
|
||||
.closeButtonText("Shut down")
|
||||
.onClose(BitsquareApp.shutDownHandler::run)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ public class AccountView extends ActivatableView<TabPane, AccountViewModel> {
|
|||
};
|
||||
|
||||
keyEventEventHandler = event -> {
|
||||
if (new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN).match(event) &&
|
||||
if (new KeyCodeCombination(KeyCode.R, KeyCombination.ALT_DOWN).match(event) &&
|
||||
arbitratorRegistrationTab == null) {
|
||||
arbitratorRegistrationTab = new Tab("Arbitrator registration");
|
||||
arbitratorRegistrationTab.setClosable(false);
|
||||
|
|
|
@ -164,6 +164,16 @@ public class AltCoinAccountsView extends ActivatableViewAndModel<GridPane, AltCo
|
|||
"If you are not sure about that process visit the Monero forum (https://forum.getmonero.org) to find more information.")
|
||||
.closeButtonText("I understand")
|
||||
.show();
|
||||
} else if (code.equals("ZEC")) {
|
||||
new Popup().information("When using ZEC you can only use the transparent addresses (starting with t) not " +
|
||||
"the z-addresses, because the arbitrator would not be able to verify the transaction with z-addresses.")
|
||||
.closeButtonText("I understand")
|
||||
.show();
|
||||
} else if (code.equals("XZC")) {
|
||||
new Popup().information("When using XZC you can only use the transparent transactions not " +
|
||||
"the private transactions, because the arbitrator would not be able to verify the private transactions.")
|
||||
.closeButtonText("I understand")
|
||||
.show();
|
||||
}
|
||||
|
||||
if (!model.getPaymentAccounts().stream().filter(e -> {
|
||||
|
|
|
@ -20,6 +20,7 @@ package io.bitsquare.gui.main.disputes;
|
|||
import io.bitsquare.app.DevFlags;
|
||||
import io.bitsquare.arbitration.Arbitrator;
|
||||
import io.bitsquare.arbitration.ArbitratorManager;
|
||||
import io.bitsquare.arbitration.DisputeManager;
|
||||
import io.bitsquare.common.crypto.KeyRing;
|
||||
import io.bitsquare.gui.Navigation;
|
||||
import io.bitsquare.gui.common.model.Activatable;
|
||||
|
@ -51,6 +52,7 @@ public class DisputesView extends ActivatableViewAndModel<TabPane, Activatable>
|
|||
|
||||
private final Navigation navigation;
|
||||
private final ArbitratorManager arbitratorManager;
|
||||
private DisputeManager disputeManager;
|
||||
private final KeyRing keyRing;
|
||||
private Preferences preferences;
|
||||
|
||||
|
@ -59,14 +61,15 @@ public class DisputesView extends ActivatableViewAndModel<TabPane, Activatable>
|
|||
private Tab currentTab;
|
||||
private final ViewLoader viewLoader;
|
||||
private MapChangeListener<NodeAddress, Arbitrator> arbitratorMapChangeListener;
|
||||
private boolean isArbitrator;
|
||||
|
||||
@Inject
|
||||
public DisputesView(CachingViewLoader viewLoader, Navigation navigation, ArbitratorManager arbitratorManager,
|
||||
public DisputesView(CachingViewLoader viewLoader, Navigation navigation,
|
||||
ArbitratorManager arbitratorManager, DisputeManager disputeManager,
|
||||
KeyRing keyRing, Preferences preferences) {
|
||||
this.viewLoader = viewLoader;
|
||||
this.navigation = navigation;
|
||||
this.arbitratorManager = arbitratorManager;
|
||||
this.disputeManager = disputeManager;
|
||||
this.keyRing = keyRing;
|
||||
|
||||
|
||||
|
@ -92,11 +95,15 @@ public class DisputesView extends ActivatableViewAndModel<TabPane, Activatable>
|
|||
}
|
||||
|
||||
private void updateArbitratorsDisputesTabDisableState() {
|
||||
isArbitrator = arbitratorManager.getArbitratorsObservableMap().values().stream()
|
||||
boolean isActiveArbitrator = arbitratorManager.getArbitratorsObservableMap().values().stream()
|
||||
.filter(e -> e.getPubKeyRing() != null && e.getPubKeyRing().equals(keyRing.getPubKeyRing()))
|
||||
.findAny().isPresent();
|
||||
|
||||
if (arbitratorsDisputesTab == null && isArbitrator) {
|
||||
boolean hasDisputesAsArbitrator = disputeManager.getDisputesAsObservableList().stream()
|
||||
.filter(d -> d.getArbitratorPubKeyRing().equals(keyRing.getPubKeyRing()))
|
||||
.findAny().isPresent();
|
||||
|
||||
if (arbitratorsDisputesTab == null && (isActiveArbitrator || hasDisputesAsArbitrator)) {
|
||||
arbitratorsDisputesTab = new Tab("Arbitrator's support tickets");
|
||||
arbitratorsDisputesTab.setClosable(false);
|
||||
root.getTabs().add(arbitratorsDisputesTab);
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
package io.bitsquare.gui.main.disputes.arbitrator;
|
||||
|
||||
import io.bitsquare.alert.PrivateNotificationManager;
|
||||
import io.bitsquare.arbitration.Dispute;
|
||||
import io.bitsquare.arbitration.DisputeManager;
|
||||
import io.bitsquare.common.crypto.KeyRing;
|
||||
import io.bitsquare.gui.common.view.FxmlView;
|
||||
|
@ -29,7 +28,6 @@ import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow;
|
|||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.p2p.P2PService;
|
||||
import io.bitsquare.trade.TradeManager;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -47,9 +45,27 @@ public class ArbitratorDisputeView extends TraderDisputeView {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void setFilteredListPredicate(FilteredList<Dispute> filteredList) {
|
||||
filteredList.setPredicate(dispute -> dispute.getArbitratorPubKeyRing().equals(keyRing.getPubKeyRing()));
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
|
||||
filterBox.setVisible(true);
|
||||
filterBox.setManaged(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyFilteredListPredicate(String filterString) {
|
||||
// If in arbitrator view we must only display disputes where we are selected as arbitrator (must not receive others anyway)
|
||||
filteredList.setPredicate(dispute ->
|
||||
dispute.getArbitratorPubKeyRing().equals(keyRing.getPubKeyRing()) &&
|
||||
(filterString.isEmpty() ||
|
||||
(dispute.getId().contains(filterString) ||
|
||||
formatter.formatDate(dispute.getOpeningDate()).contains(filterString)) ||
|
||||
getBuyerOnionAddressColumnLabel(dispute).contains(filterString) ||
|
||||
getSellerOnionAddressColumnLabel(dispute).contains(filterString)
|
||||
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.google.common.io.ByteStreams;
|
|||
import de.jensd.fx.fontawesome.AwesomeDude;
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
import io.bitsquare.alert.PrivateNotificationManager;
|
||||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.arbitration.Dispute;
|
||||
import io.bitsquare.arbitration.DisputeManager;
|
||||
import io.bitsquare.arbitration.messages.DisputeCommunicationMessage;
|
||||
|
@ -34,6 +35,7 @@ import io.bitsquare.gui.common.view.ActivatableView;
|
|||
import io.bitsquare.gui.common.view.FxmlView;
|
||||
import io.bitsquare.gui.components.BusyAnimation;
|
||||
import io.bitsquare.gui.components.HyperlinkWithIcon;
|
||||
import io.bitsquare.gui.components.InputTextField;
|
||||
import io.bitsquare.gui.components.TableGroupHeadline;
|
||||
import io.bitsquare.gui.main.overlays.popups.Popup;
|
||||
import io.bitsquare.gui.main.overlays.windows.ContractWindow;
|
||||
|
@ -92,7 +94,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
protected final KeyRing keyRing;
|
||||
private final TradeManager tradeManager;
|
||||
private final Stage stage;
|
||||
private final BSFormatter formatter;
|
||||
protected final BSFormatter formatter;
|
||||
private final DisputeSummaryWindow disputeSummaryWindow;
|
||||
private PrivateNotificationManager privateNotificationManager;
|
||||
private final ContractWindow contractWindow;
|
||||
|
@ -124,6 +126,10 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
private Subscription inputTextAreaTextSubscription;
|
||||
private EventHandler<KeyEvent> keyEventEventHandler;
|
||||
private Scene scene;
|
||||
protected FilteredList<Dispute> filteredList;
|
||||
private InputTextField filterTextField;
|
||||
private ChangeListener<String> filterTextFieldListener;
|
||||
protected HBox filterBox;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -148,10 +154,24 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
public void initialize() {
|
||||
Label label = new Label("Filter list:");
|
||||
HBox.setMargin(label, new Insets(5, 0, 0, 0));
|
||||
filterTextField = new InputTextField();
|
||||
filterTextFieldListener = (observable, oldValue, newValue) -> applyFilteredListPredicate(filterTextField.getText());
|
||||
|
||||
filterBox = new HBox();
|
||||
filterBox.setSpacing(5);
|
||||
filterBox.getChildren().addAll(label, filterTextField);
|
||||
VBox.setVgrow(filterBox, Priority.NEVER);
|
||||
filterBox.setVisible(false);
|
||||
filterBox.setManaged(false);
|
||||
|
||||
tableView = new TableView<>();
|
||||
VBox.setVgrow(tableView, Priority.SOMETIMES);
|
||||
tableView.setMinHeight(150);
|
||||
root.getChildren().add(tableView);
|
||||
|
||||
root.getChildren().addAll(filterBox, tableView);
|
||||
|
||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
Label placeholder = new Label("There are no open tickets");
|
||||
placeholder.setWrapText(true);
|
||||
|
@ -208,7 +228,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
disputeDirectMessageListListener = c -> scrollToBottom();
|
||||
|
||||
keyEventEventHandler = event -> {
|
||||
if (new KeyCodeCombination(KeyCode.L, KeyCombination.SHORTCUT_DOWN).match(event)) {
|
||||
if (new KeyCodeCombination(KeyCode.L, KeyCombination.ALT_DOWN).match(event)) {
|
||||
Map<String, List<Dispute>> map = new HashMap<>();
|
||||
disputeManager.getDisputesAsObservableList().stream().forEach(dispute -> {
|
||||
String tradeId = dispute.getTradeId();
|
||||
|
@ -269,14 +289,14 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
.actionButtonText("Copy")
|
||||
.onAction(() -> Utilities.copyToClipboard(message))
|
||||
.show();
|
||||
} else if (new KeyCodeCombination(KeyCode.U, KeyCombination.SHORTCUT_DOWN).match(event)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.U, KeyCombination.ALT_DOWN).match(event)) {
|
||||
// Hidden shortcut to re-open a dispute. Allow it also for traders not only arbitrator.
|
||||
if (selectedDispute != null) {
|
||||
if (selectedDisputeClosedPropertyListener != null)
|
||||
selectedDispute.isClosedProperty().removeListener(selectedDisputeClosedPropertyListener);
|
||||
selectedDispute.setIsClosed(false);
|
||||
}
|
||||
} else if (new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN).match(event)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.R, KeyCombination.ALT_DOWN).match(event)) {
|
||||
if (selectedDispute != null) {
|
||||
PubKeyRing pubKeyRing = selectedDispute.getTraderPubKeyRing();
|
||||
NodeAddress nodeAddress;
|
||||
|
@ -295,10 +315,11 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
protected void activate() {
|
||||
filterTextField.textProperty().addListener(filterTextFieldListener);
|
||||
disputeManager.cleanupDisputes();
|
||||
|
||||
FilteredList<Dispute> filteredList = new FilteredList<>(disputeManager.getDisputesAsObservableList());
|
||||
setFilteredListPredicate(filteredList);
|
||||
filteredList = new FilteredList<>(disputeManager.getDisputesAsObservableList());
|
||||
applyFilteredListPredicate(filterTextField.getText());
|
||||
|
||||
sortedList = new SortedList<>(filteredList);
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
|
@ -320,6 +341,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
filterTextField.textProperty().removeListener(filterTextFieldListener);
|
||||
sortedList.comparatorProperty().unbind();
|
||||
selectedDisputeSubscription.unsubscribe();
|
||||
removeListenersOnSelectDispute();
|
||||
|
@ -328,7 +350,8 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||
}
|
||||
|
||||
protected void setFilteredListPredicate(FilteredList<Dispute> filteredList) {
|
||||
protected void applyFilteredListPredicate(String filterString) {
|
||||
// If in trader view we must not display arbitrators own disputes as trader (must not happen anyway)
|
||||
filteredList.setPredicate(dispute -> !dispute.getArbitratorPubKeyRing().equals(keyRing.getPubKeyRing()));
|
||||
}
|
||||
|
||||
|
@ -393,8 +416,17 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
}
|
||||
|
||||
private void onCloseDispute(Dispute dispute) {
|
||||
disputeSummaryWindow.onFinalizeDispute(() -> messagesAnchorPane.getChildren().remove(messagesInputBox))
|
||||
.show(dispute);
|
||||
long protocolVersion = dispute.getContract().offer.getProtocolVersion();
|
||||
if (protocolVersion == Version.TRADE_PROTOCOL_VERSION) {
|
||||
disputeSummaryWindow.onFinalizeDispute(() -> messagesAnchorPane.getChildren().remove(messagesInputBox))
|
||||
.show(dispute);
|
||||
} else {
|
||||
new Popup<>()
|
||||
.warning("The offer in that dispute has been created with an older version of Bitsquare.\n" +
|
||||
"You cannot close that dispute with your version of the application.\n\n" +
|
||||
"Please use an older version with protocol version " + protocolVersion)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
private void onRequestUpload() {
|
||||
|
@ -489,7 +521,8 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
messageListView.prefWidthProperty().bind(root.widthProperty());
|
||||
messagesAnchorPane.prefWidthProperty().bind(root.widthProperty());
|
||||
disputeCommunicationMessages.addListener(disputeDirectMessageListListener);
|
||||
selectedDispute.isClosedProperty().addListener(selectedDisputeClosedPropertyListener);
|
||||
if (selectedDispute != null)
|
||||
selectedDispute.isClosedProperty().addListener(selectedDisputeClosedPropertyListener);
|
||||
inputTextAreaTextSubscription = EasyBind.subscribe(inputTextArea.textProperty(), t -> sendButton.setDisable(t.isEmpty()));
|
||||
}
|
||||
}
|
||||
|
@ -497,8 +530,8 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
private void onSelectDispute(Dispute dispute) {
|
||||
removeListenersOnSelectDispute();
|
||||
if (dispute == null) {
|
||||
if (root.getChildren().size() > 1)
|
||||
root.getChildren().remove(1);
|
||||
if (root.getChildren().size() > 2)
|
||||
root.getChildren().remove(2);
|
||||
|
||||
selectedDispute = null;
|
||||
} else if (selectedDispute != dispute) {
|
||||
|
@ -805,9 +838,9 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
}
|
||||
});
|
||||
|
||||
if (root.getChildren().size() > 1)
|
||||
root.getChildren().remove(1);
|
||||
root.getChildren().add(1, messagesAnchorPane);
|
||||
if (root.getChildren().size() > 2)
|
||||
root.getChildren().remove(2);
|
||||
root.getChildren().add(2, messagesAnchorPane);
|
||||
|
||||
scrollToBottom();
|
||||
}
|
||||
|
@ -1022,7 +1055,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
}
|
||||
|
||||
|
||||
private String getBuyerOnionAddressColumnLabel(Dispute item) {
|
||||
protected String getBuyerOnionAddressColumnLabel(Dispute item) {
|
||||
Contract contract = item.getContract();
|
||||
if (contract != null) {
|
||||
NodeAddress buyerNodeAddress = contract.getBuyerNodeAddress();
|
||||
|
@ -1035,7 +1068,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
}
|
||||
}
|
||||
|
||||
private String getSellerOnionAddressColumnLabel(Dispute item) {
|
||||
protected String getSellerOnionAddressColumnLabel(Dispute item) {
|
||||
Contract contract = item.getContract();
|
||||
if (contract != null) {
|
||||
NodeAddress sellerNodeAddress = contract.getSellerNodeAddress();
|
||||
|
|
|
@ -184,9 +184,9 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
};
|
||||
|
||||
keyEventEventHandler = event -> {
|
||||
if (new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN).match(event))
|
||||
if (new KeyCodeCombination(KeyCode.R, KeyCombination.ALT_DOWN).match(event))
|
||||
revertTxColumn.setVisible(!revertTxColumn.isVisible());
|
||||
else if (new KeyCodeCombination(KeyCode.A, KeyCombination.SHORTCUT_DOWN).match(event))
|
||||
else if (new KeyCodeCombination(KeyCode.A, KeyCombination.ALT_DOWN).match(event))
|
||||
showStatisticsPopup();
|
||||
};
|
||||
|
||||
|
|
|
@ -15,14 +15,16 @@ public class SpreadItem {
|
|||
public final int numberOfOffers;
|
||||
@Nullable
|
||||
public final Fiat spread;
|
||||
public final String percentage;
|
||||
public final Coin totalAmount;
|
||||
|
||||
public SpreadItem(String currencyCode, int numberOfBuyOffers, int numberOfSellOffers, int numberOfOffers, @Nullable Fiat spread, Coin totalAmount) {
|
||||
public SpreadItem(String currencyCode, int numberOfBuyOffers, int numberOfSellOffers, int numberOfOffers, @Nullable Fiat spread, String percentage, Coin totalAmount) {
|
||||
this.currencyCode = currencyCode;
|
||||
this.numberOfBuyOffers = numberOfBuyOffers;
|
||||
this.numberOfSellOffers = numberOfSellOffers;
|
||||
this.numberOfOffers = numberOfOffers;
|
||||
this.spread = spread;
|
||||
this.percentage = percentage;
|
||||
this.totalAmount = totalAmount;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -286,7 +286,7 @@ public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewMode
|
|||
super.updateItem(item, empty);
|
||||
if (item != null && !empty) {
|
||||
if (item.spread != null)
|
||||
setText(formatter.formatVolumeWithCode(item.spread));
|
||||
setText(formatter.formatVolumeWithCode(item.spread) + item.percentage);
|
||||
else
|
||||
setText("-");
|
||||
} else {
|
||||
|
|
|
@ -18,9 +18,12 @@
|
|||
package io.bitsquare.gui.main.market.spread;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.btc.pricefeed.MarketPrice;
|
||||
import io.bitsquare.btc.pricefeed.PriceFeedService;
|
||||
import io.bitsquare.gui.common.model.ActivatableViewModel;
|
||||
import io.bitsquare.gui.main.offer.offerbook.OfferBook;
|
||||
import io.bitsquare.gui.main.offer.offerbook.OfferBookListItem;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.trade.offer.Offer;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
|
@ -37,6 +40,8 @@ import java.util.stream.Collectors;
|
|||
class SpreadViewModel extends ActivatableViewModel {
|
||||
|
||||
private final OfferBook offerBook;
|
||||
private PriceFeedService priceFeedService;
|
||||
private BSFormatter formatter;
|
||||
private final ObservableList<OfferBookListItem> offerBookListItems;
|
||||
private final ListChangeListener<OfferBookListItem> listChangeListener;
|
||||
final ObservableList<SpreadItem> spreadItems = FXCollections.observableArrayList();
|
||||
|
@ -47,8 +52,10 @@ class SpreadViewModel extends ActivatableViewModel {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public SpreadViewModel(OfferBook offerBook) {
|
||||
public SpreadViewModel(OfferBook offerBook, PriceFeedService priceFeedService, BSFormatter formatter) {
|
||||
this.offerBook = offerBook;
|
||||
this.priceFeedService = priceFeedService;
|
||||
this.formatter = formatter;
|
||||
|
||||
offerBookListItems = offerBook.getOfferBookListItems();
|
||||
listChangeListener = c -> update(offerBookListItems);
|
||||
|
@ -108,8 +115,16 @@ class SpreadViewModel extends ActivatableViewModel {
|
|||
if (bestBuyOfferPrice != null && bestSellOfferPrice != null)
|
||||
spread = bestSellOfferPrice.subtract(bestBuyOfferPrice);
|
||||
|
||||
String percentage = "";
|
||||
MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode);
|
||||
if (spread != null && marketPrice != null) {
|
||||
double marketPriceAsDouble = marketPrice.getPrice(PriceFeedService.Type.LAST);
|
||||
double result = ((double) spread.value / 10000) / marketPriceAsDouble;
|
||||
percentage = " (" + formatter.formatPercentagePrice(result) + ")";
|
||||
}
|
||||
|
||||
Coin totalAmount = Coin.valueOf(offers.stream().mapToLong(offer -> offer.getAmount().getValue()).sum());
|
||||
spreadItems.add(new SpreadItem(currencyCode, buyOffers.size(), sellOffers.size(), offers.size(), spread, totalAmount));
|
||||
spreadItems.add(new SpreadItem(currencyCode, buyOffers.size(), sellOffers.size(), offers.size(), spread, percentage, totalAmount));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package io.bitsquare.gui.main.offer.createoffer;
|
|||
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.app.DevFlags;
|
||||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.arbitration.Arbitrator;
|
||||
import io.bitsquare.btc.AddressEntry;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
|
@ -28,6 +29,7 @@ import io.bitsquare.btc.blockchain.BlockchainService;
|
|||
import io.bitsquare.btc.listeners.BalanceListener;
|
||||
import io.bitsquare.btc.pricefeed.PriceFeedService;
|
||||
import io.bitsquare.common.crypto.KeyRing;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.gui.Navigation;
|
||||
import io.bitsquare.gui.common.model.ActivatableDataModel;
|
||||
import io.bitsquare.gui.main.offer.createoffer.monetary.Price;
|
||||
|
@ -137,10 +139,10 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
|||
this.blockchainService = blockchainService;
|
||||
this.formatter = formatter;
|
||||
|
||||
// isMainNet.set(preferences.getBitcoinNetwork() == BitcoinNetwork.MAINNET);
|
||||
|
||||
offerId = UUID.randomUUID().toString();
|
||||
shortOfferId = offerId.substring(0, Math.min(8, offerId.length()));
|
||||
offerId = Utilities.getRandomPrefix(5, 8) + "-" +
|
||||
UUID.randomUUID().toString() + "-" +
|
||||
Version.VERSION.replace(".", "");
|
||||
shortOfferId = Utilities.getShortId(offerId);
|
||||
addressEntry = walletService.getOrCreateAddressEntry(offerId, AddressEntry.Context.OFFER_FUNDING);
|
||||
offerFeeAsCoin = FeePolicy.getCreateOfferFee();
|
||||
networkFeeAsCoin = FeePolicy.getFixedTxFeeForTrades();
|
||||
|
|
|
@ -160,7 +160,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
|||
UserThread.runAfter(() -> {
|
||||
amount.set("1");
|
||||
minAmount.set(amount.get());
|
||||
price.set("700");
|
||||
price.set("1000");
|
||||
|
||||
setAmountToModel();
|
||||
setMinAmountToModel();
|
||||
|
|
|
@ -147,7 +147,7 @@ public class PeerInfoWithTagEditor extends Overlay<PeerInfoWithTagEditor> {
|
|||
inputTextField.setText(tag);
|
||||
|
||||
keyEventEventHandler = event -> {
|
||||
if (new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN).match(event)) {
|
||||
if (new KeyCodeCombination(KeyCode.R, KeyCombination.ALT_DOWN).match(event)) {
|
||||
new SendPrivateNotificationWindow(offer.getPubKeyRing(), offer.getOffererNodeAddress())
|
||||
.onAddAlertMessage(privateNotificationManager::sendPrivateNotificationMessageIfKeyIsValid)
|
||||
.show();
|
||||
|
|
|
@ -177,7 +177,10 @@ public class ContractWindow extends Overlay<ContractWindow> {
|
|||
viewContractButton.setDefaultButton(false);
|
||||
viewContractButton.setOnAction(e -> {
|
||||
TextArea textArea = new TextArea();
|
||||
textArea.setText(dispute.getContractAsJson());
|
||||
String contractAsJson = dispute.getContractAsJson();
|
||||
contractAsJson += "\n\nBuyerPubKeyHex: " + Utils.HEX.encode(dispute.getContract().getBuyerBtcPubKey());
|
||||
contractAsJson += "\nSellerPubKeyHex: " + Utils.HEX.encode(dispute.getContract().getSellerBtcPubKey());
|
||||
textArea.setText(contractAsJson);
|
||||
textArea.setPrefHeight(50);
|
||||
textArea.setEditable(false);
|
||||
textArea.setWrapText(true);
|
||||
|
|
|
@ -598,7 +598,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
byte[] sellerPubKey,
|
||||
byte[] arbitratorPubKey)
|
||||
*/
|
||||
byte[] arbitratorSignature = tradeWalletService.signDisputedPayoutTx(
|
||||
byte[] arbitratorSignature = tradeWalletService.arbitratorSignsDisputedPayoutTx(
|
||||
dispute.getDepositTxSerialized(),
|
||||
disputeResult.getBuyerPayoutAmount(),
|
||||
disputeResult.getSellerPayoutAmount(),
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.gui.main.overlays.windows;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import io.bitsquare.btc.TradeWalletService;
|
||||
import io.bitsquare.btc.exceptions.TransactionVerificationException;
|
||||
import io.bitsquare.btc.exceptions.WalletException;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.gui.components.InputTextField;
|
||||
import io.bitsquare.gui.main.overlays.Overlay;
|
||||
import io.bitsquare.gui.main.overlays.popups.Popup;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import org.bitcoinj.core.AddressFormatException;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static io.bitsquare.gui.util.FormBuilder.addLabelInputTextField;
|
||||
|
||||
public class SpendFromDepositTxWindow extends Overlay<SpendFromDepositTxWindow> {
|
||||
private static final Logger log = LoggerFactory.getLogger(SpendFromDepositTxWindow.class);
|
||||
private TradeWalletService tradeWalletService;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public SpendFromDepositTxWindow(TradeWalletService tradeWalletService) {
|
||||
this.tradeWalletService = tradeWalletService;
|
||||
type = Type.Attention;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (headLine == null)
|
||||
headLine = "Emergency MS payout tool";
|
||||
|
||||
width = 1000;
|
||||
createGridPane();
|
||||
addHeadLine();
|
||||
addSeparator();
|
||||
addContent();
|
||||
addCloseButton();
|
||||
applyStyles();
|
||||
display();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
protected void setupKeyHandler(Scene scene) {
|
||||
if (!hideCloseButton) {
|
||||
scene.setOnKeyPressed(e -> {
|
||||
if (e.getCode() == KeyCode.ESCAPE) {
|
||||
e.consume();
|
||||
doClose();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void addContent() {
|
||||
InputTextField depositTxHex = addLabelInputTextField(gridPane, ++rowIndex, "depositTxHex:").second;
|
||||
|
||||
InputTextField buyerPayoutAmount = addLabelInputTextField(gridPane, ++rowIndex, "buyerPayoutAmount:").second;
|
||||
InputTextField sellerPayoutAmount = addLabelInputTextField(gridPane, ++rowIndex, "sellerPayoutAmount:").second;
|
||||
InputTextField arbitratorPayoutAmount = addLabelInputTextField(gridPane, ++rowIndex, "arbitratorPayoutAmount:").second;
|
||||
|
||||
InputTextField buyerAddressString = addLabelInputTextField(gridPane, ++rowIndex, "buyerAddressString:").second;
|
||||
InputTextField sellerAddressString = addLabelInputTextField(gridPane, ++rowIndex, "sellerAddressString:").second;
|
||||
InputTextField arbitratorAddressString = addLabelInputTextField(gridPane, ++rowIndex, "arbitratorAddressString:").second;
|
||||
|
||||
InputTextField buyerPrivateKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "buyerPrivateKeyAsHex:").second;
|
||||
InputTextField sellerPrivateKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "sellerPrivateKeyAsHex:").second;
|
||||
InputTextField arbitratorPrivateKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "arbitratorPrivateKeyAsHex:").second;
|
||||
|
||||
InputTextField buyerPubKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "buyerPubKeyAsHex:").second;
|
||||
InputTextField sellerPubKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "sellerPubKeyAsHex:").second;
|
||||
InputTextField arbitratorPubKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "arbitratorPubKeyAsHex:").second;
|
||||
|
||||
InputTextField P2SHMultiSigOutputScript = addLabelInputTextField(gridPane, ++rowIndex, "P2SHMultiSigOutputScript:").second;
|
||||
InputTextField buyerPubKeysInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "buyerPubKeys:").second;
|
||||
InputTextField sellerPubKeysInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "sellerPubKeys:").second;
|
||||
|
||||
List<String> buyerPubKeys = !buyerPubKeysInputTextField.getText().isEmpty() ? Arrays.asList(buyerPubKeysInputTextField.getText().split(",")) : new ArrayList<>();
|
||||
List<String> sellerPubKeys = !sellerPubKeysInputTextField.getText().isEmpty() ? Arrays.asList(sellerPubKeysInputTextField.getText().split(",")) : new ArrayList<>();
|
||||
|
||||
|
||||
// Notes:
|
||||
// Open with alt+g and enable DEV mode
|
||||
// Priv key is only visible if pw protection is removed (wallet details data (alt+j))
|
||||
// Take P2SHMultiSigOutputScript from depositTx in blockexplorer
|
||||
// Take missing buyerPubKeyAsHex and sellerPubKeyAsHex from contract data!
|
||||
// Lookup sellerPrivateKeyAsHex associated with sellerPubKeyAsHex (or buyers) in wallet details data
|
||||
// sellerPubKeys/buyerPubKeys are auto generated if used the fields below
|
||||
// Never set the priv arbitr. key here!
|
||||
|
||||
depositTxHex.setText("");
|
||||
|
||||
buyerPayoutAmount.setText("0.51");
|
||||
sellerPayoutAmount.setText("0.01");
|
||||
arbitratorPayoutAmount.setText("0");
|
||||
|
||||
buyerAddressString.setText("");
|
||||
buyerPubKeyAsHex.setText("");
|
||||
buyerPrivateKeyAsHex.setText("");
|
||||
|
||||
sellerAddressString.setText("");
|
||||
sellerPubKeyAsHex.setText("");
|
||||
sellerPrivateKeyAsHex.setText("");
|
||||
|
||||
//4.9
|
||||
// arbitratorAddressString.setText("19xdeiQM2Hn2M2wbpT5imcYWzqhiSDHPy4");
|
||||
// arbitratorPubKeyAsHex.setText("02c62e794fe67f3a2115e2de4757143ff7f27bdf38aa4ae58a3595baa6d676875b");
|
||||
|
||||
// 4.2
|
||||
arbitratorAddressString.setText("1FdFzBazmHQxbUbdCUJwuCtR37DrZrEobu");
|
||||
arbitratorPubKeyAsHex.setText("030fdc2ebc297df4047442f6079f1ce3b7d1938a41f88bd11497545cc94fcfd315");
|
||||
|
||||
P2SHMultiSigOutputScript.setText("");
|
||||
|
||||
sellerPubKeys = Arrays.asList();
|
||||
|
||||
buyerPubKeys = Arrays.asList();
|
||||
|
||||
|
||||
actionButtonText("Sign and publish transaction");
|
||||
|
||||
final List<String> finalSellerPubKeys = sellerPubKeys;
|
||||
final List<String> finalBuyerPubKeys = buyerPubKeys;
|
||||
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Transaction result) {
|
||||
log.error("onSuccess");
|
||||
UserThread.execute(() -> {
|
||||
String txId = result != null ? result.getHashAsString() : "null";
|
||||
new Popup<>()
|
||||
.information("Transaction successful published. Transaction ID: " + txId)
|
||||
.show();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
log.error(t.toString());
|
||||
log.error("onFailure");
|
||||
UserThread.execute(() -> new Popup<>().warning(t.toString()).show());
|
||||
}
|
||||
};
|
||||
onAction(() -> {
|
||||
try {
|
||||
tradeWalletService.emergencySignAndPublishPayoutTx(depositTxHex.getText(),
|
||||
Coin.parseCoin(buyerPayoutAmount.getText()),
|
||||
Coin.parseCoin(sellerPayoutAmount.getText()),
|
||||
Coin.parseCoin(arbitratorPayoutAmount.getText()),
|
||||
buyerAddressString.getText(),
|
||||
sellerAddressString.getText(),
|
||||
arbitratorAddressString.getText(),
|
||||
buyerPrivateKeyAsHex.getText(),
|
||||
sellerPrivateKeyAsHex.getText(),
|
||||
arbitratorPrivateKeyAsHex.getText(),
|
||||
buyerPubKeyAsHex.getText(),
|
||||
sellerPubKeyAsHex.getText(),
|
||||
arbitratorPubKeyAsHex.getText(),
|
||||
P2SHMultiSigOutputScript.getText(),
|
||||
finalBuyerPubKeys,
|
||||
finalSellerPubKeys,
|
||||
callback);
|
||||
} catch (AddressFormatException | WalletException | TransactionVerificationException e) {
|
||||
log.error(e.toString());
|
||||
e.printStackTrace();
|
||||
UserThread.execute(() -> new Popup<>().warning(e.toString()).show());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addCloseButton() {
|
||||
super.addCloseButton();
|
||||
actionButton.setOnAction(event -> actionHandlerOptional.ifPresent(Runnable::run));
|
||||
}
|
||||
}
|
|
@ -252,7 +252,7 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
|||
}
|
||||
|
||||
public String getReference() {
|
||||
return getOffer() != null ? getOffer().getReferenceText() : "";
|
||||
return getOffer() != null ? getOffer().getShortId() : "";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
|
||||
// we use a hidden emergency shortcut to open support ticket
|
||||
keyEventEventHandler = event -> {
|
||||
if (new KeyCodeCombination(KeyCode.O, KeyCombination.SHORTCUT_DOWN).match(event)) {
|
||||
if (new KeyCodeCombination(KeyCode.O, KeyCombination.SHORTCUT_DOWN).match(event) || new KeyCodeCombination(KeyCode.O, KeyCombination.CONTROL_DOWN).match(event)) {
|
||||
Popup popup = new Popup();
|
||||
popup.headLine("Open support ticket")
|
||||
.message("Please use that only in emergency case if you don't get displayed a \"Open support\" or \"Open dispute\" button.\n\n" +
|
||||
|
|
|
@ -206,7 +206,7 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
|
|||
peerList.stream().forEach(e -> {
|
||||
if (bitcoinPeersTextArea.getText().length() > 0)
|
||||
bitcoinPeersTextArea.appendText("\n");
|
||||
bitcoinPeersTextArea.appendText(e.getAddress().getSocketAddress().toString());
|
||||
bitcoinPeersTextArea.appendText(e.toString());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -294,10 +294,10 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Activatab
|
|||
deviationListener = (observable, oldValue, newValue) -> {
|
||||
try {
|
||||
double value = formatter.parsePercentStringToDouble(newValue);
|
||||
if (value <= 0.2) {
|
||||
if (value <= 0.3) {
|
||||
preferences.setMaxPriceDistanceInPercent(value);
|
||||
} else {
|
||||
new Popup().warning("Amounts larger than 20 % are not allowed.").show();
|
||||
new Popup().warning("Values higher than 30 % are not allowed.").show();
|
||||
UserThread.runAfter(() -> deviationInputTextField.setText(formatter.formatPercentagePrice(preferences.getMaxPriceDistanceInPercent())), 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
} catch (NumberFormatException t) {
|
||||
|
|
|
@ -76,7 +76,7 @@ public class GUIUtil {
|
|||
new Popup<>().information("Please be sure that the mining fee used at your external wallet is " +
|
||||
"sufficiently high so that the funding transaction will be accepted by the miners.\n" +
|
||||
"Otherwise the trade transactions cannot be confirmed and a trade would end up in a dispute.\n\n" +
|
||||
"The recommended fee is about 50 Satoshi/Byte which is for an average transaction about 0.0002 BTC.\n\n" +
|
||||
"The recommended fee is about 120 Satoshi/Byte which is for an average transaction about 0.0005 BTC.\n\n" +
|
||||
"You can view typically used fees at: https://tradeblock.com/blockchain")
|
||||
.dontShowAgainId(key, Preferences.INSTANCE)
|
||||
.onClose(runnable::run)
|
||||
|
@ -87,7 +87,6 @@ public class GUIUtil {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static void exportAccounts(ArrayList<PaymentAccount> accounts, String fileName, Preferences preferences, Stage stage) {
|
||||
if (!accounts.isEmpty()) {
|
||||
String directory = getDirectoryFormChooser(preferences, stage);
|
||||
|
|
|
@ -20,6 +20,7 @@ package io.bitsquare.gui.util.validation;
|
|||
|
||||
import io.bitsquare.locale.BSResources;
|
||||
import io.bitsquare.locale.BankUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public final class AccountNrValidator extends BankValidator {
|
||||
public AccountNrValidator(String countryCode) {
|
||||
|
@ -75,12 +76,58 @@ public final class AccountNrValidator extends BankValidator {
|
|||
return super.validate(input);
|
||||
else
|
||||
return new ValidationResult(false, "Account number must be of format: 005-231289-112");
|
||||
case "NO":
|
||||
if (input != null) {
|
||||
length = 11;
|
||||
// Provided by sturles:
|
||||
// https://github.com/bitsquare/bitsquare/pull/707
|
||||
|
||||
// https://no.wikipedia.org/wiki/MOD11#Implementasjoner_i_forskjellige_programmeringspr.C3.A5k
|
||||
// https://en.wikipedia.org/wiki/International_Bank_Account_Number#Generating_IBAN_check_digits6
|
||||
|
||||
// 11 digits, last digit is checksum. Checksum algoritm is
|
||||
// MOD11 with weights 2,3,4,5,6,7,2,3,4,5 right to left.
|
||||
// First remove whitespace and periods. Normal formatting is:
|
||||
// 1234.56.78903
|
||||
input2 = StringUtils.remove(input, " ");
|
||||
input2 = StringUtils.remove(input2, ".");
|
||||
// 11 digits, numbers only
|
||||
if (input2.length() != length || !StringUtils.isNumeric(input2))
|
||||
return new ValidationResult(false, BSResources.get("validation.sortCodeNumber", getLabel(), length));
|
||||
int lastDigit = Character.getNumericValue(input2.charAt(input2.length() - 1));
|
||||
if (getMod11ControlDigit(input2) != lastDigit)
|
||||
return new ValidationResult(false, "Kontonummer har feil sjekksum");
|
||||
else
|
||||
return super.validate(input);
|
||||
} else {
|
||||
return super.validate(input);
|
||||
}
|
||||
default:
|
||||
return super.validate(input);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private int getMod11ControlDigit(String accountNrString) {
|
||||
int sumForMod = 0;
|
||||
int controlNumber = 2;
|
||||
char[] accountNr = accountNrString.toCharArray();
|
||||
|
||||
for (int i = accountNr.length - 2; i >= 0; i--) {
|
||||
sumForMod += (Character.getNumericValue(accountNr[i]) * controlNumber);
|
||||
controlNumber++;
|
||||
|
||||
if (controlNumber > 7) {
|
||||
controlNumber = 2;
|
||||
}
|
||||
}
|
||||
int calculus = (11 - sumForMod % 11);
|
||||
if (calculus == 11) {
|
||||
return 0;
|
||||
} else {
|
||||
return calculus;
|
||||
}
|
||||
}
|
||||
|
||||
private String getLabel() {
|
||||
String label = BankUtil.getAccountNrLabel(countryCode);
|
||||
|
|
|
@ -18,16 +18,129 @@
|
|||
package io.bitsquare.gui.util.validation;
|
||||
|
||||
|
||||
import io.bitsquare.gui.util.validation.altcoins.ByteballAddressValidator;
|
||||
import io.bitsquare.gui.util.validation.params.IOPParams;
|
||||
import io.bitsquare.gui.util.validation.params.PivxParams;
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.AddressFormatException;
|
||||
import org.bitcoinj.params.MainNetParams;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public final class AltCoinAddressValidator extends InputValidator {
|
||||
private static final Logger log = LoggerFactory.getLogger(AltCoinAddressValidator.class);
|
||||
|
||||
private String currencyCode;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setCurrencyCode(String currencyCode) {
|
||||
this.currencyCode = currencyCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validate(String input) {
|
||||
ValidationResult validationResult = super.validate(input);
|
||||
if (!validationResult.isValid || currencyCode == null) {
|
||||
return validationResult;
|
||||
} else {
|
||||
|
||||
// Validation:
|
||||
// 1: With a regex checking the correct structure of an address
|
||||
// 2: If the address contains a checksum, verify the checksum
|
||||
|
||||
ValidationResult wrongChecksum = new ValidationResult(false, "Address validation failed because checksum was not correct.");
|
||||
ValidationResult regexTestFailed = new ValidationResult(false, "Address validation failed because it does not match the structure of a " + currencyCode + " address.");
|
||||
|
||||
switch (currencyCode) {
|
||||
// Example for BTC, though for BTC we use the BitcoinJ library address check
|
||||
case "BTC":
|
||||
// taken form: https://stackoverflow.com/questions/21683680/regex-to-match-bitcoin-addresses
|
||||
if (input.matches("^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$")) {
|
||||
if (verifyChecksum(input))
|
||||
try {
|
||||
new Address(MainNetParams.get(), input);
|
||||
return new ValidationResult(true);
|
||||
} catch (AddressFormatException e) {
|
||||
return new ValidationResult(false, getErrorMessage(e));
|
||||
}
|
||||
else
|
||||
return wrongChecksum;
|
||||
} else {
|
||||
return regexTestFailed;
|
||||
}
|
||||
case "PIVX":
|
||||
if (input.matches("^[D][a-km-zA-HJ-NP-Z1-9]{25,34}$")) {
|
||||
if (verifyChecksum(input)) {
|
||||
try {
|
||||
new Address(PivxParams.get(), input);
|
||||
return new ValidationResult(true);
|
||||
} catch (AddressFormatException e) {
|
||||
return new ValidationResult(false, getErrorMessage(e));
|
||||
}
|
||||
} else {
|
||||
return wrongChecksum;
|
||||
}
|
||||
} else {
|
||||
return regexTestFailed;
|
||||
}
|
||||
case "IOP":
|
||||
if (input.matches("^[p][a-km-zA-HJ-NP-Z1-9]{25,34}$")) {
|
||||
if (verifyChecksum(input)) {
|
||||
try {
|
||||
new Address(IOPParams.get(), input);
|
||||
return new ValidationResult(true);
|
||||
} catch (AddressFormatException e) {
|
||||
return new ValidationResult(false, getErrorMessage(e));
|
||||
}
|
||||
} else {
|
||||
return wrongChecksum;
|
||||
}
|
||||
} else {
|
||||
return regexTestFailed;
|
||||
}
|
||||
case "ZEC":
|
||||
// We only support t addresses (transparent transactions)
|
||||
if (input.startsWith("t"))
|
||||
return validationResult;
|
||||
else
|
||||
return new ValidationResult(false, "ZEC address need to start with t. Addresses starting with z are not supported.");
|
||||
|
||||
// TODO test not successful
|
||||
/*case "XTO":
|
||||
if (input.matches("^[T2][a-km-zA-HJ-NP-Z1-9]{25,34}$")) {
|
||||
if (verifyChecksum(input))
|
||||
try {
|
||||
new Address(MainNetParams.get(), input);
|
||||
return new ValidationResult(true);
|
||||
} catch (AddressFormatException e) {
|
||||
return new ValidationResult(false, getErrorMessage(e));
|
||||
}
|
||||
else
|
||||
return wrongChecksum;
|
||||
} else {
|
||||
return regexTestFailed;
|
||||
}*/
|
||||
case "GBYTE":
|
||||
return ByteballAddressValidator.validate(input);
|
||||
default:
|
||||
log.debug("Validation for AltCoinAddress not implemented yet. currencyCode:" + currencyCode);
|
||||
return validationResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getErrorMessage(AddressFormatException e) {
|
||||
return "Address is not a valid " + currencyCode + " address! " + e.getMessage();
|
||||
}
|
||||
|
||||
private boolean verifyChecksum(String input) {
|
||||
// TODO
|
||||
return super.validate(input);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,24 @@
|
|||
|
||||
package io.bitsquare.gui.util.validation;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/*
|
||||
* BIC information taken from German wikipedia (2017-01-30)
|
||||
*
|
||||
* length 8 or 11 characters
|
||||
* General format: BBBB CC LL (bbb)
|
||||
* with B - Bank code
|
||||
* C - Country code
|
||||
* L - Location code
|
||||
* b - branch code (if applicable)
|
||||
*
|
||||
* B and C must be letters
|
||||
* first L cannot be 0 or 1, second L cannot be O (upper case 'o')
|
||||
* bbb cannot begin with X, unless it is XXX
|
||||
*/
|
||||
|
||||
// TODO Special letters like ä, å, ... are not detected as invalid
|
||||
|
||||
public final class BICValidator extends InputValidator {
|
||||
|
||||
|
@ -29,8 +47,34 @@ public final class BICValidator extends InputValidator {
|
|||
// TODO Add validation for primary and secondary IDs according to the selected type
|
||||
|
||||
// IBAN max 34 chars
|
||||
// bic: max 11 char
|
||||
return super.validate(input);
|
||||
// bic: 8 or 11 chars
|
||||
|
||||
// check ensure length 8 or 11
|
||||
if (!isStringWithFixedLength(input,8) && !isStringWithFixedLength(input,11))
|
||||
return new ValidationResult(false, "Input length is neither 8 nor 11");
|
||||
|
||||
input = input.toUpperCase(Locale.ROOT);
|
||||
|
||||
// ensure Bank and Contry code to be letters only
|
||||
for (int k=0; k<6; k++) {
|
||||
if (!Character.isLetter(input.charAt(k)))
|
||||
return new ValidationResult(false, "Bank and Country code must be letters");
|
||||
}
|
||||
|
||||
// ensure location code starts not with 0 or 1 and ends not with O
|
||||
char ch = input.charAt(6);
|
||||
if (ch == '0' || ch == '1' || input.charAt(7) == 'O')
|
||||
return new ValidationResult(false, "BIC contains invalid location code");
|
||||
|
||||
// check complete for 8 char BIC
|
||||
if (input.length() == 8)
|
||||
return new ValidationResult(true);
|
||||
|
||||
// ensure branch code does not start with X unless it is XXX
|
||||
if (input.charAt(8) == 'X')
|
||||
if (input.charAt(9) != 'X' || input.charAt(10) != 'X')
|
||||
return new ValidationResult(false, "BIC contains invalid branch code");
|
||||
return new ValidationResult(true);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,23 +17,22 @@
|
|||
|
||||
package io.bitsquare.gui.util.validation;
|
||||
|
||||
|
||||
public final class ChaseQuickPayValidator extends InputValidator {
|
||||
|
||||
private final EmailValidator emailValidator;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public ValidationResult validate(String input) {
|
||||
// TODO
|
||||
return super.validate(input);
|
||||
public ChaseQuickPayValidator() {
|
||||
super();
|
||||
emailValidator = new EmailValidator();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public ValidationResult validate(String input) {
|
||||
return emailValidator.validate(input);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,22 @@
|
|||
|
||||
package io.bitsquare.gui.util.validation;
|
||||
|
||||
/*
|
||||
* Mail addresses consist of localPart @ domainPart
|
||||
*
|
||||
* Local part:
|
||||
* May contain lots of symbols A-Za-z0-9.!#$%&'*+-/=?^_`{|}~
|
||||
* but cannot begin or end with a dot (.)
|
||||
* between double quotes many more symbols are allowed:
|
||||
* "(),:;<>@[\] (ASCII: 32, 34, 40, 41, 44, 58, 59, 60, 62, 64, 91–93)
|
||||
*
|
||||
* Domain part:
|
||||
* Consists of name dot TLD
|
||||
* name can but usually doesn't (compatibility reasons) contain non-ASCII
|
||||
* symbols.
|
||||
* TLD is at least two letters long
|
||||
*
|
||||
*/
|
||||
|
||||
public final class EmailValidator extends InputValidator {
|
||||
|
||||
|
@ -24,10 +40,49 @@ public final class EmailValidator extends InputValidator {
|
|||
// Public methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private final ValidationResult invalidAddress = new ValidationResult(false, "Invalid address");
|
||||
|
||||
@Override
|
||||
public ValidationResult validate(String input) {
|
||||
// TODO
|
||||
return super.validate(input);
|
||||
if (input == null || input.length() < 6) // shortest address is l@d.cc
|
||||
return invalidAddress;
|
||||
String[] subStrings;
|
||||
String local, domain;
|
||||
|
||||
subStrings = input.split("@", -1);
|
||||
|
||||
if (subStrings.length == 1) // address does not contain '@'
|
||||
return invalidAddress;
|
||||
if (subStrings.length > 2) // multiple @'s included -> check for valid double quotes
|
||||
if (!checkForValidQuotes(subStrings)) // around @'s -> "..@..@.." and concatenate local part
|
||||
return invalidAddress;
|
||||
local = subStrings[0];
|
||||
domain = subStrings[subStrings.length - 1];
|
||||
|
||||
if (local.isEmpty())
|
||||
return invalidAddress;
|
||||
|
||||
// local part cannot begin or end with '.'
|
||||
if (local.startsWith(".") || local.endsWith("."))
|
||||
return invalidAddress;
|
||||
|
||||
String[] splitDomain = domain.split("\\.", -1); // '.' is a regex in java and has to be escaped
|
||||
String tld = splitDomain[splitDomain.length - 1];
|
||||
if (splitDomain.length < 2)
|
||||
return invalidAddress;
|
||||
|
||||
if (splitDomain[0] == null || splitDomain[0].isEmpty())
|
||||
return invalidAddress;
|
||||
|
||||
// TLD length is at least two
|
||||
if (tld.length() < 2)
|
||||
return invalidAddress;
|
||||
|
||||
// TLD is letters only
|
||||
for (int k = 0; k < tld.length(); k++)
|
||||
if (!Character.isLetter(tld.charAt(k)))
|
||||
return invalidAddress;
|
||||
return new ValidationResult(true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,5 +90,22 @@ public final class EmailValidator extends InputValidator {
|
|||
// Private methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private boolean checkForValidQuotes(String[] subStrings) {
|
||||
int length = subStrings.length - 2; // is index on last substring of local part
|
||||
|
||||
// check for odd number of double quotes before first and after last '@'
|
||||
if ((subStrings[0].split("\"", -1).length % 2 == 1) || (subStrings[length].split("\"", -1).length % 2 == 1))
|
||||
return false;
|
||||
for (int k = 1; k < length; k++) {
|
||||
if (subStrings[k].split("\"", -1).length % 2 == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
String patchLocal = "";
|
||||
for (int k = 0; k <= length; k++) // remember: length is last index not array length
|
||||
patchLocal = patchLocal.concat(subStrings[k]); // @'s are not reinstalled, since not needed for further checks
|
||||
subStrings[0] = patchLocal;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,11 @@
|
|||
|
||||
package io.bitsquare.gui.util.validation;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
// TODO Does not yet recognize special letters like ä, ö, ü, å, ... as invalid characters
|
||||
|
||||
public final class IBANValidator extends InputValidator {
|
||||
|
||||
|
@ -28,9 +33,56 @@ public final class IBANValidator extends InputValidator {
|
|||
public ValidationResult validate(String input) {
|
||||
// TODO Add validation for primary and secondary IDs according to the selected type
|
||||
|
||||
// IBAN max 34 chars
|
||||
// IBAN max 34 chars, shortest is Norwegian with 15 chars, BBAN may include letters
|
||||
// bic: max 11 char
|
||||
return super.validate(input);
|
||||
|
||||
// check input length first
|
||||
if (isStringInRange(input, 15, 34)) {
|
||||
input = input.toUpperCase(Locale.ROOT); // ensure upper case
|
||||
|
||||
// check if country code is letters and checksum numeric
|
||||
if (!( Character.isLetter(input.charAt(0)) && Character.isLetter(input.charAt(1)) ))
|
||||
return new ValidationResult(false, "Country code invalid");
|
||||
if (!( Character.isDigit(input.charAt(2)) && Character.isDigit(input.charAt(3)) ))
|
||||
return new ValidationResult(false, "Checksum must be numeric");
|
||||
|
||||
// reorder IBAN to format <account number> <country code> <checksum>
|
||||
String input2 = new String(input.substring(4, input.length()) + input.substring(0,4));
|
||||
|
||||
// check if input is alphanumeric and count included letters
|
||||
int charCount = 0;
|
||||
char ch;
|
||||
for (int k=0; k<input2.length(); k++) {
|
||||
ch = input2.charAt(k);
|
||||
if (Character.isLetter(ch))
|
||||
charCount++;
|
||||
else if (!Character.isDigit(ch))
|
||||
return (new ValidationResult(false, "Non-alphanumeric character detected"));
|
||||
}
|
||||
|
||||
// create final char array for checksum validation
|
||||
char [] charArray = new char[input2.length()+charCount];
|
||||
int i = 0;
|
||||
int tmp;
|
||||
for (int k=0; k<input2.length(); k++) {
|
||||
ch = input2.charAt(k);
|
||||
if (Character.isLetter(ch)) {
|
||||
tmp = ch - ('A' - 10); // letters are transformed to two digit numbers A->10, B->11, ...
|
||||
String s = Integer.toString(tmp);
|
||||
charArray[i++] = s.charAt(0); // insert transformed
|
||||
charArray[i++] = s.charAt(1); // letters into char array
|
||||
} else charArray[i++] = ch; // transfer digits directly to char array
|
||||
}
|
||||
// System.out.print(Arrays.toString(charArray) + '\t');
|
||||
BigInteger bigInt = new BigInteger(new String(charArray));
|
||||
int result = bigInt.mod(new BigInteger(Integer.toString(97))).intValue();
|
||||
if (result == 1)
|
||||
return new ValidationResult(true);
|
||||
else
|
||||
return new ValidationResult(false, "IBAN checksum is invalid");
|
||||
}
|
||||
// return new ValidationResult(false, BSResources.get("validation.accountNrChars", "15 - 34"));
|
||||
return new ValidationResult(false, "Number must have length 15 to 34 chars.");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,17 +17,44 @@
|
|||
|
||||
package io.bitsquare.gui.util.validation;
|
||||
|
||||
/*
|
||||
* Interac e-Transfer requires a mail address or Canadian (mobile) phone number
|
||||
*
|
||||
* Mail addresses are covered with class EmailValidator
|
||||
*
|
||||
* Phone numbers have 11 digits, expected format is +1 NPA xxx-xxxx
|
||||
* Plus, spaces and dash might be omitted
|
||||
* Canadian area codes (NPA) taken from http://www.cnac.ca/canadian_dial_plan/Current_&_Future_Dialling_Plan.pdf
|
||||
* Valid (as of 2017-06-27) NPAs are hardcoded here
|
||||
* They are to change in some future (according to the linked document around 2019/2020)
|
||||
*/
|
||||
|
||||
public final class InteracETransferValidator extends InputValidator {
|
||||
|
||||
private static final String[] NPAS = {"204", "226", "236", "249", "250", "289", "306", "343", "365", "403", "416", "418", "431", "437", "438", "450", "506", "514", "519", "548", "579", "581", "587", "604", "613", "639", "647", "705", "709", "778", "780", "782", "807", "819", "825", "867", "873", "902", "905"};
|
||||
private final EmailValidator emailValidator;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public InteracETransferValidator() {
|
||||
emailValidator = new EmailValidator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validate(String input) {
|
||||
// TODO
|
||||
return super.validate(input);
|
||||
ValidationResult result = validateIfNotEmpty(input);
|
||||
if (!result.isValid) {
|
||||
return result;
|
||||
} else {
|
||||
ValidationResult emailResult = emailValidator.validate(input);
|
||||
if (emailResult.isValid)
|
||||
return emailResult;
|
||||
else
|
||||
return validatePhoneNumber(input);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,5 +62,22 @@ public final class InteracETransferValidator extends InputValidator {
|
|||
// Private methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private ValidationResult validatePhoneNumber(String input) {
|
||||
// check for correct format and strip +, space and -
|
||||
if (input.matches("\\+?1[ -]?\\d{3}[ -]?\\d{3}[ -]?\\d{4}")) {
|
||||
input = input.replace("+", "");
|
||||
input = input.replace(" ", "");
|
||||
input = input.replace("-", "");
|
||||
|
||||
String inputAreaCode = input.substring(1, 4);
|
||||
for (String s : NPAS) {
|
||||
// check area code agains list and return if valid
|
||||
if (inputAreaCode.compareTo(s) == 0)
|
||||
return new ValidationResult(true);
|
||||
}
|
||||
return new ValidationResult(false, "Non-Canadian area code");
|
||||
} else {
|
||||
return new ValidationResult(false, "Invalid phone number format and not an email address");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.gui.util.validation.altcoins;
|
||||
|
||||
import io.bitsquare.gui.util.validation.InputValidator;
|
||||
import org.apache.commons.codec.binary.Base32;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by DevAlexey on 19.12.2016.
|
||||
*/
|
||||
public class ByteballAddressValidator {
|
||||
private static final Base32 base32 = new Base32();
|
||||
private static final Base64 base64 = new Base64();
|
||||
private static final String PI = "14159265358979323846264338327950288419716939937510";
|
||||
private static final String[] arrRelativeOffsets = PI.split("");
|
||||
private static Integer[] arrOffsets160, arrOffsets288;
|
||||
|
||||
static {
|
||||
try {
|
||||
arrOffsets160 = calcOffsets(160);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
arrOffsets288 = calcOffsets(288);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static InputValidator.ValidationResult validate(String input) {
|
||||
return new InputValidator.ValidationResult(isValidAddress(input));
|
||||
}
|
||||
|
||||
private static boolean isValidAddress(String address) {
|
||||
return isValidChash(address, 32);
|
||||
}
|
||||
|
||||
private static boolean isValidChash(String str, int len) {
|
||||
return (isStringOfLength(str, len) && isChashValid(str));
|
||||
}
|
||||
|
||||
private static boolean isStringOfLength(String str, int len) {
|
||||
return str.length() == len;
|
||||
}
|
||||
|
||||
private static void checkLength(int chash_length) throws Exception {
|
||||
if (chash_length != 160 && chash_length != 288)
|
||||
throw new Exception("unsupported c-hash length: " + chash_length);
|
||||
}
|
||||
|
||||
private static Integer[] calcOffsets(int chash_length) throws Exception {
|
||||
checkLength(chash_length);
|
||||
List<Integer> arrOffsets = new ArrayList<>(chash_length);
|
||||
int offset = 0;
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; offset < chash_length; i++) {
|
||||
int relative_offset = Integer.parseInt(arrRelativeOffsets[i]);
|
||||
if (relative_offset == 0)
|
||||
continue;
|
||||
offset += relative_offset;
|
||||
if (chash_length == 288)
|
||||
offset += 4;
|
||||
if (offset >= chash_length)
|
||||
break;
|
||||
arrOffsets.add(offset);
|
||||
//console.log("index="+index+", offset="+offset);
|
||||
index++;
|
||||
}
|
||||
|
||||
if (index != 32)
|
||||
throw new Exception("wrong number of checksum bits");
|
||||
|
||||
return arrOffsets.toArray(new Integer[0]);
|
||||
}
|
||||
|
||||
private static SeparatedData separateIntoCleanDataAndChecksum(String bin) throws Exception {
|
||||
int len = bin.length();
|
||||
Integer[] arrOffsets;
|
||||
if (len == 160)
|
||||
arrOffsets = arrOffsets160;
|
||||
else if (len == 288)
|
||||
arrOffsets = arrOffsets288;
|
||||
else
|
||||
throw new Exception("bad length");
|
||||
StringBuilder arrFrags = new StringBuilder();
|
||||
StringBuilder arrChecksumBits = new StringBuilder();
|
||||
int start = 0;
|
||||
for (int i = 0; i < arrOffsets.length; i++) {
|
||||
arrFrags.append(bin.substring(start, arrOffsets[i]));
|
||||
arrChecksumBits.append(bin.substring(arrOffsets[i], arrOffsets[i] + 1));
|
||||
start = arrOffsets[i] + 1;
|
||||
}
|
||||
// add last frag
|
||||
if (start < bin.length())
|
||||
arrFrags.append(bin.substring(start));
|
||||
String binCleanData = arrFrags.toString();
|
||||
String binChecksum = arrChecksumBits.toString();
|
||||
return new SeparatedData(binCleanData, binChecksum);
|
||||
}
|
||||
|
||||
private static String buffer2bin(byte[] buf) {
|
||||
StringBuffer bytes = new StringBuffer();
|
||||
for (int i = 0; i < buf.length; i++) {
|
||||
String bin = String.format("%8s", Integer.toBinaryString(buf[i] & 0xFF)).replace(' ', '0');
|
||||
bytes.append(bin);
|
||||
}
|
||||
return bytes.toString();
|
||||
}
|
||||
|
||||
private static byte[] bin2buffer(String bin) {
|
||||
int len = bin.length() / 8;
|
||||
byte[] buf = new byte[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
buf[i] = (byte) Integer.parseInt(bin.substring(i * 8, (i + 1) * 8), 2);
|
||||
return buf;
|
||||
}
|
||||
|
||||
private static boolean isChashValid(String encoded) {
|
||||
int encoded_len = encoded.length();
|
||||
if (encoded_len != 32 && encoded_len != 48) // 160/5 = 32, 288/6 = 48
|
||||
return false;
|
||||
byte[] chash = (encoded_len == 32) ? base32.decode(encoded) : base64.decode(encoded);
|
||||
String binChash = buffer2bin(chash);
|
||||
SeparatedData separated = null;
|
||||
try {
|
||||
separated = separateIntoCleanDataAndChecksum(binChash);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
byte[] clean_data = bin2buffer(separated.clean_data);
|
||||
byte[] checksum = bin2buffer(separated.checksum);
|
||||
return Arrays.equals(getChecksum(clean_data), checksum);
|
||||
}
|
||||
|
||||
private static byte[] getChecksum(byte[] clean_data) {
|
||||
|
||||
try {
|
||||
byte[] full_checksum = MessageDigest.getInstance("SHA-256").digest(clean_data);
|
||||
byte[] checksum = {full_checksum[5], full_checksum[13], full_checksum[21], full_checksum[29]};
|
||||
return checksum;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SeparatedData {
|
||||
String clean_data, checksum;
|
||||
|
||||
public SeparatedData(String clean_data, String checksum) {
|
||||
this.clean_data = clean_data;
|
||||
this.checksum = checksum;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.gui.util.validation.params;
|
||||
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.store.BlockStore;
|
||||
import org.bitcoinj.store.BlockStoreException;
|
||||
import org.bitcoinj.utils.MonetaryFormat;
|
||||
|
||||
public class IOPParams extends NetworkParameters {
|
||||
|
||||
private static IOPParams instance;
|
||||
|
||||
public static synchronized IOPParams get() {
|
||||
if (instance == null) {
|
||||
instance = new IOPParams();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
// We only use the properties needed for address validation
|
||||
public IOPParams() {
|
||||
super();
|
||||
addressHeader = 117;
|
||||
p2shHeader = 174;
|
||||
acceptableAddressCodes = new int[]{addressHeader, p2shHeader};
|
||||
}
|
||||
|
||||
// default dummy implementations, not used...
|
||||
@Override
|
||||
public String getPaymentProtocolId() {
|
||||
return PAYMENT_PROTOCOL_ID_MAINNET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkDifficultyTransitions(StoredBlock storedPrev, Block next, BlockStore blockStore) throws VerificationException, BlockStoreException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coin getMaxMoney() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coin getMinNonDustOutput() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonetaryFormat getMonetaryFormat() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUriScheme() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMaxMoney() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.gui.util.validation.params;
|
||||
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.store.BlockStore;
|
||||
import org.bitcoinj.store.BlockStoreException;
|
||||
import org.bitcoinj.utils.MonetaryFormat;
|
||||
|
||||
public class PivxParams extends NetworkParameters {
|
||||
|
||||
private static PivxParams instance;
|
||||
|
||||
public static synchronized PivxParams get() {
|
||||
if (instance == null) {
|
||||
instance = new PivxParams();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
// We only use the properties needed for address validation
|
||||
public PivxParams() {
|
||||
super();
|
||||
addressHeader = 30;
|
||||
p2shHeader = 13;
|
||||
acceptableAddressCodes = new int[]{addressHeader, p2shHeader};
|
||||
}
|
||||
|
||||
// default dummy implementations, not used...
|
||||
@Override
|
||||
public String getPaymentProtocolId() {
|
||||
return PAYMENT_PROTOCOL_ID_MAINNET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkDifficultyTransitions(StoredBlock storedPrev, Block next, BlockStore blockStore) throws VerificationException, BlockStoreException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coin getMaxMoney() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coin getMinNonDustOutput() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonetaryFormat getMonetaryFormat() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUriScheme() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMaxMoney() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -217,7 +217,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -230,12 +230,11 @@ FASTER_PAYMENTS_SHORT=Faster Payments
|
|||
NATIONAL_BANK_SHORT=National banks
|
||||
SAME_BANK_SHORT=Same bank
|
||||
SPECIFIC_BANKS_SHORT=Specific banks
|
||||
FED_WIRE_SHORT=Fed Wire
|
||||
SWISH_SHORT=Swish
|
||||
CLEAR_X_CHANGE_SHORT=ClearXchange
|
||||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,7 +238,7 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
|
@ -219,7 +219,7 @@ CLEAR_X_CHANGE=ClearXchange
|
|||
CHASE_QUICK_PAY=Chase QuickPay
|
||||
INTERAC_E_TRANSFER=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER=US Postal Money Order
|
||||
CASH_DEPOSIT=Cash/ATM deposit
|
||||
CASH_DEPOSIT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS=Altcoins
|
||||
|
||||
|
@ -238,6 +238,6 @@ CLEAR_X_CHANGE_SHORT=ClearXchange
|
|||
CHASE_QUICK_PAY_SHORT=Chase QuickPay
|
||||
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
|
||||
US_POSTAL_MONEY_ORDER_SHORT=US Money Order
|
||||
CASH_DEPOSIT_SHORT=Cash/ATM deposit
|
||||
CASH_DEPOSIT_SHORT=Cash Deposit
|
||||
|
||||
BLOCK_CHAINS_SHORT=Altcoins
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue