TEAL Compile and Disassemble
Description
Section titled “Description”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
Section titled “Prerequisites”- LocalNet running (via
algokit localnet start)
Run This Example
Section titled “Run This Example”From the repository root:
cd examplesnpm run example algod_client/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 10invalid_opcodeint 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 10int`
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 999int 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)})Other examples in Algod Client
Section titled “Other examples in Algod Client”- Node Health and Status
- Version and Genesis Information
- Ledger Supply Information
- Account Information
- Transaction Parameters
- Send and Confirm Transaction
- Pending Transactions
- Block Data
- Asset Information
- Application Information
- Application Boxes
- TEAL Compile and Disassemble
- Transaction Simulation
- Ledger State Deltas
- Transaction Proof
- Light Block Header Proof
- State Proof
- DevMode Timestamp Offset
- Sync Round Management