diff --git a/pom.xml b/pom.xml index 25b664e8ea..8067c84c28 100644 --- a/pom.xml +++ b/pom.xml @@ -110,12 +110,19 @@ - + com.google + bitcoinj + 0.12-SNAPSHOT + + + net.tomp2p diff --git a/src/main/java/io/bitsquare/BitSquare.java b/src/main/java/io/bitsquare/BitSquare.java index 6a2bc5f9b5..2e5980fcba 100644 --- a/src/main/java/io/bitsquare/BitSquare.java +++ b/src/main/java/io/bitsquare/BitSquare.java @@ -138,7 +138,9 @@ public class BitSquare extends Application private MenuBar getMenuBar() { MenuBar menuBar = new MenuBar(); - menuBar.setUseSystemMenuBar(true); + // on mac we could placemenu bar in the systems menu + // menuBar.setUseSystemMenuBar(true); + menuBar.setUseSystemMenuBar(false); Menu fileMenu = new Menu("_File"); fileMenu.setMnemonicParsing(true); diff --git a/src/main/java/io/bitsquare/btc/AddressBasedCoinSelector.java b/src/main/java/io/bitsquare/btc/AddressBasedCoinSelector.java index cdf8823e43..58628dad6f 100644 --- a/src/main/java/io/bitsquare/btc/AddressBasedCoinSelector.java +++ b/src/main/java/io/bitsquare/btc/AddressBasedCoinSelector.java @@ -6,10 +6,7 @@ import com.google.bitcoin.wallet.CoinSelection; import com.google.bitcoin.wallet.DefaultCoinSelector; import com.google.common.annotations.VisibleForTesting; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; +import java.util.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,38 +42,33 @@ class AddressBasedCoinSelector extends DefaultCoinSelector @VisibleForTesting static void sortOutputs(ArrayList outputs) { - Collections.sort(outputs, (a, b) -> { - int depth1 = 0; - int depth2 = 0; - TransactionConfidence conf1 = a.getParentTransaction().getConfidence(); - TransactionConfidence conf2 = b.getParentTransaction().getConfidence(); - if (conf1.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) + Collections.sort(outputs, new Comparator() + { + @Override + public int compare(TransactionOutput a, TransactionOutput b) { - depth1 = conf1.getDepthInBlocks(); + int depth1 = 0; + int depth2 = 0; + TransactionConfidence conf1 = a.getParentTransaction().getConfidence(); + TransactionConfidence conf2 = b.getParentTransaction().getConfidence(); + if (conf1.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) + depth1 = conf1.getDepthInBlocks(); + if (conf2.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) + depth2 = conf2.getDepthInBlocks(); + Coin aValue = a.getValue(); + Coin bValue = b.getValue(); + BigInteger aCoinDepth = BigInteger.valueOf(aValue.value).multiply(BigInteger.valueOf(depth1)); + BigInteger bCoinDepth = BigInteger.valueOf(bValue.value).multiply(BigInteger.valueOf(depth2)); + int c1 = bCoinDepth.compareTo(aCoinDepth); + if (c1 != 0) return c1; + // The "coin*days" destroyed are equal, sort by value alone to get the lowest transaction size. + int c2 = bValue.compareTo(aValue); + if (c2 != 0) return c2; + // They are entirely equivalent (possibly pending) so sort by hash to ensure a total ordering. + BigInteger aHash = a.getParentTransaction().getHash().toBigInteger(); + BigInteger bHash = b.getParentTransaction().getHash().toBigInteger(); + return aHash.compareTo(bHash); } - if (conf2.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) - { - depth2 = conf2.getDepthInBlocks(); - } - BigInteger aValue = a.getValue(); - BigInteger bValue = b.getValue(); - BigInteger aCoinDepth = aValue.multiply(BigInteger.valueOf(depth1)); - BigInteger bCoinDepth = bValue.multiply(BigInteger.valueOf(depth2)); - int c1 = bCoinDepth.compareTo(aCoinDepth); - if (c1 != 0) - { - return c1; - } - // The "coin*days" destroyed are equal, sort by value alone to get the lowest transaction size. - int c2 = bValue.compareTo(aValue); - if (c2 != 0) - { - return c2; - } - // They are entirely equivalent (possibly pending) so sort by hash to ensure a total ordering. - BigInteger aHash = a.getParentTransaction().getHash().toBigInteger(); - BigInteger bHash = b.getParentTransaction().getHash().toBigInteger(); - return aHash.compareTo(bHash); }); } @@ -129,7 +121,7 @@ class AddressBasedCoinSelector extends DefaultCoinSelector } - public CoinSelection select(BigInteger biTarget, LinkedList candidates) + public CoinSelection select(Coin biTarget, LinkedList candidates) { long target = biTarget.longValue(); HashSet selected = new HashSet<>(); @@ -163,7 +155,7 @@ class AddressBasedCoinSelector extends DefaultCoinSelector } // Total may be lower than target here, if the given candidates were insufficient to create to requested // transaction. - return new CoinSelection(BigInteger.valueOf(total), selected); + return new CoinSelection(Coin.valueOf(total), selected); } /* diff --git a/src/main/java/io/bitsquare/btc/AddressEntry.java b/src/main/java/io/bitsquare/btc/AddressEntry.java index 0f03f1510a..0e4770f2a4 100644 --- a/src/main/java/io/bitsquare/btc/AddressEntry.java +++ b/src/main/java/io/bitsquare/btc/AddressEntry.java @@ -1,25 +1,28 @@ package io.bitsquare.btc; import com.google.bitcoin.core.Address; -import com.google.bitcoin.core.ECKey; import com.google.bitcoin.core.NetworkParameters; import com.google.bitcoin.core.Utils; +import com.google.bitcoin.crypto.DeterministicKey; import java.io.Serializable; public class AddressEntry implements Serializable { private static final long serialVersionUID = 5501603992599920416L; - private final ECKey key; + private transient DeterministicKey key; private final NetworkParameters params; private final AddressContext addressContext; + private final byte[] pubKeyHash; private String tradeId = null; - public AddressEntry(ECKey key, NetworkParameters params, AddressContext addressContext) + public AddressEntry(DeterministicKey key, NetworkParameters params, AddressContext addressContext) { this.key = key; this.params = params; this.addressContext = addressContext; + + pubKeyHash = key.getPubOnly().getPubKeyHash(); } @@ -45,10 +48,10 @@ public class AddressEntry implements Serializable public String getPubKeyAsHexString() { - return Utils.bytesToHexString(key.getPubKey()); + return Utils.HEX.encode(key.getPubKey()); } - public ECKey getKey() + public DeterministicKey getKey() { return key; } @@ -58,6 +61,16 @@ public class AddressEntry implements Serializable return key.toAddress(params); } + public void setDeterministicKey(DeterministicKey key) + { + this.key = key; + } + + public byte[] getPubKeyHash() + { + return pubKeyHash; + } + public static enum AddressContext { REGISTRATION_FEE, diff --git a/src/main/java/io/bitsquare/btc/BitSquareWallet.java b/src/main/java/io/bitsquare/btc/BitSquareWallet.java deleted file mode 100644 index cbcc1d4621..0000000000 --- a/src/main/java/io/bitsquare/btc/BitSquareWallet.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.bitsquare.btc; - -import com.google.bitcoin.core.NetworkParameters; -import com.google.bitcoin.core.Wallet; -import com.google.bitcoin.crypto.KeyCrypter; -import java.io.Serializable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class BitSquareWallet extends Wallet implements Serializable -{ - private static final Logger log = LoggerFactory.getLogger(BitSquareWallet.class); - private static final long serialVersionUID = -6231929674475881549L; - - public BitSquareWallet(NetworkParameters params) - { - super(params); - } - - private BitSquareWallet(NetworkParameters params, KeyCrypter keyCrypter) - { - super(params, keyCrypter); - } - -} diff --git a/src/main/java/io/bitsquare/btc/BitSquareWalletAppKit.java b/src/main/java/io/bitsquare/btc/BitSquareWalletAppKit.java deleted file mode 100644 index ea5a990317..0000000000 --- a/src/main/java/io/bitsquare/btc/BitSquareWalletAppKit.java +++ /dev/null @@ -1,171 +0,0 @@ -package io.bitsquare.btc; - -import com.google.bitcoin.core.*; -import com.google.bitcoin.kits.WalletAppKit; -import com.google.bitcoin.net.discovery.DnsDiscovery; -import com.google.bitcoin.store.BlockStoreException; -import com.google.bitcoin.store.SPVBlockStore; -import com.google.bitcoin.store.WalletProtobufSerializer; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.concurrent.TimeUnit; - -public class BitSquareWalletAppKit extends WalletAppKit -{ - - public BitSquareWalletAppKit(NetworkParameters params, File directory) - { - super(params, directory, WalletFacade.WALLET_PREFIX); - } - - @Override - protected void startUp() throws Exception - { - // Runs in a separate thread. - if (!directory.exists()) - { - if (!directory.mkdir()) - { - throw new IOException("Could not create named directory " + directory.getCanonicalPath()); - } - } - FileInputStream walletStream = null; - try - { - File chainFile = new File(directory, filePrefix + ".spvchain"); - boolean chainFileExists = chainFile.exists(); - vWalletFile = new File(directory, filePrefix + ".wallet"); - boolean shouldReplayWallet = vWalletFile.exists() && !chainFileExists; - - vStore = new SPVBlockStore(params, chainFile); - if (!chainFileExists && checkpoints != null) - { - // Ugly hack! We have to create the wallet once here to learn the earliest key time, and then throw it - // away. The reason is that wallet extensions might need access to peergroups/chains/etc so we have to - // create the wallet later, but we need to know the time early here before we create the BlockChain - // object. - long time = Long.MAX_VALUE; - if (vWalletFile.exists()) - { - Wallet wallet = new BitSquareWallet(params); - FileInputStream stream = new FileInputStream(vWalletFile); - new WalletProtobufSerializer().readWallet(WalletProtobufSerializer.parseToProto(stream), wallet); - time = wallet.getEarliestKeyCreationTime(); - } - CheckpointManager.checkpoint(params, checkpoints, vStore, time); - } - vChain = new BlockChain(params, vStore); - vPeerGroup = createPeerGroup(); - - vPeerGroup.setBloomFilterFalsePositiveRate(0.001); // 0,1% instead of default 0,05% - - if (this.userAgent != null) - { - vPeerGroup.setUserAgent(userAgent, version); - } - if (vWalletFile.exists()) - { - walletStream = new FileInputStream(vWalletFile); - vWallet = new BitSquareWallet(params); - addWalletExtensions(); // All extensions must be present before we deserialize - new WalletProtobufSerializer().readWallet(WalletProtobufSerializer.parseToProto(walletStream), vWallet); - if (shouldReplayWallet) - { - vWallet.clearTransactions(0); - } - } - else - { - vWallet = new BitSquareWallet(params); - vWallet.addKey(new ECKey()); - addWalletExtensions(); - } - if (useAutoSave) - { - vWallet.autosaveToFile(vWalletFile, 1, TimeUnit.SECONDS, null); - } - // Set up peer addresses or discovery first, so if wallet extensions try to broadcast a transaction - // before we're actually connected the broadcast waits for an appropriate number of connections. - if (peerAddresses != null) - { - for (PeerAddress addr : peerAddresses) - { - vPeerGroup.addAddress(addr); - } - peerAddresses = null; - } - else - { - vPeerGroup.addPeerDiscovery(new DnsDiscovery(params)); - } - vChain.addWallet(vWallet); - vPeerGroup.addWallet(vWallet); - onSetupCompleted(); - - if (blockingStartup) - { - vPeerGroup.startAsync(); - vPeerGroup.awaitRunning(); - // Make sure we shut down cleanly. - installShutdownHook(); - // TODO: Be able to use the provided download listener when doing a blocking startup. - final DownloadListener listener = new DownloadListener(); - vPeerGroup.startBlockChainDownload(listener); - listener.await(); - } - else - { - //TODO deprecated - Futures.addCallback(vPeerGroup.start(), new FutureCallback() - { - @Override - public void onSuccess(State result) - { - final PeerEventListener l = downloadListener == null ? new DownloadListener() : downloadListener; - vPeerGroup.startBlockChainDownload(l); - } - - @Override - public void onFailure(Throwable t) - { - throw new RuntimeException(t); - } - }); - } - } catch (BlockStoreException e) - { - throw new IOException(e); - } finally - { - if (walletStream != null) - { - walletStream.close(); - } - } - } - - private void installShutdownHook() - { - if (autoStop) - { - Runtime.getRuntime().addShutdownHook(new Thread() - { - @Override - public void run() - { - try - { - BitSquareWalletAppKit.this.stopAsync(); - - } catch (Exception e) - { - throw new RuntimeException(e); - } - } - }); - } - } -} diff --git a/src/main/java/io/bitsquare/btc/BtcFormatter.java b/src/main/java/io/bitsquare/btc/BtcFormatter.java deleted file mode 100644 index 6763e5331c..0000000000 --- a/src/main/java/io/bitsquare/btc/BtcFormatter.java +++ /dev/null @@ -1,59 +0,0 @@ -package io.bitsquare.btc; - -import com.google.bitcoin.core.Utils; -import io.bitsquare.gui.util.BitSquareConverter; -import java.math.BigInteger; -import java.text.DecimalFormat; -import java.util.Locale; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -// TODO -public class BtcFormatter -{ - private static final BigInteger BTC = new BigInteger("100000000"); - private static final Logger log = LoggerFactory.getLogger(BtcFormatter.class); - - public static BigInteger mBTC = new BigInteger("100000"); - - - public static String formatSatoshis(BigInteger value) - { - return Utils.bitcoinValueToFriendlyString(value); - } - - //TODO - public static double satoshiToBTC(BigInteger satoshis) - { - return satoshis.doubleValue() / BTC.doubleValue(); - } - - public static BigInteger stringValueToSatoshis(String value) - { - try - { - return Utils.toNanoCoins(String.valueOf(BitSquareConverter.stringToDouble(value))); - } catch (ArithmeticException e) - { - log.warn("ArithmeticException " + e); - } - return BigInteger.ZERO; - } - - public static BigInteger doubleValueToSatoshis(double value) - { - try - { - // only "." as decimal sep supported by Utils.toNanoCoins - final DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Locale.ENGLISH); - decimalFormat.setMaximumFractionDigits(10); - decimalFormat.setMinimumFractionDigits(10); - String stringValue = decimalFormat.format(value); - return Utils.toNanoCoins(stringValue); - } catch (Exception e) - { - log.warn("Exception at doubleValueToSatoshis " + e.getMessage()); - return BigInteger.ZERO; - } - } -} diff --git a/src/main/java/io/bitsquare/btc/BtcValidator.java b/src/main/java/io/bitsquare/btc/BtcValidator.java index 2fd5388ced..c242439baa 100644 --- a/src/main/java/io/bitsquare/btc/BtcValidator.java +++ b/src/main/java/io/bitsquare/btc/BtcValidator.java @@ -1,10 +1,8 @@ package io.bitsquare.btc; -import com.google.bitcoin.core.Address; -import com.google.bitcoin.core.AddressFormatException; +import com.google.bitcoin.core.Coin; import com.google.bitcoin.core.NetworkParameters; import com.google.bitcoin.core.Transaction; -import java.math.BigInteger; import javax.inject.Inject; public class BtcValidator @@ -17,12 +15,12 @@ public class BtcValidator BtcValidator.params = params; } - public static boolean isMinSpendableAmount(BigInteger amount) + public static boolean isMinSpendableAmount(Coin amount) { return amount != null && amount.compareTo(FeePolicy.TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT)) > 0; } - public boolean isAddressValid(String addressString) + /* public boolean isAddressValid(String addressString) { try { @@ -32,6 +30,6 @@ public class BtcValidator { return false; } - } + } */ } diff --git a/src/main/java/io/bitsquare/btc/FeePolicy.java b/src/main/java/io/bitsquare/btc/FeePolicy.java index eb1a8d72f9..d7a0bb0e8e 100644 --- a/src/main/java/io/bitsquare/btc/FeePolicy.java +++ b/src/main/java/io/bitsquare/btc/FeePolicy.java @@ -1,17 +1,16 @@ package io.bitsquare.btc; import com.google.bitcoin.core.*; -import java.math.BigInteger; import javax.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FeePolicy { - public static final BigInteger TX_FEE = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; - public static final BigInteger ACCOUNT_REGISTRATION_FEE = Utils.toNanoCoins("0.01"); - public static final BigInteger CREATE_OFFER_FEE = Utils.toNanoCoins("0.001"); - public static final BigInteger TAKE_OFFER_FEE = CREATE_OFFER_FEE; + public static final Coin TX_FEE = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; + public static final Coin ACCOUNT_REGISTRATION_FEE = Coin.CENT; // 0.01 + public static final Coin CREATE_OFFER_FEE = Coin.MILLICOIN; // 0.001 + public static final Coin TAKE_OFFER_FEE = CREATE_OFFER_FEE; private static final Logger log = LoggerFactory.getLogger(FeePolicy.class); private static final String registrationFeeAddress = "mvkDXt4QmN4Nq9dRUsRigBCaovde9nLkZR"; private static final String createOfferFeeAddress = "n2upbsaKAe4PD3cc4JfS7UCqPC5oNd7Ckg"; diff --git a/src/main/java/io/bitsquare/btc/WalletFacade.java b/src/main/java/io/bitsquare/btc/WalletFacade.java index aa7a4e22ae..4752ece02f 100644 --- a/src/main/java/io/bitsquare/btc/WalletFacade.java +++ b/src/main/java/io/bitsquare/btc/WalletFacade.java @@ -1,7 +1,9 @@ package io.bitsquare.btc; import com.google.bitcoin.core.*; +import com.google.bitcoin.crypto.DeterministicKey; import com.google.bitcoin.crypto.TransactionSignature; +import com.google.bitcoin.kits.WalletAppKit; import com.google.bitcoin.params.MainNetParams; import com.google.bitcoin.params.RegTestParams; import com.google.bitcoin.script.Script; @@ -18,6 +20,7 @@ import io.bitsquare.btc.listeners.BalanceListener; import io.bitsquare.btc.listeners.ConfidenceListener; import io.bitsquare.crypto.CryptoFacade; import io.bitsquare.storage.Persistence; +import io.bitsquare.util.StorageDirectory; import java.io.Serializable; import java.math.BigInteger; import java.util.*; @@ -30,10 +33,9 @@ import javax.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static com.google.bitcoin.script.ScriptOpCodes.OP_RETURN; - /** * TODO: use walletextension (with protobuffer) instead of saving addressEntryList via storage + * TODO: use HD wallet features instead of addressEntryList */ public class WalletFacade { @@ -49,14 +51,14 @@ public class WalletFacade private final NetworkParameters params; - private final BitSquareWalletAppKit walletAppKit; + private WalletAppKit walletAppKit; private final FeePolicy feePolicy; private final CryptoFacade cryptoFacade; private final Persistence persistence; private final List downloadListeners = new ArrayList<>(); private final List confidenceListeners = new ArrayList<>(); private final List balanceListeners = new ArrayList<>(); - private BitSquareWallet wallet; + private Wallet wallet; private WalletEventListener walletEventListener; @GuardedBy("lock") @@ -67,10 +69,9 @@ public class WalletFacade /////////////////////////////////////////////////////////////////////////////////////////// @Inject - public WalletFacade(NetworkParameters params, BitSquareWalletAppKit walletAppKit, FeePolicy feePolicy, CryptoFacade cryptoFacade, Persistence persistence) + public WalletFacade(NetworkParameters params, FeePolicy feePolicy, CryptoFacade cryptoFacade, Persistence persistence) { this.params = params; - this.walletAppKit = walletAppKit; this.feePolicy = feePolicy; this.cryptoFacade = cryptoFacade; this.persistence = persistence; @@ -81,7 +82,7 @@ public class WalletFacade // Public Methods /////////////////////////////////////////////////////////////////////////////////////////// - public void initWallet() + public void initialize(StartupListener startupListener) { // Tell bitcoinj to execute event handlers on the JavaFX UI thread. This keeps things simple and means // we cannot forget to switch threads when adding event handlers. Unfortunately, the DownloadListener @@ -89,9 +90,27 @@ public class WalletFacade // a future version. Threading.USER_THREAD = Platform::runLater; + // If seed is non-null it means we are restoring from backup. + walletAppKit = new WalletAppKit(params, StorageDirectory.getStorageDirectory(), WALLET_PREFIX) + { + @Override + protected void onSetupCompleted() + { + // Don't make the user wait for confirmations for now, as the intention is they're sending it + // their own money! + walletAppKit.wallet().allowSpendingUnconfirmedTransactions(); + if (params != RegTestParams.get()) + walletAppKit.peerGroup().setMaxConnections(11); + walletAppKit.peerGroup().setBloomFilterFalsePositiveRate(0.00001); + initWallet(); + Platform.runLater(startupListener::completed); + } + }; + // Now configure and start the appkit. This will take a second or two - we could show a temporary splash screen + // or progress widget to keep the user engaged whilst we initialise, but we don't. if (params == RegTestParams.get()) { - walletAppKit.connectToLocalHost(); // You should execute a regtest mode bitcoind locally. + walletAppKit.connectToLocalHost(); // You should run a regtest mode bitcoind locally. } else if (params == MainNetParams.get()) { @@ -99,23 +118,21 @@ public class WalletFacade // in the checkpoints file and then download the rest from the network. It makes things much faster. // Checkpoint files are made using the BuildCheckpoints tool and usually we have to download the // last months worth or more (takes a few seconds). - walletAppKit.setCheckpoints(getClass().getResourceAsStream("/wallet/checkpoints")); + walletAppKit.setCheckpoints(getClass().getResourceAsStream("checkpoints")); + // As an example! + // walletAppKit.useTor(); } + walletAppKit.setDownloadListener(new BlockChainDownloadListener()) + .setBlockingStartup(false) + .restoreWalletFromSeed(null) + .setUserAgent("BitSquare", "0.1"); - walletAppKit.setAutoSave(true); - - // add well known stable nodes - //walletAppKit.peerGroup().addAddress(); - - // Now configure and start the appkit. This will take a second or two - we could show a temporary splash screen - // or progress widget to keep the user engaged whilst we initialise, but we don't. - walletAppKit.setDownloadListener(new BlockChainDownloadListener()); - walletAppKit.setBlockingStartup(false); - walletAppKit.setUserAgent("BitSquare", "0.1"); walletAppKit.startAsync(); - walletAppKit.awaitRunning(); + } - wallet = (BitSquareWallet) walletAppKit.wallet(); + private void initWallet() + { + wallet = walletAppKit.wallet(); wallet.allowSpendingUnconfirmedTransactions(); //walletAppKit.peerGroup().setMaxConnections(11); @@ -127,45 +144,48 @@ public class WalletFacade /* else walletAppKit.peerGroup().setMinBroadcastConnections(2); */ - walletEventListener = new WalletEventListener() { @Override - public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) + public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { notifyBalanceListeners(); } + @Override + public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) + { + notifyBalanceListeners(); + } + + @Override + public void onReorganize(Wallet wallet) + { + + } + @Override public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) { notifyConfidenceListeners(tx); } - @Override - public void onCoinsSent(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) - { - notifyBalanceListeners(); - } - - @Override - public void onReorganize(Wallet wallet) - { - } - @Override public void onWalletChanged(Wallet wallet) { - } - @Override - public void onKeysAdded(Wallet wallet, List keys) - { } @Override public void onScriptsAdded(Wallet wallet, List