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 CounterThis 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 --allWhen generating all wrappers, use --output-dir to choose a directory. --output is only for a single contract because it names one file.
Precompiled .boc contracts can also have wrappers when their contract section points types to a Tolk interface file:
[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 --testThe 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 incontract { incomingMessages: ... }.counter.sendAny(from, body, config)— sends a custom internal body cell.counter.sendExternal{MessageName}(...)— one method per external incoming message type declared incontract { incomingExternal: ... }; these methods returnExternalSendResult.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.
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 typedfromStorage()initializer; without it, the initializer falls back to an untyped form.incomingMessages: ...enables typedsend{MessageName}helpers; without it, only the genericsendAny()internal-message helper is generated.incomingExternal: ...enablessendExternal{MessageName}helpers andsendAnyExternal().
Storage aliases and workchains
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:
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():
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 testnetSee 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 CounterGenerate a TypeScript wrapper
Pass --ts to emit a TypeScript wrapper:
acton wrapper Counter --tsThis 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:
[wrappers.tolk]
output-dir = "wrappers"
generate-test = true
test-output-dir = "tests"
[wrappers.typescript]
output-dir = "wrappers-ts"Override any of these fields for one contract by nesting the same tables under its contract entry:
[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