What Is AssemblyScript and How Is It Used for Amadeus Contracts?

AssemblyScript is a TypeScript-like language that compiles to WebAssembly, enabling Amadeus developers to write blockchain smart contracts with familiar syntax while producing fast, compact Wasm binaries.

The Amadeus protocol leverages AssemblyScript as its primary smart contract language. In the amadeusprotocol/node repository, contracts are authored in .ts files, compiled to .wasm modules, and executed within the node's WebAssembly runtime. This approach combines the ergonomics of TypeScript with the performance and determinism required for blockchain consensus.

Understanding AssemblyScript in the Amadeus Ecosystem

AssemblyScript strictly compiles a TypeScript subset to WebAssembly (Wasm), avoiding JavaScript's dynamic features in favor of static types and predictable memory layout. For Amadeus, this translates to contracts that are:

  • Deterministic — required for replicated state machines
  • Compact — small binary size reduces storage and bandwidth costs
  • Fast — near-native execution speed via Wasm runtime
  • Familiar — TypeScript syntax lowers the learning curve

The Amadeus node implements a host environment in Elixir (ex/lib/api/api_contract.ex) that exposes blockchain operations—logging, key-value storage, and cross-contract calls—as imports callable from Wasm modules.

The AssemblyScript SDK Architecture

Amadeus provides a dedicated SDK located at contract_samples/assemblyscript/sdk.ts that abstracts the low-level host imports into developer-friendly TypeScript functions.

Core SDK Components

Component Location Purpose
Host import wrappers sdk.ts Wrap import_log, import_kv_put, import_call, etc. with automatic encoding/decoding
Memory helpers sdk.ts memory_read_string, memory_read_bytes for argument extraction
Serialization utilities sdk.ts bToI64, coin_raw, b58 for binary data handling
Return mechanism sdk.ts sdk.ret() for passing results back to the caller

The SDK functions manage memory allocation, convert between AssemblyScript types and the node's binary interface, and ensure proper cleanup—shielding contract authors from Wasm's low-level details.

Writing and Compiling Amadeus Contracts

Step 1: Implement Contract Entry Points

A minimal contract defines exported functions that the node invokes. Here's the canonical counter example from contract_samples/assemblyscript/0_counter.ts:

import * as sdk from "./sdk";

export function init(): void {
  sdk.log("Init called during deployment of contract");
  sdk.kv_put("inited", "true");
}

export function get(): void {
  let cur_counter = sdk.bToI64(sdk.kv_get("the_counter"));
  sdk.ret(cur_counter);
}

export function increment(amount_ptr: i32): void {
  let amount = sdk.memory_read_string(amount_ptr);
  sdk.kv_increment("the_counter", amount);
  let incremented_counter = sdk.kv_increment("the_counter", 1);
  sdk.ret(incremented_counter);
}

Key patterns demonstrated:

  • init() — runs once at deployment, initializes state
  • sdk.kv_put / sdk.kv_get — persistent key-value storage
  • sdk.kv_increment — atomic numeric operations
  • sdk.ret — return values to the caller
  • amount_ptr: i32 — pointer-based argument passing (Wasm convention)

Step 2: Cross-Contract Calls

The same file shows how contracts invoke each other:

export function increment_another_counter(contract_ptr: i32): void {
  let contract = sdk.memory_read_bytes(contract_ptr);
  let incr_by = 3;
  sdk.log(`Calling increment on ${sdk.b58(contract)} by ${incr_by}`);
  let other_counter = sdk.call(contract, "increment", [sdk.b(incr_by)]);
  sdk.ret(other_counter);
}

This pattern uses sdk.call with the target contract address, method name, and serialized arguments array.

Step 3: Compile with the Build Script

The repository includes contract_samples/assemblyscript/build_and_validate.sh to handle compilation flags:


# From build_and_validate.sh

asc assembly/$1.ts \
  --target release \
  --use abort=doom \
  --runtime stub \
  --exportRuntime \
  -O3 \
  -o assembly/$1.wasm

This invokes the AssemblyScript compiler (asc) with optimizations enabled and the minimal runtime, producing the deployable Wasm binary.

Deploying and Executing Contracts

Once compiled, contracts interact with the Amadeus testnet through CLI commands shown in the repository README:


# Deploy the compiled Wasm

Testnet.deploy "/path/to/contract_samples/assemblyscript/counter.wasm"

# Query the current counter value

Testnet.call sk, pk, "get", []

# Increment by a specific amount

Testnet.call sk, pk, "increment", ["2"]

The node handles:

  1. Module loading — validates and instantiates the Wasm binary
  2. Symbol registration — exposes exported functions as callable methods
  3. Transaction routing — matches incoming calls to the appropriate entry point
  4. State isolation — provides each contract with its own KV namespace
  5. Gas metering — tracks execution cost for consensus

Host Import Implementation

The bridge between Wasm and the blockchain is implemented in ex/lib/api/api_contract.ex. Key imports available to AssemblyScript contracts include:

Import SDK Wrapper Function
import_log sdk.log Debug logging
import_kv_put sdk.kv_put / sdk.kv_increment Persistent storage writes
import_kv_get sdk.kv_get Storage reads
import_call sdk.call Cross-contract invocation
import_ret sdk.ret Return data to caller

These imports operate on linear memory shared between the Wasm runtime and the host, with the SDK handling pointer arithmetic and encoding.

Why AssemblyScript for Amadeus?

Compared to alternatives, the Amadeus AssemblyScript approach offers:

  • Familiar toolchain — npm-based, TypeScript-compatible IDE support
  • Deterministic output — same source always produces identical Wasm
  • Minimal overhead — no garbage collector in the default runtime, predictable performance
  • Small bundle size — contracts measured in kilobytes, not megabytes
  • Auditable binaries — Wasm is easier to formally verify than high-level bytecode

The b58 encoding utilities and raw byte operations in sdk.ts also reflect blockchain-native requirements without forcing developers into unfamiliar paradigms.

Summary

  • AssemblyScript compiles TypeScript to WebAssembly for Amadeus smart contracts
  • The SDK in sdk.ts wraps host imports for storage, logging, and cross-contract calls
  • Contracts export entry points (init, get, increment) that the node invokes via Wasm runtime
  • build_and_validate.sh automates compilation with optimization flags
  • Host imports in ex/lib/api/api_contract.ex provide the blockchain bridge
  • Deployment uses Testnet.deploy and Testnet.call commands against the compiled .wasm file

Frequently Asked Questions

What makes AssemblyScript different from regular TypeScript?

AssemblyScript is a strict subset of TypeScript that compiles directly to WebAssembly rather than JavaScript. It requires explicit types, lacks dynamic features like any, and produces standalone binary modules. For Amadeus, this ensures deterministic execution and eliminates JavaScript engine dependencies.

How does the Amadeus node execute AssemblyScript contracts?

The node loads the .wasm binary into a WebAssembly runtime, registers exported functions as callable contract methods, and invokes them when processing transactions. Host imports in ex/lib/api/api_contract.ex give contracts access to blockchain state and operations.

Can I use npm packages in Amadeus AssemblyScript contracts?

Only packages compatible with AssemblyScript's strict type system and standard library. Most npm packages targeting Node.js or browsers will not compile. The Amadeus SDK (sdk.ts) provides the primary dependencies needed for contract development.

Where can I find example Amadeus AssemblyScript contracts?

The repository includes contract_samples/assemblyscript/0_counter.ts, a complete example showing initialization, state management, arithmetic operations, and cross-contract calls. The build_and_validate.sh script demonstrates proper compilation flags.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →