Create Publication

We are looking for publications that demonstrate building dApps or smart contracts!
See the full list of Gitcoin bounties that are eligible for rewards.

Tutorial Thumbnail
Beginner · 15 minutes or less

Setting the Transaction Fee in Java

This tutorial is intended to help you understand the difference between using a flat fee versus a suggested fee with any transaction. The sample also shows how to set these fees with Java.

Requirements

Background

All transactions on the Algorand blockchain require a fee, which must be greater than or equal to the minimum transaction fee (currently 1000 microAlgos). The SDKs provide two primary methods to determine the fee for your transaction. One method uses the suggested fee-per-byte and the other allows you to specify a flat fee. See Fees to learn more about how these are calculated and why you may want to use one over the other. This tutorial also creates and submits the transaction. See Your First Transaction for details on transactions.

Steps

1. Connect to Algod and Get Suggested Params

The Rest API provides a method to get the suggested fee per byte of a transaction (suggestedFee). It is important to realize that this number is a fee per byte and not a total fee. For transactions of normal size (1kb) this is currently 1000 microAlgos. For transactions that are larger (note field usage and smart contracts) this fee may be higher than the minimum transaction. You can also set the fee per byte to 0 and the system will automatically set the fee to the current minimum transaction fee. The code below sets up a connection to the algod process, gets the suggested transaction parameters and the suggested transaction fee per byte.

package com.algorand.algosdk.transactionfee;

import java.math.BigInteger;

import com.algorand.algosdk.account.Account;
import com.algorand.algosdk.algod.client.AlgodClient;
import com.algorand.algosdk.algod.client.ApiException;
import com.algorand.algosdk.algod.client.api.AlgodApi;
import com.algorand.algosdk.algod.client.auth.ApiKeyAuth;
import com.algorand.algosdk.algod.client.model.TransactionID;
import com.algorand.algosdk.algod.client.model.TransactionParams;
import com.algorand.algosdk.crypto.Digest;
import com.algorand.algosdk.transaction.SignedTransaction;
import com.algorand.algosdk.transaction.Transaction;
import com.algorand.algosdk.util.Encoder;

public class TransactionFee 
{   

    public static void main(String args[]) throws Exception {
        final String ALGOD_API_ADDR = "http://<your-algod-host>:<your-alogd-port>";
        final String ALGOD_API_TOKEN = "<your-api-token>";

        AlgodClient client = (AlgodClient) new AlgodClient().setBasePath(ALGOD_API_ADDR);
        ApiKeyAuth api_key = (ApiKeyAuth) client.getAuthentication("api_key");
        api_key.setApiKey(ALGOD_API_TOKEN);
        AlgodApi algodApiInstance = new AlgodApi(client);


        // Setup suggested parameters
        TransactionParams params = algodApiInstance.transactionParams();
        BigInteger suggestedFee = algodApiInstance.suggestedFee().getFee();
        BigInteger firstRound = params.getLastRound();
        BigInteger lastRound = firstRound.add(BigInteger.valueOf(1000));
        Digest genHash = new Digest(params.getGenesishashb64());

    }
}

2. Recover Sender Account

Recover the account that is going to submit the transaction. Make sure to use the dispenser to fund the recovered account.

package com.algorand.algosdk.transactionfee;

import java.math.BigInteger;

import com.algorand.algosdk.account.Account;
import com.algorand.algosdk.algod.client.AlgodClient;
import com.algorand.algosdk.algod.client.ApiException;
import com.algorand.algosdk.algod.client.api.AlgodApi;
import com.algorand.algosdk.algod.client.auth.ApiKeyAuth;
import com.algorand.algosdk.algod.client.model.TransactionID;
import com.algorand.algosdk.algod.client.model.TransactionParams;
import com.algorand.algosdk.crypto.Digest;
import com.algorand.algosdk.transaction.SignedTransaction;
import com.algorand.algosdk.transaction.Transaction;
import com.algorand.algosdk.util.Encoder;

