Atomic Transfer SDK Usage

Below you will find examples for creating group transactions and sending them to the network in each of the available SDKs. The example code is separated into snippets categorized by these core functions.

For information on installing Go, Java, JavaScript and Python SDKs see Using the SDKs and REST APIs.

  1. Setup: Imports, Global Variables, Helper Functions, etc. (Go, Java, JavaScript, Python)
  2. Create the transactions (Go, Java, JavaScript, Python) - this is like creating any kind of transaction in Algorand.
  3. Group the transactions (Go, Java, JavaScript, Python) - this involves computing a groupID and assigning that id to each transaction.
  4. Sign the grouped transactions (Go, Java, JavaScript, Python) - sign the grouped transactions with their respective private keys.
  5. Send transactions to the network (Go, Java, JavaScript, Python) - combine the transactions and send it to the net.

 

A couple things to note before getting started...

  • Be sure to update your algod address and token for all examples.
  • There are three private mnemonics shown for demonstration purposes. In practice, you should never reveal these. We recommend changing these to your own mnemonics even when running these examples so you will be in control of asset inflows/outflows. Use the BetaNet dispenser to fund your accounts on BetaNet.

Atomic Transfers in Go

Setup: Imports, Global Variables, Helper Functions, etc.

Define algod constants and transaction headers. Define several helper functions that will be used throughout the Go examples.


package main

import (
	"fmt"

	"github.com/algorand/go-algorand-sdk/client/algod"
	"github.com/algorand/go-algorand-sdk/crypto"
	"github.com/algorand/go-algorand-sdk/mnemonic"
	"github.com/algorand/go-algorand-sdk/transaction"
	"github.com/algorand/go-algorand-sdk/types"
)

// CHANGE ME
const algodAddress = "ADDRESS"
const algodToken = "TOKEN"

func main() {

	// Initialize an algodClient
	algodClient, err := algod.MakeClient(algodAddress, algodToken)
	if err != nil {
		fmt.Printf("failed to make algod client: %v\n", err)
		return
	}

	txParams, err := algodClient.SuggestedParams()
	if err != nil {
		fmt.Printf("error getting suggested tx params: %s\n", err)
		return
	}

	// declare accounts
    // change these values to use different accounts.
	account1 := "MMNSBCYSMMVUXSCYNX5YT3WUDNX5HT6PHLHGOW53XROQLQKLNCQNMNPK6Y"
	account2 := "TKHRH6FLTZWOXBN3YGW5SZPPTYXEROIVMSYXZTYT5UAKYL5ESP4HQ6MPOQ"
	account3 := "6OTHHMVTWMZHEHEYD6ZYDECJ4JTU5PECIYJHDYZQBRJOFBTMY74GXW22MI"
    
    // shown for demonstration purposes. NEVER reveal secret mnemonics in practice. 
    // change these values to use different accounts.
	// declare account mnemonics for later consumption for private key conversion
	const mnemonic1 = "wine magnet pumpkin coral verb endless alone edit kangaroo pipe ability choice reform movie mother draw friend sea toe sword plate blouse awesome absent puzzle"
	const mnemonic2 = "road tuna such twin large ozone sleep chaos lemon frost celery outdoor team gentle ethics cycle toe spray quiz tiny basic that cute absorb shallow"
	const mnemonic3 = "lava skate speak erupt case route rotate above picture boat insane parrot bid century slow rose clinic into endless wood dose right ignore able occur"

	// declare txn parameters
	fee := txParams.Fee
	firstRound := txParams.LastRound
	lastRound := txParams.LastRound + 1000
	genesisID := txParams.GenesisID     // replace me
	genesisHash := txParams.GenesisHash // replace me
	const amount1 = 2000
	const amount2 = 1500
	var note []byte
	var lease [32]byte

Create Transactions in Go

The Go example computes the group id of several transactions using the ComputeGroupID() function call. The example highlights how to sign group transactions and send the sign transactions to the network. Additionally each SDK repository will contain tests files that may also be helpful in understanding the APIs.

Here we create the transactions (tx1 and tx2).


    // create transaction 1
	tx1, err := transaction.MakePaymentTxnWithFlatFee(
		account1, account2, fee, amount1, firstRound, lastRound,
		note, "", genesisID, genesisHash, lease,
	)
	if err != nil {
		fmt.Printf("Failed to create payment transaction: %v\n", err)
		return
	}

    // create transaction 2
	tx2, err := transaction.MakePaymentTxnWithFlatFee(
		account2, account3, fee, amount2, firstRound, lastRound,
		note, "", genesisID, genesisHash, lease,
	)
	if err != nil {
		fmt.Printf("Failed to create payment transaction: %v\n", err)
		return
	}

Group Transactions in Go

Compute the group id of the transactions and assign it the each transaction using tx.Group = gid


    // compute group id and put it into each transaction
	gid, err := crypto.ComputeGroupID([]types.Transaction{tx1, tx2})
	tx1.Group = gid
	tx2.Group = gid

Sign Grouped Transactions in Go

Before signing the transaction, you must first convert the declared mnemonics into ed25519 private keys. Sign each transaction using the sk1 and sk2 variables.


// convert mnemonic1 and mnemonic2 using the mnemonic.ToPrivateKey() helper function
sk1, err := mnemonic.ToPrivateKey(mnemonic1)
sk2, err := mnemonic.ToPrivateKey(mnemonic2)

// sign transaction 1
_, stx1, err := crypto.SignTransaction(sks[1], txn1)
if err != nil {
    fmt.Printf("Failed to sign transaction: %s\n", err)
    return
}
// sign transaction 2
_, stx2, err := crypto.SignTransaction(sks[2], txn2)
if err != nil {
    fmt.Printf("Failed to sign transaction: %s\n", err)
    return
}

Send Transactions to the Network in Go

Append the transactions into an array to be sent over the network.


	var signedGroup []byte
	signedGroup = append(signedGroup, stx1...)
	signedGroup = append(signedGroup, stx2...)
	signed, err := algodClient.SendRawTransaction(signedGroup)
	if err != nil {
		fmt.Printf("Failed to create payment transaction: %v\n", err)
		return
	}
	fmt.Printf("Transaction ID: %s\n", signed.TxID)
}

