ASC1 SDK Usage

This guide will walk you through the use of the SDKs, to initiate transactions using TEAL. Generally, each of the SDKs expects the TEAL program to be compiled and then the bytes referenced in the SDK. Note that each example shows how to use a TEAL program as an escrow account or via signature delegation, where you delegate your signature (or a Multisig account signature) based on logic. Most of the examples will have comments that explain how you can switch between these scenarios. The SDKs will also soon be providing APIs that allow TEAL templates that are officially supported to be executed. To learn more about TEAL, see Algorand Smart Contract.

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

Compiling Teal and Getting the Byte Output

Compiling TEAL programs are covered extensively in the TEAL tutorial. This section covers how to dump the bytes of a compiled TEAL program so it can be used in the various SDKs. We use a very simple example of a TEAL program that always returns 0, meaning no transaction will ever be approved with this code.

To create the simple example either create a file with the one line containing ā€œint 0ā€ or use a command similar to the following

$ echo int 0 > zero.teal 

You can then compile the TEAL program using the following goal command.

$ goal clerk compile zero.teal
zero.teal: KI4DJG2OOFJGUERJGSWCYGFZWDNEU2KWTU56VRJHITP62PLJ5VYMBFDBFE

This produces an Algorand account for the teal logic that can be used to fund the TEAL contract if you plan on using the escrow pattern. The compiled program will have a .tok extension. To get the bytes for various SDKs will either require that you hex dump the compiled version or cat it with base64 formatting as shown below.

 //hexdump
$ hexdump -C zero.teal.tok
00000000  01 20 01 00 22                                    |. .."|
00000005
//base64 format
$ cat zero.teal.tok | base64
ASABACI=

Using Teal with the JavaScript SDK

As covered in the TEAL specification, TEAL programs can be used to create contract accounts that can function like escrows or they can be used to delegate signature authority. The JavaScript example below shows delegating your signature. Within the comments, you will see that the only difference is whether you sign the transaction using the LogicSig.sign method. Additionally in an escrow account, the from field will be the account generated when you compile the TEAL logic. In a delegation scenario, the from field will be the account that is delegating the signature. The JavaScript SDK README contains additional examples. Additionally, each SDK repository will contain test files that may also be helpful in understanding the APIs.


 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
const token = "61bddc5e84ed1ea3f8e9143a70da8fbe3478ae5e06caa52064332b09d158bb70";
const server = "http://127.0.0.1";
const port = 8080;

//Recover the account
//GMHW5XK626T5PUNRWP2DKEISTCDP2VFR3ZLW4D5WBYYXWPPN4R6JOCER7A
var mnemonic = "young pear hard disorder execute trim upper alone jewel service mango resemble mansion emerge fabric jungle gesture yellow power mouse insect month kiss ability hurt";
var recoveredAccount = algosdk.mnemonicToSecretKey(mnemonic);
console.log(recoveredAccount.addr);
//check to see if account is valid
var isValid = algosdk.isValidAddress(recoveredAccount.addr);
console.log("Is this a valid address: " + isValid);


