mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-22 14:42:37 +01:00
payment to MS fund
This commit is contained in:
parent
7d0676a995
commit
a4efa29bcd
37 changed files with 1081 additions and 546 deletions
|
@ -19,11 +19,13 @@ git clone --recursive git://github.com/bitsquare/bitsquare
|
|||
* bitcoinj integration
|
||||
* Setup with account registration and tx with OP_RETURN + embedded and blinded bank account data
|
||||
* Offer fee payment with a OP_RETURN tx and fees to miners
|
||||
* Pay in to MS fund
|
||||
|
||||
### Next steps:
|
||||
* Other trade variants (Buy BTC taker, Sell BTC offerer, Sell BTC offerer)
|
||||
* Payout from MS fund
|
||||
* Arbitrator integration
|
||||
* Messaging system
|
||||
* Other trade variants (Buy BTC taker, Sell BTC offerer, Sell BTC offerer)
|
||||
* ...
|
||||
|
||||
|
||||
|
|
6
TODO.txt
6
TODO.txt
|
@ -1,5 +1,4 @@
|
|||
- payment process update with new models
|
||||
- btc payments in payment process
|
||||
- pay out from MS in payment process
|
||||
- arbitration integration
|
||||
|
||||
Messaging!
|
||||
|
@ -9,8 +8,7 @@ low prio:
|
|||
- add settings after setup
|
||||
- settings screen
|
||||
- return to setup when unregistered, change/add bank accounts from settings
|
||||
- warning popups
|
||||
-
|
||||
- BigInteger for all btc values
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.bitsquare;
|
||||
|
||||
import com.google.bitcoin.core.Utils;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import io.bitsquare.bank.BankAccount;
|
||||
|
@ -45,9 +46,11 @@ public class BitSquare extends Application
|
|||
final Storage storage = injector.getInstance(Storage.class);
|
||||
user.updateFromStorage((User) storage.read(user.getClass().getName()));
|
||||
|
||||
settings.updateFromStorage((Settings) storage.read(settings.getClass().getName()));
|
||||
// mock
|
||||
initSettings(settings, storage, user);
|
||||
|
||||
settings.updateFromStorage((Settings) storage.read(settings.getClass().getName()));
|
||||
|
||||
stage.setTitle("BitSquare");
|
||||
|
||||
GuiceFXMLLoader.setInjector(injector);
|
||||
|
@ -83,55 +86,62 @@ public class BitSquare extends Application
|
|||
{
|
||||
// write default settings
|
||||
settings.getAcceptedCountryLocales().clear();
|
||||
settings.getAcceptedLanguageLocales().clear();
|
||||
|
||||
settings.addAcceptedLanguageLocale(Locale.getDefault());
|
||||
settings.addAcceptedCountryLocale(Locale.getDefault());
|
||||
|
||||
//TODO mock
|
||||
// settings.addAcceptedLanguageLocale(Locale.getDefault());
|
||||
settings.addAcceptedLanguageLocale(MockData.getLocales().get(0));
|
||||
settings.addAcceptedLanguageLocale(new Locale("en", "US"));
|
||||
settings.addAcceptedLanguageLocale(new Locale("es", "ES"));
|
||||
|
||||
settings.addAcceptedCountryLocale(new Locale("de", "AT"));
|
||||
settings.getAcceptedCountryLocales().clear();
|
||||
//settings.addAcceptedCountryLocale(Locale.getDefault());
|
||||
settings.addAcceptedCountryLocale(MockData.getLocales().get(0));
|
||||
settings.addAcceptedCountryLocale(new Locale("en", "US"));
|
||||
settings.addAcceptedCountryLocale(new Locale("es", "ES"));
|
||||
|
||||
settings.addArbitrator(new Arbitrator("Charly Boom", UUID.randomUUID().toString(), UUID.randomUUID().toString(), "http://www.arbit.io/Charly_Boom"));
|
||||
settings.addArbitrator(new Arbitrator("Tom Shang", UUID.randomUUID().toString(), UUID.randomUUID().toString(), "http://www.arbit.io/Tom_Shang"));
|
||||
settings.addArbitrator(new Arbitrator("Edward Snow", UUID.randomUUID().toString(), UUID.randomUUID().toString(), "http://www.arbit.io/Edward_Swow"));
|
||||
settings.addArbitrator(new Arbitrator("Julian Sander", UUID.randomUUID().toString(), UUID.randomUUID().toString(), "http://www.arbit.io/Julian_Sander"));
|
||||
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);
|
||||
|
||||
storage.write(settings.getClass().getName(), settings);
|
||||
|
||||
initMockUser(storage, user);
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.updateFromStorage(savedSettings);
|
||||
//initMockUser(storage, user);
|
||||
}
|
||||
}
|
||||
|
||||
private void initMockUser(Storage storage, User user)
|
||||
{
|
||||
user.getBankAccounts().clear();
|
||||
|
||||
BankAccount bankAccount1 = new BankAccount(new BankAccountType(BankAccountType.BankAccountTypeEnum.SEPA, "Iban", "Bic"),
|
||||
MockData.getCurrencies().get(0),
|
||||
MockData.getLocales().get(0),
|
||||
"Main account",
|
||||
"Main EUR account",
|
||||
"Manfred Karrer",
|
||||
"564613242346",
|
||||
"23432432434"
|
||||
);
|
||||
BankAccount bankAccount2 = new BankAccount(new BankAccountType(BankAccountType.BankAccountTypeEnum.OK_PAY, "Number", "ID"),
|
||||
MockData.getCurrencies().get(0),
|
||||
MockData.getLocales().get(0),
|
||||
"OK account",
|
||||
user.addBankAccount(bankAccount1);
|
||||
|
||||
BankAccount bankAccount2 = new BankAccount(new BankAccountType(BankAccountType.BankAccountTypeEnum.INTERNATIONAL, "Number", "ID"),
|
||||
MockData.getCurrencies().get(1),
|
||||
MockData.getLocales().get(2),
|
||||
"US account",
|
||||
"Manfred Karrer",
|
||||
"22312123123123123",
|
||||
"asdasdasdas"
|
||||
);
|
||||
user.addBankAccount(bankAccount2);
|
||||
user.addBankAccount(bankAccount1);
|
||||
|
||||
user.setAccountID(UUID.randomUUID().toString());
|
||||
|
||||
storage.write(user.getClass().getName(), user);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,20 +42,23 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList
|
|||
walletFile = new File(".", "bitsquare_account_reg" + ".wallet");
|
||||
if (walletFile.exists())
|
||||
{
|
||||
FileInputStream walletStream = null;
|
||||
try
|
||||
{
|
||||
FileInputStream walletStream = new FileInputStream(walletFile);
|
||||
new WalletProtobufSerializer().readWallet(WalletProtobufSerializer.parseToProto(walletStream), this);
|
||||
walletStream = new FileInputStream(walletFile);
|
||||
} catch (FileNotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
} catch (UnreadableWalletException e)
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
e.printStackTrace();
|
||||
} catch (IOException e)
|
||||
new WalletProtobufSerializer().readWallet(WalletProtobufSerializer.parseToProto(walletStream), this);
|
||||
} catch (UnreadableWalletException | IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -69,7 +72,7 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList
|
|||
saveToFile(walletFile);
|
||||
} catch (IOException e)
|
||||
{
|
||||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
|
||||
e.printStackTrace();
|
||||
}
|
||||
autosaveToFile(walletFile, 1, TimeUnit.SECONDS, null);
|
||||
}
|
||||
|
@ -81,7 +84,7 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList
|
|||
saveToFile(walletFile);
|
||||
} catch (IOException e)
|
||||
{
|
||||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
package io.bitsquare.btc;
|
||||
|
||||
import com.google.bitcoin.core.Utils;
|
||||
import io.bitsquare.gui.util.Converter;
|
||||
import io.bitsquare.gui.util.Formatter;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
public class BtcFormatter
|
||||
{
|
||||
|
@ -12,4 +18,31 @@ public class BtcFormatter
|
|||
{
|
||||
return satoshis.doubleValue() / BTC.doubleValue();
|
||||
}
|
||||
|
||||
public static BigInteger stringValueToSatoshis(String value)
|
||||
{
|
||||
return Utils.toNanoCoins(String.valueOf(Converter.stringToDouble(value)));
|
||||
}
|
||||
|
||||
public static BigInteger doubleValueToSatoshis(double value)
|
||||
{
|
||||
try
|
||||
{
|
||||
// only "." as decimal sep supported by Utils.toNanoCoins
|
||||
DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Locale.ENGLISH);
|
||||
String stringValue = decimalFormat.format(value);
|
||||
return Utils.toNanoCoins(stringValue);
|
||||
} catch (Exception e)
|
||||
{
|
||||
return BigInteger.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatSatoshis(BigInteger satoshis, boolean useBTC)
|
||||
{
|
||||
if (useBTC)
|
||||
return Formatter.formatDouble(satoshiToBTC(satoshis), 8) + " BTC";
|
||||
else
|
||||
return Formatter.formatDouble(satoshiToBTC(satoshis), 8);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
package io.bitsquare.btc;
|
||||
|
||||
import com.google.bitcoin.core.Transaction;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class Fees
|
||||
{
|
||||
|
||||
public static BigInteger ACCOUNT_REGISTRATION_FEE = Transaction.MIN_NONDUST_OUTPUT;// Utils.toNanoCoins("0.001");
|
||||
public static BigInteger OFFER_CREATION_FEE = Transaction.MIN_NONDUST_OUTPUT; // Utils.toNanoCoins("0.001");
|
||||
public static BigInteger OFFER_TAKER_FEE = OFFER_CREATION_FEE;
|
||||
// min dust value lead to exception at for non standard to address pay scripts, so we use a value >= 7860 instead
|
||||
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_TAKER_FEE = BigInteger.valueOf(7860);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
package io.bitsquare.btc;
|
||||
|
||||
import com.google.bitcoin.core.*;
|
||||
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;
|
||||
import com.google.bitcoin.script.ScriptBuilder;
|
||||
import com.google.bitcoin.utils.Threading;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
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.crypto.CryptoFacade;
|
||||
import io.bitsquare.gui.util.Popups;
|
||||
import javafx.application.Platform;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -19,9 +23,7 @@ import java.math.BigInteger;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.google.bitcoin.script.ScriptOpCodes.OP_RETURN;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* That facade delivers wallet functionality from the bitcoinJ library
|
||||
|
@ -33,28 +35,44 @@ public class WalletFacade implements WalletEventListener
|
|||
public static final String MAIN_NET = "MAIN_NET";
|
||||
public static final String TEST_NET = "TEST_NET";
|
||||
|
||||
// for testing trade process between offerer and taker
|
||||
//public static final String WALLET_PREFIX = "offerer"; // offerer
|
||||
// public static final String WALLET_PREFIX = "taker"; // offerer
|
||||
|
||||
public static final String WALLET_PREFIX = "bitsquare";
|
||||
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(WalletFacade.class);
|
||||
|
||||
private NetworkParameters networkParameters;
|
||||
private NetworkParameters params;
|
||||
private WalletAppKit walletAppKit;
|
||||
private CryptoFacade cryptoFacade;
|
||||
private BlockChainFacade blockChainFacade;
|
||||
|
||||
// that wallet is used only for the registration process
|
||||
private AccountRegistrationWallet accountRegistrationWallet = null;
|
||||
|
||||
private List<DownloadListener> downloadListeners = new ArrayList<>();
|
||||
private List<WalletListener> walletListeners = new ArrayList<>();
|
||||
private Wallet wallet;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public WalletFacade(NetworkParameters networkParameters, WalletAppKit walletAppKit, CryptoFacade cryptoFacade, BlockChainFacade blockChainFacade)
|
||||
public WalletFacade(NetworkParameters params, WalletAppKit walletAppKit, CryptoFacade cryptoFacade)
|
||||
{
|
||||
this.networkParameters = networkParameters;
|
||||
this.params = params;
|
||||
this.walletAppKit = walletAppKit;
|
||||
this.cryptoFacade = cryptoFacade;
|
||||
this.blockChainFacade = blockChainFacade;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public Methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void initWallet()
|
||||
{
|
||||
// Tell bitcoinj to run event handlers on the JavaFX UI thread. This keeps things simple and means
|
||||
|
@ -63,11 +81,11 @@ public class WalletFacade implements WalletEventListener
|
|||
// a future version.
|
||||
Threading.USER_THREAD = Platform::runLater;
|
||||
|
||||
if (networkParameters == RegTestParams.get())
|
||||
if (params == RegTestParams.get())
|
||||
{
|
||||
walletAppKit.connectToLocalHost(); // You should run a regtest mode bitcoind locally.
|
||||
}
|
||||
else if (networkParameters == MainNetParams.get())
|
||||
else if (params == MainNetParams.get())
|
||||
{
|
||||
// Checkpoints are block headers that ship inside our app: for a new user, we pick the last header
|
||||
// in the checkpoints file and then download the rest from the network. It makes things much faster.
|
||||
|
@ -80,16 +98,214 @@ public class WalletFacade implements WalletEventListener
|
|||
// or progress widget to keep the user engaged whilst we initialise, but we don't.
|
||||
walletAppKit.setDownloadListener(new BlockChainDownloadListener())
|
||||
.setBlockingStartup(false)
|
||||
.setUserAgent("BitSquare", "1.0");
|
||||
.setUserAgent("BitSquare", "0.1");
|
||||
walletAppKit.startAsync();
|
||||
walletAppKit.awaitRunning();
|
||||
|
||||
wallet = walletAppKit.wallet();
|
||||
|
||||
// Don't make the user wait for confirmations for now, as the intention is they're sending it their own money!
|
||||
getWallet().allowSpendingUnconfirmedTransactions();
|
||||
walletAppKit.peerGroup().setMaxConnections(11);
|
||||
wallet.allowSpendingUnconfirmedTransactions();
|
||||
walletAppKit.peerGroup().setMaxConnections(20);
|
||||
|
||||
getWallet().addEventListener(this);
|
||||
wallet.addEventListener(this);
|
||||
|
||||
log.info(getWallet().toString());
|
||||
log.info(wallet.toString());
|
||||
|
||||
// testTradeProcess();
|
||||
}
|
||||
|
||||
// TODO only temp. for testing trade process between offerer and taker
|
||||
private void testTradeProcess()
|
||||
{
|
||||
//wallet.allowSpendingUnconfirmedTransactions();
|
||||
|
||||
try
|
||||
{
|
||||
String tx1AsHex, tx2AsHex, tx2ScriptSigAsHex, tx2ConnOutAsHex;
|
||||
|
||||
BigInteger offererAmount = Utils.toNanoCoins("0.01");
|
||||
BigInteger takerAmount = Utils.toNanoCoins("0.02");
|
||||
|
||||
String takerPubKey = "0207cf5fb65d6923d5d41db21ceac9567a0fc3eb92c6137f274018381ced7b6568";
|
||||
String offererPubKey = "0352f2e34760514099f90b03aab91239466924c3b06047d3cf0e011f26ef96ceb7";
|
||||
String arbitratorPubKey = "";
|
||||
|
||||
// 1 offerer creates MS TX and pay in
|
||||
/* 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);
|
||||
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);
|
||||
|
||||
log.info(tx3.toString());
|
||||
|
||||
} catch (AddressFormatException | InsufficientMoneyException | InterruptedException | ExecutionException e)
|
||||
{
|
||||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
|
||||
} catch (Exception e)
|
||||
{
|
||||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
// 1. offerer
|
||||
private 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
|
||||
Transaction tx = new Transaction(params);
|
||||
Script multiSigOutputScript = getMultiSigScript(offererPubKey, takerPubKey, arbitratorPubKey);
|
||||
tx.addOutput(offererAmount, multiSigOutputScript);
|
||||
Wallet.SendRequest request = Wallet.SendRequest.forTx(tx);
|
||||
wallet.completeTx(request);
|
||||
// TODO remove sig or use SigHash.NONE
|
||||
//tx.getInput(0).setScriptSig(null);
|
||||
|
||||
/*
|
||||
IN[0] offerer
|
||||
OUT[0] MS
|
||||
OUT[1] offerer change
|
||||
*/
|
||||
return tx;
|
||||
}
|
||||
|
||||
// 2. taker
|
||||
public Transaction takerAddPaymentAndSign(BigInteger takerAmount,
|
||||
BigInteger msOutputAmount,
|
||||
String offererPubKey,
|
||||
String takerPubKey,
|
||||
String arbitratorPubKey,
|
||||
String tx1AsHex
|
||||
) throws InsufficientMoneyException, ExecutionException, InterruptedException, AddressFormatException
|
||||
{
|
||||
Script multiSigOutputScript = getMultiSigScript(offererPubKey, takerPubKey, arbitratorPubKey);
|
||||
|
||||
// use that to use the convenient api for getting the best coin selection and fee calculation
|
||||
// TODO should be constructed manually
|
||||
Transaction dummyTx = new Transaction(params);
|
||||
dummyTx.addOutput(takerAmount, multiSigOutputScript);
|
||||
wallet.completeTx(Wallet.SendRequest.forTx(dummyTx));
|
||||
|
||||
Transaction tx = new Transaction(params, Utils.parseAsHexOrBase58(tx1AsHex));
|
||||
tx.addInput(dummyTx.getInput(0));
|
||||
tx.addOutput(dummyTx.getOutput(1));
|
||||
tx.getOutput(0).setValue(msOutputAmount);
|
||||
|
||||
TransactionInput input = tx.getInput(1);
|
||||
Script scriptPubKey = input.getConnectedOutput().getScriptPubKey();
|
||||
ECKey sigKey = input.getOutpoint().getConnectedKey(wallet);
|
||||
Sha256Hash hash = tx.hashForSignature(1, scriptPubKey, Transaction.SigHash.ALL, false);
|
||||
ECKey.ECDSASignature ecSig = sigKey.sign(hash);
|
||||
TransactionSignature txSig = new TransactionSignature(ecSig, Transaction.SigHash.ALL, false);
|
||||
if (scriptPubKey.isSentToRawPubKey())
|
||||
input.setScriptSig(ScriptBuilder.createInputScript(txSig));
|
||||
else if (scriptPubKey.isSentToAddress())
|
||||
input.setScriptSig(ScriptBuilder.createInputScript(txSig, sigKey));
|
||||
else
|
||||
throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey);
|
||||
|
||||
input.getScriptSig().correctlySpends(tx, 1, scriptPubKey, false);
|
||||
|
||||
/*
|
||||
IN[0] offerer
|
||||
IN[1] taker signed
|
||||
OUT[0] MS
|
||||
OUT[1] offerer change
|
||||
OUT[2] taker change
|
||||
*/
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
public Transaction offererSignAndSendTx(String tx1AsHex,
|
||||
String tx2AsHex,
|
||||
String tx2ConnOutAsHex,
|
||||
String tx2ScriptSigAsHex) throws Exception
|
||||
{
|
||||
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);
|
||||
TransactionInput tx1Input = new TransactionInput(params, tx, tx1.getInput(0).getScriptBytes(), tx1OutPoint);
|
||||
tx1Input.setParent(tx);
|
||||
tx.addInput(tx1Input);
|
||||
|
||||
Transaction tx2 = new Transaction(params, Utils.parseAsHexOrBase58(tx2AsHex));
|
||||
Transaction tx2ConnOut = new Transaction(params, Utils.parseAsHexOrBase58(tx2ConnOutAsHex));
|
||||
TransactionOutPoint tx2OutPoint = new TransactionOutPoint(params, 1, tx2ConnOut);
|
||||
TransactionInput tx2Input = new TransactionInput(params, tx, Utils.parseAsHexOrBase58(tx2ScriptSigAsHex), tx2OutPoint);
|
||||
tx2Input.setParent(tx);
|
||||
tx.addInput(tx2Input);
|
||||
|
||||
tx.addOutput(tx2.getOutput(0));
|
||||
tx.addOutput(tx2.getOutput(1));
|
||||
tx.addOutput(tx2.getOutput(2));
|
||||
|
||||
TransactionInput input = tx.getInput(0);
|
||||
Script scriptPubKey = input.getConnectedOutput().getScriptPubKey();
|
||||
ECKey sigKey = input.getOutpoint().getConnectedKey(wallet);
|
||||
Sha256Hash hash = tx.hashForSignature(0, scriptPubKey, Transaction.SigHash.ALL, false);
|
||||
ECKey.ECDSASignature ecSig = sigKey.sign(hash);
|
||||
TransactionSignature txSig = new TransactionSignature(ecSig, Transaction.SigHash.ALL, false);
|
||||
if (scriptPubKey.isSentToRawPubKey())
|
||||
input.setScriptSig(ScriptBuilder.createInputScript(txSig));
|
||||
else if (scriptPubKey.isSentToAddress())
|
||||
input.setScriptSig(ScriptBuilder.createInputScript(txSig, sigKey));
|
||||
else
|
||||
throw new ScriptException("Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey);
|
||||
|
||||
input.getScriptSig().correctlySpends(tx, 0, scriptPubKey, false);
|
||||
|
||||
input = tx.getInput(1);
|
||||
scriptPubKey = input.getConnectedOutput().getScriptPubKey();
|
||||
input.getScriptSig().correctlySpends(tx, 1, scriptPubKey, false);
|
||||
|
||||
/*
|
||||
IN[0] offerer signed
|
||||
IN[1] taker signed
|
||||
OUT[0] MS
|
||||
OUT[1] offerer change
|
||||
OUT[2] taker change
|
||||
*/
|
||||
|
||||
tx.verify();
|
||||
|
||||
ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(tx);
|
||||
|
||||
FutureCallback callback = new FutureCallback<Transaction>()
|
||||
{
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction)
|
||||
{
|
||||
log.info("sendResult onSuccess:" + transaction.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t)
|
||||
{
|
||||
log.warn("sendResult onFailure:" + t.toString());
|
||||
Popups.openErrorPopup("Fee payment failed", "Fee payment failed. " + t.toString());
|
||||
}
|
||||
};
|
||||
Futures.addCallback(broadcastComplete, callback);
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
public void shutDown()
|
||||
|
@ -100,6 +316,10 @@ public class WalletFacade implements WalletEventListener
|
|||
walletAppKit.awaitTerminated();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Listener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void addDownloadListener(DownloadListener listener)
|
||||
{
|
||||
downloadListeners.add(listener);
|
||||
|
@ -131,23 +351,40 @@ public class WalletFacade implements WalletEventListener
|
|||
}
|
||||
|
||||
|
||||
//MOCK
|
||||
public KeyPair createNewAddress()
|
||||
{
|
||||
return new KeyPair(UUID.randomUUID().toString(), UUID.randomUUID().toString());
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Trading wallet
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public BigInteger getBalance()
|
||||
{
|
||||
return getWallet().getBalance(Wallet.BalanceType.ESTIMATED);
|
||||
return wallet.getBalance(Wallet.BalanceType.ESTIMATED);
|
||||
}
|
||||
|
||||
public String getAddress()
|
||||
{
|
||||
return getWallet().getKeys().get(0).toAddress(networkParameters).toString();
|
||||
return wallet.getKeys().get(0).toAddress(params).toString();
|
||||
}
|
||||
|
||||
// account registration
|
||||
public String payFee(BigInteger fee, FutureCallback<Transaction> callback) throws InsufficientMoneyException
|
||||
{
|
||||
Transaction tx = new Transaction(params);
|
||||
//TransactionOutput output = new TransactionOutput(params, tx, Transaction.MIN_NONDUST_OUTPUT, WalletUtil.getEmptyOP_RETURNScript());
|
||||
tx.addOutput(Transaction.MIN_NONDUST_OUTPUT, WalletUtil.getEmptyOP_RETURNScript());
|
||||
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
|
||||
|
||||
// give fee to miners yet. Later it could be spent to other traders via lottery...
|
||||
sendRequest.fee = fee;
|
||||
|
||||
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
|
||||
Futures.addCallback(sendResult.broadcastComplete, callback);
|
||||
|
||||
return tx.getHashAsString();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Account registration
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Address getAccountRegistrationAddress()
|
||||
{
|
||||
return getAccountRegistrationWallet().getAddress();
|
||||
|
@ -155,7 +392,6 @@ public class WalletFacade implements WalletEventListener
|
|||
|
||||
public String getAccountRegistrationPubKey()
|
||||
{
|
||||
|
||||
return Utils.bytesToHexString(getAccountRegistrationWallet().getKey().getPubKey());
|
||||
}
|
||||
|
||||
|
@ -169,14 +405,9 @@ public class WalletFacade implements WalletEventListener
|
|||
getAccountRegistrationWallet().saveToBlockchain(cryptoFacade.getEmbeddedAccountRegistrationData(getAccountRegistrationWallet().getKey(), stringifiedBankAccounts));
|
||||
}
|
||||
|
||||
public boolean verifyAccountRegistration(String address, String hashAsHexStringToVerify, byte[] pubKey, String bankAccountIDs, String signatureBankAccountIDs)
|
||||
{
|
||||
return true;
|
||||
/*
|
||||
return cryptoFacade.verifySignature(pubKey, bankAccountIDs, signatureBankAccountIDs)
|
||||
&& cryptoFacade.verifyHash(hashAsHexStringToVerify, bankAccountIDs, signatureBankAccountIDs)
|
||||
&& blockChainFacade.verifyEmbeddedData(address); */
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Getter
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int getRegConfNumBroadcastPeers()
|
||||
{
|
||||
|
@ -188,7 +419,16 @@ public class WalletFacade implements WalletEventListener
|
|||
return WalletUtil.getConfDepthInBlocks(getAccountRegistrationWallet());
|
||||
}
|
||||
|
||||
// WalletEventListener
|
||||
public ECKey getAccountKey()
|
||||
{
|
||||
return getAccountRegistrationWallet().getKey();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface implementation: WalletEventListener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance)
|
||||
{
|
||||
|
@ -202,7 +442,7 @@ public class WalletFacade implements WalletEventListener
|
|||
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx)
|
||||
{
|
||||
for (WalletListener walletListener : walletListeners)
|
||||
walletListener.onConfidenceChanged(tx.getConfidence().numBroadcastPeers(), WalletUtil.getConfDepthInBlocks(getWallet()));
|
||||
walletListener.onConfidenceChanged(tx.getConfidence().numBroadcastPeers(), WalletUtil.getConfDepthInBlocks(wallet));
|
||||
|
||||
log.info("onTransactionConfidenceChanged " + tx.getConfidence().toString());
|
||||
}
|
||||
|
@ -238,61 +478,33 @@ public class WalletFacade implements WalletEventListener
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private AccountRegistrationWallet getAccountRegistrationWallet()
|
||||
{
|
||||
if (accountRegistrationWallet == null)
|
||||
accountRegistrationWallet = new AccountRegistrationWallet(networkParameters, walletAppKit.chain(), walletAppKit.peerGroup());
|
||||
accountRegistrationWallet = new AccountRegistrationWallet(params, walletAppKit.chain(), walletAppKit.peerGroup());
|
||||
|
||||
return accountRegistrationWallet;
|
||||
}
|
||||
|
||||
public String payOfferFee() throws InsufficientMoneyException
|
||||
private Script getMultiSigScript(String offererPubKey, String takerPubKey, String arbitratorPubKey)
|
||||
{
|
||||
getWallet();
|
||||
ECKey offererKey = new ECKey(null, Utils.parseAsHexOrBase58(offererPubKey));
|
||||
ECKey takerKey = new ECKey(null, Utils.parseAsHexOrBase58(takerPubKey));
|
||||
ECKey arbitratorKey = new ECKey(null, Utils.parseAsHexOrBase58(arbitratorPubKey));
|
||||
|
||||
Script script = new ScriptBuilder()
|
||||
.op(OP_RETURN)
|
||||
.build();
|
||||
Transaction transaction = new Transaction(networkParameters);
|
||||
TransactionOutput dataOutput = new TransactionOutput(networkParameters,
|
||||
transaction,
|
||||
Transaction.MIN_NONDUST_OUTPUT,
|
||||
script.getProgram());
|
||||
transaction.addOutput(dataOutput);
|
||||
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(transaction);
|
||||
|
||||
// give fee to miners yet. Later it could be spent to other traders via lottery...
|
||||
sendRequest.fee = Fees.OFFER_CREATION_FEE;
|
||||
|
||||
Wallet.SendResult sendResult = getWallet().sendCoins(sendRequest);
|
||||
|
||||
Futures.addCallback(sendResult.broadcastComplete, new FutureCallback<Transaction>()
|
||||
{
|
||||
@Override
|
||||
public void onSuccess(Transaction result)
|
||||
{
|
||||
log.info("sendResult onSuccess:" + result.toString());
|
||||
// Platform.runLater(overlayUi::done);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t)
|
||||
{
|
||||
log.warn("sendResult onFailure:" + t.toString());
|
||||
// We died trying to empty the wallet.
|
||||
// crashAlert(t);
|
||||
}
|
||||
});
|
||||
|
||||
return transaction.getHashAsString();
|
||||
List<ECKey> keys = ImmutableList.of(offererKey, takerKey, arbitratorKey);
|
||||
return ScriptBuilder.createMultiSigOutputScript(2, keys);
|
||||
}
|
||||
|
||||
private Wallet getWallet()
|
||||
{
|
||||
return walletAppKit.wallet();
|
||||
}
|
||||
|
||||
// inner classes
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Inner classes
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private class BlockChainDownloadListener extends com.google.bitcoin.core.DownloadListener
|
||||
{
|
||||
@Override
|
||||
|
@ -326,5 +538,4 @@ public class WalletFacade implements WalletEventListener
|
|||
void onCoinsReceived(BigInteger newBalance);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -3,10 +3,14 @@ package io.bitsquare.btc;
|
|||
import com.google.bitcoin.core.Transaction;
|
||||
import com.google.bitcoin.core.TransactionConfidence;
|
||||
import com.google.bitcoin.core.Wallet;
|
||||
import com.google.bitcoin.script.Script;
|
||||
import com.google.bitcoin.script.ScriptBuilder;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.bitcoin.script.ScriptOpCodes.OP_RETURN;
|
||||
|
||||
public class WalletUtil
|
||||
{
|
||||
|
||||
|
@ -41,4 +45,11 @@ public class WalletUtil
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Script getEmptyOP_RETURNScript()
|
||||
{
|
||||
return new ScriptBuilder()
|
||||
.op(OP_RETURN)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,11 +37,9 @@ public class CryptoFacade
|
|||
return Utils.sha256hash160(concatenateChunks(stringifiedBankAccounts, signedBankAccountIDs).getBytes(Charsets.UTF_8));
|
||||
}
|
||||
|
||||
|
||||
// TODO MOCK
|
||||
public String signContract(String contractAsJson)
|
||||
public String signContract(ECKey key, String contractAsJson)
|
||||
{
|
||||
return contractAsJson;
|
||||
return key.signMessage(contractAsJson);
|
||||
}
|
||||
|
||||
// registration
|
||||
|
|
|
@ -62,7 +62,7 @@ class WalletAppKitProvider implements Provider<WalletAppKit>
|
|||
|
||||
public WalletAppKit get()
|
||||
{
|
||||
return new WalletAppKit(networkParameters, new File("."), "bitsquare");
|
||||
return new WalletAppKit(networkParameters, new File("."), WalletFacade.WALLET_PREFIX);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,12 @@ package io.bitsquare.gui;
|
|||
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.bank.BankAccount;
|
||||
import io.bitsquare.btc.BtcFormatter;
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.di.GuiceFXMLLoader;
|
||||
import io.bitsquare.gui.components.NetworkSyncPane;
|
||||
import io.bitsquare.gui.market.MarketController;
|
||||
import io.bitsquare.gui.setup.SetupController;
|
||||
import io.bitsquare.gui.util.Formatter;
|
||||
import io.bitsquare.gui.util.Icons;
|
||||
import io.bitsquare.gui.util.Localisation;
|
||||
import io.bitsquare.trade.Direction;
|
||||
|
@ -251,7 +251,7 @@ public class MainController implements Initializable, NavigationController, Wall
|
|||
balanceLabel.setMouseTransparent(true);
|
||||
balanceLabel.setPrefWidth(90);
|
||||
balanceLabel.setId("nav-balance-label");
|
||||
balanceLabel.setText(Formatter.formatSatoshis(walletFacade.getBalance(), false));
|
||||
balanceLabel.setText(BtcFormatter.formatSatoshis(walletFacade.getBalance(), false));
|
||||
|
||||
Label balanceCurrencyLabel = new Label("BTC");
|
||||
balanceCurrencyLabel.setPadding(new Insets(6, 0, 0, 0));
|
||||
|
|
|
@ -3,10 +3,10 @@ package io.bitsquare.gui.funds;
|
|||
import com.google.inject.Inject;
|
||||
import de.jensd.fx.fontawesome.AwesomeDude;
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
import io.bitsquare.btc.BtcFormatter;
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.gui.ChildController;
|
||||
import io.bitsquare.gui.NavigationController;
|
||||
import io.bitsquare.gui.util.Formatter;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Label;
|
||||
|
@ -63,7 +63,7 @@ public class FundsController implements Initializable, ChildController
|
|||
this.navigationController = navigationController;
|
||||
|
||||
addressLabel.setText(walletFacade.getAddress());
|
||||
balanceLabel.setText(Formatter.formatSatoshis(walletFacade.getBalance(), false));
|
||||
balanceLabel.setText(BtcFormatter.formatSatoshis(walletFacade.getBalance(), false));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package io.bitsquare.gui.market.offer;
|
||||
|
||||
import com.google.bitcoin.core.InsufficientMoneyException;
|
||||
import com.google.bitcoin.core.Transaction;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.btc.BtcFormatter;
|
||||
import io.bitsquare.btc.Fees;
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.gui.ChildController;
|
||||
|
@ -13,6 +16,7 @@ import io.bitsquare.trade.Direction;
|
|||
import io.bitsquare.trade.Offer;
|
||||
import io.bitsquare.trade.Trading;
|
||||
import io.bitsquare.trade.orderbook.OrderBookFilter;
|
||||
import io.bitsquare.user.Arbitrator;
|
||||
import io.bitsquare.user.User;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
@ -22,10 +26,8 @@ import javafx.scene.control.Button;
|
|||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import org.controlsfx.dialog.Dialogs;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -43,9 +45,11 @@ public class CreateOfferController implements Initializable, ChildController, Wa
|
|||
private Settings settings;
|
||||
private User user;
|
||||
private Direction direction;
|
||||
private Offer offer;
|
||||
private int gridRow;
|
||||
|
||||
private Button placeOfferButton;
|
||||
private int gridRow;
|
||||
private TextField collateralTextField, minAmountTextField;
|
||||
|
||||
@FXML
|
||||
private AnchorPane holderPane;
|
||||
|
@ -54,7 +58,12 @@ public class CreateOfferController implements Initializable, ChildController, Wa
|
|||
@FXML
|
||||
public Label buyLabel;
|
||||
@FXML
|
||||
public TextField volume, amount, price, minAmount;
|
||||
public TextField volumeTextField, amountTextField, priceTextField;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public CreateOfferController(Trading trading, WalletFacade walletFacade, Settings settings, User user)
|
||||
|
@ -65,86 +74,51 @@ public class CreateOfferController implements Initializable, ChildController, Wa
|
|||
this.user = user;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setOrderBookFilter(OrderBookFilter orderBookFilter)
|
||||
{
|
||||
direction = orderBookFilter.getDirection();
|
||||
amountTextField.setText(Formatter.formatPrice(orderBookFilter.getAmount()));
|
||||
minAmountTextField.setText(Formatter.formatPrice(orderBookFilter.getAmount()));
|
||||
priceTextField.setText(Formatter.formatPrice(orderBookFilter.getPrice()));
|
||||
buyLabel.setText(Formatter.formatDirection(direction, false) + ":");
|
||||
collateralTextField.setText(Formatter.formatVolume(settings.getMinCollateral()));
|
||||
updateVolume();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface implementation: Initializable
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb)
|
||||
{
|
||||
walletFacade.addRegistrationWalletListener(this);
|
||||
|
||||
gridRow = 2;
|
||||
FormBuilder.addVSpacer(formGridPane, ++gridRow);
|
||||
FormBuilder.addHeaderLabel(formGridPane, "Offer details:", ++gridRow);
|
||||
FormBuilder.addTextField(formGridPane, "Bank account type:", Localisation.get(user.getCurrentBankAccount().getBankAccountType().getType().toString()), ++gridRow);
|
||||
FormBuilder.addTextField(formGridPane, "Bank account currency:", user.getCurrentBankAccount().getCurrency().getCurrencyCode(), ++gridRow);
|
||||
FormBuilder.addTextField(formGridPane, "Bank account county:", user.getCurrentBankAccount().getCountryLocale().getDisplayCountry(), ++gridRow);
|
||||
FormBuilder.addTextField(formGridPane, "Accepted countries:", Formatter.countryLocalesToString(settings.getAcceptedCountryLocales()), ++gridRow);
|
||||
FormBuilder.addTextField(formGridPane, "Accepted languages:", Formatter.languageLocalesToString(settings.getAcceptedLanguageLocales()), ++gridRow);
|
||||
|
||||
FormBuilder.addVSpacer(formGridPane, ++gridRow);
|
||||
Label placeOfferTitle = FormBuilder.addHeaderLabel(formGridPane, "Place offer:", ++gridRow);
|
||||
|
||||
TextField feeLabel = FormBuilder.addTextField(formGridPane, "Offer fee:", Formatter.formatSatoshis(Fees.OFFER_CREATION_FEE, true), ++gridRow);
|
||||
feeLabel.setMouseTransparent(true);
|
||||
|
||||
placeOfferButton = new Button("Place offer");
|
||||
formGridPane.add(placeOfferButton, 1, ++gridRow);
|
||||
placeOfferButton.setDefaultButton(true);
|
||||
|
||||
// handlers
|
||||
amount.textProperty().addListener(new ChangeListener<String>()
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
|
||||
{
|
||||
updateVolume();
|
||||
}
|
||||
});
|
||||
|
||||
price.textProperty().addListener(new ChangeListener<String>()
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
|
||||
{
|
||||
updateVolume();
|
||||
}
|
||||
});
|
||||
|
||||
placeOfferButton.setOnAction(e -> {
|
||||
|
||||
if (inputValid())
|
||||
{
|
||||
Offer offer = new Offer(user.getAccountID(),
|
||||
user.getMessageID(),
|
||||
direction,
|
||||
Converter.stringToDouble(price.getText()),
|
||||
Converter.stringToDouble(amount.getText()),
|
||||
Converter.stringToDouble(minAmount.getText()),
|
||||
user.getCurrentBankAccount().getBankAccountType().getType(),
|
||||
user.getCurrentBankAccount().getCurrency(),
|
||||
user.getCurrentBankAccount().getCountryLocale(),
|
||||
settings.getRandomArbitrator(),
|
||||
settings.getAcceptedCountryLocales(),
|
||||
settings.getAcceptedLanguageLocales());
|
||||
|
||||
try
|
||||
{
|
||||
String txID = trading.placeNewOffer(offer);
|
||||
formGridPane.getChildren().remove(placeOfferButton);
|
||||
placeOfferTitle.setText("Transaction sent:");
|
||||
buildConfirmationView(txID);
|
||||
} catch (InsufficientMoneyException e1)
|
||||
{
|
||||
Dialogs.create()
|
||||
.title("Not enough money available")
|
||||
.message("There is not enough money available. Please pay in first to your wallet.")
|
||||
.nativeTitleBar()
|
||||
.lightweight()
|
||||
.showError();
|
||||
}
|
||||
}
|
||||
});
|
||||
buildScreen();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface implementation: ChildController
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void setNavigationController(NavigationController navigationController)
|
||||
{
|
||||
this.navigationController = navigationController;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface implementation: WalletFacade.WalletListener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onConfidenceChanged(int numBroadcastPeers, int depthInBlocks)
|
||||
{
|
||||
|
@ -157,11 +131,119 @@ public class CreateOfferController implements Initializable, ChildController, Wa
|
|||
log.info("onCoinsReceived " + newBalance);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void buildScreen()
|
||||
{
|
||||
gridRow = 1;
|
||||
minAmountTextField = FormBuilder.addTextField(formGridPane, "Min. Amount:", String.valueOf(settings.getMaxCollateral()), ++gridRow, true, true);
|
||||
collateralTextField = FormBuilder.addTextField(formGridPane, "Collateral (%):", String.valueOf(settings.getMaxCollateral() * 100), ++gridRow, true, true);
|
||||
|
||||
FormBuilder.addVSpacer(formGridPane, ++gridRow);
|
||||
FormBuilder.addHeaderLabel(formGridPane, "Offer details:", ++gridRow);
|
||||
FormBuilder.addTextField(formGridPane, "Bank account type:", Localisation.get(user.getCurrentBankAccount().getBankAccountType().getType().toString()), ++gridRow);
|
||||
FormBuilder.addTextField(formGridPane, "Bank account currency:", user.getCurrentBankAccount().getCurrency().getCurrencyCode(), ++gridRow);
|
||||
FormBuilder.addTextField(formGridPane, "Bank account county:", user.getCurrentBankAccount().getCountryLocale().getDisplayCountry(), ++gridRow);
|
||||
FormBuilder.addTextField(formGridPane, "Accepted countries:", Formatter.countryLocalesToString(settings.getAcceptedCountryLocales()), ++gridRow);
|
||||
FormBuilder.addTextField(formGridPane, "Accepted languages:", Formatter.languageLocalesToString(settings.getAcceptedLanguageLocales()), ++gridRow);
|
||||
|
||||
FormBuilder.addVSpacer(formGridPane, ++gridRow);
|
||||
Label placeOfferTitle = FormBuilder.addHeaderLabel(formGridPane, "Place offer:", ++gridRow);
|
||||
|
||||
TextField feeLabel = FormBuilder.addTextField(formGridPane, "Offer fee:", BtcFormatter.formatSatoshis(Fees.OFFER_CREATION_FEE, true), ++gridRow);
|
||||
feeLabel.setMouseTransparent(true);
|
||||
|
||||
placeOfferButton = new Button("Place offer");
|
||||
formGridPane.add(placeOfferButton, 1, ++gridRow);
|
||||
placeOfferButton.setDefaultButton(true);
|
||||
|
||||
// handlers
|
||||
amountTextField.textProperty().addListener(new ChangeListener<String>()
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
|
||||
{
|
||||
updateVolume();
|
||||
}
|
||||
});
|
||||
|
||||
priceTextField.textProperty().addListener(new ChangeListener<String>()
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
|
||||
{
|
||||
updateVolume();
|
||||
}
|
||||
});
|
||||
|
||||
placeOfferButton.setOnAction(e -> {
|
||||
if (!inputValid())
|
||||
{
|
||||
Popups.openWarningPopup("Invalid input", "Your input is invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
double collateralAsDouble = Converter.stringToDouble(collateralTextField.getText()) / 100;
|
||||
Arbitrator arbitrator = settings.getRandomArbitrator(collateralAsDouble, getAmountAsBI());
|
||||
if (arbitrator == null)
|
||||
{
|
||||
Popups.openWarningPopup("No arbitrator available", "No arbitrator from your arbitrator list does match the collateral and amount value.");
|
||||
return;
|
||||
}
|
||||
|
||||
offer = new Offer(user.getAccountID(),
|
||||
user.getMessageID(),
|
||||
direction,
|
||||
Converter.stringToDouble(priceTextField.getText()),
|
||||
BtcFormatter.stringValueToSatoshis(amountTextField.getText()),
|
||||
BtcFormatter.stringValueToSatoshis(minAmountTextField.getText()),
|
||||
user.getCurrentBankAccount().getBankAccountType().getType(),
|
||||
user.getCurrentBankAccount().getCurrency(),
|
||||
user.getCurrentBankAccount().getCountryLocale(),
|
||||
arbitrator,
|
||||
collateralAsDouble,
|
||||
settings.getAcceptedCountryLocales(),
|
||||
settings.getAcceptedLanguageLocales());
|
||||
|
||||
FutureCallback callback = new FutureCallback<Transaction>()
|
||||
{
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction)
|
||||
{
|
||||
log.info("sendResult onSuccess:" + transaction.toString());
|
||||
offer.setOfferPaymentTxID(transaction.getHashAsString());
|
||||
buildConfirmationView(transaction.getHashAsString());
|
||||
placeOfferTitle.setText("Transaction sent:");
|
||||
formGridPane.getChildren().remove(placeOfferButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t)
|
||||
{
|
||||
log.warn("sendResult onFailure:" + t.toString());
|
||||
Popups.openErrorPopup("Fee payment failed", "Fee payment failed. " + t.toString());
|
||||
}
|
||||
};
|
||||
try
|
||||
{
|
||||
trading.placeNewOffer(offer, callback);
|
||||
|
||||
} catch (InsufficientMoneyException e1)
|
||||
{
|
||||
Popups.openErrorPopup("Not enough money available", "There is not enough money available. Please pay in first to your wallet.");
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private void buildConfirmationView(String txID)
|
||||
{
|
||||
FormBuilder.addTextField(formGridPane, "Transaction ID:", txID, ++gridRow, false, true);
|
||||
|
||||
ConfirmationComponent confirmationComponent = new ConfirmationComponent(walletFacade, formGridPane, ++gridRow);
|
||||
new ConfirmationComponent(walletFacade, formGridPane, ++gridRow);
|
||||
|
||||
Button closeButton = new Button("Close");
|
||||
formGridPane.add(closeButton, 1, ++gridRow);
|
||||
|
@ -176,50 +258,36 @@ public class CreateOfferController implements Initializable, ChildController, Wa
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setNavigationController(NavigationController navigationController)
|
||||
{
|
||||
this.navigationController = navigationController;
|
||||
}
|
||||
|
||||
public void setOrderBookFilter(OrderBookFilter orderBookFilter)
|
||||
{
|
||||
direction = orderBookFilter.getDirection();
|
||||
amount.setText(Formatter.formatPrice(orderBookFilter.getAmount()));
|
||||
minAmount.setText(Formatter.formatPrice(orderBookFilter.getAmount()));
|
||||
price.setText(Formatter.formatPrice(orderBookFilter.getPrice()));
|
||||
|
||||
String iconPath = (direction == Direction.BUY) ? Icons.BUY : Icons.SELL;
|
||||
buyLabel.setText(Formatter.formatDirection(direction, false) + ":");
|
||||
updateVolume();
|
||||
}
|
||||
|
||||
//TODO
|
||||
private boolean inputValid()
|
||||
{
|
||||
return true;
|
||||
double priceAsDouble = Converter.stringToDouble(priceTextField.getText());
|
||||
double minAmountAsDouble = Converter.stringToDouble(minAmountTextField.getText());
|
||||
double amountAsDouble = Converter.stringToDouble(amountTextField.getText());
|
||||
double collateralAsDouble = Converter.stringToDouble(collateralTextField.getText());
|
||||
|
||||
return priceAsDouble > 0 &&
|
||||
amountAsDouble > 0 &&
|
||||
minAmountAsDouble > 0 &&
|
||||
minAmountAsDouble <= amountAsDouble &&
|
||||
collateralAsDouble >= settings.getMinCollateral() &&
|
||||
collateralAsDouble <= settings.getMaxCollateral();
|
||||
}
|
||||
|
||||
private void updateVolume()
|
||||
{
|
||||
double amountAsDouble = Converter.stringToDouble(amount.getText());
|
||||
double priceAsDouble = Converter.stringToDouble(price.getText());
|
||||
volume.setText(Formatter.formatPrice(amountAsDouble * priceAsDouble));
|
||||
volumeTextField.setText(Formatter.formatVolume(getVolume()));
|
||||
}
|
||||
|
||||
private Image getConfirmIconImage(int numBroadcastPeers, int depthInBlocks)
|
||||
private double getVolume()
|
||||
{
|
||||
if (depthInBlocks > 0)
|
||||
return Icons.getIconImage(Icons.getIconIDForConfirmations(depthInBlocks));
|
||||
else
|
||||
return Icons.getIconImage(Icons.getIconIDForPeersSeenTx(numBroadcastPeers));
|
||||
double amountAsDouble = Converter.stringToDouble(amountTextField.getText());
|
||||
double priceAsDouble = Converter.stringToDouble(priceTextField.getText());
|
||||
return amountAsDouble * priceAsDouble;
|
||||
}
|
||||
|
||||
private String getConfirmationsText(int registrationConfirmationNumBroadcastPeers, int registrationConfirmationDepthInBlocks)
|
||||
private BigInteger getAmountAsBI()
|
||||
{
|
||||
return registrationConfirmationDepthInBlocks + " confirmation(s) / " + "Seen by " + registrationConfirmationNumBroadcastPeers + " peer(s)";
|
||||
return BtcFormatter.stringValueToSatoshis(amountTextField.getText());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -6,45 +6,34 @@
|
|||
<AnchorPane fx:id="holderPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
|
||||
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="io.bitsquare.gui.market.offer.CreateOfferController">
|
||||
<children>
|
||||
<VBox spacing="10" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="5.0"
|
||||
AnchorPane.bottomAnchor="10.0">
|
||||
<GridPane fx:id="formGridPane" vgap="5" hgap="5">
|
||||
<children>
|
||||
<Label id="form-header-text" text="Create new offer:" GridPane.rowIndex="0"
|
||||
GridPane.columnIndex="0"/>
|
||||
<VBox spacing="10" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="5.0"
|
||||
AnchorPane.bottomAnchor="10.0">
|
||||
<GridPane fx:id="formGridPane" vgap="5" hgap="5">
|
||||
<Label id="form-header-text" text="Create new offer:" GridPane.rowIndex="0"
|
||||
GridPane.columnIndex="0"/>
|
||||
|
||||
<Label fx:id="buyLabel" text="Buy" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
|
||||
<Label fx:id="buyLabel" text="Buy" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
|
||||
|
||||
<HBox GridPane.rowIndex="1" GridPane.columnIndex="1" GridPane.hgrow="NEVER" spacing="5"
|
||||
alignment="CENTER_RIGHT">
|
||||
<children>
|
||||
<TextField fx:id="amount" prefWidth="70.0" alignment="CENTER_RIGHT"/>
|
||||
<Label text="BTC for:"/>
|
||||
<TextField fx:id="price" prefWidth="70.0" alignment="CENTER_RIGHT"/>
|
||||
<Label text="EUR ="/>
|
||||
<TextField fx:id="volume" prefWidth="70.0" alignment="CENTER_RIGHT"
|
||||
mouseTransparent="true"/>
|
||||
<Label text="EUR in total"/>
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox GridPane.rowIndex="1" GridPane.columnIndex="1" GridPane.hgrow="NEVER" spacing="5"
|
||||
alignment="CENTER_RIGHT">
|
||||
<TextField fx:id="amountTextField" prefWidth="70.0" alignment="CENTER_RIGHT"/>
|
||||
<Label text="BTC for:"/>
|
||||
<TextField fx:id="priceTextField" prefWidth="70.0" alignment="CENTER_RIGHT"/>
|
||||
<Label text="EUR ="/>
|
||||
<TextField fx:id="volumeTextField" prefWidth="70.0" alignment="CENTER_RIGHT" editable="false"
|
||||
mouseTransparent="true"/>
|
||||
<Label text="EUR in total"/>
|
||||
</HBox>
|
||||
|
||||
<Label text="Min. Amount:" GridPane.rowIndex="2" GridPane.columnIndex="0"/>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
|
||||
</padding>
|
||||
|
||||
<TextField fx:id="minAmount" GridPane.rowIndex="2" GridPane.columnIndex="1"/>
|
||||
|
||||
</children>
|
||||
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
|
||||
</padding>
|
||||
|
||||
<columnConstraints>
|
||||
<ColumnConstraints halignment="RIGHT"/>
|
||||
<ColumnConstraints halignment="LEFT"/>
|
||||
<ColumnConstraints halignment="LEFT"/>
|
||||
</columnConstraints>
|
||||
</GridPane>
|
||||
</VBox>
|
||||
</children>
|
||||
<columnConstraints>
|
||||
<ColumnConstraints halignment="RIGHT"/>
|
||||
<ColumnConstraints halignment="LEFT"/>
|
||||
<ColumnConstraints halignment="LEFT"/>
|
||||
</columnConstraints>
|
||||
</GridPane>
|
||||
</VBox>
|
||||
</AnchorPane>
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.bitsquare.gui.market.orderbook;
|
|||
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.bank.BankAccountType;
|
||||
import io.bitsquare.btc.BtcFormatter;
|
||||
import io.bitsquare.gui.ChildController;
|
||||
import io.bitsquare.gui.NavigationController;
|
||||
import io.bitsquare.gui.market.offer.CreateOfferController;
|
||||
|
@ -30,6 +31,7 @@ import javafx.util.Callback;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.net.URL;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.ParseException;
|
||||
|
@ -155,9 +157,9 @@ public class OrderBookController implements Initializable, ChildController
|
|||
String title = orderBookListItem.getOffer().getDirection() == Direction.BUY ? "Trade: Sell Bitcoin" : "Trade: Buy Bitcoin";
|
||||
TradeController tradeController = (TradeController) navigationController.navigateToView(NavigationController.TRADE, title);
|
||||
|
||||
double requestedAmount = orderBookListItem.getOffer().getAmount();
|
||||
BigInteger requestedAmount = orderBookListItem.getOffer().getAmount();
|
||||
if (!amount.getText().equals(""))
|
||||
requestedAmount = Converter.stringToDouble(amount.getText());
|
||||
requestedAmount = BtcFormatter.stringValueToSatoshis(amount.getText());
|
||||
|
||||
tradeController.initWithData(orderBookListItem.getOffer(), requestedAmount);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ public class OrderBookListItem
|
|||
this.offer = offer;
|
||||
|
||||
this.price.set(Formatter.formatPrice(offer.getPrice()));
|
||||
this.amount.set(Formatter.formatAmountWithMinAmount(offer.getAmount(), offer.getMinAmount()));
|
||||
this.amount.set(Formatter.formatAmountWithMinAmount(offer.getAmount().doubleValue(), offer.getMinAmount().doubleValue()));
|
||||
this.volume.set(Formatter.formatVolumeWithMinVolume(offer.getVolume(), offer.getMinVolume()));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package io.bitsquare.gui.market.trade;
|
||||
|
||||
import com.google.bitcoin.core.InsufficientMoneyException;
|
||||
import com.google.bitcoin.core.Transaction;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.btc.BlockChainFacade;
|
||||
import io.bitsquare.btc.BtcFormatter;
|
||||
|
@ -23,7 +26,6 @@ import javafx.scene.control.*;
|
|||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Pane;
|
||||
import org.controlsfx.dialog.Dialogs;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -36,7 +38,7 @@ import java.util.ResourceBundle;
|
|||
public class TradeController implements Initializable, ChildController, WalletFacade.WalletListener
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(TradeController.class);
|
||||
private static final int SIM_DELAY = 1000;
|
||||
private static final int SIM_DELAY = 2000;
|
||||
|
||||
private Trading trading;
|
||||
private WalletFacade walletFacade;
|
||||
|
@ -44,14 +46,14 @@ public class TradeController implements Initializable, ChildController, WalletFa
|
|||
private Offer offer;
|
||||
private Trade trade;
|
||||
private Contract contract;
|
||||
private double requestedAmount;
|
||||
private BigInteger requestedAmount;
|
||||
private boolean offererIsOnline;
|
||||
private int row;
|
||||
|
||||
private List<ProcessStepItem> processStepItems = new ArrayList();
|
||||
|
||||
private NavigationController navigationController;
|
||||
private TextField amountTextField, totalToPayLabel, totalLabel;
|
||||
private TextField amountTextField, totalToPayLabel, totalLabel, collateralTextField;
|
||||
private Label statusTextField, infoLabel;
|
||||
private Button nextButton;
|
||||
private ProgressBar progressBar;
|
||||
|
@ -81,14 +83,14 @@ public class TradeController implements Initializable, ChildController, WalletFa
|
|||
// Public methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void initWithData(Offer offer, double requestedAmount)
|
||||
public void initWithData(Offer offer, BigInteger requestedAmount)
|
||||
{
|
||||
this.offer = offer;
|
||||
this.requestedAmount = requestedAmount > 0 ? requestedAmount : offer.getAmount();
|
||||
this.requestedAmount = requestedAmount.compareTo(BigInteger.ZERO) > 0 ? requestedAmount : offer.getAmount();
|
||||
|
||||
trade = trading.createNewTrade(offer);
|
||||
trade = trading.createTrade(offer);
|
||||
trade.setTradeAmount(requestedAmount);
|
||||
contract = trading.createNewContract(trade);
|
||||
contract = trading.createContract(trade);
|
||||
|
||||
processStepItems.add(new ProcessStepItem(takerIsSelling() ? "Sell BTC" : "Buy BTC"));
|
||||
processStepItems.add(new ProcessStepItem("Bank transfer"));
|
||||
|
@ -148,19 +150,22 @@ public class TradeController implements Initializable, ChildController, WalletFa
|
|||
row = -1;
|
||||
|
||||
FormBuilder.addHeaderLabel(gridPane, "Take offer:", ++row);
|
||||
amountTextField = FormBuilder.addTextField(gridPane, "Amount BTC:", Formatter.formatAmount(requestedAmount), ++row, true, true);
|
||||
amountTextField = FormBuilder.addTextField(gridPane, "Amount (BTC):", BtcFormatter.formatSatoshis(requestedAmount, false), ++row, true, true);
|
||||
amountTextField.textProperty().addListener(e -> {
|
||||
applyVolume();
|
||||
applyCollateral();
|
||||
totalToPayLabel.setText(getTotalToPay());
|
||||
|
||||
});
|
||||
Label amountRangeLabel = new Label("(" + Formatter.formatAmount(offer.getMinAmount()) + " - " + Formatter.formatAmount(offer.getAmount()) + ")");
|
||||
Label amountRangeLabel = new Label("(" + BtcFormatter.formatSatoshis(offer.getMinAmount(), false) + " - " + BtcFormatter.formatSatoshis(offer.getAmount(), false) + ")");
|
||||
gridPane.add(amountRangeLabel, 2, row);
|
||||
|
||||
FormBuilder.addTextField(gridPane, "Price:", Formatter.formatPriceWithCurrencyPair(offer.getPrice(), offer.getCurrency()), ++row);
|
||||
totalLabel = FormBuilder.addTextField(gridPane, "Total:", Formatter.formatVolume(getVolume(), offer.getCurrency()), ++row);
|
||||
FormBuilder.addTextField(gridPane, "Offer fee:", Formatter.formatSatoshis(Fees.OFFER_TAKER_FEE, true), ++row);
|
||||
totalToPayLabel = FormBuilder.addTextField(gridPane, "Total to pay:", getTotalToPay(), ++row);
|
||||
FormBuilder.addTextField(gridPane, "Price (" + offer.getCurrency() + "/BTC):", Formatter.formatPrice(offer.getPrice()), ++row);
|
||||
totalLabel = FormBuilder.addTextField(gridPane, "Total (" + offer.getCurrency() + "):", Formatter.formatVolume(getVolume()), ++row);
|
||||
collateralTextField = FormBuilder.addTextField(gridPane, "Collateral (BTC):", "", ++row);
|
||||
applyCollateral();
|
||||
FormBuilder.addTextField(gridPane, "Offer fee (BTC):", BtcFormatter.formatSatoshis(Fees.OFFER_TAKER_FEE, false), ++row);
|
||||
totalToPayLabel = FormBuilder.addTextField(gridPane, "Total to pay (BTC):", getTotalToPay(), ++row);
|
||||
|
||||
nextButton = FormBuilder.addButton(gridPane, "Take offer and pay", ++row);
|
||||
nextButton.setDefaultButton(true);
|
||||
|
@ -247,9 +252,9 @@ public class TradeController implements Initializable, ChildController, WalletFa
|
|||
progressIndicatorHolder.getChildren().addAll(progressIndicator);
|
||||
gridPane.add(progressIndicatorHolder, 1, row);
|
||||
|
||||
trade.setTradeAmount(Converter.stringToDouble(amountTextField.getText()));
|
||||
trading.sendTakeOfferRequest(trade);
|
||||
trade.setTradeAmount(BtcFormatter.stringValueToSatoshis(amountTextField.getText()));
|
||||
|
||||
trading.sendTakeOfferRequest(trade);
|
||||
Utils.setTimeout(SIM_DELAY, (AnimationTimer animationTimer) -> {
|
||||
onTakeOfferRequestConfirmed();
|
||||
progressBar.setProgress(1.0 / 3.0);
|
||||
|
@ -259,14 +264,37 @@ public class TradeController implements Initializable, ChildController, WalletFa
|
|||
|
||||
private void onTakeOfferRequestConfirmed()
|
||||
{
|
||||
trading.payOfferFee(trade);
|
||||
FutureCallback callback = new FutureCallback<Transaction>()
|
||||
{
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction)
|
||||
{
|
||||
log.info("sendResult onSuccess:" + transaction.toString());
|
||||
trade.setTakeOfferFeeTxID(transaction.getHashAsString());
|
||||
|
||||
statusTextField.setText("Offer fee payed. Send offerer payment transaction ID for confirmation.");
|
||||
Utils.setTimeout(SIM_DELAY, (AnimationTimer animationTimer) -> {
|
||||
onOfferFeePaymentConfirmed();
|
||||
progressBar.setProgress(2.0 / 3.0);
|
||||
return null;
|
||||
});
|
||||
statusTextField.setText("Offer fee payed. Send offerer payment transaction ID for confirmation.");
|
||||
Utils.setTimeout(SIM_DELAY, (AnimationTimer animationTimer) -> {
|
||||
onOfferFeePaymentConfirmed();
|
||||
progressBar.setProgress(2.0 / 3.0);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t)
|
||||
{
|
||||
log.warn("sendResult onFailure:" + t.toString());
|
||||
Popups.openErrorPopup("Fee payment failed", "Fee payment failed. " + t.toString());
|
||||
}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
trading.payOfferFee(trade, callback);
|
||||
} catch (InsufficientMoneyException e)
|
||||
{
|
||||
Popups.openErrorPopup("Not enough money available", "There is not enough money available. Please pay in first to your wallet.");
|
||||
}
|
||||
}
|
||||
|
||||
private void onOfferFeePaymentConfirmed()
|
||||
|
@ -282,14 +310,10 @@ public class TradeController implements Initializable, ChildController, WalletFa
|
|||
|
||||
private void onUserDetailsReceived()
|
||||
{
|
||||
if (!walletFacade.verifyAccountRegistration(offer.getAccountID(), null, null, null, null))
|
||||
if (!blockChainFacade.verifyEmbeddedData(offer.getAccountID()))
|
||||
{
|
||||
Dialogs.create()
|
||||
.title("Offerers bank account is blacklisted")
|
||||
.message("Offerers bank account is blacklisted.")
|
||||
.nativeTitleBar()
|
||||
.lightweight()
|
||||
.showError();
|
||||
Popups.openErrorPopup("Offerers bank account is blacklisted", "Offerers bank account is blacklisted.");
|
||||
return;
|
||||
}
|
||||
|
||||
trading.signContract(contract);
|
||||
|
@ -337,8 +361,19 @@ public class TradeController implements Initializable, ChildController, WalletFa
|
|||
gridPane.getChildren().clear();
|
||||
row = -1;
|
||||
FormBuilder.addHeaderLabel(gridPane, "Trade successfully completed", ++row);
|
||||
FormBuilder.addTextField(gridPane, "You have payed:", getTotalToPay(), ++row);
|
||||
FormBuilder.addTextField(gridPane, "You have received:", getTotalToReceive(), ++row);
|
||||
FormBuilder.addTextField(gridPane, "You have payed in total (BTC):", getTotalToPay(), ++row);
|
||||
if (takerIsSelling())
|
||||
{
|
||||
FormBuilder.addTextField(gridPane, "You got returned collateral (BTC):", BtcFormatter.formatSatoshis(getCollateralInSatoshis(), false), ++row);
|
||||
FormBuilder.addTextField(gridPane, "You have received (" + offer.getCurrency() + "):", Formatter.formatVolume(getVolume()), ++row);
|
||||
}
|
||||
else
|
||||
{
|
||||
FormBuilder.addTextField(gridPane, "You got returned collateral (BTC):", BtcFormatter.formatSatoshis(getCollateralInSatoshis(), false), ++row);
|
||||
FormBuilder.addTextField(gridPane, "You have received (" + offer.getCurrency() + "):", Formatter.formatVolume(getVolume()), ++row);
|
||||
FormBuilder.addTextField(gridPane, "You have received (BTC):", BtcFormatter.formatSatoshis(offer.getAmount(), false), ++row);
|
||||
}
|
||||
|
||||
gridPane.add(nextButton, 1, ++row);
|
||||
}
|
||||
|
||||
|
@ -355,8 +390,8 @@ public class TradeController implements Initializable, ChildController, WalletFa
|
|||
// Other Private methods
|
||||
private boolean tradeAmountValid()
|
||||
{
|
||||
double tradeAmount = Converter.stringToDouble(amountTextField.getText());
|
||||
return tradeAmount <= offer.getAmount() && tradeAmount >= offer.getMinAmount();
|
||||
BigInteger tradeAmount = BtcFormatter.stringValueToSatoshis(amountTextField.getText());
|
||||
return tradeAmount.compareTo(offer.getAmount()) <= 0 && tradeAmount.compareTo(offer.getMinAmount()) >= 0;
|
||||
}
|
||||
|
||||
private boolean takerIsSelling()
|
||||
|
@ -388,28 +423,31 @@ public class TradeController implements Initializable, ChildController, WalletFa
|
|||
|
||||
private String getTotalToPay()
|
||||
{
|
||||
String result = "";
|
||||
if (takerIsSelling())
|
||||
{
|
||||
double btcValue = Converter.stringToDouble(amountTextField.getText()) + BtcFormatter.satoshiToBTC(Fees.OFFER_CREATION_FEE)/* +
|
||||
offer.getConstraints().getCollateral() * Converter.stringToDouble(amountTextField.getText())*/;
|
||||
result = Formatter.formatAmount(btcValue, true, true);
|
||||
return BtcFormatter.formatSatoshis(getAmountInSatoshis().add(Fees.OFFER_TAKER_FEE).add(getCollateralInSatoshis()), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
double btcValue = BtcFormatter.satoshiToBTC(Fees.OFFER_CREATION_FEE) /*+ offer.getConstraints().getCollateral() * Converter.stringToDouble(amountTextField.getText())*/;
|
||||
result = Formatter.formatAmount(btcValue, true, true) + "\n" + Formatter.formatVolume(getVolume(), offer.getCurrency());
|
||||
return BtcFormatter.formatSatoshis(Fees.OFFER_TAKER_FEE.add(getCollateralInSatoshis()), false) + "\n" +
|
||||
Formatter.formatVolume(getVolume(), offer.getCurrency());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getTotalToReceive()
|
||||
|
||||
private void applyCollateral()
|
||||
{
|
||||
if (takerIsSelling())
|
||||
return Formatter.formatVolume(getVolume(), offer.getCurrency());
|
||||
else
|
||||
return Formatter.formatAmount(offer.getAmount(), true, true);
|
||||
collateralTextField.setText(BtcFormatter.formatSatoshis(getCollateralInSatoshis(), false));
|
||||
}
|
||||
|
||||
private BigInteger getCollateralInSatoshis()
|
||||
{
|
||||
return BtcFormatter.doubleValueToSatoshis(Converter.stringToDouble(amountTextField.getText()) * offer.getCollateral());
|
||||
}
|
||||
|
||||
private BigInteger getAmountInSatoshis()
|
||||
{
|
||||
return BtcFormatter.stringValueToSatoshis(amountTextField.getText());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,24 +9,14 @@ public class MockDelay
|
|||
{
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
Future<String> future = executor.submit(new Task(expectedMsg));
|
||||
// max timeout 5 sec
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
// max timeout 5 sec
|
||||
return future.get(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (TimeoutException e)
|
||||
return future.get(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException | TimeoutException | ExecutionException e)
|
||||
{
|
||||
System.out.println("Terminated!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
executor.shutdownNow();
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import de.jensd.fx.fontawesome.AwesomeDude;
|
|||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
import io.bitsquare.bank.BankAccount;
|
||||
import io.bitsquare.bank.BankAccountType;
|
||||
import io.bitsquare.btc.BtcFormatter;
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.gui.ChildController;
|
||||
import io.bitsquare.gui.NavigationController;
|
||||
|
@ -14,8 +15,8 @@ import io.bitsquare.gui.components.NetworkSyncPane;
|
|||
import io.bitsquare.gui.components.processbar.ProcessStepBar;
|
||||
import io.bitsquare.gui.components.processbar.ProcessStepItem;
|
||||
import io.bitsquare.gui.util.FormBuilder;
|
||||
import io.bitsquare.gui.util.Formatter;
|
||||
import io.bitsquare.gui.util.Localisation;
|
||||
import io.bitsquare.gui.util.Popups;
|
||||
import io.bitsquare.gui.util.Verification;
|
||||
import io.bitsquare.storage.Storage;
|
||||
import io.bitsquare.user.User;
|
||||
|
@ -29,7 +30,6 @@ import javafx.scene.layout.AnchorPane;
|
|||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.util.StringConverter;
|
||||
import org.controlsfx.dialog.Dialogs;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -41,13 +41,15 @@ public class SetupController implements Initializable, ChildController, WalletFa
|
|||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(SetupController.class);
|
||||
|
||||
private User user;
|
||||
private final User user;
|
||||
private final WalletFacade walletFacade;
|
||||
private Storage storage;
|
||||
private List<ProcessStepItem> processStepItems = new ArrayList();
|
||||
private final Storage storage;
|
||||
private final List<ProcessStepItem> processStepItems = new ArrayList<>();
|
||||
private NavigationController navigationController;
|
||||
private TextField balanceLabel, accountTitle, accountHolderName, accountPrimaryID, accountSecondaryID;
|
||||
private ComboBox countryComboBox, bankTransferTypeComboBox, currencyComboBox;
|
||||
private ComboBox<Locale> countryComboBox;
|
||||
private ComboBox<BankAccountType> bankTransferTypeComboBox;
|
||||
private ComboBox<Currency> currencyComboBox;
|
||||
private Button addBankAccountButton;
|
||||
|
||||
@FXML
|
||||
|
@ -133,7 +135,7 @@ public class SetupController implements Initializable, ChildController, WalletFa
|
|||
public void onCoinsReceived(BigInteger newBalance)
|
||||
{
|
||||
updateCreateAccountButton();
|
||||
balanceLabel.setText(Formatter.formatSatoshis(walletFacade.getAccountRegistrationBalance(), true));
|
||||
balanceLabel.setText(BtcFormatter.formatSatoshis(walletFacade.getAccountRegistrationBalance(), true));
|
||||
log.info("onCoinsReceived " + newBalance);
|
||||
}
|
||||
|
||||
|
@ -161,7 +163,7 @@ public class SetupController implements Initializable, ChildController, WalletFa
|
|||
AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY);
|
||||
Tooltip.install(copyIcon, new Tooltip("Copy address to clipboard"));
|
||||
|
||||
balanceLabel = FormBuilder.addTextField(gridPane, "Balance:", Formatter.formatSatoshis(walletFacade.getAccountRegistrationBalance(), true), ++row);
|
||||
balanceLabel = FormBuilder.addTextField(gridPane, "Balance:", BtcFormatter.formatSatoshis(walletFacade.getAccountRegistrationBalance(), true), ++row);
|
||||
|
||||
new ConfirmationComponent(walletFacade, gridPane, ++row);
|
||||
|
||||
|
@ -194,7 +196,7 @@ public class SetupController implements Initializable, ChildController, WalletFa
|
|||
|
||||
gridPane.getChildren().clear();
|
||||
int row = -1;
|
||||
bankTransferTypeComboBox = FormBuilder.addComboBox(gridPane, "Bank account type:", Utils.getAllBankAccountTypes(), ++row);
|
||||
bankTransferTypeComboBox = FormBuilder.addBankAccountComboBox(gridPane, "Bank account type:", Utils.getAllBankAccountTypes(), ++row);
|
||||
bankTransferTypeComboBox.setConverter(new StringConverter<BankAccountType>()
|
||||
{
|
||||
@Override
|
||||
|
@ -216,7 +218,7 @@ public class SetupController implements Initializable, ChildController, WalletFa
|
|||
accountPrimaryID = FormBuilder.addInputField(gridPane, "Bank account primary ID", "", ++row);
|
||||
accountSecondaryID = FormBuilder.addInputField(gridPane, "Bank account secondary ID:", "", ++row);
|
||||
|
||||
currencyComboBox = FormBuilder.addComboBox(gridPane, "Currency used for bank account:", Utils.getAllCurrencies(), ++row);
|
||||
currencyComboBox = FormBuilder.addCurrencyComboBox(gridPane, "Currency used for bank account:", Utils.getAllCurrencies(), ++row);
|
||||
currencyComboBox.setPromptText("Select currency");
|
||||
currencyComboBox.setConverter(new StringConverter<Currency>()
|
||||
{
|
||||
|
@ -233,7 +235,7 @@ public class SetupController implements Initializable, ChildController, WalletFa
|
|||
}
|
||||
});
|
||||
|
||||
countryComboBox = FormBuilder.addComboBox(gridPane, "Country of bank account:", Utils.getAllLocales(), ++row);
|
||||
countryComboBox = FormBuilder.addLocalesComboBox(gridPane, "Country of bank account:", Utils.getAllLocales(), ++row);
|
||||
countryComboBox.setPromptText("Select country");
|
||||
countryComboBox.setConverter(new StringConverter<Locale>()
|
||||
{
|
||||
|
@ -267,11 +269,10 @@ public class SetupController implements Initializable, ChildController, WalletFa
|
|||
bankTransferTypeComboBox.valueProperty().addListener((ov, oldValue, newValue) -> {
|
||||
if (newValue != null && newValue instanceof BankAccountType)
|
||||
{
|
||||
BankAccountType bankAccountType = (BankAccountType) newValue;
|
||||
accountPrimaryID.setText("");
|
||||
accountPrimaryID.setPromptText(bankAccountType.getPrimaryIDName());
|
||||
accountPrimaryID.setPromptText(newValue.getPrimaryIDName());
|
||||
accountSecondaryID.setText("");
|
||||
accountSecondaryID.setPromptText(bankAccountType.getSecondaryIDName());
|
||||
accountSecondaryID.setPromptText(newValue.getSecondaryIDName());
|
||||
|
||||
checkCreateAccountButtonState();
|
||||
}
|
||||
|
@ -303,19 +304,14 @@ public class SetupController implements Initializable, ChildController, WalletFa
|
|||
{
|
||||
walletFacade.sendRegistrationTx(user.getStringifiedBankAccounts());
|
||||
user.setAccountID(walletFacade.getAccountRegistrationAddress().toString());
|
||||
user.setMessageID(walletFacade.getAccountRegistrationPubKey().toString());
|
||||
user.setMessageID(walletFacade.getAccountRegistrationPubKey());
|
||||
|
||||
storage.write(user.getClass().getName(), user);
|
||||
processStepBar.next();
|
||||
buildStep2();
|
||||
} catch (InsufficientMoneyException e1)
|
||||
{
|
||||
Dialogs.create()
|
||||
.title("Not enough money available")
|
||||
.message("There is not enough money available. Please pay in first to your wallet.")
|
||||
.nativeTitleBar()
|
||||
.lightweight()
|
||||
.showError();
|
||||
Popups.openErrorPopup("Not enough money available", "There is not enough money available. Please pay in first to your wallet.");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -334,7 +330,7 @@ public class SetupController implements Initializable, ChildController, WalletFa
|
|||
|
||||
FormBuilder.addHeaderLabel(gridPane, "Registration complete", ++row);
|
||||
FormBuilder.addTextField(gridPane, "Registration address:", walletFacade.getAccountRegistrationAddress().toString(), ++row);
|
||||
FormBuilder.addTextField(gridPane, "Balance:", Formatter.formatSatoshis(walletFacade.getAccountRegistrationBalance(), true), ++row);
|
||||
FormBuilder.addTextField(gridPane, "Balance:", BtcFormatter.formatSatoshis(walletFacade.getAccountRegistrationBalance(), true), ++row);
|
||||
|
||||
Button closeButton = FormBuilder.addButton(gridPane, "Close", ++row);
|
||||
closeButton.setDefaultButton(true);
|
||||
|
@ -409,9 +405,9 @@ public class SetupController implements Initializable, ChildController, WalletFa
|
|||
if (verifyBankAccountData())
|
||||
{
|
||||
BankAccount bankAccount = new BankAccount(
|
||||
(BankAccountType) bankTransferTypeComboBox.getSelectionModel().getSelectedItem(),
|
||||
(Currency) currencyComboBox.getSelectionModel().getSelectedItem(),
|
||||
(Locale) countryComboBox.getSelectionModel().getSelectedItem(),
|
||||
bankTransferTypeComboBox.getSelectionModel().getSelectedItem(),
|
||||
currencyComboBox.getSelectionModel().getSelectedItem(),
|
||||
countryComboBox.getSelectionModel().getSelectedItem(),
|
||||
accountTitle.getText(),
|
||||
accountHolderName.getText(),
|
||||
accountPrimaryID.getText(),
|
||||
|
|
|
@ -7,25 +7,23 @@
|
|||
xmlns:fx="http://javafx.com/fxml">
|
||||
<ScrollPane fitToWidth="true" AnchorPane.leftAnchor="10" AnchorPane.rightAnchor="10" AnchorPane.topAnchor="10"
|
||||
AnchorPane.bottomAnchor="30">
|
||||
<content>
|
||||
<VBox fx:id="vBox" spacing="10">
|
||||
<Label text="Setup trading account" id="headline-label"/>
|
||||
<ProcessStepBar fx:id="processStepBar"/>
|
||||
<VSpacer prefHeight="10"/>
|
||||
<Label fx:id="infoLabel"/>
|
||||
<GridPane fx:id="gridPane" vgap="5" hgap="5">
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
|
||||
</padding>
|
||||
<columnConstraints>
|
||||
<ColumnConstraints halignment="RIGHT"/>
|
||||
<ColumnConstraints halignment="LEFT" prefWidth="320"/>
|
||||
<ColumnConstraints halignment="LEFT"/>
|
||||
</columnConstraints>
|
||||
</GridPane>
|
||||
<Button fx:id="nextButton" defaultButton="true"/>
|
||||
<Button fx:id="skipButton"/>
|
||||
</VBox>
|
||||
</content>
|
||||
<VBox fx:id="vBox" spacing="10">
|
||||
<Label text="Setup trading account" id="headline-label"/>
|
||||
<ProcessStepBar fx:id="processStepBar"/>
|
||||
<VSpacer prefHeight="10"/>
|
||||
<Label fx:id="infoLabel"/>
|
||||
<GridPane fx:id="gridPane" vgap="5" hgap="5">
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
|
||||
</padding>
|
||||
<columnConstraints>
|
||||
<ColumnConstraints halignment="RIGHT"/>
|
||||
<ColumnConstraints halignment="LEFT" prefWidth="320"/>
|
||||
<ColumnConstraints halignment="LEFT"/>
|
||||
</columnConstraints>
|
||||
</GridPane>
|
||||
<Button fx:id="nextButton" defaultButton="true"/>
|
||||
<Button fx:id="skipButton"/>
|
||||
</VBox>
|
||||
</ScrollPane>
|
||||
</AnchorPane>
|
|
@ -20,9 +20,8 @@ public class Converter
|
|||
} catch (ParseException e)
|
||||
{
|
||||
log.warn(e.toString());
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.bitsquare.gui.util;
|
||||
|
||||
import io.bitsquare.bank.BankAccountType;
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.gui.components.VSpacer;
|
||||
import javafx.collections.FXCollections;
|
||||
|
@ -8,7 +9,9 @@ import javafx.scene.image.Image;
|
|||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.GridPane;
|
||||
|
||||
import java.util.Currency;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class FormBuilder
|
||||
{
|
||||
|
@ -67,14 +70,38 @@ public class FormBuilder
|
|||
return button;
|
||||
}
|
||||
|
||||
public static ComboBox addComboBox(GridPane gridPane, String title, List<?> list, int row)
|
||||
public static ComboBox<Locale> addLocalesComboBox(GridPane gridPane, String title, List<Locale> list, int row)
|
||||
{
|
||||
gridPane.add(new Label(title), 0, row);
|
||||
ComboBox comboBox = new ComboBox(FXCollections.observableArrayList(list));
|
||||
ComboBox<Locale> comboBox = new ComboBox<>(FXCollections.observableArrayList(list));
|
||||
gridPane.add(comboBox, 1, row);
|
||||
return comboBox;
|
||||
}
|
||||
|
||||
public static ComboBox<Currency> addCurrencyComboBox(GridPane gridPane, String title, List<Currency> list, int row)
|
||||
{
|
||||
gridPane.add(new Label(title), 0, row);
|
||||
ComboBox<Currency> comboBox = new ComboBox<>(FXCollections.observableArrayList(list));
|
||||
gridPane.add(comboBox, 1, row);
|
||||
return comboBox;
|
||||
}
|
||||
|
||||
public static ComboBox<BankAccountType> addBankAccountComboBox(GridPane gridPane, String title, List<BankAccountType> list, int row)
|
||||
{
|
||||
gridPane.add(new Label(title), 0, row);
|
||||
ComboBox<BankAccountType> comboBox = new ComboBox<>(FXCollections.observableArrayList(list));
|
||||
gridPane.add(comboBox, 1, row);
|
||||
return comboBox;
|
||||
}
|
||||
|
||||
/* public static ComboBox addLocalesComboBox(GridPane gridPane, String title, List<?> list, int row)
|
||||
{
|
||||
gridPane.add(new Label(title), 0, row);
|
||||
ComboBox<?> comboBox = new ComboBox<>(FXCollections.observableArrayList(list));
|
||||
gridPane.add(comboBox, 1, row);
|
||||
return comboBox;
|
||||
} */
|
||||
|
||||
|
||||
public static TextField addConfirmationsLabel(GridPane gridPane, WalletFacade walletFacade, int row)
|
||||
{
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package io.bitsquare.gui.util;
|
||||
|
||||
import io.bitsquare.btc.BtcFormatter;
|
||||
import io.bitsquare.trade.Direction;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Currency;
|
||||
import java.util.List;
|
||||
|
@ -88,14 +86,6 @@ public class Formatter
|
|||
return s.substring(1, s.length() - 1);
|
||||
}
|
||||
|
||||
public static String formatSatoshis(BigInteger satoshis, boolean useBTC)
|
||||
{
|
||||
if (useBTC)
|
||||
return formatDouble(BtcFormatter.satoshiToBTC(satoshis), 4) + " BTC";
|
||||
else
|
||||
return formatDouble(BtcFormatter.satoshiToBTC(satoshis), 4);
|
||||
}
|
||||
|
||||
public static String formatDouble(double value)
|
||||
{
|
||||
return formatDouble(value, 2);
|
||||
|
|
|
@ -13,4 +13,14 @@ public class Popups
|
|||
.lightweight()
|
||||
.showError();
|
||||
}
|
||||
|
||||
public static void openWarningPopup(String title, String message)
|
||||
{
|
||||
Dialogs.create()
|
||||
.title(title)
|
||||
.message(message)
|
||||
.nativeTitleBar()
|
||||
.lightweight()
|
||||
.showWarning();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,16 +12,16 @@ import static com.google.common.base.Preconditions.checkState;
|
|||
public class Transitions
|
||||
{
|
||||
|
||||
public static final int UI_ANIMATION_TIME_MSEC = 350;
|
||||
public static final int UI_ANIMATION_TIME = 350;
|
||||
|
||||
public static void fadeIn(Node ui)
|
||||
{
|
||||
fadeIn(ui, UI_ANIMATION_TIME_MSEC);
|
||||
fadeIn(ui, UI_ANIMATION_TIME);
|
||||
}
|
||||
|
||||
public static void fadeIn(Node ui, int time)
|
||||
{
|
||||
FadeTransition ft = new FadeTransition(Duration.millis(UI_ANIMATION_TIME_MSEC), ui);
|
||||
FadeTransition ft = new FadeTransition(Duration.millis(UI_ANIMATION_TIME), ui);
|
||||
ft.setFromValue(0.0);
|
||||
ft.setToValue(1.0);
|
||||
ft.play();
|
||||
|
@ -29,7 +29,7 @@ public class Transitions
|
|||
|
||||
public static Animation fadeOut(Node ui)
|
||||
{
|
||||
FadeTransition ft = new FadeTransition(Duration.millis(UI_ANIMATION_TIME_MSEC), ui);
|
||||
FadeTransition ft = new FadeTransition(Duration.millis(UI_ANIMATION_TIME), ui);
|
||||
ft.setFromValue(ui.getOpacity());
|
||||
ft.setToValue(0.0);
|
||||
ft.play();
|
||||
|
@ -45,7 +45,7 @@ public class Transitions
|
|||
|
||||
public static void blurOut(Node node)
|
||||
{
|
||||
blurOut(node, UI_ANIMATION_TIME_MSEC);
|
||||
blurOut(node, UI_ANIMATION_TIME);
|
||||
}
|
||||
|
||||
public static void blurOut(Node node, int time)
|
||||
|
@ -64,7 +64,7 @@ public class Transitions
|
|||
GaussianBlur blur = (GaussianBlur) node.getEffect();
|
||||
Timeline timeline = new Timeline();
|
||||
KeyValue kv = new KeyValue(blur.radiusProperty(), 0.0);
|
||||
KeyFrame kf = new KeyFrame(Duration.millis(UI_ANIMATION_TIME_MSEC), kv);
|
||||
KeyFrame kf = new KeyFrame(Duration.millis(UI_ANIMATION_TIME), kv);
|
||||
timeline.getKeyFrames().add(kf);
|
||||
timeline.setOnFinished(actionEvent -> node.setEffect(null));
|
||||
timeline.play();
|
||||
|
|
|
@ -49,7 +49,7 @@ public class Message
|
|||
|
||||
public String toString()
|
||||
{
|
||||
return type + ": " + Utils.convertToJson(payload);
|
||||
return type + ": " + Utils.objectToJson(payload);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.google.inject.Inject;
|
|||
import io.bitsquare.user.Arbitrator;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -14,8 +15,9 @@ public class Settings implements Serializable
|
|||
|
||||
private List<Locale> acceptedLanguageLocales = new ArrayList<>();
|
||||
private List<Locale> acceptedCountryLocales = new ArrayList<>();
|
||||
private List<Arbitrator> arbitrators = new ArrayList<>();
|
||||
|
||||
private List<Arbitrator> acceptedArbitrators = new ArrayList<>();
|
||||
private double maxCollateral;
|
||||
private double minCollateral;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
|
@ -37,7 +39,9 @@ public class Settings implements Serializable
|
|||
{
|
||||
acceptedLanguageLocales = savedSettings.getAcceptedLanguageLocales();
|
||||
acceptedCountryLocales = savedSettings.getAcceptedCountryLocales();
|
||||
arbitrators = savedSettings.getArbitrators();
|
||||
acceptedArbitrators = savedSettings.getAcceptedArbitrators();
|
||||
maxCollateral = savedSettings.getMaxCollateral();
|
||||
minCollateral = savedSettings.getMinCollateral();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,20 +57,29 @@ public class Settings implements Serializable
|
|||
acceptedCountryLocales.add(locale);
|
||||
}
|
||||
|
||||
public void addArbitrator(Arbitrator arbitrator)
|
||||
public void addAcceptedArbitrator(Arbitrator arbitrator)
|
||||
{
|
||||
if (!arbitrators.contains(arbitrator))
|
||||
arbitrators.add(arbitrator);
|
||||
if (!acceptedArbitrators.contains(arbitrator))
|
||||
acceptedArbitrators.add(arbitrator);
|
||||
}
|
||||
|
||||
public void setMaxCollateral(double maxCollateral)
|
||||
{
|
||||
this.maxCollateral = maxCollateral;
|
||||
}
|
||||
|
||||
public void setMinCollateral(double minCollateral)
|
||||
{
|
||||
this.minCollateral = minCollateral;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Getters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public List<Arbitrator> getArbitrators()
|
||||
public List<Arbitrator> getAcceptedArbitrators()
|
||||
{
|
||||
return arbitrators;
|
||||
return acceptedArbitrators;
|
||||
}
|
||||
|
||||
public List<Locale> getAcceptedLanguageLocales()
|
||||
|
@ -79,8 +92,28 @@ public class Settings implements Serializable
|
|||
return acceptedCountryLocales;
|
||||
}
|
||||
|
||||
public Arbitrator getRandomArbitrator()
|
||||
public Arbitrator getRandomArbitrator(double collateral, BigInteger amount)
|
||||
{
|
||||
return arbitrators.size() > 0 ? arbitrators.get((int) (Math.random() * arbitrators.size())) : null;
|
||||
List<Arbitrator> candidates = new ArrayList<>();
|
||||
for (Arbitrator arbitrator : acceptedArbitrators)
|
||||
{
|
||||
if (arbitrator.getArbitrationFeePercent() >= collateral &&
|
||||
arbitrator.getMinArbitrationFee().compareTo(amount) < 0)
|
||||
{
|
||||
candidates.add(arbitrator);
|
||||
}
|
||||
}
|
||||
return candidates.size() > 0 ? candidates.get((int) (Math.random() * candidates.size())) : null;
|
||||
}
|
||||
|
||||
public double getMaxCollateral()
|
||||
{
|
||||
return maxCollateral;
|
||||
}
|
||||
|
||||
public double getMinCollateral()
|
||||
{
|
||||
return minCollateral;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.bitsquare.trade;
|
|||
import io.bitsquare.bank.BankAccountType;
|
||||
import io.bitsquare.user.Arbitrator;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Currency;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -12,29 +13,37 @@ public class Offer
|
|||
{
|
||||
private UUID uid;
|
||||
private double price;
|
||||
private double amount;
|
||||
private double minAmount;
|
||||
private BigInteger amount;
|
||||
private BigInteger minAmount;
|
||||
private String accountID;
|
||||
private String messageID;
|
||||
private Direction direction;
|
||||
private BankAccountType.BankAccountTypeEnum bankAccountTypeEnum;
|
||||
private Currency currency;
|
||||
private Locale bankAccountCountryLocale;
|
||||
|
||||
private double collateral;
|
||||
private List<Locale> acceptedCountryLocales;
|
||||
private List<Locale> acceptedLanguageLocales;
|
||||
private String offerPaymentTxID;
|
||||
private Arbitrator arbitrator;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Offer(String accountID,
|
||||
String messageID,
|
||||
Direction direction,
|
||||
double price,
|
||||
double amount,
|
||||
double minAmount,
|
||||
BigInteger amount,
|
||||
BigInteger minAmount,
|
||||
BankAccountType.BankAccountTypeEnum bankAccountTypeEnum,
|
||||
Currency currency,
|
||||
Locale bankAccountCountryLocale,
|
||||
Arbitrator arbitrator,
|
||||
double collateral,
|
||||
List<Locale> acceptedCountryLocales,
|
||||
List<Locale> acceptedLanguageLocales)
|
||||
{
|
||||
|
@ -48,6 +57,7 @@ public class Offer
|
|||
this.currency = currency;
|
||||
this.bankAccountCountryLocale = bankAccountCountryLocale;
|
||||
this.arbitrator = arbitrator;
|
||||
this.collateral = collateral;
|
||||
this.acceptedCountryLocales = acceptedCountryLocales;
|
||||
this.acceptedLanguageLocales = acceptedLanguageLocales;
|
||||
|
||||
|
@ -89,12 +99,12 @@ public class Offer
|
|||
return price;
|
||||
}
|
||||
|
||||
public double getAmount()
|
||||
public BigInteger getAmount()
|
||||
{
|
||||
return amount;
|
||||
}
|
||||
|
||||
public double getMinAmount()
|
||||
public BigInteger getMinAmount()
|
||||
{
|
||||
return minAmount;
|
||||
}
|
||||
|
@ -131,12 +141,12 @@ public class Offer
|
|||
|
||||
public double getVolume()
|
||||
{
|
||||
return price * amount;
|
||||
return price * amount.doubleValue();
|
||||
}
|
||||
|
||||
public double getMinVolume()
|
||||
{
|
||||
return price * minAmount;
|
||||
return price * minAmount.doubleValue();
|
||||
}
|
||||
|
||||
public String getOfferPaymentTxID()
|
||||
|
@ -148,4 +158,9 @@ public class Offer
|
|||
{
|
||||
return arbitrator;
|
||||
}
|
||||
|
||||
public double getCollateral()
|
||||
{
|
||||
return collateral;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.bitsquare.trade;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Trade
|
||||
|
@ -7,8 +8,7 @@ public class Trade
|
|||
private Offer offer;
|
||||
private boolean takeOfferRequested;
|
||||
private boolean takeOfferAccepted;
|
||||
private double requestedAmount;
|
||||
private boolean takeOfferFeePayed;
|
||||
private BigInteger requestedAmount;
|
||||
private boolean takeOfferFeePaymentConfirmed;
|
||||
private String jsonRepresentation;
|
||||
private String signature;
|
||||
|
@ -59,21 +59,16 @@ public class Trade
|
|||
this.takeOfferAccepted = takeOfferAccepted;
|
||||
}
|
||||
|
||||
public double getRequestedAmount()
|
||||
public BigInteger getRequestedAmount()
|
||||
{
|
||||
return requestedAmount;
|
||||
}
|
||||
|
||||
public void setTradeAmount(double requestedAmount)
|
||||
public void setTradeAmount(BigInteger requestedAmount)
|
||||
{
|
||||
this.requestedAmount = requestedAmount;
|
||||
}
|
||||
|
||||
public void setTakeOfferFeePayed(boolean takeOfferFeePayed)
|
||||
{
|
||||
this.takeOfferFeePayed = takeOfferFeePayed;
|
||||
}
|
||||
|
||||
public void setTakeOfferFeePaymentConfirmed(boolean takeOfferFeePaymentConfirmed)
|
||||
{
|
||||
this.takeOfferFeePaymentConfirmed = takeOfferFeePaymentConfirmed;
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package io.bitsquare.trade;
|
||||
|
||||
import com.google.bitcoin.core.InsufficientMoneyException;
|
||||
import com.google.bitcoin.core.Transaction;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.btc.BlockChainFacade;
|
||||
import io.bitsquare.btc.Fees;
|
||||
import io.bitsquare.btc.KeyPair;
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.crypto.CryptoFacade;
|
||||
|
@ -18,8 +21,9 @@ import java.util.HashMap;
|
|||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Main facade for operating with trade domain between GUI and services (msg, btc)
|
||||
* Represents trade domain. Keeps complexity of process apart from view controller
|
||||
*/
|
||||
//TODO use scheduler/process pattern with tasks for every async job
|
||||
public class Trading
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(Trading.class);
|
||||
|
@ -34,6 +38,11 @@ public class Trading
|
|||
private CryptoFacade cryptoFacade;
|
||||
private Settings settings;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public Trading(User user,
|
||||
Settings settings,
|
||||
|
@ -50,64 +59,21 @@ public class Trading
|
|||
this.cryptoFacade = cryptoFacade;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param offer
|
||||
*/
|
||||
public String placeNewOffer(Offer offer) throws InsufficientMoneyException
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public Methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void placeNewOffer(Offer offer, FutureCallback<Transaction> callback) throws InsufficientMoneyException
|
||||
{
|
||||
log.info("place New Offer");
|
||||
offers.put(offer.getUid().toString(), offer);
|
||||
String txID = walletFacade.payOfferFee();
|
||||
offer.setOfferPaymentTxID(txID);
|
||||
walletFacade.payFee(Fees.OFFER_CREATION_FEE, callback);
|
||||
|
||||
messageFacade.broadcast(new Message(Message.BROADCAST_NEW_OFFER, offer));
|
||||
return txID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Taker requests offerer to take the offer
|
||||
*
|
||||
* @param trade
|
||||
*/
|
||||
public void sendTakeOfferRequest(Trade trade)
|
||||
{
|
||||
log.info("Taker asks offerer to take his offer");
|
||||
//messageFacade.send(new Message(Message.REQUEST_TAKE_OFFER, trade), trade.getOffer().getOfferer().getMessageID());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param trade
|
||||
* @return
|
||||
*/
|
||||
public Contract createNewContract(Trade trade)
|
||||
{
|
||||
log.info("create new contract");
|
||||
KeyPair address = walletFacade.createNewAddress();
|
||||
|
||||
Contract contract = new Contract(user, trade, address.getPubKey());
|
||||
contracts.put(trade.getUid().toString(), contract);
|
||||
return contract;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contract
|
||||
*/
|
||||
public void signContract(Contract contract)
|
||||
{
|
||||
log.info("sign Contract");
|
||||
|
||||
String contractAsJson = Utils.convertToJson(contract);
|
||||
|
||||
contract.getTrade().setJsonRepresentation(contractAsJson);
|
||||
contract.getTrade().setSignature(cryptoFacade.signContract(contractAsJson));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param offer
|
||||
* @return
|
||||
*/
|
||||
public Trade createNewTrade(Offer offer)
|
||||
public Trade createTrade(Offer offer)
|
||||
{
|
||||
log.info("create New Trade");
|
||||
Trade trade = new Trade(offer);
|
||||
|
@ -115,55 +81,63 @@ public class Trading
|
|||
return trade;
|
||||
}
|
||||
|
||||
|
||||
public HashMap<String, Trade> getTrades()
|
||||
public Contract createContract(Trade trade)
|
||||
{
|
||||
return trades;
|
||||
log.info("create new contract");
|
||||
KeyPair address = new KeyPair(UUID.randomUUID().toString(), UUID.randomUUID().toString());
|
||||
//TODO
|
||||
Contract contract = new Contract(user, trade, address.getPubKey());
|
||||
contracts.put(trade.getUid().toString(), contract);
|
||||
return contract;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param trade
|
||||
*/
|
||||
public void payOfferFee(Trade trade)
|
||||
|
||||
// trade process
|
||||
// 1
|
||||
public void sendTakeOfferRequest(Trade trade)
|
||||
{
|
||||
log.info("Taker asks offerer to take his offer");
|
||||
//messageFacade.send(new Message(Message.REQUEST_TAKE_OFFER, trade), trade.getOffer().getOfferer().getMessageID());
|
||||
}
|
||||
|
||||
// 2
|
||||
public void payOfferFee(Trade trade, FutureCallback<Transaction> callback) throws InsufficientMoneyException
|
||||
{
|
||||
log.info("Pay offer fee");
|
||||
|
||||
trade.setTakeOfferFeePayed(true);
|
||||
walletFacade.payFee(Fees.OFFER_TAKER_FEE, callback);
|
||||
|
||||
String txID = UUID.randomUUID().toString();
|
||||
trade.setTakeOfferFeePayed(true);
|
||||
trade.setTakeOfferFeeTxID(txID);
|
||||
|
||||
log.info("Taker asks offerer for confirmation for his fee payment. txID=" + txID);
|
||||
log.info("Taker asks offerer for confirmation for his fee payment.");
|
||||
// messageFacade.send(new Message(Message.REQUEST_OFFER_FEE_PAYMENT_CONFIRM, trade), trade.getOffer().getOfferer().getMessageID());
|
||||
}
|
||||
|
||||
|
||||
// 3
|
||||
public void requestOffererDetailData()
|
||||
{
|
||||
log.info("Request offerer detail data");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param trade
|
||||
*/
|
||||
// 4
|
||||
public void signContract(Contract contract)
|
||||
{
|
||||
log.info("sign Contract");
|
||||
|
||||
String contractAsJson = Utils.objectToJson(contract);
|
||||
|
||||
contract.getTrade().setJsonRepresentation(contractAsJson);
|
||||
contract.getTrade().setSignature(cryptoFacade.signContract(walletFacade.getAccountKey(), contractAsJson));
|
||||
}
|
||||
|
||||
// 5
|
||||
public void payToDepositTx(Trade trade)
|
||||
{
|
||||
log.info("create MultiSig address");
|
||||
|
||||
log.info("Create deposit tx");
|
||||
|
||||
log.info("Sign deposit tx");
|
||||
|
||||
log.info("Send deposit Tx");
|
||||
//walletFacade.takerAddPaymentAndSign();
|
||||
// messageFacade.send(new Message(Message.REQUEST_OFFER_FEE_PAYMENT_CONFIRM, trade), trade.getOffer().getOfferer().getMessageID());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param trade
|
||||
*/
|
||||
// 6
|
||||
public void releaseBTC(Trade trade)
|
||||
{
|
||||
log.info("Sign payment tx");
|
||||
|
@ -174,5 +148,13 @@ public class Trading
|
|||
// messageFacade.send(new Message(Message.REQUEST_OFFER_FEE_PAYMENT_CONFIRM, trade), trade.getOffer().getOfferer().getMessageID());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Getters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public HashMap<String, Trade> getTrades()
|
||||
{
|
||||
return trades;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.bitsquare.trade.orderbook;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.btc.BtcFormatter;
|
||||
import io.bitsquare.gui.market.orderbook.OrderBookListItem;
|
||||
import io.bitsquare.gui.util.Converter;
|
||||
import io.bitsquare.gui.util.Formatter;
|
||||
|
@ -42,19 +43,20 @@ public class MockOrderBook extends OrderBook
|
|||
direction = Direction.SELL;
|
||||
price = 500 - Math.random() * 50;
|
||||
}
|
||||
|
||||
double collateral = 0.1;// Math.random() * 20 + 0.1;
|
||||
Offer offer = new Offer("mjbxLbuVpU1cNXLJbrJZyirYwweoRPVVTj",
|
||||
UUID.randomUUID().toString(),
|
||||
direction,
|
||||
price,
|
||||
amount,
|
||||
minAmount,
|
||||
MockData.getBankTransferTypeEnums().get(0),
|
||||
MockData.getCurrencies().get(0),
|
||||
MockData.getLocales().get(0),
|
||||
MockData.getArbitrators().get(0),
|
||||
MockData.getLocales(),
|
||||
MockData.getLocales());
|
||||
BtcFormatter.doubleValueToSatoshis(amount),
|
||||
BtcFormatter.doubleValueToSatoshis(minAmount),
|
||||
MockData.getRandomBankTransferTypeEnums().get(0),
|
||||
MockData.getRandomCurrencies().get(0),
|
||||
MockData.getRandomLocales().get(0),
|
||||
MockData.getRandomArbitrators().get(0),
|
||||
collateral,
|
||||
MockData.getRandomLocales(),
|
||||
MockData.getRandomLocales());
|
||||
|
||||
return offer;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import io.bitsquare.gui.market.orderbook.OrderBookListItem;
|
|||
import io.bitsquare.settings.Settings;
|
||||
import io.bitsquare.trade.Direction;
|
||||
import io.bitsquare.trade.Offer;
|
||||
import io.bitsquare.user.Arbitrator;
|
||||
import io.bitsquare.user.User;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
|
@ -76,7 +77,7 @@ public class OrderBook
|
|||
// The requested amount must be lower or equal then the offer amount
|
||||
boolean amountResult = true;
|
||||
if (orderBookFilter.getAmount() > 0)
|
||||
amountResult = orderBookFilter.getAmount() <= offer.getAmount();
|
||||
amountResult = orderBookFilter.getAmount() <= offer.getAmount().doubleValue();
|
||||
|
||||
// The requested trade direction must be opposite of the offerList trade direction
|
||||
boolean directionResult = !orderBookFilter.getDirection().equals(offer.getDirection());
|
||||
|
@ -91,40 +92,46 @@ public class OrderBook
|
|||
priceResult = orderBookFilter.getPrice() <= offer.getPrice();
|
||||
}
|
||||
|
||||
// The arbitrator defined in the offer must match one of the accepted arbitrators defined in the settings (1 to n)
|
||||
boolean arbitratorResult = arbitratorInList(offer.getArbitrator(), settings.getAcceptedArbitrators());
|
||||
|
||||
|
||||
boolean result = currencyResult
|
||||
&& countryResult
|
||||
&& languageResult
|
||||
&& amountResult
|
||||
&& directionResult
|
||||
&& priceResult;
|
||||
&& priceResult
|
||||
&& arbitratorResult;
|
||||
|
||||
/*
|
||||
/*
|
||||
log.debug("result = " + result +
|
||||
", currencyResult = " + currencyResult +
|
||||
", countryResult = " + countryResult +
|
||||
", languageResult = " + languageResult +
|
||||
", bankAccountTypeEnumResult = " + bankAccountTypeEnumResult +
|
||||
", amountResult = " + amountResult +
|
||||
", directionResult = " + directionResult +
|
||||
", priceResult = " + priceResult
|
||||
", priceResult = " + priceResult +
|
||||
", arbitratorResult = " + arbitratorResult
|
||||
);
|
||||
|
||||
log.debug("currentBankAccount.getCurrency() = " + currentBankAccount.getCurrency() +
|
||||
", offer.getCurrency() = " + offer.getCurrency());
|
||||
log.debug("offer.getCountryLocale() = " + offer.getCountryLocale() +
|
||||
log.debug("offer.getCountryLocale() = " + offer.getBankAccountCountryLocale() +
|
||||
", settings.getAcceptedCountryLocales() = " + settings.getAcceptedCountryLocales().toString());
|
||||
log.debug("settings.getAcceptedLanguageLocales() = " + settings.getAcceptedLanguageLocales() +
|
||||
", constraints.getAcceptedLanguageLocales() = " + constraints.getLanguageLocales());
|
||||
", offer.getAcceptedLanguageLocales() = " + offer.getAcceptedLanguageLocales());
|
||||
log.debug("currentBankAccount.getBankAccountType().getType() = " + currentBankAccount.getBankAccountType().getType() +
|
||||
", constraints.getBankAccountTypes() = " + constraints.getBankAccountTypes());
|
||||
", offer.getBankAccountTypeEnum() = " + offer.getBankAccountTypeEnum());
|
||||
log.debug("orderBookFilter.getAmount() = " + orderBookFilter.getAmount() +
|
||||
", offer.getAmount() = " + offer.getAmount());
|
||||
log.debug("orderBookFilter.getDirection() = " + orderBookFilter.getDirection() +
|
||||
", offer.getDirection() = " + offer.getDirection());
|
||||
log.debug("orderBookFilter.getPrice() = " + orderBookFilter.getPrice() +
|
||||
", offer.getPrice() = " + offer.getPrice());
|
||||
*/
|
||||
|
||||
log.debug("offer.getArbitrator() = " + offer.getArbitrator() +
|
||||
", settings.getAcceptedArbitrators() = " + settings.getAcceptedArbitrators());
|
||||
*/
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
@ -144,26 +151,45 @@ public class OrderBook
|
|||
// Private Methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private boolean countryInList(Locale orderBookFilterLocale, List<Locale> offerConstraintsLocales)
|
||||
private boolean countryInList(Locale localeToMatch, List<Locale> list)
|
||||
{
|
||||
for (Locale locale : offerConstraintsLocales)
|
||||
for (Locale locale : list)
|
||||
{
|
||||
if (locale.getCountry().equals(orderBookFilterLocale.getCountry()))
|
||||
if (locale.getCountry().equals(localeToMatch.getCountry()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean languagesInList(List<Locale> orderBookFilterLocales, List<Locale> offerConstraintsLocales)
|
||||
private boolean languagesInList(List<Locale> list1, List<Locale> list2)
|
||||
{
|
||||
for (Locale offerConstraintsLocale : offerConstraintsLocales)
|
||||
for (Locale locale1 : list2)
|
||||
{
|
||||
for (Locale orderBookFilterLocale : orderBookFilterLocales)
|
||||
for (Locale locale2 : list1)
|
||||
{
|
||||
if (offerConstraintsLocale.getLanguage().equals(orderBookFilterLocale.getLanguage()))
|
||||
if (locale1.getLanguage().equals(locale2.getLanguage()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean arbitratorInList(Arbitrator arbitratorToMatch, List<Arbitrator> list)
|
||||
{
|
||||
if (arbitratorToMatch != null)
|
||||
{
|
||||
for (Arbitrator arbitrator : list)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (arbitrator.getUID().equals(arbitratorToMatch.getUID()))
|
||||
return true;
|
||||
} catch (Exception e)
|
||||
{
|
||||
log.error(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.bitsquare.user;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class Arbitrator implements Serializable
|
||||
{
|
||||
|
@ -11,13 +12,22 @@ public class Arbitrator implements Serializable
|
|||
private String messageID;
|
||||
private String url;
|
||||
|
||||
public Arbitrator(String name, String pubKey, String messageID, String url)
|
||||
{
|
||||
|
||||
private double baseFeePercent;
|
||||
private double arbitrationFeePercent;
|
||||
private BigInteger minArbitrationFee;
|
||||
private String uid;
|
||||
|
||||
public Arbitrator(String uid, String name, String pubKey, String messageID, String url, double baseFeePercent, double arbitrationFeePercent, BigInteger minArbitrationFee)
|
||||
{
|
||||
this.uid = uid;
|
||||
this.name = name;
|
||||
this.pubKey = pubKey;
|
||||
this.messageID = messageID;
|
||||
this.url = url;
|
||||
this.baseFeePercent = baseFeePercent;
|
||||
this.arbitrationFeePercent = arbitrationFeePercent;
|
||||
this.minArbitrationFee = minArbitrationFee;
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,4 +55,23 @@ public class Arbitrator implements Serializable
|
|||
return url;
|
||||
}
|
||||
|
||||
public BigInteger getMinArbitrationFee()
|
||||
{
|
||||
return minArbitrationFee;
|
||||
}
|
||||
|
||||
public double getBaseFeePercent()
|
||||
{
|
||||
return baseFeePercent;
|
||||
}
|
||||
|
||||
public double getArbitrationFeePercent()
|
||||
{
|
||||
return arbitrationFeePercent;
|
||||
}
|
||||
|
||||
public Object getUID()
|
||||
{
|
||||
return uid;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ public class User implements Serializable
|
|||
private List<BankAccount> bankAccounts = new ArrayList<>();
|
||||
private BankAccount currentBankAccount = null;
|
||||
|
||||
|
||||
public User()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -20,7 +20,12 @@ public class MockData
|
|||
list.add(Currency.getInstance("JPY"));
|
||||
list.add(Currency.getInstance("CNY"));
|
||||
list.add(Currency.getInstance("CHF"));
|
||||
return randomizeList(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<Currency> getRandomCurrencies()
|
||||
{
|
||||
return randomizeList(getCurrencies());
|
||||
}
|
||||
|
||||
public static List<Locale> getLocales()
|
||||
|
@ -36,20 +41,40 @@ public class MockData
|
|||
list.add(new Locale("en", "AU"));
|
||||
list.add(new Locale("it", "IT"));
|
||||
list.add(new Locale("en", "CA"));
|
||||
return randomizeList(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<Locale> getRandomLocales()
|
||||
{
|
||||
return randomizeList(getLocales());
|
||||
}
|
||||
|
||||
public static List<Arbitrator> getArbitrators()
|
||||
{
|
||||
List<Arbitrator> list = new ArrayList<>();
|
||||
list.add(new Arbitrator("Charly Shen", UUID.randomUUID().toString(), UUID.randomUUID().toString(), "http://www.arbit.io/Charly_Shen"));
|
||||
list.add(new Arbitrator("Tom Shang", UUID.randomUUID().toString(), UUID.randomUUID().toString(), "http://www.arbit.io/Tom_Shang"));
|
||||
list.add(new Arbitrator("Edward Swow", UUID.randomUUID().toString(), UUID.randomUUID().toString(), "http://www.arbit.io/Edward_Swow"));
|
||||
list.add(new Arbitrator("Julian Sangre", UUID.randomUUID().toString(), UUID.randomUUID().toString(), "http://www.arbit.io/Julian_Sangre"));
|
||||
return randomizeList(list);
|
||||
list.add(new Arbitrator("uid_1", "Charlie Boom", UUID.randomUUID().toString(),
|
||||
UUID.randomUUID().toString(), "http://www.arbit.io/Charly_Boom", 0.1, 10, com.google.bitcoin.core.Utils.toNanoCoins("0.01")));
|
||||
list.add(new Arbitrator("uid_2", "Tom Shang", UUID.randomUUID().toString(),
|
||||
UUID.randomUUID().toString(), "http://www.arbit.io/Tom_Shang", 0, 1, com.google.bitcoin.core.Utils.toNanoCoins("0.001")));
|
||||
list.add(new Arbitrator("uid_3", "Edward Snow", UUID.randomUUID().toString(),
|
||||
UUID.randomUUID().toString(), "http://www.arbit.io/Edward_Swow", 0.2, 5, com.google.bitcoin.core.Utils.toNanoCoins("0.05")));
|
||||
list.add(new Arbitrator("uid_4", "Julian Sander", UUID.randomUUID().toString(),
|
||||
UUID.randomUUID().toString(), "http://www.arbit.io/Julian_Sander", 0, 20, com.google.bitcoin.core.Utils.toNanoCoins("0.1")));
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<Arbitrator> getRandomArbitrators()
|
||||
{
|
||||
return randomizeList(getArbitrators());
|
||||
}
|
||||
|
||||
|
||||
public static List<BankAccountType.BankAccountTypeEnum> getBankTransferTypeEnums()
|
||||
{
|
||||
return Utils.getAllBankAccountTypeEnums();
|
||||
}
|
||||
|
||||
public static List<BankAccountType.BankAccountTypeEnum> getRandomBankTransferTypeEnums()
|
||||
{
|
||||
return randomizeList(Utils.getAllBankAccountTypeEnums());
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.bitsquare.util;
|
|||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.sun.xml.internal.messaging.saaj.util.ByteInputStream;
|
||||
import io.bitsquare.bank.BankAccountType;
|
||||
import javafx.animation.AnimationTimer;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -20,12 +21,66 @@ public class Utils
|
|||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(Utils.class);
|
||||
|
||||
public static String convertToJson(Object object)
|
||||
public static String objectToJson(Object object)
|
||||
{
|
||||
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
|
||||
return gson.toJson(object);
|
||||
}
|
||||
|
||||
public static <T> T jsonToObject(String jsonString, Class<T> classOfT)
|
||||
{
|
||||
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
|
||||
return gson.fromJson(jsonString, classOfT);
|
||||
}
|
||||
|
||||
public static Object deserializeHexStringToObject(String serializedHexString)
|
||||
{
|
||||
Object result = null;
|
||||
try
|
||||
{
|
||||
ByteInputStream byteInputStream = new ByteInputStream();
|
||||
byteInputStream.setBuf(com.google.bitcoin.core.Utils.parseAsHexOrBase58(serializedHexString));
|
||||
ObjectInputStream objectInputStream = new ObjectInputStream(byteInputStream);
|
||||
|
||||
try
|
||||
{
|
||||
result = objectInputStream.readObject();
|
||||
} catch (ClassNotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
} finally
|
||||
{
|
||||
byteInputStream.close();
|
||||
objectInputStream.close();
|
||||
}
|
||||
|
||||
} catch (IOException i)
|
||||
{
|
||||
i.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String serializeObjectToHexString(Object serializable)
|
||||
{
|
||||
String result = null;
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
try
|
||||
{
|
||||
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
|
||||
objectOutputStream.writeObject(serializable);
|
||||
|
||||
result = com.google.bitcoin.core.Utils.bytesToHexString(byteArrayOutputStream.toByteArray());
|
||||
byteArrayOutputStream.close();
|
||||
objectOutputStream.close();
|
||||
|
||||
} catch (IOException e)
|
||||
{
|
||||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static long lastTimeStamp = System.currentTimeMillis();
|
||||
|
||||
public static void printElapsedTime(String msg)
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
|
||||
<logger name="io.bitsquare" level="DEBUG"/>
|
||||
|
||||
<logger name="com.google.bitcoin" level="WARN"/>
|
||||
<logger name="com.google.bitcoin" level="INFO"/>
|
||||
|
||||
<logger name="com.google.bitcoin.core.Peer" level="ERROR" additivity="false"/>
|
||||
<logger name="com.google.bitcoin.core.PeerGroup" level="ERROR" additivity="false"/>
|
||||
<logger name="com.google.bitcoin.net.NioClientManager" level="ERROR" additivity="false"/>
|
||||
<logger name="com.google.bitcoin.net.ConnectionHandler" level="ERROR" additivity="false"/>
|
||||
|
|
Loading…
Add table
Reference in a new issue