Recipes

Converting App Argument to Integer

All arguments passed to the application in the ApplicationCall transaction are converted to bytes. If you passed an integer and want to use it as integer in the contract, you have to convert it to integer using btoi opcode.

 1bytes input_as_bytes = Txn.ApplicationArgs[0]
 2int input_as_int = btoi(input_as_bytes)
 3
 4# Example: Total sum of all app arguments
 5int app_args_count = Txn.NumAppArgs
 6int total = 0
 7
 8for index in 0:app_args_count:
 9    total = total + btoi(Txn.ApplicationArgs[index])
10end

Opting in the application to an asset

 1int asset_id
 2
 3int is_opted_in
 4is_opted_in, _ = asset_holding_get(AssetBalance, Global.CurrentApplicationAddress, asset_id)
 5
 6if is_opted_in == 0:
 7    inner_txn:
 8        TypeEnum: Axfer
 9        Sender: Global.CurrentApplicationAddress
10        AssetReceiver: Global.CurrentApplicationAddress
11        AssetAmount: 0
12        XferAsset: asset_id
13        Fee: 0
14    end
15end

Inner app call

 1inner_txn:
 2    TypeEnum: Appl
 3    OnCompletion: NoOp
 4    ApplicationID: THE_APP_ID
 5    ApplicationArgs[0]: "arg1"
 6    ApplicationArgs[1]: "arg2"
 7    Accounts[0]: Txn.Sender
 8    Accounts[1]: Txn.Accounts[1]
 9    Fee: 0
10end

Calling another application with an inner transaction

 1inner_txn:
 2    TypeEnum: Appl
 3    OnCompletion: NoOp
 4    ApplicationID: THE_APP_ID
 5    ApplicationArgs[0]: "arg1"
 6    ApplicationArgs[1]: "arg2"
 7    Accounts[0]: Txn.Sender
 8    Accounts[1]: Txn.Accounts[1]
 9    Fee: 0
10end

Handling Integer Overflow

Converting integers to big-endian unsigned integers and using byte arithmetics allows handling integers up to 512 bits without overflow. Note that these b* and others have a higher opcode cost than the normal integer operators.

1const int MAX_INT_64 = 18446744073709551615
2
3# a and b are very big numbers and multiplication of them doesn't fit in to uint 64.
4int a = MAX_INT_64
5int b = MAX_INT_64 / 2
6
7bytes mul = itob(a) b* itob(b)
8bytes sum = itob(a) b+ itob(b)
9int result = btoi(mul b/ sum)

Optimizing the generated TEAL code partially

Teal allows using raw TEAL directly, see Inline Teal. Decreasing the size and computational cost using TEAL and custom stack management is possible.

Reformatting the Tealish code may result a small gain. Reducing the variable usage help you ascetically if you are on the limit of budget cost. Variable assignment generates store, and usages generates load opcodes. So, you can remove the variables used one time.

 1int a = get_int()
 2int b = get_int()
 3int c = get_int()
 4
 5int result = (a + b) + c
 6
 7# Dummy function
 8func get_int() int:
 9    return 2
10end
1int result = (get_int() + get_int()) + get_int()
2
3# Dummy function
4func get_int() int:
5    return 2
6end

Increasing the budget

The opcode budget of an application call is 700. Most TEAL Opcodes have a cost of 1 but some are much higher. For example b+ is 20 times more costly than b If the transaction group has multiple application calls, the budget is pooled. The details are explained in the Algorand Developer Documentation.

Similar to OpUp utility of PyTeal, you can increase the cost budget by adding another app call using inner transactions. Each app call adds an extra 700 to the budget.

increase_cost_budget creates and deletes an app with single transactions. This is the most portable and efficient way to achieve the goal.

 1func increase_cost_budget():
 2    inner_txn:
 3        TypeEnum: Appl
 4        OnCompletion: DeleteApplication
 5        ApprovalProgram: "\x06\x81\x01"
 6        ClearStateProgram: "\x06\x81\x01"
 7        Fee: 0
 8    end
 9    return
10end

Testing & Debugging

After compiling the Tealish code into TEAL, you can use all the testing, and debugging tools that are compatible with TEAL. Using Sandbox node for testing and developing as explained on Algorand Developer Documentation is also an option.

Algojig

AlgoJig is a development and testing jig for Algorand. It allows developers to run transactions and write tests starting from a known Algorand ledger state. It is suitable for testing all kinds of transactions, including application calls and logic signatures.”

Counter Prize and Auction example contracts implemented by Tealish contains unit-tests and they use AlgoJig.

Example:

 1        stxn = txn.sign(self.app_creator_sk)
 2
 3        block = self.ledger.eval_transactions(transactions=[stxn])
 4        block_txns = block[b"txns"]
 5
 6        self.assertEqual(len(block_txns), 1)
 7        txn = block_txns[0]
 8
 9        app_id = txn[b"apid"]
10        self.assertIsNotNone(app_id)
11
12        # check final state
13        final_global_state = self.ledger.get_global_state(
14            app_id=app_id,
15        )
16        self.assertDictEqual(
17            final_global_state,
18            {b"counter": 0},
19        )
20
21        # check delta
22        global_delta = txn[b"dt"][b"gd"]
23        self.assertDictEqual(
24            global_delta,
25            {b"counter": {b"at": 2}},
26        )