Docs
Building

Tolk wrappers

Learn how to generate Tolk wrappers and use them in tests and scripts

acton wrapper generates a typed Tolk wrapper from a contract's compiler ABI. The wrapper exposes methods to create, deploy, send messages to, and call get methods on the contract — the same API works in both tests and scripts.

Available since: Acton 1.2

Reuse generated wrappers through the Studio workflow: local emulator tests, scripts connected to a simulator network, then testnet and mainnet. The --net option selects the destination network.

Generate a Tolk wrapper

Run acton wrapper with the contract name from Acton.toml:

acton wrapper Counter

This writes a Counter.gen.tolk wrapper to wrappers/ by default. The acton wrapper does not require a prior acton build run.

Generate wrappers for every contract in Acton.toml at once:

acton wrapper --all

When generating all wrappers, use --output-dir to choose a directory. --output is only for a single contract because it names one file.

Available since: Acton 1.1

Precompiled .boc contracts can also have wrappers when their contract section points types to a Tolk interface file:

Acton.toml
[contracts.Precompiled]
src = "contracts/Precompiled.boc"
types = "contracts/Precompiled.types.tolk"

Acton reads deployable code from the BoC and reads the ABI from Precompiled.types.tolk. A BoC contract without types is skipped by acton wrapper --all, and acton wrapper Precompiled reports that types is required. See Precompiled BoC contracts for the build and wrapper workflow.

Pass --test to also emit a runnable test stub alongside the wrapper:

acton wrapper Counter --test

The stub is written to tests/Counter.test.tolk and contains a setupTest() helper with an example test case ready to extend.

Wrapper file structure

The generated file provides:

  • Counter.fromStorage(storage) — initializes contract state from a storage struct instance and calculates the deployment address.
  • counter.deploy(from, config) — deploys the contract.
  • counter.send{MessageName}(from, ...) — one method per internal incoming message type declared in contract { incomingMessages: ... }.
  • counter.sendAny(from, body, config) — sends a custom internal body cell.
  • counter.sendExternal{MessageName}(...) — one method per external incoming message type declared in contract { incomingExternal: ... }; these methods return ExternalSendResult.
  • counter.sendAnyExternal(body) — sends a custom external-in body when the contract declares external incoming messages.
  • counter.{getMethodName}() — one method per declared get method.

In local emulation, ExternalSendResult.isAccepted() reports whether the contract accepted the external-in message.

Available since: Acton 1.2

After a network broadcast, use waitForFirstTransaction() or waitForTrace() instead: successful submission does not prove contract acceptance, so isAccepted() exits with an error.

Fine tune wrapper generation with the contract { ... } header in the contract entrypoint file:

  • storage: ... enables the typed fromStorage() initializer; without it, the initializer falls back to an untyped form.
  • incomingMessages: ... enables typed send{MessageName} helpers; without it, only the generic sendAny() internal-message helper is generated.
  • incomingExternal: ... enables sendExternal{MessageName} helpers and sendAnyExternal().

Storage aliases and workchains

Available since: Acton 1.2

Tolk wrappers accept union aliases as storage types. Generated test stubs use the corresponding storage types and imports.

fromStorage(storage, toShard, workchain) accepts an optional workchain after toShard, defaulting to BASECHAIN. For masterchain deployment, use Counter.fromStorage(storage, null, MASTERCHAIN). Deployments preserve the selected workchain and shard settings.

Wrapper names and default filenames use the PascalCase contract ID from Acton.toml, independent of the source filename and display-name.

Use a wrapper in a Tolk test

Import the wrapper and any types it references, then create and deploy the contract:

tests/Counter.test.tolk
import "@wrappers/Counter.gen"
import "@contracts/types"
import "@acton/emulation/testing"
import "@acton/testing/expect"

get fun `test increase`() {
    val deployer = testing.treasury("deployer");

    val contract = Counter.fromStorage({ id: 0, counter: 0 });
    val deployResult = contract.deploy(deployer.address, { value: grams("0.05") });
    expect(deployResult).toHaveSuccessfulDeploy({ to: contract.address });

    val sendResult = contract.sendIncreaseCounter(deployer.address, 5);
    expect(sendResult).toHaveTransaction({ success: true });

    expect(contract.currentCounter()).toEqual(5);
}

See the testing guides for more.

Use a wrapper in a Tolk script

Replace testing.treasury() with scripts.wallet():

scripts/deploy.tolk
import "@wrappers/Counter.gen"
import "@contracts/types"
// Replaces @acton/emulation/testing:
import "@acton/emulation/scripts"

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

    val contract = Counter.fromStorage({ id: 0, counter: 0 });
    val result = contract.deploy(deployer.address, { value: grams("0.05") });
    result.waitForFirstTransaction();

    println("Deployed to {}", contract.address);
}

Run and test locally first, then broadcast to testnet with --net:

acton script scripts/deploy.tolk
acton script scripts/deploy.tolk --net testnet

See the scripting guides for more.

Regenerate after contract changes

Regenerate the wrapper whenever the contract's storage struct, accepted messages, or get-methods change:

acton wrapper Counter

Generate a TypeScript wrapper

Pass --ts to emit a TypeScript wrapper:

acton wrapper Counter --ts

This writes a Counter.gen.ts wrapper to wrappers-ts/ by default.

Node.js, npm, and npx must be available in the PATH.

See the dApps development guide for working with TypeScript wrappers.

Configure wrapper defaults

Set per-project defaults in Acton.toml:

Acton.toml
[wrappers.tolk]
output-dir = "wrappers"
generate-test = true
test-output-dir = "tests"

[wrappers.typescript]
output-dir = "wrappers-ts"
Available since: Acton 1.2

Override any of these fields for one contract by nesting the same tables under its contract entry:

Acton.toml
[contracts.Counter.wrappers.tolk]
output-dir = "generated/counter"
generate-test = false

[contracts.Counter.wrappers.typescript]
output-dir = "app/src/wrappers/counter"

Acton resolves each field independently, so omitted per-contract fields inherit the project defaults. CLI output and test options still have the highest priority. acton wrapper --all applies the resulting settings separately to each contract.

See the build reference for all available fields.

See also

Last updated on

On this page