zhell is a lightweight, high-performance gas station service for the Sui blockchain, built with Kotlin and Ktor. It allows authorized clients (via API Keys) to request gas sponsorship for their transactions, enabling "gasless" user experiences.
It is designed to be stateless and serverless-ready, using Google Cloud Firestore for API key management and Google Cloud Run for scalable deployment.
- Gas Sponsorship: Signs Sui transaction bytes with a sponsor key to pay for gas fees.
- API Key Management: Admin API to generate, validate, and revoke API keys.
- Secure Authentication:
- Admin: Bearer Token authentication (constant-time comparison).
- Client: High-entropy API keys (
zk_...) stored in Firestore.
- Serverless Architecture:
- Compute: Dockerized Ktor application (Cloud Run).
- Database: Google Cloud Firestore (NoSQL) for low-latency key lookups.
- Network Agnostic: Configurable for Sui Mainnet, Testnet, or Devnet.
- Language: Kotlin
- Framework: Ktor (Netty)
- Database: Google Cloud Firestore (Native Mode)
- Blockchain: Sui (via
ksuiSDK) - Build Tool: Gradle (Kotlin DSL)
- Container: Docker (Multi-stage build)
The application is configured entirely via Environment Variables.
| Variable | Description | Required | Default |
|---|---|---|---|
ADMIN_TOKEN |
A secure string used to authenticate Admin requests. | Yes | - |
SPONSOR_PRIVATE_KEY |
The Sui private key (bech32 suiprivkey...) used to sign transactions. |
Yes | - |
SUI_NETWORK |
The target Sui network: MAINNET, TESTNET, or DEVNET. |
No | TESTNET |
GOOGLE_APPLICATION_CREDENTIALS |
Path to service account JSON (only required for local dev). | No | - |
- Java 21 installed.
- Google Cloud Project with Firestore enabled (Native Mode).
- Service Account JSON with "Cloud Datastore User" role (for local testing).
-
Set Environment Variables:
export ADMIN_TOKEN="my-super-secret-admin-token" export SPONSOR_PRIVATE_KEY="suiprivkey1..." export SUI_NETWORK="TESTNET" export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"
-
Run the Server:
./gradlew run
-
Test the Admin Endpoint:
curl -X POST [http://0.0.0.0:8080/admin/api-keys](http://0.0.0.0:8080/admin/api-keys) \ -H "Authorization: Bearer my-super-secret-admin-token" \ -H "Content-Type: application/json" \ -d '{"name": "Local Test", "owner": "Developer"}'
This project is optimized for Cloud Run. It does not require a SQL database; it connects directly to Firestore using the container's identity.
- Google Cloud CLI (
gcloud) installed and authenticated. - Artifact Registry repo created (or use GCR).
- Firestore Database created in your project.
Use Google Cloud Build to create the image without needing local Docker:
gcloud builds submit --tag gcr.io/YOUR_PROJECT_ID/zhell-gas-serviceDeploy the container, setting the production secrets as environment variables. Security Tip: In a real production setup, use Google Secret Manager for the private key and admin token instead of plain text env vars.
gcloud run deploy zhell-gas-service \
--image gcr.io/YOUR_PROJECT_ID/zhell-gas-service \
--platform managed \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars ADMIN_TOKEN="prod-secure-admin-token" \
--set-env-vars SPONSOR_PRIVATE_KEY="suiprivkey1..." \
--set-env-vars SUI_NETWORK="MAINNET"Ensure the Cloud Run Service Account has the Cloud Datastore User role to access Firestore. API Reference
POST /admin/api-keys
Headers: Authorization: Bearer <ADMIN_TOKEN>
Body:
{
"name": "Mobile App v1",
"owner": "Frontend Team"
}Response:
{
"apiKey": "zk_abc123..."
}POST /gas
Headers: X-API-Key: <YOUR_API_KEY>
Body:
{
"txBytes": "<BASE64_ENCODED_TX_BYTES>",
"sender": "0xUserAddress"
}Response:
{
"txBytes": "<BYTES>",
"sponsorSignature": "<SUI_SIGNATURE>",
"status": "SPONSORED"
}