From 762cd6dc3481101d93c8a46cf63e513b0082533c Mon Sep 17 00:00:00 2001 From: nkramer44 Date: Tue, 4 May 2021 15:50:32 -0400 Subject: [PATCH] remove SendPayment.java. Add Java to send-xrp tutorial --- content/_code-samples/send-xrp/SendXrp.java | 102 ++++++++++++++++++ content/_code-samples/xrpl4j/SendPayment.java | 56 ---------- .../use-simple-xrp-payments/send-xrp.md | 66 +++++++++++- 3 files changed, 163 insertions(+), 61 deletions(-) create mode 100644 content/_code-samples/send-xrp/SendXrp.java delete mode 100644 content/_code-samples/xrpl4j/SendPayment.java diff --git a/content/_code-samples/send-xrp/SendXrp.java b/content/_code-samples/send-xrp/SendXrp.java new file mode 100644 index 0000000000..269567818f --- /dev/null +++ b/content/_code-samples/send-xrp/SendXrp.java @@ -0,0 +1,102 @@ +// Example Credentials ---------------------------------------------------------- +WalletFactory walletFactory = DefaultWalletFactory.getInstance(); +Wallet testWallet = walletFactory.fromSeed("sn3nxiW7v8KXzPzAqzyHXbSSKNuN9", true).wallet(); + +// Get the Classic address from testWallet +Address classicAddress = testWallet.classicAddress(); +System.out.println(classicAddress); // "rMCcNuTcajgw7YTgBy1sys3b89QqjUrMpH" + +// Connect ---------------------------------------------------------------------- +HttpUrl rippledUrl = HttpUrl.get("https://s.altnet.rippletest.net:51234/"); +XrplClient xrplClient = new XrplClient(rippledUrl); + +// Prepare transaction ---------------------------------------------------------- +// Look up your Account Info +AccountInfoRequestParams requestParams = AccountInfoRequestParams.builder() + .ledgerIndex(LedgerIndex.VALIDATED) + .account(classicAddress) + .build(); +AccountInfoResult accountInfoResult = xrplClient.accountInfo(requestParams); +UnsignedInteger sequence = accountInfoResult.accountData().sequence(); + +// Request current fee information from rippled +FeeResult feeResult = xrplClient.fee(); +XrpCurrencyAmount openLedgerFee = feeResult.drops().openLedgerFee(); + +// Get the latest validated ledger index +LedgerIndex validatedLedger = xrplClient.ledger(LedgerRequestParams.builder().ledgerIndex(LedgerIndex.VALIDATED).build()) + .ledgerIndex() + .orElseThrow(() -> new RuntimeException("LedgerIndex not available.")); + +// Workaround for https://github.com/XRPLF/xrpl4j/issues/84 +UnsignedInteger lastLedgerSequence = UnsignedInteger.valueOf( + validatedLedger.plus(UnsignedLong.valueOf(4)).unsignedLongValue().intValue() + ); + +// Construct a Payment +Payment payment = Payment.builder() + .account(classicAddress) + .amount(XrpCurrencyAmount.ofXrp(BigDecimal.ONE)) + .destination(Address.of("rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe")) + .sequence(sequence) + .fee(openLedgerFee) + .signingPublicKey(testWallet.publicKey()) + .lastLedgerSequence(lastLedgerSequence) + .build(); +System.out.println("Constructed Payment: " + payment); + +// Sign transaction ------------------------------------------------------------- +// Construct a SignatureService to sign the Payment +PrivateKey privateKey = PrivateKey.fromBase16EncodedPrivateKey(testWallet.privateKey().get()); +SignatureService signatureService = new SingleKeySignatureService(privateKey); + +// Sign the Payment +SignedTransaction signedPayment = signatureService.sign(KeyMetadata.EMPTY, payment); +System.out.println("Signed Payment: " + signedPayment.signedTransaction()); + +// Submit transaction ----------------------------------------------------------- +SubmitResult submitResult = xrplClient.submit(signedPayment); +System.out.println(submitResult); + +// Wait for validation ---------------------------------------------------------- +boolean transactionValidated = false; +boolean transactionExpired = false; +while (!transactionValidated && !transactionExpired) { + Thread.sleep(4 * 1000); + LedgerIndex latestValidatedLedgerIndex = xrplClient.ledger( + LedgerRequestParams.builder().ledgerIndex(LedgerIndex.VALIDATED).build() + ) + .ledgerIndex() + .orElseThrow(() -> new RuntimeException("Ledger response did not contain a LedgerIndex.")); + + TransactionResult transactionResult = xrplClient.transaction( + TransactionRequestParams.of(signedPayment.hash()), + Payment.class + ); + + if (transactionResult.validated()) { + System.out.println("Payment was validated with result code " + transactionResult.metadata().get().transactionResult()); + transactionValidated = true; + } else { + boolean lastLedgerSequenceHasPassed = FluentCompareTo. + is(latestValidatedLedgerIndex.unsignedLongValue()) + .greaterThan(UnsignedLong.valueOf(lastLedgerSequence.intValue())); + if (lastLedgerSequenceHasPassed) { + System.out.println("Payment was never validated and has expired."); + transactionExpired = true; + } else { + System.out.println("Payment not yet validated."); + } + } +} + +// Check transaction results ---------------------------------------------------- +System.out.println(transactionResult); +System.out.println("Explorer link: https://testnet.xrpl.org/transactions/" + signedPayment.hash()); +transactionResult.metadata().ifPresent(metadata -> { + System.out.println("Result code: " + metadata.transactionResult()); + + metadata.deliveredAmount().ifPresent(deliveredAmount -> + System.out.println("XRP Delivered: " + ((XrpCurrencyAmount) deliveredAmount).toXrp()) + ); +}); diff --git a/content/_code-samples/xrpl4j/SendPayment.java b/content/_code-samples/xrpl4j/SendPayment.java deleted file mode 100644 index e025721250..0000000000 --- a/content/_code-samples/xrpl4j/SendPayment.java +++ /dev/null @@ -1,56 +0,0 @@ -// Construct a network client -final HttpUrl rippledUrl = HttpUrl.get("https://s.altnet.rippletest.net:51234/"); -XrplClient xrplClient = new XrplClient(rippledUrl); - -// Create a Wallet using a WalletFactory -WalletFactory walletFactory = DefaultWalletFactory.getInstance(); -final Wallet testWallet = walletFactory.randomWallet(true).wallet(); -System.out.println("Generated a wallet with the following public key: " + testWallet.publicKey()); - -// Get the Classic and X-Addresses from testWallet -final Address classicAddress = testWallet.classicAddress(); -System.out.println("Classic Address: " + classicAddress); - -// Fund the account using the testnet Faucet -final FaucetClient faucetClient = FaucetClient - .construct(HttpUrl.get("https://faucet.altnet.rippletest.net")); -faucetClient.fundAccount(FundAccountRequest.of(classicAddress)); -System.out.println("Funded the account using the Testnet faucet."); - -// Look up your Account Info -final AccountInfoRequestParams requestParams = AccountInfoRequestParams.of(classicAddress); -final AccountInfoResult accountInfoResult = xrplClient.accountInfo(requestParams); -final UnsignedInteger sequence = accountInfoResult.accountData().sequence(); - -// Request current fee information from rippled -final FeeResult feeResult = xrplClient.fee(); -final XrpCurrencyAmount openLedgerFee = feeResult.drops().openLedgerFee(); - -// Construct a Payment -Payment payment = Payment.builder() - .account(classicAddress) - .amount(XrpCurrencyAmount.ofXrp(BigDecimal.ONE)) - .destination(Address.of("rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe")) - .sequence(sequence) - .fee(openLedgerFee) - .signingPublicKey(testWallet.publicKey()) - .build(); - -// Print the Payment -System.out.println("Constructed Payment: " + payment); - -// Construct a SignatureService to sign the Payment -PrivateKey privateKey = PrivateKey.fromBase16EncodedPrivateKey(testWallet.privateKey().get()); -SignatureService signatureService = new SingleKeySignatureService(privateKey); - -// Sign the Payment -final SignedTransaction signedPayment = signatureService.sign(KeyMetadata.EMPTY, payment); - -// Print the signed transaction -System.out.println("Signed Payment: " + signedPayment.signedTransaction()); - -// Submit the Payment -final SubmitResult submitResult = xrplClient.submit(signedPayment); - -// Print the response -System.out.println(submitResult); diff --git a/content/tutorials/use-simple-xrp-payments/send-xrp.md b/content/tutorials/use-simple-xrp-payments/send-xrp.md index 97df74fd2a..9c0a8aafa0 100644 --- a/content/tutorials/use-simple-xrp-payments/send-xrp.md +++ b/content/tutorials/use-simple-xrp-payments/send-xrp.md @@ -12,9 +12,9 @@ filters: --- # Send XRP -This tutorial explains how to send a simple XRP Payment using ripple-lib for JavaScript or xrpl-py for Python. First, we step through the process with the [XRP Ledger Testnet](parallel-networks.html). Then, we compare that to the additional requirements for doing the equivalent in production. +This tutorial explains how to send a simple XRP Payment using ripple-lib for JavaScript, xrpl-py for Python, or xrpl4j for Java. First, we step through the process with the [XRP Ledger Testnet](parallel-networks.html). Then, we compare that to the additional requirements for doing the equivalent in production. -**Tip:** Check out the [Code Samples](https://github.com/ripple/xrpl-dev-portal/tree/master/content/_code-samples) for a complete version of the code used in this tutorial. +**Tip:** Check out the [Code Samples](https://github.com/ripple/xrpl-dev-portal/tree/master/content/_code-samples) for a complete version of the code used in this tutorial. ## Prerequisites @@ -48,7 +48,7 @@ _Python_ _Java_ -{{ include_code("_code-samples/send-xrp/send-xrp.py", end_before="# Connect", language="py") }} +{{ include_code("_code-samples/send-xrp/SendXrp.java", end_before="// Connect", language="java") }} @@ -75,6 +75,10 @@ _Python_ {{ include_code("_code-samples/send-xrp/send-xrp.py", start_with="# Connect", end_before="# Get credentials", language="py") }} +_Java_ + +{{ include_code("_code-samples/send-xrp/SendXrp.java", start_with="// Connect", end_before="// Prepare transaction", language="java") }} + For this tutorial, you can connect directly from your browser by pressing the following button: @@ -106,6 +110,9 @@ Technically, a viable transaction must contain some additional fields, and certa - If you're using ripple-lib for JavaScript, you can use the [`prepareTransaction()` method](rippleapi-reference.html#preparetransaction) to automatically fill in good defaults for the remaining fields of a transaction. - With xrpl-py for Python, you can use the models in `xrpl.models.transactions` to construct transactions as native Python objects. +- With xrpl4j for Java, you can use the model objects in the `xrpl4j-model` module to construct transactions as Java objects. + - Unlike the other SDKs, you must provide the account `sequence` and the `signingPublicKey` of the source + account of a `Transaction` at the time of construction, as well as a `fee`. Here's an example of preparing the above payment: @@ -119,6 +126,10 @@ _Python_ {{ include_code("_code-samples/send-xrp/send-xrp.py", start_with="# Prepare", end_before="# Sign", language="py" ) }} +_Java_ + +{{ include_code("_code-samples/send-xrp/SendXrp.java", start_with="// Prepare", end_before="// Sign", language="java") }} + {{ start_step("Prepare") }} @@ -145,6 +156,7 @@ Signing a transaction uses your credentials to authorize the transaction on your - **JavaScript:** Use the [sign() method](rippleapi-reference.html#sign) to sign the transaction with ripple-lib. The first argument is a string version of the JSON transaction to sign. - **Python:** Use the [xrpl.transaction.safe_sign_transaction() method](https://xrpl-py.readthedocs.io/en/latest/source/xrpl.transaction.html#xrpl.transaction.safe_sign_transaction) with a model and wallet object. +- **Java:** Use a [`SignatureService`](https://javadoc.io/doc/org.xrpl/xrpl4j-crypto-core/latest/org/xrpl/xrpl4j/crypto/signing/SignatureService.html) instance to sign the transaction. For this tutorial, use the [`SingleKeySignatureService`](https://javadoc.io/doc/org.xrpl/xrpl4j-crypto-bouncycastle/latest/org/xrpl/xrpl4j/crypto/signing/SingleKeySignatureService.html). @@ -158,12 +170,18 @@ _Python_ {{ include_code("_code-samples/send-xrp/send-xrp.py", start_with="# Sign", end_before="# Submit", language="py" ) }} +_Java_ + +{{ include_code("_code-samples/send-xrp/SendXrp.java", + start_with="// Sign", end_before="// Submit", language="java" ) }} + The result of the signing operation is a transaction object containing a signature. Typically, XRP Ledger APIs expect a signed transaction to be the hexadecimal representation of the transaction's canonical [binary format](serialization.html), called a "blob". - In ripple-lib, the signing API also returns the transaction's ID, or identifying hash, which you can use to look up the transaction later. This is a 64-character hexadecimal string that is unique to this transaction. - In xrpl-py, you can get the transaction's hash in the response to submitting it in the next step. +- In xrpl4j, `SignatureService.sign` returns a `SignedTransaction`, which contains the transaction's hash, which you can use to look up the transaction later. {{ start_step("Sign") }}