Handle arbitrator giving all payout to one trader

This commit is contained in:
Randall Coding 2021-11-22 13:14:44 -06:00 committed by woodser
parent 1f7daac389
commit c7cc810d47

View file

@ -65,6 +65,7 @@ import com.google.common.base.Preconditions;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
@ -618,12 +619,10 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
// TODO (woodser): include arbitration fee // TODO (woodser): include arbitration fee
//System.out.println("Creating feeEstimateTx!"); //System.out.println("Creating feeEstimateTx!");
MoneroTxWallet feeEstimateTx = multisigWallet.createTx(new MoneroTxConfig() MoneroTxConfig txConfig = new MoneroTxConfig().setAccountIndex(0).setRelay(false);
.setAccountIndex(0) if (buyerPayoutAmount.compareTo(BigInteger.ZERO) == 1) txConfig.addDestination(buyerPayoutAddress, buyerPayoutAmount.multiply(BigInteger.valueOf(4)).divide(BigInteger.valueOf(5))); // reduce payment amount to compute fee of similar tx
.addDestination(buyerPayoutAddress, buyerPayoutAmount.multiply(BigInteger.valueOf(4)).divide(BigInteger.valueOf(5))) // reduce payment amount to compute fee of similar tx if (sellerPayoutAmount.compareTo(BigInteger.ZERO) == 1) txConfig.addDestination(sellerPayoutAddress, sellerPayoutAmount.multiply(BigInteger.valueOf(4)).divide(BigInteger.valueOf(5)));
.addDestination(sellerPayoutAddress, sellerPayoutAmount.multiply(BigInteger.valueOf(4)).divide(BigInteger.valueOf(5))) MoneroTxWallet feeEstimateTx = multisigWallet.createTx(txConfig);
.setRelay(false)
);
System.out.println("Created fee estimate tx!"); System.out.println("Created fee estimate tx!");
System.out.println(feeEstimateTx); System.out.println(feeEstimateTx);
@ -632,16 +631,21 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
// attempt to create payout tx by increasing estimated fee until successful // attempt to create payout tx by increasing estimated fee until successful
MoneroTxWallet payoutTx = null; MoneroTxWallet payoutTx = null;
int numAttempts = 0; int numAttempts = 0;
int feeDivisor = 0; // adjust fee divisor based on number of payout destinations
if (buyerPayoutAmount.compareTo(BigInteger.ZERO) == 1) feeDivisor += 1;
if (sellerPayoutAmount.compareTo(BigInteger.ZERO) == 1) feeDivisor += 1;
while (payoutTx == null && numAttempts < 50) { while (payoutTx == null && numAttempts < 50) {
BigInteger feeEstimate = feeEstimateTx.getFee().add(feeEstimateTx.getFee().multiply(BigInteger.valueOf(numAttempts)).divide(BigInteger.valueOf(10))); // add 1/10 of fee until tx is successful BigInteger feeEstimate = feeEstimateTx.getFee().add(feeEstimateTx.getFee().multiply(BigInteger.valueOf(numAttempts)).divide(BigInteger.valueOf(10))); // add 1/10 of fee until tx is successful
txConfig = new MoneroTxConfig().setAccountIndex(0).setRelay(false);
if (buyerPayoutAmount.compareTo(BigInteger.ZERO) == 1) txConfig.addDestination(buyerPayoutAddress, buyerPayoutAmount.subtract(feeEstimate.divide(BigInteger.valueOf(feeDivisor)))); // split fee subtracted from each payout amount
if (sellerPayoutAmount.compareTo(BigInteger.ZERO) == 1) txConfig.addDestination(sellerPayoutAddress, sellerPayoutAmount.subtract(feeEstimate.divide(BigInteger.valueOf(feeDivisor))));
try { try {
numAttempts++; numAttempts++;
payoutTx = multisigWallet.createTx(new MoneroTxConfig() payoutTx = multisigWallet.createTx(txConfig);
.setAccountIndex(0)
.addDestination(buyerPayoutAddress, buyerPayoutAmount.subtract(feeEstimate.divide(BigInteger.valueOf(2)))) // split fee subtracted from each payout amount
.addDestination(sellerPayoutAddress, sellerPayoutAmount.subtract(feeEstimate.divide(BigInteger.valueOf(2))))
.setRelay(false));
} catch (MoneroError e) { } catch (MoneroError e) {
System.out.println(e.toString());
System.out.println(e.getStackTrace());
// exception expected // TODO: better way of estimating fee? // exception expected // TODO: better way of estimating fee?
} }
} }
@ -677,32 +681,36 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
MoneroTxWallet arbitratorSignedPayoutTx = parsedTxSet.getTxs().get(0); MoneroTxWallet arbitratorSignedPayoutTx = parsedTxSet.getTxs().get(0);
System.out.println("Parsed arbitrator-signed payout tx:\n" + arbitratorSignedPayoutTx); System.out.println("Parsed arbitrator-signed payout tx:\n" + arbitratorSignedPayoutTx);
// verify payout tx has exactly 2 destinations // verify payout tx has 1 or 2 destinations
if (arbitratorSignedPayoutTx.getOutgoingTransfer() == null || arbitratorSignedPayoutTx.getOutgoingTransfer().getDestinations() == null || arbitratorSignedPayoutTx.getOutgoingTransfer().getDestinations().size() != 2) throw new RuntimeException("Buyer-signed payout tx does not have exactly two destinations"); int numDestinations = arbitratorSignedPayoutTx.getOutgoingTransfer() == null || arbitratorSignedPayoutTx.getOutgoingTransfer().getDestinations() == null ? 0 : arbitratorSignedPayoutTx.getOutgoingTransfer().getDestinations().size();
if (numDestinations != 1 && numDestinations != 2) throw new RuntimeException("Buyer-signed payout tx does not have 1 or 2 destinations");
// get buyer and seller destinations (order not preserved) // get buyer and seller destinations (order not preserved)
boolean buyerFirst = arbitratorSignedPayoutTx.getOutgoingTransfer().getDestinations().get(0).getAddress().equals(contract.getBuyerPayoutAddressString()); List<MoneroDestination> destinations = arbitratorSignedPayoutTx.getOutgoingTransfer().getDestinations();
MoneroDestination buyerPayoutDestination = arbitratorSignedPayoutTx.getOutgoingTransfer().getDestinations().get(buyerFirst ? 0 : 1); boolean buyerFirst = destinations.get(0).getAddress().equals(contract.getBuyerPayoutAddressString());
MoneroDestination sellerPayoutDestination = arbitratorSignedPayoutTx.getOutgoingTransfer().getDestinations().get(buyerFirst ? 1 : 0); MoneroDestination buyerPayoutDestination = buyerFirst ? destinations.get(0) : numDestinations == 2 ? destinations.get(1) : null;
MoneroDestination sellerPayoutDestination = buyerFirst ? (numDestinations == 2 ? destinations.get(1) : null) : destinations.get(0);
// verify payout addresses // verify payout addresses
if (!buyerPayoutDestination.getAddress().equals(contract.getBuyerPayoutAddressString())) throw new RuntimeException("Buyer payout address does not match contract"); if (buyerPayoutDestination != null && !buyerPayoutDestination.getAddress().equals(contract.getBuyerPayoutAddressString())) throw new RuntimeException("Buyer payout address does not match contract");
if (!sellerPayoutDestination.getAddress().equals(contract.getSellerPayoutAddressString())) throw new RuntimeException("Seller payout address does not match contract"); if (sellerPayoutDestination != null && !sellerPayoutDestination.getAddress().equals(contract.getSellerPayoutAddressString())) throw new RuntimeException("Seller payout address does not match contract");
// verify change address is multisig's primary address // verify change address is multisig's primary address
if (!arbitratorSignedPayoutTx.getChangeAddress().equals(multisigWallet.getPrimaryAddress())) throw new RuntimeException("Change address is not multisig wallet's primary address"); if (!arbitratorSignedPayoutTx.getChangeAddress().equals(multisigWallet.getPrimaryAddress())) throw new RuntimeException("Change address is not multisig wallet's primary address");
// verify sum of outputs = destination amounts + change amount // verify sum of outputs = destination amounts + change amount
if (!arbitratorSignedPayoutTx.getOutputSum().equals(buyerPayoutDestination.getAmount().add(sellerPayoutDestination.getAmount()).add(arbitratorSignedPayoutTx.getChangeAmount()))) throw new RuntimeException("Sum of outputs != destination amounts + change amount"); BigInteger destinationSum = (buyerPayoutDestination == null ? BigInteger.ZERO : buyerPayoutDestination.getAmount()).add(sellerPayoutDestination == null ? BigInteger.ZERO : sellerPayoutDestination.getAmount());
if (!arbitratorSignedPayoutTx.getOutputSum().equals(destinationSum.add(arbitratorSignedPayoutTx.getChangeAmount()))) throw new RuntimeException("Sum of outputs != destination amounts + change amount");
// verify buyer destination amount is payout amount - 1/2 tx costs // verify buyer destination amount is payout amount - 1/2 tx costs
if (buyerPayoutDestination != null) {
BigInteger txCost = arbitratorSignedPayoutTx.getFee().add(arbitratorSignedPayoutTx.getChangeAmount()); BigInteger txCost = arbitratorSignedPayoutTx.getFee().add(arbitratorSignedPayoutTx.getChangeAmount());
BigInteger expectedBuyerPayout = buyerPayoutAmount.subtract(txCost.divide(BigInteger.valueOf(2))); BigInteger expectedBuyerPayout = buyerPayoutAmount.subtract(txCost.divide(BigInteger.valueOf(2)));
System.out.println("Dispute buyer payout amount: " + buyerPayoutAmount); System.out.println("Dispute buyer payout amount: " + buyerPayoutAmount);
System.out.println("Tx cost: " + txCost); System.out.println("Tx cost: " + txCost);
System.out.println("Buyer destination payout amount: " + buyerPayoutDestination.getAmount()); System.out.println("Buyer destination payout amount: " + buyerPayoutDestination.getAmount());
}
// payout amount is dispute payout amount - 1/2 tx cost - deposit tx fee // payout amount is dispute payout amount - 1/2 tx cost - deposit tx fee