Here is the full Go code.


func main() {

	// Initialize an algodClient
	algodClient, err := algod.MakeClient(algodAddress, algodToken)
	if err != nil {
		fmt.Printf("failed to make algod client: %v\n", err)
		return
	}

	txParams, err := algodClient.SuggestedParams()
	if err != nil {
		fmt.Printf("error getting suggested tx params: %s\n", err)
		return
	}

	// declare accounts
	account1 := "MMNSBCYSMMVUXSCYNX5YT3WUDNX5HT6PHLHGOW53XROQLQKLNCQNMNPK6Y"
	account2 := "TKHRH6FLTZWOXBN3YGW5SZPPTYXEROIVMSYXZTYT5UAKYL5ESP4HQ6MPOQ"
	account3 := "6OTHHMVTWMZHEHEYD6ZYDECJ4JTU5PECIYJHDYZQBRJOFBTMY74GXW22MI"

	// declare account mnemonics for later consumption for private key conversion
	const mnemonic1 = "wine magnet pumpkin coral verb endless alone edit kangaroo pipe ability choice reform movie mother draw friend sea toe sword plate blouse awesome absent puzzle"
	const mnemonic2 = "road tuna such twin large ozone sleep chaos lemon frost celery outdoor team gentle ethics cycle toe spray quiz tiny basic that cute absorb shallow"
	const mnemonic3 = "lava skate speak erupt case route rotate above picture boat insane parrot bid century slow rose clinic into endless wood dose right ignore able occur"

	// declare txn parameters
	fee := txParams.Fee
	firstRound := txParams.LastRound
	lastRound := txParams.LastRound + 1000
	genesisID := txParams.GenesisID     // replace me
	genesisHash := txParams.GenesisHash // replace me
	const amount1 = 2000
	const amount2 = 1500
	var note []byte
	var lease [32]byte

	// convert mnemonic1 and mnemonic2 using the mnemonic.ToPrivateKey() helper function
	sk1, err := mnemonic.ToPrivateKey(mnemonic1)
	sk2, err := mnemonic.ToPrivateKey(mnemonic2)

	tx1, err := transaction.MakePaymentTxnWithFlatFee(
		account1, account2, fee, amount1, firstRound, lastRound,
		note, "", genesisID, genesisHash, lease,
	)
	if err != nil {
		fmt.Printf("Failed to create payment transaction: %v\n", err)
		return
	}

	tx2, err := transaction.MakePaymentTxnWithFlatFee(
		account2, account3, fee, amount2, firstRound, lastRound,
		note, "", genesisID, genesisHash, lease,
	)
	if err != nil {
		fmt.Printf("Failed to create payment transaction: %v\n", err)
		return
	}

	// compute group id and put it into each transaction
	gid, err := crypto.ComputeGroupID([]types.Transaction{tx1, tx2})
	tx1.Group = gid
	tx2.Group = gid

	_, stx1, err := crypto.SignTransaction(sk1, tx1)
	if err != nil {
		fmt.Printf("Failed to sign transaction: %s\n", err)
		return
	}
	_, stx2, err := crypto.SignTransaction(sk2, tx2)
	if err != nil {
		fmt.Printf("Failed to sign transaction: %s\n", err)
		return
	}

	var signedGroup []byte
	signedGroup = append(signedGroup, stx1...)
	signedGroup = append(signedGroup, stx2...)
	signed, err := algodClient.SendRawTransaction(signedGroup)
	if err != nil {
		fmt.Printf("Failed to create payment transaction: %v\n", err)
		return
	}
	fmt.Printf("Transaction ID: %s\n", signed.TxID)
}