public class TransactionFee 
{   

    public static void main(String args[]) throws Exception {
        final String ALGOD_API_ADDR = "http://<your-algod-host>:<your-alogd-port>";
        final String ALGOD_API_TOKEN = "<your-api-token>";

        AlgodClient client = (AlgodClient) new AlgodClient().setBasePath(ALGOD_API_ADDR);
        ApiKeyAuth api_key = (ApiKeyAuth) client.getAuthentication("api_key");
        api_key.setApiKey(ALGOD_API_TOKEN);
        AlgodApi algodApiInstance = new AlgodApi(client);


        // Setup suggested parameters
        TransactionParams params = algodApiInstance.transactionParams();
        BigInteger suggestedFee = algodApiInstance.suggestedFee().getFee();
        BigInteger firstRound = params.getLastRound();
        BigInteger lastRound = firstRound.add(BigInteger.valueOf(1000));
        Digest genHash = new Digest(params.getGenesishashb64());

        // Shown for demonstration purposes. NEVER reveal secret mnemonics in practice.
        // These three accounts are for testing purposes
        final String account1_mnemonic = "champion weather blame curtain " 
        + "thing strike despair month pattern unaware feel congress carpet "
        + "sniff palm predict olive talk mango toe teach jelly priority above squirrel";
        Account acct1  = new Account(account1_mnemonic);   
    }
}


Learn More
- Add Funds using Dispenser

3. Construct Transaction with Fee

The transaction can now be created. The fee can be set to the suggested fee per byte or optionally you can set a flat fee.

Use a suggested fee per byte

package com.algorand.algosdk.transactionfee;

import java.math.BigInteger;

import com.algorand.algosdk.account.Account;
import com.algorand.algosdk.algod.client.AlgodClient;
import com.algorand.algosdk.algod.client.ApiException;
import com.algorand.algosdk.algod.client.api.AlgodApi;
import com.algorand.algosdk.algod.client.auth.ApiKeyAuth;
import com.algorand.algosdk.algod.client.model.TransactionID;
import com.algorand.algosdk.algod.client.model.TransactionParams;
import com.algorand.algosdk.crypto.Digest;
import com.algorand.algosdk.transaction.SignedTransaction;
import com.algorand.algosdk.transaction.Transaction;
import com.algorand.algosdk.util.Encoder;

public class TransactionFee 
{   

    public static void main(String args[]) throws Exception {
        final String ALGOD_API_ADDR = "http://<your-algod-host>:<your-alogd-port>";
        final String ALGOD_API_TOKEN = "<your-api-token>";

        AlgodClient client = (AlgodClient) new AlgodClient().setBasePath(ALGOD_API_ADDR);
        ApiKeyAuth api_key = (ApiKeyAuth) client.getAuthentication("api_key");
        api_key.setApiKey(ALGOD_API_TOKEN);
        AlgodApi algodApiInstance = new AlgodApi(client);


        // Setup suggested parameters
        TransactionParams params = algodApiInstance.transactionParams();
        BigInteger suggestedFee = algodApiInstance.suggestedFee().getFee();
        BigInteger firstRound = params.getLastRound();
        BigInteger lastRound = firstRound.add(BigInteger.valueOf(1000));
        Digest genHash = new Digest(params.getGenesishashb64());

        // Shown for demonstration purposes. NEVER reveal secret mnemonics in practice.
        // These three accounts are for testing purposes
        final String account1_mnemonic = "champion weather blame curtain " 
        + "thing strike despair month pattern unaware feel congress carpet "
        + "sniff palm predict olive talk mango toe teach jelly priority above squirrel";

        Account acct1  = new Account(account1_mnemonic);   


        // Create transaction with either suggested fee
        // or flat fee 
        Transaction tx1 = Transaction.PaymentTransactionBuilder()
                .sender(acct1.getAddress())
                .receiver("GD64YIY3TWGDMCNPP553DZPPR6LDUSFQOIJVFDPPXWEG3FVOJCCDBBHU5A")
                .fee(suggestedFee)
                .amount(10000)
                .firstValid(firstRound)
                .lastValid(lastRound)
                .genesisHash(genHash)
                .build();

    }
}

