diff --git a/pom.xml b/pom.xml index f1973689..e0e3f90c 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ 3.4.0 ${maven.build.timestamp} 1.4.1 - 3.10.0 + 3.8.0 1.11.0 2.11.0 1.24.0 @@ -43,7 +43,7 @@ 3.3.0 3.3.1 3.5.1 - 3.2.1 + 3.2.2 1.1.0 UTF-8 3.24.4 diff --git a/src/main/java/org/qortal/api/resource/CrossChainPirateChainResource.java b/src/main/java/org/qortal/api/resource/CrossChainPirateChainResource.java index 550b86b9..7f2e8402 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainPirateChainResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainPirateChainResource.java @@ -222,6 +222,77 @@ public class CrossChainPirateChainResource { } } + @POST + @Path("/walletprivatekey") + @Operation( + summary = "Returns main wallet private key", + description = "Supply 32 bytes of entropy, Base58 encoded", + requestBody = @RequestBody( + required = true, + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string", + description = "32 bytes of entropy, Base58 encoded", + example = "5oSXF53qENtdUyKhqSxYzP57m6RhVFP9BJKRr9E5kRGV" + ) + ) + ), + responses = { + @ApiResponse( + content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string", description = "Private Key String")) + ) + } + ) + @ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) + @SecurityRequirement(name = "apiKey") + public String getPirateChainPrivateKey(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String entropy58) { + Security.checkApiCallAllowed(request); + + PirateChain pirateChain = PirateChain.getInstance(); + + try { + return pirateChain.getPrivateKey(entropy58); + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE, e.getMessage()); + } + } + + @POST + @Path("/walletseedphrase") + @Operation( + summary = "Returns main wallet seedphrase", + description = "Supply 32 bytes of entropy, Base58 encoded", + requestBody = @RequestBody( + required = true, + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string", + description = "32 bytes of entropy, Base58 encoded", + example = "5oSXF53qENtdUyKhqSxYzP57m6RhVFP9BJKRr9E5kRGV" + ) + ) + ), + responses = { + @ApiResponse( + content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string", description = "Wallet Seedphrase String")) + ) + } + ) + @ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) + @SecurityRequirement(name = "apiKey") + public String getPirateChainWalletSeed(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String entropy58) { + Security.checkApiCallAllowed(request); + + PirateChain pirateChain = PirateChain.getInstance(); + + try { + return pirateChain.getWalletSeed(entropy58); + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE, e.getMessage()); + } + } @POST @Path("/syncstatus") diff --git a/src/main/java/org/qortal/crosschain/PirateChain.java b/src/main/java/org/qortal/crosschain/PirateChain.java index 403d90e5..6587baca 100644 --- a/src/main/java/org/qortal/crosschain/PirateChain.java +++ b/src/main/java/org/qortal/crosschain/PirateChain.java @@ -356,6 +356,30 @@ public class PirateChain extends Bitcoiny { } } + public String getPrivateKey(String entropy58) throws ForeignBlockchainException { + synchronized (this) { + PirateChainWalletController walletController = PirateChainWalletController.getInstance(); + walletController.initWithEntropy58(entropy58); + walletController.ensureInitialized(); + walletController.ensureNotNullSeed(); + walletController.getCurrentWallet().unlock(); + + return walletController.getCurrentWallet().getPrivateKey(); + } + } + + public String getWalletSeed(String entropy58) throws ForeignBlockchainException { + synchronized (this) { + PirateChainWalletController walletController = PirateChainWalletController.getInstance(); + walletController.initWithEntropy58(entropy58); + walletController.ensureInitialized(); + walletController.ensureNotNullSeed(); + walletController.getCurrentWallet().unlock(); + + return walletController.getCurrentWallet().getWalletSeed(entropy58); + } + } + public String getUnusedReceiveAddress(String key58) throws ForeignBlockchainException { // For now, return the main wallet address // FUTURE: generate an unused one diff --git a/src/main/java/org/qortal/crosschain/PirateWallet.java b/src/main/java/org/qortal/crosschain/PirateWallet.java index 4b95d3cc..d8fdc351 100644 --- a/src/main/java/org/qortal/crosschain/PirateWallet.java +++ b/src/main/java/org/qortal/crosschain/PirateWallet.java @@ -398,6 +398,25 @@ public class PirateWallet { return null; } + public String getWalletSeed(String entropy58) { + // Decode entropy to bytes + byte[] myEntropyBytes = Base58.decode(entropy58); + + // Pirate library uses base64 encoding + String myEntropy64 = Base64.toBase64String(myEntropyBytes); + + // Derive seed phrase from entropy bytes + String mySeedResponse = LiteWalletJni.getseedphrasefromentropyb64(myEntropy64); + JSONObject mySeedJson = new JSONObject(mySeedResponse); + String mySeedPhrase = null; + if (mySeedJson.has("seedPhrase")) { + mySeedPhrase = mySeedJson.getString("seedPhrase"); + + return mySeedPhrase; + } + return null; + } + public PirateLightClient.Server getRandomServer() { PirateChain.PirateChainNet pirateChainNet = Settings.getInstance().getPirateChainNet(); Collection servers = pirateChainNet.getServers();