From 23f0969b2d8603ae39a5aa437a5a5198d95bb675 Mon Sep 17 00:00:00 2001 From: catbref Date: Mon, 7 Dec 2020 15:40:05 +0000 Subject: [PATCH] Requesting BTC/LTC wallet balance now accepts public key xpub/tpub too --- .../resource/CrossChainBitcoinResource.java | 14 +++++++------- .../resource/CrossChainLitecoinResource.java | 14 +++++++------- .../java/org/qortal/crosschain/Bitcoiny.java | 19 +++++++++++++------ .../org/qortal/test/crosschain/apps/Pay.java | 2 +- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java b/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java index 33a38024..f04b5a04 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java @@ -33,15 +33,15 @@ public class CrossChainBitcoinResource { @Path("/walletbalance") @Operation( summary = "Returns BTC balance for hierarchical, deterministic BIP32 wallet", - description = "Supply BIP32 'm' private key in base58, starting with 'xprv' for mainnet, 'tprv' for testnet", + description = "Supply BIP32 'm' private/public key in base58, starting with 'xprv'/'xpub' for mainnet, 'tprv'/'tpub' for testnet", requestBody = @RequestBody( required = true, content = @Content( mediaType = MediaType.TEXT_PLAIN, schema = @Schema( type = "string", - description = "BIP32 'm' private key in base58", - example = "tprv___________________________________________________________________________________________________________" + description = "BIP32 'm' private/public key in base58", + example = "tpub___________________________________________________________________________________________________________" ) ) ), @@ -52,15 +52,15 @@ public class CrossChainBitcoinResource { } ) @ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) - public String getBitcoinWalletBalance(String xprv58) { + public String getBitcoinWalletBalance(String key58) { Security.checkApiCallAllowed(request); Bitcoin bitcoin = Bitcoin.getInstance(); - if (!bitcoin.isValidXprv(xprv58)) + if (!bitcoin.isValidDeterministicKey(key58)) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PRIVATE_KEY); - Long balance = bitcoin.getWalletBalance(xprv58); + Long balance = bitcoin.getWalletBalance(key58); if (balance == null) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); @@ -102,7 +102,7 @@ public class CrossChainBitcoinResource { if (!bitcoin.isValidAddress(bitcoinSendRequest.receivingAddress)) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS); - if (!bitcoin.isValidXprv(bitcoinSendRequest.xprv58)) + if (!bitcoin.isValidDeterministicKey(bitcoinSendRequest.xprv58)) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PRIVATE_KEY); Transaction spendTransaction = bitcoin.buildSpend(bitcoinSendRequest.xprv58, diff --git a/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java b/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java index 8e6f3b32..5a8cd712 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java @@ -33,15 +33,15 @@ public class CrossChainLitecoinResource { @Path("/walletbalance") @Operation( summary = "Returns LTC balance for hierarchical, deterministic BIP32 wallet", - description = "Supply BIP32 'm' private key in base58, starting with 'xprv' for mainnet, 'tprv' for testnet", + description = "Supply BIP32 'm' private/public key in base58, starting with 'xprv'/'xpub' for mainnet, 'tprv'/'tpub' for testnet", requestBody = @RequestBody( required = true, content = @Content( mediaType = MediaType.TEXT_PLAIN, schema = @Schema( type = "string", - description = "BIP32 'm' private key in base58", - example = "tprv___________________________________________________________________________________________________________" + description = "BIP32 'm' private/public key in base58", + example = "tpub___________________________________________________________________________________________________________" ) ) ), @@ -52,15 +52,15 @@ public class CrossChainLitecoinResource { } ) @ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) - public String getLitecoinWalletBalance(String xprv58) { + public String getLitecoinWalletBalance(String key58) { Security.checkApiCallAllowed(request); Litecoin litecoin = Litecoin.getInstance(); - if (!litecoin.isValidXprv(xprv58)) + if (!litecoin.isValidDeterministicKey(key58)) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PRIVATE_KEY); - Long balance = litecoin.getWalletBalance(xprv58); + Long balance = litecoin.getWalletBalance(key58); if (balance == null) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); @@ -102,7 +102,7 @@ public class CrossChainLitecoinResource { if (!litecoin.isValidAddress(litecoinSendRequest.receivingAddress)) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS); - if (!litecoin.isValidXprv(litecoinSendRequest.xprv58)) + if (!litecoin.isValidDeterministicKey(litecoinSendRequest.xprv58)) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PRIVATE_KEY); Transaction spendTransaction = litecoin.buildSpend(litecoinSendRequest.xprv58, diff --git a/src/main/java/org/qortal/crosschain/Bitcoiny.java b/src/main/java/org/qortal/crosschain/Bitcoiny.java index d7f858f0..e4c9235d 100644 --- a/src/main/java/org/qortal/crosschain/Bitcoiny.java +++ b/src/main/java/org/qortal/crosschain/Bitcoiny.java @@ -98,7 +98,7 @@ public abstract class Bitcoiny implements ForeignBlockchain { @Override public boolean isValidWalletKey(String walletKey) { - return this.isValidXprv(walletKey); + return this.isValidDeterministicKey(walletKey); } // Actual useful methods for use by other classes @@ -111,10 +111,10 @@ public abstract class Bitcoiny implements ForeignBlockchain { return Amounts.prettyAmount(amount) + " " + this.currencyCode; } - public boolean isValidXprv(String xprv58) { + public boolean isValidDeterministicKey(String key58) { try { Context.propagate(this.bitcoinjContext); - DeterministicKey.deserializeB58(null, xprv58, this.params); + DeterministicKey.deserializeB58(null, key58, this.params); return true; } catch (IllegalArgumentException e) { return false; @@ -307,13 +307,20 @@ public abstract class Bitcoiny implements ForeignBlockchain { /** * Returns unspent Bitcoin balance given 'm' BIP32 key. * - * @param xprv58 BIP32 extended Bitcoin private key + * @param key58 BIP32/HD extended Bitcoin private/public key * @return unspent BTC balance, or null if unable to determine balance */ - public Long getWalletBalance(String xprv58) { + public Long getWalletBalance(String key58) { Context.propagate(bitcoinjContext); - Wallet wallet = Wallet.fromSpendingKeyB58(this.params, xprv58, DeterministicHierarchy.BIP32_STANDARDISATION_TIME_SECS); + final DeterministicKey watchKey = DeterministicKey.deserializeB58(null, key58, this.params); + + Wallet wallet; + if (watchKey.hasPrivKey()) + wallet = Wallet.fromSpendingKeyB58(this.params, key58, DeterministicHierarchy.BIP32_STANDARDISATION_TIME_SECS); + else + wallet = Wallet.fromWatchingKeyB58(this.params, key58, DeterministicHierarchy.BIP32_STANDARDISATION_TIME_SECS); + wallet.setUTXOProvider(new WalletAwareUTXOProvider(this, wallet)); Coin balance = wallet.getBalance(); diff --git a/src/test/java/org/qortal/test/crosschain/apps/Pay.java b/src/test/java/org/qortal/test/crosschain/apps/Pay.java index d8cf10c9..38ff4f14 100644 --- a/src/test/java/org/qortal/test/crosschain/apps/Pay.java +++ b/src/test/java/org/qortal/test/crosschain/apps/Pay.java @@ -53,7 +53,7 @@ public class Pay { params = bitcoiny.getNetworkParameters(); xprv58 = args[argIndex++]; - if (!bitcoiny.isValidXprv(xprv58)) + if (!bitcoiny.isValidDeterministicKey(xprv58)) usage("xprv invalid"); address = Address.fromString(params, args[argIndex++]);