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 statesdk.kv_put/sdk.kv_get— persistent key-value storagesdk.kv_increment— atomic numeric operationssdk.ret— return values to the calleramount_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:
- Module loading — validates and instantiates the Wasm binary
- Symbol registration — exposes exported functions as callable methods
- Transaction routing — matches incoming calls to the appropriate entry point
- State isolation — provides each contract with its own KV namespace
- 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.tswraps 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.shautomates compilation with optimization flags- Host imports in
ex/lib/api/api_contract.exprovide the blockchain bridge - Deployment uses
Testnet.deployandTestnet.callcommands against the compiled.wasmfile
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →