Refactor wallets, add support for both wallet seeds (restore still not working). Cleanups.

This commit is contained in:
Manfred Karrer 2016-12-10 23:55:15 +01:00
parent 38a69c7711
commit a218bd1e15
67 changed files with 929 additions and 863 deletions

View file

@ -23,10 +23,10 @@ import io.bitsquare.app.Log;
import io.bitsquare.arbitration.messages.*;
import io.bitsquare.arbitration.payload.Attachment;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.exceptions.TransactionVerificationException;
import io.bitsquare.btc.exceptions.WalletException;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.TradeWalletService;
import io.bitsquare.common.Timer;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.crypto.KeyRing;
@ -71,7 +71,7 @@ public class DisputeManager {
private final TradeWalletService tradeWalletService;
private final BtcWalletService walletService;
private final TradeManager tradeManager;
private ClosedTradableManager closedTradableManager;
private final ClosedTradableManager closedTradableManager;
private final OpenOfferManager openOfferManager;
private final P2PService p2PService;
private final KeyRing keyRing;
@ -83,7 +83,7 @@ public class DisputeManager {
private final CopyOnWriteArraySet<DecryptedMsgWithPubKey> decryptedDirectMessageWithPubKeys = new CopyOnWriteArraySet<>();
private final Map<String, Dispute> openDisputes;
private final Map<String, Dispute> closedDisputes;
private Map<String, Timer> delayMsgMap = new HashMap<>();
private final Map<String, Timer> delayMsgMap = new HashMap<>();
///////////////////////////////////////////////////////////////////////////////////////////
@ -91,7 +91,7 @@ public class DisputeManager {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public DisputeManager(P2PService p2PService,
private DisputeManager(P2PService p2PService,
TradeWalletService tradeWalletService,
BtcWalletService walletService,
TradeManager tradeManager,

View file

@ -23,6 +23,10 @@ import io.bitsquare.app.AppOptionKeys;
import io.bitsquare.btc.blockchain.BlockchainService;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.SquWalletService;
import io.bitsquare.btc.wallet.TradeWalletService;
import io.bitsquare.btc.wallet.WalletsSetup;
import io.bitsquare.http.HttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -56,7 +60,7 @@ public class BitcoinModule extends AppModule {
bindConstant().annotatedWith(named(AppOptionKeys.PROVIDERS)).to(env.getRequiredProperty(AppOptionKeys.PROVIDERS));
bind(AddressEntryList.class).in(Singleton.class);
bind(WalletSetup.class).in(Singleton.class);
bind(WalletsSetup.class).in(Singleton.class);
bind(BtcWalletService.class).in(Singleton.class);
bind(SquWalletService.class).in(Singleton.class);
bind(TradeWalletService.class).in(Singleton.class);

View file

@ -15,12 +15,11 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import com.google.common.collect.ImmutableList;
import org.bitcoinj.crypto.ChildNumber;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.HDUtils;
import org.bitcoinj.crypto.KeyCrypter;
import org.bitcoinj.wallet.DeterministicKeyChain;
import org.bitcoinj.wallet.DeterministicSeed;
@ -29,13 +28,13 @@ import org.slf4j.LoggerFactory;
import java.security.SecureRandom;
public class BitcoinDeterministicKeyChain extends DeterministicKeyChain {
class BitcoinDeterministicKeyChain extends DeterministicKeyChain {
private static final Logger log = LoggerFactory.getLogger(BitcoinDeterministicKeyChain.class);
// See https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
// https://github.com/satoshilabs/slips/blob/master/slip-0044.md
// We use 0 (0x80000000) as coin_type for BTC
public static ImmutableList<ChildNumber> BIP44_BTC_ACCOUNT_PATH = ImmutableList.of(
public static final ImmutableList<ChildNumber> BIP44_BTC_ACCOUNT_PATH = ImmutableList.of(
new ChildNumber(44, true),
new ChildNumber(0, true),
ChildNumber.ZERO_HARDENED,
@ -55,8 +54,6 @@ public class BitcoinDeterministicKeyChain extends DeterministicKeyChain {
@Override
protected ImmutableList<ChildNumber> getAccountPath() {
log.error(HDUtils.formatPath(BIP44_BTC_ACCOUNT_PATH));
return BIP44_BTC_ACCOUNT_PATH;
}

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import com.google.common.collect.ImmutableList;
import org.bitcoinj.crypto.ChildNumber;
@ -28,8 +28,8 @@ import org.bitcoinj.wallet.DeterministicSeed;
import org.bitcoinj.wallet.KeyChainFactory;
import org.bitcoinj.wallet.Protos;
public class BitsquareKeyChainFactory implements KeyChainFactory {
private boolean useBitcoinDeterministicKeyChain;
class BitsquareKeyChainFactory implements KeyChainFactory {
private final boolean useBitcoinDeterministicKeyChain;
public BitsquareKeyChainFactory(boolean useBitcoinDeterministicKeyChain) {
this.useBitcoinDeterministicKeyChain = useBitcoinDeterministicKeyChain;

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.wallet.DeterministicKeyChain;
@ -24,8 +24,8 @@ import org.bitcoinj.wallet.KeyChainGroup;
import java.security.SecureRandom;
public class BitsquareKeyChainGroup extends KeyChainGroup {
private boolean useBitcoinDeterministicKeyChain;
class BitsquareKeyChainGroup extends KeyChainGroup {
private final boolean useBitcoinDeterministicKeyChain;
public boolean isUseBitcoinDeterministicKeyChain() {
return useBitcoinDeterministicKeyChain;
@ -36,8 +36,8 @@ public class BitsquareKeyChainGroup extends KeyChainGroup {
this.useBitcoinDeterministicKeyChain = useBitcoinDeterministicKeyChain;
}
public BitsquareKeyChainGroup(NetworkParameters params, DeterministicSeed watchKey, boolean useBitcoinDeterministicKeyChain) {
super(params, watchKey);
public BitsquareKeyChainGroup(NetworkParameters params, DeterministicSeed seed, boolean useBitcoinDeterministicKeyChain) {
super(params, seed);
this.useBitcoinDeterministicKeyChain = useBitcoinDeterministicKeyChain;
}

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import com.google.common.annotations.VisibleForTesting;
import org.bitcoinj.core.*;
@ -36,16 +36,16 @@ import static com.google.common.base.Preconditions.checkNotNull;
* We use a specialized version of the CoinSelector based on the DefaultCoinSelector implementation.
* We lookup for spendable outputs which matches our address of our addressEntry.
*/
abstract class BitsquareCoinSelector implements CoinSelector {
private static final Logger log = LoggerFactory.getLogger(BitsquareCoinSelector.class);
protected final NetworkParameters params;
abstract class BtcCoinSelector implements CoinSelector {
private static final Logger log = LoggerFactory.getLogger(BtcCoinSelector.class);
final NetworkParameters params;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
protected BitsquareCoinSelector(NetworkParameters params) {
BtcCoinSelector(NetworkParameters params) {
this.params = params;
}
@ -64,7 +64,7 @@ abstract class BitsquareCoinSelector implements CoinSelector {
/**
* Sub-classes can override this to just customize whether transactions are usable, but keep age sorting.
*/
protected boolean shouldSelect(Transaction tx) {
private boolean shouldSelect(Transaction tx) {
return isInBlockChainOrPending(tx);
}

View file

@ -15,24 +15,21 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import io.bitsquare.btc.exceptions.SigningException;
import io.bitsquare.btc.*;
import io.bitsquare.btc.exceptions.TransactionVerificationException;
import io.bitsquare.btc.exceptions.WalletException;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ExceptionHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.user.Preferences;
import org.bitcoinj.core.*;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.KeyCrypterScrypt;
import org.bitcoinj.wallet.DeterministicSeed;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -63,55 +60,43 @@ public class BtcWalletService extends WalletService {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public BtcWalletService(WalletSetup walletSetup,
public BtcWalletService(WalletsSetup walletsSetup,
AddressEntryList addressEntryList,
Preferences preferences,
FeeService feeService) {
super(walletSetup,
super(walletsSetup,
preferences,
feeService);
this.addressEntryList = addressEntryList;
walletSetup.addSetupCompletedHandler(() -> {
wallet = walletSetup.getWallet();
walletsSetup.addSetupCompletedHandler(() -> {
wallet = walletsSetup.getBtcWallet();
wallet.addEventListener(walletEventListener);
});
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public Methods
// Overridden Methods
///////////////////////////////////////////////////////////////////////////////////////////
@Override
void decryptWallet(@NotNull KeyParameter key) {
super.decryptWallet(key);
public String exportWalletData(boolean includePrivKeys) {
StringBuilder addressEntryListData = new StringBuilder();
getAddressEntryListAsImmutableList().stream().forEach(e -> addressEntryListData.append(e.toString()).append("\n"));
return "BitcoinJ wallet:\n" +
wallet.toString(includePrivKeys, true, true, walletSetup.chain()) + "\n\n" +
"Bitsquare address entry list:\n" +
addressEntryListData.toString() +
"All pubkeys as hex:\n" +
wallet.printAllPubKeysAsHex();
}
// TODO
public void restoreSeedWords(DeterministicSeed seed, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
walletSetup.restoreBtcSeedWords(seed, resultHandler, exceptionHandler);
}
public void decryptWallet(@NotNull KeyParameter key) {
addressEntryList.stream().forEach(e -> {
final DeterministicKey keyPair = e.getKeyPair();
if (keyPair != null && keyPair.isEncrypted())
e.setDeterministicKey(keyPair.decrypt(key));
});
addressEntryList.queueUpForSave();
}
public void encryptWallet(KeyCrypterScrypt keyCrypterScrypt, KeyParameter key) {
@Override
void encryptWallet(KeyCrypterScrypt keyCrypterScrypt, KeyParameter key) {
super.encryptWallet(keyCrypterScrypt, key);
addressEntryList.stream().forEach(e -> {
final DeterministicKey keyPair = e.getKeyPair();
if (keyPair != null && keyPair.isEncrypted())
@ -120,13 +105,31 @@ public class BtcWalletService extends WalletService {
addressEntryList.queueUpForSave();
}
@Override
String getWalletAsString(boolean includePrivKeys) {
StringBuilder sb = new StringBuilder();
getAddressEntryListAsImmutableList().stream().forEach(e -> sb.append(e.toString()).append("\n"));
return "BitcoinJ wallet:\n" +
wallet.toString(includePrivKeys, true, true, walletsSetup.getChain()) + "\n\n" +
"Bitsquare address entry list:\n" +
sb.toString() +
"All pubkeys as hex:\n" +
wallet.printAllPubKeysAsHex();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Fee tx for SQU
// Public Methods
///////////////////////////////////////////////////////////////////////////////////////////
public Transaction getTransactionWithFeeInput(Transaction transaction) throws
TransactionVerificationException, WalletException, AddressFormatException, AddressEntryException, InsufficientFundsException, SigningException {
log.trace("takerCreatesDepositsTxInputs called");
///////////////////////////////////////////////////////////////////////////////////////////
// Add fee input to prepared SQU send tx
///////////////////////////////////////////////////////////////////////////////////////////
public Transaction addFeeInputToPreparedSquSendTx(Transaction transaction) throws
TransactionVerificationException, WalletException, InsufficientFundsException {
log.trace("addFeeInputToPreparedSquSendTx called");
try {
int counter = 0;
int txSize = 407; // typical size for a tx with 2 inputs and 3 outputs
@ -135,7 +138,7 @@ public class BtcWalletService extends WalletService {
Address changeAddress = getOrCreateAddressEntry(AddressEntry.Context.AVAILABLE).getAddress();
checkNotNull(feePaymentAddress, "feePaymentAddress must not be null");
checkNotNull(changeAddress, "changeAddress must not be null");
TokenFeeCoinSelector coinSelector = new TokenFeeCoinSelector(params, feePaymentAddress);
SquCoinSelector coinSelector = new SquCoinSelector(params, feePaymentAddress);
List<TransactionInput> inputs = transaction.getInputs();
List<TransactionOutput> outputs = transaction.getOutputs();
Transaction resultTx;
@ -146,7 +149,7 @@ public class BtcWalletService extends WalletService {
outputs.stream().forEach(tx::addOutput);
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
sendRequest.shuffleOutputs = false;
sendRequest.aesKey = walletSetup.getAesKey();
sendRequest.aesKey = aesKey;
// Need to be false as it would try to sign all inputs (SQU inputs are not in this wallet)
sendRequest.signInputs = false;
sendRequest.ensureMinRequiredFee = false;
@ -182,10 +185,6 @@ public class BtcWalletService extends WalletService {
}
}
public void commitTx(Transaction tx) {
wallet.commitTx(tx);
}
///////////////////////////////////////////////////////////////////////////////////////////
// AddressEntry
@ -223,7 +222,7 @@ public class BtcWalletService extends WalletService {
return addressEntryList.addAddressEntry(new AddressEntry(wallet.freshReceiveKey(), wallet.getParams(), context));
}
public Optional<AddressEntry> findAddressEntry(String address, AddressEntry.Context context) {
private Optional<AddressEntry> findAddressEntry(String address, AddressEntry.Context context) {
return getAddressEntryListAsImmutableList().stream()
.filter(e -> address.equals(e.getAddressString()))
.filter(e -> context == e.getContext())
@ -248,7 +247,7 @@ public class BtcWalletService extends WalletService {
.collect(Collectors.toList());
}
public List<AddressEntry> getAddressEntryListAsImmutableList() {
private List<AddressEntry> getAddressEntryListAsImmutableList() {
return ImmutableList.copyOf(addressEntryList);
}
@ -288,7 +287,7 @@ public class BtcWalletService extends WalletService {
///////////////////////////////////////////////////////////////////////////////////////////
public void doubleSpendTransaction(String txId, Runnable resultHandler, ErrorMessageHandler errorMessageHandler)
throws InsufficientMoneyException, AddressFormatException, AddressEntryException, InsufficientFundsException {
throws InsufficientFundsException {
AddressEntry addressEntry = getOrCreateUnusedAddressEntry(AddressEntry.Context.AVAILABLE);
checkNotNull(addressEntry.getAddress(), "addressEntry.getAddress() must not be null");
Optional<Transaction> transactionOptional = wallet.getTransactions(true).stream()
@ -352,7 +351,7 @@ public class BtcWalletService extends WalletService {
sendRequest = Wallet.SendRequest.forTx(newTransaction);
sendRequest.fee = fee;
sendRequest.feePerKb = Coin.ZERO;
sendRequest.aesKey = walletSetup.getAesKey();
sendRequest.aesKey = aesKey;
sendRequest.coinSelector = new TradeWalletCoinSelector(params, toAddress);
sendRequest.changeAddress = toAddress;
wallet.completeTx(sendRequest);
@ -371,7 +370,7 @@ public class BtcWalletService extends WalletService {
sendRequest = Wallet.SendRequest.forTx(newTransaction);
sendRequest.fee = fee;
sendRequest.feePerKb = Coin.ZERO;
sendRequest.aesKey = walletSetup.getAesKey();
sendRequest.aesKey = aesKey;
sendRequest.coinSelector = new TradeWalletCoinSelector(params, toAddress);
sendRequest.changeAddress = toAddress;
sendResult = wallet.sendCoins(sendRequest);
@ -386,7 +385,7 @@ public class BtcWalletService extends WalletService {
sendRequest = Wallet.SendRequest.forTx(newTransaction);
sendRequest.fee = fee;
sendRequest.feePerKb = Coin.ZERO;
sendRequest.aesKey = walletSetup.getAesKey();
sendRequest.aesKey = aesKey;
sendRequest.coinSelector = new TradeWalletCoinSelector(params, toAddress, false);
sendRequest.changeAddress = toAddress;
@ -459,7 +458,7 @@ public class BtcWalletService extends WalletService {
if (fee.compareTo(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE) < 0)
fee = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE;
Wallet.SendRequest sendRequest = getSendRequest(fromAddress, toAddress, amount, fee, walletSetup.getAesKey(), context);
Wallet.SendRequest sendRequest = getSendRequest(fromAddress, toAddress, amount, fee, aesKey, context);
wallet.completeTx(sendRequest);
tx = sendRequest.tx;
txSize = tx.bitcoinSerialize().length;
@ -509,7 +508,7 @@ public class BtcWalletService extends WalletService {
fee = txFeeForWithdrawalPerByte.multiply(txSize);
if (fee.compareTo(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE) < 0)
fee = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE;
Wallet.SendRequest sendRequest = getSendRequestForMultipleAddresses(fromAddresses, toAddress, amount, fee, null, walletSetup.getAesKey());
Wallet.SendRequest sendRequest = getSendRequestForMultipleAddresses(fromAddresses, toAddress, amount, fee, null, aesKey);
wallet.completeTx(sendRequest);
tx = sendRequest.tx;
txSize = tx.bitcoinSerialize().length;
@ -564,13 +563,13 @@ public class BtcWalletService extends WalletService {
return sendResult.tx.getHashAsString();
}
protected Wallet.SendRequest getSendRequest(String fromAddress,
private Wallet.SendRequest getSendRequest(String fromAddress,
String toAddress,
Coin amount,
Coin fee,
@Nullable KeyParameter aesKey,
AddressEntry.Context context) throws AddressFormatException,
AddressEntryException, InsufficientMoneyException {
AddressEntryException {
Transaction tx = new Transaction(params);
Preconditions.checkArgument(Restrictions.isAboveDust(amount, fee),
"The amount is too low (dust limit).");
@ -598,7 +597,7 @@ public class BtcWalletService extends WalletService {
Coin fee,
@Nullable String changeAddress,
@Nullable KeyParameter aesKey) throws
AddressFormatException, AddressEntryException, InsufficientMoneyException {
AddressFormatException, AddressEntryException {
Transaction tx = new Transaction(params);
Preconditions.checkArgument(Restrictions.isAboveDust(amount),
"The amount is too low (dust limit).");

View file

@ -15,8 +15,9 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import io.bitsquare.btc.AddressEntry;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.TransactionConfidence;
@ -31,7 +32,7 @@ import java.util.Set;
* We use a specialized version of the CoinSelector based on the DefaultCoinSelector implementation.
* We lookup for spendable outputs which matches our address of our addressEntry.
*/
class MultiAddressesCoinSelector extends BitsquareCoinSelector {
class MultiAddressesCoinSelector extends BtcCoinSelector {
private static final Logger log = LoggerFactory.getLogger(MultiAddressesCoinSelector.class);
private final Set<AddressEntry> addressEntries;
private final boolean allowUnconfirmedSpend;
@ -46,7 +47,7 @@ class MultiAddressesCoinSelector extends BitsquareCoinSelector {
}
public MultiAddressesCoinSelector(NetworkParameters params, @NotNull Set<AddressEntry> addressEntries, boolean allowUnconfirmedSpend) {
private MultiAddressesCoinSelector(NetworkParameters params, @NotNull Set<AddressEntry> addressEntries, boolean allowUnconfirmedSpend) {
super(params);
this.addressEntries = addressEntries;
this.allowUnconfirmedSpend = allowUnconfirmedSpend;
@ -55,7 +56,7 @@ class MultiAddressesCoinSelector extends BitsquareCoinSelector {
@Override
protected boolean matchesRequirement(TransactionOutput transactionOutput) {
if (transactionOutput.getScriptPubKey().isSentToAddress() || transactionOutput.getScriptPubKey().isPayToScriptHash()) {
boolean confirmationCheck = allowUnconfirmedSpend || false;
boolean confirmationCheck = allowUnconfirmedSpend;
if (!allowUnconfirmedSpend && transactionOutput.getParentTransaction() != null &&
transactionOutput.getParentTransaction().getConfidence() != null) {
final TransactionConfidence.ConfidenceType confidenceType = transactionOutput.getParentTransaction().getConfidence().getConfidenceType();

View file

@ -15,8 +15,9 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import io.bitsquare.btc.AddressEntry;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.TransactionOutput;
@ -32,7 +33,7 @@ import java.util.stream.Collectors;
* We use a specialized version of the CoinSelector based on the DefaultCoinSelector implementation.
* We lookup for spendable outputs which matches our address of our addressEntry.
*/
class SavingsWalletCoinSelector extends BitsquareCoinSelector {
class SavingsWalletCoinSelector extends BtcCoinSelector {
private static final Logger log = LoggerFactory.getLogger(SavingsWalletCoinSelector.class);
private final Set<Address> savingsWalletAddressSet;

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.NetworkParameters;
@ -29,21 +29,21 @@ import org.slf4j.LoggerFactory;
* We use a specialized version of the CoinSelector based on the DefaultCoinSelector implementation.
* We lookup for spendable outputs which matches our address of our address.
*/
class TokenFeeCoinSelector extends BitsquareCoinSelector {
private static final Logger log = LoggerFactory.getLogger(TokenFeeCoinSelector.class);
class SquCoinSelector extends BtcCoinSelector {
private static final Logger log = LoggerFactory.getLogger(SquCoinSelector.class);
private final Address address;
private boolean allowUnconfirmedSpend;
private final boolean allowUnconfirmedSpend;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public TokenFeeCoinSelector(NetworkParameters params, @NotNull Address address) {
SquCoinSelector(NetworkParameters params, @NotNull Address address) {
this(params, address, true);
}
public TokenFeeCoinSelector(NetworkParameters params, @NotNull Address address, boolean allowUnconfirmedSpend) {
private SquCoinSelector(NetworkParameters params, @NotNull Address address, boolean allowUnconfirmedSpend) {
super(params);
this.address = address;
this.allowUnconfirmedSpend = allowUnconfirmedSpend;
@ -52,7 +52,7 @@ class TokenFeeCoinSelector extends BitsquareCoinSelector {
@Override
protected boolean matchesRequirement(TransactionOutput transactionOutput) {
if (transactionOutput.getScriptPubKey().isSentToAddress() || transactionOutput.getScriptPubKey().isPayToScriptHash()) {
boolean confirmationCheck = allowUnconfirmedSpend || false;
boolean confirmationCheck = allowUnconfirmedSpend;
if (!allowUnconfirmedSpend && transactionOutput.getParentTransaction() != null &&
transactionOutput.getParentTransaction().getConfidence() != null) {
final TransactionConfidence.ConfidenceType confidenceType = transactionOutput.getParentTransaction().getConfidence().getConfidenceType();

View file

@ -15,12 +15,11 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import com.google.common.collect.ImmutableList;
import org.bitcoinj.crypto.ChildNumber;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.HDUtils;
import org.bitcoinj.crypto.KeyCrypter;
import org.bitcoinj.wallet.DeterministicKeyChain;
import org.bitcoinj.wallet.DeterministicSeed;
@ -29,14 +28,14 @@ import org.slf4j.LoggerFactory;
import java.security.SecureRandom;
public class SquDeterministicKeyChain extends DeterministicKeyChain {
class SquDeterministicKeyChain extends DeterministicKeyChain {
private static final Logger log = LoggerFactory.getLogger(SquDeterministicKeyChain.class);
// See https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
// https://github.com/satoshilabs/slips/blob/master/slip-0044.md
// We use 139 (0x80000000) as coin_type for SQU
// TODO register once the token name is fix
public static ImmutableList<ChildNumber> BIP44_SQU_ACCOUNT_PATH = ImmutableList.of(
public static final ImmutableList<ChildNumber> BIP44_SQU_ACCOUNT_PATH = ImmutableList.of(
new ChildNumber(44, true),
new ChildNumber(139, true),
ChildNumber.ZERO_HARDENED,
@ -56,8 +55,6 @@ public class SquDeterministicKeyChain extends DeterministicKeyChain {
@Override
protected ImmutableList<ChildNumber> getAccountPath() {
log.error(HDUtils.formatPath(BIP44_SQU_ACCOUNT_PATH));
return BIP44_SQU_ACCOUNT_PATH;
}

View file

@ -15,20 +15,17 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import io.bitsquare.btc.Restrictions;
import io.bitsquare.btc.exceptions.TransactionVerificationException;
import io.bitsquare.btc.exceptions.WalletException;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.common.handlers.ExceptionHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.user.Preferences;
import org.bitcoinj.core.*;
import org.bitcoinj.wallet.DeterministicSeed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -48,59 +45,46 @@ public class SquWalletService extends WalletService {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public SquWalletService(WalletSetup walletSetup,
public SquWalletService(WalletsSetup walletsSetup,
Preferences preferences,
FeeService feeService) {
super(walletSetup,
super(walletsSetup,
preferences,
feeService);
walletSetup.addSetupCompletedHandler(() -> {
wallet = walletSetup.getTokenWallet();
walletsSetup.addSetupCompletedHandler(() -> {
wallet = walletsSetup.getSquWallet();
wallet.addEventListener(walletEventListener);
});
}
///////////////////////////////////////////////////////////////////////////////////////////
// Overridden Methods
///////////////////////////////////////////////////////////////////////////////////////////
@Override
String getWalletAsString(boolean includePrivKeys) {
return "BitcoinJ wallet:\n" +
wallet.toString(includePrivKeys, true, true, walletsSetup.getChain()) + "\n\n" +
"All pubkeys as hex:\n" +
wallet.printAllPubKeysAsHex();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public Methods
///////////////////////////////////////////////////////////////////////////////////////////
public String exportWalletData(boolean includePrivKeys) {
StringBuilder addressEntryListData = new StringBuilder();
return "BitcoinJ SQU wallet:\n" +
wallet.toString(includePrivKeys, true, true, walletSetup.chain()) + "\n\n" +
"SQU address entry list:\n" +
addressEntryListData.toString() +
"All pubkeys as hex:\n" +
wallet.printAllPubKeysAsHex();
}
//TODO
public void restoreSeedWords(DeterministicSeed seed, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
/* Context ctx = Context.get();
new Thread(() -> {
try {
Context.propagate(ctx);
walletAppKit.stopAsync();
walletAppKit.awaitTerminated();
initialize(seed, resultHandler, exceptionHandler);
} catch (Throwable t) {
t.printStackTrace();
log.error("Executing task failed. " + t.getMessage());
}
}, "RestoreWallet-%d").start();*/
}
///////////////////////////////////////////////////////////////////////////////////////////
// Withdrawal Send
// Send SQU with BTC fee
///////////////////////////////////////////////////////////////////////////////////////////
public Transaction prepareSendTx(String receiverAddress,
public Transaction getPreparedSendTx(String receiverAddress,
Coin receiverAmount,
Optional<String> changeAddressStringOptional) throws AddressFormatException,
AddressEntryException, InsufficientMoneyException, WalletException, TransactionVerificationException {
InsufficientMoneyException, WalletException, TransactionVerificationException {
Transaction tx = new Transaction(params);
Preconditions.checkArgument(Restrictions.isAboveDust(receiverAmount),
@ -110,7 +94,7 @@ public class SquWalletService extends WalletService {
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
sendRequest.fee = Coin.ZERO;
sendRequest.feePerKb = Coin.ZERO;
sendRequest.aesKey = walletSetup.getAesKey();
sendRequest.aesKey = aesKey;
sendRequest.shuffleOutputs = false;
sendRequest.signInputs = false;
sendRequest.ensureMinRequiredFee = false;
@ -124,7 +108,14 @@ public class SquWalletService extends WalletService {
return tx;
}
public Transaction signFinalSendTx(Transaction tx) throws WalletException, TransactionVerificationException {
public void signAndBroadcastSendTx(Transaction tx, FutureCallback<Transaction> callback) throws WalletException, TransactionVerificationException {
Transaction signedTx = signFinalSendTx(tx);
wallet.commitTx(signedTx);
Futures.addCallback(walletsSetup.getPeerGroup().broadcastTransaction(signedTx).future(), callback);
printTx("commitAndBroadcastTx", signedTx);
}
private Transaction signFinalSendTx(Transaction tx) throws WalletException, TransactionVerificationException {
// TODO
int index = 0;
TransactionInput txIn = tx.getInput(index);
@ -138,22 +129,4 @@ public class SquWalletService extends WalletService {
return tx;
}
public void commitAndBroadcastTx(Transaction tx, FutureCallback<Transaction> callback) {
wallet.commitTx(tx);
ListenableFuture<Transaction> broadcastComplete = walletSetup.peerGroup().broadcastTransaction(tx).future();
Futures.addCallback(broadcastComplete, callback);
printTx("commitAndBroadcastTx", tx);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
// Util
///////////////////////////////////////////////////////////////////////////////////////////
}

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.NetworkParameters;
@ -29,10 +29,10 @@ import org.slf4j.LoggerFactory;
* We use a specialized version of the CoinSelector based on the DefaultCoinSelector implementation.
* We lookup for spendable outputs which matches our address of our address.
*/
class TradeWalletCoinSelector extends BitsquareCoinSelector {
class TradeWalletCoinSelector extends BtcCoinSelector {
private static final Logger log = LoggerFactory.getLogger(TradeWalletCoinSelector.class);
private final Address address;
private boolean allowUnconfirmedSpend;
private final boolean allowUnconfirmedSpend;
///////////////////////////////////////////////////////////////////////////////////////////
@ -52,7 +52,7 @@ class TradeWalletCoinSelector extends BitsquareCoinSelector {
@Override
protected boolean matchesRequirement(TransactionOutput transactionOutput) {
if (transactionOutput.getScriptPubKey().isSentToAddress() || transactionOutput.getScriptPubKey().isPayToScriptHash()) {
boolean confirmationCheck = allowUnconfirmedSpend || false;
boolean confirmationCheck = allowUnconfirmedSpend;
if (!allowUnconfirmedSpend && transactionOutput.getParentTransaction() != null &&
transactionOutput.getParentTransaction().getConfidence() != null) {
final TransactionConfidence.ConfidenceType confidenceType = transactionOutput.getParentTransaction().getConfidence().getConfidenceType();

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@ -23,6 +23,8 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import io.bitsquare.app.Log;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.AddressEntryList;
import io.bitsquare.btc.data.InputsAndChangeOutput;
import io.bitsquare.btc.data.PreparedDepositTxAndOffererInputs;
import io.bitsquare.btc.data.RawTransactionInput;
@ -97,7 +99,7 @@ public class TradeWalletService {
@Nullable
private Wallet wallet;
@Nullable
private BitSquareWalletAppKit walletAppKit;
private WalletConfig walletConfig;
@Nullable
private KeyParameter aesKey;
private AddressEntryList addressEntryList;
@ -113,12 +115,12 @@ public class TradeWalletService {
}
// After WalletService is initialized we get the walletAppKit set
public void setWalletAppKit(BitSquareWalletAppKit walletAppKit) {
this.walletAppKit = walletAppKit;
wallet = walletAppKit.wallet();
public void setWalletConfig(WalletConfig walletConfig) {
this.walletConfig = walletConfig;
wallet = walletConfig.wallet();
}
public void setAesKey(KeyParameter aesKey) {
void setAesKey(KeyParameter aesKey) {
this.aesKey = aesKey;
}
@ -194,7 +196,7 @@ public class TradeWalletService {
* @throws WalletException
*/
public InputsAndChangeOutput takerCreatesDepositsTxInputs(Coin inputAmount, Coin txFee, AddressEntry takersAddressEntry, Address takersChangeAddress) throws
TransactionVerificationException, WalletException, AddressFormatException {
TransactionVerificationException, WalletException {
log.trace("takerCreatesDepositsTxInputs called");
log.trace("inputAmount " + inputAmount.toFriendlyString());
log.trace("txFee " + txFee.toFriendlyString());
@ -506,8 +508,8 @@ public class TradeWalletService {
BtcWalletService.printTx("depositTx", depositTx);
// Broadcast depositTx
checkNotNull(walletAppKit);
ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(depositTx).future();
checkNotNull(walletConfig);
ListenableFuture<Transaction> broadcastComplete = walletConfig.peerGroup().broadcastTransaction(depositTx).future();
Futures.addCallback(broadcastComplete, callback);
return depositTx;
@ -947,8 +949,8 @@ public class TradeWalletService {
verifyTransaction(payoutTx);
checkWalletConsistency();
if (walletAppKit != null) {
ListenableFuture<Transaction> future = walletAppKit.peerGroup().broadcastTransaction(payoutTx).future();
if (walletConfig != null) {
ListenableFuture<Transaction> future = walletConfig.peerGroup().broadcastTransaction(payoutTx).future();
Futures.addCallback(future, callback);
}
@ -965,8 +967,8 @@ public class TradeWalletService {
* @param callback
*/
public void broadcastTx(Transaction tx, FutureCallback<Transaction> callback) {
checkNotNull(walletAppKit);
ListenableFuture<Transaction> future = walletAppKit.peerGroup().broadcastTransaction(tx).future();
checkNotNull(walletConfig);
ListenableFuture<Transaction> future = walletConfig.peerGroup().broadcastTransaction(tx).future();
Futures.addCallback(future, callback);
}
@ -1025,23 +1027,23 @@ public class TradeWalletService {
}
public ListenableFuture<StoredBlock> getBlockHeightFuture(Transaction transaction) {
checkNotNull(walletAppKit);
return walletAppKit.chain().getHeightFuture((int) transaction.getLockTime());
checkNotNull(walletConfig);
return walletConfig.chain().getHeightFuture((int) transaction.getLockTime());
}
public int getBestChainHeight() {
checkNotNull(walletAppKit);
return walletAppKit.chain().getBestChainHeight();
checkNotNull(walletConfig);
return walletConfig.chain().getBestChainHeight();
}
public void addBlockChainListener(BlockChainListener blockChainListener) {
checkNotNull(walletAppKit);
walletAppKit.chain().addListener(blockChainListener);
checkNotNull(walletConfig);
walletConfig.chain().addListener(blockChainListener);
}
public void removeBlockChainListener(BlockChainListener blockChainListener) {
checkNotNull(walletAppKit);
walletAppKit.chain().removeListener(blockChainListener);
checkNotNull(walletConfig);
walletConfig.chain().removeListener(blockChainListener);
}
@ -1206,7 +1208,7 @@ public class TradeWalletService {
this.addressEntryList = addressEntryList;
}
public List<AddressEntry> getAddressEntryListAsImmutableList() {
private List<AddressEntry> getAddressEntryListAsImmutableList() {
return ImmutableList.copyOf(addressEntryList);
}

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.AbstractIdleService;
@ -23,6 +23,7 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy;
import com.subgraph.orchid.TorClient;
import io.bitsquare.btc.ProxySocketFactory;
import org.bitcoinj.core.*;
import org.bitcoinj.net.BlockingClientManager;
import org.bitcoinj.net.discovery.DnsDiscovery;
@ -35,6 +36,7 @@ import org.bitcoinj.store.WalletProtobufSerializer;
import org.bitcoinj.wallet.DeterministicSeed;
import org.bitcoinj.wallet.KeyChainGroup;
import org.bitcoinj.wallet.Protos;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -52,39 +54,41 @@ import java.util.concurrent.TimeoutException;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
public class BitSquareWalletAppKit extends AbstractIdleService {
private static final Logger log = LoggerFactory.getLogger(BitSquareWalletAppKit.class);
// Derived from WalletAppKit
public class WalletConfig extends AbstractIdleService {
private static final Logger log = LoggerFactory.getLogger(WalletConfig.class);
protected final String walletFilePrefix;
protected final String tokenWalletFilePrefix;
protected volatile Wallet vWallet;
protected volatile Wallet vTokenWallet;
protected volatile File vWalletFile;
protected volatile File vTokenWalletFile;
private final String walletFilePrefix;
private final String tokenWalletFilePrefix;
private volatile Wallet vWallet;
private volatile Wallet vTokenWallet;
private volatile File vWalletFile;
private volatile File vTokenWalletFile;
@Nullable
protected DeterministicSeed restoreWalletFromSeed;
private DeterministicSeed btcSeed;
@Nullable
protected DeterministicSeed restoreTokenWalletFromSeed;
private DeterministicSeed squSeed;
protected final NetworkParameters params;
protected volatile BlockChain vChain;
protected volatile BlockStore vStore;
protected volatile PeerGroup vPeerGroup;
protected final File directory;
protected boolean useAutoSave = true;
protected PeerAddress[] peerAddresses;
protected PeerEventListener downloadListener;
protected boolean autoStop = true;
protected InputStream checkpoints;
protected boolean blockingStartup = true;
protected boolean useTor = false; // Perhaps in future we can change this to true.
protected String userAgent, version;
protected WalletProtobufSerializer.WalletFactory walletFactory;
final NetworkParameters params;
private volatile BlockChain vChain;
private volatile BlockStore vStore;
private volatile PeerGroup vPeerGroup;
private final File directory;
private boolean useAutoSave = true;
private PeerAddress[] peerAddresses;
private PeerEventListener downloadListener;
private boolean autoStop = true;
private InputStream checkpoints;
private boolean blockingStartup = true;
private boolean useTor = false; // Perhaps in future we can change this to true.
private String userAgent;
private String version;
private WalletProtobufSerializer.WalletFactory walletFactory;
@Nullable
protected PeerDiscovery discovery;
private PeerDiscovery discovery;
protected volatile Context context;
private final Context context;
private long bloomFilterTweak = 0;
private double bloomFilterFPRate = -1;
private int lookaheadSize = -1;
@ -94,7 +98,7 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
/**
* Creates a new WalletAppKitBitSquare, with a newly created {@link Context}. Files will be stored in the given directory.
*/
public BitSquareWalletAppKit(NetworkParameters params, Socks5Proxy socks5Proxy, File directory, String walletFilePrefix, String tokenWalletFilePrefix) {
public WalletConfig(NetworkParameters params, Socks5Proxy socks5Proxy, File directory, String walletFilePrefix, String tokenWalletFilePrefix) {
this(new Context(params), directory, walletFilePrefix, tokenWalletFilePrefix);
this.socks5Proxy = socks5Proxy;
}
@ -102,21 +106,21 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
/**
* Creates a new WalletAppKitBitSquare, with a newly created {@link Context}. Files will be stored in the given directory.
*/
public BitSquareWalletAppKit(NetworkParameters params, File directory, String walletFilePrefix, String tokenWalletFilePrefix) {
private WalletConfig(NetworkParameters params, File directory, String walletFilePrefix, String tokenWalletFilePrefix) {
this(new Context(params), directory, walletFilePrefix, tokenWalletFilePrefix);
}
/**
* Creates a new WalletAppKitBitSquare, with the given {@link Context}. Files will be stored in the given directory.
*/
public BitSquareWalletAppKit(Context context, File directory, String walletFilePrefix, String tokenWalletFilePrefix) {
private WalletConfig(Context context, File directory, String walletFilePrefix, String tokenWalletFilePrefix) {
this.context = context;
this.params = checkNotNull(context.getParams());
this.directory = checkNotNull(directory);
this.walletFilePrefix = checkNotNull(walletFilePrefix);
this.tokenWalletFilePrefix = tokenWalletFilePrefix;
if (!Utils.isAndroidRuntime()) {
InputStream stream = BitSquareWalletAppKit.class.getResourceAsStream("/" + params.getId() + ".checkpoints");
InputStream stream = WalletConfig.class.getResourceAsStream("/" + params.getId() + ".checkpoints");
if (stream != null)
setCheckpoints(stream);
}
@ -126,7 +130,7 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
return socks5Proxy;
}
protected PeerGroup createPeerGroup() throws TimeoutException {
private PeerGroup createPeerGroup() throws TimeoutException {
// no proxy case.
if (socks5Proxy == null) {
if (useTor) {
@ -157,7 +161,7 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
/**
* Will only connect to the given addresses. Cannot be called after startup.
*/
public BitSquareWalletAppKit setPeerNodes(PeerAddress... addresses) {
public WalletConfig setPeerNodes(PeerAddress... addresses) {
checkState(state() == State.NEW, "Cannot call after startup");
this.peerAddresses = addresses;
return this;
@ -166,7 +170,7 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
/**
* Will only connect to localhost. Cannot be called after startup.
*/
public BitSquareWalletAppKit connectToLocalHost() {
public WalletConfig connectToLocalHost() {
try {
final InetAddress localHost = InetAddress.getLocalHost();
return setPeerNodes(new PeerAddress(localHost, params.getPort()));
@ -179,7 +183,7 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
/**
* If true, the wallet will save itself to disk automatically whenever it changes.
*/
public BitSquareWalletAppKit setAutoSave(boolean value) {
public WalletConfig setAutoSave(boolean value) {
checkState(state() == State.NEW, "Cannot call after startup");
useAutoSave = value;
return this;
@ -190,7 +194,7 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
* {@link org.bitcoinj.core.DownloadProgressTracker} is a good choice. This has no effect unless setBlockingStartup(false) has been called
* too, due to some missing implementation code.
*/
public BitSquareWalletAppKit setDownloadListener(PeerEventListener listener) {
public WalletConfig setDownloadListener(PeerEventListener listener) {
this.downloadListener = listener;
return this;
}
@ -198,7 +202,7 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
/**
* If true, will register a shutdown hook to stop the library. Defaults to true.
*/
public BitSquareWalletAppKit setAutoStop(boolean autoStop) {
public WalletConfig setAutoStop(boolean autoStop) {
this.autoStop = autoStop;
return this;
}
@ -207,7 +211,7 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
* If set, the file is expected to contain a checkpoints file calculated with BuildCheckpoints. It makes initial
* block sync faster for new users - please refer to the documentation on the bitcoinj website for further details.
*/
public BitSquareWalletAppKit setCheckpoints(InputStream checkpoints) {
public WalletConfig setCheckpoints(InputStream checkpoints) {
if (this.checkpoints != null)
Utils.closeUnchecked(this.checkpoints);
this.checkpoints = checkNotNull(checkpoints);
@ -216,11 +220,11 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
/**
* If true (the default) then the startup of this service won't be considered complete until the network has been
* brought up, peer connections established and the block chain synchronised. Therefore {@link #startAndWait()} can
* brought up, peer connections established and the block chain synchronised. Therefore startAndWait() can
* potentially take a very long time. If false, then startup is considered complete once the network activity
* begins and peer connections/block chain sync will continue in the background.
*/
public BitSquareWalletAppKit setBlockingStartup(boolean blockingStartup) {
public WalletConfig setBlockingStartup(boolean blockingStartup) {
this.blockingStartup = blockingStartup;
return this;
}
@ -231,7 +235,7 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
* @param userAgent A short string that should be the name of your app, e.g. "My Wallet"
* @param version A short string that contains the version number, e.g. "1.0-BETA"
*/
public BitSquareWalletAppKit setUserAgent(String userAgent, String version) {
public WalletConfig setUserAgent(String userAgent, String version) {
this.userAgent = checkNotNull(userAgent);
this.version = checkNotNull(version);
return this;
@ -241,7 +245,7 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
* If called, then an embedded Tor client library will be used to connect to the P2P network. The user does not need
* any additional software for this: it's all pure Java. As of April 2014 <b>this mode is experimental</b>.
*/
public BitSquareWalletAppKit useTor() {
public WalletConfig useTor() {
this.useTor = true;
return this;
}
@ -254,35 +258,35 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
* up the new kit. The next time your app starts it should work as normal (that is, don't keep calling this each
* time).
*/
public BitSquareWalletAppKit restoreWalletFromSeed(DeterministicSeed seed) {
this.restoreWalletFromSeed = seed;
public WalletConfig restoreWalletFromSeed(DeterministicSeed seed) {
this.btcSeed = seed;
return this;
}
public BitSquareWalletAppKit restoreTokenWalletFromSeed(DeterministicSeed seed) {
this.restoreTokenWalletFromSeed = seed;
public WalletConfig restoreSquWalletFromSeed(DeterministicSeed seed) {
this.squSeed = seed;
return this;
}
/**
* Sets the peer discovery class to use. If none is provided then DNS is used, which is a reasonable default.
*/
public BitSquareWalletAppKit setDiscovery(@Nullable PeerDiscovery discovery) {
public WalletConfig setDiscovery(@Nullable PeerDiscovery discovery) {
this.discovery = discovery;
return this;
}
public BitSquareWalletAppKit setBloomFilterFalsePositiveRate(double bloomFilterFPRate) {
public WalletConfig setBloomFilterFalsePositiveRate(double bloomFilterFPRate) {
this.bloomFilterFPRate = bloomFilterFPRate;
return this;
}
public BitSquareWalletAppKit setBloomFilterTweak(long bloomFilterTweak) {
public WalletConfig setBloomFilterTweak(long bloomFilterTweak) {
this.bloomFilterTweak = bloomFilterTweak;
return this;
}
public BitSquareWalletAppKit setLookaheadSize(int lookaheadSize) {
public WalletConfig setLookaheadSize(int lookaheadSize) {
this.lookaheadSize = lookaheadSize;
return this;
}
@ -293,14 +297,14 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
* <p>When this is called, chain(), store(), and peerGroup() will return the created objects, however they are not
* initialized/started.</p>
*/
protected List<WalletExtension> provideWalletExtensions() throws Exception {
private List<WalletExtension> provideWalletExtensions() {
return ImmutableList.of();
}
/**
* Override this to use a {@link BlockStore} that isn't the default of {@link SPVBlockStore}.
*/
protected BlockStore provideBlockStore(File file) throws BlockStoreException {
private BlockStore provideBlockStore(File file) throws BlockStoreException {
return new SPVBlockStore(params, file);
}
@ -308,7 +312,7 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
* This method is invoked on a background thread after all objects are initialised, but before the peer group
* or block chain download is started. You can tweak the objects configuration here.
*/
protected void onSetupCompleted() {
void onSetupCompleted() {
}
/**
@ -349,35 +353,34 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
try {
File chainFile = new File(directory, walletFilePrefix + ".spvchain");
boolean chainFileExists = chainFile.exists();
vWalletFile = new File(directory, walletFilePrefix + ".wallet");
boolean shouldReplayWallet = (vWalletFile.exists() && !chainFileExists) || restoreWalletFromSeed != null;
vWalletFile = new File(directory, walletFilePrefix + ".wallet");
boolean shouldReplayBtcWallet = (vWalletFile.exists() && !chainFileExists) || btcSeed != null;
BitsquareKeyChainGroup keyChainGroup;
if (restoreWalletFromSeed != null)
keyChainGroup = new BitsquareKeyChainGroup(params, restoreWalletFromSeed, true);
if (btcSeed != null)
keyChainGroup = new BitsquareKeyChainGroup(params, btcSeed, true);
else
keyChainGroup = new BitsquareKeyChainGroup(params, true);
vWallet = createOrLoadWallet(vWalletFile, shouldReplayWallet, restoreWalletFromSeed, keyChainGroup);
vWallet = createOrLoadWallet(vWalletFile, shouldReplayBtcWallet, btcSeed, squSeed, keyChainGroup);
vTokenWalletFile = new File(directory, tokenWalletFilePrefix + ".wallet");
boolean shouldReplayTokenWallet = (vTokenWalletFile.exists() && !chainFileExists) || restoreTokenWalletFromSeed != null;
if (restoreWalletFromSeed != null)
keyChainGroup = new BitsquareKeyChainGroup(params, restoreWalletFromSeed, false);
boolean shouldReplaySquWallet = (vTokenWalletFile.exists() && !chainFileExists) || squSeed != null;
if (squSeed != null)
keyChainGroup = new BitsquareKeyChainGroup(params, squSeed, false);
else
keyChainGroup = new BitsquareKeyChainGroup(params, false);
vTokenWallet = createOrLoadWallet(vTokenWalletFile, shouldReplayTokenWallet, restoreTokenWalletFromSeed, keyChainGroup);
vTokenWallet = createOrLoadWallet(vTokenWalletFile, shouldReplaySquWallet, btcSeed, squSeed, keyChainGroup);
// Initiate Bitcoin network objects (block store, blockchain and peer group)
vStore = provideBlockStore(chainFile);
if (!chainFileExists || restoreWalletFromSeed != null || restoreTokenWalletFromSeed != null) {
if (!chainFileExists || btcSeed != null || squSeed != null) {
if (checkpoints != null) {
// Initialize the chain file with a checkpoint to speed up first-run sync.
long time;
if (restoreWalletFromSeed != null || restoreTokenWalletFromSeed != null) {
if (btcSeed != null || squSeed != null) {
// we created both wallets at the same time
time = restoreWalletFromSeed.getCreationTimeSeconds();
time = btcSeed.getCreationTimeSeconds();
if (chainFileExists) {
log.info("Deleting the chain file in preparation from restore.");
vStore.close();
@ -447,7 +450,7 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
}
@Override
public void onFailure(Throwable t) {
public void onFailure(@NotNull Throwable t) {
throw new RuntimeException(t);
}
@ -458,10 +461,13 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
}
}
private Wallet createOrLoadWallet(File walletFile, boolean shouldReplayWallet, DeterministicSeed restoreFromSeed, BitsquareKeyChainGroup keyChainGroup) throws Exception {
private Wallet createOrLoadWallet(File walletFile, boolean shouldReplayWallet, @Nullable DeterministicSeed restoreFromBtcSeed, @Nullable DeterministicSeed restoreFromSquSeed, BitsquareKeyChainGroup keyChainGroup) throws Exception {
Wallet wallet;
maybeMoveOldWalletOutOfTheWay(walletFile, restoreFromSeed);
if (restoreFromBtcSeed != null)
maybeMoveOldWalletOutOfTheWay(walletFile, restoreFromBtcSeed);
if (restoreFromSquSeed != null)
maybeMoveOldWalletOutOfTheWay(walletFile, restoreFromSquSeed);
if (walletFile.exists()) {
wallet = loadWallet(walletFile, shouldReplayWallet, keyChainGroup.isUseBitcoinDeterministicKeyChain());
@ -507,7 +513,7 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
return wallet;
}
protected Wallet createWallet(KeyChainGroup keyChainGroup) {
private Wallet createWallet(KeyChainGroup keyChainGroup) {
if (lookaheadSize != -1)
keyChainGroup.setLookaheadSize(lookaheadSize);
@ -540,8 +546,8 @@ public class BitSquareWalletAppKit extends AbstractIdleService {
@Override
public void run() {
try {
BitSquareWalletAppKit.this.stopAsync();
BitSquareWalletAppKit.this.awaitTerminated();
WalletConfig.this.stopAsync();
WalletConfig.this.awaitTerminated();
} catch (Exception e) {
throw new RuntimeException(e);
}

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
@ -30,6 +30,7 @@ import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.user.Preferences;
import org.bitcoinj.core.*;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.KeyCrypterScrypt;
import org.bitcoinj.crypto.TransactionSignature;
import org.bitcoinj.script.Script;
import org.bitcoinj.signers.TransactionSigner;
@ -56,49 +57,74 @@ import static com.google.common.base.Preconditions.checkState;
* It startup the wallet app kit and initialized the wallet.
*/
public abstract class WalletService {
protected static final Logger log = LoggerFactory.getLogger(WalletService.class);
private static final Logger log = LoggerFactory.getLogger(WalletService.class);
protected final CopyOnWriteArraySet<AddressConfidenceListener> addressConfidenceListeners = new CopyOnWriteArraySet<>();
protected final CopyOnWriteArraySet<TxConfidenceListener> txConfidenceListeners = new CopyOnWriteArraySet<>();
protected final CopyOnWriteArraySet<BalanceListener> balanceListeners = new CopyOnWriteArraySet<>();
private final CopyOnWriteArraySet<AddressConfidenceListener> addressConfidenceListeners = new CopyOnWriteArraySet<>();
private final CopyOnWriteArraySet<TxConfidenceListener> txConfidenceListeners = new CopyOnWriteArraySet<>();
private final CopyOnWriteArraySet<BalanceListener> balanceListeners = new CopyOnWriteArraySet<>();
protected final WalletEventListener walletEventListener = new BitsquareWalletEventListener();
protected final NetworkParameters params;
final WalletEventListener walletEventListener = new BitsquareWalletEventListener();
final NetworkParameters params;
protected WalletSetup walletSetup;
protected final Preferences preferences;
protected final FeeService feeService;
protected Wallet wallet;
final WalletsSetup walletsSetup;
private final Preferences preferences;
private final FeeService feeService;
Wallet wallet;
KeyParameter aesKey;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public WalletService(WalletSetup walletSetup,
WalletService(WalletsSetup walletsSetup,
Preferences preferences,
FeeService feeService) {
this.walletSetup = walletSetup;
this.walletsSetup = walletsSetup;
this.preferences = preferences;
this.feeService = feeService;
params = walletSetup.getParams();
params = walletsSetup.getParams();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected Methods
///////////////////////////////////////////////////////////////////////////////////////////
void decryptWallet(@NotNull KeyParameter key) {
wallet.decrypt(key);
aesKey = null;
}
void encryptWallet(KeyCrypterScrypt keyCrypterScrypt, KeyParameter key) {
if (this.aesKey != null) {
log.warn("encryptWallet called but we have a aesKey already set. " +
"We decryptWallet with the old key before we apply the new key.");
decryptWallet(this.aesKey);
}
wallet.encrypt(keyCrypterScrypt, key);
aesKey = key;
}
void setAesKey(KeyParameter aesKey) {
this.aesKey = aesKey;
}
abstract String getWalletAsString(boolean includePrivKeys);
///////////////////////////////////////////////////////////////////////////////////////////
// Public Methods
///////////////////////////////////////////////////////////////////////////////////////////
public void shutDown() {
if (wallet != null)
wallet.removeEventListener(walletEventListener);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Listener
///////////////////////////////////////////////////////////////////////////////////////////
@ -132,7 +158,7 @@ public abstract class WalletService {
// Checks
///////////////////////////////////////////////////////////////////////////////////////////
protected void checkWalletConsistency() throws WalletException {
void checkWalletConsistency() throws WalletException {
try {
log.trace("Check if wallet is consistent before commit.");
checkNotNull(wallet);
@ -144,7 +170,7 @@ public abstract class WalletService {
}
}
protected void verifyTransaction(Transaction transaction) throws TransactionVerificationException {
void verifyTransaction(Transaction transaction) throws TransactionVerificationException {
try {
log.trace("Verify transaction " + transaction);
transaction.verify();
@ -155,13 +181,13 @@ public abstract class WalletService {
}
}
protected void checkScriptSigs(Transaction transaction) throws TransactionVerificationException {
void checkScriptSigs(Transaction transaction) throws TransactionVerificationException {
for (int i = 0; i < transaction.getInputs().size(); i++) {
checkScriptSig(transaction, transaction.getInputs().get(i), i);
}
}
protected void checkScriptSig(Transaction transaction, TransactionInput input, int inputIndex) throws TransactionVerificationException {
void checkScriptSig(Transaction transaction, TransactionInput input, int inputIndex) throws TransactionVerificationException {
try {
log.trace("Verifies that this script (interpreted as a scriptSig) correctly spends the given scriptPubKey. Check input at index: " + inputIndex);
checkNotNull(input.getConnectedOutput(), "input.getConnectedOutput() must not be null");
@ -177,6 +203,7 @@ public abstract class WalletService {
// Sign tx
///////////////////////////////////////////////////////////////////////////////////////////
//TODOcheck with signTransactionInput
/* protected void signInput(Transaction transaction) throws SigningException {
List<TransactionInput> inputs = transaction.getInputs();
@ -189,9 +216,9 @@ public abstract class WalletService {
ECKey sigKey = input.getOutpoint().getConnectedKey(wallet);
checkNotNull(sigKey, "signInput: sigKey must not be null. input.getOutpoint()=" + input.getOutpoint().toString());
if (sigKey.isEncrypted())
checkNotNull(walletSetup.getAesKey());
checkNotNull(aesKey);
Sha256Hash hash = transaction.hashForSignature(inputIndex, scriptPubKey, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature signature = sigKey.sign(hash, walletSetup.getAesKey());
ECKey.ECDSASignature signature = sigKey.sign(hash, aesKey);
TransactionSignature txSig = new TransactionSignature(signature, Transaction.SigHash.ALL, false);
if (scriptPubKey.isSentToRawPubKey()) {
input.setScriptSig(ScriptBuilder.createInputScript(txSig));
@ -202,8 +229,8 @@ public abstract class WalletService {
}
}*/
public void signTransactionInput(Transaction tx, TransactionInput txIn, int index) {
KeyBag maybeDecryptingKeyBag = new DecryptingKeyBag(wallet, walletSetup.getAesKey());
void signTransactionInput(Transaction tx, TransactionInput txIn, int index) {
KeyBag maybeDecryptingKeyBag = new DecryptingKeyBag(wallet, aesKey);
if (txIn.getConnectedOutput() != null) {
try {
// We assume if its already signed, its hopefully got a SIGHASH type that will not invalidate when
@ -297,7 +324,7 @@ public abstract class WalletService {
return null;
}
protected TransactionConfidence getTransactionConfidence(Transaction tx, Address address) {
private TransactionConfidence getTransactionConfidence(Transaction tx, Address address) {
List<TransactionOutput> mergedOutputs = getOutputsWithConnectedOutputs(tx);
List<TransactionConfidence> transactionConfidenceList = new ArrayList<>();
@ -312,7 +339,7 @@ public abstract class WalletService {
}
protected List<TransactionOutput> getOutputsWithConnectedOutputs(Transaction tx) {
private List<TransactionOutput> getOutputsWithConnectedOutputs(Transaction tx) {
List<TransactionOutput> transactionOutputs = tx.getOutputs();
List<TransactionOutput> connectedOutputs = new ArrayList<>();
@ -332,7 +359,7 @@ public abstract class WalletService {
}
protected TransactionConfidence getMostRecentConfidence(List<TransactionConfidence> transactionConfidenceList) {
private TransactionConfidence getMostRecentConfidence(List<TransactionConfidence> transactionConfidenceList) {
TransactionConfidence transactionConfidence = null;
for (TransactionConfidence confidence : transactionConfidenceList) {
if (confidence != null) {
@ -363,7 +390,7 @@ public abstract class WalletService {
return wallet != null ? getBalance(wallet.calculateAllSpendCandidates(), address) : Coin.ZERO;
}
protected Coin getBalance(List<TransactionOutput> transactionOutputs, Address address) {
private Coin getBalance(List<TransactionOutput> transactionOutputs, Address address) {
Coin balance = Coin.ZERO;
for (TransactionOutput transactionOutput : transactionOutputs) {
if (transactionOutput.getScriptPubKey().isSentToAddress() || transactionOutput.getScriptPubKey().isPayToScriptHash()) {
@ -389,7 +416,7 @@ public abstract class WalletService {
return outputs;
}
protected Coin getTxFeeForWithdrawalPerByte() {
Coin getTxFeeForWithdrawalPerByte() {
Coin fee = (preferences.getUseCustomWithdrawalTxFee()) ?
Coin.valueOf(preferences.getWithdrawalTxFeeInBytes()) :
feeService.getTxFeePerByte();
@ -460,7 +487,7 @@ public abstract class WalletService {
///////////////////////////////////////////////////////////////////////////////////////////
protected class BitsquareWalletEventListener extends AbstractWalletEventListener {
class BitsquareWalletEventListener extends AbstractWalletEventListener {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
notifyBalanceListeners(tx);
@ -490,7 +517,7 @@ public abstract class WalletService {
txConfidenceListener.onTransactionConfidenceChanged(tx.getConfidence()));
}
protected void notifyBalanceListeners(Transaction tx) {
void notifyBalanceListeners(Transaction tx) {
for (BalanceListener balanceListener : balanceListeners) {
Coin balance;
if (balanceListener.getAddress() != null)

View file

@ -0,0 +1,135 @@
/*
* 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.btc.wallet;
import com.google.inject.Inject;
import io.bitsquare.common.handlers.ExceptionHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.crypto.ScryptUtil;
import org.bitcoinj.core.Wallet;
import org.bitcoinj.crypto.KeyCrypter;
import org.bitcoinj.crypto.KeyCrypterScrypt;
import org.bitcoinj.wallet.DeterministicSeed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.crypto.params.KeyParameter;
import javax.annotation.Nullable;
public class WalletsManager {
private static final Logger log = LoggerFactory.getLogger(WalletsManager.class);
private final BtcWalletService btcWalletService;
private final TradeWalletService tradeWalletService;
private final SquWalletService squWalletService;
private final WalletsSetup walletsSetup;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public WalletsManager(BtcWalletService btcWalletService, TradeWalletService tradeWalletService, SquWalletService squWalletService, WalletsSetup walletsSetup) {
this.btcWalletService = btcWalletService;
this.tradeWalletService = tradeWalletService;
this.squWalletService = squWalletService;
this.walletsSetup = walletsSetup;
}
public void decryptWallets(KeyParameter aesKey) {
btcWalletService.decryptWallet(aesKey);
squWalletService.decryptWallet(aesKey);
tradeWalletService.setAesKey(null);
}
public void encryptWallets(KeyCrypterScrypt keyCrypterScrypt, KeyParameter aesKey) {
squWalletService.encryptWallet(keyCrypterScrypt, aesKey);
btcWalletService.encryptWallet(keyCrypterScrypt, aesKey);
// we save the key for the trade wallet as we don't require passwords here
tradeWalletService.setAesKey(aesKey);
}
public String getWalletsAsString(boolean includePrivKeys) {
return "BTC Wallet:\n" +
btcWalletService.getWalletAsString(includePrivKeys) +
"\n\nSQU Wallet:\n" +
squWalletService.getWalletAsString(includePrivKeys);
}
public void restoreSeedWords(@Nullable DeterministicSeed btcSeed, @Nullable DeterministicSeed squSeed, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
walletsSetup.restoreSeedWords(btcSeed, squSeed, resultHandler, exceptionHandler);
}
public void backupWallets() {
walletsSetup.backupWallets();
}
public void clearBackup() {
walletsSetup.clearBackups();
}
public boolean areWalletsEncrypted() {
return getBtcWallet() != null && getBtcWallet().isEncrypted();
}
public boolean areWalletsAvailable() {
return getBtcWallet() != null;
}
private Wallet getBtcWallet() {
return btcWalletService.getWallet();
}
public KeyCrypterScrypt getKeyCrypterScrypt() {
if (areWalletsEncrypted())
return (KeyCrypterScrypt) getBtcWallet().getKeyCrypter();
else
return ScryptUtil.getKeyCrypterScrypt();
}
public boolean checkAESKey(KeyParameter aesKey) {
return getBtcWallet() != null && getBtcWallet().checkAESKey(aesKey);
}
public long getChainSeedCreationTimeSeconds() {
return getBtcWallet() != null ? getBtcWallet().getKeyChainSeed().getCreationTimeSeconds() : 0;
}
public boolean hasPositiveBalance() {
return getBtcWallet() != null &&
(getBtcWallet().getBalance(Wallet.BalanceType.AVAILABLE).value > 0 ||
squWalletService.getWallet().getBalance(Wallet.BalanceType.AVAILABLE).value > 0);
}
public void setAesKey(KeyParameter aesKey) {
btcWalletService.setAesKey(aesKey);
squWalletService.setAesKey(aesKey);
tradeWalletService.setAesKey(aesKey);
}
public DeterministicSeed getDecryptedSeed(KeyParameter aesKey, Wallet wallet) {
KeyCrypter btcKeyCrypter = wallet.getKeyCrypter();
if (btcKeyCrypter != null) {
DeterministicSeed btcKeyChainSeed = wallet.getKeyChainSeed();
return btcKeyChainSeed.decrypt(btcKeyCrypter, "", aesKey);
} else {
log.warn("keyCrypter is null");
return null;
}
}
}

View file

@ -15,13 +15,13 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
package io.bitsquare.btc.wallet;
import com.google.common.util.concurrent.Service;
import com.google.inject.Inject;
import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy;
import io.bitsquare.app.Log;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.btc.*;
import io.bitsquare.common.Timer;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.ExceptionHandler;
@ -32,8 +32,6 @@ import io.bitsquare.storage.Storage;
import io.bitsquare.user.Preferences;
import javafx.beans.property.*;
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;
@ -57,8 +55,10 @@ import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class WalletSetup {
private static final Logger log = LoggerFactory.getLogger(WalletSetup.class);
import static com.google.common.base.Preconditions.checkArgument;
public class WalletsSetup {
private static final Logger log = LoggerFactory.getLogger(WalletsSetup.class);
private static final long STARTUP_TIMEOUT_SEC = 60;
@ -67,15 +67,14 @@ public class WalletSetup {
private final AddressEntryList addressEntryList;
private final UserAgent userAgent;
private final Preferences preferences;
private final FeeService feeService;
private final Socks5ProxyProvider socks5ProxyProvider;
private final NetworkParameters params;
private final File walletDir;
private BitSquareWalletAppKit walletAppKit;
private Wallet wallet;
private Wallet tokenWallet;
private String walletFileName = "Bitsquare";
private String tokenWalletFileName = "SQU";
private WalletConfig walletConfig;
private Wallet btcWallet;
private Wallet squWallet;
private final String walletFileName = "Bitsquare";
private final String tokenWalletFileName = "SQU";
private final Long bloomFilterTweak;
private KeyParameter aesKey;
private final Storage<Long> storage;
@ -84,16 +83,15 @@ public class WalletSetup {
private final ObjectProperty<List<Peer>> connectedPeers = new SimpleObjectProperty<>();
private final DownloadListener downloadListener = new DownloadListener();
// private final WalletEventListener walletEventListener = new BitsquareWalletEventListener();
private List<Runnable> setupCompletedHandlers = new ArrayList<>();
private final List<Runnable> setupCompletedHandlers = new ArrayList<>();
@Inject
public WalletSetup(RegTestHost regTestHost,
public WalletsSetup(RegTestHost regTestHost,
TradeWalletService tradeWalletService,
AddressEntryList addressEntryList,
UserAgent userAgent,
Preferences preferences,
FeeService feeService,
Socks5ProxyProvider socks5ProxyProvider,
@Named(BtcOptionKeys.WALLET_DIR) File appDir) {
@ -102,7 +100,6 @@ public class WalletSetup {
this.addressEntryList = addressEntryList;
this.userAgent = userAgent;
this.preferences = preferences;
this.feeService = feeService;
this.socks5ProxyProvider = socks5ProxyProvider;
params = preferences.getBitcoinNetwork().getParameters();
@ -118,7 +115,7 @@ public class WalletSetup {
}
}
public void initialize(@Nullable DeterministicSeed seed, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
public void initialize(@Nullable DeterministicSeed btcSeed, @Nullable DeterministicSeed squSeed, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
Log.traceCall();
// Tell bitcoinj to execute event handlers on the JavaFX UI thread. This keeps things simple and means
@ -138,26 +135,26 @@ public class WalletSetup {
log.debug("Use socks5Proxy for bitcoinj: " + socks5Proxy);
// If seed is non-null it means we are restoring from backup.
walletAppKit = new BitSquareWalletAppKit(params, socks5Proxy, walletDir, walletFileName, tokenWalletFileName) {
walletConfig = new WalletConfig(params, socks5Proxy, walletDir, walletFileName, tokenWalletFileName) {
@Override
protected void onSetupCompleted() {
wallet = walletAppKit.wallet();
tokenWallet = walletAppKit.tokenWallet();
btcWallet = walletConfig.wallet();
squWallet = walletConfig.tokenWallet();
// Don't make the user wait for confirmations for now, as the intention is they're sending it
// their own money!
wallet.allowSpendingUnconfirmedTransactions();
tokenWallet.allowSpendingUnconfirmedTransactions();
btcWallet.allowSpendingUnconfirmedTransactions();
squWallet.allowSpendingUnconfirmedTransactions();
if (params != RegTestParams.get())
walletAppKit.peerGroup().setMaxConnections(11);
walletConfig.peerGroup().setMaxConnections(11);
// wallet.addEventListener(walletEventListener);
addressEntryList.onWalletReady(wallet);
addressEntryList.onWalletReady(btcWallet);
walletAppKit.peerGroup().addEventListener(new PeerEventListener() {
walletConfig.peerGroup().addEventListener(new PeerEventListener() {
@Override
public void onPeersDiscovered(Set<PeerAddress> peerAddresses) {
}
@ -173,13 +170,13 @@ public class WalletSetup {
@Override
public void onPeerConnected(Peer peer, int peerCount) {
numPeers.set(peerCount);
connectedPeers.set(walletAppKit.peerGroup().getConnectedPeers());
connectedPeers.set(walletConfig.peerGroup().getConnectedPeers());
}
@Override
public void onPeerDisconnected(Peer peer, int peerCount) {
numPeers.set(peerCount);
connectedPeers.set(walletAppKit.peerGroup().getConnectedPeers());
connectedPeers.set(walletConfig.peerGroup().getConnectedPeers());
}
@Override
@ -199,7 +196,7 @@ public class WalletSetup {
});
// set after wallet is ready
tradeWalletService.setWalletAppKit(walletAppKit);
tradeWalletService.setWalletConfig(walletConfig);
tradeWalletService.setAddressEntryList(addressEntryList);
timeoutTimer.stop();
@ -216,7 +213,7 @@ public class WalletSetup {
// Bitsquare's BitcoinJ fork has added a bloomFilterTweak (nonce) setter to reuse the same seed avoiding the trivial vulnerability
// by getting the real pub keys by intersections of several filters sent at each startup.
walletAppKit.setBloomFilterTweak(bloomFilterTweak);
walletConfig.setBloomFilterTweak(bloomFilterTweak);
// Avoid the simple attack (see: https://jonasnick.github.io/blog/2015/02/12/privacy-in-bitcoinj/) due to the
// default implementation using both pubkey and hash of pubkey. We have set a insertPubKey flag in BasicKeyChain to default false.
@ -225,7 +222,7 @@ public class WalletSetup {
// the threshold. To avoid reaching the threshold we create much more keys which are unlikely to cause update of the
// filter for most users. With lookaheadSize of 500 we get 1333 keys which should be enough for most users to
// never need to update a bloom filter, which would weaken privacy.
walletAppKit.setLookaheadSize(500);
walletConfig.setLookaheadSize(500);
// Calculation is derived from: https://www.reddit.com/r/Bitcoin/comments/2vrx6n/privacy_in_bitcoinj_android_wallet_multibit_hive/coknjuz
// No. of false positives (56M keys in the blockchain):
@ -243,7 +240,7 @@ public class WalletSetup {
// For now to reduce risks with high bandwidth consumption we reduce the FP rate by half.
// FP rate = 0,00005; No. of false positives: 0,00005 * 56 000 000 = 2800
// 1333 / (2800 + 1333) = 0.32 -> 32 % probability that a pub key is in our wallet
walletAppKit.setBloomFilterFalsePositiveRate(0.00005);
walletConfig.setBloomFilterFalsePositiveRate(0.00005);
String btcNodes = preferences.getBitcoinNodes();
log.debug("btcNodes: " + btcNodes);
@ -284,7 +281,7 @@ public class WalletSetup {
PeerAddress peerAddressListFixed[] = new PeerAddress[peerAddressList.size()];
log.debug("btcNodes parsed: " + Arrays.toString(peerAddressListFixed));
walletAppKit.setPeerNodes(peerAddressList.toArray(peerAddressListFixed));
walletConfig.setPeerNodes(peerAddressList.toArray(peerAddressListFixed));
usePeerNodes = true;
}
}
@ -294,13 +291,13 @@ public class WalletSetup {
if (params == RegTestParams.get()) {
if (regTestHost == RegTestHost.REG_TEST_SERVER) {
try {
walletAppKit.setPeerNodes(new PeerAddress(InetAddress.getByName(RegTestHost.SERVER_IP), params.getPort()));
walletConfig.setPeerNodes(new PeerAddress(InetAddress.getByName(RegTestHost.SERVER_IP), params.getPort()));
usePeerNodes = true;
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
} else if (regTestHost == RegTestHost.LOCALHOST) {
walletAppKit.connectToLocalHost(); // You should run a regtest mode bitcoind locally.}
walletConfig.connectToLocalHost(); // You should run a regtest mode bitcoind locally.}
}
} else if (params == MainNetParams.get()) {
// Checkpoints are block headers that ship inside our app: for a new user, we pick the last header
@ -308,13 +305,13 @@ public class WalletSetup {
// Checkpoint files are made using the BuildCheckpoints tool and usually we have to download the
// last months worth or more (takes a few seconds).
try {
walletAppKit.setCheckpoints(getClass().getResourceAsStream("/wallet/checkpoints"));
walletConfig.setCheckpoints(getClass().getResourceAsStream("/wallet/checkpoints"));
} catch (Exception e) {
e.printStackTrace();
log.error(e.toString());
}
} else if (params == TestNet3Params.get()) {
walletAppKit.setCheckpoints(getClass().getResourceAsStream("/wallet/checkpoints.testnet"));
walletConfig.setCheckpoints(getClass().getResourceAsStream("/wallet/checkpoints.testnet"));
}
// If operating over a proxy and we haven't set any peer nodes, then
@ -331,31 +328,35 @@ public class WalletSetup {
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));
walletConfig.setDiscovery(new SeedPeers(params));
}
walletAppKit.setDownloadListener(downloadListener)
walletConfig.setDownloadListener(downloadListener)
.setBlockingStartup(false)
.setUserAgent(userAgent.getName(), userAgent.getVersion())
.restoreWalletFromSeed(seed);
.setUserAgent(userAgent.getName(), userAgent.getVersion());
walletAppKit.addListener(new Service.Listener() {
if (btcSeed != null)
walletConfig.restoreWalletFromSeed(btcSeed);
if (squSeed != null)
walletConfig.restoreSquWalletFromSeed(squSeed);
walletConfig.addListener(new Service.Listener() {
@Override
public void failed(@NotNull Service.State from, @NotNull Throwable failure) {
walletAppKit = null;
walletConfig = null;
log.error("walletAppKit failed");
timeoutTimer.stop();
UserThread.execute(() -> exceptionHandler.handleException(failure));
}
}, Threading.USER_THREAD);
walletAppKit.startAsync();
walletConfig.startAsync();
}
public void shutDown() {
if (walletAppKit != null) {
if (walletConfig != null) {
try {
walletAppKit.stopAsync();
walletAppKit.awaitTerminated(5, TimeUnit.SECONDS);
walletConfig.stopAsync();
walletConfig.awaitTerminated(5, TimeUnit.SECONDS);
} catch (Throwable e) {
// ignore
}
@ -363,12 +364,12 @@ public class WalletSetup {
}
}
public void backupWallets() {
void backupWallets() {
FileUtil.rollingBackup(walletDir, walletFileName + ".wallet", 20);
FileUtil.rollingBackup(walletDir, tokenWalletFileName + ".wallet", 20);
}
public void clearBackup() {
void clearBackups() {
try {
FileUtil.deleteDirectory(new File(Paths.get(walletDir.getAbsolutePath(), "backup").toString()));
} catch (IOException e) {
@ -381,24 +382,20 @@ public class WalletSetup {
setupCompletedHandlers.add(handler);
}
public Wallet getWallet() {
return wallet;
public Wallet getBtcWallet() {
return btcWallet;
}
public Wallet getTokenWallet() {
return tokenWallet;
public Wallet getSquWallet() {
return squWallet;
}
public NetworkParameters getParams() {
return params;
}
public KeyParameter getAesKey() {
return aesKey;
}
public BlockChain chain() {
return walletAppKit.chain();
public BlockChain getChain() {
return walletConfig.chain();
}
public ReadOnlyIntegerProperty numPeersProperty() {
@ -413,66 +410,10 @@ public class WalletSetup {
return downloadListener.percentageProperty();
}
public void setAesKey(KeyParameter aesKey) {
this.aesKey = aesKey;
public PeerGroup getPeerGroup() {
return walletConfig.peerGroup();
}
public void decryptWallets(@NotNull KeyParameter key) {
wallet.decrypt(key);
tokenWallet.decrypt(key);
addressEntryList.stream().forEach(e -> {
final DeterministicKey keyPair = e.getKeyPair();
if (keyPair != null && keyPair.isEncrypted())
e.setDeterministicKey(keyPair.decrypt(key));
});
setAesKey(null);
addressEntryList.queueUpForSave();
}
public void encryptWallets(KeyCrypterScrypt keyCrypterScrypt, KeyParameter key) {
if (this.aesKey != null) {
log.warn("encryptWallet called but we have a aesKey already set. " +
"We decryptWallet with the old key before we apply the new key.");
decryptWallets(this.aesKey);
}
wallet.encrypt(keyCrypterScrypt, key);
tokenWallet.encrypt(keyCrypterScrypt, key);
addressEntryList.stream().forEach(e -> {
final DeterministicKey keyPair = e.getKeyPair();
if (keyPair != null && keyPair.isEncrypted())
e.setDeterministicKey(keyPair.encrypt(keyCrypterScrypt, key));
});
setAesKey(key);
addressEntryList.queueUpForSave();
}
public PeerGroup peerGroup() {
return walletAppKit.peerGroup();
}
/* public String exportWalletData(boolean includePrivKeys) {
StringBuilder addressEntryListData = new StringBuilder();
getAddressEntryListAsImmutableList().stream().forEach(e -> addressEntryListData.append(e.toString()).append("\n"));
return "BitcoinJ wallet:\n" +
wallet.toString(includePrivKeys, true, true, walletAppKit.chain()) + "\n\n" +
"Bitsquare address entry list:\n" +
addressEntryListData.toString() +
"All pubkeys as hex:\n" +
wallet.printAllPubKeysAsHex();
}
public String exportTokenWalletData(boolean includePrivKeys) {
StringBuilder addressEntryListData = new StringBuilder();
return "BitcoinJ SQU wallet:\n" +
tokenWallet.toString(includePrivKeys, true, true, walletAppKit.chain()) + "\n\n" +
"SQU address entry list:\n" +
addressEntryListData.toString() +
"All pubkeys as hex:\n" +
tokenWallet.printAllPubKeysAsHex();
}*/
///////////////////////////////////////////////////////////////////////////////////////////
// Inner classes
@ -498,62 +439,19 @@ public class WalletSetup {
}
}
/*private class BitsquareWalletEventListener extends AbstractWalletEventListener {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
notifyBalanceListeners(tx);
}
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
notifyBalanceListeners(tx);
}
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
for (AddressConfidenceListener addressConfidenceListener : addressConfidenceListeners) {
List<TransactionConfidence> transactionConfidenceList = new ArrayList<>();
transactionConfidenceList.add(getTransactionConfidence(tx, addressConfidenceListener.getAddress()));
TransactionConfidence transactionConfidence = getMostRecentConfidence(transactionConfidenceList);
addressConfidenceListener.onTransactionConfidenceChanged(transactionConfidence);
}
txConfidenceListeners.stream()
.filter(txConfidenceListener -> tx != null &&
tx.getHashAsString() != null &&
txConfidenceListener != null &&
tx.getHashAsString().equals(txConfidenceListener.getTxID()))
.forEach(txConfidenceListener ->
txConfidenceListener.onTransactionConfidenceChanged(tx.getConfidence()));
}
private void notifyBalanceListeners(Transaction tx) {
for (BalanceListener balanceListener : balanceListeners) {
Coin balance;
if (balanceListener.getAddress() != null)
balance = getBalanceForAddress(balanceListener.getAddress());
else
balance = getAvailableBalance();
balanceListener.onBalanceChanged(balance, tx);
}
}
}*/
public void restoreBtcSeedWords(DeterministicSeed seed, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
public void restoreSeedWords(@Nullable DeterministicSeed btcSeed, @Nullable DeterministicSeed squSeed, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
checkArgument(btcSeed != null || squSeed != null, "Either btcSeed or squSeed must be set.");
Context ctx = Context.get();
new Thread(() -> {
try {
Context.propagate(ctx);
walletAppKit.stopAsync();
walletAppKit.awaitTerminated();
initialize(seed, resultHandler, exceptionHandler);
walletConfig.stopAsync();
walletConfig.awaitTerminated();
initialize(btcSeed, squSeed, resultHandler, exceptionHandler);
} catch (Throwable t) {
t.printStackTrace();
log.error("Executing task failed. " + t.getMessage());
}
}, "RestoreWallet-%d").start();
}, "RestoreBTCWallet-%d").start();
}
}

View file

@ -25,8 +25,8 @@ import io.bitsquare.app.Log;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.arbitration.ArbitratorManager;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.TradeWalletService;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.common.taskrunner.Model;
import io.bitsquare.crypto.DecryptedMsgWithPubKey;

View file

@ -22,9 +22,9 @@ import io.bitsquare.app.Log;
import io.bitsquare.arbitration.ArbitratorManager;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.AddressEntryException;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.TradeWalletService;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.common.handlers.ErrorMessageHandler;
@ -436,7 +436,7 @@ public class TradeManager {
removeTrade(trade);
}
public void removeTrade(Trade trade) {
private void removeTrade(Trade trade) {
trades.remove(trade);
if (!openOfferManager.findOpenOffer(trade.getId()).isPresent())
walletService.swapAnyTradeEntryContextToAvailableEntry(trade.getId());

View file

@ -21,9 +21,9 @@ import com.google.inject.Inject;
import io.bitsquare.app.DevFlags;
import io.bitsquare.app.Log;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.TradeWalletService;
import io.bitsquare.common.Timer;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.crypto.KeyRing;
@ -82,7 +82,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
private final TradeWalletService tradeWalletService;
private final OfferBookService offerBookService;
private final ClosedTradableManager closedTradableManager;
private Preferences preferences;
private final Preferences preferences;
private final TradableList<OpenOffer> openOffers;
private final Storage<TradableList<OpenOffer>> openOffersStorage;
@ -197,7 +197,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
// BootstrapListener delegate
///////////////////////////////////////////////////////////////////////////////////////////
public void onBootstrapComplete() {
private void onBootstrapComplete() {
stopped = false;
// Republish means we send the complete offer object
@ -546,7 +546,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
private void refreshOffer(OpenOffer openOffer) {
offerBookService.refreshTTL(openOffer.getOffer(),
() -> log.debug("Successful refreshed TTL for offer"),
errorMessage -> log.warn(errorMessage));
log::warn);
}
private void restart() {

View file

@ -17,8 +17,8 @@
package io.bitsquare.trade.protocol.placeoffer;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.TradeWalletService;
import io.bitsquare.common.taskrunner.Model;
import io.bitsquare.trade.offer.Offer;
import io.bitsquare.trade.offer.OfferBookService;

View file

@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.placeoffer.tasks;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.NodeAddress;
@ -35,7 +35,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class CreateOfferFeeTx extends Task<PlaceOfferModel> {
private static final Logger log = LoggerFactory.getLogger(CreateOfferFeeTx.class);
public CreateOfferFeeTx(TaskRunner taskHandler, PlaceOfferModel model) {
private CreateOfferFeeTx(TaskRunner taskHandler, PlaceOfferModel model) {
super(taskHandler, model);
}

View file

@ -19,9 +19,9 @@ package io.bitsquare.trade.protocol.trade;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.ArbitratorManager;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.data.RawTransactionInput;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.TradeWalletService;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.common.crypto.PubKeyRing;
import io.bitsquare.common.taskrunner.Model;

View file

@ -18,8 +18,8 @@
package io.bitsquare.trade.protocol.trade.tasks.buyer;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.data.PreparedDepositTxAndOffererInputs;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.crypto.Hash;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
@ -33,7 +33,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class OffererCreatesAndSignsDepositTxAsBuyer extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCreatesAndSignsDepositTxAsBuyer.class);
public OffererCreatesAndSignsDepositTxAsBuyer(TaskRunner taskHandler, Trade trade) {
private OffererCreatesAndSignsDepositTxAsBuyer(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@ -43,7 +43,7 @@ public class OffererCreatesAndSignsDepositTxAsBuyer extends TradeTask {
runInterceptHook();
checkNotNull(trade.getTradeAmount(), "trade.getTradeAmount() must not be null");
Coin securityDeposit = trade.getOffer().getSecurityDeposit();
Coin buyerInputAmount = securityDeposit;
@SuppressWarnings("UnnecessaryLocalVariable") Coin buyerInputAmount = securityDeposit;
Coin msOutputAmount = buyerInputAmount.add(trade.getTxFee()).add(securityDeposit).add(trade.getTradeAmount());
log.debug("\n\n------------------------------------------------------------\n"

View file

@ -19,8 +19,8 @@ package io.bitsquare.trade.protocol.trade.tasks.buyer;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.data.RawTransactionInput;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.crypto.Hash;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
@ -37,7 +37,7 @@ import java.util.ArrayList;
public class SignAndPublishDepositTxAsBuyer extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTxAsBuyer.class);
public SignAndPublishDepositTxAsBuyer(TaskRunner taskHandler, Trade trade) {
private SignAndPublishDepositTxAsBuyer(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}

View file

@ -18,8 +18,8 @@
package io.bitsquare.trade.protocol.trade.tasks.offerer;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererTrade;
@ -42,7 +42,7 @@ public class SetupDepositBalanceListener extends TradeTask {
private Subscription tradeStateSubscription;
private BalanceListener balanceListener;
public SetupDepositBalanceListener(TaskRunner taskHandler, Trade trade) {
private SetupDepositBalanceListener(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}

View file

@ -18,8 +18,8 @@
package io.bitsquare.trade.protocol.trade.tasks.seller;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.data.PreparedDepositTxAndOffererInputs;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.crypto.Hash;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
@ -33,7 +33,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class OffererCreatesAndSignsDepositTxAsSeller extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(OffererCreatesAndSignsDepositTxAsSeller.class);
public OffererCreatesAndSignsDepositTxAsSeller(TaskRunner taskHandler, Trade trade) {
private OffererCreatesAndSignsDepositTxAsSeller(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}

View file

@ -19,8 +19,8 @@ package io.bitsquare.trade.protocol.trade.tasks.seller;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.data.RawTransactionInput;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.crypto.Hash;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
@ -37,7 +37,7 @@ import java.util.ArrayList;
public class SignAndPublishDepositTxAsSeller extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTxAsSeller.class);
public SignAndPublishDepositTxAsSeller(TaskRunner taskHandler, Trade trade) {
private SignAndPublishDepositTxAsSeller(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}

View file

@ -18,7 +18,7 @@
package io.bitsquare.trade.protocol.trade.tasks.seller;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
@ -31,7 +31,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class SignPayoutTx extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(SignPayoutTx.class);
public SignPayoutTx(TaskRunner taskHandler, Trade trade) {
private SignPayoutTx(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}

View file

@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.trade.tasks.taker;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.NodeAddress;
import io.bitsquare.trade.Trade;
@ -35,7 +35,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class CreateTakeOfferFeeTx extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateTakeOfferFeeTx.class);
public CreateTakeOfferFeeTx(TaskRunner taskHandler, Trade trade) {
private CreateTakeOfferFeeTx(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}

View file

@ -23,7 +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.*;
import io.bitsquare.btc.wallet.*;
import io.bitsquare.common.CommonOptionKeys;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.ResultHandler;
@ -209,10 +209,9 @@ public class BitsquareApp extends Application {
} else if (new KeyCodeCombination(KeyCode.F, KeyCombination.ALT_DOWN).match(keyEvent)) {
showFPSWindow();
} else if (new KeyCodeCombination(KeyCode.J, KeyCombination.ALT_DOWN).match(keyEvent)) {
BtcWalletService btcWalletService = injector.getInstance(BtcWalletService.class);
SquWalletService squWalletService = injector.getInstance(SquWalletService.class);
if (btcWalletService.getWallet() != null)
new ShowWalletDataWindow(btcWalletService, squWalletService).information("Wallet raw data").show();
WalletsManager walletsManager = injector.getInstance(WalletsManager.class);
if (walletsManager.areWalletsAvailable())
new ShowWalletDataWindow(walletsManager).information("Wallet raw data").show();
else
new Popup<>().warning("The wallet is not initialized yet").show();
} else if (DevFlags.DEV_MODE && new KeyCodeCombination(KeyCode.G, KeyCombination.ALT_DOWN).match(keyEvent)) {
@ -406,12 +405,12 @@ public class BitsquareApp extends Application {
injector.getInstance(TradeManager.class).shutDown();
injector.getInstance(OpenOfferManager.class).shutDown(() -> {
injector.getInstance(P2PService.class).shutDown(() -> {
injector.getInstance(WalletSetup.class).shutDownDone.addListener((ov, o, n) -> {
injector.getInstance(WalletsSetup.class).shutDownDone.addListener((ov, o, n) -> {
bitsquareAppModule.close(injector);
log.debug("Graceful shutdown completed");
resultHandler.handleResult();
});
injector.getInstance(WalletSetup.class).shutDown();
injector.getInstance(WalletsSetup.class).shutDown();
injector.getInstance(BtcWalletService.class).shutDown();
injector.getInstance(SquWalletService.class).shutDown();
});

View file

@ -17,7 +17,6 @@
package io.bitsquare.gui.components;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.gui.util.BSFormatter;
import javafx.scene.control.TextField;
import javafx.scene.effect.BlurType;
@ -29,13 +28,7 @@ import org.bitcoinj.core.Coin;
public class BalanceTextField extends AnchorPane {
private static BtcWalletService walletService;
private Coin targetAmount;
public static void setWalletService(BtcWalletService walletService) {
BalanceTextField.walletService = walletService;
}
private final TextField textField;
private final Effect fundedEffect = new DropShadow(BlurType.THREE_PASS_BOX, Color.GREEN, 4, 0.0, 0, 0);
private final Effect notFundedEffect = new DropShadow(BlurType.THREE_PASS_BOX, Color.ORANGERED, 4, 0.0, 0, 0);

View file

@ -17,9 +17,9 @@
package io.bitsquare.gui.components;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.listeners.AddressConfidenceListener;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.gui.components.indicator.TxConfidenceIndicator;
import io.bitsquare.gui.util.BSFormatter;
import javafx.scene.control.TextField;

View file

@ -19,8 +19,8 @@ package io.bitsquare.gui.components;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.listeners.TxConfidenceListener;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.components.indicator.TxConfidenceIndicator;
import io.bitsquare.gui.main.overlays.popups.Popup;

View file

@ -29,11 +29,14 @@ import io.bitsquare.app.Version;
import io.bitsquare.arbitration.ArbitratorManager;
import io.bitsquare.arbitration.Dispute;
import io.bitsquare.arbitration.DisputeManager;
import io.bitsquare.btc.*;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.btc.provider.price.MarketPrice;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.WalletsManager;
import io.bitsquare.btc.wallet.WalletsSetup;
import io.bitsquare.common.Clock;
import io.bitsquare.common.Timer;
import io.bitsquare.common.UserThread;
@ -41,7 +44,6 @@ import io.bitsquare.common.crypto.*;
import io.bitsquare.filter.FilterManager;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.ViewModel;
import io.bitsquare.gui.components.BalanceTextField;
import io.bitsquare.gui.components.BalanceWithConfirmationTextField;
import io.bitsquare.gui.components.TxIdTextField;
import io.bitsquare.gui.main.overlays.notifications.NotificationCenter;
@ -78,7 +80,6 @@ import javafx.collections.SetChangeListener;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Wallet;
import org.bitcoinj.store.BlockStoreException;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription;
@ -96,14 +97,15 @@ import java.util.stream.Collectors;
public class MainViewModel implements ViewModel {
private static final Logger log = LoggerFactory.getLogger(MainViewModel.class);
private final BtcWalletService walletService;
private final TradeWalletService tradeWalletService;
private final WalletsManager walletsManager;
private final WalletsSetup walletsSetup;
private final BtcWalletService btcWalletService;
private final ArbitratorManager arbitratorManager;
private final P2PService p2PService;
private final TradeManager tradeManager;
private final OpenOfferManager openOfferManager;
private final DisputeManager disputeManager;
final Preferences preferences;
private final Preferences preferences;
private final AlertManager alertManager;
private final PrivateNotificationManager privateNotificationManager;
private final FilterManager filterManager;
@ -132,7 +134,7 @@ public class MainViewModel implements ViewModel {
final StringProperty lockedBalance = new SimpleStringProperty();
private MonadicBinding<String> btcInfoBinding;
final StringProperty marketPrice = new SimpleStringProperty("N/A");
private final StringProperty marketPrice = new SimpleStringProperty("N/A");
// P2P network
final StringProperty p2PNetworkInfo = new SimpleStringProperty();
@ -155,8 +157,6 @@ public class MainViewModel implements ViewModel {
final StringProperty p2pNetworkLabelId = new SimpleStringProperty("footer-pane");
private MonadicBinding<Boolean> allServicesDone, tradesAndUIReady;
private WalletSetup walletSetup;
private SquWalletService squWalletService;
final PriceFeedService priceFeedService;
private final User user;
private int numBtcPeers = 0;
@ -176,20 +176,19 @@ public class MainViewModel implements ViewModel {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public MainViewModel(WalletSetup walletSetup, BtcWalletService walletService, TradeWalletService tradeWalletService,
SquWalletService squWalletService, PriceFeedService priceFeedService,
public MainViewModel(WalletsManager walletsManager, WalletsSetup walletsSetup,
BtcWalletService btcWalletService, PriceFeedService priceFeedService,
ArbitratorManager arbitratorManager, P2PService p2PService, TradeManager tradeManager,
OpenOfferManager openOfferManager, DisputeManager disputeManager, Preferences preferences,
User user, AlertManager alertManager, PrivateNotificationManager privateNotificationManager,
FilterManager filterManager, WalletPasswordWindow walletPasswordWindow, AddBitcoinNodesWindow addBitcoinNodesWindow,
NotificationCenter notificationCenter, TacWindow tacWindow, Clock clock, FeeService feeService,
KeyRing keyRing, Navigation navigation, BSFormatter formatter) {
this.walletSetup = walletSetup;
this.squWalletService = squWalletService; // Add it to get it initiated
this.walletsManager = walletsManager;
this.walletsSetup = walletsSetup;
this.btcWalletService = btcWalletService;
this.priceFeedService = priceFeedService;
this.user = user;
this.walletService = walletService;
this.tradeWalletService = tradeWalletService;
this.arbitratorManager = arbitratorManager;
this.p2PService = p2PService;
this.tradeManager = tradeManager;
@ -213,9 +212,10 @@ public class MainViewModel implements ViewModel {
(preferences.getUseTorForBitcoinJ() ? " (using Tor)" : "");
TxIdTextField.setPreferences(preferences);
TxIdTextField.setWalletService(walletService);
BalanceTextField.setWalletService(walletService);
BalanceWithConfirmationTextField.setWalletService(walletService);
// TODO
TxIdTextField.setWalletService(btcWalletService);
BalanceWithConfirmationTextField.setWalletService(btcWalletService);
}
@ -237,8 +237,7 @@ public class MainViewModel implements ViewModel {
Timer startupTimeout = UserThread.runAfter(() -> {
log.warn("startupTimeout called");
Wallet wallet = walletService.getWallet();
if (wallet != null && wallet.isEncrypted())
if (walletsManager.areWalletsEncrypted())
walletInitialized.addListener(walletInitializedListener);
else
showStartupTimeoutPopup();
@ -435,7 +434,7 @@ public class MainViewModel implements ViewModel {
private void initWalletService() {
Log.traceCall();
ObjectProperty<Throwable> walletServiceException = new SimpleObjectProperty<>();
btcInfoBinding = EasyBind.combine(walletSetup.downloadPercentageProperty(), walletSetup.numPeersProperty(), walletServiceException,
btcInfoBinding = EasyBind.combine(walletsSetup.downloadPercentageProperty(), walletsSetup.numPeersProperty(), walletServiceException,
(downloadPercentage, numPeers, exception) -> {
String result = "";
if (exception == null) {
@ -480,18 +479,18 @@ public class MainViewModel implements ViewModel {
btcInfo.set(newValue);
});
walletSetup.initialize(null,
walletsSetup.initialize(null, null,
() -> {
numBtcPeers = walletSetup.numPeersProperty().get();
numBtcPeers = walletsSetup.numPeersProperty().get();
if (walletService.getWallet().isEncrypted()) {
// We only check one as we apply encryption to all or none
if (walletsManager.areWalletsEncrypted()) {
if (p2pNetWorkReady.get())
splashP2PNetworkAnimationVisible.set(false);
walletPasswordWindow
.onAesKey(aesKey -> {
walletSetup.setAesKey(aesKey);
tradeWalletService.setAesKey(aesKey);
walletsManager.setAesKey(aesKey);
walletInitialized.set(true);
})
.hideCloseButton()
@ -529,7 +528,7 @@ public class MainViewModel implements ViewModel {
});
// walletService
walletService.addBalanceListener(new BalanceListener() {
btcWalletService.addBalanceListener(new BalanceListener() {
@Override
public void onBalanceChanged(Coin balance, Transaction tx) {
updateBalance();
@ -615,7 +614,7 @@ public class MainViewModel implements ViewModel {
String remindPasswordAndBackupKey = "remindPasswordAndBackup";
user.getPaymentAccountsAsObservable().addListener((SetChangeListener<PaymentAccount>) change -> {
if (!walletService.getWallet().isEncrypted() && preferences.showAgain(remindPasswordAndBackupKey) && change.wasAdded()) {
if (!walletsManager.areWalletsEncrypted() && preferences.showAgain(remindPasswordAndBackupKey) && change.wasAdded()) {
new Popup<>().headLine("Important security recommendation")
.information("We would like to remind you to consider using password protection for your wallet if you have not already enabled that.\n\n" +
"It is also highly recommended to write down the wallet seed words. Those seed words are like a master password for recovering your Bitcoin wallet.\n" +
@ -747,7 +746,7 @@ public class MainViewModel implements ViewModel {
}
private void setupBtcNumPeersWatcher() {
walletSetup.numPeersProperty().addListener((observable, oldValue, newValue) -> {
walletsSetup.numPeersProperty().addListener((observable, oldValue, newValue) -> {
int numPeers = (int) newValue;
if ((int) oldValue > 0 && numPeers == 0) {
if (checkNumberOfBtcPeersTimer != null)
@ -755,7 +754,7 @@ public class MainViewModel implements ViewModel {
checkNumberOfBtcPeersTimer = UserThread.runAfter(() -> {
// check again numPeers
if (walletSetup.numPeersProperty().get() == 0) {
if (walletsSetup.numPeersProperty().get() == 0) {
walletServiceErrorMsg.set("You lost the connection to all bitcoin network peers.\n" +
"Maybe you lost your internet connection or your computer was in standby mode.");
} else {
@ -855,7 +854,7 @@ public class MainViewModel implements ViewModel {
selectedPriceFeedComboBoxItemProperty.set(itemOptional.get());
else
findPriceFeedComboBoxItem(preferences.getPreferredTradeCurrency().getCode())
.ifPresent(item2 -> selectedPriceFeedComboBoxItemProperty.set(item2));
.ifPresent(selectedPriceFeedComboBoxItemProperty::set);
priceFeedService.setCurrencyCode(item.currencyCode);
} else if (item != null) {
@ -863,7 +862,7 @@ public class MainViewModel implements ViewModel {
priceFeedService.setCurrencyCode(item.currencyCode);
} else {
findPriceFeedComboBoxItem(preferences.getPreferredTradeCurrency().getCode())
.ifPresent(item2 -> selectedPriceFeedComboBoxItemProperty.set(item2));
.ifPresent(selectedPriceFeedComboBoxItemProperty::set);
}
// Need a delay a bit as we get item.isPriceAvailable() set after that call.
@ -877,7 +876,7 @@ public class MainViewModel implements ViewModel {
}, 100, TimeUnit.MILLISECONDS);
}
Optional<PriceFeedComboBoxItem> findPriceFeedComboBoxItem(String currencyCode) {
private Optional<PriceFeedComboBoxItem> findPriceFeedComboBoxItem(String currencyCode) {
return priceFeedComboBoxItems.stream()
.filter(item -> item.currencyCode.equals(currencyCode))
.findAny();
@ -904,7 +903,7 @@ public class MainViewModel implements ViewModel {
new Popup<>().headLine("Important private notification!")
.attention(privateNotification.message)
.setHeadlineStyle("-fx-text-fill: -bs-error-red; -fx-font-weight: bold; -fx-font-size: 16;")
.onClose(() -> privateNotificationManager.removePrivateNotification())
.onClose(privateNotificationManager::removePrivateNotification)
.closeButtonText("I understand")
.show();
}
@ -912,7 +911,7 @@ public class MainViewModel implements ViewModel {
private void swapPendingOfferFundingEntries() {
tradeManager.getAddressEntriesForAvailableBalanceStream()
.filter(addressEntry -> addressEntry.getOfferId() != null)
.forEach(addressEntry -> walletService.swapTradeEntryToAvailableEntry(addressEntry.getOfferId(), AddressEntry.Context.OFFER_FUNDING));
.forEach(addressEntry -> btcWalletService.swapTradeEntryToAvailableEntry(addressEntry.getOfferId(), AddressEntry.Context.OFFER_FUNDING));
}
private void updateBalance() {
@ -927,7 +926,7 @@ public class MainViewModel implements ViewModel {
private void updateAvailableBalance() {
Coin totalAvailableBalance = Coin.valueOf(tradeManager.getAddressEntriesForAvailableBalanceStream()
.mapToLong(addressEntry -> walletService.getBalanceForAddress(addressEntry.getAddress()).getValue())
.mapToLong(addressEntry -> btcWalletService.getBalanceForAddress(addressEntry.getAddress()).getValue())
.sum());
availableBalance.set(formatter.formatCoinWithCode(totalAvailableBalance));
}
@ -935,8 +934,8 @@ public class MainViewModel implements ViewModel {
private void updateReservedBalance() {
Coin sum = Coin.valueOf(openOfferManager.getOpenOffers().stream()
.map(openOffer -> {
Address address = walletService.getOrCreateAddressEntry(openOffer.getId(), AddressEntry.Context.RESERVED_FOR_TRADE).getAddress();
return walletService.getBalanceForAddress(address);
Address address = btcWalletService.getOrCreateAddressEntry(openOffer.getId(), AddressEntry.Context.RESERVED_FOR_TRADE).getAddress();
return btcWalletService.getBalanceForAddress(address);
})
.mapToLong(Coin::getValue)
.sum());
@ -947,7 +946,7 @@ public class MainViewModel implements ViewModel {
private void updateLockedBalance() {
Coin sum = Coin.valueOf(tradeManager.getLockedTradeStream()
.mapToLong(trade -> {
Coin lockedTradeAmount = walletService.getOrCreateAddressEntry(trade.getId(), AddressEntry.Context.MULTI_SIG).getLockedTradeAmount();
Coin lockedTradeAmount = btcWalletService.getOrCreateAddressEntry(trade.getId(), AddressEntry.Context.MULTI_SIG).getLockedTradeAmount();
return lockedTradeAmount != null ? lockedTradeAmount.getValue() : 0;
})
.sum());

View file

@ -21,7 +21,7 @@ import com.google.inject.Inject;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.arbitration.ArbitratorManager;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
@ -42,7 +42,7 @@ import java.util.Date;
class ArbitratorRegistrationViewModel extends ActivatableViewModel {
private final ArbitratorManager arbitratorManager;
private User user;
private final User user;
private final P2PService p2PService;
private final BtcWalletService walletService;
private final KeyRing keyRing;

View file

@ -17,9 +17,7 @@
package io.bitsquare.gui.main.account.content.password;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletSetup;
import io.bitsquare.btc.wallet.WalletsManager;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.common.util.Tuple3;
import io.bitsquare.crypto.ScryptUtil;
@ -36,7 +34,6 @@ import javafx.beans.value.ChangeListener;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import org.bitcoinj.core.Wallet;
import org.bitcoinj.crypto.KeyCrypterScrypt;
import javax.inject.Inject;
@ -47,10 +44,8 @@ import static io.bitsquare.gui.util.FormBuilder.*;
@FxmlView
public class PasswordView extends ActivatableView<GridPane, Void> {
private final WalletsManager walletsManager;
private final PasswordValidator passwordValidator;
private final WalletSetup walletSetup;
private final BtcWalletService walletService;
private final TradeWalletService tradeWalletService;
private PasswordTextField passwordField;
private PasswordTextField repeatedPasswordField;
@ -67,11 +62,9 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private PasswordView(PasswordValidator passwordValidator, WalletSetup walletSetup, BtcWalletService walletService, TradeWalletService tradeWalletService) {
private PasswordView(WalletsManager walletsManager, PasswordValidator passwordValidator) {
this.walletsManager = walletsManager;
this.passwordValidator = passwordValidator;
this.walletSetup = walletSetup;
this.walletService = walletService;
this.tradeWalletService = tradeWalletService;
}
@Override
@ -103,28 +96,20 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
deriveStatusLabel.setText("Derive key from password");
busyAnimation.play();
KeyCrypterScrypt keyCrypterScrypt;
Wallet wallet = walletService.getWallet();
if (wallet.isEncrypted())
keyCrypterScrypt = (KeyCrypterScrypt) wallet.getKeyCrypter();
else
keyCrypterScrypt = ScryptUtil.getKeyCrypterScrypt();
KeyCrypterScrypt keyCrypterScrypt = walletsManager.getKeyCrypterScrypt();
ScryptUtil.deriveKeyWithScrypt(keyCrypterScrypt, password, aesKey -> {
deriveStatusLabel.setText("");
busyAnimation.stop();
if (wallet.isEncrypted()) {
if (wallet.checkAESKey(aesKey)) {
walletSetup.decryptWallets(aesKey);
walletService.decryptWallet(aesKey);
tradeWalletService.setAesKey(null);
if (walletsManager.areWalletsEncrypted()) {
if (walletsManager.checkAESKey(aesKey)) {
walletsManager.decryptWallets(aesKey);
new Popup()
.feedback("Wallet successfully decrypted and password protection removed.")
.show();
passwordField.setText("");
repeatedPasswordField.setText("");
walletSetup.backupWallets();
walletsManager.backupWallets();
} else {
pwButton.setDisable(false);
new Popup()
@ -133,17 +118,14 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
.show();
}
} else {
// we save the key for the trade wallet as we don't require passwords here
walletSetup.encryptWallets(keyCrypterScrypt, aesKey);
walletService.encryptWallet(keyCrypterScrypt, aesKey);
tradeWalletService.setAesKey(aesKey);
walletsManager.encryptWallets(keyCrypterScrypt, aesKey);
new Popup()
.feedback("Wallet successfully encrypted and password protection enabled.")
.show();
passwordField.setText("");
repeatedPasswordField.setText("");
walletSetup.clearBackup();
walletSetup.backupWallets();
walletsManager.clearBackup();
walletsManager.backupWallets();
}
setText();
});
@ -158,7 +140,7 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
}
private void setText() {
if (walletService.getWallet().isEncrypted()) {
if (walletsManager.areWalletsEncrypted()) {
pwButton.setText("Remove password");
headline.setText("Remove password protection for wallet");
repeatedPasswordField.setVisible(false);
@ -193,7 +175,7 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
passwordValidator.setExternalValidationResult(null);
InputValidator.ValidationResult result = passwordValidator.validate(passwordField.getText());
if (result.isValid) {
if (walletService.getWallet().isEncrypted()) {
if (walletsManager.areWalletsEncrypted()) {
pwButton.setDisable(false);
return;
} else {

View file

@ -20,7 +20,9 @@ package io.bitsquare.gui.main.account.content.seedwords;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import io.bitsquare.app.BitsquareApp;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.SquWalletService;
import io.bitsquare.btc.wallet.WalletsManager;
import io.bitsquare.common.UserThread;
import io.bitsquare.gui.common.view.ActivatableView;
import io.bitsquare.gui.common.view.FxmlView;
@ -35,8 +37,6 @@ import javafx.scene.control.Button;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
import org.bitcoinj.core.Wallet;
import org.bitcoinj.crypto.KeyCrypter;
import org.bitcoinj.crypto.MnemonicCode;
import org.bitcoinj.crypto.MnemonicException;
import org.bitcoinj.wallet.DeterministicSeed;
@ -54,24 +54,29 @@ import static javafx.beans.binding.Bindings.createBooleanBinding;
@FxmlView
public class SeedWordsView extends ActivatableView<GridPane, Void> {
private final BtcWalletService walletService;
private final WalletsManager walletsManager;
private final BtcWalletService btcWalletService;
private final SquWalletService squWalletService;
private final WalletPasswordWindow walletPasswordWindow;
private Preferences preferences;
private final Preferences preferences;
private Button restoreButton;
private TextArea displaySeedWordsTextArea, restoreSeedWordsTextArea;
private TextArea displayBtcSeedWordsTextArea, displaySquSeedWordsTextArea, btcSeedWordsTextArea, squSeedWordsTextArea;
private DatePicker datePicker, restoreDatePicker;
private int gridRow = 0;
private DeterministicSeed keyChainSeed;
private ChangeListener<Boolean> seedWordsValidChangeListener;
private SimpleBooleanProperty seedWordsValid = new SimpleBooleanProperty(false);
private SimpleBooleanProperty dateValid = new SimpleBooleanProperty(false);
private ChangeListener<String> seedWordsTextAreaChangeListener;
private ChangeListener<Boolean> btcSeedWordsValidChangeListener, squSeedWordsValidChangeListener;
private final SimpleBooleanProperty btcSeedWordsValid = new SimpleBooleanProperty(false);
private final SimpleBooleanProperty squSeedWordsValid = new SimpleBooleanProperty(false);
private final SimpleBooleanProperty dateValid = new SimpleBooleanProperty(false);
private ChangeListener<String> btcSeedWordsTextAreaChangeListener;
private ChangeListener<String> squSeedWordsTextAreaChangeListener;
private ChangeListener<Boolean> datePickerChangeListener;
private ChangeListener<LocalDate> dateChangeListener;
private BooleanProperty seedWordsEdited = new SimpleBooleanProperty();
private String seedWordText;
private final BooleanProperty btcSeedWordsEdited = new SimpleBooleanProperty();
private final BooleanProperty squSeedWordsEdited = new SimpleBooleanProperty();
private String btcSeedWordText;
private String squSeedWordText;
private LocalDate walletCreationDate;
@ -80,52 +85,80 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private SeedWordsView(BtcWalletService walletService, WalletPasswordWindow walletPasswordWindow, Preferences preferences) {
this.walletService = walletService;
private SeedWordsView(WalletsManager walletsManager, BtcWalletService btcWalletService, SquWalletService squWalletService, WalletPasswordWindow walletPasswordWindow, Preferences preferences) {
this.walletsManager = walletsManager;
this.btcWalletService = btcWalletService;
this.squWalletService = squWalletService;
this.walletPasswordWindow = walletPasswordWindow;
this.preferences = preferences;
}
@Override
protected void initialize() {
addTitledGroupBg(root, gridRow, 2, "Backup your wallet seed words");
displaySeedWordsTextArea = addLabelTextArea(root, gridRow, "Wallet seed words:", "", Layout.FIRST_ROW_DISTANCE).second;
displaySeedWordsTextArea.setPrefHeight(60);
displaySeedWordsTextArea.setEditable(false);
addTitledGroupBg(root, gridRow, 3, "Backup your wallet seed words");
displayBtcSeedWordsTextArea = addLabelTextArea(root, gridRow, "BTC wallet seed words:", "", Layout.FIRST_ROW_DISTANCE).second;
displayBtcSeedWordsTextArea.setPrefHeight(60);
displayBtcSeedWordsTextArea.setEditable(false);
displaySquSeedWordsTextArea = addLabelTextArea(root, ++gridRow, "SQU wallet seed words:", "").second;
displaySquSeedWordsTextArea.setPrefHeight(60);
displaySquSeedWordsTextArea.setEditable(false);
datePicker = addLabelDatePicker(root, ++gridRow, "Wallet Date:").second;
datePicker.setMouseTransparent(true);
addTitledGroupBg(root, ++gridRow, 2, "Restore your wallet seed words", Layout.GROUP_DISTANCE);
restoreSeedWordsTextArea = addLabelTextArea(root, gridRow, "Wallet seed words:", "", Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
restoreSeedWordsTextArea.setPrefHeight(60);
addTitledGroupBg(root, ++gridRow, 3, "Restore your wallet seed words", Layout.GROUP_DISTANCE);
btcSeedWordsTextArea = addLabelTextArea(root, gridRow, "BTC wallet seed words:", "", Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
btcSeedWordsTextArea.setPrefHeight(60);
squSeedWordsTextArea = addLabelTextArea(root, ++gridRow, "SQU wallet seed words:", "").second;
squSeedWordsTextArea.setPrefHeight(60);
restoreDatePicker = addLabelDatePicker(root, ++gridRow, "Wallet Date:").second;
restoreButton = addButtonAfterGroup(root, ++gridRow, "Restore wallet");
addTitledGroupBg(root, ++gridRow, 1, "Information", Layout.GROUP_DISTANCE);
addMultilineLabel(root, gridRow, "Please write down you wallet seed words and the date! " +
addMultilineLabel(root, gridRow, "Please write down both wallet seed words and the date! " +
"You can recover your wallet any time with those seed words and the date.",
Layout.FIRST_ROW_AND_GROUP_DISTANCE);
seedWordsValidChangeListener = (observable, oldValue, newValue) -> {
btcSeedWordsValidChangeListener = (observable, oldValue, newValue) -> {
if (newValue) {
restoreSeedWordsTextArea.getStyleClass().remove("validation_error");
btcSeedWordsTextArea.getStyleClass().remove("validation_error");
} else {
restoreSeedWordsTextArea.getStyleClass().add("validation_error");
btcSeedWordsTextArea.getStyleClass().add("validation_error");
}
};
seedWordsTextAreaChangeListener = (observable, oldValue, newValue) -> {
seedWordsEdited.set(true);
squSeedWordsValidChangeListener = (observable, oldValue, newValue) -> {
if (newValue) {
squSeedWordsTextArea.getStyleClass().remove("validation_error");
} else {
squSeedWordsTextArea.getStyleClass().add("validation_error");
}
};
btcSeedWordsTextAreaChangeListener = (observable, oldValue, newValue) -> {
btcSeedWordsEdited.set(true);
try {
MnemonicCode codec = new MnemonicCode();
codec.check(Splitter.on(" ").splitToList(newValue));
seedWordsValid.set(true);
btcSeedWordsValid.set(true);
} catch (IOException | MnemonicException e) {
seedWordsValid.set(false);
btcSeedWordsValid.set(false);
}
};
squSeedWordsTextAreaChangeListener = (observable, oldValue, newValue) -> {
squSeedWordsEdited.set(true);
try {
MnemonicCode codec = new MnemonicCode();
codec.check(Splitter.on(" ").splitToList(newValue));
squSeedWordsValid.set(true);
} catch (IOException | MnemonicException e) {
squSeedWordsValid.set(false);
}
};
datePickerChangeListener = (observable, oldValue, newValue) -> {
if (newValue)
@ -139,23 +172,27 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
@Override
public void activate() {
seedWordsValid.addListener(seedWordsValidChangeListener);
btcSeedWordsValid.addListener(btcSeedWordsValidChangeListener);
squSeedWordsValid.addListener(squSeedWordsValidChangeListener);
dateValid.addListener(datePickerChangeListener);
restoreSeedWordsTextArea.textProperty().addListener(seedWordsTextAreaChangeListener);
btcSeedWordsTextArea.textProperty().addListener(btcSeedWordsTextAreaChangeListener);
squSeedWordsTextArea.textProperty().addListener(squSeedWordsTextAreaChangeListener);
restoreDatePicker.valueProperty().addListener(dateChangeListener);
restoreButton.disableProperty().bind(createBooleanBinding(() -> !seedWordsValid.get() || !dateValid.get() || !seedWordsEdited.get(),
seedWordsValid, dateValid, seedWordsEdited));
restoreButton.disableProperty().bind(createBooleanBinding(() -> !btcSeedWordsValid.get() || !squSeedWordsValid.get() || !dateValid.get() || !btcSeedWordsEdited.get() || !squSeedWordsEdited.get(),
btcSeedWordsValid, squSeedWordsValid, dateValid, btcSeedWordsEdited, squSeedWordsEdited));
restoreButton.setOnAction(e -> onRestore());
restoreSeedWordsTextArea.getStyleClass().remove("validation_error");
btcSeedWordsTextArea.getStyleClass().remove("validation_error");
squSeedWordsTextArea.getStyleClass().remove("validation_error");
restoreDatePicker.getStyleClass().remove("validation_error");
DeterministicSeed keyChainSeed = walletService.getWallet().getKeyChainSeed();
DeterministicSeed btcKeyChainSeed = btcWalletService.getWallet().getKeyChainSeed();
DeterministicSeed squKeyChainSeed = squWalletService.getWallet().getKeyChainSeed();
// wallet creation date is not encrypted
walletCreationDate = Instant.ofEpochSecond(keyChainSeed.getCreationTimeSeconds()).atZone(ZoneId.systemDefault()).toLocalDate();
if (keyChainSeed.isEncrypted()) {
walletCreationDate = Instant.ofEpochSecond(walletsManager.getChainSeedCreationTimeSeconds()).atZone(ZoneId.systemDefault()).toLocalDate();
if (btcKeyChainSeed.isEncrypted()) {
askForPassword();
} else {
String key = "showSeedWordsWarning";
@ -165,13 +202,15 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
.actionButtonText("Yes, and don't ask me again")
.onAction(() -> {
preferences.dontShowAgain(key, true);
initSeedWords(keyChainSeed);
initBtcSeedWords(btcKeyChainSeed);
initSquSeedWords(squKeyChainSeed);
showSeedScreen();
})
.closeButtonText("No")
.show();
} else {
initSeedWords(keyChainSeed);
initBtcSeedWords(btcKeyChainSeed);
initSquSeedWords(squKeyChainSeed);
showSeedScreen();
}
}
@ -179,55 +218,58 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
@Override
protected void deactivate() {
seedWordsValid.removeListener(seedWordsValidChangeListener);
btcSeedWordsValid.removeListener(btcSeedWordsValidChangeListener);
squSeedWordsValid.removeListener(squSeedWordsValidChangeListener);
dateValid.removeListener(datePickerChangeListener);
restoreSeedWordsTextArea.textProperty().removeListener(seedWordsTextAreaChangeListener);
btcSeedWordsTextArea.textProperty().removeListener(btcSeedWordsTextAreaChangeListener);
squSeedWordsTextArea.textProperty().removeListener(squSeedWordsTextAreaChangeListener);
restoreDatePicker.valueProperty().removeListener(dateChangeListener);
restoreButton.disableProperty().unbind();
restoreButton.setOnAction(null);
displaySeedWordsTextArea.setText("");
restoreSeedWordsTextArea.setText("");
displayBtcSeedWordsTextArea.setText("");
displaySquSeedWordsTextArea.setText("");
btcSeedWordsTextArea.setText("");
squSeedWordsTextArea.setText("");
restoreDatePicker.setValue(null);
datePicker.setValue(null);
restoreSeedWordsTextArea.getStyleClass().remove("validation_error");
btcSeedWordsTextArea.getStyleClass().remove("validation_error");
squSeedWordsTextArea.getStyleClass().remove("validation_error");
restoreDatePicker.getStyleClass().remove("validation_error");
}
private void askForPassword() {
walletPasswordWindow.headLine("Enter password to view seed words").onAesKey(aesKey -> {
Wallet wallet = walletService.getWallet();
KeyCrypter keyCrypter = wallet.getKeyCrypter();
keyChainSeed = wallet.getKeyChainSeed();
if (keyCrypter != null) {
DeterministicSeed decryptedSeed = keyChainSeed.decrypt(keyCrypter, "", aesKey);
initSeedWords(decryptedSeed);
initBtcSeedWords(walletsManager.getDecryptedSeed(aesKey, btcWalletService.getWallet()));
initSquSeedWords(walletsManager.getDecryptedSeed(aesKey, squWalletService.getWallet()));
showSeedScreen();
} else {
log.warn("keyCrypter is null");
}
}).show();
}
private void initSeedWords(DeterministicSeed seed) {
private void initBtcSeedWords(DeterministicSeed seed) {
List<String> mnemonicCode = seed.getMnemonicCode();
if (mnemonicCode != null) {
seedWordText = Joiner.on(" ").join(mnemonicCode);
btcSeedWordText = Joiner.on(" ").join(mnemonicCode);
}
}
private void initSquSeedWords(DeterministicSeed seed) {
List<String> mnemonicCode = seed.getMnemonicCode();
if (mnemonicCode != null) {
squSeedWordText = Joiner.on(" ").join(mnemonicCode);
}
}
private void showSeedScreen() {
displaySeedWordsTextArea.setText(seedWordText);
displayBtcSeedWordsTextArea.setText(btcSeedWordText);
displaySquSeedWordsTextArea.setText(squSeedWordText);
datePicker.setValue(walletCreationDate);
}
private void onRestore() {
Wallet wallet = walletService.getWallet();
if (wallet.getBalance(Wallet.BalanceType.AVAILABLE).value > 0) {
if (walletsManager.hasPositiveBalance()) {
new Popup()
.warning("Your bitcoin wallet is not empty.\n\n" +
"You must empty this wallet before attempting to restore an older one, as mixing wallets " +
@ -237,7 +279,7 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
"To open that emergency tool press \"cmd + e\".")
.actionButtonText("I want to restore anyway")
.onAction(this::checkIfEncrypted)
.closeButtonText("I will empty my wallet first")
.closeButtonText("I will empty my wallets first")
.show();
} else {
checkIfEncrypted();
@ -245,10 +287,10 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
}
private void checkIfEncrypted() {
if (walletService.getWallet().isEncrypted()) {
if (walletsManager.areWalletsEncrypted()) {
new Popup()
.information("Your bitcoin wallet is encrypted.\n\n" +
"After restore, the wallet will no longer be encrypted and you must set a new password.\n\n" +
.information("Your wallets are encrypted.\n\n" +
"After restore, the wallets will no longer be encrypted and you must set a new password.\n\n" +
"Do you want to proceed?")
.closeButtonText("No")
.actionButtonText("Yes")
@ -261,13 +303,16 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
private void doRestore() {
long date = restoreDatePicker.getValue().atStartOfDay().toEpochSecond(ZoneOffset.UTC);
DeterministicSeed seed = new DeterministicSeed(Splitter.on(" ").splitToList(restoreSeedWordsTextArea.getText()), null, "", date);
walletService.restoreSeedWords(seed,
DeterministicSeed btcSeed = new DeterministicSeed(Splitter.on(" ").splitToList(btcSeedWordsTextArea.getText()), null, "", date);
DeterministicSeed squSeed = new DeterministicSeed(Splitter.on(" ").splitToList(squSeedWordsTextArea.getText()), null, "", date);
walletsManager.restoreSeedWords(
btcSeed,
squSeed,
() -> UserThread.execute(() -> {
log.info("Wallet restored with seed words");
log.info("Wallets restored with seed words");
new Popup()
.feedback("Wallet restored successfully with the new seed words.\n\n" +
.feedback("Wallets restored successfully with the new seed words.\n\n" +
"You need to shut down and restart the application.")
.closeButtonText("Shut down")
.onClose(BitsquareApp.shutDownHandler::run).show();
@ -275,7 +320,7 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
throwable -> UserThread.execute(() -> {
log.error(throwable.getMessage());
new Popup()
.error("An error occurred when restoring the wallet with seed words.\n" +
.error("An error occurred when restoring the wallets with seed words.\n" +
"Error message: " + throwable.getMessage())
.show();
}));

View file

@ -17,7 +17,7 @@
package io.bitsquare.gui.main.dao.wallet.dashboard;
import io.bitsquare.btc.SquWalletService;
import io.bitsquare.btc.wallet.SquWalletService;
import io.bitsquare.gui.common.view.ActivatableView;
import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.util.BSFormatter;
@ -44,7 +44,7 @@ public class TokenDashboardView extends ActivatableView<GridPane, Void> {
@Nullable
private Wallet squWallet;
private int gridRow = 0;
private final int gridRow = 0;
private WalletEventListener walletEventListener;
///////////////////////////////////////////////////////////////////////////////////////////
@ -115,6 +115,7 @@ public class TokenDashboardView extends ActivatableView<GridPane, Void> {
}
private void updateBalance() {
if (squWallet != null)
confirmedBalance.setText(formatter.formatCoinWithCode(squWallet.getBalance()));
}
}

View file

@ -18,7 +18,7 @@
package io.bitsquare.gui.main.dao.wallet.receive;
import io.bitsquare.app.DevFlags;
import io.bitsquare.btc.SquWalletService;
import io.bitsquare.btc.wallet.SquWalletService;
import io.bitsquare.common.UserThread;
import io.bitsquare.gui.common.view.ActivatableView;
import io.bitsquare.gui.common.view.FxmlView;
@ -194,6 +194,7 @@ public class TokenReceiveView extends ActivatableView<GridPane, Void> {
}
private void updateBalance() {
if (squWallet != null)
confirmedBalance.setText(formatter.formatCoinWithCode(squWallet.getBalance()));
}
}

View file

@ -19,14 +19,12 @@ package io.bitsquare.gui.main.dao.wallet.send;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.app.DevFlags;
import io.bitsquare.btc.AddressEntryException;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.InsufficientFundsException;
import io.bitsquare.btc.SquWalletService;
import io.bitsquare.btc.exceptions.SigningException;
import io.bitsquare.btc.exceptions.TransactionVerificationException;
import io.bitsquare.btc.exceptions.WalletException;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.SquWalletService;
import io.bitsquare.gui.common.view.ActivatableView;
import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.components.InputTextField;
@ -39,6 +37,7 @@ import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import org.bitcoinj.core.*;
import org.bitcoinj.script.Script;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import javax.inject.Inject;
@ -54,8 +53,8 @@ public class TokenSendView extends ActivatableView<GridPane, Void> {
private TextField confirmedBalance;
private final SquWalletService squWalletService;
private BtcWalletService btcWalletService;
private FeeService feeService;
private final BtcWalletService btcWalletService;
private final FeeService feeService;
private final BSFormatter formatter;
@Nullable
@ -103,10 +102,9 @@ public class TokenSendView extends ActivatableView<GridPane, Void> {
Coin receiverAmount = formatter.parseToCoin(amountInputTextField.getText());
Optional<String> changeAddressStringOptional = Optional.empty();
try {
Transaction preparedSquTx = squWalletService.prepareSendTx(receiversAddressString, receiverAmount, changeAddressStringOptional);
Transaction preparedMixedTx = btcWalletService.getTransactionWithFeeInput(preparedSquTx);
Transaction signedMixedTx = squWalletService.signFinalSendTx(preparedMixedTx);
squWalletService.commitAndBroadcastTx(signedMixedTx, new FutureCallback<Transaction>() {
Transaction preparedSendTx = squWalletService.getPreparedSendTx(receiversAddressString, receiverAmount, changeAddressStringOptional);
Transaction txWithBtcFee = btcWalletService.addFeeInputToPreparedSquSendTx(preparedSendTx);
squWalletService.signAndBroadcastSendTx(txWithBtcFee, new FutureCallback<Transaction>() {
@Override
public void onSuccess(@Nullable Transaction result) {
if (result != null) {
@ -117,12 +115,12 @@ public class TokenSendView extends ActivatableView<GridPane, Void> {
}
@Override
public void onFailure(Throwable t) {
public void onFailure(@NotNull Throwable t) {
log.error(t.toString());
new Popup<>().warning(t.toString());
}
});
} catch (AddressFormatException | AddressEntryException | SigningException | InsufficientFundsException |
} catch (AddressFormatException | InsufficientFundsException |
TransactionVerificationException | WalletException | InsufficientMoneyException e) {
log.error(e.toString());
e.printStackTrace();
@ -183,6 +181,7 @@ public class TokenSendView extends ActivatableView<GridPane, Void> {
}
private void updateBalance() {
if (squWallet != null)
confirmedBalance.setText(formatter.formatCoinWithCode(squWallet.getBalance()));
}
}

View file

@ -18,9 +18,9 @@
package io.bitsquare.gui.main.funds.deposit;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.listeners.TxConfidenceListener;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.gui.components.indicator.TxConfidenceIndicator;
import io.bitsquare.gui.util.BSFormatter;
import javafx.beans.property.SimpleStringProperty;
@ -33,7 +33,7 @@ import org.bitcoinj.core.TransactionConfidence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DepositListItem {
class DepositListItem {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final StringProperty balance = new SimpleStringProperty();
@ -41,7 +41,7 @@ public class DepositListItem {
private Coin balanceAsCoin;
private final TxConfidenceIndicator txConfidenceIndicator;
private final Tooltip tooltip;
private String addressString;
private final String addressString;
private String usage = "-";
private TxConfidenceListener txConfidenceListener;
private int numTxOutputs = 0;

View file

@ -20,9 +20,9 @@ package io.bitsquare.gui.main.funds.deposit;
import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.app.DevFlags;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.gui.common.view.ActivatableView;
@ -83,7 +83,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
private InputTextField amountTextField;
private final BtcWalletService walletService;
private FeeService feeService;
private final FeeService feeService;
private final BSFormatter formatter;
private final Preferences preferences;
private final String paymentLabelString;

View file

@ -18,8 +18,8 @@
package io.bitsquare.gui.main.funds.locked;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.trade.Tradable;
import io.bitsquare.trade.Trade;
@ -32,7 +32,7 @@ import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LockedListItem {
class LockedListItem {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final StringProperty date = new SimpleStringProperty();

View file

@ -19,8 +19,8 @@ package io.bitsquare.gui.main.funds.locked;
import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.gui.common.view.ActivatableView;
import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.components.HyperlinkWithIcon;

View file

@ -18,8 +18,8 @@
package io.bitsquare.gui.main.funds.reserved;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.trade.Tradable;
import io.bitsquare.trade.offer.OpenOffer;
@ -32,7 +32,7 @@ import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReservedListItem {
class ReservedListItem {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final StringProperty date = new SimpleStringProperty();

View file

@ -19,8 +19,8 @@ package io.bitsquare.gui.main.funds.reserved;
import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.gui.common.view.ActivatableView;
import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.components.HyperlinkWithIcon;

View file

@ -17,8 +17,8 @@
package io.bitsquare.gui.main.funds.transactions;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.listeners.TxConfidenceListener;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.gui.components.indicator.TxConfidenceIndicator;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.trade.Tradable;
@ -33,7 +33,7 @@ import javax.annotation.Nullable;
import java.util.Date;
import java.util.Optional;
public class TransactionsListItem {
class TransactionsListItem {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private String dateString;
@ -69,7 +69,7 @@ public class TransactionsListItem {
Coin valueSentToMe = transaction.getValueSentToMe(walletService.getWallet());
Coin valueSentFromMe = transaction.getValueSentFromMe(walletService.getWallet());
Address address = null;
Address address;
if (valueSentToMe.isZero()) {
amountAsCoin = valueSentFromMe.multiply(-1);
@ -186,7 +186,6 @@ public class TransactionsListItem {
private void updateConfidence(TransactionConfidence confidence) {
confirmations = confidence.getDepthInBlocks();
if (confidence != null) {
switch (confidence.getConfidenceType()) {
case UNKNOWN:
tooltip.setText("Unknown transaction status");
@ -209,7 +208,6 @@ public class TransactionsListItem {
txConfidenceIndicator.setPrefSize(24, 24);
}
}
public TxConfidenceIndicator getTxConfidenceIndicator() {
return txConfidenceIndicator;

View file

@ -20,7 +20,7 @@ package io.bitsquare.gui.main.funds.transactions;
import com.googlecode.jcsv.writer.CSVEntryConverter;
import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.arbitration.DisputeManager;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.common.util.Tuple4;
import io.bitsquare.common.util.Utilities;
@ -88,7 +88,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
private final Preferences preferences;
private final TradeDetailsWindow tradeDetailsWindow;
private final DisputeManager disputeManager;
private Stage stage;
private final Stage stage;
private final OfferDetailsWindow offerDetailsWindow;
private WalletEventListener walletEventListener;
private EventHandler<KeyEvent> keyEventEventHandler;
@ -564,9 +564,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
walletService.swapAnyTradeEntryContextToAvailableEntry(tradable.getId());
new Popup().information("Transaction successfully sent to a new address in the local Bitsquare wallet.").show();
}, errorMessage -> {
new Popup().warning(errorMessage).show();
});
}, errorMessage -> new Popup().warning(errorMessage).show());
} catch (Throwable e) {
new Popup().warning(e.getMessage()).show();
}

View file

@ -18,15 +18,15 @@
package io.bitsquare.gui.main.funds.withdrawal;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.gui.util.BSFormatter;
import javafx.scene.control.Label;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
public class WithdrawalListItem {
class WithdrawalListItem {
private final BalanceListener balanceListener;
private final Label balanceLabel;
private final AddressEntry addressEntry;
@ -83,12 +83,12 @@ public class WithdrawalListItem {
WithdrawalListItem that = (WithdrawalListItem) o;
return !(addressEntry != null ? !addressEntry.equals(that.addressEntry) : that.addressEntry != null);
return addressEntry.equals(that.addressEntry);
}
@Override
public int hashCode() {
return addressEntry != null ? addressEntry.hashCode() : 0;
return addressEntry.hashCode();
}
private Address getAddress() {

View file

@ -22,10 +22,10 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.app.DevFlags;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.AddressEntryException;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.InsufficientFundsException;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.MathUtils;
import io.bitsquare.gui.common.view.ActivatableView;
@ -90,7 +90,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
private BalanceListener balanceListener;
private Set<String> fromAddresses;
private Coin amountOfSelectedItems = Coin.ZERO;
private ObjectProperty<Coin> senderAmountAsCoinProperty = new SimpleObjectProperty<>(Coin.ZERO);
private final ObjectProperty<Coin> senderAmountAsCoinProperty = new SimpleObjectProperty<>(Coin.ZERO);
private ChangeListener<String> amountListener;
private ChangeListener<Boolean> amountFocusListener;

View file

@ -22,12 +22,12 @@ import io.bitsquare.app.DevFlags;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.blockchain.BlockchainService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.TradeWalletService;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.ActivatableDataModel;
@ -63,8 +63,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
class CreateOfferDataModel extends ActivatableDataModel {
private final OpenOfferManager openOfferManager;
final BtcWalletService walletService;
final TradeWalletService tradeWalletService;
private final BtcWalletService walletService;
private final TradeWalletService tradeWalletService;
private final Preferences preferences;
private final User user;
private final KeyRing keyRing;
@ -79,7 +79,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
private final AddressEntry addressEntry;
private Coin createOfferFeeAsCoin;
private Coin txFeeAsCoin;
private Coin securityDepositAsCoin;
private final Coin securityDepositAsCoin;
private final BalanceListener balanceListener;
private final SetChangeListener<PaymentAccount> paymentAccountsChangeListener;
@ -111,7 +111,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
PaymentAccount paymentAccount;
boolean isTabSelected;
private Notification walletFundedNotification;
boolean useSavingsWallet;
private boolean useSavingsWallet;
Coin totalAvailableBalance;
private double marketPriceMargin = 0;
@ -400,13 +400,9 @@ class CreateOfferDataModel extends ActivatableDataModel {
Optional<TradeCurrency> tradeCurrencyOptional = preferences.getTradeCurrenciesAsObservable().stream().filter(e -> e.getCode().equals(code)).findAny();
if (!tradeCurrencyOptional.isPresent()) {
if (CurrencyUtil.isCryptoCurrency(code)) {
CurrencyUtil.getCryptoCurrency(code).ifPresent(cryptoCurrency -> {
preferences.addCryptoCurrency(cryptoCurrency);
});
CurrencyUtil.getCryptoCurrency(code).ifPresent(preferences::addCryptoCurrency);
} else {
CurrencyUtil.getFiatCurrency(code).ifPresent(fiatCurrency -> {
preferences.addFiatCurrency(fiatCurrency);
});
CurrencyUtil.getFiatCurrency(code).ifPresent(preferences::addFiatCurrency);
}
}
}
@ -526,7 +522,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
}
}
void updateBalance() {
private void updateBalance() {
Coin tradeWalletBalance = walletService.getBalanceForAddress(addressEntry.getAddress());
if (useSavingsWallet) {
Coin savingWalletBalance = walletService.getSavingWalletBalance();

View file

@ -21,12 +21,12 @@ import com.google.inject.Inject;
import io.bitsquare.app.DevFlags;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.blockchain.BlockchainService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.TradeWalletService;
import io.bitsquare.gui.common.model.ActivatableDataModel;
import io.bitsquare.gui.main.overlays.notifications.Notification;
import io.bitsquare.gui.main.overlays.popups.Popup;
@ -59,8 +59,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
class TakeOfferDataModel extends ActivatableDataModel {
private final TradeManager tradeManager;
final TradeWalletService tradeWalletService;
final BtcWalletService walletService;
private final TradeWalletService tradeWalletService;
private final BtcWalletService walletService;
private final User user;
private final FeeService feeService;
private final Preferences preferences;
@ -88,9 +88,9 @@ class TakeOfferDataModel extends ActivatableDataModel {
final ObjectProperty<Coin> missingCoin = new SimpleObjectProperty<>(Coin.ZERO);
private BalanceListener balanceListener;
PaymentAccount paymentAccount;
private PaymentAccount paymentAccount;
private boolean isTabSelected;
boolean useSavingsWallet;
private boolean useSavingsWallet;
Coin totalAvailableBalance;
private Notification walletFundedNotification;
Fiat tradePrice;
@ -367,7 +367,7 @@ class TakeOfferDataModel extends ActivatableDataModel {
}
}
void updateBalance() {
private void updateBalance() {
Coin tradeWalletBalance = walletService.getBalanceForAddress(addressEntry.getAddress());
if (useSavingsWallet) {
Coin savingWalletBalance = walletService.getSavingWalletBalance();

View file

@ -21,9 +21,9 @@ import io.bitsquare.arbitration.Dispute;
import io.bitsquare.arbitration.DisputeManager;
import io.bitsquare.arbitration.DisputeResult;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.exceptions.TransactionVerificationException;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.TradeWalletService;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.gui.components.InputTextField;
@ -93,7 +93,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public DisputeSummaryWindow(BSFormatter formatter, DisputeManager disputeManager, BtcWalletService walletService, TradeWalletService tradeWalletService) {
private DisputeSummaryWindow(BSFormatter formatter, DisputeManager disputeManager, BtcWalletService walletService, TradeWalletService tradeWalletService) {
this.formatter = formatter;
this.disputeManager = disputeManager;
this.walletService = walletService;
@ -638,7 +638,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
hide();
finalizeDisputeHandlerOptional.ifPresent(finalizeDisputeHandler -> finalizeDisputeHandler.run());
finalizeDisputeHandlerOptional.ifPresent(Runnable::run);
} catch (AddressFormatException | TransactionVerificationException e2) {
e2.printStackTrace();
}

View file

@ -19,7 +19,7 @@ package io.bitsquare.gui.main.overlays.windows;
import io.bitsquare.app.DevFlags;
import io.bitsquare.btc.Restrictions;
import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.wallet.WalletService;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.gui.components.InputTextField;
@ -160,9 +160,7 @@ public class EmptyWalletWindow extends Overlay<EmptyWalletWindow> {
new Popup().warning("You have open offers which will be removed if you empty the wallet.\n" +
"Are you sure that you want to empty your wallet?")
.actionButtonText("Yes, I am sure")
.onAction(() -> {
doEmptyWallet2(aesKey);
})
.onAction(() -> doEmptyWallet2(aesKey))
.show(), 300, TimeUnit.MILLISECONDS);
} else {
doEmptyWallet2(aesKey);

View file

@ -17,8 +17,7 @@
package io.bitsquare.gui.main.overlays.windows;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.SquWalletService;
import io.bitsquare.btc.wallet.WalletsManager;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.main.overlays.Overlay;
@ -35,17 +34,15 @@ import static io.bitsquare.gui.util.FormBuilder.addLabelTextArea;
public class ShowWalletDataWindow extends Overlay<ShowWalletDataWindow> {
private static final Logger log = LoggerFactory.getLogger(ShowWalletDataWindow.class);
private BtcWalletService btcWalletService;
private SquWalletService squWalletService;
private final WalletsManager walletsManager;
///////////////////////////////////////////////////////////////////////////////////////////
// Public API
///////////////////////////////////////////////////////////////////////////////////////////
public ShowWalletDataWindow(BtcWalletService btcWalletService, SquWalletService squWalletService) {
this.btcWalletService = btcWalletService;
this.squWalletService = squWalletService;
public ShowWalletDataWindow(WalletsManager walletsManager) {
this.walletsManager = walletsManager;
type = Type.Attention;
}
@ -98,9 +95,7 @@ public class ShowWalletDataWindow extends Overlay<ShowWalletDataWindow> {
onAction(() -> Utilities.copyToClipboard(textArea.getText()));
}
private void showWallet(TextArea textArea, CheckBox isUpdateCheckBox) {
String btcWalletData = btcWalletService.exportWalletData(isUpdateCheckBox.isSelected());
String sqrWalletData = squWalletService.exportWalletData(isUpdateCheckBox.isSelected());
textArea.setText("BTC Wallet:\n" + btcWalletData + "\n\nSQU Wallet:\n" + sqrWalletData);
private void showWallet(TextArea textArea, CheckBox includePrivKeysCheckBox) {
textArea.setText(walletsManager.getWalletsAsString(includePrivKeysCheckBox.isSelected()));
}
}

View file

@ -18,9 +18,9 @@
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.btc.wallet.TradeWalletService;
import io.bitsquare.common.UserThread;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.main.overlays.Overlay;
@ -30,6 +30,7 @@ import javafx.scene.input.KeyCode;
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -42,7 +43,7 @@ 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;
private final TradeWalletService tradeWalletService;
///////////////////////////////////////////////////////////////////////////////////////////
@ -159,7 +160,7 @@ public class SpendFromDepositTxWindow extends Overlay<SpendFromDepositTxWindow>
}
@Override
public void onFailure(Throwable t) {
public void onFailure(@NotNull Throwable t) {
log.error(t.toString());
log.error("onFailure");
UserThread.execute(() -> new Popup<>().warning(t.toString()).show());

View file

@ -19,7 +19,7 @@ package io.bitsquare.gui.main.overlays.windows;
import com.google.common.base.Splitter;
import io.bitsquare.app.BitsquareApp;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.wallet.WalletsManager;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.crypto.ScryptUtil;
@ -44,7 +44,6 @@ import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import org.bitcoinj.core.Wallet;
import org.bitcoinj.crypto.KeyCrypterScrypt;
import org.bitcoinj.crypto.MnemonicCode;
import org.bitcoinj.crypto.MnemonicException;
@ -67,23 +66,25 @@ import static javafx.beans.binding.Bindings.createBooleanBinding;
public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
private static final Logger log = LoggerFactory.getLogger(WalletPasswordWindow.class);
private final BtcWalletService walletService;
private Button unlockButton;
private AesKeyHandler aesKeyHandler;
private PasswordTextField passwordTextField;
private Button forgotPasswordButton;
private Button restoreButton;
private TextArea restoreSeedWordsTextArea;
private TextArea btcSeedWordsTextArea, squSeedWordsTextArea;
private DatePicker restoreDatePicker;
private SimpleBooleanProperty seedWordsValid = new SimpleBooleanProperty(false);
private SimpleBooleanProperty dateValid = new SimpleBooleanProperty(false);
private BooleanProperty seedWordsEdited = new SimpleBooleanProperty();
private final SimpleBooleanProperty btcSeedWordsValid = new SimpleBooleanProperty(false);
private final SimpleBooleanProperty squSeedWordsValid = new SimpleBooleanProperty(false);
private final SimpleBooleanProperty dateValid = new SimpleBooleanProperty(false);
private final BooleanProperty btcSeedWordsEdited = new SimpleBooleanProperty();
private final BooleanProperty squSeedWordsEdited = new SimpleBooleanProperty();
private ChangeListener<String> changeListener;
private ChangeListener<String> seedWordsTextAreaChangeListener;
private ChangeListener<String> btcWordsTextAreaChangeListener, squWordsTextAreaChangeListener;
private ChangeListener<Boolean> datePickerChangeListener;
private ChangeListener<Boolean> seedWordsValidChangeListener;
private ChangeListener<LocalDate> dateChangeListener;
private LocalDate walletCreationDate;
private final WalletsManager walletsManager;
///////////////////////////////////////////////////////////////////////////////////////////
@ -95,8 +96,8 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
}
@Inject
public WalletPasswordWindow(BtcWalletService walletService) {
this.walletService = walletService;
private WalletPasswordWindow(WalletsManager walletsManager) {
this.walletsManager = walletsManager;
type = Type.Attention;
width = 800;
}
@ -136,15 +137,18 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
passwordTextField.textProperty().removeListener(changeListener);
if (seedWordsValidChangeListener != null) {
seedWordsValid.removeListener(seedWordsValidChangeListener);
btcSeedWordsValid.removeListener(seedWordsValidChangeListener);
dateValid.removeListener(datePickerChangeListener);
restoreSeedWordsTextArea.textProperty().removeListener(seedWordsTextAreaChangeListener);
btcSeedWordsTextArea.textProperty().removeListener(btcWordsTextAreaChangeListener);
squSeedWordsTextArea.textProperty().removeListener(squWordsTextAreaChangeListener);
restoreDatePicker.valueProperty().removeListener(dateChangeListener);
restoreButton.disableProperty().unbind();
restoreButton.setOnAction(null);
restoreSeedWordsTextArea.setText("");
btcSeedWordsTextArea.setText("");
squSeedWordsTextArea.setText("");
restoreDatePicker.setValue(null);
restoreSeedWordsTextArea.getStyleClass().remove("validation_error");
btcSeedWordsTextArea.getStyleClass().remove("validation_error");
squSeedWordsTextArea.getStyleClass().remove("validation_error");
restoreDatePicker.getStyleClass().remove("validation_error");
}
}
@ -193,13 +197,12 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
unlockButton.setOnAction(e -> {
String password = passwordTextField.getText();
checkArgument(password.length() < 50, "Password must be less then 50 characters.");
Wallet wallet = walletService.getWallet();
KeyCrypterScrypt keyCrypterScrypt = (KeyCrypterScrypt) wallet.getKeyCrypter();
KeyCrypterScrypt keyCrypterScrypt = walletsManager.getKeyCrypterScrypt();
if (keyCrypterScrypt != null) {
busyAnimation.play();
deriveStatusLabel.setText("Derive key from password");
ScryptUtil.deriveKeyWithScrypt(keyCrypterScrypt, password, aesKey -> {
if (wallet.checkAESKey(aesKey)) {
if (walletsManager.checkAESKey(aesKey)) {
if (aesKeyHandler != null)
aesKeyHandler.onAesKey(aesKey);
@ -229,7 +232,7 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
Button cancelButton = new Button("Cancel");
cancelButton.setOnAction(event -> {
hide();
closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run());
closeHandlerOptional.ifPresent(Runnable::run);
});
HBox hBox = new HBox();
@ -273,41 +276,56 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
gridPane.getChildren().add(separator);
Tuple2<Label, TextArea> tuple = addLabelTextArea(gridPane, ++rowIndex, "Wallet seed words:", "", 5);
restoreSeedWordsTextArea = tuple.second;
restoreSeedWordsTextArea.setPrefHeight(60);
restoreSeedWordsTextArea.setStyle("-fx-border-color: #ddd;");
Tuple2<Label, TextArea> tuple = addLabelTextArea(gridPane, ++rowIndex, "BTC wallet seed words:", "", 5);
btcSeedWordsTextArea = tuple.second;
btcSeedWordsTextArea.setPrefHeight(60);
btcSeedWordsTextArea.setStyle("-fx-border-color: #ddd;");
Tuple2<Label, TextArea> tuple2 = addLabelTextArea(gridPane, ++rowIndex, "SQU wallet seed words:", "", 5);
squSeedWordsTextArea = tuple2.second;
squSeedWordsTextArea.setPrefHeight(60);
squSeedWordsTextArea.setStyle("-fx-border-color: #ddd;");
Tuple2<Label, DatePicker> labelDatePickerTuple2 = addLabelDatePicker(gridPane, ++rowIndex, "Creation Date:");
restoreDatePicker = labelDatePickerTuple2.second;
restoreButton = addButton(gridPane, ++rowIndex, "Restore wallet");
restoreButton = addButton(gridPane, ++rowIndex, "Restore wallets");
restoreButton.setDefaultButton(true);
stage.setHeight(340);
DeterministicSeed keyChainSeed = walletService.getWallet().getKeyChainSeed();
// wallet creation date is not encrypted
walletCreationDate = Instant.ofEpochSecond(keyChainSeed.getCreationTimeSeconds()).atZone(ZoneId.systemDefault()).toLocalDate();
walletCreationDate = Instant.ofEpochSecond(walletsManager.getChainSeedCreationTimeSeconds()).atZone(ZoneId.systemDefault()).toLocalDate();
restoreButton.disableProperty().bind(createBooleanBinding(() -> !seedWordsValid.get() || !dateValid.get() || !seedWordsEdited.get(),
seedWordsValid, dateValid, seedWordsEdited));
restoreButton.disableProperty().bind(createBooleanBinding(() -> !btcSeedWordsValid.get() || !dateValid.get() || !btcSeedWordsEdited.get(),
btcSeedWordsValid, dateValid, btcSeedWordsEdited));
seedWordsValidChangeListener = (observable, oldValue, newValue) -> {
if (newValue) {
restoreSeedWordsTextArea.getStyleClass().remove("validation_error");
btcSeedWordsTextArea.getStyleClass().remove("validation_error");
} else {
restoreSeedWordsTextArea.getStyleClass().add("validation_error");
btcSeedWordsTextArea.getStyleClass().add("validation_error");
}
};
seedWordsTextAreaChangeListener = (observable, oldValue, newValue) -> {
seedWordsEdited.set(true);
btcWordsTextAreaChangeListener = (observable, oldValue, newValue) -> {
btcSeedWordsEdited.set(true);
try {
MnemonicCode codec = new MnemonicCode();
codec.check(Splitter.on(" ").splitToList(newValue));
seedWordsValid.set(true);
btcSeedWordsValid.set(true);
} catch (IOException | MnemonicException e) {
seedWordsValid.set(false);
btcSeedWordsValid.set(false);
}
};
squWordsTextAreaChangeListener = (observable, oldValue, newValue) -> {
squSeedWordsEdited.set(true);
try {
MnemonicCode codec = new MnemonicCode();
codec.check(Splitter.on(" ").splitToList(newValue));
squSeedWordsValid.set(true);
} catch (IOException | MnemonicException e) {
squSeedWordsValid.set(false);
}
};
@ -318,28 +336,27 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
else
restoreDatePicker.getStyleClass().add("validation_error");
};
dateChangeListener = (observable, oldValue, newValue) -> {
dateValid.set(walletCreationDate.equals(newValue));
};
dateChangeListener = (observable, oldValue, newValue) -> dateValid.set(walletCreationDate.equals(newValue));
seedWordsValid.addListener(seedWordsValidChangeListener);
btcSeedWordsValid.addListener(seedWordsValidChangeListener);
dateValid.addListener(datePickerChangeListener);
restoreSeedWordsTextArea.textProperty().addListener(seedWordsTextAreaChangeListener);
btcSeedWordsTextArea.textProperty().addListener(btcWordsTextAreaChangeListener);
squSeedWordsTextArea.textProperty().addListener(squWordsTextAreaChangeListener);
restoreDatePicker.valueProperty().addListener(dateChangeListener);
restoreButton.disableProperty().bind(createBooleanBinding(() -> !seedWordsValid.get() || !dateValid.get() || !seedWordsEdited.get(),
seedWordsValid, dateValid, seedWordsEdited));
restoreButton.disableProperty().bind(createBooleanBinding(() -> !btcSeedWordsValid.get() || !dateValid.get() || !btcSeedWordsEdited.get(),
btcSeedWordsValid, dateValid, btcSeedWordsEdited));
restoreButton.setOnAction(e -> onRestore());
restoreSeedWordsTextArea.getStyleClass().remove("validation_error");
btcSeedWordsTextArea.getStyleClass().remove("validation_error");
squSeedWordsTextArea.getStyleClass().remove("validation_error");
restoreDatePicker.getStyleClass().remove("validation_error");
layout();
}
private void onRestore() {
Wallet wallet = walletService.getWallet();
if (wallet.getBalance(Wallet.BalanceType.AVAILABLE).value > 0) {
if (walletsManager.hasPositiveBalance()) {
new Popup()
.warning("Your bitcoin wallet is not empty.\n\n" +
"You must empty this wallet before attempting to restore an older one, as mixing wallets " +
@ -357,7 +374,7 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
}
private void checkIfEncrypted() {
if (walletService.getWallet().isEncrypted()) {
if (walletsManager.areWalletsEncrypted()) {
new Popup()
.information("Your bitcoin wallet is encrypted.\n\n" +
"After restore, the wallet will no longer be encrypted and you must set a new password.\n\n" +
@ -373,8 +390,11 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
private void doRestore() {
long date = restoreDatePicker.getValue().atStartOfDay().toEpochSecond(ZoneOffset.UTC);
DeterministicSeed seed = new DeterministicSeed(Splitter.on(" ").splitToList(restoreSeedWordsTextArea.getText()), null, "", date);
walletService.restoreSeedWords(seed,
DeterministicSeed btcSeed = new DeterministicSeed(Splitter.on(" ").splitToList(btcSeedWordsTextArea.getText()), null, "", date);
DeterministicSeed squSeed = new DeterministicSeed(Splitter.on(" ").splitToList(squSeedWordsTextArea.getText()), null, "", date);
walletsManager.restoreSeedWords(
btcSeed,
squSeed,
() -> UserThread.execute(() -> {
log.debug("Wallet restored with seed words");

View file

@ -22,9 +22,9 @@ import io.bitsquare.app.Log;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.arbitration.Dispute;
import io.bitsquare.arbitration.DisputeManager;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.TradeWalletService;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.FaultHandler;
@ -70,11 +70,11 @@ public class PendingTradesDataModel extends ActivatableDataModel {
public final TradeManager tradeManager;
public final BtcWalletService walletService;
private final TradeWalletService tradeWalletService;
private FeeService feeService;
private final FeeService feeService;
private final User user;
private final KeyRing keyRing;
public final DisputeManager disputeManager;
private P2PService p2PService;
private final P2PService p2PService;
public final Navigation navigation;
public final WalletPasswordWindow walletPasswordWindow;
private final NotificationCenter notificationCenter;
@ -213,7 +213,7 @@ public class PendingTradesDataModel extends ActivatableDataModel {
return tradeManager.isMyOffer(offer);
}
boolean isOfferer() {
private boolean isOfferer() {
return isOfferer;
}

View file

@ -19,7 +19,11 @@ package io.bitsquare.gui.main.portfolio.pendingtrades.steps.buyer;
import io.bitsquare.app.DevFlags;
import io.bitsquare.app.Log;
import io.bitsquare.btc.*;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.AddressEntryException;
import io.bitsquare.btc.InsufficientFundsException;
import io.bitsquare.btc.Restrictions;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.FaultHandler;
import io.bitsquare.common.handlers.ResultHandler;
@ -54,8 +58,8 @@ import static io.bitsquare.gui.util.FormBuilder.*;
public class BuyerStep5View extends TradeStepView {
private final ChangeListener<Boolean> focusedPropertyListener;
protected Label btcTradeAmountLabel;
protected Label fiatTradeAmountLabel;
private Label btcTradeAmountLabel;
private Label fiatTradeAmountLabel;
private InputTextField withdrawAddressTextField;
private Button withdrawToExternalWalletButton, useSavingsWalletButton;

View file

@ -18,8 +18,7 @@
package io.bitsquare.gui.main.settings.network;
import io.bitsquare.app.BitsquareApp;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.WalletSetup;
import io.bitsquare.btc.wallet.WalletsSetup;
import io.bitsquare.common.Clock;
import io.bitsquare.common.UserThread;
import io.bitsquare.gui.common.model.Activatable;
@ -68,26 +67,24 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
TableColumn<P2pNetworkListItem, String> onionAddressColumn, connectionTypeColumn, creationDateColumn,
roundTripTimeColumn, sentBytesColumn, receivedBytesColumn, peerTypeColumn;
private final BtcWalletService walletService;
private final Preferences preferences;
private Clock clock;
private final Clock clock;
private final BSFormatter formatter;
private final WalletSetup walletSetup;
private final WalletsSetup walletsSetup;
private final P2PService p2PService;
private Subscription numP2PPeersSubscription;
private Subscription bitcoinPeersSubscription;
private Subscription nodeAddressSubscription;
private ObservableList<P2pNetworkListItem> networkListItems = FXCollections.observableArrayList();
private final ObservableList<P2pNetworkListItem> networkListItems = FXCollections.observableArrayList();
private final SortedList<P2pNetworkListItem> sortedList = new SortedList<>(networkListItems);
private ChangeListener<Boolean> btcNodesFocusListener;
private String btcNodesPreFocusText;
@Inject
public NetworkSettingsView(BtcWalletService walletService, WalletSetup walletSetup, P2PService p2PService, Preferences preferences, Clock clock,
public NetworkSettingsView(WalletsSetup walletsSetup, P2PService p2PService, Preferences preferences, Clock clock,
BSFormatter formatter) {
super();
this.walletService = walletService;
this.walletSetup = walletSetup;
this.walletsSetup = walletsSetup;
this.p2PService = p2PService;
this.preferences = preferences;
this.clock = clock;
@ -137,7 +134,7 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
}
});
bitcoinPeersSubscription = EasyBind.subscribe(walletSetup.connectedPeersProperty(), connectedPeers -> updateBitcoinPeersTextArea());
bitcoinPeersSubscription = EasyBind.subscribe(walletsSetup.connectedPeersProperty(), connectedPeers -> updateBitcoinPeersTextArea());
nodeAddressSubscription = EasyBind.subscribe(p2PService.getNetworkNode().nodeAddressProperty(),
nodeAddress -> onionAddress.setText(nodeAddress == null ? "Not known yet..." : p2PService.getAddress().getFullAddress()));
@ -204,7 +201,7 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
private void updateBitcoinPeersTextArea() {
bitcoinPeersTextArea.clear();
List<Peer> peerList = walletSetup.connectedPeersProperty().get();
List<Peer> peerList = walletsSetup.connectedPeersProperty().get();
if (peerList != null) {
peerList.stream().forEach(e -> {
if (bitcoinPeersTextArea.getText().length() > 0)

View file

@ -27,9 +27,9 @@ public class SQUFormatter extends BSFormatter {
private static final Logger log = LoggerFactory.getLogger(SQUFormatter.class);
@Inject
public SQUFormatter() {
private SQUFormatter() {
super();
coinFormat = new MonetaryFormat().shift(8).minDecimals(0).repeatOptionalDecimals(0, 0);
coinFormat = new MonetaryFormat().shift(5).minDecimals(0).code(5, "SQU").minDecimals(3);
}
}

View file

@ -8,9 +8,9 @@ import io.bitsquare.app.BitsquareEnvironment;
import io.bitsquare.app.Log;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.ArbitratorManager;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.SquWalletService;
import io.bitsquare.btc.WalletSetup;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.SquWalletService;
import io.bitsquare.btc.wallet.WalletsSetup;
import io.bitsquare.common.CommonOptionKeys;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.ResultHandler;
@ -39,7 +39,7 @@ public class Headless {
private final OpenOfferManager openOfferManager;
private final HeadlessModule headlessModule;
private P2PService p2pService;
private final P2PService p2pService;
public static void setEnvironment(Environment env) {
Headless.env = env;
@ -137,12 +137,12 @@ public class Headless {
injector.getInstance(ArbitratorManager.class).shutDown();
injector.getInstance(OpenOfferManager.class).shutDown(() -> {
injector.getInstance(P2PService.class).shutDown(() -> {
injector.getInstance(WalletSetup.class).shutDownDone.addListener((ov, o, n) -> {
injector.getInstance(WalletsSetup.class).shutDownDone.addListener((ov, o, n) -> {
headlessModule.close(injector);
log.debug("Graceful shutdown completed");
resultHandler.handleResult();
});
injector.getInstance(WalletSetup.class).shutDown();
injector.getInstance(WalletsSetup.class).shutDown();
injector.getInstance(BtcWalletService.class).shutDown();
injector.getInstance(SquWalletService.class).shutDown();
});

View file

@ -8,9 +8,9 @@ import io.bitsquare.app.BitsquareEnvironment;
import io.bitsquare.app.Log;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.ArbitratorManager;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.SquWalletService;
import io.bitsquare.btc.WalletSetup;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.SquWalletService;
import io.bitsquare.btc.wallet.WalletsSetup;
import io.bitsquare.common.CommonOptionKeys;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.ResultHandler;
@ -40,7 +40,7 @@ public class Monitor {
private final OpenOfferManager openOfferManager;
private final MonitorModule monitorModule;
private P2PService p2pService;
private final P2PService p2pService;
public static void setEnvironment(Environment env) {
Monitor.env = env;
@ -140,12 +140,12 @@ public class Monitor {
injector.getInstance(ArbitratorManager.class).shutDown();
injector.getInstance(OpenOfferManager.class).shutDown(() -> {
injector.getInstance(P2PService.class).shutDown(() -> {
injector.getInstance(WalletSetup.class).shutDownDone.addListener((ov, o, n) -> {
injector.getInstance(WalletsSetup.class).shutDownDone.addListener((ov, o, n) -> {
monitorModule.close(injector);
log.debug("Graceful shutdown completed");
resultHandler.handleResult();
});
injector.getInstance(WalletSetup.class).shutDown();
injector.getInstance(WalletsSetup.class).shutDown();
injector.getInstance(BtcWalletService.class).shutDown();
injector.getInstance(SquWalletService.class).shutDown();
});

View file

@ -8,9 +8,9 @@ import io.bitsquare.app.BitsquareEnvironment;
import io.bitsquare.app.Log;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.ArbitratorManager;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.SquWalletService;
import io.bitsquare.btc.WalletSetup;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.SquWalletService;
import io.bitsquare.btc.wallet.WalletsSetup;
import io.bitsquare.common.CommonOptionKeys;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.ResultHandler;
@ -38,7 +38,7 @@ public class SeedNode {
private final SeedNodeModule seedNodeModule;
private final TradeStatisticsManager tradeStatisticsManager;
private P2PService p2pService;
private final P2PService p2pService;
public static void setEnvironment(Environment env) {
SeedNode.env = env;
@ -92,7 +92,7 @@ public class SeedNode {
tradeStatisticsManager = injector.getInstance(TradeStatisticsManager.class);
}
public void shutDown() {
private void shutDown() {
gracefulShutDown(() -> {
log.debug("Shutdown complete");
System.exit(0);
@ -106,12 +106,12 @@ public class SeedNode {
injector.getInstance(ArbitratorManager.class).shutDown();
injector.getInstance(OpenOfferManager.class).shutDown(() -> {
injector.getInstance(P2PService.class).shutDown(() -> {
injector.getInstance(WalletSetup.class).shutDownDone.addListener((ov, o, n) -> {
injector.getInstance(WalletsSetup.class).shutDownDone.addListener((ov, o, n) -> {
seedNodeModule.close(injector);
log.debug("Graceful shutdown completed");
resultHandler.handleResult();
});
injector.getInstance(WalletSetup.class).shutDown();
injector.getInstance(WalletsSetup.class).shutDown();
injector.getInstance(BtcWalletService.class).shutDown();
injector.getInstance(SquWalletService.class).shutDown();
});

View file

@ -8,10 +8,10 @@ import io.bitsquare.app.BitsquareEnvironment;
import io.bitsquare.app.Log;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.ArbitratorManager;
import io.bitsquare.btc.BtcWalletService;
import io.bitsquare.btc.SquWalletService;
import io.bitsquare.btc.WalletSetup;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.btc.wallet.BtcWalletService;
import io.bitsquare.btc.wallet.SquWalletService;
import io.bitsquare.btc.wallet.WalletsSetup;
import io.bitsquare.common.CommonOptionKeys;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.ResultHandler;
@ -43,7 +43,7 @@ public class Statistics {
private final OfferBookService offerBookService;
private final PriceFeedService priceFeedService;
private P2PService p2pService;
private final P2PService p2pService;
public static void setEnvironment(Environment env) {
Statistics.env = env;
@ -105,7 +105,7 @@ public class Statistics {
(errorMessage, throwable) -> log.warn(throwable.getMessage()));
}
public void shutDown() {
private void shutDown() {
gracefulShutDown(() -> {
log.debug("Shutdown complete");
System.exit(0);
@ -119,12 +119,12 @@ public class Statistics {
injector.getInstance(ArbitratorManager.class).shutDown();
injector.getInstance(OpenOfferManager.class).shutDown(() -> {
injector.getInstance(P2PService.class).shutDown(() -> {
injector.getInstance(WalletSetup.class).shutDownDone.addListener((ov, o, n) -> {
injector.getInstance(WalletsSetup.class).shutDownDone.addListener((ov, o, n) -> {
statisticsModule.close(injector);
log.debug("Graceful shutdown completed");
resultHandler.handleResult();
});
injector.getInstance(WalletSetup.class).shutDown();
injector.getInstance(WalletsSetup.class).shutDown();
injector.getInstance(BtcWalletService.class).shutDown();
injector.getInstance(SquWalletService.class).shutDown();
});