mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-11-17 00:07:49 +00:00
enable editing offers
This commit is contained in:
parent
cb7d9364e5
commit
b2b4706f14
11 changed files with 93 additions and 26 deletions
|
@ -243,7 +243,7 @@ public class OfferFilterService {
|
|||
public boolean hasValidSignature(Offer offer) {
|
||||
Arbitrator arbitrator = user.getAcceptedArbitratorByAddress(offer.getOfferPayload().getArbitratorSigner());
|
||||
if (arbitrator == null) return false; // invalid arbitrator
|
||||
return HavenoUtils.isArbitratorSignatureValid(offer, arbitrator);
|
||||
return HavenoUtils.isArbitratorSignatureValid(offer.getOfferPayload(), arbitrator);
|
||||
}
|
||||
|
||||
public boolean isReservedFundsSpent(Offer offer) {
|
||||
|
|
|
@ -243,6 +243,52 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
|
|||
return this.hash;
|
||||
}
|
||||
|
||||
public byte[] getSignatureHash() {
|
||||
|
||||
// create copy with ignored fields standardized
|
||||
OfferPayload signee = new OfferPayload(
|
||||
id,
|
||||
date,
|
||||
ownerNodeAddress,
|
||||
pubKeyRing,
|
||||
direction,
|
||||
price,
|
||||
0,
|
||||
false,
|
||||
amount,
|
||||
minAmount,
|
||||
baseCurrencyCode,
|
||||
counterCurrencyCode,
|
||||
paymentMethodId,
|
||||
makerPaymentAccountId,
|
||||
offerFeeTxId,
|
||||
countryCode,
|
||||
acceptedCountryCodes,
|
||||
bankId,
|
||||
acceptedBankIds,
|
||||
versionNr,
|
||||
blockHeightAtOfferCreation,
|
||||
makerFee,
|
||||
buyerSecurityDeposit,
|
||||
sellerSecurityDeposit,
|
||||
maxTradeLimit,
|
||||
maxTradePeriod,
|
||||
useAutoClose,
|
||||
useReOpenAfterAutoClose,
|
||||
lowerClosePrice,
|
||||
upperClosePrice,
|
||||
isPrivateOffer,
|
||||
hashOfChallenge,
|
||||
extraDataMap,
|
||||
protocolVersion,
|
||||
arbitratorSigner,
|
||||
null,
|
||||
reserveTxKeyImages
|
||||
);
|
||||
|
||||
return signee.getHash();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTTL() {
|
||||
return TTL;
|
||||
|
|
|
@ -30,6 +30,7 @@ import lombok.Setter;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
@ -103,6 +104,21 @@ public final class OpenOffer implements Tradable {
|
|||
state = State.SCHEDULED;
|
||||
}
|
||||
|
||||
public OpenOffer(Offer offer, long triggerPrice, OpenOffer openOffer) {
|
||||
this.offer = offer;
|
||||
this.triggerPrice = triggerPrice;
|
||||
|
||||
// copy open offer fields
|
||||
this.state = openOffer.state;
|
||||
this.reserveExactAmount = openOffer.reserveExactAmount;
|
||||
this.scheduledAmount = openOffer.scheduledAmount;
|
||||
this.scheduledTxHashes = openOffer.scheduledTxHashes == null ? null : new ArrayList<String>(openOffer.scheduledTxHashes);
|
||||
this.splitOutputTxHash = openOffer.splitOutputTxHash;
|
||||
this.reserveTxHash = openOffer.reserveTxHash;
|
||||
this.reserveTxHex = openOffer.reserveTxHex;
|
||||
this.reserveTxKey = openOffer.reserveTxKey;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PROTO BUFFER
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -624,7 +624,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
openOffer.setState(OpenOffer.State.CANCELED);
|
||||
removeOpenOffer(openOffer);
|
||||
|
||||
OpenOffer editedOpenOffer = new OpenOffer(editedOffer, triggerPrice);
|
||||
OpenOffer editedOpenOffer = new OpenOffer(editedOffer, triggerPrice, openOffer);
|
||||
editedOpenOffer.setState(originalState);
|
||||
|
||||
addOpenOffer(editedOpenOffer);
|
||||
|
@ -1172,8 +1172,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
true);
|
||||
|
||||
// arbitrator signs offer to certify they have valid reserve tx
|
||||
String offerPayloadAsJson = JsonUtil.objectToJson(request.getOfferPayload());
|
||||
byte[] signature = HavenoUtils.sign(keyRing, offerPayloadAsJson);
|
||||
byte[] signature = HavenoUtils.signOffer(request.getOfferPayload(), keyRing);
|
||||
OfferPayload signedOfferPayload = request.getOfferPayload();
|
||||
signedOfferPayload.setArbitratorSignature(signature);
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ public class MakerProcessSignOfferResponse extends Task<PlaceOfferModel> {
|
|||
Arbitrator arbitrator = checkNotNull(model.getUser().getAcceptedArbitratorByAddress(offer.getOfferPayload().getArbitratorSigner()), "user.getAcceptedArbitratorByAddress(arbitratorSigner) must not be null");
|
||||
|
||||
// validate arbitrator signature
|
||||
if (!HavenoUtils.isArbitratorSignatureValid(new Offer(model.getSignOfferResponse().getSignedOfferPayload()), arbitrator)) {
|
||||
if (!HavenoUtils.isArbitratorSignatureValid(model.getSignOfferResponse().getSignedOfferPayload(), arbitrator)) {
|
||||
throw new RuntimeException("Offer payload has invalid arbitrator signature");
|
||||
}
|
||||
|
||||
|
|
|
@ -20,13 +20,13 @@ package haveno.core.trade;
|
|||
import com.google.common.base.CaseFormat;
|
||||
import com.google.common.base.Charsets;
|
||||
import haveno.common.config.Config;
|
||||
import haveno.common.crypto.CryptoException;
|
||||
import haveno.common.crypto.Hash;
|
||||
import haveno.common.crypto.KeyRing;
|
||||
import haveno.common.crypto.PubKeyRing;
|
||||
import haveno.common.crypto.Sig;
|
||||
import haveno.common.util.Utilities;
|
||||
import haveno.core.app.HavenoSetup;
|
||||
import haveno.core.offer.Offer;
|
||||
import haveno.core.offer.OfferPayload;
|
||||
import haveno.core.support.dispute.arbitration.ArbitrationManager;
|
||||
import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator;
|
||||
|
@ -245,6 +245,10 @@ public class HavenoUtils {
|
|||
return sign(keyRing.getSignatureKeyPair().getPrivate(), message);
|
||||
}
|
||||
|
||||
public static byte[] sign(KeyRing keyRing, byte[] bytes) {
|
||||
return sign(keyRing.getSignatureKeyPair().getPrivate(), bytes);
|
||||
}
|
||||
|
||||
public static byte[] sign(PrivateKey privateKey, String message) {
|
||||
return sign(privateKey, message.getBytes(Charsets.UTF_8));
|
||||
}
|
||||
|
@ -263,9 +267,10 @@ public class HavenoUtils {
|
|||
|
||||
public static void verifySignature(PubKeyRing pubKeyRing, byte[] bytes, byte[] signature) {
|
||||
try {
|
||||
Sig.verify(pubKeyRing.getSignaturePubKey(), bytes, signature);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
boolean isValid = Sig.verify(pubKeyRing.getSignaturePubKey(), bytes, signature);
|
||||
if (!isValid) throw new IllegalArgumentException("Signature verification failed.");
|
||||
} catch (CryptoException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -282,6 +287,17 @@ public class HavenoUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign an offer.
|
||||
*
|
||||
* @param offer is an unsigned offer to sign
|
||||
* @param keyRing is the arbitrator's key ring to sign with
|
||||
* @return the arbitrator's signature
|
||||
*/
|
||||
public static byte[] signOffer(OfferPayload offer, KeyRing keyRing) {
|
||||
return HavenoUtils.sign(keyRing, offer.getSignatureHash());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the arbitrator signature is valid for an offer.
|
||||
*
|
||||
|
@ -289,20 +305,8 @@ public class HavenoUtils {
|
|||
* @param arbitrator is the original signing arbitrator
|
||||
* @return true if the arbitrator's signature is valid for the offer
|
||||
*/
|
||||
public static boolean isArbitratorSignatureValid(Offer offer, Arbitrator arbitrator) {
|
||||
|
||||
// copy offer payload
|
||||
OfferPayload offerPayloadCopy = OfferPayload.fromProto(offer.toProtoMessage().getOfferPayload());
|
||||
|
||||
// remove arbitrator signature from signed payload
|
||||
byte[] signature = offerPayloadCopy.getArbitratorSignature();
|
||||
offerPayloadCopy.setArbitratorSignature(null);
|
||||
|
||||
// get unsigned offer payload as json string
|
||||
String unsignedOfferAsJson = JsonUtil.objectToJson(offerPayloadCopy);
|
||||
|
||||
// verify signature
|
||||
return isSignatureValid(arbitrator.getPubKeyRing(), unsignedOfferAsJson, signature);
|
||||
public static boolean isArbitratorSignatureValid(OfferPayload offer, Arbitrator arbitrator) {
|
||||
return isSignatureValid(arbitrator.getPubKeyRing(), offer.getSignatureHash(), offer.getArbitratorSignature());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -71,6 +71,7 @@ public class ArbitratorProcessReserveTx extends TradeTask {
|
|||
null,
|
||||
true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("Error processing reserve tx from " + (isFromTaker ? "taker " : "maker ") + request.getSenderNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage());
|
||||
}
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ public class FormattingUtils {
|
|||
}
|
||||
|
||||
public static String formatPrice(Price price) {
|
||||
return formatPrice(price, getPriceMonetaryFormat(price.getCurrencyCode()), false);
|
||||
return formatPrice(price, price == null ? null : getPriceMonetaryFormat(price.getCurrencyCode()), false);
|
||||
}
|
||||
|
||||
public static String formatMarketPrice(double price, String currencyCode) {
|
||||
|
|
|
@ -467,6 +467,7 @@ public class XmrWalletService {
|
|||
* @return tuple with the verified tx and its actual security deposit
|
||||
*/
|
||||
public Tuple2<MoneroTx, BigInteger> verifyTradeTx(String offerId, BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address, String txHash, String txHex, String txKey, List<String> keyImages, boolean isReserveTx) {
|
||||
if (txHash == null) throw new IllegalArgumentException("Cannot verify trade tx with null id");
|
||||
MoneroDaemonRpc daemon = getDaemon();
|
||||
MoneroWallet wallet = getWallet();
|
||||
MoneroTx tx = null;
|
||||
|
|
|
@ -1078,7 +1078,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
|
|||
hbox.setSpacing(8);
|
||||
hbox.setAlignment(Pos.CENTER);
|
||||
hbox.getChildren().add(button);
|
||||
//hbox.getChildren().add(button2); // TODO: re-enable editing offers
|
||||
hbox.getChildren().add(button2);
|
||||
HBox.setHgrow(button, Priority.ALWAYS);
|
||||
HBox.setHgrow(button2, Priority.ALWAYS);
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
setPaymentMethodColumnCellFactory();
|
||||
setDateColumnCellFactory();
|
||||
setDeactivateColumnCellFactory();
|
||||
// setEditColumnCellFactory(); // TODO: re-enable to edit offer price, etc?
|
||||
setEditColumnCellFactory();
|
||||
setTriggerIconColumnCellFactory();
|
||||
setTriggerPriceColumnCellFactory();
|
||||
setRemoveColumnCellFactory();
|
||||
|
|
Loading…
Reference in a new issue