# How to Interact with Amadeus Protocol Smart Contracts: Complete Developer Guide

> Learn how to interact with Amadeus Protocol smart contracts using the Elixir node REPL or JSON-RPC API. This guide covers WASM binaries and trainer key pairs for developers.

- Repository: [Amadeus Protocol/node](https://github.com/amadeusprotocol/node)
- Tags: how-to-guide
- Published: 2026-08-20

---

**Amadeus Protocol smart contracts are deployed and called through the Elixir node's REPL or JSON-RPC API, using AssemblyScript-compiled WASM binaries signed by a trainer key pair.**

The Amadeus Protocol node (`amadeusprotocol/node`) provides a unified interface for smart contract interaction. Contracts are written in **AssemblyScript**, compiled to **WebAssembly (`.wasm`)**, and executed by the node's WebAssembly runtime. Whether you prefer the interactive Elixir REPL or standard HTTP JSON-RPC calls, the underlying transaction flow remains identical: construct a signed transaction, submit it to the transaction pool, and await block inclusion.

## Deploying Smart Contracts to the Testnet

The `Testnet` module in [`ex/lib/misc/testnet.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/misc/testnet.ex) provides the primary interface for contract deployment during development and testing.

### Prerequisites: Trainer Key Configuration

Before deploying, your node must have a trainer key pair configured in the application environment:

```elixir

# These are automatically set when running a local testnet node

pk = Application.fetch_env!(:ama, :trainer_pk)  # public key

sk = Application.fetch_env!(:ama, :trainer_sk)  # private key (signing key)

```

The trainer key serves as the default account for gas fees and contract ownership on local testnets.

### Deploying a Compiled WASM Contract

Use `Testnet.deploy/1` to upload a compiled `.wasm` file:

```elixir

# Absolute or relative path to the compiled contract

contract_path = "/path/to/node/contract_samples/assemblyscript/counter.wasm"
{:ok, contract_address} = Testnet.deploy(contract_path)

```

The deploy function:
- Loads the WASM binary from disk
- Constructs a **deploy transaction** (defined in [`ex/lib/consensus/models/tx.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/consensus/models/tx.ex))
- Signs it with the trainer private key
- Submits to [`ex/lib/node/txpool.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/node/txpool.ex) for block inclusion
- Returns the **contract address** for subsequent calls

Sample contracts are located at `contract_samples/assemblyscript/` (e.g., `counter.wasm`), providing ready-to-deploy examples for testing.

## Calling Contract Methods

Once deployed, interact with contracts via `Testnet.call/4` or the JSON-RPC equivalent.

### REPL-Based Contract Calls

The four-parameter `call/4` function in [`ex/lib/misc/testnet.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/misc/testnet.ex) follows the signature:

```elixir
Testnet.call(private_key, public_key, function_name, args_list)

```

Example: interacting with the counter contract

```elixir

# Read initial state

{:ok, value} = Testnet.call(sk, pk, "get", [])
IO.puts("Current counter: #{value}")

# => "0"

# Execute state-changing call (increment by 3)

{:ok, tx_hash} = Testnet.call(sk, pk, "increment", ["3"])

# Verify the change

{:ok, new_value} = Testnet.call(sk, pk, "get", [])
IO.puts("New counter: #{new_value}")

# => "3"

```

Key implementation details from the source:
- **Transaction construction**: `Testnet.call/4` builds a `Tx` struct as defined in [`ex/lib/consensus/models/tx.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/consensus/models/tx.ex)
- **Signing**: Uses the provided `private_key` to cryptographically sign the transaction
- **Submission**: Pushes to the mempool via [`ex/lib/node/txpool.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/node/txpool.ex)
- **Result decoding**: Automatically decodes the contract's return value from the execution trace

### HTTP JSON-RPC Contract Calls

For external clients, the `ApiContract` handler in [`ex/lib/api/api_contract.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/api/api_contract.ex) exposes identical functionality:

```bash
curl -X POST https://nodes.amadeus.bot/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "contract.call",
    "params": {
      "signer": "0x<private_key_hex>",
      "contract": "0x<contract_address>",
      "function": "increment",
      "args": ["5"]
    },
    "id": 1
  }'

```

Response format:

```json
{
  "jsonrpc": "2.0",
  "result": {
    "tx_hash": "0x...",
    "return_value": "8"
  },
  "id": 1
}

```

The RPC handler constructs the same internal transaction structure as the REPL, ensuring behavioral parity between interfaces.

## Transaction Lifecycle and Architecture

Understanding the flow helps debug failed calls and optimize integration timing.

### Step 1: Transaction Structure ([`ex/lib/consensus/models/tx.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/consensus/models/tx.ex))

