mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-05 12:25:50 +00:00
Update tutorial for xrpl4j v3
This PR updates all Java examples to utilize xrpl4j v3, which has slight different contracts as compared to v2.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ __pycache__
|
||||
out/
|
||||
package-lock.json
|
||||
yarn-error.log
|
||||
/.idea
|
||||
|
||||
@@ -1,28 +1,26 @@
|
||||
// Construct a network client
|
||||
HttpUrl rippledUrl = HttpUrl
|
||||
.get("https://s.altnet.rippletest.net:51234/");
|
||||
HttpUrl rippledUrl = HttpUrl.get("https://s.altnet.rippletest.net:51234/");
|
||||
System.out.println("Constructing an XrplClient connected to " + rippledUrl);
|
||||
XrplClient xrplClient = new XrplClient(rippledUrl);
|
||||
|
||||
// Create a Wallet using a WalletFactory
|
||||
WalletFactory walletFactory = DefaultWalletFactory.getInstance();
|
||||
Wallet testWallet = walletFactory.randomWallet(true).wallet();
|
||||
// Create a random KeyPair
|
||||
KeyPair randomKeyPair = Seed.ed25519Seed().deriveKeyPair();
|
||||
System.out.println("Generated KeyPair: " + randomKeyPair);
|
||||
|
||||
// Get the Classic and X-Addresses from testWallet
|
||||
Address classicAddress = testWallet.classicAddress();
|
||||
XAddress xAddress = testWallet.xAddress();
|
||||
// Derive the Classic and X-Addresses from testWallet
|
||||
Address classicAddress = randomKeyPair.publicKey().deriveAddress();
|
||||
XAddress xAddress = AddressCodec.getInstance().classicAddressToXAddress(classicAddress, true);
|
||||
System.out.println("Classic Address: " + classicAddress);
|
||||
System.out.println("X-Address: " + xAddress);
|
||||
|
||||
// Fund the account using the testnet Faucet
|
||||
FaucetClient faucetClient = FaucetClient
|
||||
.construct(HttpUrl.get("https://faucet.altnet.rippletest.net"));
|
||||
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
|
||||
AccountInfoRequestParams requestParams =
|
||||
AccountInfoRequestParams.of(classicAddress);
|
||||
AccountInfoResult accountInfoResult =
|
||||
xrplClient.accountInfo(requestParams);
|
||||
AccountInfoRequestParams requestParams = AccountInfoRequestParams.of(classicAddress);
|
||||
AccountInfoResult accountInfoResult = xrplClient.accountInfo(requestParams);
|
||||
|
||||
// Print the result
|
||||
System.out.println(accountInfoResult);
|
||||
System.out.println(accountInfoResult);
|
||||
@@ -4,21 +4,22 @@
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.google.common.primitives.UnsignedLong;
|
||||
import okhttp3.HttpUrl;
|
||||
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
|
||||
import org.xrpl.xrpl4j.client.XrplClient;
|
||||
import org.xrpl.xrpl4j.client.faucet.FaucetClient;
|
||||
import org.xrpl.xrpl4j.client.faucet.FundAccountRequest;
|
||||
import org.xrpl.xrpl4j.crypto.KeyMetadata;
|
||||
import org.xrpl.xrpl4j.crypto.PrivateKey;
|
||||
import org.xrpl.xrpl4j.crypto.keys.KeyPair;
|
||||
import org.xrpl.xrpl4j.crypto.keys.PrivateKey;
|
||||
import org.xrpl.xrpl4j.crypto.keys.Seed;
|
||||
import org.xrpl.xrpl4j.crypto.signing.SignatureService;
|
||||
import org.xrpl.xrpl4j.crypto.signing.SignedTransaction;
|
||||
import org.xrpl.xrpl4j.crypto.signing.SingleKeySignatureService;
|
||||
import org.xrpl.xrpl4j.crypto.signing.SingleSignedTransaction;
|
||||
import org.xrpl.xrpl4j.crypto.signing.bc.BcSignatureService;
|
||||
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoRequestParams;
|
||||
import org.xrpl.xrpl4j.model.client.accounts.AccountLinesRequestParams;
|
||||
import org.xrpl.xrpl4j.model.client.accounts.TrustLine;
|
||||
import org.xrpl.xrpl4j.model.client.common.LedgerIndex;
|
||||
import org.xrpl.xrpl4j.model.client.common.LedgerSpecifier;
|
||||
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
|
||||
import org.xrpl.xrpl4j.model.client.ledger.LedgerRequestParams;
|
||||
import org.xrpl.xrpl4j.model.client.transactions.TransactionRequestParams;
|
||||
@@ -29,9 +30,6 @@ import org.xrpl.xrpl4j.model.transactions.ImmutableTrustSet;
|
||||
import org.xrpl.xrpl4j.model.transactions.IssuedCurrencyAmount;
|
||||
import org.xrpl.xrpl4j.model.transactions.Payment;
|
||||
import org.xrpl.xrpl4j.model.transactions.TrustSet;
|
||||
import org.xrpl.xrpl4j.wallet.DefaultWalletFactory;
|
||||
import org.xrpl.xrpl4j.wallet.Wallet;
|
||||
import org.xrpl.xrpl4j.wallet.WalletFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -47,16 +45,15 @@ public class IssueToken {
|
||||
FeeResult feeResult = xrplClient.fee();
|
||||
|
||||
|
||||
// Create cold and hot Wallets using a WalletFactory -----------------------
|
||||
WalletFactory walletFactory = DefaultWalletFactory.getInstance();
|
||||
Wallet coldWallet = walletFactory.randomWallet(true).wallet();
|
||||
Wallet hotWallet = walletFactory.randomWallet(true).wallet();
|
||||
// Create cold and hot KeyPairs -----------------------
|
||||
KeyPair coldWalletKeyPair = Seed.ed25519Seed().deriveKeyPair();
|
||||
KeyPair hotWalletKeyPair = Seed.ed25519Seed().deriveKeyPair();
|
||||
|
||||
// Fund the account using the testnet Faucet -------------------------------
|
||||
FaucetClient faucetClient = FaucetClient
|
||||
.construct(HttpUrl.get("https://faucet.altnet.rippletest.net"));
|
||||
faucetClient.fundAccount(FundAccountRequest.of(coldWallet.classicAddress()));
|
||||
faucetClient.fundAccount(FundAccountRequest.of(hotWallet.classicAddress()));
|
||||
faucetClient.fundAccount(FundAccountRequest.of(coldWalletKeyPair.publicKey().deriveAddress()));
|
||||
faucetClient.fundAccount(FundAccountRequest.of(hotWalletKeyPair.publicKey().deriveAddress()));
|
||||
|
||||
// If you go too soon, the funding transaction might slip back a ledger and
|
||||
// then your starting Sequence number will be off. This is mostly relevant
|
||||
@@ -67,15 +64,15 @@ public class IssueToken {
|
||||
try {
|
||||
xrplClient.accountInfo(
|
||||
AccountInfoRequestParams.builder()
|
||||
.ledgerIndex(LedgerIndex.VALIDATED)
|
||||
.account(coldWallet.classicAddress())
|
||||
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
|
||||
.account(coldWalletKeyPair.publicKey().deriveAddress())
|
||||
.build()
|
||||
);
|
||||
|
||||
xrplClient.accountInfo(
|
||||
AccountInfoRequestParams.builder()
|
||||
.ledgerIndex(LedgerIndex.VALIDATED)
|
||||
.account(hotWallet.classicAddress())
|
||||
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
|
||||
.account(hotWalletKeyPair.publicKey().deriveAddress())
|
||||
.build()
|
||||
);
|
||||
|
||||
@@ -91,99 +88,85 @@ public class IssueToken {
|
||||
// Configure issuer settings -----------------------------------------------
|
||||
UnsignedInteger coldWalletSequence = xrplClient.accountInfo(
|
||||
AccountInfoRequestParams.builder()
|
||||
.ledgerIndex(LedgerIndex.CURRENT)
|
||||
.account(coldWallet.classicAddress())
|
||||
.ledgerSpecifier(LedgerSpecifier.CURRENT)
|
||||
.account(coldWalletKeyPair.publicKey().deriveAddress())
|
||||
.build()
|
||||
).accountData().sequence();
|
||||
|
||||
AccountSet setDefaultRipple = AccountSet.builder()
|
||||
.account(coldWallet.classicAddress())
|
||||
.account(coldWalletKeyPair.publicKey().deriveAddress())
|
||||
.fee(feeResult.drops().minimumFee())
|
||||
.sequence(coldWalletSequence)
|
||||
.signingPublicKey(coldWallet.publicKey())
|
||||
.signingPublicKey(coldWalletKeyPair.publicKey())
|
||||
.setFlag(AccountSet.AccountSetFlag.DEFAULT_RIPPLE)
|
||||
.lastLedgerSequence(computeLastLedgerSequence(xrplClient))
|
||||
.build();
|
||||
|
||||
PrivateKey coldWalletPrivateKey = PrivateKey.fromBase16EncodedPrivateKey(
|
||||
coldWallet.privateKey().get()
|
||||
);
|
||||
SignatureService coldWalletSignatureService = new SingleKeySignatureService(coldWalletPrivateKey);
|
||||
|
||||
SignedTransaction<AccountSet> signedSetDefaultRipple = coldWalletSignatureService.sign(
|
||||
KeyMetadata.EMPTY,
|
||||
setDefaultRipple
|
||||
SignatureService<PrivateKey> signatureService = new BcSignatureService();
|
||||
SingleSignedTransaction<AccountSet> signedAccountSet = signatureService.sign(
|
||||
coldWalletKeyPair.privateKey(), setDefaultRipple
|
||||
);
|
||||
|
||||
submitAndWaitForValidation(signedSetDefaultRipple, xrplClient);
|
||||
submitAndWaitForValidation(signedAccountSet, xrplClient);
|
||||
|
||||
// Configure hot address settings ------------------------------------------
|
||||
UnsignedInteger hotWalletSequence = xrplClient.accountInfo(
|
||||
AccountInfoRequestParams.builder()
|
||||
.ledgerIndex(LedgerIndex.CURRENT)
|
||||
.account(hotWallet.classicAddress())
|
||||
.ledgerSpecifier(LedgerSpecifier.CURRENT)
|
||||
.account(hotWalletKeyPair.publicKey().deriveAddress())
|
||||
.build()
|
||||
).accountData().sequence();
|
||||
|
||||
AccountSet setRequireAuth = AccountSet.builder()
|
||||
.account(hotWallet.classicAddress())
|
||||
.account(hotWalletKeyPair.publicKey().deriveAddress())
|
||||
.fee(feeResult.drops().minimumFee())
|
||||
.sequence(hotWalletSequence)
|
||||
.signingPublicKey(hotWallet.publicKey())
|
||||
.signingPublicKey(hotWalletKeyPair.publicKey())
|
||||
.setFlag(AccountSet.AccountSetFlag.REQUIRE_AUTH)
|
||||
.lastLedgerSequence(computeLastLedgerSequence(xrplClient))
|
||||
.build();
|
||||
|
||||
PrivateKey hotWalletPrivateKey = PrivateKey.fromBase16EncodedPrivateKey(
|
||||
hotWallet.privateKey().get()
|
||||
SingleSignedTransaction<AccountSet> signedSetRequireAuth = signatureService.sign(
|
||||
hotWalletKeyPair.privateKey(), setRequireAuth
|
||||
);
|
||||
SignatureService hotWalletSignatureService = new SingleKeySignatureService(hotWalletPrivateKey);
|
||||
|
||||
SignedTransaction<AccountSet> signedSetRequireAuth = hotWalletSignatureService.sign(
|
||||
KeyMetadata.EMPTY,
|
||||
setRequireAuth
|
||||
);
|
||||
|
||||
submitAndWaitForValidation(signedSetRequireAuth, xrplClient);
|
||||
|
||||
// Create trust line -------------------------------------------------------
|
||||
String currencyCode = "FOO";
|
||||
ImmutableTrustSet trustSet = TrustSet.builder()
|
||||
.account(hotWallet.classicAddress())
|
||||
.account(hotWalletKeyPair.publicKey().deriveAddress())
|
||||
.fee(feeResult.drops().openLedgerFee())
|
||||
.sequence(hotWalletSequence.plus(UnsignedInteger.ONE))
|
||||
.limitAmount(IssuedCurrencyAmount.builder()
|
||||
.currency(currencyCode)
|
||||
.issuer(coldWallet.classicAddress())
|
||||
.issuer(coldWalletKeyPair.publicKey().deriveAddress())
|
||||
.value("10000000000")
|
||||
.build())
|
||||
.signingPublicKey(hotWallet.publicKey())
|
||||
.signingPublicKey(hotWalletKeyPair.publicKey())
|
||||
.build();
|
||||
|
||||
SignedTransaction<TrustSet> signedTrustSet = hotWalletSignatureService.sign(
|
||||
KeyMetadata.EMPTY,
|
||||
trustSet
|
||||
SingleSignedTransaction<TrustSet> signedTrustSet = signatureService.sign(
|
||||
hotWalletKeyPair.privateKey(), trustSet
|
||||
);
|
||||
|
||||
submitAndWaitForValidation(signedTrustSet, xrplClient);
|
||||
|
||||
// Send token --------------------------------------------------------------
|
||||
Payment payment = Payment.builder()
|
||||
.account(coldWallet.classicAddress())
|
||||
.account(coldWalletKeyPair.publicKey().deriveAddress())
|
||||
.fee(feeResult.drops().openLedgerFee())
|
||||
.sequence(coldWalletSequence.plus(UnsignedInteger.ONE))
|
||||
.destination(hotWallet.classicAddress())
|
||||
.destination(hotWalletKeyPair.publicKey().deriveAddress())
|
||||
.amount(IssuedCurrencyAmount.builder()
|
||||
.issuer(coldWallet.classicAddress())
|
||||
.issuer(coldWalletKeyPair.publicKey().deriveAddress())
|
||||
.currency(currencyCode)
|
||||
.value("3840")
|
||||
.build())
|
||||
.signingPublicKey(coldWallet.publicKey())
|
||||
.signingPublicKey(coldWalletKeyPair.publicKey())
|
||||
.build();
|
||||
|
||||
SignedTransaction<Payment> signedPayment = coldWalletSignatureService.sign(
|
||||
KeyMetadata.EMPTY,
|
||||
payment
|
||||
SingleSignedTransaction<Payment> signedPayment = signatureService.sign(
|
||||
coldWalletKeyPair.privateKey(), payment
|
||||
);
|
||||
|
||||
submitAndWaitForValidation(signedPayment, xrplClient);
|
||||
@@ -191,8 +174,8 @@ public class IssueToken {
|
||||
// Check balances ----------------------------------------------------------
|
||||
List<TrustLine> lines = xrplClient.accountLines(
|
||||
AccountLinesRequestParams.builder()
|
||||
.account(hotWallet.classicAddress())
|
||||
.ledgerIndex(LedgerIndex.VALIDATED)
|
||||
.account(hotWalletKeyPair.publicKey().deriveAddress())
|
||||
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
|
||||
.build()
|
||||
).lines();
|
||||
System.out.println("Hot wallet TrustLines: " + lines);
|
||||
@@ -203,20 +186,20 @@ public class IssueToken {
|
||||
throws JsonRpcClientErrorException {
|
||||
// Get the latest validated ledger index
|
||||
LedgerIndex validatedLedger = xrplClient.ledger(
|
||||
LedgerRequestParams.builder()
|
||||
.ledgerIndex(LedgerIndex.VALIDATED)
|
||||
.build()
|
||||
)
|
||||
LedgerRequestParams.builder()
|
||||
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
|
||||
.build()
|
||||
)
|
||||
.ledgerIndex()
|
||||
.orElseThrow(() -> new RuntimeException("LedgerIndex not available."));
|
||||
|
||||
// Workaround for https://github.com/XRPLF/xrpl4j/issues/84
|
||||
return UnsignedInteger.valueOf(
|
||||
validatedLedger.plus(UnsignedLong.valueOf(4)).unsignedLongValue().intValue()
|
||||
validatedLedger.plus(UnsignedInteger.valueOf(4)).unsignedIntegerValue().intValue()
|
||||
);
|
||||
}
|
||||
|
||||
private static void submitAndWaitForValidation(SignedTransaction<?> signedTransaction, XrplClient xrplClient)
|
||||
private static void submitAndWaitForValidation(SingleSignedTransaction<?> signedTransaction, XrplClient xrplClient)
|
||||
throws InterruptedException, JsonRpcClientErrorException, JsonProcessingException {
|
||||
|
||||
xrplClient.submit(signedTransaction);
|
||||
@@ -224,10 +207,10 @@ public class IssueToken {
|
||||
boolean transactionValidated = false;
|
||||
boolean transactionExpired = false;
|
||||
while (!transactionValidated && !transactionExpired) {
|
||||
Thread.sleep(4 * 1000);
|
||||
Thread.sleep(1000);
|
||||
LedgerIndex latestValidatedLedgerIndex = xrplClient.ledger(
|
||||
LedgerRequestParams.builder().ledgerIndex(LedgerIndex.VALIDATED).build()
|
||||
)
|
||||
LedgerRequestParams.builder().ledgerSpecifier(LedgerSpecifier.VALIDATED).build()
|
||||
)
|
||||
.ledgerIndex()
|
||||
.orElseThrow(() ->
|
||||
new RuntimeException("Ledger response did not contain a LedgerIndex.")
|
||||
@@ -243,12 +226,14 @@ public class IssueToken {
|
||||
transactionResult.metadata().get().transactionResult());
|
||||
transactionValidated = true;
|
||||
} else {
|
||||
boolean lastLedgerSequenceHasPassed = FluentCompareTo.
|
||||
is(latestValidatedLedgerIndex.unsignedLongValue())
|
||||
.greaterThan(UnsignedLong.valueOf(
|
||||
signedTransaction.signedTransaction().lastLedgerSequence().get().intValue()
|
||||
)
|
||||
);
|
||||
|
||||
boolean lastLedgerSequenceHasPassed = signedTransaction.signedTransaction().lastLedgerSequence()
|
||||
.map((signedTransactionLastLedgerSeq) ->
|
||||
FluentCompareTo.is(latestValidatedLedgerIndex.unsignedIntegerValue())
|
||||
.greaterThan(signedTransactionLastLedgerSeq)
|
||||
)
|
||||
.orElse(false);
|
||||
|
||||
if (lastLedgerSequenceHasPassed) {
|
||||
System.out.println("LastLedgerSequence has passed. Last tx response: " +
|
||||
transactionResult);
|
||||
@@ -260,4 +245,4 @@ public class IssueToken {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,29 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Sign using a SingleKeySignatureService:
|
||||
// This implementation of SignatureService simply holds a PrivateKey in
|
||||
// memory and signs Transactions using that PrivateKey. This may be
|
||||
// suitable for some applications, but is likely not secure enough for
|
||||
// server side applications, as keys must be stored and kept in memory.
|
||||
// This implementation of SignatureService signs Transactions using a
|
||||
// supplied PrivateKey. This may be suitable for some applications, but is
|
||||
// likely not secure enough for server side applications, as keys should not
|
||||
// be stored in memory whenever possible.
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Create a random wallet
|
||||
WalletFactory walletFactory = DefaultWalletFactory.getInstance();
|
||||
Wallet wallet = walletFactory.randomWallet(true).wallet();
|
||||
KeyPair randomKeyPair = Seed.ed25519Seed().deriveKeyPair();
|
||||
PublicKey publicKey = randomKeyPair.publicKey();
|
||||
PrivateKey privateKey = randomKeyPair.privateKey()
|
||||
|
||||
// Construct a SingleKeySignatureService from the Wallet private key
|
||||
PrivateKey privateKey = PrivateKey.fromBase16EncodedPrivateKey(
|
||||
wallet.privateKey().get()
|
||||
);
|
||||
SingleKeySignatureService signatureService =
|
||||
new SingleKeySignatureService(privateKey);
|
||||
// Construct a SignatureService
|
||||
SignatureService<PrivateKey> signatureService = new BcSignatureService();
|
||||
|
||||
// Construct and sign the Payment
|
||||
Payment payment = Payment.builder()
|
||||
.account(wallet.classicAddress())
|
||||
.account(publicKey.deriveAddress())
|
||||
.destination(Address.of("rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"))
|
||||
.amount(XrpCurrencyAmount.ofDrops(1000))
|
||||
.fee(XrpCurrencyAmount.ofDrops(10))
|
||||
.sequence(UnsignedInteger.valueOf(16126889))
|
||||
.signingPublicKey(signatureService.getPublicKey(KeyMetadata.EMPTY))
|
||||
.signingPublicKey(publicKey)
|
||||
.build();
|
||||
SignedTransaction<Payment> signedPayment = signatureService.sign(
|
||||
KeyMetadata.EMPTY,
|
||||
payment
|
||||
);
|
||||
SingleSignedTransaction<Payment> signedPayment = signatureService.sign(privateKey, payment);
|
||||
System.out.println("Signed Payment: " + signedPayment.signedTransaction());
|
||||
|
||||
|
||||
@@ -47,25 +41,26 @@ System.out.println("Signed Payment: " + signedPayment.signedTransaction());
|
||||
// implementation.
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Construct a DerivedKeysSignatureService with a server secret
|
||||
// (in this case "shh")
|
||||
DerivedKeysSignatureService signatureService =
|
||||
new DerivedKeysSignatureService("shh"::getBytes, VersionType.ED25519);
|
||||
// Construct a DerivedKeysSignatureService with a server secret (in this case "shh")
|
||||
SignatureService<PrivateKeyReference> derivedKeySignatureService = new BcDerivedKeySignatureService(
|
||||
() -> ServerSecret.of("shh".getBytes())
|
||||
);
|
||||
|
||||
// Choose a walletId. This can be anything as long as it is unique to your system.
|
||||
String walletId = "sample-wallet";
|
||||
KeyMetadata keyMetadata = KeyMetadata.builder()
|
||||
.platformIdentifier("jks")
|
||||
.keyringIdentifier("n/a")
|
||||
.keyIdentifier(walletId)
|
||||
.keyVersion("1")
|
||||
.keyPassword("password")
|
||||
.build();
|
||||
PrivateKeyReference privateKeyReference = new PrivateKeyReference() {
|
||||
@Override
|
||||
public KeyType keyType() {
|
||||
return KeyType.ED25519;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String keyIdentifier() {
|
||||
return "sample-keypair";
|
||||
}
|
||||
};
|
||||
|
||||
// Get the public key and classic address for the given walletId
|
||||
PublicKey publicKey = signatureService.getPublicKey(keyMetadata);
|
||||
Address classicAddress = DefaultKeyPairService.getInstance()
|
||||
.deriveAddress(publicKey.value());
|
||||
PublicKey publicKey = derivedKeySignatureService.derivePublicKey(privateKeyReference);
|
||||
Address classicAddress = publicKey.deriveAddress();
|
||||
|
||||
// Construct and sign the Payment
|
||||
Payment payment = Payment.builder()
|
||||
@@ -74,9 +69,8 @@ Payment payment = Payment.builder()
|
||||
.amount(XrpCurrencyAmount.ofDrops(1000))
|
||||
.fee(XrpCurrencyAmount.ofDrops(10))
|
||||
.sequence(UnsignedInteger.valueOf(16126889))
|
||||
.signingPublicKey(publicKey.base16Encoded())
|
||||
.signingPublicKey(publicKey)
|
||||
.build();
|
||||
|
||||
SignedTransaction<Payment> signedPayment = signatureService
|
||||
.sign(keyMetadata, payment);
|
||||
System.out.println("Signed Payment: " + signedPayment.signedTransaction());
|
||||
SingleSignedTransaction<Payment> signedPayment = derivedKeySignatureService.sign(privateKeyReference, payment);
|
||||
System.out.println("Signed Payment: " + signedPayment.signedTransaction());
|
||||
@@ -1,12 +1,8 @@
|
||||
// Example Credentials --------------------------------------------------------
|
||||
WalletFactory walletFactory = DefaultWalletFactory.getInstance();
|
||||
Wallet testWallet = walletFactory
|
||||
.fromSeed("sn3nxiW7v8KXzPzAqzyHXbSSKNuN9", true)
|
||||
.wallet();
|
||||
// Create a KeyPair
|
||||
KeyPair randomKeyPair = Seed.ed25519Seed().deriveKeyPair();
|
||||
|
||||
// Get the Classic address from testWallet
|
||||
Address classicAddress = testWallet.classicAddress();
|
||||
System.out.println(classicAddress); // "rMCcNuTcajgw7YTgBy1sys3b89QqjUrMpH"
|
||||
Address classicAddress = randomKeyPair.publicKey().deriveAddress();
|
||||
|
||||
// Connect --------------------------------------------------------------------
|
||||
HttpUrl rippledUrl = HttpUrl.get("https://s.altnet.rippletest.net:51234/");
|
||||
@@ -15,9 +11,9 @@ XrplClient xrplClient = new XrplClient(rippledUrl);
|
||||
// Prepare transaction --------------------------------------------------------
|
||||
// Look up your Account Info
|
||||
AccountInfoRequestParams requestParams = AccountInfoRequestParams.builder()
|
||||
.ledgerIndex(LedgerIndex.VALIDATED)
|
||||
.account(classicAddress)
|
||||
.build();
|
||||
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
|
||||
.build();
|
||||
AccountInfoResult accountInfoResult = xrplClient.accountInfo(requestParams);
|
||||
UnsignedInteger sequence = accountInfoResult.accountData().sequence();
|
||||
|
||||
@@ -27,17 +23,15 @@ XrpCurrencyAmount openLedgerFee = feeResult.drops().openLedgerFee();
|
||||
|
||||
// Get the latest validated ledger index
|
||||
LedgerIndex validatedLedger = xrplClient.ledger(
|
||||
LedgerRequestParams.builder()
|
||||
.ledgerIndex(LedgerIndex.VALIDATED)
|
||||
.build()
|
||||
)
|
||||
LedgerRequestParams.builder()
|
||||
.ledgerSpecifier(LedgerSpecifier.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()
|
||||
);
|
||||
// LastLedgerSequence is the current ledger index + 4
|
||||
UnsignedInteger lastLedgerSequence = validatedLedger.plus(UnsignedInteger.valueOf(4)).unsignedIntegerValue();
|
||||
|
||||
// Construct a Payment
|
||||
Payment payment = Payment.builder()
|
||||
@@ -46,75 +40,61 @@ Payment payment = Payment.builder()
|
||||
.destination(Address.of("rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"))
|
||||
.sequence(sequence)
|
||||
.fee(openLedgerFee)
|
||||
.signingPublicKey(testWallet.publicKey())
|
||||
.signingPublicKey(randomKeyPair.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);
|
||||
SignatureService<PrivateKey> signatureService = new BcSignatureService();
|
||||
|
||||
// Sign the Payment
|
||||
SignedTransaction<Payment> signedPayment = signatureService.sign(
|
||||
KeyMetadata.EMPTY,
|
||||
payment
|
||||
);
|
||||
SingleSignedTransaction<Payment> signedPayment = signatureService.sign(randomKeyPair.privateKey(), payment);
|
||||
System.out.println("Signed Payment: " + signedPayment.signedTransaction());
|
||||
|
||||
// Submit transaction ---------------------------------------------------------
|
||||
SubmitResult<Transaction> prelimResult = xrplClient.submit(signedPayment);
|
||||
System.out.println(prelimResult);
|
||||
SubmitResult<Payment> paymentSubmitResult = xrplClient.submit(signedPayment);
|
||||
System.out.println(paymentSubmitResult);
|
||||
|
||||
// Wait for validation --------------------------------------------------------
|
||||
TransactionResult<Payment> transactionResult = null;
|
||||
|
||||
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<Payment> transactionResult = xrplClient.transaction(
|
||||
TransactionRequestParams.of(signedPayment.hash()),
|
||||
Payment.class
|
||||
);
|
||||
LedgerIndex latestValidatedLedgerIndex = xrplClient.ledger(
|
||||
LedgerRequestParams.builder()
|
||||
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
|
||||
.build()
|
||||
)
|
||||
.ledgerIndex()
|
||||
.orElseThrow(() -> new RuntimeException("Ledger response did not contain a LedgerIndex."));
|
||||
|
||||
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());
|
||||
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()));
|
||||
boolean lastLedgerSequenceHasPassed = FluentCompareTo.is(latestValidatedLedgerIndex.unsignedIntegerValue())
|
||||
.greaterThan(UnsignedInteger.valueOf(lastLedgerSequence.intValue()));
|
||||
if (lastLedgerSequenceHasPassed) {
|
||||
System.out.println("LastLedgerSequence has passed. Last tx response: "
|
||||
transactionResult);
|
||||
);
|
||||
System.out.println("LastLedgerSequence has passed. Last tx response: " + transactionResult);
|
||||
transactionExpired = true;
|
||||
} else {
|
||||
System.out.println("Payment not yet validated.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check transaction results --------------------------------------------------
|
||||
// Check transaction results
|
||||
System.out.println(transactionResult);
|
||||
System.out.println("Explorer link: https://testnet.xrpl.org/transactions/" +
|
||||
signedPayment.hash());
|
||||
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())
|
||||
);
|
||||
});
|
||||
System.out.println("XRP Delivered: " + ((XrpCurrencyAmount) deliveredAmount).toXrp()));
|
||||
}
|
||||
);
|
||||
@@ -44,27 +44,31 @@ In this tutorial, you need the [xrpl4j-client](https://javadoc.io/doc/org.xrpl/x
|
||||
|
||||
To install with Maven, add the following to your project's `pom.xml` file and then run `mvn install`:
|
||||
|
||||
```xml
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.xrpl</groupId>
|
||||
<artifactId>xrpl4j-bom</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
```
|
||||
|
||||
```xml
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.xrpl</groupId>
|
||||
<artifactId>xrpl4j-core</artifactId>
|
||||
<version>3.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xrpl</groupId>
|
||||
<artifactId>xrpl4j-client</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xrpl</groupId>
|
||||
<artifactId>xrpl4j-address-codec</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xrpl</groupId>
|
||||
<artifactId>xrpl4j-keypairs</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xrpl</groupId>
|
||||
<artifactId>xrpl4j-model</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
@@ -86,9 +90,9 @@ Here are the basic steps you'll need to cover for almost any XRP Ledger project:
|
||||
### {{n.next()}}. Connect to the XRP Ledger
|
||||
|
||||
To make queries and submit transactions, you need to connect to the XRP Ledger. To do this with `xrpl4j`,
|
||||
you can use an [`XrplClient`](https://javadoc.io/doc/org.xrpl/xrpl4j-client/latest/org/xrpl/xrpl4j/client/XrplClient.html):
|
||||
you can use an [`XrplClient`](https://javadoc.io/doc/org.xrpl/xrpl4j-client/3.0.1/org/xrpl/xrpl4j/client/XrplClient.html):
|
||||
|
||||
{{ include_code("_code-samples/get-started/java/GetAccountInfo.java", start_with="// Construct a network client", end_before="// Create a Wallet using a WalletFactory", language="java") }}
|
||||
{{ include_code("_code-samples/get-started/java/GetAccountInfo.java", start_with="// Construct a network client", end_before="// Create a random KeyPair", language="java") }}
|
||||
|
||||
#### Connect to the production XRP Ledger
|
||||
|
||||
@@ -112,7 +116,7 @@ To store value and execute transactions on the XRP Ledger, you need to get an ac
|
||||
|
||||
To generate a new account, `xrpl4j` provides the [`DefaultWalletFactory`](https://javadoc.io/doc/org.xrpl/xrpl4j-keypairs/latest/org/xrpl/xrpl4j/wallet/DefaultWalletFactory.html).
|
||||
|
||||
{{ include_code("_code-samples/get-started/java/GetAccountInfo.java", start_with="// Create a Wallet using a WalletFactory", end_before="// Get the Classic and X-Addresses from testWallet", language="java") }}
|
||||
{{ include_code("_code-samples/get-started/java/GetAccountInfo.java", start_with="// Create a random KeyPair", end_before="// Derive the Classic and X-Addresses from testWallet", language="java") }}
|
||||
|
||||
|
||||
The result of a call to `walletFactory.randomWallet(true).wallet()` is a [`Wallet` instance](https://javadoc.io/doc/org.xrpl/xrpl4j-keypairs/latest/org/xrpl/xrpl4j/wallet/Wallet.html):
|
||||
@@ -170,26 +174,33 @@ You should see output similar to this example:
|
||||
```sh
|
||||
Running the GetAccountInfo sample...
|
||||
Constructing an XrplClient connected to https://s.altnet.rippletest.net:51234/
|
||||
Generated a wallet with the following public key: ED015D922B5EACF09DF01168141FF27FA6229B0FAB9B4CD88D2B6DA036090EFAA4
|
||||
Generated KeyPair: KeyPair{
|
||||
privateKey=PrivateKey{value=[redacted], destroyed=false},
|
||||
publicKey=PublicKey{value=UnsignedByteArray{unsignedBytes=List(size=33)},
|
||||
base58Value=aKGgrZL2WTc85HJSkQGuKfinem5oMH1uCJankSWFATGUhqvygxir,
|
||||
base16Value=EDFB1073327CCBDA342AD685AF1C04530294866B9CB10C21126DC004BFDBA287D1,
|
||||
keyType=ED25519
|
||||
}
|
||||
}
|
||||
Classic Address: rBXHGshqXu3Smy9FUsQTmo49bGpQUQEm3X
|
||||
X-Address: T7yMiiJJCmgY2yg5WB2davUedDeBFAG5B8r9KHjKCxDdvv3
|
||||
Funded the account using the Testnet faucet.
|
||||
AccountInfoResult{
|
||||
status=success,
|
||||
accountData=AccountRootObject{
|
||||
ledgerEntryType=ACCOUNT_ROOT,
|
||||
account=rBXHGshqXu3Smy9FUsQTmo49bGpQUQEm3X,
|
||||
balance=1000000000,
|
||||
flags=0,
|
||||
ownerCount=0,
|
||||
previousTransactionId=0000000000000000000000000000000000000000000000000000000000000000,
|
||||
previousTransactionLedgerSequence=0,
|
||||
sequence=17178149,
|
||||
signerLists=[],
|
||||
index=0DC1B13C73A7F3D2D82446526D0C5D08E88F89BA442D54291117F1A08E447685
|
||||
},
|
||||
ledgerCurrentIndex=17178149,
|
||||
validated=false
|
||||
status=success,
|
||||
accountData=AccountRootObject{
|
||||
ledgerEntryType=ACCOUNT_ROOT,
|
||||
account=rDNwS2t4afhBogKqSFFmsDi1k7gmeGhz4p,
|
||||
balance=10000000000,
|
||||
flags=0,
|
||||
ownerCount=0,
|
||||
previousTransactionId=0000000000000000000000000000000000000000000000000000000000000000,
|
||||
previousTransactionLedgerSequence=0,
|
||||
sequence=37649083,
|
||||
signerLists=[],
|
||||
index=F607809578C2A413774B9A240480B8B7B10C3E296CA609337D2F41813F566B92
|
||||
},
|
||||
ledgerCurrentIndex=37649083,
|
||||
validated=false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ Here are examples of how to sign transaction instructions locally using the foll
|
||||
|
||||
* **Python** - [`xrpl-py`](https://github.com/XRPLF/xrpl-py)
|
||||
|
||||
* **Java** - [`xrpl4j-crypto-bouncycastle`](https://javadoc.io/doc/org.xrpl/xrpl4j-crypto-bouncycastle/latest/index.html)
|
||||
* **Java** - [`xrpl4j`](https://github.com/XRPLF/xrpl4j)
|
||||
|
||||
<!-- MULTICODE_BLOCK_START -->
|
||||
|
||||
|
||||
Reference in New Issue
Block a user