Acton
Tutorial

Contract deployment

Learn how to deploy smart contracts

TODO: To be reworked. Some parts will go to deploy.mdx, and this page will become a part of a single cohesive tutorial.

In Acton, there is no dedicated acton deploy command. Instead, it uses Tolk scripts for deployment.

This approach provides maximum flexibility. Real-world contracts often require complex initialization data—such as dictionaries for metadata, encoded cell structures, or specific initial state configurations—which are cumbersome or impossible to pass via command-line arguments. By using scripts, you can utilize the full power of the Tolk language to prepare deployment data, calculate initial state, and manage the deployment flow programmatically.

Prerequisites

Before deploying to the real network, you need to configure a wallet in your wallets.toml (or global configuration).

wallets.toml
[wallets.deployer]
kind = "v5r1"
workchain = 0
keys = { mnemonic = "word1 word2 word3 ... word24" }

See the Setting up wallets guide for detailed instructions on configuring wallets safely.

Writing a Deploy Script

A deploy script is a standard Tolk script that interacts with the network. It typically involves three steps:

  1. Loading the deployer wallet.
  2. Preparing the contract's initial state and code.
  3. Sending the deployment transaction.

Here is an example of a script that deploys a simple Counter contract:

scripts/deploy.tolk
import "@acton/io"
import "@acton/emulation/network"
import "@acton/emulation/scripts"
import "@acton/build"

import "@wrappers/Counter"       // Import your contract wrapper
import "@contracts/types"        // Import types if needed

fun main() {
    // 1. Load the configured wallet (searches wallets.toml and global wallets)
    val deployer = scripts.wallet("deployer");

    // 2. Prepare the contract
    // We create the contract instance locally with its initial state
    val counter = Counter.fromStorage({
        id: 123,       // Unique ID to randomize address
        counter: 0,    // Initial counter value
    });

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

    // 3. Deploy the contract
    // This sends a transaction from the deployer wallet with the stateInit
    val result = counter.deploy(deployer.address, { value: ton("0.05") });

    // Wait for the transaction to be confirmed on the blockchain
    if (!result.wait()) {
        return;
    }

    println("Deployment complete: {}", counter.address);
    println("On-chain counter is {}", counter.currentCounter());
}

Complex Deployments

For more complex contracts like Jettons, you can construct dictionaries and other data structures directly in the script:

// ... imports ...
import "@acton/emulation/scripts"

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

    // Construct Jetton metadata
    val content = buildOnchainMetadata({
        name: "MyJetton",
        symbol: "JET",
        description: "A cool jetton on TON",
        image: "https://example.com/icon.png",
    });

    val minter = JettonMinter.fromStorage({
        totalSupply: 1_000_000_000,
        adminAddress: deployer.address,
        content: content,
        jettonWalletCode: build("JettonWallet"),
    });

    // Deploy
    minter.deploy(deployer.address, { value: ton("0.05") }).wait();

    println("Jetton deployed at {}", minter.address);
}

Running the Deployment

To execute your deployment script on the real blockchain, use the acton script command with --net <network>.

Executing scripts in real blockchain is often called "broadcasting", opposed to local "emulation".

Testnet

acton script scripts/deploy.tolk --net testnet

In broadcast mode, read-only calls such as counter.currentCounter() use the same network by default, so deploy scripts can verify on-chain state without an extra --fork-net.

To deploy to testnet, your wallet must have testnet TONs. You can get them for free with acton wallet airdrop command or from the Testnet Faucet.

Mainnet

To deploy to the mainnet, specify the network flag:

acton script scripts/deploy.tolk --net mainnet

When deploying to mainnet, real value is transferred. Ensure your contract logic is tested and audit-ready.

Localnet

Deployment to a local network allows you to get closer to real networks than tests, but at the same time not depend on the external network and remain completely local.

acton script scripts/deploy.tolk --net localnet

Before deploying, make sure you have launched the localnet.

Using API Keys

For faster and more reliable interactions, especially on mainnet, it is recommended to use an API key from TonCenter.

TONCENTER_MAINNET_API_KEY=YOUR_API_KEY acton script scripts/deploy.tolk --net mainnet

Set TONCENTER_MAINNET_API_KEY for mainnet flows and TONCENTER_TESTNET_API_KEY for testnet flows. Acton reads the matching env variable automatically for the built-in TonCenter-backed networks.

Local Testing

One of the biggest advantages of using scripts is that you can test the exact same deployment logic locally before spending money.

Simply run the script without --net:

acton script scripts/deploy.tolk

In this mode, scripts.wallet("deployer") creates a virtual wallet, and the deployment happens in the local emulator. This allows you to verify that your state initialization and logic are correct before spending any money. The same script can still call wrapper getters after deploy: in emulation they read emulator state, and in broadcast mode they read the selected real network.

Last updated on

On this page