mirror of
https://github.com/boldsuck/haveno.git
synced 2024-12-23 04:29:22 +00:00
seller decrypts buyer payment info on payment sent
This commit is contained in:
parent
64925d0137
commit
1f32fc2cbe
9 changed files with 65 additions and 49 deletions
|
@ -24,8 +24,10 @@ import bisq.core.monetary.Price;
|
||||||
import bisq.core.monetary.Volume;
|
import bisq.core.monetary.Volume;
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
import bisq.core.offer.OfferDirection;
|
import bisq.core.offer.OfferDirection;
|
||||||
|
import bisq.core.payment.payload.PaymentAccountPayload;
|
||||||
import bisq.core.payment.payload.PaymentMethod;
|
import bisq.core.payment.payload.PaymentMethod;
|
||||||
import bisq.core.proto.CoreProtoResolver;
|
import bisq.core.proto.CoreProtoResolver;
|
||||||
|
import bisq.core.proto.network.CoreNetworkProtoResolver;
|
||||||
import bisq.core.support.dispute.mediation.MediationResultState;
|
import bisq.core.support.dispute.mediation.MediationResultState;
|
||||||
import bisq.core.support.dispute.refund.RefundResultState;
|
import bisq.core.support.dispute.refund.RefundResultState;
|
||||||
import bisq.core.support.messages.ChatMessage;
|
import bisq.core.support.messages.ChatMessage;
|
||||||
|
@ -41,6 +43,7 @@ import bisq.network.p2p.AckMessage;
|
||||||
import bisq.network.p2p.NodeAddress;
|
import bisq.network.p2p.NodeAddress;
|
||||||
import bisq.network.p2p.P2PService;
|
import bisq.network.p2p.P2PService;
|
||||||
import bisq.common.UserThread;
|
import bisq.common.UserThread;
|
||||||
|
import bisq.common.crypto.Encryption;
|
||||||
import bisq.common.crypto.PubKeyRing;
|
import bisq.common.crypto.PubKeyRing;
|
||||||
import bisq.common.proto.ProtoUtil;
|
import bisq.common.proto.ProtoUtil;
|
||||||
import bisq.common.taskrunner.Model;
|
import bisq.common.taskrunner.Model;
|
||||||
|
@ -63,6 +66,7 @@ import javafx.beans.property.StringProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.time.Clock;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -77,6 +81,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
@ -633,11 +638,6 @@ public abstract class Trade implements Tradable, Model {
|
||||||
return trade;
|
return trade;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// API
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public void initialize(ProcessModelServiceProvider serviceProvider) {
|
public void initialize(ProcessModelServiceProvider serviceProvider) {
|
||||||
serviceProvider.getArbitratorManager().getDisputeAgentByNodeAddress(arbitratorNodeAddress).ifPresent(arbitrator -> {
|
serviceProvider.getArbitratorManager().getDisputeAgentByNodeAddress(arbitratorNodeAddress).ifPresent(arbitrator -> {
|
||||||
arbitratorPubKeyRing = arbitrator.getPubKeyRing();
|
arbitratorPubKeyRing = arbitrator.getPubKeyRing();
|
||||||
|
@ -841,6 +841,32 @@ public abstract class Trade implements Tradable, Model {
|
||||||
walletService.closeMultisigWallet(getId());
|
walletService.closeMultisigWallet(getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt the peer's payment account payload using the given key.
|
||||||
|
*
|
||||||
|
* @param paymentAccountKey is the key to decrypt the payment account payload
|
||||||
|
*/
|
||||||
|
public void decryptPeersPaymentAccountPayload(byte[] paymentAccountKey) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
// decrypt payment account payload
|
||||||
|
getTradingPeer().setPaymentAccountKey(paymentAccountKey);
|
||||||
|
SecretKey sk = Encryption.getSecretKeyFromBytes(getTradingPeer().getPaymentAccountKey());
|
||||||
|
byte[] decryptedPaymentAccountPayload = Encryption.decrypt(getTradingPeer().getEncryptedPaymentAccountPayload(), sk);
|
||||||
|
CoreNetworkProtoResolver resolver = new CoreNetworkProtoResolver(Clock.systemDefaultZone()); // TODO: reuse resolver from elsewhere?
|
||||||
|
PaymentAccountPayload paymentAccountPayload = resolver.fromProto(protobuf.PaymentAccountPayload.parseFrom(decryptedPaymentAccountPayload));
|
||||||
|
|
||||||
|
// verify hash of payment account payload
|
||||||
|
byte[] peerPaymentAccountPayloadHash = this instanceof MakerTrade ? getContract().getTakerPaymentAccountPayloadHash() : getContract().getMakerPaymentAccountPayloadHash();
|
||||||
|
if (!Arrays.equals(paymentAccountPayload.getHash(), peerPaymentAccountPayloadHash)) throw new RuntimeException("Hash of peer's payment account payload does not match contract");
|
||||||
|
|
||||||
|
// set payment account payload
|
||||||
|
getTradingPeer().setPaymentAccountPayload(paymentAccountPayload);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen for deposit transactions to unlock and then apply the transactions.
|
* Listen for deposit transactions to unlock and then apply the transactions.
|
||||||
*
|
*
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
package bisq.core.trade.messages;
|
package bisq.core.trade.messages;
|
||||||
|
|
||||||
import bisq.network.p2p.NodeAddress;
|
import bisq.network.p2p.NodeAddress;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
private final String payoutTxHex;
|
private final String payoutTxHex;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final String updatedMultisigHex;
|
private final String updatedMultisigHex;
|
||||||
|
@Nullable
|
||||||
|
private final byte[] paymentAccountKey;
|
||||||
|
|
||||||
// Added after v1.3.7
|
// Added after v1.3.7
|
||||||
// We use that for the XMR txKey but want to keep it generic to be flexible for data of other payment methods or assets.
|
// We use that for the XMR txKey but want to keep it generic to be flexible for data of other payment methods or assets.
|
||||||
|
@ -53,7 +55,8 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
@Nullable String counterCurrencyExtraData,
|
@Nullable String counterCurrencyExtraData,
|
||||||
String uid,
|
String uid,
|
||||||
String signedPayoutTxHex,
|
String signedPayoutTxHex,
|
||||||
String updatedMultisigHex) {
|
String updatedMultisigHex,
|
||||||
|
@Nullable byte[] paymentAccountKey) {
|
||||||
this(tradeId,
|
this(tradeId,
|
||||||
buyerPayoutAddress,
|
buyerPayoutAddress,
|
||||||
senderNodeAddress,
|
senderNodeAddress,
|
||||||
|
@ -62,7 +65,8 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
uid,
|
uid,
|
||||||
Version.getP2PMessageVersion(),
|
Version.getP2PMessageVersion(),
|
||||||
signedPayoutTxHex,
|
signedPayoutTxHex,
|
||||||
updatedMultisigHex);
|
updatedMultisigHex,
|
||||||
|
paymentAccountKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,7 +82,8 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
String uid,
|
String uid,
|
||||||
String messageVersion,
|
String messageVersion,
|
||||||
@Nullable String signedPayoutTxHex,
|
@Nullable String signedPayoutTxHex,
|
||||||
@Nullable String updatedMultisigHex) {
|
@Nullable String updatedMultisigHex,
|
||||||
|
@Nullable byte[] paymentAccountKey) {
|
||||||
super(messageVersion, tradeId, uid);
|
super(messageVersion, tradeId, uid);
|
||||||
this.buyerPayoutAddress = buyerPayoutAddress;
|
this.buyerPayoutAddress = buyerPayoutAddress;
|
||||||
this.senderNodeAddress = senderNodeAddress;
|
this.senderNodeAddress = senderNodeAddress;
|
||||||
|
@ -86,6 +91,7 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
this.counterCurrencyExtraData = counterCurrencyExtraData;
|
this.counterCurrencyExtraData = counterCurrencyExtraData;
|
||||||
this.payoutTxHex = signedPayoutTxHex;
|
this.payoutTxHex = signedPayoutTxHex;
|
||||||
this.updatedMultisigHex = updatedMultisigHex;
|
this.updatedMultisigHex = updatedMultisigHex;
|
||||||
|
this.paymentAccountKey = paymentAccountKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -100,6 +106,7 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
Optional.ofNullable(counterCurrencyExtraData).ifPresent(e -> builder.setCounterCurrencyExtraData(counterCurrencyExtraData));
|
Optional.ofNullable(counterCurrencyExtraData).ifPresent(e -> builder.setCounterCurrencyExtraData(counterCurrencyExtraData));
|
||||||
Optional.ofNullable(payoutTxHex).ifPresent(e -> builder.setPayoutTxHex(payoutTxHex));
|
Optional.ofNullable(payoutTxHex).ifPresent(e -> builder.setPayoutTxHex(payoutTxHex));
|
||||||
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)));
|
||||||
|
|
||||||
return getNetworkEnvelopeBuilder().setPaymentSentMessage(builder).build();
|
return getNetworkEnvelopeBuilder().setPaymentSentMessage(builder).build();
|
||||||
}
|
}
|
||||||
|
@ -114,7 +121,9 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
proto.getUid(),
|
proto.getUid(),
|
||||||
messageVersion,
|
messageVersion,
|
||||||
ProtoUtil.stringOrNullFromProto(proto.getPayoutTxHex()),
|
ProtoUtil.stringOrNullFromProto(proto.getPayoutTxHex()),
|
||||||
ProtoUtil.stringOrNullFromProto(proto.getUpdatedMultisigHex()));
|
ProtoUtil.stringOrNullFromProto(proto.getUpdatedMultisigHex()),
|
||||||
|
ProtoUtil.byteArrayOrNullFromProto(proto.getPaymentAccountKey())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,6 +137,7 @@ public final class PaymentSentMessage extends TradeMailboxMessage {
|
||||||
",\n uid='" + uid + '\'' +
|
",\n uid='" + uid + '\'' +
|
||||||
",\n payoutTxHex=" + payoutTxHex +
|
",\n payoutTxHex=" + payoutTxHex +
|
||||||
",\n updatedMultisigHex=" + updatedMultisigHex +
|
",\n updatedMultisigHex=" + updatedMultisigHex +
|
||||||
|
",\n paymentAccountKey=" + paymentAccountKey +
|
||||||
"\n} " + super.toString();
|
"\n} " + super.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,16 +18,9 @@
|
||||||
package bisq.core.trade.protocol.tasks;
|
package bisq.core.trade.protocol.tasks;
|
||||||
|
|
||||||
|
|
||||||
import bisq.common.crypto.Encryption;
|
|
||||||
import bisq.common.taskrunner.TaskRunner;
|
import bisq.common.taskrunner.TaskRunner;
|
||||||
import bisq.core.payment.payload.PaymentAccountPayload;
|
|
||||||
import bisq.core.proto.network.CoreNetworkProtoResolver;
|
|
||||||
import bisq.core.trade.MakerTrade;
|
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.messages.PaymentAccountKeyResponse;
|
import bisq.core.trade.messages.PaymentAccountKeyResponse;
|
||||||
import java.time.Clock;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import javax.crypto.SecretKey;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -54,22 +47,9 @@ public class BuyerProcessesPaymentAccountKeyResponse extends TradeTask {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get peer's payment account payload key
|
|
||||||
PaymentAccountKeyResponse request = (PaymentAccountKeyResponse) processModel.getTradeMessage(); // TODO (woodser): verify request
|
|
||||||
trade.getTradingPeer().setPaymentAccountKey(request.getPaymentAccountKey());
|
|
||||||
|
|
||||||
// decrypt peer's payment account payload
|
// decrypt peer's payment account payload
|
||||||
SecretKey sk = Encryption.getSecretKeyFromBytes(trade.getTradingPeer().getPaymentAccountKey());
|
PaymentAccountKeyResponse request = (PaymentAccountKeyResponse) processModel.getTradeMessage();
|
||||||
byte[] decryptedPaymentAccountPayload = Encryption.decrypt(trade.getTradingPeer().getEncryptedPaymentAccountPayload(), sk);
|
trade.decryptPeersPaymentAccountPayload(request.getPaymentAccountKey());
|
||||||
CoreNetworkProtoResolver resolver = new CoreNetworkProtoResolver(Clock.systemDefaultZone()); // TODO: reuse resolver from elsewhere?
|
|
||||||
PaymentAccountPayload paymentAccountPayload = resolver.fromProto(protobuf.PaymentAccountPayload.parseFrom(decryptedPaymentAccountPayload));
|
|
||||||
|
|
||||||
// verify hash of payment account payload
|
|
||||||
byte[] peerPaymentAccountPayloadHash = trade instanceof MakerTrade ? trade.getContract().getTakerPaymentAccountPayloadHash() : trade.getContract().getMakerPaymentAccountPayloadHash();
|
|
||||||
if (!Arrays.equals(paymentAccountPayload.getHash(), peerPaymentAccountPayloadHash)) throw new RuntimeException("Hash of peer's payment account payload does not match contract");
|
|
||||||
|
|
||||||
// set payment account payload
|
|
||||||
trade.getTradingPeer().setPaymentAccountPayload(paymentAccountPayload);
|
|
||||||
|
|
||||||
// store updated multisig hex for processing on payment sent
|
// store updated multisig hex for processing on payment sent
|
||||||
trade.getTradingPeer().setUpdatedMultisigHex(request.getUpdatedMultisigHex());
|
trade.getTradingPeer().setUpdatedMultisigHex(request.getUpdatedMultisigHex());
|
||||||
|
|
|
@ -71,7 +71,8 @@ public class BuyerSendsPaymentSentMessage extends SendMailboxMessageTask {
|
||||||
trade.getCounterCurrencyExtraData(),
|
trade.getCounterCurrencyExtraData(),
|
||||||
deterministicId,
|
deterministicId,
|
||||||
trade.getBuyer().getPayoutTxHex(),
|
trade.getBuyer().getPayoutTxHex(),
|
||||||
trade.getBuyer().getUpdatedMultisigHex()
|
trade.getBuyer().getUpdatedMultisigHex(),
|
||||||
|
trade.getSelf().getPaymentAccountKey()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return message;
|
return message;
|
||||||
|
|
|
@ -64,7 +64,7 @@ public class ProcessSignContractRequest extends TradeTask {
|
||||||
TradingPeer trader = trade.getTradingPeer(request.getSenderNodeAddress());
|
TradingPeer trader = trade.getTradingPeer(request.getSenderNodeAddress());
|
||||||
trader.setDepositTxHash(request.getDepositTxHash());
|
trader.setDepositTxHash(request.getDepositTxHash());
|
||||||
trader.setAccountId(request.getAccountId());
|
trader.setAccountId(request.getAccountId());
|
||||||
trader.setPaymentAccountPayloadHash(request.getPaymentAccountPayloadHash()); // TODO: only seller's payment account payload is shared, so no need to send payment hash
|
trader.setPaymentAccountPayloadHash(request.getPaymentAccountPayloadHash());
|
||||||
trader.setPayoutAddressString(request.getPayoutAddress());
|
trader.setPayoutAddressString(request.getPayoutAddress());
|
||||||
|
|
||||||
// sign contract only when both deposit txs hashes known
|
// sign contract only when both deposit txs hashes known
|
||||||
|
@ -86,9 +86,9 @@ public class ProcessSignContractRequest extends TradeTask {
|
||||||
trade.setContractHash(Hash.getSha256Hash(checkNotNull(contractAsJson)));
|
trade.setContractHash(Hash.getSha256Hash(checkNotNull(contractAsJson)));
|
||||||
trade.getSelf().setContractSignature(signature);
|
trade.getSelf().setContractSignature(signature);
|
||||||
|
|
||||||
// seller sends encrypted payment account payload
|
// traders send encrypted payment account payload
|
||||||
byte[] encryptedPaymentAccountPayload = null;
|
byte[] encryptedPaymentAccountPayload = null;
|
||||||
if (trade.isSeller()) {
|
if (!trade.isArbitrator()) {
|
||||||
|
|
||||||
// generate random key to encrypt payment account payload
|
// generate random key to encrypt payment account payload
|
||||||
byte[] decryptionKey = ScryptUtil.getKeyCrypterScrypt().deriveKey(UUID.randomUUID().toString()).getKey();
|
byte[] decryptionKey = ScryptUtil.getKeyCrypterScrypt().deriveKey(UUID.randomUUID().toString()).getKey();
|
||||||
|
|
|
@ -61,11 +61,9 @@ public class ProcessSignContractResponse extends TradeTask {
|
||||||
else if (peer == processModel.getTaker()) peerPubKeyRing = trade.getTakerPubKeyRing();
|
else if (peer == processModel.getTaker()) peerPubKeyRing = trade.getTakerPubKeyRing();
|
||||||
else throw new RuntimeException(response.getClass().getSimpleName() + " is not from maker, taker, or arbitrator");
|
else throw new RuntimeException(response.getClass().getSimpleName() + " is not from maker, taker, or arbitrator");
|
||||||
|
|
||||||
// buyer saves seller's encrypted payment account payload
|
// save peer's encrypted payment account payload
|
||||||
if (trade.isBuyer() && peer == trade.getSeller()) {
|
|
||||||
peer.setEncryptedPaymentAccountPayload(response.getEncryptedPaymentAccountPayload());
|
peer.setEncryptedPaymentAccountPayload(response.getEncryptedPaymentAccountPayload());
|
||||||
if (peer.getEncryptedPaymentAccountPayload() == null) throw new RuntimeException("Seller did not send encrypted payment account payload");
|
if (peer.getEncryptedPaymentAccountPayload() == null) throw new RuntimeException("Peer did not send encrypted payment account payload");
|
||||||
}
|
|
||||||
|
|
||||||
// verify signature
|
// verify signature
|
||||||
// TODO (woodser): transfer contract for convenient comparison?
|
// TODO (woodser): transfer contract for convenient comparison?
|
||||||
|
|
|
@ -46,6 +46,9 @@ public class SellerProcessesPaymentSentMessage extends TradeTask {
|
||||||
trade.getBuyer().setPayoutTxHex(message.getPayoutTxHex());
|
trade.getBuyer().setPayoutTxHex(message.getPayoutTxHex());
|
||||||
trade.getBuyer().setUpdatedMultisigHex(message.getUpdatedMultisigHex());
|
trade.getBuyer().setUpdatedMultisigHex(message.getUpdatedMultisigHex());
|
||||||
|
|
||||||
|
// decrypt peer's payment account payload
|
||||||
|
trade.decryptPeersPaymentAccountPayload(message.getPaymentAccountKey());
|
||||||
|
|
||||||
// sync and update multisig wallet
|
// sync and update multisig wallet
|
||||||
if (trade.getBuyer().getUpdatedMultisigHex() != null) {
|
if (trade.getBuyer().getUpdatedMultisigHex() != null) {
|
||||||
XmrWalletService walletService = processModel.getProvider().getXmrWalletService();
|
XmrWalletService walletService = processModel.getProvider().getXmrWalletService();
|
||||||
|
|
|
@ -28,7 +28,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import monero.wallet.MoneroWallet;
|
import monero.wallet.MoneroWallet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send the buyer payment account info when the trade state is confirmed.
|
* Allow sender's payment account info to be decrypted when trade state is confirmed.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class SellerSendsPaymentAccountPayloadKey extends SendMailboxMessageTask {
|
public class SellerSendsPaymentAccountPayloadKey extends SendMailboxMessageTask {
|
||||||
|
@ -52,9 +52,6 @@ public class SellerSendsPaymentAccountPayloadKey extends SendMailboxMessageTask
|
||||||
protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) {
|
protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) {
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
|
|
||||||
// set payment account payload
|
|
||||||
trade.getSelf().setPaymentAccountPayload(processModel.getPaymentAccountPayload(trade));
|
|
||||||
|
|
||||||
// get updated multisig hex
|
// get updated multisig hex
|
||||||
if (trade.getSelf().getUpdatedMultisigHex() == null) {
|
if (trade.getSelf().getUpdatedMultisigHex() == null) {
|
||||||
XmrWalletService walletService = processModel.getProvider().getXmrWalletService();
|
XmrWalletService walletService = processModel.getProvider().getXmrWalletService();
|
||||||
|
|
|
@ -447,6 +447,7 @@ message PaymentSentMessage {
|
||||||
string counter_currency_extra_data = 6;
|
string counter_currency_extra_data = 6;
|
||||||
string payout_tx_hex = 7;
|
string payout_tx_hex = 7;
|
||||||
string updated_multisig_hex = 8;
|
string updated_multisig_hex = 8;
|
||||||
|
bytes payment_account_key = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PaymentReceivedMessage {
|
message PaymentReceivedMessage {
|
||||||
|
|
Loading…
Reference in a new issue