Sample Java Programs
In the Ardor client there are some sample java programs that demonstrate some common uses of the Ardor platform using Java. There is a javadoc documentation as well.
These java programs are located under the installation folder of Ardor -> addons -> src -> java -> com -> jelurida -> ardor -> client -> api
FeeCalculation
This java program demonstrates how to calculate best bundling fee for child chain transactions. Javadoc
Source code
package com.jelurida.ardor.client.api;
import nxt.addons.JO;
import nxt.blockchain.Chain;
import nxt.crypto.Crypto;
import nxt.http.callers.GetBundlerRatesCall;
import nxt.http.callers.SendMoneyCall;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
/**
* Show how to calculate best bundling fee for child chain transactions
*/
public class FeeCalculation {
private static final String SECRET_PHRASE = "hope peace happen touch easy pretend worthless talk them indeed wheel state";
public static void main(String[] args) throws MalformedURLException {
URL remoteUrl = new URL("https://testardor.jelurida.com/nxt");
FeeCalculation feeCalculation = new FeeCalculation();
Chain chain = Chain.getChain("IGNIS");
JO transactionResponse = feeCalculation.prepare(remoteUrl, chain.getId());
long minimumParentChainFeeFQT = transactionResponse.getLong("minimumFeeFQT");
long feeRateNQTPerFXT = feeCalculation.getBestBundlingFee(remoteUrl, minimumParentChainFeeFQT, chain.getId());
long feeNQT = BigDecimal.valueOf(minimumParentChainFeeFQT).multiply(BigDecimal.valueOf(feeRateNQTPerFXT)).divide(BigDecimal.valueOf(chain.ONE_COIN), RoundingMode.HALF_EVEN).longValue();
System.out.printf("calculatedFee: %d\n", feeNQT);
JO submittedTransaction = feeCalculation.submit(remoteUrl, chain.getId(), feeNQT);
System.out.printf("submittedTransaction: %s\n", submittedTransaction);
}
private JO prepare(URL remoteUrl, int chainId) {
// Prepare the transaction but do not broadcast it. This will calculate the parent chain fee
return SendMoneyCall.create(chainId).
recipient("NXT-KX2S-UULA-7YZ7-F3R8L").
amountNQT(12345678).
deadline(15).
broadcast(false).
publicKey(Crypto.getPublicKey(SECRET_PHRASE)).
remote(remoteUrl).
message("012345678901234567890123456789012"). // permanent attached message of more than 32 bytes increases the ARDR fee
call();
}
private long getBestBundlingFee(URL remoteUrl, long minBundlerBalanceFXT, int chainId) {
JO response = GetBundlerRatesCall.create().minBundlerBalanceFXT(minBundlerBalanceFXT).remote(remoteUrl).call();
List<JO> rates = response.getArray("rates").objects();
Long bestRate = rates.stream().
filter(r -> r.getInt("chain") == chainId).
map(r -> r.getLong("minRateNQTPerFXT")).
sorted().findFirst().orElse(null);
if (bestRate == null) {
throw new IllegalStateException("Best bundling fee cannot be determined");
}
return bestRate;
}
private JO submit(URL remoteUrl, int chainId, long feeNQT) {
return SendMoneyCall.create(chainId).
recipient("NXT-KX2S-UULA-7YZ7-F3R8L").
amountNQT(12345678).
deadline(15).
broadcast(true).
secretPhrase(SECRET_PHRASE).
remote(remoteUrl).
feeNQT(feeNQT).
message("012345678901234567890123456789012").
call();
}
}
InProcessApiCalls
This java program demonstrates the use of APIs locally without relying on a remote node. Javadoc
Source code
package com.jelurida.ardor.client.api;
import nxt.Nxt;
import nxt.addons.JO;
import nxt.configuration.Setup;
import nxt.http.callers.SendMoneyCall;
/**
* Use APIs locally without relying on a remote node
*/
public class InProcessApiCalls {
private static final String SECRET_PHRASE = "hope peace happen touch easy pretend worthless talk them indeed wheel state";
public static void main(String[] args) {
Nxt.init(Setup.COMMAND_LINE_TOOL);
// start the node, so make sure it is not already running or you'll receive a BindException
try {
InProcessApiCalls inProcessApiCalls = new InProcessApiCalls();
inProcessApiCalls.submit();
} finally {
Nxt.shutdown(); // shutdown the node properly before closing the Java process
}
}
private void submit() {
// This is just a sample, you can submit any transaction type using its specific caller
JO signedTransactionResponse = SendMoneyCall.create(1).
recipient("NXT-KX2S-UULA-7YZ7-F3R8L").
amountNQT(12345678).
secretPhrase(SECRET_PHRASE).
deadline(15).
feeNQT(100000000). // See other examples for fee calculation
broadcast(false).
call();
System.out.printf("signedTransactionResponse: %s\n", signedTransactionResponse.toJSONString());
if (signedTransactionResponse.isExist("errorCode")) {
System.out.printf("Error code %d description %s\n", signedTransactionResponse.getInt("errorCode"), signedTransactionResponse.getString("errorDescription"));
}
}
}
LocalSigning
This java program demonstrates how to create a transaction on a remote node, signs it locally and then broadcasts it to a remote node. Javadoc
Source code
package com.jelurida.ardor.client.api;
import nxt.addons.JO;
import nxt.crypto.Crypto;
import nxt.http.callers.BroadcastTransactionCall;
import nxt.http.callers.SendMoneyCall;
import nxt.http.callers.SignTransactionCall;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Create the transaction on a remote node, sign it locally, then broadcast to a remote node
*/
public class LocalSigning {
private static final String SECRET_PHRASE = "hope peace happen touch easy pretend worthless talk them indeed wheel state"; // Only needed for signTransactionCall
public static void main(String[] args) throws MalformedURLException {
LocalSigning localSigning = new LocalSigning();
localSigning.submitSignAndBroadcast();
}
private void submitSignAndBroadcast() throws MalformedURLException {
URL localUrl = new URL("http://localhost:26876/nxt"); // Start your local testnet node
URL remoteUrl = new URL("https://testardor.jelurida.com/nxt"); // Jelurida remote testnet node
byte[] publicKey = Crypto.getPublicKey(SECRET_PHRASE); // Use to generate unsigned transaction without revealing the secret phrase
int chainId = 1; // Use 2 for Ignis
// This is just a sample, you can submit any transaction type using its specific caller
JO unsignedTransactionResponse = submitRemotely(remoteUrl, publicKey, chainId);
// Somehow transfer the unsigned transaction data to an offline workstation.
// Then sign the transaction on the offline workstation
JO signTransactionResponse = signLocally(localUrl, unsignedTransactionResponse);
// Transfer the information signed transaction data to an online workstation
// Then broadcast it to network
broadcast(remoteUrl, signTransactionResponse);
}
private void broadcast(URL remoteUrl, JO signTransactionResponse) {
JO signedTransactionJSON = signTransactionResponse.getJo("transactionJSON");
JO broadcastResponse = BroadcastTransactionCall.create().
transactionJSON(signedTransactionJSON.toJSONString()).
remote(remoteUrl).
call();
System.out.printf("broadcastResponse: %s\n", broadcastResponse.toJSONString());
}
private JO signLocally(URL localUrl, JO unsignedTransactionResponse) {
JO unsignedTransactionJSON = unsignedTransactionResponse.getJo("transactionJSON");
JO signTransactionResponse = SignTransactionCall.create().
unsignedTransactionJSON(unsignedTransactionJSON.toJSONString()).
secretPhrase(SECRET_PHRASE).
remote(localUrl).
call();
System.out.printf("signTransactionResponse: %s\n", signTransactionResponse.toJSONString());
return signTransactionResponse;
}
private JO submitRemotely(URL remoteUrl, byte[] publicKey, int chainId) {
JO unsignedTransactionResponse = SendMoneyCall.create(chainId).
recipient("NXT-KX2S-UULA-7YZ7-F3R8L").
amountNQT(12345678).
publicKey(publicKey).
deadline(15).
feeNQT(100000000). // See other examples for fee calculation
broadcast(false).
remote(remoteUrl).
call();
System.out.printf("unsignedTransactionResponse: %s\n", unsignedTransactionResponse.toJSONString());
return unsignedTransactionResponse;
}
}
MessageDecryption
This java program demonstrates how to iterate through blockchain transactions and decrypt their attached message. Javadoc
Source code
package com.jelurida.ardor.client.api;
import nxt.addons.JO;
import nxt.http.callers.DecryptFromCall;
import nxt.http.callers.GetBlockCall;
import nxt.http.callers.GetBlockchainTransactionsCall;
import nxt.http.responses.BlockResponse;
import nxt.http.responses.TransactionResponse;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.stream.Collectors;
/**
* Scan for blockchain transactions and decrypt their attached message
*/
public class MessageDecryption {
private static final String RECIPIENT_SECRET_PHRASE = "no30FiiC95auuD0tbA1QJuhACtPdT6llpYInYREIT9GKlZhvBB";
private static final String SENDER_ACCOUNT = "ARDOR-XK4R-7VJU-6EQG-7R335";
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("http://localhost:26876/nxt"); // Start your local testnet node
MessageDecryption messageDecryption = new MessageDecryption();
List<TransactionResponse> transactions = messageDecryption.getTransactions(1, 380158, SENDER_ACCOUNT, url);
for (TransactionResponse transaction : transactions) {
JO attachmentJson = transaction.getAttachmentJson();
if (!attachmentJson.isExist("encryptedMessage")) {
continue;
}
JO encryptedData = attachmentJson.getJo("encryptedMessage");
JO response = DecryptFromCall.create().account(SENDER_ACCOUNT).secretPhrase(RECIPIENT_SECRET_PHRASE).
data(encryptedData.getString("data")).nonce(encryptedData.getString("nonce")).remote(url).call();
System.out.println(response);
}
}
private List<TransactionResponse> getTransactions(int chainId, int height, String account, URL url) {
// Get the block timestamp from which to load transactions and load the contract account transactions
BlockResponse block = GetBlockCall.create().height(height).remote(url).getBlock();
GetBlockchainTransactionsCall getBlockchainTransactionsResponse = GetBlockchainTransactionsCall.create(chainId).
timestamp(block.getTimestamp()).
account(account).
executedOnly(true).
type(chainId == 1 ? -2 : 0).
subtype(0).remote(url);
List<TransactionResponse> transactionList = getBlockchainTransactionsResponse.getTransactions();
return transactionList.stream().filter(t -> t.getSenderRs().equals(account)).collect(Collectors.toList());
}
}
MessageEncryption
This java program demonstrates how to encrypt a message locally, then send the encrypted data to a remote node without exposing the passphrase. Javadoc
Source code
package com.jelurida.ardor.client.api;
import nxt.Nxt;
import nxt.addons.JO;
import nxt.configuration.Setup;
import nxt.http.callers.EncryptToCall;
import nxt.http.callers.SendMoneyCall;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Encrypt a message locally, then send the encrypted data to a remote node
*/
public class MessageEncryption {
private static final String SECRET_PHRASE = "hope peace happen touch easy pretend worthless talk them indeed wheel state";
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("https://testardor.jelurida.com/nxt");
Nxt.init(Setup.COMMAND_LINE_TOOL);
// start the node, so make sure it is not already running or you'll receive a BindException
try {
MessageEncryption messageEncryption = new MessageEncryption();
JO encryptedData = messageEncryption.encrypt();
messageEncryption.submit(encryptedData, url);
} finally {
Nxt.shutdown(); // shutdown the node properly before closing the Java process
}
}
private JO encrypt() {
return EncryptToCall.create().recipient("NXT-KX2S-UULA-7YZ7-F3R8L").messageToEncrypt("Hello World").messageToEncryptIsText(true).secretPhrase(SECRET_PHRASE).call();
}
private void submit(JO encrytpedData, URL url) {
JO signedTransactionResponse = SendMoneyCall.create(1).
recipient("NXT-KX2S-UULA-7YZ7-F3R8L").
amountNQT(12345678).
secretPhrase(SECRET_PHRASE).
deadline(15).
feeNQT(100000000). // See other examples for fee calculation
encryptedMessageData(encrytpedData.getString("data")).
encryptedMessageNonce(encrytpedData.getString("nonce")).
encryptedMessageIsPrunable(true).
remote(url).
call();
System.out.printf("SendMoney response: %s\n", signedTransactionResponse.toJSONString());
}
}
PhasedTransaction
This java program demonstrates how to submit a phased transaction. Javadoc
Source code
package com.jelurida.ardor.client.api;
import nxt.Nxt;
import nxt.addons.JO;
import nxt.configuration.Setup;
import nxt.http.callers.GetBlockCall;
import nxt.http.callers.SendMoneyCall;
import nxt.http.responses.BlockResponse;
import nxt.http.responses.BlockResponseImpl;
import nxt.http.responses.TransactionResponse;
import nxt.http.responses.TransactionResponseImpl;
import nxt.voting.VoteWeighting;
import java.net.MalformedURLException;
import java.net.URL;
public class PhasedTransaction {
private static final String SECRET_PHRASE = "hope peace happen touch easy pretend worthless talk them indeed wheel state";
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("https://testardor.jelurida.com/nxt");
Nxt.init(Setup.COMMAND_LINE_TOOL);
// start the node, so make sure it is not already running or you'll receive a BindException
try {
PhasedTransaction phasedTransaction = new PhasedTransaction();
phasedTransaction.submitPhasedTransaction(url);
} finally {
Nxt.shutdown(); // shutdown the node properly before closing the Java process
}
}
private void submitPhasedTransaction(URL url) {
JO block = GetBlockCall.create().remote(url).call();
BlockResponse blockResponse = new BlockResponseImpl(block);
int height = blockResponse.getHeight();
JO signedTransactionResponse = SendMoneyCall.create(2).
recipient("NXT-KX2S-UULA-7YZ7-F3R8L").
amountNQT(12345678).
secretPhrase(SECRET_PHRASE).
deadline(15).
feeNQT(100000000).
phased(true).
phasingVotingModel("" + VoteWeighting.VotingModel.ACCOUNT.getCode()). // Another account will need to approve this
phasingQuorum("1"). // One approver account is enough
phasingWhitelisted("NXT-EVHD-5FLM-3NMQ-G46NR"). // This is the account that needs to approve
phasingFinishHeight("" + (height + 100)). // It has 100 blocks to submit the approval
phasingMinBalanceModel("" + VoteWeighting.MinBalanceModel.NONE.getCode()). // There is no minimum balance requirement
remote(url).
call();
System.out.printf("SendMoney response: %s\n", signedTransactionResponse.toJSONString());
TransactionResponse transactionResponse = new TransactionResponseImpl(signedTransactionResponse.getJo("transactionJSON"));
System.out.printf("Phased: %s\n", transactionResponse.isPhased());
}
}
WaitForBlock
This java program demonstrates how to register a listener and wait for the next block. Javadoc
Source code
package com.jelurida.ardor.client.api;
import nxt.addons.JA;
import nxt.addons.JO;
import nxt.http.callers.EventRegisterCall;
import nxt.http.callers.EventWaitCall;
import nxt.util.Logger;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Register a listener and wait for the next block
*/
public class WaitForBlock {
public static void main(String[] args) throws MalformedURLException {
WaitForBlock waitForBlock = new WaitForBlock();
waitForBlock.process();
}
private void process() throws MalformedURLException {
URL remoteUrl = new URL("http://localhost:26876/nxt");
JO response;
String token = null;
try {
// Monitor the blockchain for a new block
response = EventRegisterCall.create().event("Block.BLOCK_PUSHED").remote(remoteUrl).call();
Logger.logInfoMessage("EventRegisterCall add %s", response.toJSONString());
if (!response.isExist("token")) {
// Registration failed
return;
}
token = response.getString("token");
JA events;
// Wait for the next event. The while loop is not necessary but serves as a good practice in order not to
// keep and Http request open for a long time.
while (true) {
// Wait up to 1 second for the event to occur
response = EventWaitCall.create().timeout("1").token(token).remote(remoteUrl).call();
Logger.logInfoMessage("EventWaitCall %s", response.toJSONString());
events = response.getArray("events");
if (events.size() > 0) {
// If the event occurred stop waiting
break;
}
}
// At this point the events array may include more than one event.
events.objects().forEach(e -> Logger.logInfoMessage("" + e));
} finally {
if (token != null) {
// Unregister the event listener
response = EventRegisterCall.create().token(token).remove("true").remote(remoteUrl).call();
Logger.logInfoMessage("EventRegisterCall remove %s", response.toJSONString());
}
}
}
}