Asentum

Build on Asentum

Deploy Your First Contract

Estimated read time: 10 minutes

Prerequisites

  • Node.js 20+ installed
  • An Asentum wallet — see Wallets & Accounts
  • Some testnet ASE for gas (grab some from the testnet faucet)
  • A text editor — VS Code, Vim, anything you like writing JavaScript in

Write the contract

An Asentum smart contract is plain JavaScript: a script whose last expression is an object literal. No compiler. No DSL. No new syntax. Save the following as counter.js:

// The last expression is an object: its methods are the contract.
({
  // init does not run at deploy. Call it once, right after.
  init() {
    assert(!storage.has('owner'), 'already initialized');
    storage.set('owner', msg.sender);
    storage.set('count', '0');
  },

  increment() {
    // Storage holds strings: convert to BigInt for math, back to a string to store.
    const next = BigInt(storage.get('count')) + 1n;
    storage.set('count', next.toString());
    return next.toString();
  },

  reset() {
    assert(msg.sender === storage.get('owner'), 'unauthorized');
    storage.set('count', '0');
  },

  get() {
    return storage.get('count') || '0';
  },
})

That's the entire contract. Note: state lives in storage, which stores strings only, so the count is kept as a decimal string and read back with BigInt(). msg.sender is the caller, and this is not available in methods. The contract runs inside a Hardened JavaScript (SES) sandbox: it can't touch the network, the filesystem, the clock, or random sources. It's just data and logic.

Test it locally

Paste the contract into the IDE to deploy and call it on testnet from the browser, or run it in memory with the VM package and Vitest as shown in Testing Contracts.

Deploy to testnet

asentum deploy counter.js --from <account> --init-args '[]'

The CLI signs the deploy transaction with your account, broadcasts it, then sends the init call (with the arguments from --init-args) and prints the contract's ase1 address once both are confirmed. Leave out --init-args to deploy without calling init; you can call it later with asentum call.

Your contract is now immutable. The source you just deployed is what runs forever, unless you explicitly built in a proxy pattern with a configurable upgrade authority.

Call your contract

From the SDK:

import { AsentumClient, AsentumContract } from '@asentum/sdk';

const client = new AsentumClient('https://testnet.asentum.com');
const counter = new AsentumContract(client, 'ase1...your-contract');

// Mutating call (signs a transaction with a connected wallet)
await (await counter.connect(wallet).send('increment')).wait();

// Read-only call (no signature, no gas)
const current = await counter.view('get');
console.log('Counter is now', current);   // a string, e.g. "1"

Cross-contract calls use the E(address).method() syntax. Calls execute synchronously and return the callee's value directly. A call-stack guard blocks reentrancy: if the target tries to call back into a contract already on the stack, the call reverts. From your application code (not from another contract), the SDK handles this transparently.

Verify the source

Verification on Asentum is free, automatic, and trivial. Because contracts deploy as plain JavaScript source (not bytecode), verification is just a hash compare:

hash(submitted_source) == deployed_code_hash

The block explorer shows your contract source directly with syntax highlighting, comments, everything you wrote. Anyone can hash the file locally with any BLAKE3 implementation and confirm it matches the deployed code.

Next steps