//instantiate the algod wrapper
let algodclient = new algosdk.Algod(token, server, port);
//submit the transaction
(async() => {
    //Get the relevant params from the algod
    let params = await algodclient.getTransactionParams();
    console.log("here" + params);
    let endRound = params.lastRound + parseInt(1000);
    let fee = await algodclient.suggestedFee();

    // move the TEAL  program into Uint8Array
    let program = new Uint8Array(Buffer.from("ASABACI=", "base64"));

    // makeLogicSig method takes the program and parameters
    // in this example we have no parameters
    // If we did have parameters you would add them like
    // let args = [
    //    Uint8Array.from("123"),
    //    Uint8Array.from("456")
    // ];
    // And remember TEAL parameters are order specific
    let lsig = algosdk.makeLogicSig(program);
    
    // sign the logic with your accounts secret
    // key. This is essentially giving your
    // key authority to anyone with the lsig
    // and if the logic returns true
    // exercise extreme care
    // If this were an escrow account usage
    // you would not do this sign operation
    lsig.sign(recoveredAccount.sk);

    // At this point you can save the lsig off and share
    // as your delegated signature.
    // The LogicSig class supports serialization and
    // provides the lsig.toByte and fromByte methods
    // to easily convert for file saving and 
    // reconstituting and LogicSig object

    //create a transaction
    let txn = {
        "from": recoveredAccount.addr,
        "to": "SOEI4UA72A7ZL5P25GNISSVWW724YABSGZ7GHW5ERV4QKK2XSXLXGXPG5Y",
        "fee": params.fee,
        "amount": 100000,
        "firstRound": params.lastRound,
        "lastRound": endRound,
        "genesisID": params.genesisID,
        "genesisHash": params.genesishashb64
    };

    // create logic signed transaction.
    // Had this been an escrow the lsig would not contain the
    // signature but would be submitted the same way
    let rawSignedTxn = algosdk.signLogicSigTransaction(txn, lsig);

    //Submit the lsig signed transaction
    let tx = (await algodclient.sendRawTransaction(rawSignedTxn.blob));
    console.log("Transaction : " + tx.txId);

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

Using Teal with the Java SDK

The Java example below uses the hex dump of the compiled TEAL program to load it up to use in an escrow contract account Transaction. The comments in the example below also detail how you would do delegation with the Java SDK. The Java SDK Repo contains additional examples. Additionally each SDK repository will contain test files that may also be helpful in understanding the APIs.

package com.algorand.algosdk.teal;

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.*;
import com.algorand.algosdk.crypto.Address;
import com.algorand.algosdk.crypto.Digest;
import com.algorand.algosdk.crypto.LogicsigSignature;
import com.algorand.algosdk.transaction.SignedTransaction;
import com.algorand.algosdk.transaction.Transaction;
import com.algorand.algosdk.util.Encoder;
import java.math.BigInteger;

/**
 * Sign and Submit a transaction example with TEAL
 *
 */
public class SubmitTealTransaction 
{
    public static void main(String args[]) throws Exception {
        final String ALGOD_API_ADDR = "http://localhost:8080";
        final String ALGOD_API_TOKEN = "61bddc5e84ed1ea3f8e9143a70da8fbe3478ae5e06caa52064332b09d158bb70";

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

        // Using a backup mnemonic to recover the source account to send tokens from
        // Only use SRC_ACCOUNT if you are delegating authority
        // This example functions as an escrow
        // final String SRC_ACCOUNT = "young pear hard disorder execute trim upper alone jewel service mango resemble mansion emerge fabric jungle gesture yellow power mouse insect month kiss ability hurt";
        final String DEST_ADDR = "SOEI4UA72A7ZL5P25GNISSVWW724YABSGZ7GHW5ERV4QKK2XSXLXGXPG5Y";
 

        // get last round and suggested tx fee
        BigInteger suggestedFeePerByte = BigInteger.valueOf(1);
        BigInteger firstRound = BigInteger.valueOf(301);
        String genId = null;
        Digest genesisHash = null;
        try {
            // Get suggested parameters from the node
            TransactionParams params = algodApiInstance.transactionParams();
            suggestedFeePerByte = params.getFee();
            firstRound = params.getLastRound();
            System.out.println("Suggested Fee: " + suggestedFeePerByte);
            genId = params.getGenesisID();
            genesisHash = new Digest(params.getGenesishashb64());

        } catch (ApiException e) {
            System.err.println("Exception when calling algod#transactionParams");
            e.printStackTrace();
        }


        // the src account wold only be used to delegate authority
        // Account src = new Account(SRC_ACCOUNT);
        BigInteger amount = BigInteger.valueOf(1000);
        BigInteger lastRound = firstRound.add(BigInteger.valueOf(1000)); // 1000 is the max tx window

        // Get bytes of TEAL program
        byte[] program = {
            0x01, 0x20, 0x01, 0x00, 0x22  // int 0
        };

        // This example does not have parameters but if it did
        // you could do the following 
        // ArrayList args = new ArrayList();
        // byte[] arg1 = {1, 2, 3};
        // byte[] arg2 = {4, 5, 6};
        // args.add(arg1);
        // args.add(arg2);
        //lsig = new LogicsigSignature(program, args);
        LogicsigSignature lsig = new LogicsigSignature(program, null);

        // If delegating authority do this 
        // src.signLogicsig(lsig);
        // The LogicsigSignature class is 
        // Serializeable so you can write out the lsig to share with others
        // FileOutputStream file = new FileOutputStream("./lsig.sav"); 
        // ObjectOutputStream out = new ObjectOutputStream(file); 
        // out.writeObject(lsig);
        // out.close(); 
        // file.close();
        // It is not needed or advised if you are using as an escrow
        System.out.println("Escrow address: " + lsig.toAddress().toString());
        
        Transaction tx = new Transaction(lsig.toAddress(), new Address(DEST_ADDR), BigInteger.valueOf(1000), amount, firstRound, lastRound, genId, genesisHash);

        // send the transaction to the network
        try {
            // if this was a delegation operation
            // the lsig object would contian the signature
            SignedTransaction stx = Account.signLogicsigTransaction(lsig, tx);
            // Msgpack encode the signed transaction
            byte[] encodedTxBytes = Encoder.encodeToMsgPack(stx);
            TransactionID id = algodApiInstance.rawTransaction(encodedTxBytes);
            System.out.println("Successfully sent tx with 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());
        }

    }

}[]>[]>

Using Teal with the Python SDK

The Python example below uses the hex dump version of the compiled TEAL program to load it up and use it in a delegated signature Transaction. The comments in the example discuss how to use either an escrow contract account or a Multisig account delegation LogicSig. The Python SDK README also contains a more detailed example of how to do a multi-signature account delegation. Additionally, each SDK repository will contain tests files that may also be helpful in understanding the APIs.

from algosdk import algod, transaction, account, mnemonic
  
try:
	# Get the teal program bytes
	# This can be done by hexdumping the compiled
	# TEAL program. This program contains
	# int 0 , which always returns false
	program = b"\x01\x20\x01\x00\x22"  

	# Create a LogicSig object
	# if you want to pass parameters 
	# use code similar to:
	# arg1 = (123).to_bytes(8, 'big')
	# args = [ b"abc", arg1 ]
	# lsig = transaction.LogicSig(program, args)
	lsig = transaction.LogicSig(program)

	#Recover the account that is wanting to delegate signature
	passphrase = "young pear hard disorder execute trim upper alone jewel service mango resemble mansion emerge fabric jungle gesture yellow power mouse insect month kiss ability hurt";
	sk = mnemonic.to_private_key(passphrase)
	addr = account.address_from_private_key(sk)
	print( "Address of Sender/Delgator: " + addr )

	# This example is for delegating a signture authority
	# If this were an escrow example you would not need
	# the sign operation here
	# If you want to delegate a multisig account you
	# would use code similar to:
	# private_key_1, account_1 = account.generate_account()
    # private_key_2, account_2 = account.generate_account()
    # msig = transaction.Multisig(1, 2, [account_1, account_2])
    # lsig = transaction.LogicSig(program)
    # lsig.sign(private_key_1, msig)
    # lsig.append_to_multisig(private_key_2)
	lsig.sign(sk)

	# create an algod client
	algod_token = "61bddc5e84ed1ea3f8e9143a70da8fbe3478ae5e06caa52064332b09d158bb70"
	algod_address = "http://localhost:8081"
	receiver = "MCCJX23EXH6XSEGAN4WTQ62JHWEINDN5M2GIZ3H4LC7YJGCOAQKNARZ6RY"
	acl = algod.AlgodClient(algod_token, algod_address)

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

	# create a transaction
	txn = transaction.PaymentTxn(addr, fee, last_round, last_round+100, gh, receiver, amount)
	# Create the LogicSigTransaction with delegated LogicSig
	lstx = transaction.LogicSigTransaction(txn, lsig)

	# send raw LogicSigTransaction to network
	txid = acl.send_transaction(lstx)
	print("Transaction ID: " + txid )
except Exception as e:
    print(e)

Using Teal with the Go SDK

The Go example below uses the base64 version of the compiled TEAL program to load it up and use in an escrow contract Transaction. The comments discuss how to use either an account or multisig account delegation LogicSig as well. The Go SDK README also contains a more detailed example of how to do a multisignature account delegation. Additionally each SDK repository will contain tests files that may also be helpful in understanding the APIs.

package main

import (
	"fmt"
	"encoding/base64"

	"golang.org/x/crypto/ed25519"

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


)
// This example creates an escrow contract account
func main() {
	// CHANGE ME
	const algodAddress = "http://localhost:8080"
	const algodToken = "61bddc5e84ed1ea3f8e9143a70da8fbe3478ae5e06caa52064332b09d158bb70"
	//Blank values as we are creating an escrow account
	var sk ed25519.PrivateKey
	var ma crypto.MultisigAccount

	// Using a int 0 program meaning it will always fail a logic check
	// Dump compiled teal program to base64
	// cat p.teal.tok | base64 and then
	program, err :=  base64.StdEncoding.DecodeString("ASABACI=")
	
	// Setting the args blank
	// If you need parameters you can allocate space and set the values
	// eg args = make([][]byte, 2)
	// args[0] = make([]byte, 3)
	// args[0][0] = 'a' etc
	var args [][]byte

	// Next we create a LogicSig using blank private key
	// and blank multisig account because we are creating
	// a escrow contract account
	lsig, err := crypto.MakeLogicSig(program, args, sk, ma)
	addr := crypto.LogicSigAddress(lsig).String()
	fmt.Printf("Escrow Address: %s\n" , addr )
	
	//Setup a transaction as normal
	const receiver = "47YPQTIGQEO7T4Y4RWDYWEKV6RTR2UNBQXBABEEGM72ESWDQNCQ52OPASU"
	const fee = 1000
	const amount = 200000
	var note []byte

	// Create an algod client
	algodClient, err := algod.MakeClient(algodAddress, algodToken)
	if err != nil {
		fmt.Printf("failed to make algod client: %s\n", err)
		return
	}	
	// Get suggested params for the transaction
	txParams, err := algodClient.SuggestedParams()
    if err != nil {
            fmt.Printf("error getting suggested tx params: %s\n", err)
            return
    }

	// Make transaction
	genID := txParams.GenesisID
	genHash := txParams.GenesisHash
	tx, err := transaction.MakePaymentTxnWithFlatFee(
		addr, receiver, fee, amount, txParams.LastRound, (txParams.LastRound + 1000),
		note, "", genID, genHash )

	// Sign the transaction with the created LogicSignature
	// If we were delegating a signature or multisignature 
	// we would need to use non black values in the MakeLogicSig
	// call. for example:
	// addr1, err := types.DecodeAddress("DN7MBMCL5JQ3PFUQS7TMX5AH4EEKOBJVDUF4TCV6WERATKFLQF4MQUPZTA")
	// addr2, err := types.DecodeAddress("BFRTECKTOOE7A5LHCF3TTEOH2A7BW46IYT2SX5VP6ANKEXHZYJY77SJTVM")
	// mn1 := "auction inquiry lava second expand liberty glass involve ginger illness length room item discover ahead table doctor term tackle cement bonus profit right above catch"
	// sk1, err := mnemonic.ToPrivateKey(mn1)
	// mn2 := "since during average anxiety protect cherry club long lawsuit loan expand embark forum theory winter park twenty ball kangaroo cram burst board host ability left"
	// sk2, err := mnemonic.ToPrivateKey(mn2)
	// ma, err := crypto.MultisigAccountWithParams(1, 2, []types.Address{
	//  	addr1,
	//  	addr2,
	// })	
	// lsig, err := crypto.MakeLogicSig(program, args, sk1, ma)
	// err = crypto.AppendMultisigToLogicSig(&lsig, sk2)
	txid, stx, err := crypto.SignLogicsigTransaction(lsig, tx)
	if err != nil {
		fmt.Printf("Signing failed with %v", err)
		return
	}
	fmt.Printf("Signed tx: %v\n", txid)

	// Submit the raw transaction as normal
	transactionID, err := algodClient.SendRawTransaction(stx)
	if err != nil {
		fmt.Printf("Sending failed with %v\n", err)
	}
	fmt.Printf("Transaction ID: %v\n", transactionID)

}