Atomic Transfers in Java

Setup: Imports, Global Variables, Helper Functions, etc.

Include all necessary imports. Define various utility functions to be used throughout examples and hardcode example accounts.

package com.algorand.algosdk.transaction;

import java.io.ByteArrayOutputStream;
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.transaction.TxGroup;
import com.algorand.algosdk.util.Encoder;

public class GroupedTransaction 
{   
    // Inline class to handle changing block parameters
    // Throughout the example
    static class ChangingBlockParms
    {
        public BigInteger fee; 
        public BigInteger firstRound;  
        public BigInteger lastRound; 
        public String genID;
        public Digest genHash;
        public ChangingBlockParms() {
            this.fee = BigInteger.valueOf(0);
            this.firstRound = BigInteger.valueOf(0);
            this.lastRound = BigInteger.valueOf(0);
            this.genID = "";
            this.genHash = null;
        }
    };
    // Utility function to wait on a transaction to be confirmed    
    private static void waitForTransactionToComplete(AlgodApi algodApiInstance, String txID ) throws Exception{
        while(true) {
            try {
                //Check the pending tranactions
                com.algorand.algosdk.algod.client.model.Transaction b3 = algodApiInstance.pendingTransactionInformation(txID);
                if (b3.getRound() != null && b3.getRound().longValue() > 0) {
                    //Got the completed Transaction
                    System.out.println("Transaction " + b3.getTx() + " confirmed in round " + b3.getRound().longValue());
                    break;
                } 
            } catch (Exception e) {
                throw( e );
            }
        }

    }

    // Utility function to update changing block parameters 
    public static ChangingBlockParms getChangingParms(AlgodApi algodApiInstance) throws Exception{
        ChangingBlockParms cp = new GroupedTransaction.ChangingBlockParms(); 
        try {
            TransactionParams params = algodApiInstance.transactionParams();
            cp.fee = params.getFee();
            cp.firstRound = params.getLastRound();
            cp.lastRound = cp.firstRound.add(BigInteger.valueOf(1000));
            cp.genID = params.getGenesisID();
            cp.genHash = new Digest(params.getGenesishashb64());

        } catch (ApiException e) {
           throw( e );
        }
        return( cp );
    }

