Skip to content

Latest commit

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Disclaimer: This repository contains only a partial excerpt of a larger application, shared for review purposes with the permission of the copyright holder. It is not intended to be a fully functional standalone project.

NCW Hotel — PHP Code Sample

A backend REST API for managing Non-Custodial Wallets (NCW) via Fireblocks. Built with Symfony 6.4 and PHP 8.1+.

What It Does

The service allows users to manage cryptocurrency wallets through the Fireblocks NCW infrastructure:

  • Register and authenticate via JWT
  • Manage wallet devices and accounts
  • Add and track crypto assets (Bitcoin, Ethereum, ERC20/BEP20 tokens, etc.)
  • View balances and deposit addresses (served from local cache, synced asynchronously)
  • Create and cancel transactions
  • Browse transaction history

Balances and addresses are kept fresh via background workers that periodically sync with the Fireblocks API, allowing the REST API to respond without blocking on third-party calls.

Technology Stack

LayerTechnology
FrameworkSymfony 6.4
LanguagePHP 8.1+
DatabaseMySQL 8 + Doctrine ORM 3
Cache / QueueRedis + Symfony Messenger
AuthenticationJWT (lexik/jwt-authentication-bundle)
HTTP ClientGuzzle
Background JobsSymfony Scheduler + Supervisord
Real-timeMercure (WebSocket over Caddy)
API DocsOpenAPI / Swagger (nelmio/api-doc-bundle)
InfrastructureDocker Compose

Project Structure

src/
├── Client/Fireblocks/ # Fireblocks API client (HTTP, serialization, DTOs, exceptions)
├── Command/ # CLI commands (transaction import, client test)
├── Controller/ # HTTP controllers (API v1, auth, webhooks, health)
├── Entity/ # Doctrine ORM entities (User, Wallet, Device, Asset, Balance, ...)
├── EventListener/ # Global exception handler → JSON error responses
├── Infrastructure/ # Redis factory, WebSocket publisher, custom Doctrine types
├── Model/ # Business logic layer
│ ├── Object/ # Domain objects and enums
│ ├── RequestProcessor/ # Request → Response handlers (per domain area)
│ ├── BalanceUpdater/ # Async balance sync via Messenger
│ ├── AddressFetcher/ # Async address sync via Messenger
│ ├── AccountAssetsUpdater/# Async asset list sync via Messenger
│ └── TransactionImporter/ # Async transaction import via Messenger + Scheduler
└── Repository/ # Doctrine repositories

API Endpoints

All endpoints are under /api/v1 and require JWT authentication.

MethodPathDescription
POST/auth/registerRegister a new user
POST/auth/loginObtain JWT token
GET/devicesList user's wallet devices
GET/devices/{device}Get device details
GET/devices/{device}/setup-statusGet device setup status
POST/devices/{device}/rpcInvoke Fireblocks RPC method
GET/devices/{device}/accountsList accounts
GET/devices/{device}/accounts/{id}Get account details
GET/assetsList supported crypto assets
GET/devices/{device}/accounts/{id}/assetsList account assets
POST/devices/{device}/accounts/{id}/assets/{assetId}Add asset to account
GET/devices/{device}/accounts/{id}/assets/{assetId}Get asset details
GET/devices/{device}/accounts/{id}/assets/{assetId}/balanceGet cached balance
GET/devices/{device}/accounts/{id}/assets/{assetId}/addressGet deposit address
GET/devices/{device}/transactionsList transactions
GET/devices/{device}/transactions/{txId}Get transaction details
POST/devices/{device}/accounts/{id}/assets/{assetId}/transactionsCreate transaction
POST/devices/{device}/transactions/{txId}/cancelCancel transaction
POST/callbackFireblocks webhook receiver
GET/healthHealth check

Interactive API documentation is available at /api/doc.

Architecture

flowchart TD
A[HTTP Request] --> B[Controller]
B --> C[RequestProcessor]
C --> D[Service]
D --> E[Fireblocks API Client]
D --> F[(MySQL)]
F --> G[Background Workers\nMessenger + Scheduler]
G --> C
G --> H[(Redis\nqueue / cache)]
G --> I[Mercure Hub\nWebSocket]
Loading

Async sync pipeline

Background workers run independently via Symfony Messenger:

  • BalanceUpdater — fetches asset balances from Fireblocks and stores them in MySQL
  • AddressFetcher — fetches deposit addresses from Fireblocks and stores them in MySQL
  • AccountAssetsUpdater — keeps account asset lists in sync
  • TransactionImporter — imports transaction history on schedule and via webhooks

API endpoints for balance and address serve the cached data immediately without waiting for Fireblocks.

Real-time notifications (Mercure + Caddy)

After async workers update balances, addresses or transaction statuses, they publish events via WebsocketPublisher to a Mercure hub. Clients subscribe to topics and receive live updates without polling.

Caddy serves as both the HTTPS reverse proxy and the Mercure hub (via the built-in FrankenPHP + Caddy Docker image), exposing the hub at /.well-known/mercure.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages