| name | spin-up-relayer |
| description | Use when the user wants to run the reference messaging relayer locally — cargo run, docker compose, configuring the .env file, picking testnet vs mainnet GROUPS_PACKAGE_ID. Trigger phrases - "run the relayer", "start the relayer locally", "spin up the relayer", "relayer cargo run", "relayer docker", "relayer .env", "messaging relayer setup". |
Spin up the relayer locally
The relayer is at relayer/ — a Rust axum service. Reference implementation; safe to run as-is for dev.
Prereqs
- Rust stable (toolchain pinned in
relayer/rust-toolchain.toml).
- A deployed
sui_stack_messaging package ID for the network you point at. The canonical deployments are listed in relayer/.env.example:
- Testnet:
0xba8a26d42bc8b5e5caf4dac2a0f7544128d5dd9b4614af88eec1311ade11de79
- Mainnet:
0x541840ae7df705d1c6329c22415ed61f9140a18b79b13c1c9dc7415b115c1ba8
- These are the sui-groups package IDs the relayer reads — confirm against
relayer/.env.example if it changes.
Pick testnet for dev. Pointing your local relayer at the mainnet GROUPS_PACKAGE_ID means it will sync against the live production sui_groups package and persist messages from any client that hits it. For dev work — first runs, debugging, integration tests, anything where you might restart or wipe state — use the testnet ID. Only switch to the mainnet ID when you're intentionally running against real production groups (which is a deployment decision, not a dev one).
Configure
cd relayer
cp .env.example .env
Required env vars (from .env.example):
SUI_RPC_URL — Sui fullnode endpoint (defaults to https://fullnode.testnet.sui.io:443).
GROUPS_PACKAGE_ID — sui-groups package on the target network.
Localnet: set SUI_RPC_URL to the fullnode gRPC port :9000 (e.g. http://127.0.0.1:9000), not :9124. Port :9124 is the Consistent Store that sui start --with-graphql auto-enables; it doesn't implement checkpoint subscription and returns HTTP 404 "Operation is not implemented" on subscribe_checkpoints, so membership sync never starts.
Optional (defaults shown in .env.example):
PORT (3000), REQUEST_TTL_SECONDS (900).
STORAGE_TYPE (memory), MEMBERSHIP_STORE_TYPE (memory).
WALRUS_PUBLISHER_URL, WALRUS_AGGREGATOR_URL, WALRUS_STORAGE_EPOCHS, WALRUS_SYNC_INTERVAL_SECS, WALRUS_SYNC_BATCH_SIZE, WALRUS_SYNC_MESSAGE_THRESHOLD.
RUST_LOG=messaging_relayer=info (use =debug for verbose).
Run with cargo
cargo run
PORT=8080 cargo run
RUST_LOG=debug cargo run
Health check:
curl http://localhost:3000/health_check
Run with Docker
docker compose up
docker compose up -d
docker compose logs -f
docker compose down
Compose file: relayer/docker-compose.yml. Image build: relayer/Dockerfile.
Sanity check
The relayer is up when:
curl :3000/health_check returns 200.
- Logs show membership-sync subscribed to the Sui gRPC checkpoint stream.
- The chat-app or another SDK client successfully posts a message and gets it back via GET.
Storage note
STORAGE_TYPE=memory means messages are lost on restart. Fine for dev. For persistent storage, see develop-relayer — implement the StorageAdapter trait.
What this relayer does
In one sentence: authenticates per-message wallet signatures against on-chain group membership, stores E2E-encrypted message payloads off-chain, and periodically archives them to Walrus. It never sees plaintext.
Full protocol: docs/sui-stack-messaging/Relayer.md and relayer/README.md. Postman collection: relayer/docs/messaging-relayer.postman_collection.json.
Common issues
GROUPS_PACKAGE_ID empty — the relayer will fail to start. Set it.
- Membership sync not catching up — verify
SUI_RPC_URL supports gRPC (testnet fullnode uses port 443; on localnet it's the fullnode gRPC port :9000, not the :9124 consistent store), and that GROUPS_PACKAGE_ID matches the network the RPC points to.
- Walrus calls failing — testnet Walrus endpoints are public but rate-limited; for sustained dev work, run your own publisher/aggregator.
Next steps