diff --git a/README.md b/README.md index 36764bb759..115f834a69 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,7 @@ This is just a first very basic GUI prototype with mock data. There is only the trade process for Sell BTC and the role of the offer taker modelled yet. The project use Java 8 and Maven. - -We use bitcoinj library as a submodule. To get the project with the submodule included use: -git clone --recursive git://github.com/bitsquare/bitsquare +We use the bitcoinj library and TomP2P for DHT and messaging. ### Implemented (prototype level): * Screen for orderbook with filtering mock offers by amount, price and order type (buy, sell) @@ -22,12 +20,12 @@ git clone --recursive git://github.com/bitsquare/bitsquare * Pay in to MS fund * Payout from MS fund * TomP2P as messaging lib integrated and basic use cases in msg screen implemented: orderbook, add order, remove order, find peer, chat with peer +* Payment process until wait for bank transfer implemented with messaging ### Next steps: -* Implement messaging with TomP2P for registration, orderbook and payment process +* Payment process after wait for bank transfer implemented with messaging * Arbitrator integration * Other trade variants (Buy BTC taker, Sell BTC offerer, Sell BTC offerer) -* Verify registration and fee payments tx and get them from the blockchain * ... diff --git a/TODO.txt b/TODO.txt index 5e55bbfa05..805e4623fc 100644 --- a/TODO.txt +++ b/TODO.txt @@ -2,11 +2,11 @@ - settings low prio: -- tx confirm. not working correct and reliable -- add settings after setup +- start with orderbook and open registration when user interacts with orderbook (take offer, create offer) - settings screen - return to setup when unregistered, change/add bank accounts from settings -- BigInteger for all btc values +- formatting +- validation diff --git a/libs/bitcoinj b/libs/bitcoinj deleted file mode 160000 index eda6dccf6d..0000000000 --- a/libs/bitcoinj +++ /dev/null @@ -1 +0,0 @@ -Subproject commit eda6dccf6dc015df613a19f1fc0b5c3c98546185 diff --git a/pom.xml b/pom.xml index 6ca28ffb93..260105f324 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,7 @@ A P2P Fiat-Bitcoin Exchange https://www.bitsquare.io + + GNU AFFERO GENERAL PUBLIC LICENSE @@ -97,13 +100,18 @@ - com.google bitcoinj - 0.12-SNAPSHOT + 0.11.2 + + + + net.tomp2p + TomP2P + 4.4 @@ -112,20 +120,13 @@ 4.11 test - + org.slf4j slf4j-api 1.7.7 - ch.qos.logback logback-classic @@ -146,12 +147,6 @@ 16.0.1 - - com.aquafx-project - aquafx - 0.1 - - com.google.code.gson gson @@ -177,9 +172,9 @@ - net.tomp2p - TomP2P - 4.4 + com.madgag.spongycastle + core + 1.50.0.0 @@ -187,11 +182,11 @@ - - org.apache.maven.plugins - maven-jxr-plugin - 2.1 - + diff --git a/src/main/java/io/bitsquare/BitSquare.java b/src/main/java/io/bitsquare/BitSquare.java index 436eee24f3..a09e9237cd 100644 --- a/src/main/java/io/bitsquare/BitSquare.java +++ b/src/main/java/io/bitsquare/BitSquare.java @@ -1,5 +1,6 @@ package io.bitsquare; +import com.google.bitcoin.core.ECKey; import com.google.bitcoin.core.Utils; import com.google.inject.Guice; import com.google.inject.Injector; @@ -14,6 +15,7 @@ import io.bitsquare.settings.Settings; import io.bitsquare.storage.Storage; import io.bitsquare.user.Arbitrator; import io.bitsquare.user.User; +import io.bitsquare.util.DSAKeyUtil; import io.bitsquare.util.MockData; import javafx.application.Application; import javafx.scene.Parent; @@ -22,21 +24,23 @@ import javafx.stage.Stage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PublicKey; import java.util.Locale; -import java.util.UUID; public class BitSquare extends Application { private static final Logger log = LoggerFactory.getLogger(BitSquare.class); + public static String ID = ""; private WalletFacade walletFacade; private MessageFacade messageFacade; public static void main(String[] args) { + log.debug("Startup: main"); if (args.length > 0) - WalletFacade.WALLET_PREFIX = args[0]; - else - WalletFacade.WALLET_PREFIX = "bitsquare"; + ID = args[0]; launch(args); } @@ -44,9 +48,12 @@ public class BitSquare extends Application @Override public void start(Stage stage) throws Exception { + log.debug("Startup: start"); final Injector injector = Guice.createInjector(new BitSquareModule()); walletFacade = injector.getInstance(WalletFacade.class); + messageFacade = injector.getInstance(MessageFacade.class); + log.debug("Startup: messageFacade, walletFacade inited"); // apply stored data final User user = injector.getInstance(User.class); @@ -59,7 +66,11 @@ public class BitSquare extends Application settings.updateFromStorage((Settings) storage.read(settings.getClass().getName())); - stage.setTitle("BitSquare (" + WalletFacade.WALLET_PREFIX + ")"); + if (ID.length() > 0) + stage.setTitle("BitSquare (" + ID + ")"); + else + stage.setTitle("BitSquare"); + GuiceFXMLLoader.setInjector(injector); final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource("/io/bitsquare/gui/MainView.fxml"), Localisation.getResourceBundle()); @@ -71,12 +82,13 @@ public class BitSquare extends Application final String global = getClass().getResource("/io/bitsquare/gui/global.css").toExternalForm(); scene.getStylesheets().setAll(global); - stage.setMinWidth(740); + stage.setMinWidth(800); stage.setMinHeight(400); stage.setWidth(800); stage.setHeight(600); stage.show(); + log.debug("Startup: stage displayed"); } @Override @@ -104,20 +116,22 @@ public class BitSquare extends Application //settings.addAcceptedCountryLocale(Locale.getDefault()); settings.addAcceptedCountryLocale(MockData.getLocales().get(0)); settings.addAcceptedCountryLocale(new Locale("en", "US")); + settings.addAcceptedCountryLocale(new Locale("de", "DE")); settings.addAcceptedCountryLocale(new Locale("es", "ES")); - settings.getAcceptedArbitrators().clear(); - settings.addAcceptedArbitrator(new Arbitrator("uid_1", "Charlie Boom", UUID.randomUUID().toString(), - UUID.randomUUID().toString(), "http://www.arbit.io/Charly_Boom", 0.1, 10, Utils.toNanoCoins("0.01"))); - settings.addAcceptedArbitrator(new Arbitrator("uid_2", "Tom Shang", UUID.randomUUID().toString(), - UUID.randomUUID().toString(), "http://www.arbit.io/Tom_Shang", 0, 1, Utils.toNanoCoins("0.001"))); - settings.addAcceptedArbitrator(new Arbitrator("uid_3", "Edward Snow", UUID.randomUUID().toString(), - UUID.randomUUID().toString(), "http://www.arbit.io/Edward_Swow", 0.2, 5, Utils.toNanoCoins("0.05"))); - settings.addAcceptedArbitrator(new Arbitrator("uid_4", "Julian Sander", UUID.randomUUID().toString(), - UUID.randomUUID().toString(), "http://www.arbit.io/Julian_Sander", 0, 20, Utils.toNanoCoins("0.1"))); - settings.setMinCollateral(0.01); - settings.setMaxCollateral(0.1); + settings.getAcceptedArbitrators().clear(); + settings.addAcceptedArbitrator(new Arbitrator("uid_1", "Charlie Boom", Utils.bytesToHexString(new ECKey().getPubKey()), + getMessagePubKey(), "http://www.arbit.io/Charly_Boom", 1, 10, Utils.toNanoCoins("0.01"))); + settings.addAcceptedArbitrator(new Arbitrator("uid_2", "Tom Shang", Utils.bytesToHexString(new ECKey().getPubKey()), + getMessagePubKey(), "http://www.arbit.io/Tom_Shang", 0, 1, Utils.toNanoCoins("0.001"))); + settings.addAcceptedArbitrator(new Arbitrator("uid_3", "Edward Snow", Utils.bytesToHexString(new ECKey().getPubKey()), + getMessagePubKey(), "http://www.arbit.io/Edward_Swow", 2, 5, Utils.toNanoCoins("0.05"))); + settings.addAcceptedArbitrator(new Arbitrator("uid_4", "Julian Sander", Utils.bytesToHexString(new ECKey().getPubKey()), + getMessagePubKey(), "http://www.arbit.io/Julian_Sander", 0, 20, Utils.toNanoCoins("0.1"))); + + settings.setMinCollateral(1); + settings.setMaxCollateral(10); storage.write(settings.getClass().getName(), settings); @@ -125,6 +139,22 @@ public class BitSquare extends Application } } + private String getMessagePubKey() + { + try + { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); + keyGen.initialize(1024); + KeyPair generatedKeyPair = keyGen.genKeyPair(); + PublicKey pubKey = generatedKeyPair.getPublic(); + return DSAKeyUtil.getHexStringFromPublicKey(pubKey); + } catch (Exception e2) + { + return null; + } + } + + private void initMockUser(Storage storage, User user) { user.getBankAccounts().clear(); @@ -149,7 +179,7 @@ public class BitSquare extends Application ); user.addBankAccount(bankAccount2); - user.setAccountID(UUID.randomUUID().toString()); + user.setAccountID(Utils.bytesToHexString(new ECKey().getPubKey())); storage.write(user.getClass().getName(), user); } diff --git a/src/main/java/io/bitsquare/msg/BootstrapMasterPeer.java b/src/main/java/io/bitsquare/RelayNode.java similarity index 52% rename from src/main/java/io/bitsquare/msg/BootstrapMasterPeer.java rename to src/main/java/io/bitsquare/RelayNode.java index 5dcdd6d527..48cbea124b 100755 --- a/src/main/java/io/bitsquare/msg/BootstrapMasterPeer.java +++ b/src/main/java/io/bitsquare/RelayNode.java @@ -1,24 +1,30 @@ -package io.bitsquare.msg; +package io.bitsquare; import net.tomp2p.p2p.Peer; import net.tomp2p.p2p.PeerMaker; import net.tomp2p.peers.Number160; -public class BootstrapMasterPeer +public class RelayNode { private static Peer masterPeer = null; public static Number160 ID = Number160.createHash(1); public static void main(String[] args) throws Exception { - INSTANCE(5000); + if (args.length == 1) + INSTANCE(new Integer(args[0])); + else + INSTANCE(5000); } public static Peer INSTANCE(int port) throws Exception { if (masterPeer == null) + { masterPeer = new PeerMaker(ID).setPorts(port).makeAndListen(); - + // masterPeer = new PeerMaker(ID).setPorts(port).setBagSize(100).makeAndListen(); // setBagSize cause sync problems... + masterPeer.getBroadcastRPC().getConnectionBean().getConnectionReservation().reserve(10).awaitUninterruptibly(); + } return masterPeer; } } diff --git a/src/main/java/io/bitsquare/bank/BankAccount.java b/src/main/java/io/bitsquare/bank/BankAccount.java index 3b8545b2e5..bf31ac626b 100644 --- a/src/main/java/io/bitsquare/bank/BankAccount.java +++ b/src/main/java/io/bitsquare/bank/BankAccount.java @@ -8,7 +8,6 @@ public class BankAccount implements Serializable { private static final long serialVersionUID = 1792577576443221268L; - private static final long VERSION = 1; private BankAccountType bankAccountType; private String accountPrimaryID; @@ -80,17 +79,18 @@ public class BankAccount implements Serializable return accountTitle; } - // Changes of that structure must be reflected in VERSION updates - public String getStringifiedBankAccount() + @Override + public String toString() { - return "{" + - "type=" + bankAccountType + - ", primaryID='" + accountPrimaryID + '\'' + - ", secondaryID='" + accountSecondaryID + '\'' + - ", holderName='" + accountHolderName + '\'' + - ", currency='" + currency.getCurrencyCode() + '\'' + - ", country='" + countryLocale.getCountry() + '\'' + - ", v='" + VERSION + '\'' + + return "BankAccount{" + + "bankAccountType=" + bankAccountType + + ", accountPrimaryID='" + accountPrimaryID + '\'' + + ", accountSecondaryID='" + accountSecondaryID + '\'' + + ", accountHolderName='" + accountHolderName + '\'' + + ", countryLocale=" + countryLocale + + ", currency=" + currency + + ", uid='" + uid + '\'' + + ", accountTitle='" + accountTitle + '\'' + '}'; } diff --git a/src/main/java/io/bitsquare/bank/BankAccountType.java b/src/main/java/io/bitsquare/bank/BankAccountType.java index a8305c57d7..0f9c57d926 100644 --- a/src/main/java/io/bitsquare/bank/BankAccountType.java +++ b/src/main/java/io/bitsquare/bank/BankAccountType.java @@ -7,6 +7,11 @@ public class BankAccountType implements Serializable private static final long serialVersionUID = -8772708150197835288L; + public static enum BankAccountTypeEnum + { + SEPA, WIRE, INTERNATIONAL, OK_PAY, NET_TELLER, PERFECT_MONEY, OTHER + } + private BankAccountTypeEnum type; private String primaryIDName; private String secondaryIDName; @@ -40,8 +45,4 @@ public class BankAccountType implements Serializable return type.toString(); } - public static enum BankAccountTypeEnum - { - SEPA, WIRE, INTERNATIONAL, OK_PAY, NET_TELLER, PERFECT_MONEY, OTHER - } } diff --git a/src/main/java/io/bitsquare/btc/AccountRegistrationWallet.java b/src/main/java/io/bitsquare/btc/AccountRegistrationWallet.java index e07aa3420c..3605d5c029 100644 --- a/src/main/java/io/bitsquare/btc/AccountRegistrationWallet.java +++ b/src/main/java/io/bitsquare/btc/AccountRegistrationWallet.java @@ -7,6 +7,8 @@ import com.google.bitcoin.store.UnreadableWalletException; import com.google.bitcoin.store.WalletProtobufSerializer; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; +import io.bitsquare.BitSquare; +import io.bitsquare.util.Utilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,7 +41,7 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList this.chain = chain; this.peerGroup = peerGroup; - walletFile = new File(".", "bitsquare_account_reg" + ".wallet"); + walletFile = new File(Utilities.getRootDir() + "account_reg_" + BitSquare.ID + ".wallet"); if (walletFile.exists()) { FileInputStream walletStream = null; @@ -74,7 +76,10 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList { e.printStackTrace(); } + autosaveToFile(walletFile, 1, TimeUnit.SECONDS, null); + + allowSpendingUnconfirmedTransactions(); } void shutDown() @@ -166,7 +171,7 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList for (WalletFacade.WalletListener walletListener : walletListeners) walletListener.onCoinsReceived(newBalance); - log.info("onCoinsReceived"); + // log.info("onCoinsReceived"); } @Override @@ -175,7 +180,7 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList for (WalletFacade.WalletListener walletListener : walletListeners) walletListener.onConfidenceChanged(tx.getConfidence().numBroadcastPeers(), WalletUtil.getConfDepthInBlocks(this)); - log.info("onTransactionConfidenceChanged " + tx.getConfidence().toString()); + // log.info("onTransactionConfidenceChanged " + tx.getConfidence().toString()); } @Override @@ -193,7 +198,7 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList @Override public void onWalletChanged(Wallet wallet) { - log.info("onWalletChanged"); + // log.info("onWalletChanged"); } @Override diff --git a/src/main/java/io/bitsquare/btc/BlockChainFacade.java b/src/main/java/io/bitsquare/btc/BlockChainFacade.java index a8f82a1fe4..6aefeada6b 100644 --- a/src/main/java/io/bitsquare/btc/BlockChainFacade.java +++ b/src/main/java/io/bitsquare/btc/BlockChainFacade.java @@ -16,11 +16,19 @@ public class BlockChainFacade } - public boolean verifyEmbeddedData(String address) + //TODO + public boolean isAccountBlackListed(String accountID, BankAccount bankAccount) { + return false; + } + + //TODO + public boolean verifyAccountRegistration() + { + return true; + // tx id 76982adc582657b2eb68f3e43341596a68aadc4ef6b9590e88e93387d4d5d1f9 // address: mjbxLbuVpU1cNXLJbrJZyirYwweoRPVVTj - return true; /* if (findAddressInBlockChain(address) && isFeePayed(address)) return getDataForTxWithAddress(address) != null; @@ -49,14 +57,14 @@ public class BlockChainFacade return true; } - public boolean isAccountIDBlacklisted(String accountID) + private boolean isAccountIDBlacklisted(String accountID) { // TODO // check if accountID is on blacklist return false; } - public boolean isBankAccountBlacklisted(BankAccount bankAccount) + private boolean isBankAccountBlacklisted(BankAccount bankAccount) { // TODO // check if accountID is on blacklist diff --git a/src/main/java/io/bitsquare/btc/BtcFormatter.java b/src/main/java/io/bitsquare/btc/BtcFormatter.java index ec5c0cdbd3..d395eb62e2 100644 --- a/src/main/java/io/bitsquare/btc/BtcFormatter.java +++ b/src/main/java/io/bitsquare/btc/BtcFormatter.java @@ -3,6 +3,8 @@ package io.bitsquare.btc; import com.google.bitcoin.core.Utils; import io.bitsquare.gui.util.Converter; import io.bitsquare.gui.util.Formatter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.math.BigInteger; import java.text.DecimalFormat; @@ -10,6 +12,8 @@ import java.util.Locale; public class BtcFormatter { + private static final Logger log = LoggerFactory.getLogger(BtcFormatter.class); + public static BigInteger BTC = new BigInteger("100000000"); public static BigInteger mBTC = new BigInteger("100000"); @@ -30,10 +34,13 @@ public class BtcFormatter { // only "." as decimal sep supported by Utils.toNanoCoins 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/Fees.java b/src/main/java/io/bitsquare/btc/Fees.java index b4e6f5a9ac..c2e634cf79 100644 --- a/src/main/java/io/bitsquare/btc/Fees.java +++ b/src/main/java/io/bitsquare/btc/Fees.java @@ -1,11 +1,14 @@ package io.bitsquare.btc; +import com.google.bitcoin.core.Transaction; + import java.math.BigInteger; public class Fees { // min dust value lead to exception at for non standard to address pay scripts, so we use a value >= 7860 instead + public static BigInteger MS_TX_FEE = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; // Transaction.REFERENCE_DEFAULT_MIN_TX_FEE = BigInteger.valueOf(10000) public static BigInteger ACCOUNT_REGISTRATION_FEE = BigInteger.valueOf(7860);// Utils.toNanoCoins("0.001"); - public static BigInteger OFFER_CREATION_FEE = BigInteger.valueOf(7860); // //Transaction.MIN_NONDUST_OUTPUT; // Utils.toNanoCoins("0.001"); + public static BigInteger OFFER_CREATION_FEE = BigInteger.valueOf(7860); // Transaction.MIN_NONDUST_OUTPUT; // Utils.toNanoCoins("0.001"); public static BigInteger OFFER_TAKER_FEE = BigInteger.valueOf(7860); } diff --git a/src/main/java/io/bitsquare/btc/WalletFacade.java b/src/main/java/io/bitsquare/btc/WalletFacade.java index 08f02079a1..19bf59ff36 100644 --- a/src/main/java/io/bitsquare/btc/WalletFacade.java +++ b/src/main/java/io/bitsquare/btc/WalletFacade.java @@ -13,6 +13,7 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.Inject; +import io.bitsquare.BitSquare; import io.bitsquare.crypto.CryptoFacade; import io.bitsquare.gui.util.Popups; import javafx.application.Platform; @@ -35,16 +36,14 @@ public class WalletFacade implements WalletEventListener { public static final String MAIN_NET = "MAIN_NET"; public static final String TEST_NET = "TEST_NET"; + public static final String REG_TEST_NET = "REG_TEST_NET"; - public static String WALLET_PREFIX; + public static String WALLET_PREFIX = BitSquare.ID; // for testing trade process between offerer and taker //public static String WALLET_PREFIX = "offerer"; // offerer //public static String WALLET_PREFIX = "taker"; // offerer - //public static String WALLET_PREFIX = "bitsquare"; - - private static final Logger log = LoggerFactory.getLogger(WalletFacade.class); private NetworkParameters params; @@ -56,6 +55,8 @@ public class WalletFacade implements WalletEventListener private List downloadListeners = new ArrayList<>(); private List walletListeners = new ArrayList<>(); + + private Wallet wallet; @@ -107,7 +108,7 @@ public class WalletFacade implements WalletEventListener wallet = walletAppKit.wallet(); - //wallet.allowSpendingUnconfirmedTransactions(); + wallet.allowSpendingUnconfirmedTransactions(); walletAppKit.peerGroup().setMaxConnections(20); wallet.addEventListener(this); @@ -168,7 +169,7 @@ public class WalletFacade implements WalletEventListener return wallet.getBalance(Wallet.BalanceType.ESTIMATED); } - public String getAddress() + public String getAddressAsString() { return wallet.getKeys().get(0).toAddress(params).toString(); } @@ -189,6 +190,18 @@ public class WalletFacade implements WalletEventListener return tx.getHashAsString(); } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Trade process + /////////////////////////////////////////////////////////////////////////////////////////// + + public int getNumOfPeersSeenTx(String txID) + { + // TODO check from blockchain + // will be async + return 3; + } + /////////////////////////////////////////////////////////////////////////////////////////// // Account registration /////////////////////////////////////////////////////////////////////////////////////////// @@ -200,7 +213,7 @@ public class WalletFacade implements WalletEventListener public String getAccountRegistrationPubKey() { - return Utils.bytesToHexString(getAccountRegistrationWallet().getKey().getPubKey()); + return Utils.bytesToHexString(getAccountRegistrationKey().getPubKey()); } public BigInteger getAccountRegistrationBalance() @@ -213,6 +226,11 @@ public class WalletFacade implements WalletEventListener getAccountRegistrationWallet().saveToBlockchain(cryptoFacade.getEmbeddedAccountRegistrationData(getAccountRegistrationWallet().getKey(), stringifiedBankAccounts)); } + public ECKey getAccountRegistrationKey() + { + return getAccountRegistrationWallet().getKey(); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Getter /////////////////////////////////////////////////////////////////////////////////////////// @@ -227,12 +245,11 @@ public class WalletFacade implements WalletEventListener return WalletUtil.getConfDepthInBlocks(getAccountRegistrationWallet()); } - public ECKey getAccountKey() + public Wallet getWallet() { - return getAccountRegistrationWallet().getKey(); + return wallet; } - /////////////////////////////////////////////////////////////////////////////////////////// // Interface implementation: WalletEventListener /////////////////////////////////////////////////////////////////////////////////////////// @@ -243,7 +260,7 @@ public class WalletFacade implements WalletEventListener for (WalletListener walletListener : walletListeners) walletListener.onCoinsReceived(newBalance); - log.info("onCoinsReceived"); + // log.info("onCoinsReceived"); } @Override @@ -252,13 +269,13 @@ public class WalletFacade implements WalletEventListener for (WalletListener walletListener : walletListeners) walletListener.onConfidenceChanged(tx.getConfidence().numBroadcastPeers(), WalletUtil.getConfDepthInBlocks(wallet)); - log.info("onTransactionConfidenceChanged " + tx.getConfidence().toString()); + // log.info("onTransactionConfidenceChanged " + tx.getConfidence().toString()); } @Override public void onCoinsSent(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) { - log.info("onCoinsSent"); + // log.info("onCoinsSent"); } @Override @@ -270,7 +287,7 @@ public class WalletFacade implements WalletEventListener @Override public void onWalletChanged(Wallet wallet) { - log.info("onWalletChanged"); + // log.info("onWalletChanged"); } @Override @@ -285,12 +302,11 @@ public class WalletFacade implements WalletEventListener log.info("onScriptsAdded"); } - /////////////////////////////////////////////////////////////////////////////////////////// // Private methods /////////////////////////////////////////////////////////////////////////////////////////// - private AccountRegistrationWallet getAccountRegistrationWallet() + public AccountRegistrationWallet getAccountRegistrationWallet() { if (accountRegistrationWallet == null) accountRegistrationWallet = new AccountRegistrationWallet(params, walletAppKit.chain(), walletAppKit.peerGroup()); @@ -329,25 +345,25 @@ public class WalletFacade implements WalletEventListener String arbitratorPubKey = ""; // 1 offerer creates MS TX and pay in - /* Transaction tx1 = offererCreatesMSTxAndAddPayment(offererAmount, offererPubKey, takerPubKey, arbitratorPubKey); + Transaction tx1 = offererCreatesMSTxAndAddPayment(offererAmount, offererPubKey, takerPubKey, arbitratorPubKey); tx1AsHex = Utils.bytesToHexString(tx1.bitcoinSerialize()); - */ + tx1AsHex = "01000000014378dfcd19add18eb6f118a1e35ced127ff23c9dc5034eee1cda5b9caeb814f0000000006b4830450221008e599dd7bb7223c7b036869198b14f08009f9bc117709d23c249d0bdd6b483be022047be181f467782ea277b36890feb2f6de3ceddcedf8730a9f505bac36b3b015b01210352f2e34760514099f90b03aab91239466924c3b06047d3cf0e011f26ef96ceb7ffffffff0240420f00000000004852210352f2e34760514099f90b03aab91239466924c3b06047d3cf0e011f26ef96ceb7210207cf5fb65d6923d5d41db21ceac9567a0fc3eb92c6137f274018381ced7b65680053aeb077e605000000001976a9149fc3d8e0371b6eab89a8c3c015839f9e493ccf6588ac00000000"; // 2. taker pay in and sign - /* Transaction tx2 = takerAddPaymentAndSign(takerAmount, msOutputAmount, offererPubKey, takerPubKey, arbitratorPubKey, tx1AsHex); + /* Transaction tx2 = takerAddPaymentAndSign(takerAmount, msOutputAmount, offererPubKey, takerPubKey, arbitratorPubKey, tx1AsHex); tx2AsHex = Utils.bytesToHexString(tx2.bitcoinSerialize()); tx2ScriptSigAsHex = Utils.bytesToHexString(tx2.getInput(1).getScriptBytes()); tx2ConnOutAsHex = Utils.bytesToHexString(tx2.getInput(1).getConnectedOutput().getParentTransaction().bitcoinSerialize()); - */ + */ tx2AsHex = "01000000024378dfcd19add18eb6f118a1e35ced127ff23c9dc5034eee1cda5b9caeb814f0000000006b4830450221008e599dd7bb7223c7b036869198b14f08009f9bc117709d23c249d0bdd6b483be022047be181f467782ea277b36890feb2f6de3ceddcedf8730a9f505bac36b3b015b01210352f2e34760514099f90b03aab91239466924c3b06047d3cf0e011f26ef96ceb7ffffffffa58b22a93a0fcf99ba48aa3b96d842284b2b3d24f72d045cc192ea8a6b89435c010000006a47304402207f4beeb1a86432be0b4c3d4f4db7416b52b66c84383d1980d39e21d547a1762f02200405d0d4b80d1094e3a08cb39ef6f1161be163026d417af08d54c5a1cfdbbbeb01210207cf5fb65d6923d5d41db21ceac9567a0fc3eb92c6137f274018381ced7b6568ffffffff03c0c62d00000000004852210352f2e34760514099f90b03aab91239466924c3b06047d3cf0e011f26ef96ceb7210207cf5fb65d6923d5d41db21ceac9567a0fc3eb92c6137f274018381ced7b65680053aeb077e605000000001976a9149fc3d8e0371b6eab89a8c3c015839f9e493ccf6588ac7035d705000000001976a914e5175c1f71c28218306d4a27c8cec0269dddbbde88ac00000000"; tx2ScriptSigAsHex = "47304402207f4beeb1a86432be0b4c3d4f4db7416b52b66c84383d1980d39e21d547a1762f02200405d0d4b80d1094e3a08cb39ef6f1161be163026d417af08d54c5a1cfdbbbeb01210207cf5fb65d6923d5d41db21ceac9567a0fc3eb92c6137f274018381ced7b6568"; tx2ConnOutAsHex = "01000000014378dfcd19add18eb6f118a1e35ced127ff23c9dc5034eee1cda5b9caeb814f0010000006a473044022011431387fc19b093b26a6d2371995c828179aae68e94ad5804e5d0986a6b471302206abc2b698375620e65fc9970b7781da0af2179d1bdc4ebc82a13e285359a3ce7012103c7b9e9ef657705522c85b8429bb2b42c04f0fd4a09e0605cd7dd62ffecb57944ffffffff02c0ce823e000000001976a9142d1b4347ae850805f3badbb4b2949674f46c4ccd88ac00e1f505000000001976a914e5175c1f71c28218306d4a27c8cec0269dddbbde88ac00000000"; // 3. offerer sign and send - Transaction tx3 = offererSignAndSendTx(tx1AsHex, tx2AsHex, tx2ConnOutAsHex, tx2ScriptSigAsHex); + Transaction tx3 = offererSignAndSendTx(tx1AsHex, tx2AsHex, tx2ConnOutAsHex, tx2ScriptSigAsHex, null); log.info(tx3.toString()); // tx has 453 Bytes @@ -421,8 +437,13 @@ public class WalletFacade implements WalletEventListener } + public String getMultiSigPubKeyAsHex() + { + return Utils.bytesToHexString(wallet.getKeys().get(0).getPubKey()); + } + // deposit 1. offerer - private Transaction offererCreatesMSTxAndAddPayment(BigInteger offererAmount, String offererPubKey, String takerPubKey, String arbitratorPubKey) throws InsufficientMoneyException + public Transaction offererCreatesMSTxAndAddPayment(BigInteger offererAmount, String offererPubKey, String takerPubKey, String arbitratorPubKey) throws InsufficientMoneyException { // use that to use the convenient api for getting the best coin selection and fee calculation // TODO should be constructed manually @@ -494,13 +515,15 @@ public class WalletFacade implements WalletEventListener public Transaction offererSignAndSendTx(String tx1AsHex, String tx2AsHex, String tx2ConnOutAsHex, - String tx2ScriptSigAsHex) throws Exception + String tx2ScriptSigAsHex, + FutureCallback callback) throws Exception { + log.info("offererSignAndSendTx start"); Transaction tx = new Transaction(params); Transaction tx1 = new Transaction(params, Utils.parseAsHexOrBase58(tx1AsHex)); Transaction tx1ConnOut = wallet.getTransaction(tx1.getInput(0).getOutpoint().getHash()); - TransactionOutPoint tx1OutPoint = new TransactionOutPoint(params, 0, tx1ConnOut); + TransactionOutPoint tx1OutPoint = new TransactionOutPoint(params, 1, tx1ConnOut); TransactionInput tx1Input = new TransactionInput(params, tx, tx1.getInput(0).getScriptBytes(), tx1OutPoint); tx1Input.setParent(tx); tx.addInput(tx1Input); @@ -529,10 +552,13 @@ public class WalletFacade implements WalletEventListener else throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey); + log.info("offererSignAndSendTx check correctlySpends input 0"); input.getScriptSig().correctlySpends(tx, 0, scriptPubKey, false); input = tx.getInput(1); scriptPubKey = input.getConnectedOutput().getScriptPubKey(); + + log.info("offererSignAndSendTx check correctlySpends input 1"); input.getScriptSig().correctlySpends(tx, 1, scriptPubKey, false); /* @@ -542,26 +568,28 @@ public class WalletFacade implements WalletEventListener OUT[1] offerer change OUT[2] taker change */ - + log.info("offererSignAndSendTx broadcastTransaction verify "); tx.verify(); + log.info("offererSignAndSendTx broadcastTransaction pre "); ListenableFuture broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(tx); - - FutureCallback callback = new FutureCallback() + log.info("offererSignAndSendTx broadcastTransaction post"); + FutureCallback localCallback = new FutureCallback() { @Override public void onSuccess(Transaction transaction) { - log.info("sendResult onSuccess:" + transaction.toString()); + log.info("offererSignAndSendTx onSuccess" + transaction.toString()); } @Override public void onFailure(Throwable t) { - log.warn("sendResult onFailure:" + t.toString()); + log.info("offererSignAndSendTx onFailure" + t.toString()); Popups.openErrorPopup("Fee payment failed", "Fee payment failed. " + t.toString()); } }; + Futures.addCallback(broadcastComplete, localCallback); Futures.addCallback(broadcastComplete, callback); return tx; @@ -628,7 +656,7 @@ public class WalletFacade implements WalletEventListener ListenableFuture broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(tx); - FutureCallback callback = new FutureCallback() + FutureCallback callback = new FutureCallback() { @Override public void onSuccess(Transaction transaction) @@ -648,7 +676,6 @@ public class WalletFacade implements WalletEventListener return tx; } - /////////////////////////////////////////////////////////////////////////////////////////// // Inner classes /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/main/java/io/bitsquare/crypto/CryptoFacade.java b/src/main/java/io/bitsquare/crypto/CryptoFacade.java index 6332252a60..18a6f5435b 100644 --- a/src/main/java/io/bitsquare/crypto/CryptoFacade.java +++ b/src/main/java/io/bitsquare/crypto/CryptoFacade.java @@ -6,7 +6,6 @@ import com.google.common.base.Charsets; import com.google.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.spongycastle.util.encoders.Hex; import java.security.SignatureException; import java.util.UUID; @@ -58,7 +57,7 @@ public class CryptoFacade public boolean verifyHash(String hashAsHexStringToVerify, String msg, String sig) { - String hashAsHexString = Hex.toHexString(createHash(msg, sig)); + String hashAsHexString = Utils.bytesToHexString(createHash(msg, sig)); return hashAsHexString.equals(hashAsHexStringToVerify); } diff --git a/src/main/java/io/bitsquare/di/BitSquareModule.java b/src/main/java/io/bitsquare/di/BitSquareModule.java index 157ae55f51..609a032b99 100644 --- a/src/main/java/io/bitsquare/di/BitSquareModule.java +++ b/src/main/java/io/bitsquare/di/BitSquareModule.java @@ -4,6 +4,7 @@ package io.bitsquare.di; import com.google.bitcoin.core.NetworkParameters; import com.google.bitcoin.kits.WalletAppKit; import com.google.bitcoin.params.MainNetParams; +import com.google.bitcoin.params.RegTestParams; import com.google.bitcoin.params.TestNet3Params; import com.google.inject.AbstractModule; import com.google.inject.Inject; @@ -17,10 +18,10 @@ import io.bitsquare.msg.MessageFacade; import io.bitsquare.settings.Settings; import io.bitsquare.storage.Storage; import io.bitsquare.trade.Trading; -import io.bitsquare.trade.orderbook.MockOrderBook; import io.bitsquare.trade.orderbook.OrderBook; import io.bitsquare.trade.orderbook.OrderBookFilter; import io.bitsquare.user.User; +import io.bitsquare.util.Utilities; import java.io.File; @@ -31,7 +32,7 @@ public class BitSquareModule extends AbstractModule protected void configure() { bind(User.class).asEagerSingleton(); - bind(OrderBook.class).to(MockOrderBook.class).asEagerSingleton(); + bind(OrderBook.class).asEagerSingleton(); bind(Storage.class).asEagerSingleton(); bind(Settings.class).asEagerSingleton(); bind(OrderBookFilter.class).asEagerSingleton(); @@ -44,6 +45,7 @@ public class BitSquareModule extends AbstractModule bind(Trading.class).asEagerSingleton(); //bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.MAIN_NET); + // bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.REG_TEST_NET); bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.TEST_NET); bind(NetworkParameters.class).toProvider(NetworkParametersProvider.class).asEagerSingleton(); bind(WalletAppKit.class).toProvider(WalletAppKitProvider.class).asEagerSingleton(); @@ -62,7 +64,7 @@ class WalletAppKitProvider implements Provider public WalletAppKit get() { - return new WalletAppKit(networkParameters, new File("."), WalletFacade.WALLET_PREFIX); + return new WalletAppKit(networkParameters, new File(Utilities.getRootDir()), WalletFacade.WALLET_PREFIX); } } @@ -88,6 +90,9 @@ class NetworkParametersProvider implements Provider case WalletFacade.TEST_NET: result = TestNet3Params.get(); break; + case WalletFacade.REG_TEST_NET: + result = RegTestParams.get(); + break; } return result; } diff --git a/src/main/java/io/bitsquare/gui/MainController.java b/src/main/java/io/bitsquare/gui/MainController.java index 423d9ef3a8..57b4b646ef 100644 --- a/src/main/java/io/bitsquare/gui/MainController.java +++ b/src/main/java/io/bitsquare/gui/MainController.java @@ -1,5 +1,7 @@ package io.bitsquare.gui; +import com.google.bitcoin.core.*; +import com.google.bitcoin.script.Script; import com.google.inject.Inject; import io.bitsquare.bank.BankAccount; import io.bitsquare.btc.BtcFormatter; @@ -11,7 +13,9 @@ import io.bitsquare.gui.setup.SetupController; import io.bitsquare.gui.util.Icons; import io.bitsquare.gui.util.Localisation; import io.bitsquare.msg.MessageFacade; +import io.bitsquare.msg.TradeMessage; import io.bitsquare.trade.Direction; +import io.bitsquare.trade.Trading; import io.bitsquare.user.User; import javafx.application.Platform; import javafx.beans.value.ChangeListener; @@ -26,12 +30,15 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.*; import javafx.util.StringConverter; +import net.tomp2p.peers.PeerAddress; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.math.BigInteger; import java.net.URL; import java.util.Date; +import java.util.List; import java.util.ResourceBundle; public class MainController implements Initializable, NavigationController, WalletFacade.DownloadListener @@ -41,6 +48,7 @@ public class MainController implements Initializable, NavigationController, Wall private User user; private WalletFacade walletFacade; private MessageFacade messageFacade; + private Trading trading; private ChildController childController; private ToggleGroup toggleGroup; private ToggleButton prevToggleButton; @@ -48,6 +56,9 @@ public class MainController implements Initializable, NavigationController, Wall private Pane setupView; private SetupController setupController; private NetworkSyncPane networkSyncPane; + private ToggleButton buyButton, sellButton, homeButton, msgButton, ordersButton, historyButton, fundsButton, settingsButton; + private Pane msgButtonHolder, buyButtonHolder, sellButtonHolder, ordersButtonButtonHolder; + private TextField balanceTextField; @FXML public Pane contentPane; @@ -64,11 +75,12 @@ public class MainController implements Initializable, NavigationController, Wall /////////////////////////////////////////////////////////////////////////////////////////// @Inject - public MainController(User user, WalletFacade walletFacade, MessageFacade messageFacade) + public MainController(User user, WalletFacade walletFacade, MessageFacade messageFacade, Trading trading) { this.user = user; this.walletFacade = walletFacade; this.messageFacade = messageFacade; + this.trading = trading; } @@ -88,19 +100,50 @@ public class MainController implements Initializable, NavigationController, Wall walletFacade.addDownloadListener(this); walletFacade.initWallet(); - buildNavigation(); if (user.getAccountID() == null) { buildSetupView(); - anchorPane.setOpacity(0); + anchorPane.setVisible(false); setupController.setNetworkSyncPane(networkSyncPane); rootContainer.getChildren().add(setupView); } + else + { + buildNavigation(); + + sellButton.fire(); + // ordersButton.fire(); + // homeButton.fire(); + // msgButton.fire(); + } AnchorPane.setBottomAnchor(networkSyncPane, 0.0); AnchorPane.setLeftAnchor(networkSyncPane, 0.0); + + messageFacade.addTakeOfferRequestListener((tradingMessage, sender) -> showTakeOfferRequest(tradingMessage, sender)); } + private void showTakeOfferRequest(final TradeMessage tradeMessage, PeerAddress sender) + { + trading.createOffererPaymentProtocol(tradeMessage, sender); + try + { + ImageView newTradeRequestIcon = Icons.getIconImageView(Icons.MSG_ALERT); + Button alertButton = new Button("", newTradeRequestIcon); + alertButton.setId("nav-alert-button"); + alertButton.relocate(36, 19); + Tooltip.install(alertButton, new Tooltip("Someone accepted your offer")); + + alertButton.setOnAction((e) -> { + ordersButton.fire(); + }); + ordersButtonButtonHolder.getChildren().add(alertButton); + + } catch (NullPointerException e) + { + log.warn("showTakeOfferRequest failed because of a NullPointerException"); + } + } /////////////////////////////////////////////////////////////////////////////////////////// // Interface implementation: NavigationController @@ -113,12 +156,12 @@ public class MainController implements Initializable, NavigationController, Wall { anchorPane.getChildren().add(networkSyncPane); - anchorPane.setOpacity(1); + anchorPane.setVisible(true); rootContainer.getChildren().remove(setupView); setupView = null; setupController = null; - return null; + buildNavigation(); } if (childController != null) @@ -181,21 +224,31 @@ public class MainController implements Initializable, NavigationController, Wall { toggleGroup = new ToggleGroup(); - ToggleButton homeButton = addNavButton(leftNavPane, "Overview", Icons.HOME, Icons.HOME, NavigationController.HOME); - ToggleButton buyButton = addNavButton(leftNavPane, "Buy BTC", Icons.NAV_BUY, Icons.NAV_BUY_ACTIVE, NavigationController.MARKET, Direction.BUY); - ToggleButton sellButton = addNavButton(leftNavPane, "Sell BTC", Icons.NAV_SELL, Icons.NAV_SELL_ACTIVE, NavigationController.MARKET, Direction.SELL); - addNavButton(leftNavPane, "Orders", Icons.ORDERS, Icons.ORDERS, NavigationController.ORDERS); - addNavButton(leftNavPane, "History", Icons.HISTORY, Icons.HISTORY, NavigationController.HISTORY); - addNavButton(leftNavPane, "Funds", Icons.FUNDS, Icons.FUNDS, NavigationController.FUNDS); - ToggleButton msgButton = addNavButton(leftNavPane, "Message", Icons.MSG, Icons.MSG, NavigationController.MSG); + homeButton = addNavButton(leftNavPane, "Overview", Icons.HOME, Icons.HOME, NavigationController.HOME); + + buyButtonHolder = new Pane(); + buyButton = addNavButton(buyButtonHolder, "Buy BTC", Icons.NAV_BUY, Icons.NAV_BUY_ACTIVE, NavigationController.MARKET, Direction.BUY); + leftNavPane.getChildren().add(buyButtonHolder); + + sellButtonHolder = new Pane(); + sellButton = addNavButton(sellButtonHolder, "Sell BTC", Icons.NAV_SELL, Icons.NAV_SELL_ACTIVE, NavigationController.MARKET, Direction.SELL); + leftNavPane.getChildren().add(sellButtonHolder); + + ordersButtonButtonHolder = new Pane(); + ordersButton = addNavButton(ordersButtonButtonHolder, "Orders", Icons.ORDERS, Icons.ORDERS, NavigationController.ORDERS); + leftNavPane.getChildren().add(ordersButtonButtonHolder); + + historyButton = addNavButton(leftNavPane, "History", Icons.HISTORY, Icons.HISTORY, NavigationController.HISTORY); + fundsButton = addNavButton(leftNavPane, "Funds", Icons.FUNDS, Icons.FUNDS, NavigationController.FUNDS); + + msgButtonHolder = new Pane(); + msgButton = addNavButton(msgButtonHolder, "Message", Icons.MSG, Icons.MSG, NavigationController.MSG); + leftNavPane.getChildren().add(msgButtonHolder); + addBalanceInfo(rightNavPane); addAccountComboBox(rightNavPane); - addNavButton(rightNavPane, "Settings", Icons.SETTINGS, Icons.SETTINGS, NavigationController.SETTINGS); - - //sellButton.fire(); - //homeButton.fire(); - msgButton.fire(); + settingsButton = addNavButton(rightNavPane, "Settings", Icons.SETTINGS, Icons.SETTINGS, NavigationController.SETTINGS); } private ToggleButton addNavButton(Pane parent, String title, String iconId, String iconIdActivated, String navTarget) @@ -250,18 +303,19 @@ public class MainController implements Initializable, NavigationController, Wall private TextField addBalanceInfo(Pane parent) { - TextField balanceLabel = new TextField(); - balanceLabel.setEditable(false); - balanceLabel.setMouseTransparent(true); - balanceLabel.setPrefWidth(90); - balanceLabel.setId("nav-balance-label"); - balanceLabel.setText(BtcFormatter.formatSatoshis(walletFacade.getBalance(), false)); + balanceTextField = new TextField(); + balanceTextField.setEditable(false); + balanceTextField.setMouseTransparent(true); + balanceTextField.setPrefWidth(90); + balanceTextField.setId("nav-balance-label"); + + balanceTextField.setText(BtcFormatter.formatSatoshis(walletFacade.getBalance(), false)); Label balanceCurrencyLabel = new Label("BTC"); balanceCurrencyLabel.setPadding(new Insets(6, 0, 0, 0)); HBox hBox = new HBox(); hBox.setSpacing(2); - hBox.getChildren().setAll(balanceLabel, balanceCurrencyLabel); + hBox.getChildren().setAll(balanceTextField, balanceCurrencyLabel); VBox vBox = new VBox(); vBox.setPadding(new Insets(12, 0, 0, 0)); @@ -274,7 +328,47 @@ public class MainController implements Initializable, NavigationController, Wall vBox.getChildren().setAll(hBox, titleLabel); parent.getChildren().add(vBox); - return balanceLabel; + balanceTextField.setText(Utils.bitcoinValueToFriendlyString(walletFacade.getBalance())); + walletFacade.getWallet().addEventListener(new WalletEventListener() + { + @Override + public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) + { + balanceTextField.setText(Utils.bitcoinValueToFriendlyString(newBalance)); + } + + @Override + public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) + { + } + + @Override + public void onCoinsSent(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) + { + } + + @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