    // Utility function for sending a raw signed transaction to the network
    public static TransactionID submitTransaction(AlgodApi algodApiInstance, SignedTransaction signedTx ) throws Exception{
        try {
            // Msgpack encode the signed transaction
            byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTx);
            TransactionID id = algodApiInstance.rawTransaction(encodedTxBytes);
            return( id );
        } catch (ApiException e) {
            throw( e );
        }
    }


    public static void main(String args[]) throws Exception {
        final String ALGOD_API_ADDR = "NODEADDRESS";
        final String ALGOD_API_TOKEN = "NODETOKEN";

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

        // Shown for demonstration purposes. NEVER reveal secret mnemonics in practice.
        // These three accounts are for testing purposes
        final String account1_mnemonic = "portion never forward pill lunch organ biology"  
                           + " weird catch curve isolate plug innocent skin grunt" 
                           + " bounce clown mercy hole eagle soul chunk type absorb trim";
        final String account2_mnemonic = "place blouse sad pigeon wing warrior wild script"
                            + " problem team blouse camp soldier breeze twist mother"
                            + " vanish public glass code arrow execute convince ability"
                            + " there";
        final String account3_mnemonic = "image travel claw climb bottom spot path roast "
                            + "century also task cherry address curious save item "
                            + "clean theme amateur loyal apart hybrid steak about blanket";

        Account acct1  = new Account(account1_mnemonic); 
        Account acct2  = new Account(account2_mnemonic);
        Account acct3  = new Account(account3_mnemonic);                           
        // get last round and suggested tx fee
        // We use these to get the latest round and tx fees
        // These parameters will be required before every 
        // Transaction
        // We will account for changing transaction parameters
        // before every transaction in this example
        ChangingBlockParms cp = null;
        try {
            cp = getChangingParms(algodApiInstance);
        } catch (ApiException e) {
            e.printStackTrace();
            return;
        }
    }
}

Create Transactions in Java

The Java example below uses the Java SDK to create and group transactions using the computeGroupID() and the assignGroupID() function. The Java SDK repo contains additional examples. Additionally each SDK repository will contain tests files that may also be helpful in understanding the APIs.

Update standard Transaction parameters to account for changes in the state of the blockchain and generate the two transactions (tx1 and tx2).

	
try {
    cp = getChangingParms(algodApiInstance);
} catch (ApiException e) {
    e.printStackTrace();
    return;
}
// Create the first transaction
Transaction tx1 = new Transaction(acct1.getAddress(), acct2.getAddress(), 10000, cp.firstRound.intValue(), cp.lastRound.intValue(), null, cp.genHash);
// Create the second transaction
tx1.fee = BigInteger.valueOf(1000);
Transaction tx2 = new Transaction(acct2.getAddress(), acct3.getAddress(), 20000, cp.firstRound.intValue(), cp.lastRound.intValue(), null, cp.genHash);
tx2.fee = BigInteger.valueOf(1000);

Group Transactions in Java

Compute the group ID and assign the ID each transaction using tx.assignGroupID(gid)

	
Digest gid = TxGroup.computeGroupID(new Transaction[]{tx1, tx2});

tx1.assignGroupID(gid);
tx2.assignGroupID(gid);

Sign Grouped Transactions in Java

Sign each transaction with the accounts private key using acct1 and acct2 from Setup: Imports, Global Variables, Helper Functions, etc.

	
SignedTransaction signedTx1 = acct1.signTransaction(tx1);;
SignedTransaction signedTx2 = acct2.signTransaction(tx2);;

Send Transactions to the Network in Java

Encode the transactions into a byte arrays. Copy the arrays into each other and submit to the network using rawTransaction

	
try {
    ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream( );
    byte[] encodedTxBytes1 = Encoder.encodeToMsgPack(signedTx1);
    byte[] encodedTxBytes2 = Encoder.encodeToMsgPack(signedTx2);
    byteOutputStream.write(encodedTxBytes1);
    byteOutputStream.write(encodedTxBytes2);

    byte groupTransactionBytes[] = byteOutputStream.toByteArray();
                
    TransactionID id = algodApiInstance.rawTransaction(groupTransactionBytes);
    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());
}

Here is the full Java Code

	
package com.algorand.algosdk.auction;

import java.io.ByteArrayOutputStream;
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.transaction.TxGroup;
import com.algorand.algosdk.util.Encoder;

public class GroupedTransaction {   
    // Inline class to handle changing block parameters
    // Throughout the example
    static class ChangingBlockParms {
        public BigInteger fee; 
        public BigInteger firstRound;  
        public BigInteger lastRound; 
        public String genID;
        public Digest genHash;
        public ChangingBlockParms() {
            this.fee = BigInteger.valueOf(0);
            this.firstRound = BigInteger.valueOf(0);
            this.lastRound = BigInteger.valueOf(0);
            this.genID = "";
            this.genHash = null;
        }
    };

