diff --git a/pom.xml b/pom.xml index 1e42d8f1..36d73da7 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.qora qora-core 2.0.0-SNAPSHOT - bundle + jar UTF-8 1.60 diff --git a/src/main/java/org/qora/api/resource/AssetsResource.java b/src/main/java/org/qora/api/resource/AssetsResource.java index a6e89697..9c0df73a 100644 --- a/src/main/java/org/qora/api/resource/AssetsResource.java +++ b/src/main/java/org/qora/api/resource/AssetsResource.java @@ -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); + } + } + } diff --git a/src/main/java/org/qora/api/resource/NamesResource.java b/src/main/java/org/qora/api/resource/NamesResource.java index f4a8a684..b6332567 100644 --- a/src/main/java/org/qora/api/resource/NamesResource.java +++ b/src/main/java/org/qora/api/resource/NamesResource.java @@ -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( diff --git a/src/main/java/org/qora/api/resource/PaymentsResource.java b/src/main/java/org/qora/api/resource/PaymentsResource.java index a37a9f44..ddce2712 100644 --- a/src/main/java/org/qora/api/resource/PaymentsResource.java +++ b/src/main/java/org/qora/api/resource/PaymentsResource.java @@ -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( diff --git a/src/main/java/org/qora/data/transaction/CreateOrderTransactionData.java b/src/main/java/org/qora/data/transaction/CreateOrderTransactionData.java index 8e3f0233..324cb85b 100644 --- a/src/main/java/org/qora/data/transaction/CreateOrderTransactionData.java +++ b/src/main/java/org/qora/data/transaction/CreateOrderTransactionData.java @@ -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; + } + } diff --git a/src/main/java/org/qora/data/transaction/PaymentTransactionData.java b/src/main/java/org/qora/data/transaction/PaymentTransactionData.java index 2352fd40..d9b82aef 100644 --- a/src/main/java/org/qora/data/transaction/PaymentTransactionData.java +++ b/src/main/java/org/qora/data/transaction/PaymentTransactionData.java @@ -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 diff --git a/src/main/java/org/qora/transaction/Transaction.java b/src/main/java/org/qora/transaction/Transaction.java index e535224b..d51a777a 100644 --- a/src/main/java/org/qora/transaction/Transaction.java +++ b/src/main/java/org/qora/transaction/Transaction.java @@ -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 {