This repository contains:
- A running Canton / Splice validator deployed via Docker on an AWS EC2 instance.
- A Go client that programmatically interacts with the validator wallet APIs (transactions, balance, wallet creation, user onboarding, transaction pre-approval, active contract monitoring, etc.).
- SSH port-forwarding configuration for secure local access.
- JWT-based authentication for protected API access.
- AWS EC2 instance running Ubuntu
- Docker + docker-compose
- Splice Validator container
- Wallet API exposed internally on port 5003
- External UI exposed via port 8080
- Go client running locally on Mac
- Validator runs inside Docker on EC2.
- Wallet API runs inside container (port 5003).
- We do NOT expose 5003 publicly.
- We use SSH port forwarding to securely access it from local machine.
- Go client connects to forwarded localhost port.
- All requests require a valid JWT token.
- Wallet creation, user onboarding, transaction pre-approval, and active contract monitoring are automated via the Go client.
This ensures:
- No public exposure of wallet API
- Authenticated access only
- Controlled access through SSH
- Automated wallet lifecycle and transaction management
There are two different APIs exposed by the validator setup:
- Accessed using
grpcurl - Used for:
- Party creation
- User creation
- Granting act_as rights
- Submitting commands (e.g., WalletAppInstall)
- Querying active contracts
- Reading ledger updates
- Service namespace:
com.daml.ledger.api.v2.*
This is the low-level Canton Ledger API.
- Accessed using HTTP requests
- Base path:
http://localhost:5003/api/validator/v0/ - Used for:
- Listing wallet transactions
- Getting wallet balance
- Wallet creation
- User onboarding
- Transaction pre-approval
- Active contract monitoring
This is a higher-level application API built on top of the ledger.
Important:
- Port 5001 → Ledger (gRPC)
- Port 5003 → Wallet (REST)
They serve different purposes and require separate SSH port forwarding if accessed remotely.
We DO NOT expose port 5003 publicly.
Instead, we use:
ssh -i ~/Downloads/scopex_canton.pem \
-L 5003:localhost:5003 \
ubuntu@ec2-<public-ip>.compute.amazonaws.comThis creates:
Local machine → localhost:5003
Tunnel → EC2 container:5003
Meaning:
- Only your machine can access wallet API
- No public attack surface
- Production-safe approach
If you need access to multiple internal services (Ledger gRPC, Wallet API, Wallet UI, ANS UI), you can forward multiple ports in one command:
ssh -i ~/path/to/key.pem \
-L 5001:localhost:5001 \
-L 5003:localhost:5003 \
-L 8080:wallet.localhost:80 \
-L 8081:ans.localhost:80 \
ubuntu@<EC2_PUBLIC_IP>What this does:
-L 5001:localhost:5001→ Forwards Ledger gRPC API-L 5003:localhost:5003→ Forwards Wallet REST API-L 8080:wallet.localhost:80→ Forwards Wallet Web UI-L 8081:ans.localhost:80→ Forwards ANS Web UI
Flow:
Local Machine → SSH Tunnel → EC2 → Docker Container → Internal Service
This keeps all internal services private while allowing secure local access for development.
Validator runs inside:
canton-validator/splice-node/docker-compose/validatorKey commands used:
Start validator:
./start.sh -s "https://sv.sv-1.test.global.canton.network.sync.global" -o "<TESTNET_SECRET>" -p "scopex-validator-1" -m "1" -wImportant environment variables inside container:
SPLICE_APP_VALIDATOR_WALLET_USER_NAME=administrator
SPLICE_APP_VALIDATOR_LEDGER_API_AUTH_USER_NAME=ledger-api-userThis tells us which user the wallet API expects for authentication.
We generate token using:
python3 get-token.py administratorImportant:
- The username MUST match the wallet user inside container (
administrator) - Otherwise: Authorization Failed
JWT is then passed in header:
Authorization: Bearer <token>Base path (internal):
http://localhost:5003/api/validator/v0/POST request:
/wallet/transactionsBody:
{
"page_size": 20
}GET request:
/wallet/balanceResponse includes:
- effective_unlocked_qty
- effective_locked_qty
- round
- total_holding_fees
These processes are fully automated via the Go client, enabling seamless wallet lifecycle management and pre-approval of transactions to streamline operations.
The Go client also monitors active contracts on the ledger, providing real-time insights into wallet holdings and contract states.
We have implemented financial tracking features to monitor traffic usage and enforce transfer limits:
- Traffic Usage Monitoring: Tracks API and transaction volume to ensure system performance and cost control.
- Transfer Limits: Configurable limits on transaction amounts and frequencies to prevent abuse and maintain compliance.
These features are integrated into the Go client and validator setup to provide robust financial oversight.
Located in:
cmd/Client responsibilities:
- Create HTTP client with timeout
- Inject JWT into Authorization header
- Call:
- ListTransactions(ctx, pageSize)
- GetBalance(ctx)
- Wallet creation and user onboarding workflows
- Transaction pre-approval
- Active contract monitoring
- Print structured response
Example main flow:
client, _ := cantonvalidator.NewCantonClient()
client.ListTransactions(ctx, 20)
client.GetBalance(ctx)Current Security:
- Wallet API not publicly exposed
- JWT authentication required
- Access only via SSH tunnel
- Token tied to wallet user
If additional security required:
- Rotate signing secret
- Restrict EC2 security group to known IP
- Disable public port 8080
- Add reverse proxy with TLS
✔ Deployed Canton validator via Docker
✔ Automated wallet creation and user onboarding
✔ Automated transaction pre-approval and active contract monitoring
✔ Implemented financial tracking for traffic and transfer limits
✔ Secured API using SSH tunnel and JWT authentication
✔ Built Go client for programmatic control
✔ Fetched transactions and balance successfully
System is now:
- Secure
- Scriptable
- Production-ready for automation
- Extendable for transfers and validator control
- Add transfer execution in Go
- Add structured response parsing instead of map[string]interface{}
- Add CLI flags
- Add metrics
- Add background sync loop
- Add unit tests
- Add structured logging
Never expose port 5003 publicly.
Always use SSH tunnel or private networking.
JWT must match wallet user configured inside container.
This repository now serves as:
- Validator control client
- Operational documentation
- Security reference for deployment