Sample Java Programs

From ArdorDocs
Jump to: navigation, search

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());
            }
        }
    }
}