A contract call transaction contains:
- **From**: caller's public key
- **To**: contract address (zero address for deployments)
- **Data**: ABI-encoded function selector and arguments
- **Nonce**: sequence number preventing replay attacks
- **Signature**: ECDSA signature over all fields

### Step 2: Mempool Admission ([`ex/lib/node/txpool.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/node/txpool.ex))

Submitted transactions enter the node's transaction pool where they are:
- Validated for signature correctness
- Checked for sufficient balance (gas fees)
- Ordered by nonce and fee priority

### Step 3: Block Inclusion and Execution

Validators include pooled transactions in new blocks. The WASM runtime loads the contract's bytecode, executes the specified function with provided arguments, and persists state changes.

### Step 4: Return Value Propagation

For read-only calls, the result returns immediately. For state-changing calls, the response includes the **transaction hash**; polling or WebSocket subscription confirms finality.

## Key Source Files for Contract Interaction

| File | Purpose | Critical Functions |
|------|---------|------------------|
| [`ex/lib/misc/testnet.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/misc/testnet.ex) | REPL helper for deployment and calls | `deploy/1`, `call/4` |
| [`ex/lib/consensus/models/tx.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/consensus/models/tx.ex) | Transaction data structure | `Tx` struct, signing logic |
| [`ex/lib/node/txpool.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/node/txpool.ex) | Transaction mempool management | `add_transaction/1` |
| [`ex/lib/api/api_contract.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/api/api_contract.ex) | JSON-RPC contract endpoint | `contract.call` handler |
| `contract_samples/assemblyscript/` | Reference WASM contracts | `counter.wasm`, source `.ts` files |

## Common Integration Patterns

### Pattern 1: Automated Deployment Scripts

```elixir

# script/deploy.exs

defmodule Deployer do
  def run(contract_path) do
    sk = Application.fetch_env!(:ama, :trainer_sk)
    pk = Application.fetch_env!(:ama, :trainer_pk)
    
    {:ok, addr} = Testnet.deploy(contract_path)
    IO.puts("Deployed to #{addr}")
    
    # Initialize with constructor call if needed

    Testnet.call(sk, pk, "init", ["param1", "param2"])
  end
end

Deployer.run(System.argv() |> List.first())

```

Run with: `mix run script/deploy.exs path/to/contract.wasm`

### Pattern 2: Multi-Client RPC Integration

```python

# Python example using identical RPC interface

import requests, json

def call_contract(sk_hex, contract_addr, fn_name, args):
    payload = {
        "jsonrpc": "2.0",
        "method": "contract.call",
        "params": {
            "signer": sk_hex,
            "contract": contract_addr,
            "function": fn_name,
            "args": args
        },
        "id": 1
    }
    r = requests.post("https://nodes.amadeus.bot/rpc", json=payload)
    return r.json()["result"]

```

## Summary

- **Amadeus Protocol smart contract interaction** centers on the `Testnet` module for REPL workflows and `ApiContract` for HTTP JSON-RPC clients
- **AssemblyScript → WASM compilation** produces deployable binaries stored in `contract_samples/assemblyscript/`
- **`Testnet.deploy/1`** handles contract creation; **`Testnet.call/4`** handles method invocation with automatic signing
- **Transaction flow** traverses [`tx.ex`](https://github.com/amadeusprotocol/node/blob/main/tx.ex) (structure) → [`txpool.ex`](https://github.com/amadeusprotocol/node/blob/main/txpool.ex) (admission) → block inclusion → WASM execution
- **Identical semantics** across REPL and RPC interfaces enable flexible integration from any programming environment

## Frequently Asked Questions

### How do I obtain a trainer key pair for testnet deployment?

The trainer keys are automatically generated when starting a local testnet node. They are stored in the application environment under `:trainer_pk` and `:trainer_sk`. For persistent deployments, export these values from your node's configuration or environment variables before starting the application.

### What format should contract arguments use in Testnet.call?

Arguments are passed as **strings in a list**, regardless of the target type. The contract's AssemblyScript wrapper handles type conversion. For example, pass `["123"]` for a `u64` parameter or `["0xabc..."]` for address types. The WASM runtime deserializes these according to the function's expected signature.

### Can I interact with contracts without running a full node?

Yes. Public RPC endpoints like `https://nodes.amadeus.bot/rpc` expose the same `contract.call` and `contract.deploy` methods. You only need a valid trainer key (or any account with testnet tokens) to sign transactions; no local Elixir node is required for interaction.

### Where are deployed contract addresses stored?

Contract addresses are returned by `Testnet.deploy/1` and should be persisted by your application. The node does not maintain a registry of your deployments. Track the hex address in your deployment scripts, environment variables, or database for subsequent `call` operations.