The itxn
namespace exposes types for constructing inner transactions. There is a factory method for each transaction type which accepts an object containing fields specific to the transaction type. The factories then return a *ItxnParams
object where *
is the transaction type (eg. PaymentItxnParams
). The params object has a submit
to submit the transaction immediately, a set
method to make further updates to the fields, and a copy
method to clone the params object.
To submit multiple transactions in a group - use the itxn.submitGroup
function.
import { itxn, Global, log } from '@algorandfoundation/algorand-typescript'
const assetParams = itxn.assetConfig({
total: 1000,
assetName: 'AST1',
unitName: 'unit',
decimals: 3,
manager: Global.currentApplicationAddress,
reserve: Global.currentApplicationAddress,
})
const asset1_txn = assetParams.submit()
log(asset1_txn.createdAsset.id)
Both the submitGroup
and params.submit()
functions return a *InnerTxn
object per input params object which allow you to read application logs or created asset/application ids. There are restrictions on accessing these properties which come from the current AVM implementation. The restrictions are detailed below.
The *ItxnParams
objects cannot be passed between subroutines, or stored in arrays or application state. This is because they contain up to 20 fields each with many of the fields being of variable length. Storing this object would require encoding it to binary and would be very expensive and inefficient.
Submitting dynamic group sizes with submitGroup
is not supported as the AVM is quite restrictive in how transaction results are accessed. gitxn op codes require transaction indexes to be referenced with a compile time constant value and this is obviously not possible with dynamic group sizes. An alternative API may be offered in the future which allows dynamic group sizes with the caveat of not having access to the transaction results.
If your contract needs to deploy other contracts then it's likely you will need access to the compiled approval and clear state programs. The compile
method takes a contract class and returns the compiled byte code along with some basic schema information.
import { itxn, compile } from '@algorandfoundation/algorand-typescript'
import { encodeArc4, methodSelector } from '@algorandfoundation/algorand-typescript/arc4'
const compiled = compile(Hello)
const helloApp = itxn
.applicationCall({
appArgs: [methodSelector(Hello.prototype.create), encodeArc4('hello')],
approvalProgram: compiled.approvalProgram,
clearStateProgram: compiled.clearStateProgram,
globalNumBytes: compiled.globalBytes,
})
.submit().createdApp
If the contract you are compiling makes use of template variables - these will need to be resolved to a constant value.
const compiled = compile(HelloTemplate, { templateVars: { GREETING: 'hey' } })
Assuming the contract you wish to compile extends the ARC4 Contract
type, you can make use of compileArc4
to produce a contract proxy object that makes it easy to invoke application methods with
compile time type safety.
import { assert, itxn } from '@algorandfoundation/algorand-typescript'
import { compileArc4 } from '@algorandfoundation/algorand-typescript/arc4'
const compiled = compileArc4(Hello)
const app = compiled.call.create({
args: ['hello'],
}).itxn.createdApp
const result = compiled.call.greet({
args: ['world'],
appId: app,
}).returnValue
assert(result === 'hello world')
The proxy will automatically include approval and clear state program bytes + schema properties from the compiled contract, but these can also be overridden if required.
If your use case does not require deploying another contract, and instead you are just calling methods then the abiCall
method will allow you to do this in a strongly typed manner provided you have at bare minimum a compatible stub implementation of the target contract.
A sample stub implementation
export abstract class HelloStubbed extends Contract {
// Make sure the abi decorator matches the target implementation
@abimethod()
greet(name: string): string {
// Stub implementations don't need method bodies, as long as the type information is correct
err('stub only')
}
}
Invocation using the stub
const result3 = abiCall(HelloStubbed.prototype.greet, {
appId: app,
args: ['stubbed'],
}).returnValue
assert(result3 === 'hello stubbed')