diff --git a/src/main/java/org/qortal/api/resource/CrossChainResource.java b/src/main/java/org/qortal/api/resource/CrossChainResource.java index 42c0cbe5..0c61c83b 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainResource.java @@ -1045,7 +1045,7 @@ public class CrossChainResource { ) } ) - @ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE}) + @ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.INVALID_CRITERIA, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE, ApiError.REPOSITORY_ISSUE}) public String tradeBotResponder(TradeBotRespondRequest tradeBotRespondRequest) { Security.checkApiCallAllowed(request); @@ -1068,9 +1068,22 @@ public class CrossChainResource { if (crossChainTradeData.mode != BTCACCT.Mode.OFFERING) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA); - boolean result = TradeBot.startResponse(repository, crossChainTradeData, tradeBotRespondRequest.xprv58, tradeBotRespondRequest.receivingAddress); + TradeBot.ResponseResult result = TradeBot.startResponse(repository, crossChainTradeData, tradeBotRespondRequest.xprv58, tradeBotRespondRequest.receivingAddress); - return result ? "true" : "false"; + switch (result) { + case OK: + return "true"; + + case INSUFFICIENT_FUNDS: + case BTC_BALANCE_ISSUE: + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BTC_BALANCE_ISSUE); + + case BTC_NETWORK_ISSUE: + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BTC_NETWORK_ISSUE); + + default: + return "false"; + } } catch (DataException e) { throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } diff --git a/src/main/java/org/qortal/controller/TradeBot.java b/src/main/java/org/qortal/controller/TradeBot.java index afe5c5f6..0c22cb48 100644 --- a/src/main/java/org/qortal/controller/TradeBot.java +++ b/src/main/java/org/qortal/controller/TradeBot.java @@ -45,6 +45,8 @@ import org.qortal.utils.NTP; public class TradeBot { + public enum ResponseResult { OK, INSUFFICIENT_FUNDS, BTC_BALANCE_ISSUE, BTC_NETWORK_ISSUE } + private static final Logger LOGGER = LogManager.getLogger(TradeBot.class); private static final Random RANDOM = new SecureRandom(); private static final long FEE_AMOUNT = 1000L; @@ -203,7 +205,7 @@ public class TradeBot { * @return true if P2SH-A funding transaction successfully broadcast to Bitcoin network, false otherwise * @throws DataException */ - public static boolean startResponse(Repository repository, CrossChainTradeData crossChainTradeData, String xprv58, String receivingAddress) throws DataException { + public static ResponseResult startResponse(Repository repository, CrossChainTradeData crossChainTradeData, String xprv58, String receivingAddress) throws DataException { byte[] tradePrivateKey = generateTradePrivateKey(); byte[] secretA = generateSecret(); byte[] hashOfSecretA = Crypto.hash160(secretA); @@ -233,7 +235,7 @@ public class TradeBot { Transaction fundingCheckTransaction = BTC.getInstance().buildSpend(xprv58, tradeForeignAddress, totalFundsRequired); if (fundingCheckTransaction == null) - return false; + return ResponseResult.INSUFFICIENT_FUNDS; // P2SH-A to be funded byte[] redeemScriptBytes = BTCP2SH.buildScript(tradeForeignPublicKeyHash, lockTimeA, crossChainTradeData.creatorBitcoinPKH, hashOfSecretA); @@ -241,10 +243,15 @@ public class TradeBot { // Fund P2SH-A Transaction p2shFundingTransaction = BTC.getInstance().buildSpend(tradeBotData.getXprv58(), p2shAddress, crossChainTradeData.expectedBitcoin + FEE_AMOUNT); + if (p2shFundingTransaction == null) { + LOGGER.warn(() -> String.format("Unable to build P2SH-A funding transaction - lack of funds?")); + return ResponseResult.BTC_BALANCE_ISSUE; + } + if (!BTC.getInstance().broadcastTransaction(p2shFundingTransaction)) { // We couldn't fund P2SH-A at this time LOGGER.debug(() -> String.format("Couldn't broadcast P2SH-A funding transaction?")); - return false; + return ResponseResult.BTC_NETWORK_ISSUE; } repository.getCrossChainRepository().save(tradeBotData); @@ -252,7 +259,7 @@ public class TradeBot { LOGGER.info(() -> String.format("Funding P2SH-A %s. Waiting for confirmation", p2shAddress)); - return true; + return ResponseResult.OK; } private static byte[] generateTradePrivateKey() {