Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ton-blockchain/acton/llms.txt

Use this file to discover all available pages before exploring further.

Acton’s emulation layer makes it possible to run the full lifecycle of a TON smart contract — deploy, send messages, inspect state — without touching a real network. The same code can also target testnet or mainnet by adding --net to the CLI invocation. Four modules collaborate to provide this capability: testing provides the emulated blockchain context (treasury accounts, time control, snapshots); network is the unified message-sending layer that works in both emulation and broadcast modes; scripts supplies the wallet-based primitives needed by deployment scripts; and config exposes the blockchain configuration parameters (gas prices, storage fees, forward fees) so that tests can simulate different network conditions.
Use testing.xxx methods only in test files (*.test.tolk). Use scripts.xxx methods only in script files (scripts/*.tolk). net.xxx and config types are shared between both.

@acton/emulation/testing

This module provides the test-only API for controlling the emulated blockchain environment.
import "@acton/emulation/testing"

C7 Register Access

fun testing.getC7OutsideContract(): tuple
fun testing.setC7OutsideContract(c7: tuple): void
Read or write the TVM control register C7 from outside a contract execution context. Useful for inspecting or modifying the context tuple in tests.

Treasury

In tests you never connect a real wallet. Instead, call testing.treasury to get an unlimited source of TON:
fun testing.treasury(name: string): Treasury

struct Treasury {
    address: address
}
Calling testing.treasury("deployer") twice with the same name always returns the same address.

Time Control

fun testing.setNow(now: uint32): void
fun testing.getNow(): uint32
setNow synchronises both the emulated world state and the current VM context’s C7 unixtime slot, so blockchain.now() immediately returns the mocked value.

Account Inspection

fun testing.getAccountState(addr: address): TlbAccountInfo?
fun testing.getAccountBalance(of: address): coins
fun testing.getAccountStorageFee(addr: address, seconds: int): coins?
fun testing.getShardAccount(addr: address): TlbShardAccount?
fun testing.setShardAccount(addr: address, account: TlbShardAccount?): void
fun testing.isDeployed(addr: address): bool

Funding

// Top up an address with TON (tests only — for testnet use `acton wallet airdrop`)
fun testing.topUp(to: address, amount: coins): void

Snapshots

fun testing.saveSnapshot(pathToJsonFile: string): bool
fun testing.loadSnapshot(pathToJsonFile: string): bool

Blockchain Configuration

fun testing.getConfig(): BlockchainConfigMap
fun testing.setConfig(config: BlockchainConfigMap): bool

Step-by-Step Execution

For complex cascades where you need to inspect partial traces:
fun testing.createTraceIterationCursor(from: address, message: OutMessage): TxCursor

struct TxCursor { id: int }

fun TxCursor.isDone(self): bool
fun TxCursor.executeN(self, n: int): SendResultList
fun TxCursor.executeTill<Msg>(self, params: SearchParams = {}): SendResultList
fun TxCursor.executeAllRemaining(self): SendResultList
fun TxCursor.close(self): void

Single-Step Execution

// Execute exactly one transaction without processing its out messages
fun testing.processSingleTraceStep(from: address, message: OutMessage): SendResult

Tick / Tock Transactions

fun testing.runTickTock(onAccount: address, isTock: bool): SendResultList

Library Registration

fun testing.loadAndRegisterLibrary(hash: string): bool
fun testing.registerLibrary(libCell: cell): void

Out Actions

// Returns out actions from the control register C5 at that moment
fun testing.outActions(): OutActionList

@acton/emulation/network

The network module is the heart of Acton’s emulation: it routes messages either to the local emulator or, when running with --net, to a real network.
import "@acton/emulation/network"

Sending Internal Messages

fun net.send(from: address, message: OutMessage): SendResultList
In emulation mode this recursively drains the full transaction queue and returns every resulting SendResult. In broadcast mode it routes through the real network when from matches a loaded wallet.

Sending External Messages

fun net.createExternalMessage<TBody>(
    dest: address,
    body: TBody,
    stateInit: StateInit? = null,
    src: any_address? = null,
): ExternalInMessage

fun net.sendExternal(msg: ExternalInMessage): ExternalSendResult
ExternalSendResult captures both the success path (full SendResultList) and the failure path (emulator error metadata):
struct ExternalSendResult {
    transactions: SendResultList?
    error: ExternalSendError?
    destination: address
}

fun ExternalSendResult.isAccepted(self): bool
fun ExternalSendResult.unwrap(self, location: string = ...): SendResultList
fun ExternalSendResult.at(self, index: int, location: string = ...): SendResult

Running Get Methods

fun net.runGetMethod<Ret>(addr: address, idOrName: int | string, args: array<unknown> = []): Ret
// Single-return get method
val balance = net.runGetMethod<coins>(wallet.address, "get_balance");

// Get method with arguments
val walletAddr = net.runGetMethod<address>(
    minter.address,
    "get_wallet_address",
    [ownerAddress],
);

// Structured return type
val data = net.runGetMethod<JettonDataReply>(minter.address, "get_jetton_data");

SendResult and SendResultList

struct SendResult {
    tx: Cell<TlbTransaction>
    lt: int
    childTxs: ChildTxsIds
    parentLt: int?
    outActions: Cell<TlbOutList>
    outMessages: OutMessages
    gasUsed: int
    externals: ExtOutList
}

type SendResultList = BigArray<SendResult>

fun SendResultList.at(self, index: int): SendResult
fun SendResultList.giveName(self, nameForUI: string): void
fun SendResultList.hideTraceFromUi(self): void
fun SendResultList.findTransaction<Msg>(self, params: SearchParams = {}): TlbTransaction?
fun SendResultList.findExternalOutMessage<TBody>(self, params: ExternalOutSearchParams = {}): ...

Broadcast Mode Helpers

fun net.isBroadcasting(): bool
fun net.enableBroadcast(): void
fun net.disableBroadcast(): void

Utility

fun randomAddress(name: string? = null, wc: int = BASECHAIN): address
fun net.registerAddress(addr: address, name: string): void
fun net.registerCodeCell(code: cell, name: string): void
fun net.loadLibrary(hash: string): cell?

@acton/emulation/scripts

Scripts interact with real wallets. This module provides the counterparts to the testing-only methods.
import "@acton/emulation/scripts"

Wallet

fun scripts.wallet(name: string): ActonWallet

struct ActonWallet {
    address: address
}

fun ActonWallet.toKeyPair(self): KeyPair
fun ActonWallet.privateKey(self): int
fun ActonWallet.publicKey(self): int
fun ActonWallet.walletId(self): int
fun ActonWallet.sign(self, data: cell): slice
fun ActonWallet.rawSign(self, data: int): slice
Without --net the wallet behaves like an emulated treasury. With --net it resolves to the real wallet from wallets.toml or global.wallets.toml.

Account Queries

fun scripts.fetchAccountState(addr: address): TlbAccountInfo?
fun scripts.fetchAccountBalance(of: address): coins
fun scripts.fetchAccountStorageFee(addr: address, seconds: int): coins?
fun scripts.fetchShardAccount(addr: address): TlbShardAccount?
fun scripts.isContractDeployed(addr: address): bool
fun scripts.fetchConfig(): BlockchainConfigMap

Deployment Script Example

import "@acton/emulation/scripts"
import "@acton/emulation/network"
import "@acton/build"
import "@acton/io"

fun main() {
    val deployer = scripts.wallet("deployer");

    val counter = Counter.fromStorage({
        id: 8,
        counter: 0,
    });

    println("Deploying Counter to {}", counter.address);

    val result = net.send(deployer.address, counter.deploy(deployer.address, ton("0.05")));
    result.waitForFirstTransaction();

    println("Deployed at {}", counter.address);

    val balance = scripts.fetchAccountBalance(counter.address);
    println("Balance: {:ton}", balance);
}

@acton/emulation/config

The config module exposes blockchain configuration parameters (gas prices, storage prices, message forward prices) in a type-safe way.
import "@acton/emulation/config"

BlockchainConfigMap

type BlockchainConfigMap = map<uint32, cell>

// Low-level raw access
fun BlockchainConfigMap.getParamRaw(self, index: uint32): cell
fun BlockchainConfigMap.setParamRaw(mutate self, index: uint32, data: cell): void

// Global version (Param 8)
fun BlockchainConfigMap.getGlobalVersion(self): GlobalVersion
fun BlockchainConfigMap.setGlobalVersion(mutate self, version: GlobalVersion): void

// Storage prices (Param 18)
fun BlockchainConfigMap.getStoragePrices(self): StoragePricesDict
fun BlockchainConfigMap.setStoragePrices(mutate self, prices: StoragePricesDict): void

// Gas prices (Param 20 = masterchain, Param 21 = basechain)
fun BlockchainConfigMap.getGasPrices(self, chainType: int): GasPrices
fun BlockchainConfigMap.setGasPrices(mutate self, prices: GasPrices, chainType: int): void

// Message forward prices (Param 24 = masterchain, Param 25 = basechain)
fun BlockchainConfigMap.getMsgForwardPrices(self, chainType: int): MsgForwardPrices
fun BlockchainConfigMap.setMsgForwardPrices(mutate self, prices: MsgForwardPrices, chainType: int): void

// Precompiled contracts (Param 45)
fun BlockchainConfigMap.getPrecompiledContractsConfig(self): PrecompiledContractsConfig
fun BlockchainConfigMap.setPrecompiledContractsConfig(mutate self, config: PrecompiledContractsConfig): void

Key Structs

struct (0xc4) GlobalVersion {
    version: uint32
    capabilities: uint64
}

struct (0xcc) StoragePrices {
    initialUnixTime: uint32
    bitPrice: uint64
    cellPrice: uint64
    masterchainBitPrice: uint64
    masterchainCellPrice: uint64
}

struct (0xd1) GasPrices {
    flatGasLimit: uint64
    flatGasPrice: uint64
    other: GasPricesExtended
}

struct (0xea) MsgForwardPrices {
    lumpPrice: uint64
    bitPrice: uint64
    cellPrice: uint64
    ihrPriceFactor: uint32
    firstFrac: uint16
    nextFrac: uint16
}

Modifying Config in Tests

Config changes are staged in a local BlockchainConfigMap and only committed to the emulator when you call testing.setConfig(config):
import "@acton/emulation/testing"
import "@acton/emulation/config"
import "@acton/testing/expect"

get fun `test zero-gas environment`() {
    var config = testing.getConfig();

    var storagePrices = config.getStoragePrices();
    storagePrices.setInitial(StoragePrices {
        initialUnixTime: 0,
        bitPrice: 0,
        cellPrice: 0,
        masterchainBitPrice: 0,
        masterchainCellPrice: 0,
    });
    config.setStoragePrices(storagePrices);

    val ok = testing.setConfig(config);
    expect(ok).toBeTrue();

    // subsequent transactions now pay zero storage fees
}

Build docs developers (and LLMs) love