    // Utility function to update changing block parameters 
    public static ChangingBlockParms getChangingParms(AlgodApi algodApiInstance) throws Exception{
        ChangingBlockParms cp = new GroupedTransaction.ChangingBlockParms(); 
        try {
            TransactionParams params = algodApiInstance.transactionParams();
            cp.fee = params.getFee();
            cp.firstRound = params.getLastRound();
            cp.lastRound = cp.firstRound.add(BigInteger.valueOf(1000));
            cp.genID = params.getGenesisID();
            cp.genHash = new Digest(params.getGenesishashb64());

        } catch (ApiException e) {
           throw( e );
        }
        return( cp );
    }

    // Utility function for sending a raw signed transaction to the network
    public static TransactionID submitTransaction(AlgodApi algodApiInstance, SignedTransaction signedTx ) throws Exception{
        try {
            // Msgpack encode the signed transaction
            byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTx);
            TransactionID id = algodApiInstance.rawTransaction(encodedTxBytes);
            return( id );
        } catch (ApiException e) {
            throw( e );
        }
    }

    public static void main(String args[]) throws Exception {
        final String ALGOD_API_ADDR = "http://localhost:8080";
        final String ALGOD_API_TOKEN = "b65ea5effe184f71b9ce7a8f8a1ebda9bdbc24ce0ef0d4fff506429bb3629050";

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

        // 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";
        final String account2_mnemonic = "snake unveil hello input club barrel measure announce bring seed practice enact train camp enlist wear kick science now word horror month rather abstract course";
        final String account3_mnemonic = "salmon about chair clap body sample chuckle inside adapt leg bonus afford grit floor pencil celery cherry armor solar sheriff loyal vessel stay absorb budget";

        Account acct1  = new Account(account1_mnemonic); 
        Account acct2  = new Account(account2_mnemonic);
        Account acct3  = new Account(account3_mnemonic);                           
        // get last round and suggested tx fee
        // We use these to get the latest round and tx fees
        // These parameters will be required before every 
        // Transaction
        // We will account for changing transaction parameters
        // before every transaction in this example
        ChangingBlockParms cp = null;
        try {
            cp = getChangingParms(algodApiInstance);
        } catch (ApiException e) {
            e.printStackTrace();
            return;
        }        	
        try {
            cp = getChangingParms(algodApiInstance);
        } catch (ApiException e) {
            e.printStackTrace();
            return;
        }

        // Create the first transaction
        Transaction tx1 = new Transaction(acct1.getAddress(), acct2.getAddress(), 10000, cp.firstRound.intValue(), cp.lastRound.intValue(), null, cp.genHash);
        // Create the second transaction
        tx1.fee = BigInteger.valueOf(1000);
        Transaction tx2 = new Transaction(acct2.getAddress(), acct3.getAddress(), 20000, cp.firstRound.intValue(), cp.lastRound.intValue(), null, cp.genHash);
        tx2.fee = BigInteger.valueOf(1000);
        Digest gid = TxGroup.computeGroupID(new Transaction[]{tx1, tx2});

        tx1.assignGroupID(gid);
        tx2.assignGroupID(gid);
        SignedTransaction signedTx1 = acct1.signTransaction(tx1);;
        SignedTransaction signedTx2 = acct2.signTransaction(tx2);;
            
        try {
            ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream( );
            byte[] encodedTxBytes1 = Encoder.encodeToMsgPack(signedTx1);
            byte[] encodedTxBytes2 = Encoder.encodeToMsgPack(signedTx2);
            byteOutputStream.write(encodedTxBytes1);
            byteOutputStream.write(encodedTxBytes2);

            byte groupTransactionBytes[] = byteOutputStream.toByteArray();
                        
            TransactionID id = algodApiInstance.rawTransaction(groupTransactionBytes);
            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());
        }
    }
}


Atomic Transfers in JavaScript

Setup: Imports, Global Variables, Helper Functions, etc.

Include all necessary imports. Define various utility functions to be used throughout examples and hardcode example accounts.


