increase penalty fee to security deposit
This commit is contained in:
parent
8ea556fa4f
commit
a16b03bb5c
@ -987,7 +987,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
// verify maker's reserve tx (double spend, trade fee, trade amount, mining fee)
|
// verify maker's reserve tx (double spend, trade fee, trade amount, mining fee)
|
||||||
BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.valueOf(0) : offer.getAmount();
|
BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.valueOf(0) : offer.getAmount();
|
||||||
BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
|
BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
|
||||||
MoneroTx reserveTx = xmrWalletService.verifyTradeTx(
|
Tuple2<MoneroTx, BigInteger> txResult = xmrWalletService.verifyTradeTx(
|
||||||
tradeFee,
|
tradeFee,
|
||||||
sendAmount,
|
sendAmount,
|
||||||
securityDeposit,
|
securityDeposit,
|
||||||
@ -995,7 +995,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
request.getReserveTxHash(),
|
request.getReserveTxHash(),
|
||||||
request.getReserveTxHex(),
|
request.getReserveTxHex(),
|
||||||
request.getReserveTxKey(),
|
request.getReserveTxKey(),
|
||||||
request.getReserveTxKeyImages());
|
request.getReserveTxKeyImages(),
|
||||||
|
true);
|
||||||
|
|
||||||
// arbitrator signs offer to certify they have valid reserve tx
|
// arbitrator signs offer to certify they have valid reserve tx
|
||||||
String offerPayloadAsJson = JsonUtil.objectToJson(request.getOfferPayload());
|
String offerPayloadAsJson = JsonUtil.objectToJson(request.getOfferPayload());
|
||||||
@ -1008,11 +1009,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
signedOfferPayload.getId(),
|
signedOfferPayload.getId(),
|
||||||
offer.getAmount().longValueExact(),
|
offer.getAmount().longValueExact(),
|
||||||
HavenoUtils.getMakerFee(offer.getAmount()).longValueExact(),
|
txResult.second.longValueExact(),
|
||||||
request.getReserveTxHash(),
|
request.getReserveTxHash(),
|
||||||
request.getReserveTxHex(),
|
request.getReserveTxHex(),
|
||||||
request.getReserveTxKeyImages(),
|
request.getReserveTxKeyImages(),
|
||||||
reserveTx.getFee().longValueExact(),
|
txResult.first.getFee().longValueExact(),
|
||||||
signature); // TODO (woodser): no need for signature to be part of SignedOffer?
|
signature); // TODO (woodser): no need for signature to be part of SignedOffer?
|
||||||
addSignedOffer(signedOffer);
|
addSignedOffer(signedOffer);
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
|
@ -34,7 +34,7 @@ public final class SignedOffer implements PersistablePayload {
|
|||||||
@Getter
|
@Getter
|
||||||
private final long tradeAmount;
|
private final long tradeAmount;
|
||||||
@Getter
|
@Getter
|
||||||
private final long makerTradeFee;
|
private final long penaltyAmount;
|
||||||
@Getter
|
@Getter
|
||||||
private final String reserveTxHash;
|
private final String reserveTxHash;
|
||||||
@Getter
|
@Getter
|
||||||
@ -49,7 +49,7 @@ public final class SignedOffer implements PersistablePayload {
|
|||||||
public SignedOffer(long timeStamp,
|
public SignedOffer(long timeStamp,
|
||||||
String offerId,
|
String offerId,
|
||||||
long tradeAmount,
|
long tradeAmount,
|
||||||
long makerTradeFee,
|
long penaltyAmount,
|
||||||
String reserveTxHash,
|
String reserveTxHash,
|
||||||
String reserveTxHex,
|
String reserveTxHex,
|
||||||
List<String> reserveTxKeyImages,
|
List<String> reserveTxKeyImages,
|
||||||
@ -58,7 +58,7 @@ public final class SignedOffer implements PersistablePayload {
|
|||||||
this.timeStamp = timeStamp;
|
this.timeStamp = timeStamp;
|
||||||
this.offerId = offerId;
|
this.offerId = offerId;
|
||||||
this.tradeAmount = tradeAmount;
|
this.tradeAmount = tradeAmount;
|
||||||
this.makerTradeFee = makerTradeFee;
|
this.penaltyAmount = penaltyAmount;
|
||||||
this.reserveTxHash = reserveTxHash;
|
this.reserveTxHash = reserveTxHash;
|
||||||
this.reserveTxHex = reserveTxHex;
|
this.reserveTxHex = reserveTxHex;
|
||||||
this.reserveTxKeyImages = reserveTxKeyImages;
|
this.reserveTxKeyImages = reserveTxKeyImages;
|
||||||
@ -76,7 +76,7 @@ public final class SignedOffer implements PersistablePayload {
|
|||||||
.setTimeStamp(timeStamp)
|
.setTimeStamp(timeStamp)
|
||||||
.setOfferId(offerId)
|
.setOfferId(offerId)
|
||||||
.setTradeAmount(tradeAmount)
|
.setTradeAmount(tradeAmount)
|
||||||
.setMakerTradeFee(makerTradeFee)
|
.setPenaltyAmount(penaltyAmount)
|
||||||
.setReserveTxHash(reserveTxHash)
|
.setReserveTxHash(reserveTxHash)
|
||||||
.setReserveTxHex(reserveTxHex)
|
.setReserveTxHex(reserveTxHex)
|
||||||
.addAllReserveTxKeyImages(reserveTxKeyImages)
|
.addAllReserveTxKeyImages(reserveTxKeyImages)
|
||||||
@ -89,7 +89,7 @@ public final class SignedOffer implements PersistablePayload {
|
|||||||
return new SignedOffer(proto.getTimeStamp(),
|
return new SignedOffer(proto.getTimeStamp(),
|
||||||
proto.getOfferId(),
|
proto.getOfferId(),
|
||||||
proto.getTradeAmount(),
|
proto.getTradeAmount(),
|
||||||
proto.getMakerTradeFee(),
|
proto.getPenaltyAmount(),
|
||||||
proto.getReserveTxHash(),
|
proto.getReserveTxHash(),
|
||||||
proto.getReserveTxHex(),
|
proto.getReserveTxHex(),
|
||||||
proto.getReserveTxKeyImagesList(),
|
proto.getReserveTxKeyImagesList(),
|
||||||
@ -108,7 +108,7 @@ public final class SignedOffer implements PersistablePayload {
|
|||||||
",\n timeStamp=" + timeStamp +
|
",\n timeStamp=" + timeStamp +
|
||||||
",\n offerId=" + offerId +
|
",\n offerId=" + offerId +
|
||||||
",\n tradeAmount=" + tradeAmount +
|
",\n tradeAmount=" + tradeAmount +
|
||||||
",\n makerTradeFee=" + makerTradeFee +
|
",\n penaltyAmount=" + penaltyAmount +
|
||||||
",\n reserveTxHash=" + reserveTxHash +
|
",\n reserveTxHash=" + reserveTxHash +
|
||||||
",\n reserveTxHex=" + reserveTxHex +
|
",\n reserveTxHex=" + reserveTxHex +
|
||||||
",\n reserveTxKeyImages=" + reserveTxKeyImages +
|
",\n reserveTxKeyImages=" + reserveTxKeyImages +
|
||||||
|
@ -1570,12 +1570,12 @@ public abstract class Trade implements Tradable, Model {
|
|||||||
|
|
||||||
public BigInteger getBuyerSecurityDeposit() {
|
public BigInteger getBuyerSecurityDeposit() {
|
||||||
if (getBuyer().getDepositTxHash() == null) return null;
|
if (getBuyer().getDepositTxHash() == null) return null;
|
||||||
return BigInteger.valueOf(getBuyer().getSecurityDeposit());
|
return getBuyer().getSecurityDeposit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigInteger getSellerSecurityDeposit() {
|
public BigInteger getSellerSecurityDeposit() {
|
||||||
if (getSeller().getDepositTxHash() == null) return null;
|
if (getSeller().getDepositTxHash() == null) return null;
|
||||||
return BigInteger.valueOf(getSeller().getSecurityDeposit());
|
return getSeller().getSecurityDeposit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -1719,11 +1719,11 @@ public abstract class Trade implements Tradable, Model {
|
|||||||
getTaker().setDepositTx(makerFirst ? txs.get(1) : txs.get(0));
|
getTaker().setDepositTx(makerFirst ? txs.get(1) : txs.get(0));
|
||||||
|
|
||||||
// set security deposits
|
// set security deposits
|
||||||
if (getBuyer().getSecurityDeposit() == 0) {
|
if (getBuyer().getSecurityDeposit().longValueExact() == 0) {
|
||||||
BigInteger buyerSecurityDeposit = ((MoneroTxWallet) getBuyer().getDepositTx()).getIncomingAmount();
|
BigInteger buyerSecurityDeposit = ((MoneroTxWallet) getBuyer().getDepositTx()).getIncomingAmount();
|
||||||
BigInteger sellerSecurityDeposit = ((MoneroTxWallet) getSeller().getDepositTx()).getIncomingAmount().subtract(getAmount());
|
BigInteger sellerSecurityDeposit = ((MoneroTxWallet) getSeller().getDepositTx()).getIncomingAmount().subtract(getAmount());
|
||||||
getBuyer().setSecurityDeposit(buyerSecurityDeposit.longValueExact());
|
getBuyer().setSecurityDeposit(buyerSecurityDeposit);
|
||||||
getSeller().setSecurityDeposit(sellerSecurityDeposit.longValueExact());
|
getSeller().setSecurityDeposit(sellerSecurityDeposit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set deposits published state
|
// set deposits published state
|
||||||
|
@ -27,6 +27,8 @@ import haveno.core.payment.payload.PaymentAccountPayload;
|
|||||||
import haveno.core.proto.CoreProtoResolver;
|
import haveno.core.proto.CoreProtoResolver;
|
||||||
import haveno.core.xmr.model.RawTransactionInput;
|
import haveno.core.xmr.model.RawTransactionInput;
|
||||||
import haveno.network.p2p.NodeAddress;
|
import haveno.network.p2p.NodeAddress;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -133,6 +135,14 @@ public final class TradePeer implements PersistablePayload {
|
|||||||
public TradePeer() {
|
public TradePeer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BigInteger getSecurityDeposit() {
|
||||||
|
return BigInteger.valueOf(securityDeposit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecurityDeposit(BigInteger securityDeposit) {
|
||||||
|
this.securityDeposit = securityDeposit.longValueExact();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Message toProtoMessage() {
|
public Message toProtoMessage() {
|
||||||
final protobuf.TradePeer.Builder builder = protobuf.TradePeer.newBuilder()
|
final protobuf.TradePeer.Builder builder = protobuf.TradePeer.newBuilder()
|
||||||
@ -219,7 +229,7 @@ public final class TradePeer implements PersistablePayload {
|
|||||||
tradePeer.setDepositTxHash(ProtoUtil.stringOrNullFromProto(proto.getDepositTxHash()));
|
tradePeer.setDepositTxHash(ProtoUtil.stringOrNullFromProto(proto.getDepositTxHash()));
|
||||||
tradePeer.setDepositTxHex(ProtoUtil.stringOrNullFromProto(proto.getDepositTxHex()));
|
tradePeer.setDepositTxHex(ProtoUtil.stringOrNullFromProto(proto.getDepositTxHex()));
|
||||||
tradePeer.setDepositTxKey(ProtoUtil.stringOrNullFromProto(proto.getDepositTxKey()));
|
tradePeer.setDepositTxKey(ProtoUtil.stringOrNullFromProto(proto.getDepositTxKey()));
|
||||||
tradePeer.setSecurityDeposit(proto.getSecurityDeposit());
|
tradePeer.setSecurityDeposit(BigInteger.valueOf(proto.getSecurityDeposit()));
|
||||||
tradePeer.setUpdatedMultisigHex(ProtoUtil.stringOrNullFromProto(proto.getUpdatedMultisigHex()));
|
tradePeer.setUpdatedMultisigHex(ProtoUtil.stringOrNullFromProto(proto.getUpdatedMultisigHex()));
|
||||||
return tradePeer;
|
return tradePeer;
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,8 @@ public class ArbitratorProcessDepositRequest extends TradeTask {
|
|||||||
trader.getDepositTxHash(),
|
trader.getDepositTxHash(),
|
||||||
request.getDepositTxHex(),
|
request.getDepositTxHex(),
|
||||||
request.getDepositTxKey(),
|
request.getDepositTxKey(),
|
||||||
null);
|
null,
|
||||||
|
false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Error processing deposit tx from " + (isFromTaker ? "taker " : "maker ") + trader.getNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage());
|
throw new RuntimeException("Error processing deposit tx from " + (isFromTaker ? "taker " : "maker ") + trader.getNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
package haveno.core.trade.protocol.tasks;
|
package haveno.core.trade.protocol.tasks;
|
||||||
|
|
||||||
import haveno.common.taskrunner.TaskRunner;
|
import haveno.common.taskrunner.TaskRunner;
|
||||||
|
import haveno.common.util.Tuple2;
|
||||||
import haveno.core.offer.Offer;
|
import haveno.core.offer.Offer;
|
||||||
import haveno.core.offer.OfferDirection;
|
import haveno.core.offer.OfferDirection;
|
||||||
import haveno.core.trade.Trade;
|
import haveno.core.trade.Trade;
|
||||||
@ -26,6 +27,7 @@ import haveno.core.trade.protocol.TradePeer;
|
|||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import monero.daemon.model.MoneroTx;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arbitrator verifies reserve tx from maker or taker.
|
* Arbitrator verifies reserve tx from maker or taker.
|
||||||
@ -55,8 +57,9 @@ public class ArbitratorProcessReserveTx extends TradeTask {
|
|||||||
BigInteger tradeFee = isFromTaker ? trade.getTakerFee() : trade.getMakerFee();
|
BigInteger tradeFee = isFromTaker ? trade.getTakerFee() : trade.getMakerFee();
|
||||||
BigInteger sendAmount = isFromBuyer ? BigInteger.valueOf(0) : offer.getAmount();
|
BigInteger sendAmount = isFromBuyer ? BigInteger.valueOf(0) : offer.getAmount();
|
||||||
BigInteger securityDeposit = isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
|
BigInteger securityDeposit = isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
|
||||||
|
Tuple2<MoneroTx, BigInteger> txResult;
|
||||||
try {
|
try {
|
||||||
trade.getXmrWalletService().verifyTradeTx(
|
txResult = trade.getXmrWalletService().verifyTradeTx(
|
||||||
tradeFee,
|
tradeFee,
|
||||||
sendAmount,
|
sendAmount,
|
||||||
securityDeposit,
|
securityDeposit,
|
||||||
@ -64,7 +67,8 @@ public class ArbitratorProcessReserveTx extends TradeTask {
|
|||||||
request.getReserveTxHash(),
|
request.getReserveTxHash(),
|
||||||
request.getReserveTxHex(),
|
request.getReserveTxHex(),
|
||||||
request.getReserveTxKey(),
|
request.getReserveTxKey(),
|
||||||
null);
|
null,
|
||||||
|
true);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Error processing reserve tx from " + (isFromTaker ? "taker " : "maker ") + request.getSenderNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage());
|
throw new RuntimeException("Error processing reserve tx from " + (isFromTaker ? "taker " : "maker ") + request.getSenderNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage());
|
||||||
}
|
}
|
||||||
@ -74,6 +78,7 @@ public class ArbitratorProcessReserveTx extends TradeTask {
|
|||||||
trader.setReserveTxHash(request.getReserveTxHash());
|
trader.setReserveTxHash(request.getReserveTxHash());
|
||||||
trader.setReserveTxHex(request.getReserveTxHex());
|
trader.setReserveTxHex(request.getReserveTxHex());
|
||||||
trader.setReserveTxKey(request.getReserveTxKey());
|
trader.setReserveTxKey(request.getReserveTxKey());
|
||||||
|
trader.setSecurityDeposit(txResult.second);
|
||||||
|
|
||||||
// persist trade
|
// persist trade
|
||||||
processModel.getTradeManager().requestPersistence();
|
processModel.getTradeManager().requestPersistence();
|
||||||
|
@ -9,6 +9,7 @@ import haveno.common.UserThread;
|
|||||||
import haveno.common.config.BaseCurrencyNetwork;
|
import haveno.common.config.BaseCurrencyNetwork;
|
||||||
import haveno.common.config.Config;
|
import haveno.common.config.Config;
|
||||||
import haveno.common.file.FileUtil;
|
import haveno.common.file.FileUtil;
|
||||||
|
import haveno.common.util.Tuple2;
|
||||||
import haveno.common.util.Utilities;
|
import haveno.common.util.Utilities;
|
||||||
import haveno.core.api.AccountServiceListener;
|
import haveno.core.api.AccountServiceListener;
|
||||||
import haveno.core.api.CoreAccountService;
|
import haveno.core.api.CoreAccountService;
|
||||||
@ -300,7 +301,7 @@ public class XmrWalletService {
|
|||||||
*/
|
*/
|
||||||
public MoneroTxWallet createReserveTx(BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String returnAddress) {
|
public MoneroTxWallet createReserveTx(BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String returnAddress) {
|
||||||
log.info("Creating reserve tx with fee={}, sendAmount={}, securityDeposit={}", tradeFee, sendAmount, securityDeposit);
|
log.info("Creating reserve tx with fee={}, sendAmount={}, securityDeposit={}", tradeFee, sendAmount, securityDeposit);
|
||||||
return createTradeTx(tradeFee, sendAmount, securityDeposit, returnAddress);
|
return createTradeTx(tradeFee, sendAmount, securityDeposit, returnAddress, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -326,11 +327,11 @@ public class XmrWalletService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.info("Creating deposit tx with fee={}, sendAmount={}, securityDeposit={}", tradeFee, sendAmount, securityDeposit);
|
log.info("Creating deposit tx with fee={}, sendAmount={}, securityDeposit={}", tradeFee, sendAmount, securityDeposit);
|
||||||
return createTradeTx(tradeFee, sendAmount, securityDeposit, multisigAddress);
|
return createTradeTx(tradeFee, sendAmount, securityDeposit, multisigAddress, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MoneroTxWallet createTradeTx(BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address) {
|
private MoneroTxWallet createTradeTx(BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address, boolean isReserveTx) {
|
||||||
MoneroWallet wallet = getWallet();
|
MoneroWallet wallet = getWallet();
|
||||||
synchronized (wallet) {
|
synchronized (wallet) {
|
||||||
|
|
||||||
@ -341,10 +342,10 @@ public class XmrWalletService {
|
|||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
try {
|
try {
|
||||||
BigInteger appliedSecurityDeposit = new BigDecimal(securityDeposit).multiply(new BigDecimal(1.0 - SECURITY_DEPOSIT_TOLERANCE * appliedTolerance)).toBigInteger();
|
BigInteger appliedSecurityDeposit = new BigDecimal(securityDeposit).multiply(new BigDecimal(1.0 - SECURITY_DEPOSIT_TOLERANCE * appliedTolerance)).toBigInteger();
|
||||||
BigInteger amount = sendAmount.add(appliedSecurityDeposit);
|
BigInteger amount = sendAmount.add(isReserveTx ? tradeFee : appliedSecurityDeposit);
|
||||||
tradeTx = wallet.createTx(new MoneroTxConfig()
|
tradeTx = wallet.createTx(new MoneroTxConfig()
|
||||||
.setAccountIndex(0)
|
.setAccountIndex(0)
|
||||||
.addDestination(HavenoUtils.getTradeFeeAddress(), tradeFee)
|
.addDestination(HavenoUtils.getTradeFeeAddress(), isReserveTx ? appliedSecurityDeposit : tradeFee) // reserve tx charges security deposit if published
|
||||||
.addDestination(address, amount));
|
.addDestination(address, amount));
|
||||||
appliedTolerance -= searchDiff; // apply less tolerance to increase security deposit
|
appliedTolerance -= searchDiff; // apply less tolerance to increase security deposit
|
||||||
if (appliedTolerance < 0.0) break; // can send full security deposit
|
if (appliedTolerance < 0.0) break; // can send full security deposit
|
||||||
@ -375,12 +376,13 @@ public class XmrWalletService {
|
|||||||
* @param txHex transaction hex
|
* @param txHex transaction hex
|
||||||
* @param txKey transaction key
|
* @param txKey transaction key
|
||||||
* @param keyImages expected key images of inputs, ignored if null
|
* @param keyImages expected key images of inputs, ignored if null
|
||||||
* @return the verified tx
|
* @return tuple with the verified tx and its actual security deposit
|
||||||
*/
|
*/
|
||||||
public MoneroTx verifyTradeTx(BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address, String txHash, String txHex, String txKey, List<String> keyImages) {
|
public Tuple2<MoneroTx, BigInteger> verifyTradeTx(BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address, String txHash, String txHex, String txKey, List<String> keyImages, boolean isReserveTx) {
|
||||||
MoneroDaemonRpc daemon = getDaemon();
|
MoneroDaemonRpc daemon = getDaemon();
|
||||||
MoneroWallet wallet = getWallet();
|
MoneroWallet wallet = getWallet();
|
||||||
MoneroTx tx = null;
|
MoneroTx tx = null;
|
||||||
|
BigInteger actualSecurityDeposit = null;
|
||||||
synchronized (daemon) {
|
synchronized (daemon) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@ -403,28 +405,36 @@ public class XmrWalletService {
|
|||||||
// verify unlock height
|
// verify unlock height
|
||||||
if (tx.getUnlockHeight() != 0) throw new RuntimeException("Unlock height must be 0");
|
if (tx.getUnlockHeight() != 0) throw new RuntimeException("Unlock height must be 0");
|
||||||
|
|
||||||
// verify trade fee
|
|
||||||
String feeAddress = HavenoUtils.getTradeFeeAddress();
|
|
||||||
MoneroCheckTx check = wallet.checkTxKey(txHash, txKey, feeAddress);
|
|
||||||
if (!check.isGood()) throw new RuntimeException("Invalid proof of trade fee");
|
|
||||||
if (!check.getReceivedAmount().equals(tradeFee)) throw new RuntimeException("Trade fee is incorrect amount, expected " + tradeFee + " but was " + check.getReceivedAmount());
|
|
||||||
|
|
||||||
// verify miner fee
|
// verify miner fee
|
||||||
BigInteger feeEstimate = getFeeEstimate(tx.getWeight());
|
BigInteger feeEstimate = getFeeEstimate(tx.getWeight());
|
||||||
double feeDiff = tx.getFee().subtract(feeEstimate).abs().doubleValue() / feeEstimate.doubleValue(); // TODO: use BigDecimal?
|
double feeDiff = tx.getFee().subtract(feeEstimate).abs().doubleValue() / feeEstimate.doubleValue(); // TODO: use BigDecimal?
|
||||||
if (feeDiff > MINER_FEE_TOLERANCE) throw new Error("Miner fee is not within " + (MINER_FEE_TOLERANCE * 100) + "% of estimated fee, expected " + feeEstimate + " but was " + tx.getFee());
|
if (feeDiff > MINER_FEE_TOLERANCE) throw new Error("Miner fee is not within " + (MINER_FEE_TOLERANCE * 100) + "% of estimated fee, expected " + feeEstimate + " but was " + tx.getFee());
|
||||||
log.info("Trade tx fee {} is within tolerance, diff%={}", tx.getFee(), feeDiff);
|
log.info("Trade tx fee {} is within tolerance, diff%={}", tx.getFee(), feeDiff);
|
||||||
|
|
||||||
|
// verify transfer proof to fee address
|
||||||
|
String feeAddress = HavenoUtils.getTradeFeeAddress();
|
||||||
|
MoneroCheckTx feeCheck = wallet.checkTxKey(txHash, txKey, feeAddress);
|
||||||
|
if (!feeCheck.isGood()) throw new RuntimeException("Invalid proof of trade fee");
|
||||||
|
|
||||||
|
// verify transfer proof to return address
|
||||||
|
MoneroCheckTx returnCheck = wallet.checkTxKey(txHash, txKey, address);
|
||||||
|
if (!returnCheck.isGood()) throw new RuntimeException("Invalid proof of return funds");
|
||||||
|
|
||||||
|
// collect actual trade fee, send amount, and security deposit
|
||||||
|
BigInteger actualTradeFee = isReserveTx ? returnCheck.getReceivedAmount().subtract(sendAmount) : feeCheck.getReceivedAmount();
|
||||||
|
actualSecurityDeposit = isReserveTx ? feeCheck.getReceivedAmount() : returnCheck.getReceivedAmount().subtract(sendAmount);
|
||||||
|
BigInteger actualSendAmount = returnCheck.getReceivedAmount().subtract(isReserveTx ? actualTradeFee : actualSecurityDeposit);
|
||||||
|
|
||||||
|
// verify trade fee
|
||||||
|
if (!tradeFee.equals(actualTradeFee)) throw new RuntimeException("Trade fee is incorrect amount, expected " + tradeFee + " but was " + actualTradeFee);
|
||||||
|
|
||||||
// verify sufficient security deposit
|
// verify sufficient security deposit
|
||||||
check = wallet.checkTxKey(txHash, txKey, address);
|
|
||||||
if (!check.isGood()) throw new RuntimeException("Invalid proof of deposit amount");
|
|
||||||
BigInteger minSecurityDeposit = new BigDecimal(securityDeposit).multiply(new BigDecimal(1.0 - SECURITY_DEPOSIT_TOLERANCE)).toBigInteger();
|
BigInteger minSecurityDeposit = new BigDecimal(securityDeposit).multiply(new BigDecimal(1.0 - SECURITY_DEPOSIT_TOLERANCE)).toBigInteger();
|
||||||
BigInteger actualSecurityDeposit = check.getReceivedAmount().subtract(sendAmount);
|
|
||||||
if (actualSecurityDeposit.compareTo(minSecurityDeposit) < 0) throw new RuntimeException("Security deposit amount is not enough, needed " + minSecurityDeposit + " but was " + actualSecurityDeposit);
|
if (actualSecurityDeposit.compareTo(minSecurityDeposit) < 0) throw new RuntimeException("Security deposit amount is not enough, needed " + minSecurityDeposit + " but was " + actualSecurityDeposit);
|
||||||
|
|
||||||
// verify deposit amount + miner fee within dust tolerance
|
// verify deposit amount + miner fee within dust tolerance
|
||||||
BigInteger minDepositAndFee = sendAmount.add(securityDeposit).subtract(new BigDecimal(tx.getFee()).multiply(new BigDecimal(1.0 - DUST_TOLERANCE)).toBigInteger());
|
BigInteger minDepositAndFee = sendAmount.add(securityDeposit).subtract(new BigDecimal(tx.getFee()).multiply(new BigDecimal(1.0 - DUST_TOLERANCE)).toBigInteger());
|
||||||
BigInteger actualDepositAndFee = check.getReceivedAmount().add(tx.getFee());
|
BigInteger actualDepositAndFee = actualSendAmount.add(actualSecurityDeposit).add(tx.getFee());
|
||||||
if (actualDepositAndFee.compareTo(minDepositAndFee) < 0) throw new RuntimeException("Deposit amount + fee is not enough, needed " + minDepositAndFee + " but was " + actualDepositAndFee);
|
if (actualDepositAndFee.compareTo(minDepositAndFee) < 0) throw new RuntimeException("Deposit amount + fee is not enough, needed " + minDepositAndFee + " but was " + actualDepositAndFee);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
@ -434,7 +444,7 @@ public class XmrWalletService {
|
|||||||
throw err.getCode() == -32601 ? new RuntimeException("Failed to flush tx from pool. Arbitrator must use trusted, unrestricted daemon") : err;
|
throw err.getCode() == -32601 ? new RuntimeException("Failed to flush tx from pool. Arbitrator must use trusted, unrestricted daemon") : err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tx;
|
return new Tuple2<>(tx, actualSecurityDeposit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -993,7 +993,7 @@ portfolio.failed.cantUnfail=This trade cannot be moved back to open trades at th
|
|||||||
Try again after completion of trade(s) {0}
|
Try again after completion of trade(s) {0}
|
||||||
portfolio.failed.depositTxNull=The trade cannot be reverted to a open trade. Deposit transaction is null.
|
portfolio.failed.depositTxNull=The trade cannot be reverted to a open trade. Deposit transaction is null.
|
||||||
portfolio.failed.delayedPayoutTxNull=The trade cannot be reverted to a open trade. Delayed payout transaction is null.
|
portfolio.failed.delayedPayoutTxNull=The trade cannot be reverted to a open trade. Delayed payout transaction is null.
|
||||||
portfolio.failed.penalty.msg=This will charge the {0}/{1} the trade fee of {2} and return the remaining trade funds to their wallet. Are you sure you want to send?\n\n\
|
portfolio.failed.penalty.msg=This will charge the {0}/{1} a penalty fee of {2} and return the remaining trade funds to their wallet. Are you sure you want to send?\n\n\
|
||||||
Other Info:\n\
|
Other Info:\n\
|
||||||
Transaction Fee: {3}\n\
|
Transaction Fee: {3}\n\
|
||||||
Reserve Tx Hash: {4}
|
Reserve Tx Hash: {4}
|
||||||
@ -1097,9 +1097,9 @@ support.tab.ArbitratorsSupportTickets={0}'s tickets
|
|||||||
support.filter=Search disputes
|
support.filter=Search disputes
|
||||||
support.filter.prompt=Enter trade ID, date, onion address or account data
|
support.filter.prompt=Enter trade ID, date, onion address or account data
|
||||||
support.tab.SignedOffers=Signed Offers
|
support.tab.SignedOffers=Signed Offers
|
||||||
support.prompt.signedOffer.penalty.msg=This will charge the maker the trade fee and return their remaining trade funds to their wallet. Are you sure you want to send?\n\n\
|
support.prompt.signedOffer.penalty.msg=This will charge the maker a penalty fee and return the remaining trade funds to their wallet. Are you sure you want to send?\n\n\
|
||||||
Offer ID: {0}\n\
|
Offer ID: {0}\n\
|
||||||
Maker Trade Fee: {1}\n\
|
Maker Penalty Fee: {1}\n\
|
||||||
Reserve Tx Miner Fee: {2}\n\
|
Reserve Tx Miner Fee: {2}\n\
|
||||||
Reserve Tx Hash: {3}\n\
|
Reserve Tx Hash: {3}\n\
|
||||||
Reserve Tx Key Images: {4}\n\
|
Reserve Tx Key Images: {4}\n\
|
||||||
@ -1163,15 +1163,15 @@ support.requested=Requested
|
|||||||
support.closed=Closed
|
support.closed=Closed
|
||||||
support.open=Open
|
support.open=Open
|
||||||
support.process=Process
|
support.process=Process
|
||||||
support.buyerMaker=XMR buyer/Maker
|
support.buyerMaker=XMR Buyer/Maker
|
||||||
support.sellerMaker=XMR seller/Maker
|
support.sellerMaker=XMR Seller/Maker
|
||||||
support.buyerTaker=XMR buyer/Taker
|
support.buyerTaker=XMR Buyer/Taker
|
||||||
support.sellerTaker=XMR seller/Taker
|
support.sellerTaker=XMR Seller/Taker
|
||||||
support.txKeyImages=Key Images
|
support.txKeyImages=Key Images
|
||||||
support.txHash=Transaction Hash
|
support.txHash=Transaction Hash
|
||||||
support.txHex=Transaction Hex
|
support.txHex=Transaction Hex
|
||||||
support.signature=Signature
|
support.signature=Signature
|
||||||
support.maker.trade.fee=Maker Trade Fee
|
support.maker.penalty.fee=Maker Penalty Fee
|
||||||
support.tx.miner.fee=Miner Fee
|
support.tx.miner.fee=Miner Fee
|
||||||
|
|
||||||
support.backgroundInfo=Haveno is not a company, so it handles disputes differently.\n\n\
|
support.backgroundInfo=Haveno is not a company, so it handles disputes differently.\n\n\
|
||||||
|
@ -218,7 +218,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||||||
handleContextMenu("portfolio.failed.penalty.msg",
|
handleContextMenu("portfolio.failed.penalty.msg",
|
||||||
Res.get(selectedFailedTrade.getMaker() == selectedFailedTrade.getBuyer() ? "shared.buyer" : "shared.seller"),
|
Res.get(selectedFailedTrade.getMaker() == selectedFailedTrade.getBuyer() ? "shared.buyer" : "shared.seller"),
|
||||||
Res.get("shared.maker"),
|
Res.get("shared.maker"),
|
||||||
selectedFailedTrade.getMakerFee(),
|
selectedFailedTrade.getMaker().getSecurityDeposit(),
|
||||||
selectedFailedTrade.getMaker().getReserveTxHash(),
|
selectedFailedTrade.getMaker().getReserveTxHash(),
|
||||||
selectedFailedTrade.getMaker().getReserveTxHex());
|
selectedFailedTrade.getMaker().getReserveTxHex());
|
||||||
});
|
});
|
||||||
@ -228,7 +228,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||||||
handleContextMenu("portfolio.failed.penalty.msg",
|
handleContextMenu("portfolio.failed.penalty.msg",
|
||||||
Res.get(selectedFailedTrade.getTaker() == selectedFailedTrade.getBuyer() ? "shared.buyer" : "shared.seller"),
|
Res.get(selectedFailedTrade.getTaker() == selectedFailedTrade.getBuyer() ? "shared.buyer" : "shared.seller"),
|
||||||
Res.get("shared.taker"),
|
Res.get("shared.taker"),
|
||||||
selectedFailedTrade.getTakerFee(),
|
selectedFailedTrade.getTaker().getSecurityDeposit(),
|
||||||
selectedFailedTrade.getTaker().getReserveTxHash(),
|
selectedFailedTrade.getTaker().getReserveTxHash(),
|
||||||
selectedFailedTrade.getTaker().getReserveTxHex());
|
selectedFailedTrade.getTaker().getReserveTxHex());
|
||||||
});
|
});
|
||||||
|
@ -85,7 +85,7 @@ public class SignedOfferView extends ActivatableView<VBox, Void> {
|
|||||||
@FXML
|
@FXML
|
||||||
TableColumn<SignedOffer, SignedOffer> reserveTxMinerFeeColumn;
|
TableColumn<SignedOffer, SignedOffer> reserveTxMinerFeeColumn;
|
||||||
@FXML
|
@FXML
|
||||||
TableColumn<SignedOffer, SignedOffer> makerTradeFeeColumn;
|
TableColumn<SignedOffer, SignedOffer> makerPenaltyFeeColumn;
|
||||||
@FXML
|
@FXML
|
||||||
InputTextField filterTextField;
|
InputTextField filterTextField;
|
||||||
@FXML
|
@FXML
|
||||||
@ -163,7 +163,7 @@ public class SignedOfferView extends ActivatableView<VBox, Void> {
|
|||||||
if(selectedSignedOffer != null) {
|
if(selectedSignedOffer != null) {
|
||||||
new Popup().warning(Res.get("support.prompt.signedOffer.penalty.msg",
|
new Popup().warning(Res.get("support.prompt.signedOffer.penalty.msg",
|
||||||
selectedSignedOffer.getOfferId(),
|
selectedSignedOffer.getOfferId(),
|
||||||
HavenoUtils.formatXmr(selectedSignedOffer.getMakerTradeFee(), true),
|
HavenoUtils.formatXmr(selectedSignedOffer.getPenaltyAmount(), true),
|
||||||
HavenoUtils.formatXmr(selectedSignedOffer.getReserveTxMinerFee(), true),
|
HavenoUtils.formatXmr(selectedSignedOffer.getReserveTxMinerFee(), true),
|
||||||
selectedSignedOffer.getReserveTxHash(),
|
selectedSignedOffer.getReserveTxHash(),
|
||||||
selectedSignedOffer.getReserveTxKeyImages())
|
selectedSignedOffer.getReserveTxKeyImages())
|
||||||
@ -212,8 +212,8 @@ public class SignedOfferView extends ActivatableView<VBox, Void> {
|
|||||||
arbitratorSignatureColumn = getArbitratorSignatureColumn();
|
arbitratorSignatureColumn = getArbitratorSignatureColumn();
|
||||||
tableView.getColumns().add(arbitratorSignatureColumn);
|
tableView.getColumns().add(arbitratorSignatureColumn);
|
||||||
|
|
||||||
makerTradeFeeColumn = getMakerTradeFeeColumn();
|
makerPenaltyFeeColumn = getMakerPenaltyFeeColumn();
|
||||||
tableView.getColumns().add(makerTradeFeeColumn);
|
tableView.getColumns().add(makerPenaltyFeeColumn);
|
||||||
|
|
||||||
reserveTxMinerFeeColumn = getReserveTxMinerFeeColumn();
|
reserveTxMinerFeeColumn = getReserveTxMinerFeeColumn();
|
||||||
tableView.getColumns().add(reserveTxMinerFeeColumn);
|
tableView.getColumns().add(reserveTxMinerFeeColumn);
|
||||||
@ -389,8 +389,8 @@ public class SignedOfferView extends ActivatableView<VBox, Void> {
|
|||||||
return column;
|
return column;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TableColumn<SignedOffer, SignedOffer> getMakerTradeFeeColumn() {
|
private TableColumn<SignedOffer, SignedOffer> getMakerPenaltyFeeColumn() {
|
||||||
TableColumn<SignedOffer, SignedOffer> column = new AutoTooltipTableColumn<>(Res.get("support.maker.trade.fee")) {
|
TableColumn<SignedOffer, SignedOffer> column = new AutoTooltipTableColumn<>(Res.get("support.maker.penalty.fee")) {
|
||||||
{
|
{
|
||||||
setMinWidth(160);
|
setMinWidth(160);
|
||||||
}
|
}
|
||||||
@ -405,7 +405,7 @@ public class SignedOfferView extends ActivatableView<VBox, Void> {
|
|||||||
public void updateItem(final SignedOffer item, boolean empty) {
|
public void updateItem(final SignedOffer item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
if (item != null && !empty)
|
if (item != null && !empty)
|
||||||
setText(HavenoUtils.formatXmr(item.getMakerTradeFee(), true));
|
setText(HavenoUtils.formatXmr(item.getPenaltyAmount(), true));
|
||||||
else
|
else
|
||||||
setText("");
|
setText("");
|
||||||
}
|
}
|
||||||
|
@ -1351,7 +1351,7 @@ message SignedOffer {
|
|||||||
int64 time_stamp = 1;
|
int64 time_stamp = 1;
|
||||||
string offer_id = 2;
|
string offer_id = 2;
|
||||||
uint64 trade_amount = 3;
|
uint64 trade_amount = 3;
|
||||||
uint64 maker_trade_fee = 4;
|
uint64 penalty_amount = 4;
|
||||||
string reserve_tx_hash = 5;
|
string reserve_tx_hash = 5;
|
||||||
string reserve_tx_hex = 6;
|
string reserve_tx_hex = 6;
|
||||||
repeated string reserve_tx_key_images = 7;
|
repeated string reserve_tx_key_images = 7;
|
||||||
|
Loading…
Reference in New Issue
Block a user