mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-07-26 16:35:18 -04:00
set buyer and seller payout tx fee and amount, fix csv export #720
This commit is contained in:
parent
846a8634e5
commit
8800d9ea46
18 changed files with 374 additions and 247 deletions
|
@ -69,7 +69,6 @@ import java.math.BigInteger;
|
|||
import java.security.KeyPair;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
@ -729,23 +728,21 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
dispute.addAndPersistChatMessage(chatMessage);
|
||||
}
|
||||
|
||||
// create dispute payout tx if not published
|
||||
// create dispute payout tx once per trader if we have their updated multisig hex
|
||||
TradePeer receiver = trade.getTradePeer(dispute.getTraderPubKeyRing());
|
||||
if (!trade.isPayoutPublished() && receiver.getUpdatedMultisigHex() != null) {
|
||||
trade.getProcessModel().setUnsignedPayoutTx(createDisputePayoutTx(trade, dispute.getContract(), disputeResult, false)); // can be null if we don't have receiver's multisig hex
|
||||
if (!trade.isPayoutPublished() && receiver.getUpdatedMultisigHex() != null && receiver.getUnsignedPayoutTxHex() == null) {
|
||||
createDisputePayoutTx(trade, dispute.getContract(), disputeResult, true);
|
||||
}
|
||||
|
||||
// create dispute closed message
|
||||
MoneroTxWallet unsignedPayoutTx = receiver.getUpdatedMultisigHex() == null ? null : trade.getProcessModel().getUnsignedPayoutTx();
|
||||
String unsignedPayoutTxHex = unsignedPayoutTx == null ? null : unsignedPayoutTx.getTxSet().getMultisigTxHex();
|
||||
TradePeer receiverPeer = receiver == trade.getBuyer() ? trade.getSeller() : trade.getBuyer();
|
||||
boolean deferPublishPayout = !exists && unsignedPayoutTxHex != null && receiverPeer.getUpdatedMultisigHex() != null && trade.getDisputeState().ordinal() >= Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG.ordinal();
|
||||
boolean deferPublishPayout = !exists && receiver.getUnsignedPayoutTxHex() != null && receiverPeer.getUpdatedMultisigHex() != null && trade.getDisputeState().ordinal() >= Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG.ordinal();
|
||||
DisputeClosedMessage disputeClosedMessage = new DisputeClosedMessage(disputeResult,
|
||||
p2PService.getAddress(),
|
||||
UUID.randomUUID().toString(),
|
||||
getSupportType(),
|
||||
trade.getSelf().getUpdatedMultisigHex(),
|
||||
unsignedPayoutTxHex, // include dispute payout tx if arbitrator has their updated multisig info
|
||||
receiver.getUnsignedPayoutTxHex(), // include dispute payout tx if arbitrator has their updated multisig info
|
||||
deferPublishPayout); // instruct trader to defer publishing payout tx because peer is expected to publish imminently
|
||||
|
||||
// send dispute closed message
|
||||
|
@ -812,12 +809,6 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
// save state
|
||||
if (unsignedPayoutTx != null) {
|
||||
trade.setPayoutTx(unsignedPayoutTx);
|
||||
trade.setPayoutTxHex(unsignedPayoutTx.getTxSet().getMultisigTxHex());
|
||||
}
|
||||
trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG);
|
||||
requestPersistence();
|
||||
} catch (Exception e) {
|
||||
|
@ -829,7 +820,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
// Utils
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public MoneroTxWallet createDisputePayoutTx(Trade trade, Contract contract, DisputeResult disputeResult, boolean skipMultisigImport) {
|
||||
public MoneroTxWallet createDisputePayoutTx(Trade trade, Contract contract, DisputeResult disputeResult, boolean updateState) {
|
||||
|
||||
// import multisig hex
|
||||
trade.importMultisigHex();
|
||||
|
@ -848,42 +839,34 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
// trade wallet must be synced
|
||||
if (trade.getWallet().isMultisigImportNeeded()) throw new RuntimeException("Arbitrator's wallet needs updated multisig hex to create payout tx which means a trader must have already broadcast the payout tx for trade " + trade.getId());
|
||||
|
||||
// collect winner and loser payout address and amounts
|
||||
String winnerPayoutAddress = disputeResult.getWinner() == Winner.BUYER ?
|
||||
(contract.isBuyerMakerAndSellerTaker() ? contract.getMakerPayoutAddressString() : contract.getTakerPayoutAddressString()) :
|
||||
(contract.isBuyerMakerAndSellerTaker() ? contract.getTakerPayoutAddressString() : contract.getMakerPayoutAddressString());
|
||||
String loserPayoutAddress = winnerPayoutAddress.equals(contract.getMakerPayoutAddressString()) ? contract.getTakerPayoutAddressString() : contract.getMakerPayoutAddressString();
|
||||
BigInteger winnerPayoutAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getBuyerPayoutAmount() : disputeResult.getSellerPayoutAmount();
|
||||
BigInteger loserPayoutAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmount() : disputeResult.getBuyerPayoutAmount();
|
||||
|
||||
// check sufficient balance
|
||||
if (winnerPayoutAmount.compareTo(BigInteger.ZERO) < 0) throw new RuntimeException("Winner payout cannot be negative");
|
||||
if (loserPayoutAmount.compareTo(BigInteger.ZERO) < 0) throw new RuntimeException("Loser payout cannot be negative");
|
||||
if (winnerPayoutAmount.add(loserPayoutAmount).compareTo(trade.getWallet().getUnlockedBalance()) > 0) {
|
||||
throw new RuntimeException("The payout amounts are more than the wallet's unlocked balance, unlocked balance=" + trade.getWallet().getUnlockedBalance() + " vs " + winnerPayoutAmount + " + " + loserPayoutAmount + " = " + (winnerPayoutAmount.add(loserPayoutAmount)));
|
||||
// check amounts
|
||||
if (disputeResult.getBuyerPayoutAmountBeforeCost().compareTo(BigInteger.ZERO) < 0) throw new RuntimeException("Buyer payout cannot be negative");
|
||||
if (disputeResult.getSellerPayoutAmountBeforeCost().compareTo(BigInteger.ZERO) < 0) throw new RuntimeException("Seller payout cannot be negative");
|
||||
if (disputeResult.getBuyerPayoutAmountBeforeCost().add(disputeResult.getSellerPayoutAmountBeforeCost()).compareTo(trade.getWallet().getUnlockedBalance()) > 0) {
|
||||
throw new RuntimeException("The payout amounts are more than the wallet's unlocked balance, unlocked balance=" + trade.getWallet().getUnlockedBalance() + " vs " + disputeResult.getBuyerPayoutAmountBeforeCost() + " + " + disputeResult.getSellerPayoutAmountBeforeCost() + " = " + (disputeResult.getBuyerPayoutAmountBeforeCost().add(disputeResult.getSellerPayoutAmountBeforeCost())));
|
||||
}
|
||||
|
||||
// add any loss of precision to winner payout
|
||||
winnerPayoutAmount = winnerPayoutAmount.add(trade.getWallet().getUnlockedBalance().subtract(winnerPayoutAmount.add(loserPayoutAmount)));
|
||||
|
||||
// create dispute payout tx config
|
||||
MoneroTxConfig txConfig = new MoneroTxConfig().setAccountIndex(0);
|
||||
String buyerPayoutAddress = contract.isBuyerMakerAndSellerTaker() ? contract.getMakerPayoutAddressString() : contract.getTakerPayoutAddressString();
|
||||
String sellerPayoutAddress = contract.isBuyerMakerAndSellerTaker() ? contract.getTakerPayoutAddressString() : contract.getMakerPayoutAddressString();
|
||||
txConfig.setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY);
|
||||
if (winnerPayoutAmount.compareTo(BigInteger.ZERO) > 0) txConfig.addDestination(winnerPayoutAddress, winnerPayoutAmount);
|
||||
if (loserPayoutAmount.compareTo(BigInteger.ZERO) > 0) txConfig.addDestination(loserPayoutAddress, loserPayoutAmount);
|
||||
if (disputeResult.getBuyerPayoutAmountBeforeCost().compareTo(BigInteger.ZERO) > 0) txConfig.addDestination(buyerPayoutAddress, disputeResult.getBuyerPayoutAmountBeforeCost());
|
||||
if (disputeResult.getSellerPayoutAmountBeforeCost().compareTo(BigInteger.ZERO) > 0) txConfig.addDestination(sellerPayoutAddress, disputeResult.getSellerPayoutAmountBeforeCost());
|
||||
|
||||
// configure who pays mining fee
|
||||
BigInteger loserPayoutAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmountBeforeCost() : disputeResult.getBuyerPayoutAmountBeforeCost();
|
||||
if (loserPayoutAmount.equals(BigInteger.ZERO)) txConfig.setSubtractFeeFrom(0); // winner pays fee if loser gets 0
|
||||
else {
|
||||
switch (disputeResult.getSubtractFeeFrom()) {
|
||||
case BUYER_AND_SELLER:
|
||||
txConfig.setSubtractFeeFrom(Arrays.asList(0, 1));
|
||||
txConfig.setSubtractFeeFrom(0, 1);
|
||||
break;
|
||||
case BUYER_ONLY:
|
||||
txConfig.setSubtractFeeFrom(disputeResult.getWinner() == Winner.BUYER ? 0 : 1);
|
||||
txConfig.setSubtractFeeFrom(0);
|
||||
break;
|
||||
case SELLER_ONLY:
|
||||
txConfig.setSubtractFeeFrom(disputeResult.getWinner() == Winner.SELLER ? 0 : 1);
|
||||
txConfig.setSubtractFeeFrom(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -897,8 +880,14 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
throw new RuntimeException("Loser payout is too small to cover the mining fee");
|
||||
}
|
||||
|
||||
// save updated multisig hex
|
||||
trade.getSelf().setUpdatedMultisigHex(trade.getWallet().exportMultisigHex());
|
||||
// update trade state
|
||||
if (updateState) {
|
||||
trade.getProcessModel().setUnsignedPayoutTx(payoutTx);
|
||||
trade.setPayoutTx(payoutTx);
|
||||
trade.setPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex());
|
||||
if (trade.getBuyer().getUpdatedMultisigHex() != null && trade.getBuyer().getUnsignedPayoutTxHex() == null) trade.getBuyer().setUnsignedPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex());
|
||||
if (trade.getSeller().getUpdatedMultisigHex() != null && trade.getSeller().getUnsignedPayoutTxHex() == null) trade.getSeller().setUnsignedPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex());
|
||||
}
|
||||
return payoutTx;
|
||||
} catch (Exception e) {
|
||||
trade.syncAndPollWallet();
|
||||
|
|
|
@ -86,8 +86,8 @@ public final class DisputeResult implements NetworkPayload {
|
|||
@Setter
|
||||
@Nullable
|
||||
private byte[] arbitratorSignature;
|
||||
private long buyerPayoutAmount;
|
||||
private long sellerPayoutAmount;
|
||||
private long buyerPayoutAmountBeforeCost;
|
||||
private long sellerPayoutAmountBeforeCost;
|
||||
@Setter
|
||||
@Nullable
|
||||
private byte[] arbitratorPubKey;
|
||||
|
@ -109,8 +109,8 @@ public final class DisputeResult implements NetworkPayload {
|
|||
String summaryNotes,
|
||||
@Nullable ChatMessage chatMessage,
|
||||
@Nullable byte[] arbitratorSignature,
|
||||
long buyerPayoutAmount,
|
||||
long sellerPayoutAmount,
|
||||
long buyerPayoutAmountBeforeCost,
|
||||
long sellerPayoutAmountBeforeCost,
|
||||
@Nullable byte[] arbitratorPubKey,
|
||||
long closeDate) {
|
||||
this.tradeId = tradeId;
|
||||
|
@ -124,8 +124,8 @@ public final class DisputeResult implements NetworkPayload {
|
|||
this.summaryNotesProperty.set(summaryNotes);
|
||||
this.chatMessage = chatMessage;
|
||||
this.arbitratorSignature = arbitratorSignature;
|
||||
this.buyerPayoutAmount = buyerPayoutAmount;
|
||||
this.sellerPayoutAmount = sellerPayoutAmount;
|
||||
this.buyerPayoutAmountBeforeCost = buyerPayoutAmountBeforeCost;
|
||||
this.sellerPayoutAmountBeforeCost = sellerPayoutAmountBeforeCost;
|
||||
this.arbitratorPubKey = arbitratorPubKey;
|
||||
this.closeDate = closeDate;
|
||||
}
|
||||
|
@ -147,8 +147,8 @@ public final class DisputeResult implements NetworkPayload {
|
|||
proto.getSummaryNotes(),
|
||||
proto.getChatMessage() == null ? null : ChatMessage.fromPayloadProto(proto.getChatMessage()),
|
||||
proto.getArbitratorSignature().toByteArray(),
|
||||
proto.getBuyerPayoutAmount(),
|
||||
proto.getSellerPayoutAmount(),
|
||||
proto.getBuyerPayoutAmountBeforeCost(),
|
||||
proto.getSellerPayoutAmountBeforeCost(),
|
||||
proto.getArbitratorPubKey().toByteArray(),
|
||||
proto.getCloseDate());
|
||||
}
|
||||
|
@ -163,8 +163,8 @@ public final class DisputeResult implements NetworkPayload {
|
|||
.setIdVerification(idVerificationProperty.get())
|
||||
.setScreenCast(screenCastProperty.get())
|
||||
.setSummaryNotes(summaryNotesProperty.get())
|
||||
.setBuyerPayoutAmount(buyerPayoutAmount)
|
||||
.setSellerPayoutAmount(sellerPayoutAmount)
|
||||
.setBuyerPayoutAmountBeforeCost(buyerPayoutAmountBeforeCost)
|
||||
.setSellerPayoutAmountBeforeCost(sellerPayoutAmountBeforeCost)
|
||||
.setCloseDate(closeDate);
|
||||
|
||||
Optional.ofNullable(arbitratorSignature).ifPresent(arbitratorSignature -> builder.setArbitratorSignature(ByteString.copyFrom(arbitratorSignature)));
|
||||
|
@ -213,22 +213,22 @@ public final class DisputeResult implements NetworkPayload {
|
|||
return summaryNotesProperty;
|
||||
}
|
||||
|
||||
public void setBuyerPayoutAmount(BigInteger buyerPayoutAmount) {
|
||||
if (buyerPayoutAmount.compareTo(BigInteger.ZERO) < 0) throw new IllegalArgumentException("buyerPayoutAmount cannot be negative");
|
||||
this.buyerPayoutAmount = buyerPayoutAmount.longValueExact();
|
||||
public void setBuyerPayoutAmountBeforeCost(BigInteger buyerPayoutAmountBeforeCost) {
|
||||
if (buyerPayoutAmountBeforeCost.compareTo(BigInteger.ZERO) < 0) throw new IllegalArgumentException("buyerPayoutAmountBeforeCost cannot be negative");
|
||||
this.buyerPayoutAmountBeforeCost = buyerPayoutAmountBeforeCost.longValueExact();
|
||||
}
|
||||
|
||||
public BigInteger getBuyerPayoutAmount() {
|
||||
return BigInteger.valueOf(buyerPayoutAmount);
|
||||
public BigInteger getBuyerPayoutAmountBeforeCost() {
|
||||
return BigInteger.valueOf(buyerPayoutAmountBeforeCost);
|
||||
}
|
||||
|
||||
public void setSellerPayoutAmount(BigInteger sellerPayoutAmount) {
|
||||
if (sellerPayoutAmount.compareTo(BigInteger.ZERO) < 0) throw new IllegalArgumentException("sellerPayoutAmount cannot be negative");
|
||||
this.sellerPayoutAmount = sellerPayoutAmount.longValueExact();
|
||||
public void setSellerPayoutAmountBeforeCost(BigInteger sellerPayoutAmountBeforeCost) {
|
||||
if (sellerPayoutAmountBeforeCost.compareTo(BigInteger.ZERO) < 0) throw new IllegalArgumentException("sellerPayoutAmountBeforeCost cannot be negative");
|
||||
this.sellerPayoutAmountBeforeCost = sellerPayoutAmountBeforeCost.longValueExact();
|
||||
}
|
||||
|
||||
public BigInteger getSellerPayoutAmount() {
|
||||
return BigInteger.valueOf(sellerPayoutAmount);
|
||||
public BigInteger getSellerPayoutAmountBeforeCost() {
|
||||
return BigInteger.valueOf(sellerPayoutAmountBeforeCost);
|
||||
}
|
||||
|
||||
public void setCloseDate(Date closeDate) {
|
||||
|
@ -253,8 +253,8 @@ public final class DisputeResult implements NetworkPayload {
|
|||
",\n summaryNotesProperty=" + summaryNotesProperty +
|
||||
",\n chatMessage=" + chatMessage +
|
||||
",\n arbitratorSignature=" + Utilities.bytesAsHexString(arbitratorSignature) +
|
||||
",\n buyerPayoutAmount=" + buyerPayoutAmount +
|
||||
",\n sellerPayoutAmount=" + sellerPayoutAmount +
|
||||
",\n buyerPayoutAmountBeforeCost=" + buyerPayoutAmountBeforeCost +
|
||||
",\n sellerPayoutAmountBeforeCost=" + sellerPayoutAmountBeforeCost +
|
||||
",\n arbitratorPubKey=" + Utilities.bytesAsHexString(arbitratorPubKey) +
|
||||
",\n closeDate=" + closeDate +
|
||||
"\n}";
|
||||
|
|
|
@ -380,42 +380,22 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
if (!arbitratorSignedPayoutTx.getOutputSum().equals(destinationSum.add(arbitratorSignedPayoutTx.getChangeAmount()))) throw new RuntimeException("Sum of outputs != destination amounts + change amount");
|
||||
|
||||
// get actual payout amounts
|
||||
BigInteger actualWinnerAmount = disputeResult.getWinner() == Winner.BUYER ? buyerPayoutDestination.getAmount() : sellerPayoutDestination.getAmount();
|
||||
BigInteger actualLoserAmount = numDestinations == 1 ? BigInteger.ZERO : disputeResult.getWinner() == Winner.BUYER ? sellerPayoutDestination.getAmount() : buyerPayoutDestination.getAmount();
|
||||
BigInteger actualBuyerAmount = buyerPayoutDestination == null ? BigInteger.ZERO : buyerPayoutDestination.getAmount();
|
||||
BigInteger actualSellerAmount = sellerPayoutDestination == null ? BigInteger.ZERO : sellerPayoutDestination.getAmount();
|
||||
|
||||
// verify payouts sum to unlocked balance within loss of precision due to conversion to centineros
|
||||
BigInteger txCost = arbitratorSignedPayoutTx.getFee().add(arbitratorSignedPayoutTx.getChangeAmount()); // fee + lost dust change
|
||||
if (trade.getWallet().getUnlockedBalance().subtract(actualWinnerAmount.add(actualLoserAmount).add(txCost)).compareTo(BigInteger.valueOf(0)) > 0) {
|
||||
throw new RuntimeException("The dispute payout amounts do not sum to the wallet's unlocked balance while verifying the dispute payout tx, unlocked balance=" + trade.getWallet().getUnlockedBalance() + " vs sum payout amount=" + actualWinnerAmount.add(actualLoserAmount) + ", winner payout=" + actualWinnerAmount + ", loser payout=" + actualLoserAmount);
|
||||
BigInteger txCost = arbitratorSignedPayoutTx.getFee().add(arbitratorSignedPayoutTx.getChangeAmount()); // cost = fee + lost dust change
|
||||
if (!arbitratorSignedPayoutTx.getChangeAmount().equals(BigInteger.ZERO)) log.warn("Dust left in multisig wallet for {} {}: {}", getClass().getSimpleName(), trade.getId(), arbitratorSignedPayoutTx.getChangeAmount());
|
||||
if (trade.getWallet().getUnlockedBalance().subtract(actualBuyerAmount.add(actualSellerAmount).add(txCost)).compareTo(BigInteger.valueOf(0)) > 0) {
|
||||
throw new RuntimeException("The dispute payout amounts do not sum to the wallet's unlocked balance while verifying the dispute payout tx, unlocked balance=" + trade.getWallet().getUnlockedBalance() + " vs sum payout amount=" + actualBuyerAmount.add(actualSellerAmount) + ", buyer payout=" + actualBuyerAmount + ", seller payout=" + actualSellerAmount);
|
||||
}
|
||||
|
||||
// get expected payout amounts
|
||||
BigInteger expectedWinnerAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getBuyerPayoutAmount() : disputeResult.getSellerPayoutAmount();
|
||||
BigInteger expectedLoserAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmount() : disputeResult.getBuyerPayoutAmount();
|
||||
|
||||
// subtract mining fee from expected payouts
|
||||
if (expectedLoserAmount.equals(BigInteger.ZERO)) expectedWinnerAmount = expectedWinnerAmount.subtract(txCost); // winner pays fee if loser gets 0
|
||||
else {
|
||||
switch (disputeResult.getSubtractFeeFrom()) {
|
||||
case BUYER_AND_SELLER:
|
||||
BigInteger txCostSplit = txCost.divide(BigInteger.valueOf(2));
|
||||
expectedWinnerAmount = expectedWinnerAmount.subtract(txCostSplit);
|
||||
expectedLoserAmount = expectedLoserAmount.subtract(txCostSplit);
|
||||
break;
|
||||
case BUYER_ONLY:
|
||||
expectedWinnerAmount = expectedWinnerAmount.subtract(disputeResult.getWinner() == Winner.BUYER ? txCost : BigInteger.ZERO);
|
||||
expectedLoserAmount = expectedLoserAmount.subtract(disputeResult.getWinner() == Winner.BUYER ? BigInteger.ZERO : txCost);
|
||||
break;
|
||||
case SELLER_ONLY:
|
||||
expectedWinnerAmount = expectedWinnerAmount.subtract(disputeResult.getWinner() == Winner.BUYER ? BigInteger.ZERO : txCost);
|
||||
expectedLoserAmount = expectedLoserAmount.subtract(disputeResult.getWinner() == Winner.BUYER ? txCost : BigInteger.ZERO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// verify winner and loser payout amounts
|
||||
if (!expectedWinnerAmount.equals(actualWinnerAmount)) throw new RuntimeException("Unexpected winner payout: " + expectedWinnerAmount + " vs " + actualWinnerAmount);
|
||||
if (!expectedLoserAmount.equals(actualLoserAmount)) throw new RuntimeException("Unexpected loser payout: " + expectedLoserAmount + " vs " + actualLoserAmount);
|
||||
// verify payout amounts
|
||||
BigInteger[] buyerSellerPayoutTxCost = getBuyerSellerPayoutTxCost(disputeResult, txCost);
|
||||
BigInteger expectedBuyerAmount = disputeResult.getBuyerPayoutAmountBeforeCost().subtract(buyerSellerPayoutTxCost[0]);
|
||||
BigInteger expectedSellerAmount = disputeResult.getSellerPayoutAmountBeforeCost().subtract(buyerSellerPayoutTxCost[1]);
|
||||
if (!expectedBuyerAmount.equals(actualBuyerAmount)) throw new RuntimeException("Unexpected buyer payout: " + expectedBuyerAmount + " vs " + actualBuyerAmount);
|
||||
if (!expectedSellerAmount.equals(actualSellerAmount)) throw new RuntimeException("Unexpected seller payout: " + expectedSellerAmount + " vs " + actualSellerAmount);
|
||||
|
||||
// check wallet's daemon connection
|
||||
trade.checkDaemonConnection();
|
||||
|
@ -431,7 +411,8 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
boolean signed = trade.getPayoutTxHex() != null && !nonSignedDisputePayoutTxHexes.contains(trade.getPayoutTxHex());
|
||||
|
||||
// sign arbitrator-signed payout tx
|
||||
if (!signed) {
|
||||
if (signed) disputeTxSet.setMultisigTxHex(trade.getPayoutTxHex());
|
||||
else {
|
||||
MoneroMultisigSignResult result = multisigWallet.signMultisigTxHex(unsignedPayoutTxHex);
|
||||
if (result.getSignedMultisigTxHex() == null) throw new RuntimeException("Error signing arbitrator-signed payout tx");
|
||||
String signedMultisigTxHex = result.getSignedMultisigTxHex();
|
||||
|
@ -443,8 +424,9 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
// TODO (monero-project): creating tx will require exchanging updated multisig hex if message needs reprocessed. provide weight with describe_transfer so fee can be estimated?
|
||||
MoneroTxWallet feeEstimateTx = null;
|
||||
try {
|
||||
feeEstimateTx = createDisputePayoutTx(trade, dispute.getContract(), disputeResult, true);
|
||||
feeEstimateTx = createDisputePayoutTx(trade, dispute.getContract(), disputeResult, false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.warn("Could not recreate dispute payout tx to verify fee: " + e.getMessage());
|
||||
}
|
||||
if (feeEstimateTx != null) {
|
||||
|
@ -453,8 +435,6 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
if (feeDiff > XmrWalletService.MINER_FEE_TOLERANCE) throw new IllegalArgumentException("Miner fee is not within " + (XmrWalletService.MINER_FEE_TOLERANCE * 100) + "% of estimated fee, expected " + feeEstimate + " but was " + arbitratorSignedPayoutTx.getFee());
|
||||
log.info("Payout tx fee {} is within tolerance, diff %={}", arbitratorSignedPayoutTx.getFee(), feeDiff);
|
||||
}
|
||||
} else {
|
||||
disputeTxSet.setMultisigTxHex(trade.getPayoutTxHex());
|
||||
}
|
||||
|
||||
// submit fully signed payout tx to the network
|
||||
|
@ -468,4 +448,26 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
dispute.setDisputePayoutTxId(disputeTxSet.getTxs().get(0).getHash());
|
||||
return disputeTxSet;
|
||||
}
|
||||
|
||||
public static BigInteger[] getBuyerSellerPayoutTxCost(DisputeResult disputeResult, BigInteger payoutTxCost) {
|
||||
boolean isBuyerWinner = disputeResult.getWinner() == Winner.BUYER;
|
||||
BigInteger loserAmount = isBuyerWinner ? disputeResult.getSellerPayoutAmountBeforeCost() : disputeResult.getBuyerPayoutAmountBeforeCost();
|
||||
if (loserAmount.equals(BigInteger.valueOf(0))) {
|
||||
BigInteger buyerPayoutTxFee = isBuyerWinner ? payoutTxCost : BigInteger.ZERO;
|
||||
BigInteger sellerPayoutTxFee = isBuyerWinner ? BigInteger.ZERO : payoutTxCost;
|
||||
return new BigInteger[] { buyerPayoutTxFee, sellerPayoutTxFee };
|
||||
} else {
|
||||
switch (disputeResult.getSubtractFeeFrom()) {
|
||||
case BUYER_AND_SELLER:
|
||||
BigInteger payoutTxFeeSplit = payoutTxCost.divide(BigInteger.valueOf(2));
|
||||
return new BigInteger[] { payoutTxFeeSplit, payoutTxFeeSplit };
|
||||
case BUYER_ONLY:
|
||||
return new BigInteger[] { payoutTxCost, BigInteger.ZERO };
|
||||
case SELLER_ONLY:
|
||||
return new BigInteger[] { BigInteger.ZERO, payoutTxCost };
|
||||
default:
|
||||
throw new RuntimeException("Unsupported subtract fee from: " + disputeResult.getSubtractFeeFrom());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -188,8 +188,8 @@ public final class MediationManager extends DisputeManager<MediationDisputeList>
|
|||
Trade trade = tradeOptional.get();
|
||||
if (trade.getDisputeState() == Trade.DisputeState.MEDIATION_REQUESTED ||
|
||||
trade.getDisputeState() == Trade.DisputeState.MEDIATION_STARTED_BY_PEER) {
|
||||
trade.getProcessModel().setBuyerPayoutAmountFromMediation(disputeResult.getBuyerPayoutAmount().longValueExact());
|
||||
trade.getProcessModel().setSellerPayoutAmountFromMediation(disputeResult.getSellerPayoutAmount().longValueExact());
|
||||
trade.getProcessModel().setBuyerPayoutAmountFromMediation(disputeResult.getBuyerPayoutAmountBeforeCost().longValueExact());
|
||||
trade.getProcessModel().setSellerPayoutAmountFromMediation(disputeResult.getSellerPayoutAmountBeforeCost().longValueExact());
|
||||
|
||||
trade.setDisputeState(Trade.DisputeState.MEDIATION_CLOSED);
|
||||
|
||||
|
@ -222,8 +222,8 @@ public final class MediationManager extends DisputeManager<MediationDisputeList>
|
|||
Optional<Dispute> optionalDispute = findDispute(tradeId);
|
||||
checkArgument(optionalDispute.isPresent(), "dispute must be present");
|
||||
DisputeResult disputeResult = optionalDispute.get().getDisputeResultProperty().get();
|
||||
BigInteger buyerPayoutAmount = disputeResult.getBuyerPayoutAmount();
|
||||
BigInteger sellerPayoutAmount = disputeResult.getSellerPayoutAmount();
|
||||
BigInteger buyerPayoutAmount = disputeResult.getBuyerPayoutAmountBeforeCost();
|
||||
BigInteger sellerPayoutAmount = disputeResult.getSellerPayoutAmountBeforeCost();
|
||||
ProcessModel processModel = trade.getProcessModel();
|
||||
processModel.setBuyerPayoutAmountFromMediation(buyerPayoutAmount.longValueExact());
|
||||
processModel.setSellerPayoutAmountFromMediation(sellerPayoutAmount.longValueExact());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue