3
0
mirror of https://github.com/Qortal/qortal.git synced 2025-02-12 02:05:50 +00:00

Added API call for creating an asset bid/ask order

Also added test for missing creator public key on API-submitted
transaction creation calls, like /payments/pay or /asset/issue.
(Needs to be an OpenAPI validator added at some point).
This commit is contained in:
catbref 2019-01-04 19:10:50 +00:00
parent 17f3958ad6
commit 2497ac256c
7 changed files with 79 additions and 9 deletions

View File

@ -4,7 +4,7 @@
<groupId>org.qora</groupId>
<artifactId>qora-core</artifactId>
<version>2.0.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<bouncycastle.version>1.60</bouncycastle.version>

View File

@ -32,6 +32,7 @@ import org.qora.data.account.AccountBalanceData;
import org.qora.data.asset.AssetData;
import org.qora.data.asset.OrderData;
import org.qora.data.asset.TradeData;
import org.qora.data.transaction.CreateOrderTransactionData;
import org.qora.data.transaction.IssueAssetTransactionData;
import org.qora.repository.DataException;
import org.qora.repository.Repository;
@ -39,6 +40,7 @@ import org.qora.repository.RepositoryManager;
import org.qora.transaction.Transaction;
import org.qora.transaction.Transaction.ValidationResult;
import org.qora.transform.TransformationException;
import org.qora.transform.transaction.CreateOrderTransactionTransformer;
import org.qora.transform.transaction.IssueAssetTransactionTransformer;
import org.qora.utils.Base58;
@ -243,7 +245,7 @@ public class AssetsResource {
),
responses = {
@ApiResponse(
description = "raw, unsigned payment transaction encoded in Base58",
description = "raw, unsigned, ISSUE_ASSET transaction encoded in Base58",
content = @Content(
mediaType = MediaType.TEXT_PLAIN,
schema = @Schema(
@ -271,4 +273,45 @@ public class AssetsResource {
}
}
@POST
@Path("/order")
@Operation(
summary = "Create asset order",
requestBody = @RequestBody(
required = true,
content = @Content(
mediaType = MediaType.APPLICATION_JSON,
schema = @Schema(implementation = CreateOrderTransactionData.class)
)
),
responses = {
@ApiResponse(
description = "raw, unsigned, CREATE_ORDER transaction encoded in Base58",
content = @Content(
mediaType = MediaType.TEXT_PLAIN,
schema = @Schema(
type = "string"
)
)
)
}
)
@ApiErrors({ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE, ApiError.TRANSACTION_INVALID})
public String createOrder(CreateOrderTransactionData transactionData) {
try (final Repository repository = RepositoryManager.getRepository()) {
Transaction transaction = Transaction.fromData(repository, transactionData);
ValidationResult result = transaction.isValidUnconfirmed();
if (result != ValidationResult.OK)
throw TransactionsResource.createTransactionInvalidException(request, result);
byte[] bytes = CreateOrderTransactionTransformer.toBytes(transactionData);
return Base58.encode(bytes);
} catch (TransformationException e) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSFORMATION_ERROR, e);
} catch (DataException e) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
}
}
}

View File

@ -38,7 +38,7 @@ public class NamesResource {
@POST
@Path("/register")
@Operation(
summary = "Build raw, unsigned REGISTER_NAME transaction",
summary = "Build raw, unsigned, REGISTER_NAME transaction",
requestBody = @RequestBody(
required = true,
content = @Content(
@ -50,7 +50,7 @@ public class NamesResource {
),
responses = {
@ApiResponse(
description = "raw, unsigned REGISTER_NAME transaction encoded in Base58",
description = "raw, unsigned, REGISTER_NAME transaction encoded in Base58",
content = @Content(
mediaType = MediaType.TEXT_PLAIN,
schema = @Schema(

View File

@ -38,7 +38,7 @@ public class PaymentsResource {
@POST
@Path("/pay")
@Operation(
summary = "Build raw, unsigned payment transaction",
summary = "Build raw, unsigned, PAYMENT transaction",
requestBody = @RequestBody(
required = true,
content = @Content(
@ -50,7 +50,7 @@ public class PaymentsResource {
),
responses = {
@ApiResponse(
description = "raw, unsigned payment transaction encoded in Base58",
description = "raw, unsigned, PAYMENT transaction encoded in Base58",
content = @Content(
mediaType = MediaType.TEXT_PLAIN,
schema = @Schema(

View File

@ -4,10 +4,12 @@ import java.math.BigDecimal;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import org.qora.transaction.Transaction.TransactionType;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.AccessMode;
// All properties to be converted to JSON via JAX-RS
@XmlAccessorType(XmlAccessType.FIELD)
@ -15,15 +17,20 @@ import io.swagger.v3.oas.annotations.media.Schema;
public class CreateOrderTransactionData extends TransactionData {
// Properties
@Schema(description = "asset on offer to give by order creator")
private long haveAssetId;
@Schema(description = "asset wanted to receive by order creator")
private long wantAssetId;
@Schema(description = "amount of \"have\" asset to trade")
private BigDecimal amount;
@Schema(description = "amount of \"want\" asset to receive per unit of \"have\" asset traded")
private BigDecimal price;
// Constructors
// For JAX-RS
protected CreateOrderTransactionData() {
super(TransactionType.CREATE_ASSET_ORDER);
}
public CreateOrderTransactionData(byte[] creatorPublicKey, long haveAssetId, long wantAssetId, BigDecimal amount, BigDecimal price, BigDecimal fee,
@ -59,4 +66,17 @@ public class CreateOrderTransactionData extends TransactionData {
return this.price;
}
// Re-expose creatorPublicKey for this transaction type for JAXB
@XmlElement(name = "creatorPublicKey")
@Schema(name = "creatorPublicKey", description = "order creator's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP")
public byte[] getOrderCreatorPublicKey() {
return this.creatorPublicKey;
}
@XmlElement(name = "creatorPublicKey")
@Schema(name = "creatorPublicKey", description = "order creator's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP")
public void setOrderCreatorPublicKey(byte[] creatorPublicKey) {
this.creatorPublicKey = creatorPublicKey;
}
}

View File

@ -22,9 +22,9 @@ public class PaymentTransactionData extends TransactionData {
private String recipient;
@Schema(description = "amount to send", example = "123.456")
@XmlJavaTypeAdapter(
type = BigDecimal.class,
value = org.qora.api.BigDecimalTypeAdapter.class
)
type = BigDecimal.class,
value = org.qora.api.BigDecimalTypeAdapter.class
)
private BigDecimal amount;
// Constructors

View File

@ -108,6 +108,7 @@ public abstract class Transaction {
AT_IS_FINISHED(40),
ASSET_DOES_NOT_MATCH_AT(41),
ASSET_ALREADY_EXISTS(43),
MISSING_CREATOR(44),
NOT_YET_RELEASED(1000);
public final int value;
@ -364,6 +365,9 @@ public abstract class Transaction {
* @throws DataException
*/
protected Account getCreator() throws DataException {
if (this.transactionData.getCreatorPublicKey() == null)
return null;
return new PublicKeyAccount(this.repository, this.transactionData.getCreatorPublicKey());
}
@ -432,6 +436,9 @@ public abstract class Transaction {
public ValidationResult isValidUnconfirmed() throws DataException {
try {
Account creator = this.getCreator();
if (creator == null)
return ValidationResult.MISSING_CREATOR;
creator.setLastReference(creator.getUnconfirmedLastReference());
return this.isValid();
} finally {