mirror of
https://github.com/Qortal/qortal.git
synced 2025-05-08 02:37:58 +00:00
Added API call POST /crosschain/btc/send for sending Bitcoin
This commit is contained in:
parent
99d09a9877
commit
9007dfe779
25
src/main/java/org/qortal/api/model/BitcoinSendRequest.java
Normal file
25
src/main/java/org/qortal/api/model/BitcoinSendRequest.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package org.qortal.api.model;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
public class BitcoinSendRequest {
|
||||||
|
|
||||||
|
@Schema(description = "Bitcoin BIP32 extended private key", example = "tprv8ZgxMBicQKsPdahhFSrCdvC1bsWyzHHZfTneTVqUXN6s1wEtZLwAkZXzFP6TbTVGajEB55L1HYLg2aQMecZLXLre5YJcawpdFG66STVAWPJ")
|
||||||
|
public String xprv58;
|
||||||
|
|
||||||
|
@Schema(description = "Recipient's Bitcoin address ('legacy' P2PKH only)", example = "1BitcoinEaterAddressDontSendf59kuE")
|
||||||
|
public String receivingAddress;
|
||||||
|
|
||||||
|
@Schema(description = "Amount of BTC to send")
|
||||||
|
@XmlJavaTypeAdapter(value = org.qortal.api.AmountTypeAdapter.class)
|
||||||
|
public long bitcoinAmount;
|
||||||
|
|
||||||
|
public BitcoinSendRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -27,7 +27,7 @@ public class TradeBotCreateRequest {
|
|||||||
@Schema(description = "Suggested trade timeout (minutes)", example = "10080")
|
@Schema(description = "Suggested trade timeout (minutes)", example = "10080")
|
||||||
public int tradeTimeout;
|
public int tradeTimeout;
|
||||||
|
|
||||||
@Schema(description = "Bitcoin address for receiving", example = "1NCTG9oLk41bU6pcehLNo9DVJup77EHAVx")
|
@Schema(description = "Bitcoin address for receiving", example = "1BitcoinEaterAddressDontSendf59kuE")
|
||||||
public String receivingAddress;
|
public String receivingAddress;
|
||||||
|
|
||||||
public TradeBotCreateRequest() {
|
public TradeBotCreateRequest() {
|
||||||
|
@ -46,6 +46,7 @@ import org.qortal.api.model.CrossChainTradeRequest;
|
|||||||
import org.qortal.api.model.CrossChainTradeSummary;
|
import org.qortal.api.model.CrossChainTradeSummary;
|
||||||
import org.qortal.api.model.TradeBotCreateRequest;
|
import org.qortal.api.model.TradeBotCreateRequest;
|
||||||
import org.qortal.api.model.TradeBotRespondRequest;
|
import org.qortal.api.model.TradeBotRespondRequest;
|
||||||
|
import org.qortal.api.model.BitcoinSendRequest;
|
||||||
import org.qortal.api.model.CrossChainBitcoinP2SHStatus;
|
import org.qortal.api.model.CrossChainBitcoinP2SHStatus;
|
||||||
import org.qortal.api.model.CrossChainBitcoinRedeemRequest;
|
import org.qortal.api.model.CrossChainBitcoinRedeemRequest;
|
||||||
import org.qortal.api.model.CrossChainBitcoinRefundRequest;
|
import org.qortal.api.model.CrossChainBitcoinRefundRequest;
|
||||||
@ -947,6 +948,57 @@ public class CrossChainResource {
|
|||||||
return balance.toString();
|
return balance.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("/btc/send")
|
||||||
|
@Operation(
|
||||||
|
summary = "Sends BTC from BIP32 wallet to specific address",
|
||||||
|
description = "Currently only supports 'legacy' P2PKH Bitcoin addresses. Supply BIP32 'm' private key in base58, starting with 'xprv' for mainnet, 'tprv' for testnet",
|
||||||
|
requestBody = @RequestBody(
|
||||||
|
required = true,
|
||||||
|
content = @Content(
|
||||||
|
mediaType = MediaType.APPLICATION_JSON,
|
||||||
|
schema = @Schema(
|
||||||
|
implementation = BitcoinSendRequest.class
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
responses = {
|
||||||
|
@ApiResponse(
|
||||||
|
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA, ApiError.INVALID_ADDRESS, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE})
|
||||||
|
public String sendBitcoin(BitcoinSendRequest bitcoinSendRequest) {
|
||||||
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
|
if (bitcoinSendRequest.bitcoinAmount <= 0)
|
||||||
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||||
|
|
||||||
|
Address receivingAddress;
|
||||||
|
try {
|
||||||
|
receivingAddress = Address.fromString(BTC.getInstance().getNetworkParameters(), bitcoinSendRequest.receivingAddress);
|
||||||
|
} catch (AddressFormatException e) {
|
||||||
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only support P2PKH addresses at this time
|
||||||
|
if (receivingAddress.getOutputScriptType() != ScriptType.P2PKH)
|
||||||
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS);
|
||||||
|
|
||||||
|
if (!BTC.getInstance().isValidXprv(bitcoinSendRequest.xprv58))
|
||||||
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PRIVATE_KEY);
|
||||||
|
|
||||||
|
org.bitcoinj.core.Transaction spendTransaction = BTC.getInstance().buildSpend(bitcoinSendRequest.xprv58, bitcoinSendRequest.receivingAddress, bitcoinSendRequest.bitcoinAmount);
|
||||||
|
if (spendTransaction == null)
|
||||||
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BTC_BALANCE_ISSUE);
|
||||||
|
|
||||||
|
if (!BTC.getInstance().broadcastTransaction(spendTransaction))
|
||||||
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BTC_NETWORK_ISSUE);
|
||||||
|
|
||||||
|
return "true";
|
||||||
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/tradebot")
|
@Path("/tradebot")
|
||||||
@Operation(
|
@Operation(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user