const algosdk = require('algosdk');

    //Retrieve the token, server and port values for your installation in the algod.net
    //and algod.token files within the data directory
    // UPDATE THESE VALUES
    const token = "TOKEN";
    const server = "SERVER";
    const port = PORT;

    //instantiate the algod wrapper
    let algodclient = new algosdk.Algod(token, server, port);

    // Shown for demonstration purposes. NEVER reveal secret mnemonics in practice. 
    // Change these values to use different accounts.
    // Recover accounts used in example
    var account1_mnemonic = "wine magnet pumpkin coral verb endless alone edit kangaroo pipe ability choice reform movie mother draw friend sea toe sword plate blouse awesome absent puzzle";
    var account2_mnemonic = "road tuna such twin large ozone sleep chaos lemon frost celery outdoor team gentle ethics cycle toe spray quiz tiny basic that cute absorb shallow";
    var account3_mnemonic = "lava skate speak erupt case route rotate above picture boat insane parrot bid century slow rose clinic into endless wood dose right ignore able occur";


Create Transactions in JavaScript

As covered in the Atomic Transfer specification, AT’s are Algorand batch transactions that group together two or more transactions files. The JS example below uses the JS SDK to first declare an array of transactions and an array of corresponding private keys to sign off on the respective transactions. The example discusses grouping those transactions together, signing and sending them to the net. The JavaScript SDK README

contains additional examples. Additionally, each SDK repository will contain test files that may also be helpful in understanding the APIs.

Here we create transactions tx1, tx2 and tx3. We define a txns array and store the transactions inside. We also define an array called sks and and store the recoveredAccounts inside of the array, this will be used to sign the transactions.

	
// Create transaction 1
let tx1 = algosdk.makePaymentTxn(recoveredAccount1.addr, recoveredAccount3.addr, params.fee, 200000, undefined, params.lastRound, endRound, new Uint8Array(0), params.genesishashb64, params.genesisID);
// Create transaction 2
let tx2 = algosdk.makePaymentTxn(recoveredAccount2.addr, recoveredAccount3.addr, params.fee, 100000, undefined, params.lastRound, endRound, new Uint8Array(0), params.genesishashb64, params.genesisID);
// Create transaction 3
let tx3 = algosdk.makePaymentTxn(recoveredAccount3.addr, recoveredAccount2.addr, params.fee, 50000, undefined, params.lastRound, endRound, new Uint8Array(0), params.genesishashb64, params.genesisID);
// array of unsigned transactions (dict or Transaction)
let txns = [tx1, tx2, tx3];
// array of appropriate secret keys
let sks = [recoveredAccount1, recoveredAccount2, recoveredAccount3];
let txgroup = algosdk.assignGroupID(txns);

Group Transactions in JavaScript

Compute the group id of the transactions and assign it the each.

	
transaction using algosdk.assignGroupID
let txgroup = algosdk.assignGroupID(txns);

Sign Grouped Transactions in JavaScript

Sign all transactions using the txns array.

	
let signed = []
for (let idx in txns) {
    let signedTx = txns[idx].signTxn(sks[idx].sk);
    signed.push(signedTx);
}

Send Transactions to the Network in JavaScript

Send array of signed transactions as a group.

	
let tx = (await algodclient.sendRawTransactions(signed));
console.log("Transaction : " + tx.txId);

Here is the full JavaScript Code

	
(async() => {
    let params = await algodclient.getTransactionParams();
    let endRound = params.lastRound + parseInt(1000);
    let fee = await algodclient.suggestedFee();

    var recoveredAccount1 = algosdk.mnemonicToSecretKey(account1_mnemonic);
    var recoveredAccount2 = algosdk.mnemonicToSecretKey(account2_mnemonic);
    var recoveredAccount3 = algosdk.mnemonicToSecretKey(account3_mnemonic);

    	
    let tx1 = algosdk.makePaymentTxn(recoveredAccount1.addr, recoveredAccount3.addr, params.fee, 200000, undefined, params.lastRound, endRound, new Uint8Array(0), params.genesishashb64, params.genesisID);
    // Create transaction 2
    let tx2 = algosdk.makePaymentTxn(recoveredAccount2.addr, recoveredAccount3.addr, params.fee, 100000, undefined, params.lastRound, endRound, new Uint8Array(0), params.genesishashb64, params.genesisID);
    // Create transaction 3
    let tx3 = algosdk.makePaymentTxn(recoveredAccount3.addr, recoveredAccount2.addr, params.fee, 50000, undefined, params.lastRound, endRound, new Uint8Array(0), params.genesishashb64, params.genesisID);

    // array of unsigned transactions (dict or Transaction)
    let txns = [tx1, tx2, tx3];

    // array of appropriate secret keys
    let sks = [recoveredAccount1, recoveredAccount2, recoveredAccount3];
    let txgroup = algosdk.assignGroupID(txns);

    //sign all transactions
    let signed = []
    for (let idx in txns) {
        let signedTx = txns[idx].signTxn(sks[idx].sk);
        signed.push(signedTx);
    }

    let tx = (await algodclient.sendRawTransactions(signed));
    console.log("Transaction : " + tx.txId);

    })().catch(e => {
        console.log(e);
});


