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_messagingpackage ID for the network you point at. The canonical deployments are listed inrelayer/.env.example:- Testnet:
0xba8a26d42bc8b5e5caf4dac2a0f7544128d5dd9b4614af88eec1311ade11de79 - Mainnet:
0x541840ae7df705d1c6329c22415ed61f9140a18b79b13c1c9dc7415b115c1ba8 - These are the sui-groups package IDs the relayer reads — confirm against
relayer/.env.exampleif it changes.
- Testnet:
Pick testnet for dev. Pointing your local relayer at the mainnet
GROUPS_PACKAGE_IDmeans it will sync against the live productionsui_groupspackage 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
# edit .env: set GROUPS_PACKAGE_ID (required), pick SUI_RPC_URL
Required env vars (from .env.example):
SUI_RPC_URL— Sui fullnode endpoint (defaults tohttps://fullnode.testnet.sui.io:443).GROUPS_PACKAGE_ID— sui-groups package on the target network.
Localnet: set
SUI_RPC_URLto the fullnode gRPC port:9000(e.g.http://127.0.0.1:9000), not:9124. Port:9124is the Consistent Store thatsui start --with-graphqlauto-enables; it doesn't implement checkpoint subscription and returns HTTP 404 "Operation is not implemented" onsubscribe_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=debugfor verbose).
Run with cargo
cargo run # binds :3000 by default
PORT=8080 cargo run # override port
RUST_LOG=debug cargo run # verbose logs
Health check:
curl http://localhost:3000/health_check
Run with Docker
docker compose up # foreground; reads .env automatically
docker compose up -d # detached
docker compose logs -f # follow logs
docker compose down # stop
Compose file: relayer/docker-compose.yml. Image build: relayer/Dockerfile.
Sanity check
The relayer is up when:
curl :3000/health_checkreturns 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_IDempty — the relayer will fail to start. Set it.- Membership sync not catching up — verify
SUI_RPC_URLsupports gRPC (testnet fullnode uses port 443; on localnet it's the fullnode gRPC port:9000, not the:9124consistent store), and thatGROUPS_PACKAGE_IDmatches 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
- Want to run with the chat-app and indexer? →
spin-up-e2e-stack. - Want to fork and extend (custom storage, auth, handlers)? →
develop-relayer.