mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-21 04:05:49 +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:
@@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user