Atomic Transfers in Python

Setup: Imports, Global Variables, Helper Functions, etc.

Include all necessary imports. Define various utility functions to be used throughout examples and hardcode example accounts.


import params
from algosdk import algod, transaction, account, mnemonic, encoding

# Shown for demonstration purposes. NEVER reveal secret mnemonics in practice. 
# Change these values to use different accounts.
passphrase = "address adult aisle category buzz fold series delay master advice process diamond trust they panda afraid cram piano rather time gaze govern thing able simple"
pk_sender = mnemonic.to_private_key(passphrase)
sender = account.address_from_private_key(pk_sender)

passphrase2 = "into salon destroy steel present write debris assault arm coach type exclude fatigue repair idle delay light sad cook table key tree tennis absorb tower"
pk_receiver = mnemonic.to_private_key(passphrase2)
receiver = account.address_from_private_key(pk_receiver)

# create an algod client
# you can also declare your algod token and address in this file instead of importing from params
# algod_address = "" # ADD ADDRESS
# algod_token = "" # ADD TOKEN
acl = algod.AlgodClient(params.algod_token, params.algod_address)

# get suggested parameters
params = acl.suggested_params()
gen = params["genesisID"]
gh = params["genesishashb64"]
last_round = params["lastRound"]
fee = params["fee"]
amount = 1000


Create Transactions in Python

The Python example below uses the Python SDK to first declare some account mnemonics and retrieve the account address through the mnemonic phrase. The example  below discusses how to create basic transactions, grouping those transactions together, signing and sending them to the net. The Python SDK readme also contains more detailed examples of how to do use several other functions. Additionally each SDK repository will contain tests files that may also be helpful in understanding the APIs.

The account address has already been derived from the mnemonic phrase in the Setup: Imports, Global Variables, Helper Functions, etc. using mnemonic.to_private_key() to first convert the mnemonic phrase into an ed25519 private key and then using account.address_from_private_key() to convert to the address string. Create transactions txn1 and txn2.

	
# create transaction1
txn1 = transaction.PaymentTxn(sender, fee, last_round, last_round+100, gh, receiver, amount)
# create transaction2
txn2 = transaction.PaymentTxn(receiver, fee, last_round, last_round+100, gh, sender, amount)

Group Transactions in Python

Calculate and define the group ID by passing txn1 and txn2 into transaction.calculate_group_id() and assign gid to both txn1 and txn2 using txn.group = gid

	
# get group id and assign it to transactions
gid = transaction.calculate_group_id([txn1, txn2])
txn1.group = gid
txn2.group = gid

Sign Grouped Transactions in Python

Sign the transactions

	
# sign transaction1
stxn1 = txn1.sign(pk_sender)
# sign transaction2
stxn2 = txn2.sign(pk_receiver)

Send Transactions to the Network in Python

First declare an array and append both signed transactions (stx1 and stx2) to the array. Broadcast both transactions over network.

	
signedGroup =  []
signedGroup.append(stxn1)
signedGroup.append(stxn2)
# send them over network
sent = acl.send_transactions(signedGroup)
# print txid
print(sent)

Here is the full Python Code

	
# create transaction1
txn1 = transaction.PaymentTxn(sender, fee, last_round, last_round+100, gh, receiver, amount)
# create transaction2
txn2 = transaction.PaymentTxn(receiver, fee, last_round, last_round+100, gh, sender, amount)

# get group id and assign it to transactions
gid = transaction.calculate_group_id([txn1, txn2])
txn1.group = gid
txn2.group = gid

# sign transaction1
stxn1 = txn1.sign(pk_sender)
# sign transaction2
stxn2 = txn2.sign(pk_receiver)

signedGroup =  []
signedGroup.append(stxn1)
signedGroup.append(stxn2)
# send them over network
sent = acl.send_transactions(signedGroup)
# print txid
print(sent)