Skip to content

TEAL Compile and Disassemble

← Back to Algod Client

This example demonstrates how to compile TEAL source code to bytecode and disassemble bytecode back to TEAL using the AlgodClient methods:

  • tealCompile(source, options?) - Compile TEAL source to bytecode
  • tealDisassemble(bytecode) - Disassemble bytecode back to TEAL
  • LocalNet running (via algokit localnet start)

From the repository root:

Terminal window
cd examples
npm run example algod_client/12-teal-compile.ts

View source on GitHub

12-teal-compile.ts
/**
* Example: TEAL Compile and Disassemble
*
* This example demonstrates how to compile TEAL source code to bytecode and
* disassemble bytecode back to TEAL using the AlgodClient methods:
* - tealCompile(source, options?) - Compile TEAL source to bytecode
* - tealDisassemble(bytecode) - Disassemble bytecode back to TEAL
*
* Prerequisites:
* - LocalNet running (via `algokit localnet start`)
*/
import {
createAlgodClient,
loadTealSource,
printError,
printHeader,
printInfo,
printStep,
printSuccess,
} from '../shared/utils.js'
async function main() {
printHeader('TEAL Compile and Disassemble Example')
// Create an Algod client connected to LocalNet
const algod = createAlgodClient()
// =========================================================================
// Step 1: Compile a Simple Approval Program
// =========================================================================
printStep(1, 'Compiling a simple approval program')
// A minimal approval program that always succeeds
const simpleSource = loadTealSource('simple-approve.teal')
try {
const compiled = await algod.tealCompile(simpleSource)
printSuccess('Compilation successful!')
printInfo('')
printInfo('Compilation Result:')
printInfo(` Hash: ${compiled.hash}`)
printInfo(` (base32 SHA512/256 of program bytes, Address-style)`)
printInfo(` Result: ${compiled.result}`)
printInfo(` (base64 encoded bytecode)`)
printInfo('')
// Decode bytecode to show the raw bytes
const bytecode = Buffer.from(compiled.result, 'base64')
printInfo('Bytecode Details:')
printInfo(` Size: ${bytecode.length} bytes`)
printInfo(` Hex: ${bytecode.toString('hex')}`)
printInfo('')
printInfo('The hash can be used as a Logic Signature address')
printInfo('The bytecode (result) is what gets stored on-chain')
printInfo('')
} catch (error) {
printError(`Compilation failed: ${error instanceof Error ? error.message : String(error)}`)
process.exit(1)
}
// =========================================================================
// Step 2: Compile a More Complex Program
// =========================================================================
printStep(2, 'Compiling a more complex approval program')
// A program that checks sender and approves specific transaction types
const complexSource = loadTealSource('complex-approve.teal')
try {
const compiled = await algod.tealCompile(complexSource)
printSuccess('Complex program compiled successfully!')
printInfo('')
printInfo('Compilation Result:')
printInfo(` Hash: ${compiled.hash}`)
printInfo(` Result: ${compiled.result}`)
printInfo('')
const bytecode = Buffer.from(compiled.result, 'base64')
printInfo('Bytecode Details:')
printInfo(` Size: ${bytecode.length} bytes`)
printInfo(` Hex: ${bytecode.toString('hex')}`)
printInfo('')
printInfo('Complex programs compile to larger bytecode')
printInfo('')
} catch (error) {
printError(`Compilation failed: ${error instanceof Error ? error.message : String(error)}`)
process.exit(1)
}
// =========================================================================
// Step 3: Compile with Sourcemap Option
// =========================================================================
printStep(3, 'Compiling with sourcemap option')
// Program with multiple lines for meaningful sourcemap
const sourcemapSource = loadTealSource('counter-init.teal')
try {
const compiled = await algod.tealCompile(sourcemapSource, { sourcemap: true })
printSuccess('Compilation with sourcemap successful!')
printInfo('')
printInfo('Compilation Result:')
printInfo(` Hash: ${compiled.hash}`)
printInfo(` Result: ${compiled.result}`)
printInfo('')
if (compiled.sourcemap) {
printInfo('Source Map:')
printInfo(` Version: ${compiled.sourcemap.version}`)
printInfo(` Sources: ${JSON.stringify(compiled.sourcemap.sources)}`)
printInfo(` Names: ${JSON.stringify(compiled.sourcemap.names)}`)
printInfo(` Mappings: ${compiled.sourcemap.mappings}`)
printInfo('')
printInfo('Sourcemaps enable debugging by mapping bytecode to source lines')
printInfo('The mappings string uses VLQ (Variable Length Quantity) encoding')
} else {
printInfo('Sourcemap was not returned (may depend on node configuration)')
}
printInfo('')
} catch (error) {
printError(`Compilation failed: ${error instanceof Error ? error.message : String(error)}`)
process.exit(1)
}
// =========================================================================
// Step 4: Disassemble Bytecode Back to TEAL
// =========================================================================
printStep(4, 'Disassembling bytecode back to TEAL')
try {
// First compile, then disassemble to show round-trip
const compiled = await algod.tealCompile(simpleSource)
const bytecode = new Uint8Array(Buffer.from(compiled.result, 'base64'))
printInfo('Original Source:')
printInfo(` ${simpleSource.split('\n').join('\n ')}`)
printInfo('')
const disassembled = await algod.tealDisassemble(bytecode)
printSuccess('Disassembly successful!')
printInfo('')
printInfo('Disassembled Output:')
printInfo(` ${disassembled.result.trim().split('\n').join('\n ')}`)
printInfo('')
printInfo('Disassembled output may differ from original (comments removed, labels renamed)')
printInfo('')
} catch (error) {
printError(`Disassembly failed: ${error instanceof Error ? error.message : String(error)}`)
process.exit(1)
}
// =========================================================================
// Step 5: Compare Original Source with Disassembled Output
// =========================================================================
printStep(5, 'Comparing original source with disassembled output')
try {
// Use the complex source for a more interesting comparison
const compiled = await algod.tealCompile(complexSource)
const bytecode = new Uint8Array(Buffer.from(compiled.result, 'base64'))
const disassembled = await algod.tealDisassemble(bytecode)
printInfo('Original Source:')
const originalLines = complexSource.trim().split('\n')
originalLines.forEach((line, i) => printInfo(` ${(i + 1).toString().padStart(2)}: ${line}`))
printInfo('')
printInfo('Disassembled Output:')
const disassembledLines = disassembled.result.trim().split('\n')
disassembledLines.forEach((line, i) => printInfo(` ${(i + 1).toString().padStart(2)}: ${line}`))
printInfo('')
printInfo('Key Differences:')
printInfo(' - Comments are removed during compilation')
printInfo(' - Labels are converted to numeric addresses')
printInfo(' - The semantic meaning remains identical')
printInfo('')
} catch (error) {
printError(`Comparison failed: ${error instanceof Error ? error.message : String(error)}`)
process.exit(1)
}
// =========================================================================
// Step 6: Handle Compilation Errors
// =========================================================================
printStep(6, 'Handling compilation errors for invalid TEAL')
// Invalid TEAL source - unknown opcode
const invalidSource1 = `#pragma version 10
invalid_opcode
int 1`
try {
printInfo('Attempting to compile invalid TEAL (unknown opcode):')
printInfo(` ${invalidSource1.split('\n').join('\n ')}`)
printInfo('')
await algod.tealCompile(invalidSource1)
printError('Expected compilation to fail but it succeeded')
} catch (error) {
printSuccess('Correctly caught compilation error!')
if (error instanceof Error) {
printInfo(` Error: ${error.message}`)
}
printInfo('')
}
// Invalid TEAL source - syntax error
const invalidSource2 = `#pragma version 10
int`
try {
printInfo('Attempting to compile invalid TEAL (missing operand):')
printInfo(` ${invalidSource2.split('\n').join('\n ')}`)
printInfo('')
await algod.tealCompile(invalidSource2)
printError('Expected compilation to fail but it succeeded')
} catch (error) {
printSuccess('Correctly caught syntax error!')
if (error instanceof Error) {
printInfo(` Error: ${error.message}`)
}
printInfo('')
}
// Invalid TEAL source - invalid version
const invalidSource3 = `#pragma version 999
int 1`
try {
printInfo('Attempting to compile invalid TEAL (invalid version):')
printInfo(` ${invalidSource3.split('\n').join('\n ')}`)
printInfo('')
await algod.tealCompile(invalidSource3)
printError('Expected compilation to fail but it succeeded')
} catch (error) {
printSuccess('Correctly caught version error!')
if (error instanceof Error) {
printInfo(` Error: ${error.message}`)
}
printInfo('')
}
printInfo('Always validate TEAL source before deployment')
printInfo('Compilation errors include line numbers and descriptions')
printInfo('')
// =========================================================================
// Step 7: Understanding Disassembly Behavior
// =========================================================================
printStep(7, 'Understanding disassembly behavior with various bytecode')
// The disassembler does best-effort interpretation of bytecode
// Even invalid patterns may produce some output
// Example 1: Bytecode with invalid version (version 0)
const invalidVersionBytecode = new Uint8Array([0x00, 0x00, 0x00])
printInfo('Disassembling bytecode with version 0:')
printInfo(` Bytes: ${Buffer.from(invalidVersionBytecode).toString('hex')}`)
try {
const result = await algod.tealDisassemble(invalidVersionBytecode)
printInfo(' Result:')
printInfo(` ${result.result.trim().split('\n').join('\n ')}`)
printInfo('Version 0 is disassembled but is not a valid TEAL version')
printInfo('')
} catch (error) {
printError(`Disassembly failed: ${error instanceof Error ? error.message : String(error)}`)
printInfo('')
}
// Example 2: Single byte (just version, no opcodes)
const minimalBytecode = new Uint8Array([0x0a]) // version 10
printInfo('Disassembling minimal bytecode (just version byte):')
printInfo(` Bytes: ${Buffer.from(minimalBytecode).toString('hex')}`)
try {
const result = await algod.tealDisassemble(minimalBytecode)
printInfo(' Result:')
printInfo(` ${result.result.trim().split('\n').join('\n ')}`)
printInfo('Minimal valid bytecode: version byte only')
printInfo('')
} catch (error) {
printError(`Disassembly failed: ${error instanceof Error ? error.message : String(error)}`)
printInfo('')
}
printInfo('The disassembler does best-effort interpretation')
printInfo('Always verify disassembled output matches expected behavior')
printInfo('')
// =========================================================================
// Step 8: Compile Different TEAL Versions
// =========================================================================
printStep(8, 'Compiling programs with different TEAL versions')
const versions = [6, 8, 10]
for (const version of versions) {
const source = `#pragma version ${version}
int 1`
try {
const compiled = await algod.tealCompile(source)
const bytecode = Buffer.from(compiled.result, 'base64')
printInfo(`TEAL Version ${version}:`)
printInfo(` Hash: ${compiled.hash}`)
printInfo(` Size: ${bytecode.length} bytes`)
printInfo(` Bytecode: ${bytecode.toString('hex')}`)
printInfo('')
} catch (error) {
printError(`Version ${version} failed: ${error instanceof Error ? error.message : String(error)}`)
}
}
printInfo('Different TEAL versions may produce different bytecode')
printInfo('Newer versions support more opcodes and features')
printInfo('')
// =========================================================================
// Summary
// =========================================================================
printHeader('Summary')
printInfo('This example demonstrated:')
printInfo(' 1. tealCompile(source) - Compile TEAL source code to bytecode')
printInfo(' 2. CompileResponse fields: hash (base32), result (base64 bytecode)')
printInfo(' 3. tealCompile(source, { sourcemap: true }) - Get source map for debugging')
printInfo(' 4. tealDisassemble(bytecode) - Convert bytecode back to TEAL')
printInfo(' 5. Comparing original source with disassembled output')
printInfo(' 6. Handling compilation errors for invalid TEAL')
printInfo(' 7. Handling disassembly errors for invalid bytecode')
printInfo(' 8. Compiling programs with different TEAL versions')
printInfo('')
printInfo('Key CompileResponse fields:')
printInfo(' - hash: base32 SHA512/256 of program bytes (Address-style)')
printInfo(' - result: base64 encoded bytecode')
printInfo(' - sourcemap?: { version, sources, names, mappings } (optional)')
printInfo('')
printInfo('Key DisassembleResponse fields:')
printInfo(' - result: Disassembled TEAL source code (string)')
printInfo('')
printInfo('Use cases:')
printInfo(' - Compile TEAL before deploying smart contracts')
printInfo(' - Get program hash for Logic Signature addresses')
printInfo(' - Debug bytecode by disassembling to readable TEAL')
printInfo(' - Validate TEAL syntax before deployment')
printInfo(' - Generate sourcemaps for debugging tools')
}
main().catch((error) => {
console.error('Fatal error:', error)
process.exit(1)
})