Using a Flat Fee

To set a flat fee, modify the PaymentTransactionBuilder method to set the flat fee and remove the suggested fee parameter.

        Transaction tx1 = Transaction.PaymentTransactionBuilder()
                .sender(acct1.getAddress())
                .receiver("GD64YIY3TWGDMCNPP553DZPPR6LDUSFQOIJVFDPPXWEG3FVOJCCDBBHU5A")
                .flatFee(1000)
                .amount(10000)
                .firstValid(firstRound)
                .lastValid(lastRound)
                .genesisHash(genHash)
                .build();

4. Sign and Submit Transaction

Sign and submit the create transaction.

package com.algorand.algosdk.transactionfee;

import java.math.BigInteger;

import com.algorand.algosdk.account.Account;
import com.algorand.algosdk.algod.client.AlgodClient;
import com.algorand.algosdk.algod.client.ApiException;
import com.algorand.algosdk.algod.client.api.AlgodApi;
import com.algorand.algosdk.algod.client.auth.ApiKeyAuth;
import com.algorand.algosdk.algod.client.model.TransactionID;
import com.algorand.algosdk.algod.client.model.TransactionParams;
import com.algorand.algosdk.crypto.Digest;
import com.algorand.algosdk.transaction.SignedTransaction;
import com.algorand.algosdk.transaction.Transaction;
import com.algorand.algosdk.util.Encoder;

public class TransactionFee 
{   

    public static void main(String args[]) throws Exception {
        final String ALGOD_API_ADDR = "http://<your-algod-host>:<your-alogd-port>";
        final String ALGOD_API_TOKEN = "<your-api-token>";

        AlgodClient client = (AlgodClient) new AlgodClient().setBasePath(ALGOD_API_ADDR);
        ApiKeyAuth api_key = (ApiKeyAuth) client.getAuthentication("api_key");
        api_key.setApiKey(ALGOD_API_TOKEN);
        AlgodApi algodApiInstance = new AlgodApi(client);


        // Setup suggested parameters
        TransactionParams params = algodApiInstance.transactionParams();
        BigInteger suggestedFee = algodApiInstance.suggestedFee().getFee();
        BigInteger firstRound = params.getLastRound();
        BigInteger lastRound = firstRound.add(BigInteger.valueOf(1000));
        Digest genHash = new Digest(params.getGenesishashb64());

        // Shown for demonstration purposes. NEVER reveal secret mnemonics in practice.
        // These three accounts are for testing purposes
        final String account1_mnemonic = "champion weather blame curtain " 
        + "thing strike despair month pattern unaware feel congress carpet "
        + "sniff palm predict olive talk mango toe teach jelly priority above squirrel";

        Account acct1  = new Account(account1_mnemonic);   


        // Create transaction with either suggested fee
        // or flat fee 
        Transaction tx1 = Transaction.PaymentTransactionBuilder()
                .sender(acct1.getAddress())
                .receiver("GD64YIY3TWGDMCNPP553DZPPR6LDUSFQOIJVFDPPXWEG3FVOJCCDBBHU5A")
                .fee(suggestedFee)
                .amount(10000)
                .firstValid(firstRound)
                .lastValid(lastRound)
                .genesisHash(genHash)
                .build();
        SignedTransaction signedTx = acct1.signTransaction(tx1);;
        // Submit the transaction
        try {
            byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTx);
            TransactionID id = algodApiInstance.rawTransaction(encodedTxBytes);
            System.out.println("Successfully sent tx group with first tx id: " + id);
            } catch (ApiException e) {
                // This is generally expected, but should give us an informative error message.
                System.err.println("Exception when calling algod#rawTransaction: " + e.getResponseBody());
        }
    }
}