mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-07-30 10:18:44 -04:00
Savings wallet (WIP)
This commit is contained in:
parent
9ac0740e33
commit
37b31a5d0a
82 changed files with 1238 additions and 740 deletions
|
@ -53,8 +53,7 @@ public final class Alert implements StoragePayload {
|
|||
in.defaultReadObject();
|
||||
storagePublicKey = KeyFactory.getInstance(Sig.KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(storagePublicKeyBytes));
|
||||
} catch (Throwable t) {
|
||||
log.error("Exception at readObject: " + t.getMessage());
|
||||
t.printStackTrace();
|
||||
log.warn("Exception at readObject: " + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ public final class Dispute implements Payload {
|
|||
disputeResultProperty = new SimpleObjectProperty<>(disputeResult);
|
||||
isClosedProperty = new SimpleBooleanProperty(isClosed);
|
||||
} catch (Throwable t) {
|
||||
log.trace("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ public final class DisputeList<DisputeCase> extends ArrayList<DisputeCase> imple
|
|||
try {
|
||||
in.defaultReadObject();
|
||||
} catch (Throwable t) {
|
||||
log.trace("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ public final class DisputeResult implements Payload {
|
|||
in.defaultReadObject();
|
||||
init();
|
||||
} catch (Throwable t) {
|
||||
log.trace("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ public final class DisputeCommunicationMessage extends DisputeMessage {
|
|||
arrivedProperty = new SimpleBooleanProperty(arrived);
|
||||
storedInMailboxProperty = new SimpleBooleanProperty(storedInMailbox);
|
||||
} catch (Throwable t) {
|
||||
log.trace("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,11 @@ class AddressBasedCoinSelector implements CoinSelector {
|
|||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public AddressBasedCoinSelector(NetworkParameters params, AddressEntry addressEntry) {
|
||||
public AddressBasedCoinSelector(NetworkParameters params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public AddressBasedCoinSelector(NetworkParameters params, @Nullable AddressEntry addressEntry) {
|
||||
this.params = params;
|
||||
this.addressEntry = addressEntry;
|
||||
}
|
||||
|
@ -119,6 +123,9 @@ class AddressBasedCoinSelector implements CoinSelector {
|
|||
|
||||
log.trace("No match found at matchesRequiredAddress addressOutput / addressEntries " + addressOutput.toString
|
||||
() + " / " + addressEntries.toString());
|
||||
} else {
|
||||
// use savings wallet
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -101,7 +101,7 @@ public final class AddressEntry implements Persistable {
|
|||
params = RegTestParams.get();
|
||||
|
||||
} catch (Throwable t) {
|
||||
log.trace("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* The List supporting our persistence solution.
|
||||
|
@ -82,6 +83,17 @@ public final class AddressEntryList extends ArrayList<AddressEntry> implements P
|
|||
}
|
||||
|
||||
|
||||
public void swapTradeToSavings(String offerId) {
|
||||
Optional<AddressEntry> addressEntryOptional = this.stream().filter(addressEntry -> offerId.equals(addressEntry.getOfferId())).findAny();
|
||||
if (addressEntryOptional.isPresent()) {
|
||||
AddressEntry addressEntry = addressEntryOptional.get();
|
||||
add(new AddressEntry(addressEntry.getKeyPair(), wallet.getParams(), AddressEntry.Context.SAVINGS));
|
||||
remove(addressEntry);
|
||||
storage.queueUpForSave();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public AddressEntry getArbitratorAddressEntry() {
|
||||
if (size() > 0)
|
||||
return get(0);
|
||||
|
|
|
@ -134,19 +134,22 @@ public class TradeWalletService {
|
|||
|
||||
/**
|
||||
* @param addressEntry From where we want to spend the transaction fee. Used also as change address.
|
||||
* @param useSavingsWallet
|
||||
* @param tradingFee The amount of the trading fee.
|
||||
* @param feeReceiverAddresses The address of the receiver of the trading fee (arbitrator).
|
||||
* @return The broadcasted transaction
|
||||
* @param feeReceiverAddresses The address of the receiver of the trading fee (arbitrator). @return The broadcasted transaction
|
||||
* @throws InsufficientMoneyException
|
||||
* @throws AddressFormatException
|
||||
*/
|
||||
public Transaction createTradingFeeTx(AddressEntry addressEntry, Coin tradingFee, String feeReceiverAddresses)
|
||||
public Transaction createTradingFeeTx(AddressEntry addressEntry, Address changeAddress, Coin reservedFundsForOffer,
|
||||
boolean useSavingsWallet, Coin tradingFee, String feeReceiverAddresses)
|
||||
throws InsufficientMoneyException, AddressFormatException {
|
||||
Transaction tradingFeeTx = new Transaction(params);
|
||||
Preconditions.checkArgument(Restrictions.isAboveFixedTxFeeAndDust(tradingFee),
|
||||
"You cannot send an amount which are smaller than the fee + dust output.");
|
||||
Coin outPutAmount = tradingFee.subtract(FeePolicy.getFixedTxFeeForTrades());
|
||||
tradingFeeTx.addOutput(outPutAmount, new Address(params, feeReceiverAddresses));
|
||||
// the reserved amount we need for the trade we send to our trade address
|
||||
tradingFeeTx.addOutput(reservedFundsForOffer, addressEntry.getAddress());
|
||||
|
||||
// we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to
|
||||
// wait for 1 confirmation)
|
||||
|
@ -154,13 +157,16 @@ public class TradeWalletService {
|
|||
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tradingFeeTx);
|
||||
sendRequest.shuffleOutputs = false;
|
||||
sendRequest.aesKey = aesKey;
|
||||
sendRequest.coinSelector = new AddressBasedCoinSelector(params, addressEntry);
|
||||
if (useSavingsWallet)
|
||||
sendRequest.coinSelector = new AddressBasedCoinSelector(params);
|
||||
else
|
||||
sendRequest.coinSelector = new AddressBasedCoinSelector(params, addressEntry);
|
||||
// We use a fixed fee
|
||||
sendRequest.feePerKb = Coin.ZERO;
|
||||
sendRequest.fee = FeePolicy.getFixedTxFeeForTrades();
|
||||
// We use always the same address for all transactions in a trade to keep things simple.
|
||||
// To be discussed if that introduce any privacy issues.
|
||||
sendRequest.changeAddress = addressEntry.getAddress();
|
||||
|
||||
// Change is optional in case of overpay or use of funds from savings wallet
|
||||
sendRequest.changeAddress = changeAddress;
|
||||
|
||||
checkNotNull(wallet, "Wallet must not be null");
|
||||
wallet.completeTx(sendRequest);
|
||||
|
@ -181,20 +187,20 @@ public class TradeWalletService {
|
|||
|
||||
|
||||
/**
|
||||
* The taker creates a dummy transaction to get the input(s) and optional change output for the amount and the addressEntry for that trade.
|
||||
* The taker creates a dummy transaction to get the input(s) and optional change output for the amount and the takersAddressEntry for that trade.
|
||||
* That will be used to send to the offerer for creating the deposit transaction.
|
||||
*
|
||||
* @param inputAmount Amount of takers input
|
||||
* @param addressEntry Address entry of taker
|
||||
* @param inputAmount Amount of takers input
|
||||
* @param takersAddressEntry Address entry of taker
|
||||
* @return A data container holding the inputs, the output value and address
|
||||
* @throws TransactionVerificationException
|
||||
* @throws WalletException
|
||||
*/
|
||||
public InputsAndChangeOutput takerCreatesDepositsTxInputs(Coin inputAmount, AddressEntry addressEntry) throws
|
||||
TransactionVerificationException, WalletException {
|
||||
public InputsAndChangeOutput takerCreatesDepositsTxInputs(Coin inputAmount, AddressEntry takersAddressEntry, Address takersChangeAddress) throws
|
||||
TransactionVerificationException, WalletException, AddressFormatException {
|
||||
log.trace("createTakerDepositTxInputs called");
|
||||
log.trace("inputAmount " + inputAmount.toFriendlyString());
|
||||
log.trace("addressEntry " + addressEntry.toString());
|
||||
log.trace("takersAddressEntry " + takersAddressEntry.toString());
|
||||
|
||||
// We add the mining fee 2 times to the deposit tx:
|
||||
// 1. Will be spent when publishing the deposit tx (paid by buyer)
|
||||
|
@ -224,7 +230,7 @@ public class TradeWalletService {
|
|||
// Find the needed inputs to pay the output, optionally add 1 change output.
|
||||
// Normally only 1 input and no change output is used, but we support multiple inputs and 1 change output.
|
||||
// Our spending transaction output is from the create offer fee payment.
|
||||
addAvailableInputsAndChangeOutputs(dummyTX, addressEntry);
|
||||
addAvailableInputsAndChangeOutputs(dummyTX, takersAddressEntry, takersChangeAddress);
|
||||
|
||||
// The completeTx() call signs the input, but we don't want to pass over signed tx inputs so we remove the signature
|
||||
removeSignatures(dummyTX);
|
||||
|
@ -261,17 +267,17 @@ public class TradeWalletService {
|
|||
/**
|
||||
* The offerer creates the deposit transaction using the takers input(s) and optional output and signs his input(s).
|
||||
*
|
||||
* @param offererIsBuyer The flag indicating if we are in the offerer as buyer role or the opposite.
|
||||
* @param contractHash The hash of the contract to be added to the OP_RETURN output.
|
||||
* @param offererInputAmount The input amount of the offerer.
|
||||
* @param msOutputAmount The output amount to our MS output.
|
||||
* @param takerRawTransactionInputs Raw data for the connected outputs for all inputs of the taker (normally 1 input)
|
||||
* @param takerChangeOutputValue Optional taker change output value
|
||||
* @param takerChangeAddressString Optional taker change address
|
||||
* @param offererAddressInfo The offerers address entry.
|
||||
* @param buyerPubKey The public key of the buyer.
|
||||
* @param sellerPubKey The public key of the seller.
|
||||
* @param arbitratorPubKey The public key of the arbitrator.
|
||||
* @param offererIsBuyer The flag indicating if we are in the offerer as buyer role or the opposite.
|
||||
* @param contractHash The hash of the contract to be added to the OP_RETURN output.
|
||||
* @param offererInputAmount The input amount of the offerer.
|
||||
* @param msOutputAmount The output amount to our MS output.
|
||||
* @param takerRawTransactionInputs Raw data for the connected outputs for all inputs of the taker (normally 1 input)
|
||||
* @param takerChangeOutputValue Optional taker change output value
|
||||
* @param takerChangeAddressString Optional taker change address
|
||||
* @param offererAddressEntry The offerers address entry.
|
||||
* @param buyerPubKey The public key of the buyer.
|
||||
* @param sellerPubKey The public key of the seller.
|
||||
* @param arbitratorPubKey The public key of the arbitrator.
|
||||
* @return A data container holding the serialized transaction and the offerer raw inputs
|
||||
* @throws SigningException
|
||||
* @throws TransactionVerificationException
|
||||
|
@ -284,7 +290,8 @@ public class TradeWalletService {
|
|||
List<RawTransactionInput> takerRawTransactionInputs,
|
||||
long takerChangeOutputValue,
|
||||
@Nullable String takerChangeAddressString,
|
||||
AddressEntry offererAddressInfo,
|
||||
AddressEntry offererAddressEntry,
|
||||
Address offererChangeAddress,
|
||||
byte[] buyerPubKey,
|
||||
byte[] sellerPubKey,
|
||||
byte[] arbitratorPubKey)
|
||||
|
@ -308,7 +315,7 @@ public class TradeWalletService {
|
|||
Coin dummyOutputAmount = offererInputAmount.subtract(FeePolicy.getFixedTxFeeForTrades());
|
||||
TransactionOutput dummyOutput = new TransactionOutput(params, dummyTx, dummyOutputAmount, new ECKey().toAddress(params));
|
||||
dummyTx.addOutput(dummyOutput);
|
||||
addAvailableInputsAndChangeOutputs(dummyTx, offererAddressInfo);
|
||||
addAvailableInputsAndChangeOutputs(dummyTx, offererAddressEntry, offererChangeAddress);
|
||||
// Normally we have only 1 input but we support multiple inputs if the user has paid in with several transactions.
|
||||
List<TransactionInput> offererInputs = dummyTx.getInputs();
|
||||
TransactionOutput offererOutput = null;
|
||||
|
@ -1035,7 +1042,7 @@ public class TradeWalletService {
|
|||
}
|
||||
}
|
||||
|
||||
private void addAvailableInputsAndChangeOutputs(Transaction transaction, AddressEntry addressEntry) throws WalletException {
|
||||
private void addAvailableInputsAndChangeOutputs(Transaction transaction, AddressEntry addressEntry, Address changeAddress) throws WalletException {
|
||||
try {
|
||||
// Lets let the framework do the work to find the right inputs
|
||||
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(transaction);
|
||||
|
@ -1047,7 +1054,7 @@ public class TradeWalletService {
|
|||
// we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to wait for 1 confirmation)
|
||||
sendRequest.coinSelector = new AddressBasedCoinSelector(params, addressEntry);
|
||||
// We use always the same address in a trade for all transactions
|
||||
sendRequest.changeAddress = addressEntry.getAddress();
|
||||
sendRequest.changeAddress = changeAddress;
|
||||
// With the usage of completeTx() we get all the work done with fee calculation, validation and coin selection.
|
||||
// We don't commit that tx to the wallet as it will be changed later and it's not signed yet.
|
||||
// So it will not change the wallet balance.
|
||||
|
|
|
@ -305,19 +305,13 @@ public class WalletService {
|
|||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AddressInfo
|
||||
// Trade AddressEntry
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public List<AddressEntry> getAddressEntryList() {
|
||||
return ImmutableList.copyOf(addressEntryList);
|
||||
}
|
||||
|
||||
public List<AddressEntry> getSavingsAddressEntryList() {
|
||||
return getAddressEntryList().stream()
|
||||
.filter(e -> e.getContext().equals(AddressEntry.Context.SAVINGS))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public AddressEntry getArbitratorAddressEntry() {
|
||||
return arbitratorAddressEntry;
|
||||
}
|
||||
|
@ -332,10 +326,6 @@ public class WalletService {
|
|||
return addressEntryList.getNewTradeAddressEntry(offerId);
|
||||
}
|
||||
|
||||
public AddressEntry getNewSavingsAddressEntry() {
|
||||
return addressEntryList.getNewSavingsAddressEntry();
|
||||
}
|
||||
|
||||
private Optional<AddressEntry> getAddressEntryByAddress(String address) {
|
||||
return getAddressEntryList().stream()
|
||||
.filter(e -> e.getAddressString() != null && e.getAddressString().equals(address))
|
||||
|
@ -343,6 +333,72 @@ public class WalletService {
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SavingsAddressEntry
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public AddressEntry getNewSavingsAddressEntry() {
|
||||
return addressEntryList.getNewSavingsAddressEntry();
|
||||
}
|
||||
|
||||
public List<AddressEntry> getSavingsAddressEntryList() {
|
||||
return getAddressEntryList().stream()
|
||||
.filter(e -> e.getContext().equals(AddressEntry.Context.SAVINGS))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public AddressEntry getUnusedSavingsAddressEntry() {
|
||||
List<AddressEntry> unusedSavingsAddressEntries = getUnusedSavingsAddressEntries();
|
||||
if (!unusedSavingsAddressEntries.isEmpty())
|
||||
return unusedSavingsAddressEntries.get(0);
|
||||
else
|
||||
return getNewSavingsAddressEntry();
|
||||
}
|
||||
|
||||
public List<AddressEntry> getUnusedSavingsAddressEntries() {
|
||||
return getSavingsAddressEntryList().stream()
|
||||
.filter(addressEntry -> getNumTxOutputsForAddress(addressEntry.getAddress()) == 0)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<AddressEntry> getUsedSavingsAddressEntries() {
|
||||
return getSavingsAddressEntryList().stream()
|
||||
.filter(addressEntry -> getNumTxOutputsForAddress(addressEntry.getAddress()) > 0)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<Address> getUsedSavingsAddresses() {
|
||||
return getSavingsAddressEntryList().stream()
|
||||
.filter(addressEntry -> getNumTxOutputsForAddress(addressEntry.getAddress()) > 0)
|
||||
.map(addressEntry -> addressEntry.getAddress())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<Transaction> getUsedSavingWalletTransactions() {
|
||||
List<Transaction> transactions = new ArrayList<>();
|
||||
List<TransactionOutput> transactionOutputs = new ArrayList<>();
|
||||
List<Address> usedSavingsAddresses = getUsedSavingsAddresses();
|
||||
log.debug("usedSavingsAddresses = " + usedSavingsAddresses);
|
||||
wallet.getTransactions(true).stream().forEach(transaction -> transactionOutputs.addAll(transaction.getOutputs()));
|
||||
for (TransactionOutput transactionOutput : transactionOutputs) {
|
||||
if (transactionOutput.getScriptPubKey().isSentToAddress() || transactionOutput.getScriptPubKey().isPayToScriptHash()) {
|
||||
Address addressOutput = transactionOutput.getScriptPubKey().getToAddress(params);
|
||||
|
||||
if (usedSavingsAddresses.contains(addressOutput) && transactionOutput.getParentTransaction() != null) {
|
||||
log.debug("transactionOutput.getParentTransaction() = " + transactionOutput.getParentTransaction().getHashAsString());
|
||||
transactions.add(transactionOutput.getParentTransaction());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return transactions;
|
||||
}
|
||||
|
||||
public void swapTradeToSavings(String offerId) {
|
||||
addressEntryList.swapTradeToSavings(offerId);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TransactionConfidence
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -448,6 +504,28 @@ public class WalletService {
|
|||
return balance;
|
||||
}
|
||||
|
||||
public Coin getSavingWalletBalance() {
|
||||
Coin balance = Coin.ZERO;
|
||||
for (AddressEntry addressEntry : getSavingsAddressEntryList()) {
|
||||
balance = balance.add(getBalanceForAddress(addressEntry.getAddress()));
|
||||
}
|
||||
return balance;
|
||||
}
|
||||
|
||||
public int getNumTxOutputsForAddress(Address address) {
|
||||
List<TransactionOutput> transactionOutputs = new ArrayList<>();
|
||||
wallet.getTransactions(true).stream().forEach(t -> transactionOutputs.addAll(t.getOutputs()));
|
||||
int outputs = 0;
|
||||
for (TransactionOutput transactionOutput : transactionOutputs) {
|
||||
if (transactionOutput.getScriptPubKey().isSentToAddress() || transactionOutput.getScriptPubKey().isPayToScriptHash()) {
|
||||
Address addressOutput = transactionOutput.getScriptPubKey().getToAddress(params);
|
||||
if (addressOutput.equals(address))
|
||||
outputs++;
|
||||
}
|
||||
}
|
||||
return outputs;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Withdrawal
|
||||
|
|
|
@ -115,7 +115,7 @@ public final class PaymentMethod implements Persistable, Comparable {
|
|||
this.maxTradePeriod = paymentMethod.getMaxTradePeriod();
|
||||
this.maxTradeLimitInBitcoin = paymentMethod.getMaxTradeLimitInBitcoin();
|
||||
} catch (Throwable t) {
|
||||
log.error("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ public final class BuyerAsOffererTrade extends BuyerTrade implements OffererTrad
|
|||
initStateProperties();
|
||||
initAmountProperty();
|
||||
} catch (Throwable t) {
|
||||
log.trace("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade {
|
|||
initStateProperties();
|
||||
initAmountProperty();
|
||||
} catch (Throwable t) {
|
||||
log.trace("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ public final class SellerAsOffererTrade extends SellerTrade implements OffererTr
|
|||
initStateProperties();
|
||||
initAmountProperty();
|
||||
} catch (Throwable t) {
|
||||
log.trace("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade
|
|||
initStateProperties();
|
||||
initAmountProperty();
|
||||
} catch (Throwable t) {
|
||||
log.trace("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ public final class TradableList<T extends Tradable> extends ArrayList<T> impleme
|
|||
try {
|
||||
in.defaultReadObject();
|
||||
} catch (Throwable t) {
|
||||
log.trace("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -209,7 +209,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
initAmountProperty();
|
||||
errorMessageProperty = new SimpleStringProperty(errorMessage);
|
||||
} catch (Throwable t) {
|
||||
log.trace("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,7 +220,8 @@ public abstract class Trade implements Tradable, Model {
|
|||
TradeManager tradeManager,
|
||||
OpenOfferManager openOfferManager,
|
||||
User user,
|
||||
KeyRing keyRing) {
|
||||
KeyRing keyRing,
|
||||
Coin fundsNeededForTrade) {
|
||||
Log.traceCall();
|
||||
processModel.onAllServicesInitialized(offer,
|
||||
tradeManager,
|
||||
|
@ -230,7 +231,8 @@ public abstract class Trade implements Tradable, Model {
|
|||
tradeWalletService,
|
||||
arbitratorManager,
|
||||
user,
|
||||
keyRing);
|
||||
keyRing,
|
||||
fundsNeededForTrade);
|
||||
|
||||
createProtocol();
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ public class TradeManager {
|
|||
else {*/
|
||||
trade.setStorage(tradableListStorage);
|
||||
trade.updateDepositTxFromWallet(tradeWalletService);
|
||||
initTrade(trade);
|
||||
initTrade(trade, trade.getProcessModel().getFundsNeededForTrade());
|
||||
|
||||
|
||||
// }
|
||||
|
@ -209,7 +209,7 @@ public class TradeManager {
|
|||
trade = new SellerAsOffererTrade(offer, tradableListStorage);
|
||||
|
||||
trade.setStorage(tradableListStorage);
|
||||
initTrade(trade);
|
||||
initTrade(trade, trade.getProcessModel().getFundsNeededForTrade());
|
||||
trades.add(trade);
|
||||
((OffererTrade) trade).handleTakeOfferRequest(message, peerNodeAddress);
|
||||
} else {
|
||||
|
@ -220,7 +220,7 @@ public class TradeManager {
|
|||
}
|
||||
}
|
||||
|
||||
private void initTrade(Trade trade) {
|
||||
private void initTrade(Trade trade, Coin fundsNeededForTrade) {
|
||||
trade.init(p2PService,
|
||||
walletService,
|
||||
tradeWalletService,
|
||||
|
@ -228,7 +228,8 @@ public class TradeManager {
|
|||
this,
|
||||
openOfferManager,
|
||||
user,
|
||||
keyRing);
|
||||
keyRing,
|
||||
fundsNeededForTrade);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -256,6 +257,7 @@ public class TradeManager {
|
|||
|
||||
// First we check if offer is still available then we create the trade with the protocol
|
||||
public void onTakeOffer(Coin amount,
|
||||
Coin fundsNeededForTrade,
|
||||
Offer offer,
|
||||
String paymentAccountId,
|
||||
TradeResultHandler tradeResultHandler) {
|
||||
|
@ -263,11 +265,12 @@ public class TradeManager {
|
|||
offer.checkOfferAvailability(model,
|
||||
() -> {
|
||||
if (offer.getState() == Offer.State.AVAILABLE)
|
||||
createTrade(amount, offer, paymentAccountId, model, tradeResultHandler);
|
||||
createTrade(amount, fundsNeededForTrade, offer, paymentAccountId, model, tradeResultHandler);
|
||||
});
|
||||
}
|
||||
|
||||
private void createTrade(Coin amount,
|
||||
Coin fundsNeededForTrade,
|
||||
Offer offer,
|
||||
String paymentAccountId,
|
||||
OfferAvailabilityModel model,
|
||||
|
@ -282,7 +285,7 @@ public class TradeManager {
|
|||
trade.setTakeOfferDateAsBlockHeight(tradeWalletService.getBestChainHeight());
|
||||
trade.setTakerPaymentAccountId(paymentAccountId);
|
||||
|
||||
initTrade(trade);
|
||||
initTrade(trade, fundsNeededForTrade);
|
||||
|
||||
trades.add(trade);
|
||||
((TakerTrade) trade).takeAvailableOffer();
|
||||
|
|
|
@ -178,7 +178,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
|||
// we don't need to fill it as the error message is only relevant locally, so we don't store it in the transmitted object
|
||||
errorMessageProperty = new SimpleStringProperty();
|
||||
} catch (Throwable t) {
|
||||
log.error("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ public final class OpenOffer implements Tradable {
|
|||
setState(State.AVAILABLE);
|
||||
|
||||
} catch (Throwable t) {
|
||||
log.error("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
public Date getDate() {
|
||||
|
|
|
@ -44,6 +44,7 @@ import io.bitsquare.trade.protocol.placeoffer.PlaceOfferModel;
|
|||
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
|
||||
import io.bitsquare.user.User;
|
||||
import javafx.collections.ObservableList;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -227,9 +228,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void placeOffer(Offer offer,
|
||||
TransactionResultHandler resultHandler) {
|
||||
PlaceOfferModel model = new PlaceOfferModel(offer, walletService, tradeWalletService, offerBookService, user);
|
||||
public void placeOffer(Offer offer, Coin reservedFundsForOffer, boolean useSavingsWallet, TransactionResultHandler resultHandler) {
|
||||
PlaceOfferModel model = new PlaceOfferModel(offer, reservedFundsForOffer, useSavingsWallet, walletService, tradeWalletService, offerBookService, user);
|
||||
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(
|
||||
model,
|
||||
transaction -> {
|
||||
|
@ -272,6 +272,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
openOffer.setState(OpenOffer.State.CANCELED);
|
||||
openOffers.remove(openOffer);
|
||||
closedTradableManager.add(openOffer);
|
||||
walletService.swapTradeToSavings(offer.getId());
|
||||
resultHandler.handleResult();
|
||||
},
|
||||
errorMessageHandler);
|
||||
|
|
|
@ -23,6 +23,7 @@ import io.bitsquare.common.taskrunner.Model;
|
|||
import io.bitsquare.trade.offer.Offer;
|
||||
import io.bitsquare.trade.offer.OfferBookService;
|
||||
import io.bitsquare.user.User;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -31,6 +32,8 @@ public class PlaceOfferModel implements Model {
|
|||
private static final Logger log = LoggerFactory.getLogger(PlaceOfferModel.class);
|
||||
|
||||
public final Offer offer;
|
||||
public final Coin reservedFundsForOffer;
|
||||
public final boolean useSavingsWallet;
|
||||
public final WalletService walletService;
|
||||
public final TradeWalletService tradeWalletService;
|
||||
public final OfferBookService offerBookService;
|
||||
|
@ -39,11 +42,15 @@ public class PlaceOfferModel implements Model {
|
|||
private Transaction transaction;
|
||||
|
||||
public PlaceOfferModel(Offer offer,
|
||||
Coin reservedFundsForOffer,
|
||||
boolean useSavingsWallet,
|
||||
WalletService walletService,
|
||||
TradeWalletService tradeWalletService,
|
||||
OfferBookService offerBookService,
|
||||
User user) {
|
||||
this.offer = offer;
|
||||
this.reservedFundsForOffer = reservedFundsForOffer;
|
||||
this.useSavingsWallet = useSavingsWallet;
|
||||
this.walletService = walletService;
|
||||
this.tradeWalletService = tradeWalletService;
|
||||
this.offerBookService = offerBookService;
|
||||
|
|
|
@ -18,13 +18,10 @@
|
|||
package io.bitsquare.trade.protocol.placeoffer.tasks;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import io.bitsquare.btc.AddressEntry;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.common.taskrunner.Task;
|
||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||
import io.bitsquare.trade.offer.Offer;
|
||||
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferModel;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -44,67 +41,59 @@ public class BroadcastCreateOfferFeeTx extends Task<PlaceOfferModel> {
|
|||
protected void run() {
|
||||
try {
|
||||
runInterceptHook();
|
||||
Coin totalsNeeded = FeePolicy.getSecurityDeposit().add(FeePolicy.getCreateOfferFee()).add(FeePolicy.getFixedTxFeeForTrades());
|
||||
AddressEntry addressEntry = model.walletService.getTradeAddressEntry(model.offer.getId());
|
||||
Coin balance = model.walletService.getBalanceForAddress(addressEntry.getAddress());
|
||||
if (balance.compareTo(totalsNeeded) >= 0) {
|
||||
model.tradeWalletService.broadcastTx(model.getTransaction(), new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction) {
|
||||
log.info("Broadcast of offer fee payment succeeded: transaction = " + transaction.toString());
|
||||
model.tradeWalletService.broadcastTx(model.getTransaction(), new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction) {
|
||||
log.info("Broadcast of offer fee payment succeeded: transaction = " + transaction.toString());
|
||||
|
||||
if (model.getTransaction().getHashAsString().equals(transaction.getHashAsString())) {
|
||||
model.offer.setState(Offer.State.OFFER_FEE_PAID);
|
||||
// No tx malleability happened after broadcast (still not in blockchain)
|
||||
complete();
|
||||
} else {
|
||||
log.warn("Tx malleability happened after broadcast. We publish the changed offer to the P2P network again.");
|
||||
// Tx malleability happened after broadcast. We first remove the malleable offer.
|
||||
// Then we publish the changed offer to the P2P network again after setting the new TxId.
|
||||
// Normally we use a delay for broadcasting to the peers, but at shut down we want to get it fast out
|
||||
model.offerBookService.removeOffer(model.offer,
|
||||
() -> {
|
||||
log.info("We store now the changed txID to the offer and add that again.");
|
||||
// We store now the changed txID to the offer and add that again.
|
||||
model.offer.setOfferFeePaymentTxID(transaction.getHashAsString());
|
||||
model.setTransaction(transaction);
|
||||
model.offerBookService.addOffer(model.offer,
|
||||
() -> complete(),
|
||||
errorMessage -> {
|
||||
log.error("addOffer failed");
|
||||
addOfferFailed = true;
|
||||
updateStateOnFault();
|
||||
model.offer.setErrorMessage("An error occurred when adding the offer to the P2P network.\n" +
|
||||
"Error message:\n"
|
||||
+ errorMessage);
|
||||
failed(errorMessage);
|
||||
});
|
||||
},
|
||||
errorMessage -> {
|
||||
log.error("removeOffer failed");
|
||||
removeOfferFailed = true;
|
||||
updateStateOnFault();
|
||||
model.offer.setErrorMessage("An error occurred when removing the offer from the P2P network.\n" +
|
||||
"Error message:\n"
|
||||
+ errorMessage);
|
||||
failed(errorMessage);
|
||||
});
|
||||
}
|
||||
if (model.getTransaction().getHashAsString().equals(transaction.getHashAsString())) {
|
||||
model.offer.setState(Offer.State.OFFER_FEE_PAID);
|
||||
// No tx malleability happened after broadcast (still not in blockchain)
|
||||
complete();
|
||||
} else {
|
||||
log.warn("Tx malleability happened after broadcast. We publish the changed offer to the P2P network again.");
|
||||
// Tx malleability happened after broadcast. We first remove the malleable offer.
|
||||
// Then we publish the changed offer to the P2P network again after setting the new TxId.
|
||||
// Normally we use a delay for broadcasting to the peers, but at shut down we want to get it fast out
|
||||
model.offerBookService.removeOffer(model.offer,
|
||||
() -> {
|
||||
log.info("We store now the changed txID to the offer and add that again.");
|
||||
// We store now the changed txID to the offer and add that again.
|
||||
model.offer.setOfferFeePaymentTxID(transaction.getHashAsString());
|
||||
model.setTransaction(transaction);
|
||||
model.offerBookService.addOffer(model.offer,
|
||||
() -> complete(),
|
||||
errorMessage -> {
|
||||
log.error("addOffer failed");
|
||||
addOfferFailed = true;
|
||||
updateStateOnFault();
|
||||
model.offer.setErrorMessage("An error occurred when adding the offer to the P2P network.\n" +
|
||||
"Error message:\n"
|
||||
+ errorMessage);
|
||||
failed(errorMessage);
|
||||
});
|
||||
},
|
||||
errorMessage -> {
|
||||
log.error("removeOffer failed");
|
||||
removeOfferFailed = true;
|
||||
updateStateOnFault();
|
||||
model.offer.setErrorMessage("An error occurred when removing the offer from the P2P network.\n" +
|
||||
"Error message:\n"
|
||||
+ errorMessage);
|
||||
failed(errorMessage);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
updateStateOnFault();
|
||||
model.offer.setErrorMessage("An error occurred.\n" +
|
||||
"Error message:\n"
|
||||
+ t.getMessage());
|
||||
failed(t);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
updateStateOnFault();
|
||||
model.offer.setErrorMessage("You don't have enough balance in your wallet for placing the offer.");
|
||||
}
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
updateStateOnFault();
|
||||
model.offer.setErrorMessage("An error occurred.\n" +
|
||||
"Error message:\n"
|
||||
+ t.getMessage());
|
||||
failed(t);
|
||||
}
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
model.offer.setErrorMessage("An error occurred.\n" +
|
||||
"Error message:\n"
|
||||
|
|
|
@ -28,6 +28,8 @@ import org.bitcoinj.core.Transaction;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class CreateOfferFeeTx extends Task<PlaceOfferModel> {
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateOfferFeeTx.class);
|
||||
|
||||
|
@ -43,8 +45,12 @@ public class CreateOfferFeeTx extends Task<PlaceOfferModel> {
|
|||
NodeAddress selectedArbitratorNodeAddress = ArbitrationSelectionRule.select(model.user.getAcceptedArbitratorAddresses(), model.offer);
|
||||
log.debug("selectedArbitratorAddress " + selectedArbitratorNodeAddress);
|
||||
Arbitrator selectedArbitrator = model.user.getAcceptedArbitratorByAddress(selectedArbitratorNodeAddress);
|
||||
checkNotNull(selectedArbitrator, "selectedArbitrator must not be null at CreateOfferFeeTx");
|
||||
Transaction transaction = model.tradeWalletService.createTradingFeeTx(
|
||||
model.walletService.getTradeAddressEntry(model.offer.getId()),
|
||||
model.walletService.getUnusedSavingsAddressEntry().getAddress(),
|
||||
model.reservedFundsForOffer,
|
||||
model.useSavingsWallet,
|
||||
FeePolicy.getCreateOfferFee(),
|
||||
selectedArbitrator.getBtcAddress());
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ public class BuyerAsOffererProtocol extends TradeProtocol implements BuyerProtoc
|
|||
VerifyTakerAccount.class,
|
||||
LoadTakeOfferFeeTx.class,
|
||||
CreateAndSignContract.class,
|
||||
CreateAndSignDepositTxAsBuyer.class,
|
||||
OffererCreatesAndSignsDepositTxAsBuyer.class,
|
||||
InitWaitPeriodForOpenDispute.class,
|
||||
SetupDepositBalanceListener.class,
|
||||
SendPublishDepositTxRequest.class
|
||||
|
|
|
@ -95,7 +95,7 @@ public class BuyerAsTakerProtocol extends TradeProtocol implements BuyerProtocol
|
|||
LoadCreateOfferFeeTx.class,
|
||||
CreateTakeOfferFeeTx.class,
|
||||
BroadcastTakeOfferFeeTx.class,
|
||||
CreateDepositTxInputsAsBuyer.class,
|
||||
TakerCreatesDepositTxInputsAsBuyer.class,
|
||||
SendPayDepositRequest.class
|
||||
);
|
||||
startTimeout();
|
||||
|
|
|
@ -36,6 +36,8 @@ import io.bitsquare.trade.offer.Offer;
|
|||
import io.bitsquare.trade.offer.OpenOfferManager;
|
||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||
import io.bitsquare.user.User;
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -64,6 +66,7 @@ public class ProcessModel implements Model, Serializable {
|
|||
transient private KeyRing keyRing;
|
||||
transient private P2PService p2PService;
|
||||
|
||||
|
||||
// Mutable
|
||||
public final TradingPeer tradingPeer;
|
||||
transient private TradeMessage tradeMessage;
|
||||
|
@ -80,6 +83,8 @@ public class ProcessModel implements Model, Serializable {
|
|||
@Nullable
|
||||
private String changeOutputAddress;
|
||||
private Transaction takeOfferFeeTx;
|
||||
public boolean useSavingsWallet;
|
||||
private Coin fundsNeededForTrade;
|
||||
|
||||
public ProcessModel() {
|
||||
tradingPeer = new TradingPeer();
|
||||
|
@ -89,7 +94,7 @@ public class ProcessModel implements Model, Serializable {
|
|||
try {
|
||||
in.defaultReadObject();
|
||||
} catch (Throwable t) {
|
||||
log.trace("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +106,8 @@ public class ProcessModel implements Model, Serializable {
|
|||
TradeWalletService tradeWalletService,
|
||||
ArbitratorManager arbitratorManager,
|
||||
User user,
|
||||
KeyRing keyRing) {
|
||||
KeyRing keyRing,
|
||||
Coin fundsNeededForTrade) {
|
||||
this.offer = offer;
|
||||
this.tradeManager = tradeManager;
|
||||
this.openOfferManager = openOfferManager;
|
||||
|
@ -111,6 +117,7 @@ public class ProcessModel implements Model, Serializable {
|
|||
this.user = user;
|
||||
this.keyRing = keyRing;
|
||||
this.p2PService = p2PService;
|
||||
this.fundsNeededForTrade = fundsNeededForTrade;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -154,6 +161,10 @@ public class ProcessModel implements Model, Serializable {
|
|||
return p2PService.getAddress();
|
||||
}
|
||||
|
||||
public Coin getFundsNeededForTrade() {
|
||||
return fundsNeededForTrade;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Getter/Setter for Mutable objects
|
||||
|
@ -183,6 +194,10 @@ public class ProcessModel implements Model, Serializable {
|
|||
return walletService.getTradeAddressEntry(offer.getId());
|
||||
}
|
||||
|
||||
public Address getUnusedSavingsAddress() {
|
||||
return walletService.getUnusedSavingsAddressEntry().getAddress();
|
||||
}
|
||||
|
||||
public byte[] getTradeWalletPubKey() {
|
||||
return getAddressEntry().getPubKey();
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ public class SellerAsOffererProtocol extends TradeProtocol implements SellerProt
|
|||
LoadTakeOfferFeeTx.class,
|
||||
InitWaitPeriodForOpenDispute.class,
|
||||
CreateAndSignContract.class,
|
||||
CreateAndSignDepositTxAsSeller.class,
|
||||
OffererCreatesAndSignsDepositTxAsSeller.class,
|
||||
SetupDepositBalanceListener.class,
|
||||
SendPublishDepositTxRequest.class
|
||||
);
|
||||
|
|
|
@ -103,7 +103,7 @@ public class SellerAsTakerProtocol extends TradeProtocol implements SellerProtoc
|
|||
LoadCreateOfferFeeTx.class,
|
||||
CreateTakeOfferFeeTx.class,
|
||||
BroadcastTakeOfferFeeTx.class,
|
||||
CreateDepositTxInputsAsSeller.class,
|
||||
TakerCreatesDepositTxInputsAsSeller.class,
|
||||
SendPayDepositRequest.class
|
||||
);
|
||||
startTimeout();
|
||||
|
|
|
@ -64,7 +64,7 @@ public final class TradingPeer implements Persistable {
|
|||
try {
|
||||
in.defaultReadObject();
|
||||
} catch (Throwable t) {
|
||||
log.trace("Cannot be deserialized." + t.getMessage());
|
||||
log.warn("Cannot be deserialized." + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,10 +29,10 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class CreateAndSignDepositTxAsBuyer extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateAndSignDepositTxAsBuyer.class);
|
||||
public class OffererCreatesAndSignsDepositTxAsBuyer extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(OffererCreatesAndSignsDepositTxAsBuyer.class);
|
||||
|
||||
public CreateAndSignDepositTxAsBuyer(TaskRunner taskHandler, Trade trade) {
|
||||
public OffererCreatesAndSignsDepositTxAsBuyer(TaskRunner taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,7 @@ public class CreateAndSignDepositTxAsBuyer extends TradeTask {
|
|||
processModel.tradingPeer.getChangeOutputValue(),
|
||||
processModel.tradingPeer.getChangeOutputAddress(),
|
||||
processModel.getAddressEntry(),
|
||||
processModel.getUnusedSavingsAddress(),
|
||||
processModel.getTradeWalletPubKey(),
|
||||
processModel.tradingPeer.getTradeWalletPubKey(),
|
||||
processModel.getArbitratorPubKey(trade.getArbitratorNodeAddress()));
|
|
@ -26,10 +26,10 @@ import org.bitcoinj.core.Coin;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class CreateDepositTxInputsAsBuyer extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateDepositTxInputsAsBuyer.class);
|
||||
public class TakerCreatesDepositTxInputsAsBuyer extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(TakerCreatesDepositTxInputsAsBuyer.class);
|
||||
|
||||
public CreateDepositTxInputsAsBuyer(TaskRunner taskHandler, Trade trade) {
|
||||
public TakerCreatesDepositTxInputsAsBuyer(TaskRunner taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,9 @@ public class CreateDepositTxInputsAsBuyer extends TradeTask {
|
|||
try {
|
||||
runInterceptHook();
|
||||
Coin takerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades());
|
||||
InputsAndChangeOutput result = processModel.getTradeWalletService().takerCreatesDepositsTxInputs(takerInputAmount, processModel.getAddressEntry());
|
||||
InputsAndChangeOutput result = processModel.getTradeWalletService()
|
||||
.takerCreatesDepositsTxInputs(takerInputAmount, processModel.getAddressEntry(),
|
||||
processModel.getUnusedSavingsAddress());
|
||||
processModel.setRawTransactionInputs(result.rawTransactionInputs);
|
||||
processModel.setChangeOutputValue(result.changeOutputValue);
|
||||
processModel.setChangeOutputAddress(result.changeOutputAddress);
|
|
@ -29,10 +29,10 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class CreateAndSignDepositTxAsSeller extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateAndSignDepositTxAsSeller.class);
|
||||
public class OffererCreatesAndSignsDepositTxAsSeller extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(OffererCreatesAndSignsDepositTxAsSeller.class);
|
||||
|
||||
public CreateAndSignDepositTxAsSeller(TaskRunner taskHandler, Trade trade) {
|
||||
public OffererCreatesAndSignsDepositTxAsSeller(TaskRunner taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,7 @@ public class CreateAndSignDepositTxAsSeller extends TradeTask {
|
|||
processModel.tradingPeer.getChangeOutputValue(),
|
||||
processModel.tradingPeer.getChangeOutputAddress(),
|
||||
processModel.getAddressEntry(),
|
||||
processModel.getUnusedSavingsAddress(),
|
||||
processModel.tradingPeer.getTradeWalletPubKey(),
|
||||
processModel.getTradeWalletPubKey(),
|
||||
processModel.getArbitratorPubKey(trade.getArbitratorNodeAddress()));
|
|
@ -26,10 +26,10 @@ import org.bitcoinj.core.Coin;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class CreateDepositTxInputsAsSeller extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateDepositTxInputsAsSeller.class);
|
||||
public class TakerCreatesDepositTxInputsAsSeller extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(TakerCreatesDepositTxInputsAsSeller.class);
|
||||
|
||||
public CreateDepositTxInputsAsSeller(TaskRunner taskHandler, Trade trade) {
|
||||
public TakerCreatesDepositTxInputsAsSeller(TaskRunner taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
}
|
||||
|
||||
|
@ -40,8 +40,10 @@ public class CreateDepositTxInputsAsSeller extends TradeTask {
|
|||
if (trade.getTradeAmount() != null) {
|
||||
Coin takerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades()).add(trade.getTradeAmount());
|
||||
|
||||
InputsAndChangeOutput result = processModel.getTradeWalletService().takerCreatesDepositsTxInputs(takerInputAmount, processModel
|
||||
.getAddressEntry());
|
||||
InputsAndChangeOutput result = processModel.getTradeWalletService()
|
||||
.takerCreatesDepositsTxInputs(takerInputAmount,
|
||||
processModel.getAddressEntry(),
|
||||
processModel.getUnusedSavingsAddress());
|
||||
processModel.setRawTransactionInputs(result.rawTransactionInputs);
|
||||
processModel.setChangeOutputValue(result.changeOutputValue);
|
||||
processModel.setChangeOutputAddress(result.changeOutputAddress);
|
|
@ -29,6 +29,8 @@ import org.bitcoinj.core.Transaction;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class CreateTakeOfferFeeTx extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateTakeOfferFeeTx.class);
|
||||
|
||||
|
@ -45,8 +47,12 @@ public class CreateTakeOfferFeeTx extends TradeTask {
|
|||
NodeAddress selectedArbitratorNodeAddress = ArbitrationSelectionRule.select(user.getAcceptedArbitratorAddresses(), processModel.getOffer());
|
||||
log.debug("selectedArbitratorAddress " + selectedArbitratorNodeAddress);
|
||||
Arbitrator selectedArbitrator = user.getAcceptedArbitratorByAddress(selectedArbitratorNodeAddress);
|
||||
checkNotNull(selectedArbitrator, "selectedArbitrator must not be null at CreateTakeOfferFeeTx");
|
||||
Transaction createTakeOfferFeeTx = processModel.getTradeWalletService().createTradingFeeTx(
|
||||
processModel.getAddressEntry(),
|
||||
processModel.getUnusedSavingsAddress(),
|
||||
processModel.getFundsNeededForTrade(),
|
||||
processModel.useSavingsWallet,
|
||||
FeePolicy.getTakeOfferFee(),
|
||||
selectedArbitrator.getBtcAddress());
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue