mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-11-17 00:07:49 +00:00
minimum support for account witness verification & storage based on bisq
verify peer witness data and share with arbitrator for signing arbitrator can sign witness hash, owner pub key (see developer-guide.md) taker signs offer id nonce in SendOfferAvailabilityRequest maker signs deposit tx hash in SendSignContractRequest buyer verifies witness with payload on deposit confirmation seller verifies witness with payload on payment sent message add synchronization to User paymentAccountsAsObservable and elsewhere
This commit is contained in:
parent
963d92478d
commit
646380bc7a
28 changed files with 210 additions and 98 deletions
|
@ -64,7 +64,7 @@ public class AccountAgeWitness implements ProcessOncePersistableNetworkPayload,
|
||||||
return protobuf.PersistableNetworkPayload.newBuilder().setAccountAgeWitness(builder).build();
|
return protobuf.PersistableNetworkPayload.newBuilder().setAccountAgeWitness(builder).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
protobuf.AccountAgeWitness toProtoAccountAgeWitness() {
|
public protobuf.AccountAgeWitness toProtoAccountAgeWitness() {
|
||||||
return toProtoMessage().getAccountAgeWitness();
|
return toProtoMessage().getAccountAgeWitness();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -531,6 +531,15 @@ public class AccountAgeWitnessService {
|
||||||
byte[] nonce,
|
byte[] nonce,
|
||||||
byte[] signature,
|
byte[] signature,
|
||||||
ErrorMessageHandler errorMessageHandler) {
|
ErrorMessageHandler errorMessageHandler) {
|
||||||
|
|
||||||
|
log.info("Verifying account age witness for {} {}, payment account payload hash={}, peers current date={}, nonce={}, signature={}",
|
||||||
|
trade.getClass().getSimpleName(),
|
||||||
|
trade.getId(),
|
||||||
|
Utilities.bytesAsHexString(peersPaymentAccountPayload.getHash()),
|
||||||
|
peersCurrentDate,
|
||||||
|
Utilities.bytesAsHexString(nonce),
|
||||||
|
Utilities.bytesAsHexString(signature));
|
||||||
|
|
||||||
final Optional<AccountAgeWitness> accountAgeWitnessOptional =
|
final Optional<AccountAgeWitness> accountAgeWitnessOptional =
|
||||||
findWitness(peersPaymentAccountPayload, peersPubKeyRing);
|
findWitness(peersPaymentAccountPayload, peersPubKeyRing);
|
||||||
// If we don't find a stored witness data we create a new dummy object which makes is easier to reuse the
|
// If we don't find a stored witness data we create a new dummy object which makes is easier to reuse the
|
||||||
|
|
|
@ -31,6 +31,7 @@ import com.google.protobuf.ByteString;
|
||||||
import bisq.common.crypto.PubKeyRing;
|
import bisq.common.crypto.PubKeyRing;
|
||||||
import bisq.common.proto.network.NetworkPayload;
|
import bisq.common.proto.network.NetworkPayload;
|
||||||
import bisq.common.util.JsonExclude;
|
import bisq.common.util.JsonExclude;
|
||||||
|
import bisq.common.util.Utilities;
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
|
||||||
|
@ -289,8 +290,8 @@ public final class Contract implements NetworkPayload {
|
||||||
",\n takerAccountId='" + takerAccountId + '\'' +
|
",\n takerAccountId='" + takerAccountId + '\'' +
|
||||||
",\n makerPaymentMethodId='" + makerPaymentMethodId + '\'' +
|
",\n makerPaymentMethodId='" + makerPaymentMethodId + '\'' +
|
||||||
",\n takerPaymentMethodId='" + takerPaymentMethodId + '\'' +
|
",\n takerPaymentMethodId='" + takerPaymentMethodId + '\'' +
|
||||||
",\n makerPaymentAccountPayloadHash=" + makerPaymentAccountPayloadHash +
|
",\n makerPaymentAccountPayloadHash=" + Utilities.bytesAsHexString(makerPaymentAccountPayloadHash) +
|
||||||
",\n takerPaymentAccountPayloadHash=" + takerPaymentAccountPayloadHash +
|
",\n takerPaymentAccountPayloadHash=" + Utilities.bytesAsHexString(takerPaymentAccountPayloadHash) +
|
||||||
",\n makerPubKeyRing=" + makerPubKeyRing +
|
",\n makerPubKeyRing=" + makerPubKeyRing +
|
||||||
",\n takerPubKeyRing=" + takerPubKeyRing +
|
",\n takerPubKeyRing=" + takerPubKeyRing +
|
||||||
",\n makerPayoutAddressString='" + makerPayoutAddressString + '\'' +
|
",\n makerPayoutAddressString='" + makerPayoutAddressString + '\'' +
|
||||||
|
|
|
@ -1020,8 +1020,10 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Trade> getOpenTrade(String tradeId) {
|
public Optional<Trade> getOpenTrade(String tradeId) {
|
||||||
|
synchronized (tradableList) {
|
||||||
return tradableList.stream().filter(e -> e.getId().equals(tradeId)).findFirst();
|
return tradableList.stream().filter(e -> e.getId().equals(tradeId)).findFirst();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<Trade> getOpenTrades() {
|
public List<Trade> getOpenTrades() {
|
||||||
return ImmutableList.copyOf(getObservableList().stream()
|
return ImmutableList.copyOf(getObservableList().stream()
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
package bisq.core.trade.messages;
|
package bisq.core.trade.messages;
|
||||||
|
|
||||||
import bisq.core.account.sign.SignedWitness;
|
import bisq.core.account.sign.SignedWitness;
|
||||||
|
import bisq.core.account.witness.AccountAgeWitness;
|
||||||
import bisq.network.p2p.NodeAddress;
|
import bisq.network.p2p.NodeAddress;
|
||||||
|
|
||||||
import bisq.common.app.Version;
|
import bisq.common.app.Version;
|
||||||
|
@ -31,7 +31,6 @@ import java.util.UUID;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.Value;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -49,32 +48,34 @@ public final class PaymentReceivedMessage extends TradeMailboxMessage {
|
||||||
private final String signedPayoutTxHex;
|
private final String signedPayoutTxHex;
|
||||||
private final String updatedMultisigHex;
|
private final String updatedMultisigHex;
|
||||||
private final boolean deferPublishPayout;
|
private final boolean deferPublishPayout;
|
||||||
|
@Nullable
|
||||||
|
private final AccountAgeWitness buyerAccountAgeWitness;
|
||||||
|
@Nullable
|
||||||
|
private final SignedWitness buyerSignedWitness;
|
||||||
private final PaymentSentMessage paymentSentMessage;
|
private final PaymentSentMessage paymentSentMessage;
|
||||||
@Setter
|
@Setter
|
||||||
@Nullable
|
@Nullable
|
||||||
private byte[] sellerSignature;
|
private byte[] sellerSignature;
|
||||||
|
|
||||||
// Added in v1.4.0
|
|
||||||
@Nullable
|
|
||||||
private final SignedWitness signedWitness;
|
|
||||||
|
|
||||||
public PaymentReceivedMessage(String tradeId,
|
public PaymentReceivedMessage(String tradeId,
|
||||||
NodeAddress senderNodeAddress,
|
NodeAddress senderNodeAddress,
|
||||||
@Nullable SignedWitness signedWitness,
|
|
||||||
String unsignedPayoutTxHex,
|
String unsignedPayoutTxHex,
|
||||||
String signedPayoutTxHex,
|
String signedPayoutTxHex,
|
||||||
String updatedMultisigHex,
|
String updatedMultisigHex,
|
||||||
boolean deferPublishPayout,
|
boolean deferPublishPayout,
|
||||||
|
AccountAgeWitness buyerAccountAgeWitness,
|
||||||
|
@Nullable SignedWitness buyerSignedWitness,
|
||||||
PaymentSentMessage paymentSentMessage) {
|
PaymentSentMessage paymentSentMessage) {
|
||||||
this(tradeId,
|
this(tradeId,
|
||||||
senderNodeAddress,
|
senderNodeAddress,
|
||||||
signedWitness,
|
|
||||||
UUID.randomUUID().toString(),
|
UUID.randomUUID().toString(),
|
||||||
Version.getP2PMessageVersion(),
|
Version.getP2PMessageVersion(),
|
||||||
unsignedPayoutTxHex,
|
unsignedPayoutTxHex,
|
||||||
signedPayoutTxHex,
|
signedPayoutTxHex,
|
||||||
updatedMultisigHex,
|
updatedMultisigHex,
|
||||||
deferPublishPayout,
|
deferPublishPayout,
|
||||||
|
buyerAccountAgeWitness,
|
||||||
|
buyerSignedWitness,
|
||||||
paymentSentMessage);
|
paymentSentMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,22 +86,24 @@ public final class PaymentReceivedMessage extends TradeMailboxMessage {
|
||||||
|
|
||||||
private PaymentReceivedMessage(String tradeId,
|
private PaymentReceivedMessage(String tradeId,
|
||||||
NodeAddress senderNodeAddress,
|
NodeAddress senderNodeAddress,
|
||||||
@Nullable SignedWitness signedWitness,
|
|
||||||
String uid,
|
String uid,
|
||||||
String messageVersion,
|
String messageVersion,
|
||||||
String unsignedPayoutTxHex,
|
String unsignedPayoutTxHex,
|
||||||
String signedPayoutTxHex,
|
String signedPayoutTxHex,
|
||||||
String updatedMultisigHex,
|
String updatedMultisigHex,
|
||||||
boolean deferPublishPayout,
|
boolean deferPublishPayout,
|
||||||
|
AccountAgeWitness buyerAccountAgeWitness,
|
||||||
|
@Nullable SignedWitness buyerSignedWitness,
|
||||||
PaymentSentMessage paymentSentMessage) {
|
PaymentSentMessage paymentSentMessage) {
|
||||||
super(messageVersion, tradeId, uid);
|
super(messageVersion, tradeId, uid);
|
||||||
this.senderNodeAddress = senderNodeAddress;
|
this.senderNodeAddress = senderNodeAddress;
|
||||||
this.signedWitness = signedWitness;
|
|
||||||
this.unsignedPayoutTxHex = unsignedPayoutTxHex;
|
this.unsignedPayoutTxHex = unsignedPayoutTxHex;
|
||||||
this.signedPayoutTxHex = signedPayoutTxHex;
|
this.signedPayoutTxHex = signedPayoutTxHex;
|
||||||
this.updatedMultisigHex = updatedMultisigHex;
|
this.updatedMultisigHex = updatedMultisigHex;
|
||||||
this.deferPublishPayout = deferPublishPayout;
|
this.deferPublishPayout = deferPublishPayout;
|
||||||
this.paymentSentMessage = paymentSentMessage;
|
this.paymentSentMessage = paymentSentMessage;
|
||||||
|
this.buyerAccountAgeWitness = buyerAccountAgeWitness;
|
||||||
|
this.buyerSignedWitness = buyerSignedWitness;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -110,10 +113,11 @@ public final class PaymentReceivedMessage extends TradeMailboxMessage {
|
||||||
.setSenderNodeAddress(senderNodeAddress.toProtoMessage())
|
.setSenderNodeAddress(senderNodeAddress.toProtoMessage())
|
||||||
.setUid(uid)
|
.setUid(uid)
|
||||||
.setDeferPublishPayout(deferPublishPayout);
|
.setDeferPublishPayout(deferPublishPayout);
|
||||||
Optional.ofNullable(signedWitness).ifPresent(signedWitness -> builder.setSignedWitness(signedWitness.toProtoSignedWitness()));
|
|
||||||
Optional.ofNullable(updatedMultisigHex).ifPresent(e -> builder.setUpdatedMultisigHex(updatedMultisigHex));
|
Optional.ofNullable(updatedMultisigHex).ifPresent(e -> builder.setUpdatedMultisigHex(updatedMultisigHex));
|
||||||
Optional.ofNullable(unsignedPayoutTxHex).ifPresent(e -> builder.setUnsignedPayoutTxHex(unsignedPayoutTxHex));
|
Optional.ofNullable(unsignedPayoutTxHex).ifPresent(e -> builder.setUnsignedPayoutTxHex(unsignedPayoutTxHex));
|
||||||
Optional.ofNullable(signedPayoutTxHex).ifPresent(e -> builder.setSignedPayoutTxHex(signedPayoutTxHex));
|
Optional.ofNullable(signedPayoutTxHex).ifPresent(e -> builder.setSignedPayoutTxHex(signedPayoutTxHex));
|
||||||
|
Optional.ofNullable(buyerAccountAgeWitness).ifPresent(buyerAccountAgeWitness -> builder.setBuyerAccountAgeWitness(buyerAccountAgeWitness.toProtoAccountAgeWitness()));
|
||||||
|
Optional.ofNullable(buyerSignedWitness).ifPresent(buyerSignedWitness -> builder.setBuyerSignedWitness(buyerSignedWitness.toProtoSignedWitness()));
|
||||||
Optional.ofNullable(paymentSentMessage).ifPresent(e -> builder.setPaymentSentMessage(paymentSentMessage.toProtoNetworkEnvelope().getPaymentSentMessage()));
|
Optional.ofNullable(paymentSentMessage).ifPresent(e -> builder.setPaymentSentMessage(paymentSentMessage.toProtoNetworkEnvelope().getPaymentSentMessage()));
|
||||||
Optional.ofNullable(sellerSignature).ifPresent(e -> builder.setSellerSignature(ByteString.copyFrom(e)));
|
Optional.ofNullable(sellerSignature).ifPresent(e -> builder.setSellerSignature(ByteString.copyFrom(e)));
|
||||||
return getNetworkEnvelopeBuilder().setPaymentReceivedMessage(builder).build();
|
return getNetworkEnvelopeBuilder().setPaymentReceivedMessage(builder).build();
|
||||||
|
@ -121,20 +125,23 @@ public final class PaymentReceivedMessage extends TradeMailboxMessage {
|
||||||
|
|
||||||
public static NetworkEnvelope fromProto(protobuf.PaymentReceivedMessage proto, String messageVersion) {
|
public static NetworkEnvelope fromProto(protobuf.PaymentReceivedMessage proto, String messageVersion) {
|
||||||
// There is no method to check for a nullable non-primitive data type object but we know that all fields
|
// There is no method to check for a nullable non-primitive data type object but we know that all fields
|
||||||
// are empty/null, so we check for the signature to see if we got a valid signedWitness.
|
// are empty/null, so we check for the signature to see if we got a valid buyerSignedWitness.
|
||||||
protobuf.SignedWitness protoSignedWitness = proto.getSignedWitness();
|
protobuf.AccountAgeWitness protoAccountAgeWitness = proto.getBuyerAccountAgeWitness();
|
||||||
SignedWitness signedWitness = !protoSignedWitness.getSignature().isEmpty() ?
|
AccountAgeWitness buyerAccountAgeWitness = protoAccountAgeWitness.getHash().isEmpty() ? null : AccountAgeWitness.fromProto(protoAccountAgeWitness);
|
||||||
|
protobuf.SignedWitness protoSignedWitness = proto.getBuyerSignedWitness();
|
||||||
|
SignedWitness buyerSignedWitness = !protoSignedWitness.getSignature().isEmpty() ?
|
||||||
SignedWitness.fromProto(protoSignedWitness) :
|
SignedWitness.fromProto(protoSignedWitness) :
|
||||||
null;
|
null;
|
||||||
PaymentReceivedMessage message = new PaymentReceivedMessage(proto.getTradeId(),
|
PaymentReceivedMessage message = new PaymentReceivedMessage(proto.getTradeId(),
|
||||||
NodeAddress.fromProto(proto.getSenderNodeAddress()),
|
NodeAddress.fromProto(proto.getSenderNodeAddress()),
|
||||||
signedWitness,
|
|
||||||
proto.getUid(),
|
proto.getUid(),
|
||||||
messageVersion,
|
messageVersion,
|
||||||
ProtoUtil.stringOrNullFromProto(proto.getUnsignedPayoutTxHex()),
|
ProtoUtil.stringOrNullFromProto(proto.getUnsignedPayoutTxHex()),
|
||||||
ProtoUtil.stringOrNullFromProto(proto.getSignedPayoutTxHex()),
|
ProtoUtil.stringOrNullFromProto(proto.getSignedPayoutTxHex()),
|
||||||
ProtoUtil.stringOrNullFromProto(proto.getUpdatedMultisigHex()),
|
ProtoUtil.stringOrNullFromProto(proto.getUpdatedMultisigHex()),
|
||||||
proto.getDeferPublishPayout(),
|
proto.getDeferPublishPayout(),
|
||||||
|
buyerAccountAgeWitness,
|
||||||
|
buyerSignedWitness,
|
||||||
proto.hasPaymentSentMessage() ? PaymentSentMessage.fromProto(proto.getPaymentSentMessage(), messageVersion) : null);
|
proto.hasPaymentSentMessage() ? PaymentSentMessage.fromProto(proto.getPaymentSentMessage(), messageVersion) : null);
|
||||||
message.setSellerSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getSellerSignature()));
|
message.setSellerSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getSellerSignature()));
|
||||||
return message;
|
return message;
|
||||||
|
@ -144,7 +151,7 @@ public final class PaymentReceivedMessage extends TradeMailboxMessage {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PaymentReceivedMessage{" +
|
return "PaymentReceivedMessage{" +
|
||||||
"\n senderNodeAddress=" + senderNodeAddress +
|
"\n senderNodeAddress=" + senderNodeAddress +
|
||||||
",\n signedWitness=" + signedWitness +
|
",\n buyerSignedWitness=" + buyerSignedWitness +
|
||||||
",\n unsignedPayoutTxHex=" + unsignedPayoutTxHex +
|
",\n unsignedPayoutTxHex=" + unsignedPayoutTxHex +
|
||||||
",\n signedPayoutTxHex=" + signedPayoutTxHex +
|
",\n signedPayoutTxHex=" + signedPayoutTxHex +
|
||||||
",\n updatedMultisigHex=" + (updatedMultisigHex == null ? null : updatedMultisigHex.substring(0, Math.max(updatedMultisigHex.length(), 1000))) +
|
",\n updatedMultisigHex=" + (updatedMultisigHex == null ? null : updatedMultisigHex.substring(0, Math.max(updatedMultisigHex.length(), 1000))) +
|
||||||
|
|
|
@ -21,6 +21,7 @@ import bisq.network.p2p.NodeAddress;
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
import bisq.common.app.Version;
|
import bisq.common.app.Version;
|
||||||
import bisq.common.proto.ProtoUtil;
|
import bisq.common.proto.ProtoUtil;
|
||||||
|
import bisq.core.account.witness.AccountAgeWitness;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@ -42,6 +43,8 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
private final String updatedMultisigHex;
|
private final String updatedMultisigHex;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final byte[] paymentAccountKey;
|
private final byte[] paymentAccountKey;
|
||||||
|
@Nullable
|
||||||
|
private AccountAgeWitness sellerAccountAgeWitness;
|
||||||
@Setter
|
@Setter
|
||||||
@Nullable
|
@Nullable
|
||||||
private byte[] buyerSignature;
|
private byte[] buyerSignature;
|
||||||
|
@ -58,7 +61,8 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
String uid,
|
String uid,
|
||||||
@Nullable String signedPayoutTxHex,
|
@Nullable String signedPayoutTxHex,
|
||||||
@Nullable String updatedMultisigHex,
|
@Nullable String updatedMultisigHex,
|
||||||
@Nullable byte[] paymentAccountKey) {
|
@Nullable byte[] paymentAccountKey,
|
||||||
|
AccountAgeWitness sellerAccountAgeWitness) {
|
||||||
this(tradeId,
|
this(tradeId,
|
||||||
senderNodeAddress,
|
senderNodeAddress,
|
||||||
counterCurrencyTxId,
|
counterCurrencyTxId,
|
||||||
|
@ -67,7 +71,8 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
Version.getP2PMessageVersion(),
|
Version.getP2PMessageVersion(),
|
||||||
signedPayoutTxHex,
|
signedPayoutTxHex,
|
||||||
updatedMultisigHex,
|
updatedMultisigHex,
|
||||||
paymentAccountKey);
|
paymentAccountKey,
|
||||||
|
sellerAccountAgeWitness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,7 +88,8 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
String messageVersion,
|
String messageVersion,
|
||||||
@Nullable String signedPayoutTxHex,
|
@Nullable String signedPayoutTxHex,
|
||||||
@Nullable String updatedMultisigHex,
|
@Nullable String updatedMultisigHex,
|
||||||
@Nullable byte[] paymentAccountKey) {
|
@Nullable byte[] paymentAccountKey,
|
||||||
|
AccountAgeWitness sellerAccountAgeWitness) {
|
||||||
super(messageVersion, tradeId, uid);
|
super(messageVersion, tradeId, uid);
|
||||||
this.senderNodeAddress = senderNodeAddress;
|
this.senderNodeAddress = senderNodeAddress;
|
||||||
this.counterCurrencyTxId = counterCurrencyTxId;
|
this.counterCurrencyTxId = counterCurrencyTxId;
|
||||||
|
@ -91,6 +97,7 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
this.payoutTxHex = signedPayoutTxHex;
|
this.payoutTxHex = signedPayoutTxHex;
|
||||||
this.updatedMultisigHex = updatedMultisigHex;
|
this.updatedMultisigHex = updatedMultisigHex;
|
||||||
this.paymentAccountKey = paymentAccountKey;
|
this.paymentAccountKey = paymentAccountKey;
|
||||||
|
this.sellerAccountAgeWitness = sellerAccountAgeWitness;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -106,12 +113,17 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
Optional.ofNullable(updatedMultisigHex).ifPresent(e -> builder.setUpdatedMultisigHex(updatedMultisigHex));
|
Optional.ofNullable(updatedMultisigHex).ifPresent(e -> builder.setUpdatedMultisigHex(updatedMultisigHex));
|
||||||
Optional.ofNullable(paymentAccountKey).ifPresent(e -> builder.setPaymentAccountKey(ByteString.copyFrom(e)));
|
Optional.ofNullable(paymentAccountKey).ifPresent(e -> builder.setPaymentAccountKey(ByteString.copyFrom(e)));
|
||||||
Optional.ofNullable(buyerSignature).ifPresent(e -> builder.setBuyerSignature(ByteString.copyFrom(e)));
|
Optional.ofNullable(buyerSignature).ifPresent(e -> builder.setBuyerSignature(ByteString.copyFrom(e)));
|
||||||
|
Optional.ofNullable(sellerAccountAgeWitness).ifPresent(e -> builder.setSellerAccountAgeWitness(sellerAccountAgeWitness.toProtoAccountAgeWitness()));
|
||||||
|
|
||||||
return getNetworkEnvelopeBuilder().setPaymentSentMessage(builder).build();
|
return getNetworkEnvelopeBuilder().setPaymentSentMessage(builder).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PaymentSentMessage fromProto(protobuf.PaymentSentMessage proto,
|
public static PaymentSentMessage fromProto(protobuf.PaymentSentMessage proto,
|
||||||
String messageVersion) {
|
String messageVersion) {
|
||||||
|
|
||||||
|
protobuf.AccountAgeWitness protoAccountAgeWitness = proto.getSellerAccountAgeWitness();
|
||||||
|
AccountAgeWitness accountAgeWitness = protoAccountAgeWitness.getHash().isEmpty() ? null : AccountAgeWitness.fromProto(protoAccountAgeWitness);
|
||||||
|
|
||||||
PaymentSentMessage message = new PaymentSentMessage(proto.getTradeId(),
|
PaymentSentMessage message = new PaymentSentMessage(proto.getTradeId(),
|
||||||
NodeAddress.fromProto(proto.getSenderNodeAddress()),
|
NodeAddress.fromProto(proto.getSenderNodeAddress()),
|
||||||
ProtoUtil.stringOrNullFromProto(proto.getCounterCurrencyTxId()),
|
ProtoUtil.stringOrNullFromProto(proto.getCounterCurrencyTxId()),
|
||||||
|
@ -120,7 +132,8 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
messageVersion,
|
messageVersion,
|
||||||
ProtoUtil.stringOrNullFromProto(proto.getPayoutTxHex()),
|
ProtoUtil.stringOrNullFromProto(proto.getPayoutTxHex()),
|
||||||
ProtoUtil.stringOrNullFromProto(proto.getUpdatedMultisigHex()),
|
ProtoUtil.stringOrNullFromProto(proto.getUpdatedMultisigHex()),
|
||||||
ProtoUtil.byteArrayOrNullFromProto(proto.getPaymentAccountKey())
|
ProtoUtil.byteArrayOrNullFromProto(proto.getPaymentAccountKey()),
|
||||||
|
accountAgeWitness
|
||||||
);
|
);
|
||||||
message.setBuyerSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getBuyerSignature()));
|
message.setBuyerSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getBuyerSignature()));
|
||||||
return message;
|
return message;
|
||||||
|
|
|
@ -21,9 +21,15 @@ import bisq.core.proto.CoreProtoResolver;
|
||||||
|
|
||||||
import bisq.network.p2p.DirectMessage;
|
import bisq.network.p2p.DirectMessage;
|
||||||
import bisq.network.p2p.NodeAddress;
|
import bisq.network.p2p.NodeAddress;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
import bisq.common.crypto.PubKeyRing;
|
import bisq.common.crypto.PubKeyRing;
|
||||||
|
import bisq.common.proto.ProtoUtil;
|
||||||
|
import bisq.common.util.Utilities;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
|
||||||
|
@ -37,6 +43,7 @@ public final class SignContractRequest extends TradeMessage implements DirectMes
|
||||||
private final byte[] paymentAccountPayloadHash;
|
private final byte[] paymentAccountPayloadHash;
|
||||||
private final String payoutAddress;
|
private final String payoutAddress;
|
||||||
private final String depositTxHash;
|
private final String depositTxHash;
|
||||||
|
private final byte[] accountAgeWitnessSignatureOfDepositHash;
|
||||||
|
|
||||||
public SignContractRequest(String tradeId,
|
public SignContractRequest(String tradeId,
|
||||||
NodeAddress senderNodeAddress,
|
NodeAddress senderNodeAddress,
|
||||||
|
@ -47,7 +54,8 @@ public final class SignContractRequest extends TradeMessage implements DirectMes
|
||||||
String accountId,
|
String accountId,
|
||||||
byte[] paymentAccountPayloadHash,
|
byte[] paymentAccountPayloadHash,
|
||||||
String payoutAddress,
|
String payoutAddress,
|
||||||
String depositTxHash) {
|
String depositTxHash,
|
||||||
|
@Nullable byte[] accountAgeWitnessSignatureOfDepositHash) {
|
||||||
super(messageVersion, tradeId, uid);
|
super(messageVersion, tradeId, uid);
|
||||||
this.senderNodeAddress = senderNodeAddress;
|
this.senderNodeAddress = senderNodeAddress;
|
||||||
this.pubKeyRing = pubKeyRing;
|
this.pubKeyRing = pubKeyRing;
|
||||||
|
@ -56,6 +64,7 @@ public final class SignContractRequest extends TradeMessage implements DirectMes
|
||||||
this.paymentAccountPayloadHash = paymentAccountPayloadHash;
|
this.paymentAccountPayloadHash = paymentAccountPayloadHash;
|
||||||
this.payoutAddress = payoutAddress;
|
this.payoutAddress = payoutAddress;
|
||||||
this.depositTxHash = depositTxHash;
|
this.depositTxHash = depositTxHash;
|
||||||
|
this.accountAgeWitnessSignatureOfDepositHash = accountAgeWitnessSignatureOfDepositHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,6 +84,7 @@ public final class SignContractRequest extends TradeMessage implements DirectMes
|
||||||
.setPayoutAddress(payoutAddress)
|
.setPayoutAddress(payoutAddress)
|
||||||
.setDepositTxHash(depositTxHash);
|
.setDepositTxHash(depositTxHash);
|
||||||
|
|
||||||
|
Optional.ofNullable(accountAgeWitnessSignatureOfDepositHash).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfDepositHash(ByteString.copyFrom(e)));
|
||||||
builder.setCurrentDate(currentDate);
|
builder.setCurrentDate(currentDate);
|
||||||
|
|
||||||
return getNetworkEnvelopeBuilder().setSignContractRequest(builder).build();
|
return getNetworkEnvelopeBuilder().setSignContractRequest(builder).build();
|
||||||
|
@ -92,7 +102,8 @@ public final class SignContractRequest extends TradeMessage implements DirectMes
|
||||||
proto.getAccountId(),
|
proto.getAccountId(),
|
||||||
proto.getPaymentAccountPayloadHash().toByteArray(),
|
proto.getPaymentAccountPayloadHash().toByteArray(),
|
||||||
proto.getPayoutAddress(),
|
proto.getPayoutAddress(),
|
||||||
proto.getDepositTxHash());
|
proto.getDepositTxHash(),
|
||||||
|
ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfDepositHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -102,9 +113,10 @@ public final class SignContractRequest extends TradeMessage implements DirectMes
|
||||||
",\n pubKeyRing=" + pubKeyRing +
|
",\n pubKeyRing=" + pubKeyRing +
|
||||||
",\n currentDate=" + currentDate +
|
",\n currentDate=" + currentDate +
|
||||||
",\n accountId=" + accountId +
|
",\n accountId=" + accountId +
|
||||||
",\n paymentAccountPayloadHash='" + paymentAccountPayloadHash +
|
",\n paymentAccountPayloadHash='" + Utilities.bytesAsHexString(paymentAccountPayloadHash) +
|
||||||
",\n payoutAddress='" + payoutAddress +
|
",\n payoutAddress='" + payoutAddress +
|
||||||
",\n depositTxHash='" + depositTxHash +
|
",\n depositTxHash='" + depositTxHash +
|
||||||
|
",\n accountAgeWitnessSignatureOfDepositHash='" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfDepositHash) +
|
||||||
"\n} " + super.toString();
|
"\n} " + super.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,19 +22,10 @@ import bisq.core.offer.Offer;
|
||||||
import bisq.core.trade.BuyerAsTakerTrade;
|
import bisq.core.trade.BuyerAsTakerTrade;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.handlers.TradeResultHandler;
|
import bisq.core.trade.handlers.TradeResultHandler;
|
||||||
import bisq.core.trade.messages.DepositResponse;
|
|
||||||
import bisq.core.trade.messages.InitMultisigRequest;
|
|
||||||
import bisq.core.trade.messages.DepositsConfirmedMessage;
|
|
||||||
import bisq.core.trade.messages.PaymentReceivedMessage;
|
|
||||||
import bisq.core.trade.messages.SignContractRequest;
|
|
||||||
import bisq.core.trade.messages.SignContractResponse;
|
|
||||||
import bisq.core.trade.messages.TradeMessage;
|
|
||||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||||
import bisq.core.trade.protocol.tasks.TakerReserveTradeFunds;
|
import bisq.core.trade.protocol.tasks.TakerReserveTradeFunds;
|
||||||
import bisq.core.trade.protocol.tasks.TakerSendInitTradeRequestToArbitrator;
|
import bisq.core.trade.protocol.tasks.TakerSendInitTradeRequestToArbitrator;
|
||||||
import bisq.network.p2p.NodeAddress;
|
|
||||||
import bisq.common.handlers.ErrorMessageHandler;
|
import bisq.common.handlers.ErrorMessageHandler;
|
||||||
import bisq.common.handlers.ResultHandler;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ import bisq.core.trade.messages.TradeMessage;
|
||||||
import bisq.core.trade.protocol.tasks.RemoveOffer;
|
import bisq.core.trade.protocol.tasks.RemoveOffer;
|
||||||
import bisq.core.trade.protocol.tasks.ProcessPaymentSentMessage;
|
import bisq.core.trade.protocol.tasks.ProcessPaymentSentMessage;
|
||||||
import bisq.core.trade.protocol.tasks.TradeTask;
|
import bisq.core.trade.protocol.tasks.TradeTask;
|
||||||
|
import bisq.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness;
|
||||||
import bisq.core.trade.protocol.FluentProtocol.Condition;
|
import bisq.core.trade.protocol.FluentProtocol.Condition;
|
||||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||||
import bisq.core.trade.protocol.tasks.MaybeSendSignContractRequest;
|
import bisq.core.trade.protocol.tasks.MaybeSendSignContractRequest;
|
||||||
|
@ -387,7 +388,9 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
expect(new Condition(trade)
|
expect(new Condition(trade)
|
||||||
.with(response)
|
.with(response)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
.setup(tasks(ProcessDepositsConfirmedMessage.class)
|
.setup(tasks(
|
||||||
|
ProcessDepositsConfirmedMessage.class,
|
||||||
|
VerifyPeersAccountAgeWitness.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
handleTaskRunnerSuccess(sender, response);
|
handleTaskRunnerSuccess(sender, response);
|
||||||
|
@ -431,7 +434,8 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
}))
|
}))
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
ApplyFilter.class,
|
ApplyFilter.class,
|
||||||
ProcessPaymentSentMessage.class)
|
ProcessPaymentSentMessage.class,
|
||||||
|
VerifyPeersAccountAgeWitness.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
handleTaskRunnerSuccess(peer, message);
|
handleTaskRunnerSuccess(peer, message);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package bisq.core.trade.protocol;
|
package bisq.core.trade.protocol;
|
||||||
|
|
||||||
|
import bisq.core.account.witness.AccountAgeWitness;
|
||||||
import bisq.core.btc.model.RawTransactionInput;
|
import bisq.core.btc.model.RawTransactionInput;
|
||||||
import bisq.core.payment.payload.PaymentAccountPayload;
|
import bisq.core.payment.payload.PaymentAccountPayload;
|
||||||
import bisq.core.proto.CoreProtoResolver;
|
import bisq.core.proto.CoreProtoResolver;
|
||||||
|
@ -97,6 +98,10 @@ public final class TradingPeer implements PersistablePayload {
|
||||||
private byte[] accountAgeWitnessNonce;
|
private byte[] accountAgeWitnessNonce;
|
||||||
@Nullable
|
@Nullable
|
||||||
private byte[] accountAgeWitnessSignature;
|
private byte[] accountAgeWitnessSignature;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Nullable
|
||||||
|
private AccountAgeWitness accountAgeWitness;
|
||||||
private long currentDate;
|
private long currentDate;
|
||||||
|
|
||||||
// Added in v.1.1.6
|
// Added in v.1.1.6
|
||||||
|
@ -155,6 +160,7 @@ public final class TradingPeer implements PersistablePayload {
|
||||||
Optional.ofNullable(changeOutputAddress).ifPresent(builder::setChangeOutputAddress);
|
Optional.ofNullable(changeOutputAddress).ifPresent(builder::setChangeOutputAddress);
|
||||||
Optional.ofNullable(accountAgeWitnessNonce).ifPresent(e -> builder.setAccountAgeWitnessNonce(ByteString.copyFrom(e)));
|
Optional.ofNullable(accountAgeWitnessNonce).ifPresent(e -> builder.setAccountAgeWitnessNonce(ByteString.copyFrom(e)));
|
||||||
Optional.ofNullable(accountAgeWitnessSignature).ifPresent(e -> builder.setAccountAgeWitnessSignature(ByteString.copyFrom(e)));
|
Optional.ofNullable(accountAgeWitnessSignature).ifPresent(e -> builder.setAccountAgeWitnessSignature(ByteString.copyFrom(e)));
|
||||||
|
Optional.ofNullable(accountAgeWitness).ifPresent(e -> builder.setAccountAgeWitness(accountAgeWitness.toProtoAccountAgeWitness()));
|
||||||
Optional.ofNullable(mediatedPayoutTxSignature).ifPresent(e -> builder.setMediatedPayoutTxSignature(ByteString.copyFrom(e)));
|
Optional.ofNullable(mediatedPayoutTxSignature).ifPresent(e -> builder.setMediatedPayoutTxSignature(ByteString.copyFrom(e)));
|
||||||
Optional.ofNullable(reserveTxHash).ifPresent(e -> builder.setReserveTxHash(reserveTxHash));
|
Optional.ofNullable(reserveTxHash).ifPresent(e -> builder.setReserveTxHash(reserveTxHash));
|
||||||
Optional.ofNullable(reserveTxHex).ifPresent(e -> builder.setReserveTxHex(reserveTxHex));
|
Optional.ofNullable(reserveTxHex).ifPresent(e -> builder.setReserveTxHex(reserveTxHex));
|
||||||
|
@ -203,6 +209,8 @@ public final class TradingPeer implements PersistablePayload {
|
||||||
tradingPeer.setChangeOutputAddress(ProtoUtil.stringOrNullFromProto(proto.getChangeOutputAddress()));
|
tradingPeer.setChangeOutputAddress(ProtoUtil.stringOrNullFromProto(proto.getChangeOutputAddress()));
|
||||||
tradingPeer.setAccountAgeWitnessNonce(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessNonce()));
|
tradingPeer.setAccountAgeWitnessNonce(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessNonce()));
|
||||||
tradingPeer.setAccountAgeWitnessSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignature()));
|
tradingPeer.setAccountAgeWitnessSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignature()));
|
||||||
|
protobuf.AccountAgeWitness protoAccountAgeWitness = proto.getAccountAgeWitness();
|
||||||
|
tradingPeer.setAccountAgeWitness(protoAccountAgeWitness.getHash().isEmpty() ? null : AccountAgeWitness.fromProto(protoAccountAgeWitness));
|
||||||
tradingPeer.setCurrentDate(proto.getCurrentDate());
|
tradingPeer.setCurrentDate(proto.getCurrentDate());
|
||||||
tradingPeer.setMediatedPayoutTxSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getMediatedPayoutTxSignature()));
|
tradingPeer.setMediatedPayoutTxSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getMediatedPayoutTxSignature()));
|
||||||
tradingPeer.setReserveTxHash(ProtoUtil.stringOrNullFromProto(proto.getReserveTxHash()));
|
tradingPeer.setReserveTxHash(ProtoUtil.stringOrNullFromProto(proto.getReserveTxHash()));
|
||||||
|
|
|
@ -54,9 +54,6 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask {
|
||||||
runInterceptHook();
|
runInterceptHook();
|
||||||
InitTradeRequest request = (InitTradeRequest) processModel.getTradeMessage();
|
InitTradeRequest request = (InitTradeRequest) processModel.getTradeMessage();
|
||||||
|
|
||||||
// arbitrator signs offer id as nonce to avoid challenge protocol
|
|
||||||
byte[] sig = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), processModel.getOfferId().getBytes(Charsets.UTF_8));
|
|
||||||
|
|
||||||
// handle request from taker
|
// handle request from taker
|
||||||
if (request.getSenderNodeAddress().equals(trade.getTaker().getNodeAddress())) {
|
if (request.getSenderNodeAddress().equals(trade.getTaker().getNodeAddress())) {
|
||||||
|
|
||||||
|
@ -73,7 +70,7 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask {
|
||||||
request.getPaymentMethodId(),
|
request.getPaymentMethodId(),
|
||||||
UUID.randomUUID().toString(),
|
UUID.randomUUID().toString(),
|
||||||
Version.getP2PMessageVersion(),
|
Version.getP2PMessageVersion(),
|
||||||
sig,
|
request.getAccountAgeWitnessSignatureOfOfferId(),
|
||||||
new Date().getTime(),
|
new Date().getTime(),
|
||||||
trade.getMaker().getNodeAddress(),
|
trade.getMaker().getNodeAddress(),
|
||||||
trade.getTaker().getNodeAddress(),
|
trade.getTaker().getNodeAddress(),
|
||||||
|
|
|
@ -89,7 +89,8 @@ public abstract class BuyerSendPaymentSentMessage extends SendMailboxMessageTask
|
||||||
deterministicId,
|
deterministicId,
|
||||||
trade.getPayoutTxHex(),
|
trade.getPayoutTxHex(),
|
||||||
trade.getSelf().getUpdatedMultisigHex(),
|
trade.getSelf().getUpdatedMultisigHex(),
|
||||||
trade.getSelf().getPaymentAccountKey()
|
trade.getSelf().getPaymentAccountKey(),
|
||||||
|
trade.getTradingPeer().getAccountAgeWitness()
|
||||||
);
|
);
|
||||||
|
|
||||||
// sign message
|
// sign message
|
||||||
|
|
|
@ -53,11 +53,8 @@ public class MakerSendInitTradeRequest extends TradeTask {
|
||||||
checkNotNull(makerRequest);
|
checkNotNull(makerRequest);
|
||||||
checkTradeId(processModel.getOfferId(), makerRequest);
|
checkTradeId(processModel.getOfferId(), makerRequest);
|
||||||
|
|
||||||
// maker signs offer id as nonce to avoid challenge protocol // TODO: how is this used?
|
|
||||||
Offer offer = processModel.getOffer();
|
|
||||||
byte[] sig = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), offer.getId().getBytes(Charsets.UTF_8));
|
|
||||||
|
|
||||||
// create request to arbitrator
|
// create request to arbitrator
|
||||||
|
Offer offer = processModel.getOffer();
|
||||||
InitTradeRequest arbitratorRequest = new InitTradeRequest(
|
InitTradeRequest arbitratorRequest = new InitTradeRequest(
|
||||||
offer.getId(),
|
offer.getId(),
|
||||||
processModel.getMyNodeAddress(),
|
processModel.getMyNodeAddress(),
|
||||||
|
@ -70,7 +67,7 @@ public class MakerSendInitTradeRequest extends TradeTask {
|
||||||
offer.getOfferPayload().getPaymentMethodId(),
|
offer.getOfferPayload().getPaymentMethodId(),
|
||||||
UUID.randomUUID().toString(),
|
UUID.randomUUID().toString(),
|
||||||
Version.getP2PMessageVersion(),
|
Version.getP2PMessageVersion(),
|
||||||
sig,
|
null,
|
||||||
makerRequest.getCurrentDate(),
|
makerRequest.getCurrentDate(),
|
||||||
trade.getMaker().getNodeAddress(),
|
trade.getMaker().getNodeAddress(),
|
||||||
trade.getTaker().getNodeAddress(),
|
trade.getTaker().getNodeAddress(),
|
||||||
|
|
|
@ -18,17 +18,21 @@
|
||||||
package bisq.core.trade.protocol.tasks;
|
package bisq.core.trade.protocol.tasks;
|
||||||
|
|
||||||
import bisq.common.app.Version;
|
import bisq.common.app.Version;
|
||||||
|
import bisq.common.crypto.Sig;
|
||||||
import bisq.common.taskrunner.TaskRunner;
|
import bisq.common.taskrunner.TaskRunner;
|
||||||
import bisq.core.btc.model.XmrAddressEntry;
|
import bisq.core.btc.model.XmrAddressEntry;
|
||||||
import bisq.core.trade.ArbitratorTrade;
|
import bisq.core.trade.ArbitratorTrade;
|
||||||
|
import bisq.core.trade.MakerTrade;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.Trade.State;
|
import bisq.core.trade.Trade.State;
|
||||||
import bisq.core.trade.messages.SignContractRequest;
|
import bisq.core.trade.messages.SignContractRequest;
|
||||||
import bisq.network.p2p.SendDirectMessageListener;
|
import bisq.network.p2p.SendDirectMessageListener;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import monero.wallet.MoneroWallet;
|
|
||||||
import monero.wallet.model.MoneroTxWallet;
|
import monero.wallet.model.MoneroTxWallet;
|
||||||
|
|
||||||
// TODO (woodser): separate classes for deposit tx creation and contract request, or combine into ProcessInitMultisigRequest
|
// TODO (woodser): separate classes for deposit tx creation and contract request, or combine into ProcessInitMultisigRequest
|
||||||
|
@ -75,6 +79,12 @@ public class MaybeSendSignContractRequest extends TradeTask {
|
||||||
trade.getSelf().setPayoutAddressString(trade.getXmrWalletService().getAddressEntry(processModel.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).get().getAddressString()); // TODO (woodser): allow custom payout address?
|
trade.getSelf().setPayoutAddressString(trade.getXmrWalletService().getAddressEntry(processModel.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).get().getAddressString()); // TODO (woodser): allow custom payout address?
|
||||||
trade.getSelf().setPaymentAccountPayload(trade.getProcessModel().getPaymentAccountPayload(trade));
|
trade.getSelf().setPaymentAccountPayload(trade.getProcessModel().getPaymentAccountPayload(trade));
|
||||||
|
|
||||||
|
// maker signs deposit hash nonce to avoid challenge protocol
|
||||||
|
byte[] sig = null;
|
||||||
|
if (trade instanceof MakerTrade) {
|
||||||
|
sig = Sig.sign(processModel.getP2PService().getKeyRing().getSignatureKeyPair().getPrivate(), depositTx.getHash().getBytes(Charsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
// create request for peer and arbitrator to sign contract
|
// create request for peer and arbitrator to sign contract
|
||||||
SignContractRequest request = new SignContractRequest(
|
SignContractRequest request = new SignContractRequest(
|
||||||
trade.getOffer().getId(),
|
trade.getOffer().getId(),
|
||||||
|
@ -86,7 +96,8 @@ public class MaybeSendSignContractRequest extends TradeTask {
|
||||||
trade.getProcessModel().getAccountId(),
|
trade.getProcessModel().getAccountId(),
|
||||||
trade.getSelf().getPaymentAccountPayload().getHash(),
|
trade.getSelf().getPaymentAccountPayload().getHash(),
|
||||||
trade.getSelf().getPayoutAddressString(),
|
trade.getSelf().getPayoutAddressString(),
|
||||||
depositTx.getHash());
|
depositTx.getHash(),
|
||||||
|
sig);
|
||||||
|
|
||||||
// send request to trading peer
|
// send request to trading peer
|
||||||
processModel.getP2PService().sendEncryptedDirectMessage(trade.getTradingPeer().getNodeAddress(), trade.getTradingPeer().getPubKeyRing(), request, new SendDirectMessageListener() {
|
processModel.getP2PService().sendEncryptedDirectMessage(trade.getTradingPeer().getNodeAddress(), trade.getTradingPeer().getPubKeyRing(), request, new SendDirectMessageListener() {
|
||||||
|
|
|
@ -53,7 +53,7 @@ public class ProcessDepositsConfirmedMessage extends TradeTask {
|
||||||
|
|
||||||
// decrypt seller payment account payload if key given
|
// decrypt seller payment account payload if key given
|
||||||
if (request.getSellerPaymentAccountKey() != null && trade.getTradingPeer().getPaymentAccountPayload() == null) {
|
if (request.getSellerPaymentAccountKey() != null && trade.getTradingPeer().getPaymentAccountPayload() == null) {
|
||||||
log.info(trade.getClass().getSimpleName() + " decryping using seller payment account key: " + request.getSellerPaymentAccountKey());
|
log.info(trade.getClass().getSimpleName() + " decrypting using seller payment account key");
|
||||||
trade.decryptPeerPaymentAccountPayload(request.getSellerPaymentAccountKey());
|
trade.decryptPeerPaymentAccountPayload(request.getSellerPaymentAccountKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ public class ProcessInitTradeRequest extends TradeTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle maker trade
|
// handle request as maker
|
||||||
else if (trade instanceof MakerTrade) {
|
else if (trade instanceof MakerTrade) {
|
||||||
multisigParticipant = processModel.getTaker();
|
multisigParticipant = processModel.getTaker();
|
||||||
trade.getTaker().setNodeAddress(request.getSenderNodeAddress()); // arbitrator sends maker InitTradeRequest with taker's node address and pub key ring
|
trade.getTaker().setNodeAddress(request.getSenderNodeAddress()); // arbitrator sends maker InitTradeRequest with taker's node address and pub key ring
|
||||||
|
|
|
@ -20,6 +20,7 @@ package bisq.core.trade.protocol.tasks;
|
||||||
import bisq.core.account.sign.SignedWitness;
|
import bisq.core.account.sign.SignedWitness;
|
||||||
import bisq.core.support.dispute.Dispute;
|
import bisq.core.support.dispute.Dispute;
|
||||||
import bisq.core.trade.ArbitratorTrade;
|
import bisq.core.trade.ArbitratorTrade;
|
||||||
|
import bisq.core.trade.BuyerTrade;
|
||||||
import bisq.core.trade.HavenoUtils;
|
import bisq.core.trade.HavenoUtils;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.messages.PaymentReceivedMessage;
|
import bisq.core.trade.messages.PaymentReceivedMessage;
|
||||||
|
@ -55,6 +56,7 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
|
||||||
HavenoUtils.verifyPaymentReceivedMessage(trade, message);
|
HavenoUtils.verifyPaymentReceivedMessage(trade, message);
|
||||||
trade.getSeller().setUpdatedMultisigHex(message.getUpdatedMultisigHex());
|
trade.getSeller().setUpdatedMultisigHex(message.getUpdatedMultisigHex());
|
||||||
trade.getBuyer().setUpdatedMultisigHex(message.getPaymentSentMessage().getUpdatedMultisigHex());
|
trade.getBuyer().setUpdatedMultisigHex(message.getPaymentSentMessage().getUpdatedMultisigHex());
|
||||||
|
trade.getBuyer().setAccountAgeWitness(message.getBuyerAccountAgeWitness());
|
||||||
|
|
||||||
// update to the latest peer address of our peer if message is correct
|
// update to the latest peer address of our peer if message is correct
|
||||||
trade.getSeller().setNodeAddress(processModel.getTempTradingPeerNodeAddress());
|
trade.getSeller().setNodeAddress(processModel.getTempTradingPeerNodeAddress());
|
||||||
|
@ -71,8 +73,8 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
|
||||||
// process payout tx unless already unlocked
|
// process payout tx unless already unlocked
|
||||||
if (!trade.isPayoutUnlocked()) processPayoutTx(message);
|
if (!trade.isPayoutUnlocked()) processPayoutTx(message);
|
||||||
|
|
||||||
SignedWitness signedWitness = message.getSignedWitness();
|
SignedWitness signedWitness = message.getBuyerSignedWitness();
|
||||||
if (signedWitness != null) {
|
if (signedWitness != null && trade instanceof BuyerTrade) {
|
||||||
// We received the signedWitness from the seller and publish the data to the network.
|
// We received the signedWitness from the seller and publish the data to the network.
|
||||||
// The signer has published it as well but we prefer to re-do it on our side as well to achieve higher
|
// The signer has published it as well but we prefer to re-do it on our side as well to achieve higher
|
||||||
// resilience.
|
// resilience.
|
||||||
|
|
|
@ -48,6 +48,7 @@ public class ProcessPaymentSentMessage extends TradeTask {
|
||||||
trade.setPayoutTxHex(message.getPayoutTxHex());
|
trade.setPayoutTxHex(message.getPayoutTxHex());
|
||||||
trade.getBuyer().setUpdatedMultisigHex(message.getUpdatedMultisigHex());
|
trade.getBuyer().setUpdatedMultisigHex(message.getUpdatedMultisigHex());
|
||||||
trade.getBuyer().setPaymentSentMessage(message);
|
trade.getBuyer().setPaymentSentMessage(message);
|
||||||
|
trade.getSeller().setAccountAgeWitness(message.getSellerAccountAgeWitness());
|
||||||
|
|
||||||
// if seller, decrypt buyer's payment account payload
|
// if seller, decrypt buyer's payment account payload
|
||||||
if (trade.isSeller()) trade.decryptPeerPaymentAccountPayload(message.getPaymentAccountKey());
|
if (trade.isSeller()) trade.decryptPeerPaymentAccountPayload(message.getPaymentAccountKey());
|
||||||
|
|
|
@ -37,9 +37,13 @@ import bisq.core.trade.protocol.TradingPeer;
|
||||||
import bisq.core.util.JsonUtil;
|
import bisq.core.util.JsonUtil;
|
||||||
import bisq.network.p2p.NodeAddress;
|
import bisq.network.p2p.NodeAddress;
|
||||||
import bisq.network.p2p.SendDirectMessageListener;
|
import bisq.network.p2p.SendDirectMessageListener;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -67,6 +71,12 @@ public class ProcessSignContractRequest extends TradeTask {
|
||||||
trader.setPaymentAccountPayloadHash(request.getPaymentAccountPayloadHash());
|
trader.setPaymentAccountPayloadHash(request.getPaymentAccountPayloadHash());
|
||||||
trader.setPayoutAddressString(request.getPayoutAddress());
|
trader.setPayoutAddressString(request.getPayoutAddress());
|
||||||
|
|
||||||
|
// maker sends witness signature of deposit tx hash
|
||||||
|
if (trader == trade.getMaker()) {
|
||||||
|
trader.setAccountAgeWitnessNonce(request.getDepositTxHash().getBytes(Charsets.UTF_8));
|
||||||
|
trader.setAccountAgeWitnessSignature(request.getAccountAgeWitnessSignatureOfDepositHash());
|
||||||
|
}
|
||||||
|
|
||||||
// sign contract only when both deposit txs hashes known
|
// sign contract only when both deposit txs hashes known
|
||||||
// TODO (woodser): remove makerDepositTxId and takerDepositTxId from Trade
|
// TODO (woodser): remove makerDepositTxId and takerDepositTxId from Trade
|
||||||
if (processModel.getMaker().getDepositTxHash() == null || processModel.getTaker().getDepositTxHash() == null) {
|
if (processModel.getMaker().getDepositTxHash() == null || processModel.getTaker().getDepositTxHash() == null) {
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package bisq.core.trade.protocol.tasks;
|
package bisq.core.trade.protocol.tasks;
|
||||||
|
|
||||||
import bisq.core.account.sign.SignedWitness;
|
import bisq.core.account.sign.SignedWitness;
|
||||||
|
import bisq.core.account.witness.AccountAgeWitnessService;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.messages.PaymentReceivedMessage;
|
import bisq.core.trade.messages.PaymentReceivedMessage;
|
||||||
import bisq.core.trade.messages.TradeMailboxMessage;
|
import bisq.core.trade.messages.TradeMailboxMessage;
|
||||||
|
@ -63,22 +64,23 @@ public abstract class SellerSendPaymentReceivedMessage extends SendMailboxMessag
|
||||||
checkNotNull(trade.getPayoutTxHex(), "Payout tx must not be null");
|
checkNotNull(trade.getPayoutTxHex(), "Payout tx must not be null");
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
|
|
||||||
// TODO: sign witness
|
// sign account witness
|
||||||
// AccountAgeWitnessService accountAgeWitnessService = processModel.getAccountAgeWitnessService();
|
AccountAgeWitnessService accountAgeWitnessService = processModel.getAccountAgeWitnessService();
|
||||||
// if (accountAgeWitnessService.isSignWitnessTrade(trade)) {
|
if (accountAgeWitnessService.isSignWitnessTrade(trade)) {
|
||||||
// // Broadcast is done in accountAgeWitness domain.
|
accountAgeWitnessService.traderSignAndPublishPeersAccountAgeWitness(trade).ifPresent(witness -> signedWitness = witness);
|
||||||
// accountAgeWitnessService.traderSignAndPublishPeersAccountAgeWitness(trade).ifPresent(witness -> signedWitness = witness);
|
log.info("{} {} signed and published peers account age witness", trade.getClass().getSimpleName(), trade.getId());
|
||||||
// }
|
}
|
||||||
|
|
||||||
// TODO: create with deterministic id like BuyerSendPaymentSentMessage
|
// TODO: create with deterministic id like BuyerSendPaymentSentMessage
|
||||||
message = new PaymentReceivedMessage(
|
message = new PaymentReceivedMessage(
|
||||||
tradeId,
|
tradeId,
|
||||||
processModel.getMyNodeAddress(),
|
processModel.getMyNodeAddress(),
|
||||||
signedWitness,
|
|
||||||
trade.isPayoutPublished() ? null : trade.getPayoutTxHex(), // unsigned
|
trade.isPayoutPublished() ? null : trade.getPayoutTxHex(), // unsigned
|
||||||
trade.isPayoutPublished() ? trade.getPayoutTxHex() : null, // signed
|
trade.isPayoutPublished() ? trade.getPayoutTxHex() : null, // signed
|
||||||
trade.getSelf().getUpdatedMultisigHex(),
|
trade.getSelf().getUpdatedMultisigHex(),
|
||||||
trade.getState().ordinal() >= Trade.State.SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG.ordinal(), // informs to expect payout
|
trade.getState().ordinal() >= Trade.State.SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG.ordinal(), // informs to expect payout
|
||||||
|
trade.getTradingPeer().getAccountAgeWitness(),
|
||||||
|
signedWitness,
|
||||||
trade.getBuyer().getPaymentSentMessage()
|
trade.getBuyer().getPaymentSentMessage()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import bisq.core.account.witness.AccountAgeWitnessService;
|
||||||
import bisq.core.locale.CurrencyUtil;
|
import bisq.core.locale.CurrencyUtil;
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
import bisq.core.payment.payload.PaymentAccountPayload;
|
import bisq.core.payment.payload.PaymentAccountPayload;
|
||||||
|
import bisq.core.trade.ArbitratorTrade;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.protocol.TradingPeer;
|
import bisq.core.trade.protocol.TradingPeer;
|
||||||
|
|
||||||
|
@ -46,14 +47,27 @@ public class VerifyPeersAccountAgeWitness extends TradeTask {
|
||||||
try {
|
try {
|
||||||
runInterceptHook();
|
runInterceptHook();
|
||||||
|
|
||||||
|
// only verify fiat offer
|
||||||
Offer offer = checkNotNull(trade.getOffer());
|
Offer offer = checkNotNull(trade.getOffer());
|
||||||
if (CurrencyUtil.isCryptoCurrency(offer.getCurrencyCode())) {
|
if (CurrencyUtil.isCryptoCurrency(offer.getCurrencyCode())) {
|
||||||
complete();
|
complete();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AccountAgeWitnessService accountAgeWitnessService = processModel.getAccountAgeWitnessService();
|
// skip if arbitrator
|
||||||
|
if (trade instanceof ArbitratorTrade) {
|
||||||
|
complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip if payment account payload is null
|
||||||
TradingPeer tradingPeer = trade.getTradingPeer();
|
TradingPeer tradingPeer = trade.getTradingPeer();
|
||||||
|
if (tradingPeer.getPaymentAccountPayload() == null) {
|
||||||
|
complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountAgeWitnessService accountAgeWitnessService = processModel.getAccountAgeWitnessService();
|
||||||
PaymentAccountPayload peersPaymentAccountPayload = checkNotNull(tradingPeer.getPaymentAccountPayload(),
|
PaymentAccountPayload peersPaymentAccountPayload = checkNotNull(tradingPeer.getPaymentAccountPayload(),
|
||||||
"Peers peersPaymentAccountPayload must not be null");
|
"Peers peersPaymentAccountPayload must not be null");
|
||||||
PubKeyRing peersPubKeyRing = checkNotNull(tradingPeer.getPubKeyRing(), "peersPubKeyRing must not be null");
|
PubKeyRing peersPubKeyRing = checkNotNull(tradingPeer.getPubKeyRing(), "peersPubKeyRing must not be null");
|
||||||
|
@ -71,6 +85,8 @@ public class VerifyPeersAccountAgeWitness extends TradeTask {
|
||||||
signature,
|
signature,
|
||||||
errorMsg::set);
|
errorMsg::set);
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
|
trade.getTradingPeer().setAccountAgeWitness(processModel.getAccountAgeWitnessService().findWitness(trade.getTradingPeer().getPaymentAccountPayload(), trade.getTradingPeer().getPubKeyRing()).orElse(null));
|
||||||
|
log.info("{} {} verified witness data of peer {}", trade.getClass().getSimpleName(), trade.getId(), tradingPeer.getNodeAddress());
|
||||||
complete();
|
complete();
|
||||||
} else {
|
} else {
|
||||||
failed(errorMsg.get());
|
failed(errorMsg.get());
|
||||||
|
|
|
@ -119,8 +119,10 @@ public class User implements PersistedDataHost {
|
||||||
userPayload.getAcceptedLanguageLocaleCodes().add(english);
|
userPayload.getAcceptedLanguageLocaleCodes().add(english);
|
||||||
|
|
||||||
paymentAccountsAsObservable.addListener((SetChangeListener<PaymentAccount>) change -> {
|
paymentAccountsAsObservable.addListener((SetChangeListener<PaymentAccount>) change -> {
|
||||||
|
synchronized (paymentAccountsAsObservable) {
|
||||||
userPayload.setPaymentAccounts(new HashSet<>(paymentAccountsAsObservable));
|
userPayload.setPaymentAccounts(new HashSet<>(paymentAccountsAsObservable));
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
currentPaymentAccountProperty.addListener((ov) -> {
|
currentPaymentAccountProperty.addListener((ov) -> {
|
||||||
userPayload.setCurrentPaymentAccount(currentPaymentAccountProperty.get());
|
userPayload.setCurrentPaymentAccount(currentPaymentAccountProperty.get());
|
||||||
|
@ -212,14 +214,16 @@ public class User implements PersistedDataHost {
|
||||||
|
|
||||||
public void addPaymentAccount(PaymentAccount paymentAccount) {
|
public void addPaymentAccount(PaymentAccount paymentAccount) {
|
||||||
paymentAccount.onAddToUser();
|
paymentAccount.onAddToUser();
|
||||||
|
synchronized (paymentAccountsAsObservable) {
|
||||||
boolean changed = paymentAccountsAsObservable.add(paymentAccount);
|
boolean changed = paymentAccountsAsObservable.add(paymentAccount);
|
||||||
setCurrentPaymentAccount(paymentAccount);
|
setCurrentPaymentAccount(paymentAccount);
|
||||||
if (changed)
|
if (changed)
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addImportedPaymentAccounts(Collection<PaymentAccount> paymentAccounts) {
|
public void addImportedPaymentAccounts(Collection<PaymentAccount> paymentAccounts) {
|
||||||
|
synchronized (paymentAccountsAsObservable) {
|
||||||
isPaymentAccountImport = true;
|
isPaymentAccountImport = true;
|
||||||
|
|
||||||
boolean changed = paymentAccountsAsObservable.addAll(paymentAccounts);
|
boolean changed = paymentAccountsAsObservable.addAll(paymentAccounts);
|
||||||
|
@ -229,12 +233,15 @@ public class User implements PersistedDataHost {
|
||||||
|
|
||||||
isPaymentAccountImport = false;
|
isPaymentAccountImport = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void removePaymentAccount(PaymentAccount paymentAccount) {
|
public void removePaymentAccount(PaymentAccount paymentAccount) {
|
||||||
|
synchronized (paymentAccountsAsObservable) {
|
||||||
boolean changed = paymentAccountsAsObservable.remove(paymentAccount);
|
boolean changed = paymentAccountsAsObservable.remove(paymentAccount);
|
||||||
if (changed)
|
if (changed)
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean addAcceptedArbitrator(Arbitrator arbitrator) {
|
public boolean addAcceptedArbitrator(Arbitrator arbitrator) {
|
||||||
List<Arbitrator> arbitrators = userPayload.getAcceptedArbitrators();
|
List<Arbitrator> arbitrators = userPayload.getAcceptedArbitrators();
|
||||||
|
@ -513,8 +520,10 @@ public class User implements PersistedDataHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean paymentAccountExists(PaymentAccount paymentAccount) {
|
private boolean paymentAccountExists(PaymentAccount paymentAccount) {
|
||||||
|
synchronized (paymentAccountsAsObservable) {
|
||||||
return getPaymentAccountsAsObservable().stream().anyMatch(e -> e.equals(paymentAccount));
|
return getPaymentAccountsAsObservable().stream().anyMatch(e -> e.equals(paymentAccount));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Cookie getCookie() {
|
public Cookie getCookie() {
|
||||||
return userPayload.getCookie();
|
return userPayload.getCookie();
|
||||||
|
|
|
@ -523,7 +523,7 @@ public class PopOver extends PopupControl {
|
||||||
skinNode);
|
skinNode);
|
||||||
fadeOut.setFromValue(skinNode.getOpacity());
|
fadeOut.setFromValue(skinNode.getOpacity());
|
||||||
fadeOut.setToValue(0);
|
fadeOut.setToValue(0);
|
||||||
fadeOut.setOnFinished(evt -> super.hide());
|
fadeOut.setOnFinished(evt -> { if (super.isShowing()) super.hide(); });
|
||||||
fadeOut.play();
|
fadeOut.play();
|
||||||
} else {
|
} else {
|
||||||
super.hide();
|
super.hide();
|
||||||
|
|
|
@ -200,9 +200,7 @@ public class SignPaymentAccountsWindow extends Overlay<SignPaymentAccountsWindow
|
||||||
++rowIndex, Res.get("popup.accountSigning.confirmSelectedAccounts.headline"));
|
++rowIndex, Res.get("popup.accountSigning.confirmSelectedAccounts.headline"));
|
||||||
GridPane.setRowSpan(selectedPaymentAccountsTuple.third, 2);
|
GridPane.setRowSpan(selectedPaymentAccountsTuple.third, 2);
|
||||||
selectedPaymentAccountsList = selectedPaymentAccountsTuple.second;
|
selectedPaymentAccountsList = selectedPaymentAccountsTuple.second;
|
||||||
ObservableList<Dispute> disputesAsObservableList = useDevPrivilegeKeys ?
|
ObservableList<Dispute> disputesAsObservableList = arbitrationManager.getDisputesAsObservableList();
|
||||||
mediationManager.getDisputesAsObservableList()
|
|
||||||
: arbitrationManager.getDisputesAsObservableList();
|
|
||||||
long safeDate = datePicker.getValue().atStartOfDay().toEpochSecond(ZoneOffset.UTC) * 1000;
|
long safeDate = datePicker.getValue().atStartOfDay().toEpochSecond(ZoneOffset.UTC) * 1000;
|
||||||
List<TraderDataItem> traderDataItemList;
|
List<TraderDataItem> traderDataItemList;
|
||||||
StringBuilder sb = new StringBuilder("Summary for ").append(appName).append("\n");
|
StringBuilder sb = new StringBuilder("Summary for ").append(appName).append("\n");
|
||||||
|
|
|
@ -43,6 +43,7 @@ import bisq.network.p2p.NodeAddress;
|
||||||
|
|
||||||
import bisq.common.UserThread;
|
import bisq.common.UserThread;
|
||||||
import bisq.common.util.Tuple3;
|
import bisq.common.util.Tuple3;
|
||||||
|
import bisq.common.util.Utilities;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
@ -313,6 +314,11 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
|
||||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
HBox.setHgrow(spacer, Priority.ALWAYS);
|
||||||
hBox.getChildren().add(0, spacer);
|
hBox.getChildren().add(0, spacer);
|
||||||
|
|
||||||
|
String buyerWitnessHash = trade.getBuyer().getAccountAgeWitness() == null ? "null" : Utilities.bytesAsHexString(trade.getBuyer().getAccountAgeWitness().getHash());
|
||||||
|
String buyerPubKeyRingHash = Utilities.bytesAsHexString(trade.getBuyer().getPubKeyRing().getSignaturePubKeyBytes());
|
||||||
|
String sellerWitnessHash = trade.getSeller().getAccountAgeWitness() == null ? "null" : Utilities.bytesAsHexString(trade.getSeller().getAccountAgeWitness().getHash());
|
||||||
|
String sellerPubKeyRingHash = Utilities.bytesAsHexString(trade.getSeller().getPubKeyRing().getSignaturePubKeyBytes());
|
||||||
|
|
||||||
if (contract != null) {
|
if (contract != null) {
|
||||||
viewContractButton.setOnAction(e -> {
|
viewContractButton.setOnAction(e -> {
|
||||||
TextArea textArea = new HavenoTextArea();
|
TextArea textArea = new HavenoTextArea();
|
||||||
|
@ -321,8 +327,10 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
|
||||||
data += trade.getContractAsJson();
|
data += trade.getContractAsJson();
|
||||||
data += "\n\nOther detail data:";
|
data += "\n\nOther detail data:";
|
||||||
if (offer.isFiatOffer()) {
|
if (offer.isFiatOffer()) {
|
||||||
data += "\n\nBuyersAccountAge: " + buyersAccountAge;
|
data += "\n\nBuyers witness hash,pub key ring hash: " + buyerWitnessHash + "," + buyerPubKeyRingHash;
|
||||||
data += "\nSellersAccountAge: " + sellersAccountAge;
|
data += "\nBuyers account age: " + buyersAccountAge;
|
||||||
|
data += "\nSellers witness hash,pub key ring hash: " + sellerWitnessHash + "," + sellerPubKeyRingHash;
|
||||||
|
data += "\nSellers account age: " + sellersAccountAge;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (woodser): include maker and taker deposit tx hex in contract?
|
// TODO (woodser): include maker and taker deposit tx hex in contract?
|
||||||
|
|
|
@ -448,7 +448,7 @@ public class SellerStep3View extends TradeStepView {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.dataModel.isSignWitnessTrade()) {
|
if (model.dataModel.isSignWitnessTrade()) {
|
||||||
message += Res.get("portfolio.pending.step3_seller.onPaymentReceived.signer");
|
message += "\n\n" + Res.get("portfolio.pending.step3_seller.onPaymentReceived.signer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!DevEnv.isDevMode() && DontShowAgainLookup.showAgain(key)) {
|
if (!DevEnv.isDevMode() && DontShowAgainLookup.showAgain(key)) {
|
||||||
|
|
|
@ -34,6 +34,15 @@ Follow [instructions](https://github.com/haveno-dex/haveno-ts#run-tests) to run
|
||||||
9. Run the tests with `npm run test -- -t 'my test'` to run tests by name and `npm test` to run all tests together. Ensure all tests pass and there are no exception stacktraces in the terminals of Alice, Bob, or the arbitrator.
|
9. Run the tests with `npm run test -- -t 'my test'` to run tests by name and `npm test` to run all tests together. Ensure all tests pass and there are no exception stacktraces in the terminals of Alice, Bob, or the arbitrator.
|
||||||
10. Open pull requests to the haveno and haveno-ts projects for the backend and frontend implementations.
|
10. Open pull requests to the haveno and haveno-ts projects for the backend and frontend implementations.
|
||||||
|
|
||||||
|
## How to manually sign accounts as the arbitrator
|
||||||
|
|
||||||
|
1. Open legacy UI as the arbitrator.
|
||||||
|
2. Go to the 'Account' tab.
|
||||||
|
3. Open Signing tab: `ctrl+i`
|
||||||
|
a. Sign payment account: `ctrl+s`, select payment accounts to sign (sourced from disputes).
|
||||||
|
b. Sign account age witness: `ctrl+p` then enter <witness hash>,<pub key hash> (from past trade details) and click the "Import unsigned account age witness" button.
|
||||||
|
c. Sign unsigned witness pub keys: `ctrl+o`
|
||||||
|
|
||||||
## How to rebase and squash your commits
|
## How to rebase and squash your commits
|
||||||
|
|
||||||
When submitting a pull request for review, please first rebase and squash your commits.
|
When submitting a pull request for review, please first rebase and squash your commits.
|
||||||
|
|
|
@ -312,6 +312,7 @@ message SignContractRequest {
|
||||||
bytes payment_account_payload_hash = 7;
|
bytes payment_account_payload_hash = 7;
|
||||||
string payout_address = 8;;
|
string payout_address = 8;;
|
||||||
string deposit_tx_hash = 9;
|
string deposit_tx_hash = 9;
|
||||||
|
bytes account_age_witness_signature_of_deposit_hash = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SignContractResponse {
|
message SignContractResponse {
|
||||||
|
@ -404,20 +405,22 @@ message PaymentSentMessage {
|
||||||
string payout_tx_hex = 6;
|
string payout_tx_hex = 6;
|
||||||
string updated_multisig_hex = 7;
|
string updated_multisig_hex = 7;
|
||||||
bytes payment_account_key = 8;
|
bytes payment_account_key = 8;
|
||||||
bytes buyer_signature = 9;
|
AccountAgeWitness seller_account_age_witness = 9;
|
||||||
|
bytes buyer_signature = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PaymentReceivedMessage {
|
message PaymentReceivedMessage {
|
||||||
string trade_id = 1;
|
string trade_id = 1;
|
||||||
NodeAddress sender_node_address = 2;
|
NodeAddress sender_node_address = 2;
|
||||||
string uid = 3;
|
string uid = 3;
|
||||||
SignedWitness signed_witness = 4; // Added in v1.4.0
|
string unsigned_payout_tx_hex = 4;
|
||||||
string unsigned_payout_tx_hex = 5;
|
string signed_payout_tx_hex = 5;
|
||||||
string signed_payout_tx_hex = 6;
|
string updated_multisig_hex = 6;
|
||||||
string updated_multisig_hex = 7;
|
bool defer_publish_payout = 7;
|
||||||
bool defer_publish_payout = 8;
|
AccountAgeWitness buyer_account_age_witness = 8;
|
||||||
PaymentSentMessage payment_sent_message = 9;
|
SignedWitness buyer_signed_witness = 9;
|
||||||
bytes seller_signature = 10;
|
PaymentSentMessage payment_sent_message = 10;
|
||||||
|
bytes seller_signature = 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
message MediatedPayoutTxPublishedMessage {
|
message MediatedPayoutTxPublishedMessage {
|
||||||
|
@ -1732,8 +1735,9 @@ message TradingPeer {
|
||||||
string change_output_address = 17;
|
string change_output_address = 17;
|
||||||
bytes account_age_witness_nonce = 18;
|
bytes account_age_witness_nonce = 18;
|
||||||
bytes account_age_witness_signature = 19;
|
bytes account_age_witness_signature = 19;
|
||||||
int64 current_date = 20;
|
AccountAgeWitness account_age_witness = 20;
|
||||||
bytes mediated_payout_tx_signature = 21;
|
int64 current_date = 21;
|
||||||
|
bytes mediated_payout_tx_signature = 22;
|
||||||
|
|
||||||
string reserve_tx_hash = 1001;
|
string reserve_tx_hash = 1001;
|
||||||
string reserve_tx_hex = 1002;
|
string reserve_tx_hex = 1002;
|
||||||
|
|
Loading…
Reference in a new issue