diff --git a/src/main/java/org/qortal/api/model/CrossChainCancelRequest.java b/src/main/java/org/qortal/api/model/CrossChainCancelRequest.java
index f87471d0..25a18952 100644
--- a/src/main/java/org/qortal/api/model/CrossChainCancelRequest.java
+++ b/src/main/java/org/qortal/api/model/CrossChainCancelRequest.java
@@ -8,8 +8,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
@XmlAccessorType(XmlAccessType.FIELD)
public class CrossChainCancelRequest {
- @Schema(description = "AT creator's 'trade' public key", example = "K6wuddsBV3HzRrXFFezE7P5MoRXp5m3mEDokRDGZB6ry")
- public byte[] tradePublicKey;
+ @Schema(description = "AT creator's public key", example = "K6wuddsBV3HzRrXFFezE7P5MoRXp5m3mEDokRDGZB6ry")
+ public byte[] creatorPublicKey;
@Schema(description = "Qortal trade AT address")
public String atAddress;
diff --git a/src/main/java/org/qortal/api/resource/CrossChainResource.java b/src/main/java/org/qortal/api/resource/CrossChainResource.java
index 40654179..6901af06 100644
--- a/src/main/java/org/qortal/api/resource/CrossChainResource.java
+++ b/src/main/java/org/qortal/api/resource/CrossChainResource.java
@@ -380,7 +380,7 @@ public class CrossChainResource {
summary = "Builds raw, unsigned 'cancel' MESSAGE transaction that cancels cross-chain trade offer",
description = "Specify address of cross-chain AT that needs to be cancelled.
"
+ "AT needs to be in 'offer' mode. Messages sent to an AT in 'trade' mode will be ignored, but still cost fees to send!
"
- + "You need to sign output with trade's private key otherwise the MESSAGE transaction will be invalid.",
+ + "You need to sign output with AT creator's private key otherwise the MESSAGE transaction will be invalid.",
requestBody = @RequestBody(
required = true,
content = @Content(
@@ -404,9 +404,9 @@ public class CrossChainResource {
public String buildCancelMessage(CrossChainCancelRequest cancelRequest) {
Security.checkApiCallAllowed(request);
- byte[] tradePublicKey = cancelRequest.tradePublicKey;
+ byte[] creatorPublicKey = cancelRequest.creatorPublicKey;
- if (tradePublicKey == null || tradePublicKey.length != Transformer.PUBLIC_KEY_LENGTH)
+ if (creatorPublicKey == null || creatorPublicKey.length != Transformer.PUBLIC_KEY_LENGTH)
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PUBLIC_KEY);
if (cancelRequest.atAddress == null || !Crypto.isValidAtAddress(cancelRequest.atAddress))
@@ -419,16 +419,16 @@ public class CrossChainResource {
if (crossChainTradeData.mode != BTCACCT.Mode.OFFERING)
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
- // Does supplied public key match trade public key?
- if (!Crypto.toAddress(tradePublicKey).equals(crossChainTradeData.qortalCreatorTradeAddress))
+ // Does supplied public key match AT creator's public key?
+ if (!Arrays.equals(creatorPublicKey, atData.getCreatorPublicKey()))
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PUBLIC_KEY);
// Good to make MESSAGE
- String atCreatorAddress = crossChainTradeData.qortalCreator;
+ String atCreatorAddress = Crypto.toAddress(creatorPublicKey);
byte[] messageData = BTCACCT.buildCancelMessage(atCreatorAddress);
- byte[] messageTransactionBytes = buildAtMessage(repository, tradePublicKey, cancelRequest.atAddress, messageData);
+ byte[] messageTransactionBytes = buildAtMessage(repository, creatorPublicKey, cancelRequest.atAddress, messageData);
return Base58.encode(messageTransactionBytes);
} catch (DataException e) {
@@ -1222,12 +1222,18 @@ public class CrossChainResource {
}
private byte[] buildAtMessage(Repository repository, byte[] senderPublicKey, String atAddress, byte[] messageData) throws DataException {
- // senderPublicKey is actually ephemeral trade public key, so there is no corresponding account and hence no reference
long txTimestamp = NTP.getTime();
- Random random = new Random();
- byte[] lastReference = new byte[Transformer.SIGNATURE_LENGTH];
- random.nextBytes(lastReference);
+ // senderPublicKey could be ephemeral trade public key where there is no corresponding account and hence no reference
+ String senderAddress = Crypto.toAddress(senderPublicKey);
+ byte[] lastReference = repository.getAccountRepository().getLastReference(senderAddress);
+ final boolean requiresPoW = lastReference == null;
+
+ if (requiresPoW) {
+ Random random = new Random();
+ lastReference = new byte[Transformer.SIGNATURE_LENGTH];
+ random.nextBytes(lastReference);
+ }
int version = 4;
int nonce = 0;
@@ -1240,7 +1246,12 @@ public class CrossChainResource {
MessageTransaction messageTransaction = new MessageTransaction(repository, messageTransactionData);
- messageTransaction.computeNonce();
+ if (requiresPoW) {
+ messageTransaction.computeNonce();
+ } else {
+ fee = messageTransaction.calcRecommendedFee();
+ messageTransactionData.setFee(fee);
+ }
ValidationResult result = messageTransaction.isValidUnconfirmed();
if (result != ValidationResult.OK)