---
slug: 75-network
title: Synsema Network (L1)
description: The Synsema chain — an Avalanche L1 (chain id 7960, SYN as gas) that is a public registry of agents — from Synsema. Access token in one command, the faucet, registering an agent, reading the registry, verifying a payment without trusting anyone, the AgentRegistry contract, the explorer API and the gotchas of the chain.
example_ids: []
---

# Synsema Network (L1)

[Synsema Network](https://synsema.io) is an Avalanche L1 whose first job is to be a **public
registry of agents**: for each agent, the hash of its program, the address that controls it, the
hash of the capabilities it declares, the attestation measurement of the machine it runs on, and
the Merkle roots of its audit log. Checking an agent means reading its record, not trusting whoever
runs it. On top, an open EVM: payments, tokens, contracts. Gas is paid in the native token, `SYN`.

The chain does not run agents; agents run anywhere (your machine, a server, the
[platform](74-platform), a TEE) and use the chain through the EVM builtins of
[Blockchain](38-blockchain).

**Today it is a devnet**, at [devnet.synsema.io](https://devnet.synsema.io): the state can be reset
and SYN on it has no value. Everything on this page runs against it.

| | |
|---|---|
| Chain id | `7960` (`0x1f18`) |
| Native token | `SYN`, 18 decimals |
| RPC | `https://devnet.synsema.io/<token>/rpc` |
| Agent registry | `0x9124Ac7F5Ff9bA48aed29c78198b59a1Ba6732eF` |
| Explorer | [devnet.synsema.io/explorer](https://devnet.synsema.io/explorer) |
| EVM | up to Cancun (compile with `evm_version = "cancun"`) |

## Access: a token, a key, some SYN

The RPC wants a token in its path. Get one — no sign-up, 10 per address per hour, 600 requests per
minute each:

```sh
curl -s -X POST https://devnet.synsema.io/token
```

The answer carries the token, the RPC URL and the line for your `.env`. Then a key of your own —
any 32 random bytes — and its address:

```sh
openssl rand -hex 32
```

```text
# .env, next to your programs (Synsema reads it and never prints a secret)
L1_RPC=https://devnet.synsema.io/<token>/rpc
MY_KEY=<the 64 hex characters>
```

```synsema
-- address.syn
require secret("MY_KEY")
print(eth_address(secret("MY_KEY")))
```

The faucet sends 100 SYN to an address, once an hour per address:

```sh
curl -s -X POST https://devnet.synsema.io/<token>/faucet \
  -H 'content-type: application/json' -d '{"address": "0x…"}'
```

A wallet (MetaMask, Rabby) takes the same values: RPC URL with your token, chain id `7960`,
symbol `SYN`. The [home page](https://devnet.synsema.io) has a button that does the three steps and
adds the network to your wallet.

## Register an agent

`agent.syn` is the program being registered (any Synsema program). Every value that moves money is
written out: nothing is signed with a default you did not see.

```synsema
-- register.syn: synsema run register.syn
require env("L1_RPC")
require secret("MY_KEY")
require sign("MY_KEY")
require net("devnet.synsema.io")
require file.read("agent.syn")

let url be env("L1_RPC")
let registry be "0x9124Ac7F5Ff9bA48aed29c78198b59a1Ba6732eF"
let k be secret("MY_KEY")
let me be eth_address(k)

-- the record: program, capabilities, environment, agent card
let program_hash be sha256(read_file("agent.syn"))
let caps_hash be sha256(canonical_json(["net"]))
let measurement be int_to_bytes(0, 32)
let uri be "https://example.org/.well-known/agent-card.json"
let data be abi_encode("register(bytes32,bytes32,bytes32,string)", [program_hash, caps_hash, measurement, uri])

-- build, sign, send, wait
let fees be eth_fee_history(url)
let tx be tx_eip1559({"chain_id": 7960, "nonce": eth_nonce(url, me), "to": registry, "value": 0,
    "gas": eth_estimate_gas(url, {"from": me, "to": registry, "data": data}) * 2,
    "max_fee": fees["base_fee"] * 2 + fees["priority"], "max_priority": fees["priority"], "data": data})
let hash be eth_send_raw(url, tx_eip1559_raw(tx, secp256k1_sign(tx["digest"], k)))
let receipt be eth_wait_receipt(url, hash, 1, 60)
assert(receipt != nothing and receipt["status"] == 1, "the registration did not go through")

let n be abi_decode("uint256", eth_call(url, {"to": registry, "data": abi_encode("count()", [])}))[0]
print(`registered as agent {n - 1}, tx {hash}`)
```

What goes in each field:

| Field | Value |
|---|---|
| `programHash` | `sha256` of the program: the `.syn`, or the WASM module that embeds it, or any artifact of an agent written in another language |
| `capsHash` | `sha256(canonical_json(<the require lines>))` — the ceiling of what the agent may do. `0x00…00` if the agent declares nothing |
| `measurement` | The attestation measurement of the enclave it runs in ([Attestation](24-attestation)); zero without a TEE |
| `agentURI` | Where the agent describes itself (its Agent Card, [Agent identity](46-agent-identity)). The chain does not check it |

The explorer marks every agent with what it declares and proves: *capabilities declared / not
declared*, *attested / not attested*.

## Read the registry

Reading needs no key and no SYN:

```synsema
require env("L1_RPC")
require net("devnet.synsema.io")

let url be env("L1_RPC")
let registry be "0x9124Ac7F5Ff9bA48aed29c78198b59a1Ba6732eF"
task call(sig, args)
    give eth_call(url, {"to": registry, "data": abi_encode(sig, args)})

let n be abi_decode("uint256", call("count()", []))[0]
print(`{n} agents on chain {eth_chain_id(url)}`)
let a be abi_decode("(address,bytes32,bytes32,bytes32,string,uint64)", call("get(uint256)", [0]))
print(`agent 0: controller {a[0]}, card {a[4]}`)
```

Without a token, the explorer's JSON API answers the same questions: `GET /api/agents`,
`/api/agent/<id>`, `/api/tx/<hash>`, `/api/address/<0x…>`, `/api/blocks`, `/api/tokens`, described in
[`/openapi.json`](https://devnet.synsema.io/openapi.json).

## Verify a payment without trusting anyone

A `200` from an app does not prove a payment. The receipt on the chain does. This program answers
"did this hash pay exactly this amount to this address, and is it final?":

```synsema
-- paid.syn: synsema run paid.syn -- <hash> <payee>
require env("L1_RPC")
require net("devnet.synsema.io")

task hex_int(s)
    let h be slice(s, 2)
    when length(h) % 2 == 1
        set h to "0" + h
    give bytes_to_int(bytes(h, "hex"))

task paid(hash, payee, amount_wei)
    let r be eth_receipt(env("L1_RPC"), hash)
    when r == nothing or r["status"] != 1
        give false
    let t be eth_rpc(env("L1_RPC"), "eth_getTransactionByHash", [hash])
    give lower(t["to"]) == lower(payee) and hex_int(t["value"]) == amount_wei

print(paid(args()[0], args()[1], 100 * 1000000000000000000))
```

On Avalanche an accepted block is final — there are no reorganizations — so "included" means
"cannot be undone". For people, the explorer's [verify page](https://devnet.synsema.io/verify) does
the same and has a button that asks the node directly and compares.

## The `AgentRegistry` contract

| Function | Who |
|---|---|
| `register(bytes32 programHash, bytes32 capsHash, bytes32 measurement, string agentURI) → uint256 id` | anyone |
| `anchor(uint256 id, uint64 seq, bytes32 root)` | the controller; `seq` must be the last one + 1 (no gaps, no rewrites) |
| `count() → uint256`, `get(uint256 id)`, `programHashOf(uint256 id)` | read |
| `lastSeq(uint256 id)`, `lastRoot(uint256 id)` | read |

Events: `Registered(uint256 indexed id, address indexed owner, bytes32 programHash, string agentURI)`
and `Anchored(uint256 indexed id, uint64 seq, bytes32 root)`.

## Tokens and contracts

Anyone with SYN can deploy contracts; the explorer finds ERC-20 tokens by their `Transfer` events.
A Synsema program cannot create a contract yet (`tx_eip1559` requires `to`): deploy with Foundry and
call it from Synsema.

```sh
forge create --broadcast --rpc-url "$L1_RPC" --private-key "$MY_KEY" src/MyToken.sol:MyToken
```

## Gotchas

- **Fees:** the base fee is 25 gwei and the suggested tip follows recent transactions, so it can be
  larger than twice the base. Use `max_fee = base_fee * 2 + priority`; with `base_fee * 2` alone,
  `tx_eip1559` refuses (`max_priority is greater than max_fee`).
- **Blocks only with transactions.** A height that does not move means the chain is idle.
- **Recent state only.** The node prunes: `eth_call` against an old block answers
  `missing trie node`. History is complete in the explorer.
- **Big integers from text:** `number()` returns a float and loses digits past 2⁵³ — build wei
  amounts with integer arithmetic (`100 * 1000000000000000000`), not from a parsed string.
- **Hex:** `bytes(s, "hex")` wants no `0x`; `eth_rpc` returns everything with it — `slice(s, 2)`.
