How to Deploy a WASM Smart Contract on Amadeus Protocol: A Complete Guide

Deploy a WASM smart contract on Amadeus Protocol by reading the compiled .wasm binary, submitting it via Testnet.deploy/2 or the JSON-RPC API, and letting the node validate and store the bytecode under your account.

Amadeus Protocol executes smart contracts compiled to WebAssembly (WASM), providing deterministic gas metering and fast startup through the Wasmer runtime. This guide walks through the deployment flow, validation rules, and interaction patterns based on the official amadeusprotocol/node source code.

Prerequisites: Compiling Your Contract

Before deployment, compile your contract to a .wasm binary. The repository includes AssemblyScript examples for reference:


# Build the sample counter contract

./contract_samples/assemblyscript/build_and_validate.sh

This produces counter.wasm, which you will deploy in the next step. The source for this example lives at [contract_samples/assemblyscript/0_counter.ts](https://github.com/amadeusprotocol/node/blob/main/contract_samples/assemblyscript/0_counter.ts) in the repository.

Deploying via Elixir: The Testnet.deploy/2 Method

The simplest approach uses the Elixir helper module. In ex/lib/misc/testnet.ex#L16-L24, the Testnet.deploy/2 function handles file I/O and transaction construction:


# Load your trainer credentials from application config

iex> pk = Application.fetch_env!(:ama, :trainer_pk)
iex> sk = Application.fetch_env!(:ama, :trainer_sk)

# Deploy the WASM contract

iex> Testnet.deploy("/path/to/counter.wasm")
:ok

Under the hood, this function:

  1. Reads the WASM file with File.read!/1
  2. Constructs a "Contract.deploy" transaction
  3. Broadcasts it to the Amadeus network

Deploying via JSON-RPC: Direct API Access

For non-Elixir clients, use the JSON-RPC endpoint with a base64-encoded payload:

{
  "method": "contract_deploy",
  "params": {
    "wasm": "<base64-encoded .wasm file>",
    "init_func": null
  },
  "jsonrpc": "2.0",
  "id": 1
}

The node responds with a transaction hash. Once confirmed, the contract becomes addressable by your account's public key.

Node-Side Validation: How Amadeus Secures WASM Contracts

Every deployment triggers contract_validate, implemented across two layers for security and performance.

Rust NIF Entry Point

In ex/native/rdb/src/lib.rs#L819-L823, the contract_validate function receives the bytecode and forwards it to the consensus validator:

// Simplified flow: Elixir NIF -> Rust validation -> Wasmer checks
contract_validate(bytecode) -> consensus_apply::contract_validate(bytecode)

Module Limits and DoS Prevention

The check_module_limits function in ex/native/rdb/src/consensus/bic/wasm.rs#L648-L710 enforces strict boundaries:

  • Binary size: WASM_MAX_BINARY_SIZE hard limit
  • Function count: Maximum exported and internal functions
  • Global/Export/Import counts: Prevents resource exhaustion
  • Data section rules: Restricts memory initialization patterns

Validation aborts the entire transaction if any limit is breached, preventing malformed or malicious modules from reaching storage.

Gas Metering Configuration

Execution costs are predictable. The constant COST_PER_OP_WASM in ex/native/rdb/src/consensus/bic/protocol.rs#L50 defines gas per WASM operation, consumed by the metering middleware during runtime.

Calling Deployed Contracts

After deployment, interact with your contract using Testnet.call/4:


# Call the "increment" function with argument "2"

iex> Testnet.call(sk, pk, "increment", ["2"])
{:ok, result}  # Returns the updated counter value

The runtime flow in ex/native/rdb/src/consensus/bic/wasm.rs#L931-L959 handles:

  1. Retrieving stored bytecode from RocksDB (key: "account:<pk>:attribute:bytecode")
  2. Instantiating a Wasmer module with the singlepass compiler
  3. Injecting arguments and executing the requested exported function
  4. Returning results with gas consumption

Wasmer Runtime Architecture

Amadeus Protocol builds on Wasmer 7.1.0 with two critical middleware layers:

  • Singlepass compiler: Fast compilation without optimizations, ensuring deterministic execution time
  • Metering middleware: Injects gas accounting operations into every WASM instruction

This combination provides both performance and predictable resource limits for smart contract execution.

Summary

  • Compile your contract to WASM using AssemblyScript, Rust, or any WASM-targeting language
  • Deploy via Testnet.deploy/2 in Elixir or the contract_deploy JSON-RPC method
  • Validate automatically through contract_validate with strict module limits
  • Store bytecode under your account key in RocksDB after passing validation
  • Call functions through Testnet.call/4 or equivalent RPC, with Wasmer handling execution and gas metering

Frequently Asked Questions

What WASM compilers are compatible with Amadeus Protocol?

Any compiler producing valid WebAssembly 1.0+ output works, including AssemblyScript, Rust (cargo-contract), TinyGo, and C/C++ via Emscripten. The critical requirement is passing the check_module_limits validation in [wasm.rs](https://github.com/amadeusprotocol/node/blob/main/ex/native/rdb/src/consensus/bic/wasm.rs), which restricts features like multi-value returns and bulk memory operations if they exceed configured bounds.

Why did my deployment transaction fail with a validation error?

Amadeus rejects WASM modules exceeding size limits, function counts, global counts, or import/export limits defined in wasm.rs#L648-710. Run the build_and_validate.sh script from the contract samples to check your binary against these constraints before deployment.

How is gas calculated for WASM contract execution?

Each WASM instruction consumes COST_PER_OP_WASM gas units as defined in protocol.rs#L50. The metering middleware instruments your bytecode at load time, injecting accounting operations that track consumption during call_contract execution in wasm.rs#L931-959.

Can I upgrade a contract after deployment?

The source analysis reveals no native upgrade mechanism in the validation or storage layers. Contracts are immutable once stored under "account:<pk>:attribute:bytecode". To deploy updated logic, submit a new Contract.deploy transaction from the same account—this overwrites the stored bytecode with your new version.

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 →