Настройка и развёртывание серверов криптобиржи: техническое руководство по запуску
Содержание
- Перед началом работы
- Обзор серверной архитектуры
- Шаг 1: Подготовка и защита серверов
- Шаг 2: Установка веб-стека
- Шаг 3: Настройка Nginx как обратного прокси
- Шаг 4: Настройка PHP-FPM
- Шаг 5: Установка и настройка базы данных MySQL
- Шаг 6: Настройка кэша и очередей Redis
- Шаг 7: Развёртывание демонов кошельков
- Шаг 8: Настройка WebSocket-сервера
- Шаг 9: Настройка SSL/TLS и домена
- Шаг 10: Задачи cron и фоновые воркеры
- Шаг 11: Мониторинг и оповещения
- Шаг 12: Резервное копирование и аварийное восстановление
- Шаг 13: Нагрузочное тестирование
- Шаг 14: Чек-лист запуска
- Эксплуатация после запуска
Это руководство предназначено для системных администраторов, DevOps-инженеров и CTO, которые уже приняли бизнес-решение о запуске биржи и теперь нуждаются в плане развёртывания. Если вы ещё оцениваете бизнес-сторону вопроса — лицензирование, расходы, модели монетизации — сначала прочитайте бизнес-план криптобиржи или полное руководство для старта.
Здесь мы разберём каждый технический шаг: от подготовки «голого» сервера до production-готовой биржи, обрабатывающей реальные сделки и реальные деньги.
Перед началом работы
Убедитесь, что у вас есть:
- Лицензионная копия биржевого ПО Codono с полным доступом к исходному коду
- Root-доступ по SSH к вашему серверу (или серверам)
- Зарегистрированный домен с управлением DNS
- SSL-сертификаты (или план использовать Let’s Encrypt)
- Учётные данные для выбранного KYC-провайдера (SumSub или аналогичного)
Инструкции ниже предполагают Ubuntu 22.04 LTS. Codono также поддерживает CentOS/RHEL и Debian, но названия пакетов могут отличаться.
Обзор серверной архитектуры
Production-криптобиржа — это не один сервер. Как минимум, планируйте такую топологию:
| Сервер | Роль | Минимальные характеристики |
|---|---|---|
| Сервер приложений | Nginx + PHP-FPM + код приложения | 8 vCPU, 32 ГБ ОЗУ, 200 ГБ NVMe |
| Сервер базы данных | MySQL 8.0 primary | 16 vCPU, 64 ГБ ОЗУ, 500 ГБ NVMe RAID-10 |
| Сервер кэша/очередей | Redis 7.x | 4 vCPU, 16 ГБ ОЗУ |
| WebSocket-сервер | Ленты данных в реальном времени | 4 vCPU, 8 ГБ ОЗУ |
| Сервер(ы) кошельков | Демоны блокчейнов (bitcoind, geth и т. д.) | 8 vCPU, 32 ГБ ОЗУ, 1 ТБ+ SSD на каждую сеть |
Для биржи малого и среднего размера (до 5 000 одновременных пользователей) можно объединить приложение + WebSocket на одном сервере, а кэш + очереди — на другом. Никогда не совмещайте базу данных или демоны кошельков с чем-либо ещё.
Рекомендуемые провайдеры: Hetzner (лучшее соотношение цена/производительность в ЕС), OVH, AWS EC2 (если нужна мультирегиональность), DigitalOcean. Избегайте виртуального хостинга.
Шаг 1: Подготовка и защита серверов
Начните с чистой установки Ubuntu 22.04 LTS на каждом сервере.
Первичная защита:
# Update packages
apt update && apt upgrade -y
# Create a non-root deploy user
adduser deploy
usermod -aG sudo deploy
# Disable root SSH login
sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart sshd
# Configure UFW firewall
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
ufw enable
На серверах кошельков также ограничьте RPC-порты так, чтобы они принимали соединения только с внутреннего IP сервера приложений:
ufw allow from 10.0.0.2 to any port 8332 # Bitcoin RPC
ufw allow from 10.0.0.2 to any port 8545 # Ethereum RPC
Установите fail2ban для защиты от брутфорса:
apt install fail2ban -y
systemctl enable fail2ban
Настройте автоматическую установку обновлений безопасности:
apt install unattended-upgrades -y
dpkg-reconfigure --priority=low unattended-upgrades
Шаг 2: Установка веб-стека
На сервере приложений установите Nginx, PHP 8.2 и необходимые расширения:
# Nginx
apt install nginx -y
# PHP 8.2 + extensions required by Codono
apt install php8.2-fpm php8.2-mysql php8.2-redis php8.2-curl \
php8.2-gd php8.2-mbstring php8.2-xml php8.2-zip php8.2-bcmath \
php8.2-intl php8.2-soap php8.2-gmp -y
Разверните исходный код Codono:
mkdir -p /var/www/exchange
# Upload source code via rsync or git clone
rsync -avz ./codono-source/ deploy@app-server:/var/www/exchange/
chown -R www-data:www-data /var/www/exchange
chmod -R 755 /var/www/exchange
chmod -R 775 /var/www/exchange/runtime # Writable cache dir
Шаг 3: Настройка Nginx как обратного прокси
Создайте основную конфигурацию сайта:
# /etc/nginx/sites-available/exchange.conf
upstream php-fpm {
server unix:/run/php/php8.2-fpm.sock;
}
upstream websocket {
server 127.0.0.1:9502;
}
server {
listen 443 ssl http2;
server_name exchange.example.com;
root /var/www/exchange/public;
index index.php;
# SSL (see Step 9)
ssl_certificate /etc/letsencrypt/live/exchange.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/exchange.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# Gzip
gzip on;
gzip_types text/plain application/json application/javascript text/css;
gzip_min_length 1000;
# Rate limiting zone (defined in nginx.conf)
limit_req zone=api burst=20 nodelay;
# Main application
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass php-fpm;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_read_timeout 30s;
}
# WebSocket proxy
location /ws {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 86400s;
}
# Block sensitive paths
location ~ /\.(git|env|htaccess) {
deny all;
}
location ~ /(runtime|application|vendor) {
deny all;
}
# Static asset caching
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
server {
listen 80;
server_name exchange.example.com;
return 301 https://$host$request_uri;
}
Добавьте зону ограничения частоты запросов в /etc/nginx/nginx.conf внутри блока http:
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
Включите конфигурацию и проверьте её:
ln -s /etc/nginx/sites-available/exchange.conf /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
Шаг 4: Настройка PHP-FPM
Отредактируйте /etc/php/8.2/fpm/pool.d/www.conf под production-нагрузки:
; Process management
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 1000
; Timeouts
request_terminate_timeout = 30s
; Logging
slowlog = /var/log/php-fpm-slow.log
request_slowlog_timeout = 5s
Отредактируйте /etc/php/8.2/fpm/php.ini под специфику биржи:
memory_limit = 256M
max_execution_time = 30
upload_max_filesize = 10M
post_max_size = 12M
opcache.enable = 1
opcache.memory_consumption = 256
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 0 ; Set to 1 during development
session.gc_maxlifetime = 7200
Перезапустите PHP-FPM:
systemctl restart php8.2-fpm
Ключевой момент: установка opcache.validate_timestamps = 0 в production означает, что после каждого деплоя кода нужно выполнять systemctl restart php8.2-fpm. Это даёт значительный прирост производительности, потому что PHP не выполняет проверку stat файлов при каждом запросе.
Шаг 5: Установка и настройка базы данных MySQL
На сервере базы данных установите MySQL 8.0:
apt install mysql-server-8.0 -y
mysql_secure_installation
Создайте базу данных биржи и пользователя:
CREATE DATABASE exchange_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'exchange_user'@'10.0.0.%' IDENTIFIED BY 'strong_random_password';
GRANT ALL PRIVILEGES ON exchange_db.* TO 'exchange_user'@'10.0.0.%';
FLUSH PRIVILEGES;
Отредактируйте /etc/mysql/mysql.conf.d/mysqld.cnf под нагрузки биржи:
[mysqld]
# InnoDB tuning (assuming 64 GB RAM server)
innodb_buffer_pool_size = 40G
innodb_buffer_pool_instances = 8
innodb_log_file_size = 2G
innodb_flush_log_at_trx_commit = 1
innodb_flush_method = O_DIRECT
innodb_io_capacity = 2000
innodb_io_capacity_max = 4000
# Connection handling
max_connections = 500
thread_cache_size = 50
table_open_cache = 4000
# Query cache (disabled in MySQL 8, use Redis instead)
# query_cache_type = 0
# Slow query logging
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
# Network
bind-address = 10.0.0.3 # Internal IP only
max_allowed_packet = 64M
# Binary logging for replication
log_bin = mysql-bin
server-id = 1
binlog_expire_logs_seconds = 604800
Импортируйте схему базы данных Codono:
mysql -u exchange_user -p exchange_db < /var/www/exchange/database/schema.sql
Совет по производительности: innodb_buffer_pool_size должен составлять 60-70% от общего объёма ОЗУ сервера. Это самый важный параметр настройки MySQL для биржи, поскольку таблицы стакана, балансов и истории сделок интенсивно используются на чтение и запись.
Шаг 6: Настройка кэша и очередей Redis
На сервере кэша установите Redis 7:
apt install redis-server -y
Отредактируйте /etc/redis/redis.conf:
bind 10.0.0.4 # Internal IP
maxmemory 8gb
maxmemory-policy allkeys-lru
save 900 1 # RDB snapshots
save 300 10
appendonly yes # AOF for durability
Codono использует Redis для:
- Хранения сессий — быстрее, чем сессии в MySQL, и поддерживает горизонтальное масштабирование серверов приложений
- Слоя кэширования — цены монет, данные тикеров, конфигурации торговых пар
- Бэкенда очередей — обработка выводов, отправка писем, колбэки KYC
- Pub/Sub — обновления стакана и сделок в реальном времени, передаваемые WebSocket-серверу
Проверьте связь с сервера приложений:
redis-cli -h 10.0.0.4 ping
# Should return: PONG
Шаг 7: Развёртывание демонов кошельков
Это самая сложная часть. Каждому поддерживаемому блокчейну нужен собственный демон, запущенный на сервере кошельков.
Bitcoin (bitcoind)
# Install
wget https://bitcoincore.org/bin/bitcoin-core-27.0/bitcoin-27.0-x86_64-linux-gnu.tar.gz
tar xzf bitcoin-27.0-x86_64-linux-gnu.tar.gz
cp bitcoin-27.0/bin/* /usr/local/bin/
Настройте /home/bitcoin/.bitcoin/bitcoin.conf:
server=1
rpcuser=exchange_btc
rpcpassword=strong_random_rpc_password
rpcallowip=10.0.0.2/32
rpcbind=10.0.0.5
txindex=1
maxconnections=50
dbcache=4096
Ethereum (geth)
apt install -y software-properties-common
add-apt-repository -y ppa:ethereum/ethereum
apt install geth -y
Запуск в виде systemd-сервиса:
geth --http --http.addr 10.0.0.5 --http.port 8545 \
--http.api eth,net,web3,personal \
--http.corsdomain "*" \
--http.vhosts "10.0.0.5" \
--syncmode snap \
--datadir /data/ethereum \
--maxpeers 50
Другие сети
Повторите эту схему для каждого поддерживаемого блокчейна. Codono поддерживает более 50 сетей — конфигурации для конкретных демонов смотрите в документации по интеграции блокчейнов. Популярные сети для запуска:
- BNB Chain (нода BSC или RPC-эндпоинт)
- Tron (полная нода java-tron)
- Solana (solana-validator или RPC-эндпоинт)
- Polygon (bor + heimdall или RPC-эндпоинт)
Разделение горячего и холодного кошельков: настройте кошельковую систему биржи так, чтобы в горячем кошельке оставалось только 5-10% от общего объёма депозитов. Остальное перемещается на адреса холодного хранения, защищённые мультиподписью. Админ-панель Codono предоставляет пороговые оповещения и инструменты ручного пополнения горячего кошелька из холодного.
Шаг 8: Настройка WebSocket-сервера
Ленты цен в реальном времени, обновления стакана и уведомления о сделках требуют WebSocket-соединений. Codono включает WebSocket-сервер на базе Swoole.
Установите Swoole:
pecl install swoole
echo "extension=swoole.so" > /etc/php/8.2/cli/conf.d/20-swoole.ini
Запустите WebSocket-сервер:
cd /var/www/exchange
php artisan websocket:serve --host=0.0.0.0 --port=9502
Создайте systemd-сервис для автоматического перезапуска:
# /etc/systemd/system/exchange-ws.service
[Unit]
Description=Exchange WebSocket Server
After=network.target redis.service
[Service]
User=www-data
WorkingDirectory=/var/www/exchange
ExecStart=/usr/bin/php artisan websocket:serve --host=0.0.0.0 --port=9502
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Включите и запустите:
systemctl enable exchange-ws
systemctl start exchange-ws
WebSocket-сервер подписывается на каналы Redis pub/sub. Когда исполняется сделка или меняется стакан, матчинговый движок публикует обновление в Redis, а WebSocket-сервер рассылает его всем подключённым клиентам за миллисекунды.
Шаг 9: Настройка SSL/TLS и домена
Используйте Let’s Encrypt для бесплатных сертификатов с автопродлением:
apt install certbot python3-certbot-nginx -y
certbot --nginx -d exchange.example.com -d www.exchange.example.com
Проверьте автопродление:
certbot renew --dry-run
DNS-записи для настройки:
| Запись | Тип | Значение |
|---|---|---|
| exchange.example.com | A | Публичный IP сервера приложений |
| www.exchange.example.com | CNAME | exchange.example.com |
| api.exchange.example.com | A | Публичный IP сервера приложений (если используется отдельный поддомен API) |
Заголовки безопасности — добавьте в server-блок Nginx:
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
Шаг 10: Задачи cron и фоновые воркеры
Codono требует несколько запланированных задач. Добавьте их в crontab пользователя www-data:
crontab -u www-data -e
# Process pending withdrawals (every 2 minutes)
*/2 * * * * php /var/www/exchange/artisan queue:withdrawal
# Update coin prices from market data (every minute)
* * * * * php /var/www/exchange/artisan market:prices
# Process deposit confirmations (every minute)
* * * * * php /var/www/exchange/artisan wallet:deposits
# Clean expired orders (every 5 minutes)
*/5 * * * * php /var/www/exchange/artisan orders:cleanup
# Generate daily reports (daily at midnight UTC)
0 0 * * * php /var/www/exchange/artisan reports:daily
# Database backup (daily at 3 AM UTC)
0 3 * * * /usr/local/bin/exchange-backup.sh
# SSL certificate renewal check (twice daily)
0 */12 * * * certbot renew --quiet --post-hook "systemctl reload nginx"
Для воркеров очередей, которые должны работать непрерывно (email-уведомления, колбэки KYC), используйте Supervisor:
apt install supervisor -y
# /etc/supervisor/conf.d/exchange-worker.conf
[program:exchange-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/exchange/artisan queue:work redis --tries=3 --timeout=90
autostart=true
autorestart=true
numprocs=4
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/exchange-worker.log
supervisorctl reread && supervisorctl update
Шаг 11: Мониторинг и оповещения
Production-бирже нужны три уровня мониторинга:
Мониторинг инфраструктуры (Prometheus + Grafana)
Установите node_exporter на каждый сервер. Отслеживайте:
- Загрузку CPU (оповещение при устойчивом превышении 80%)
- Использование ОЗУ (оповещение выше 85%)
- Дисковый I/O и свободное место (оповещение ниже 20%)
- Пропускную способность сети и потери пакетов
Мониторинг приложения
- Статус пула PHP-FPM (
pm.status_path = /fpm-status) - Nginx stub_status для активных соединений
- Количество медленных запросов MySQL в час
- Использование памяти Redis и количество ключей
- Глубину очереди (количество ожидающих задач должно держаться около нуля)
Мониторинг кошельков (критически важен)
- Баланс горячего кошелька по каждой монете (оповещение при падении ниже порога)
- Количество ожидающих депозитов (резкий рост указывает на проблемы с синхронизацией демона)
- Количество ожидающих выводов (резкий рост указывает на сбой обработки)
- Высота блока демона по сравнению с высотой сети (оповещение при отставании более чем на 10 блоков)
Каналы оповещений: PagerDuty или Opsgenie для критических оповещений (кошельки, падение базы данных), Slack или Telegram для предупреждений (высокая загрузка CPU, медленные запросы). Админ-панель также показывает состояние системы в реальном времени.
Шаг 12: Резервное копирование и аварийное восстановление
Резервное копирование базы данных
#!/bin/bash
# /usr/local/bin/exchange-backup.sh
DATE=$(date +%Y%m%d_%H%M)
BACKUP_DIR=/backup/mysql
mysqldump --single-transaction --routines --triggers \
-u backup_user -p exchange_db | gzip > $BACKUP_DIR/exchange_$DATE.sql.gz
# Retain 30 days
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete
# Sync to offsite storage
aws s3 sync $BACKUP_DIR s3://exchange-backups/mysql/ --storage-class STANDARD_IA
Резервное копирование кошельков
- Bitcoin: сохраняйте
wallet.datв зашифрованное внешнее хранилище после генерации каждого нового адреса - Ethereum: сохраняйте каталог keystore
- Seed-фразы холодных кошельков храните в географически разнесённых огнестойких сейфах
Целевые показатели восстановления
| Компонент | RPO (потеря данных) | RTO (время простоя) |
|---|---|---|
| База данных | 1 час | 30 минут |
| Приложение | 0 (stateless, повторный деплой из исходников) | 10 минут |
| Демоны кошельков | 0 (повторная синхронизация из блокчейна) | 2-24 часа (зависит от сети) |
Настройте репликацию MySQL на резервный сервер для RPO, близкого к нулю. Тестируйте переключение на резерв ежеквартально.
Шаг 13: Нагрузочное тестирование
Прежде чем открыть биржу для реальных пользователей, протестируйте под нагрузкой каждый критический путь:
# Install k6
apt install k6 -y
# Test login endpoint
k6 run --vus 100 --duration 60s login-test.js
# Test order placement
k6 run --vus 50 --duration 120s order-test.js
# Test WebSocket connections
k6 run --vus 500 --duration 60s ws-test.js
Базовые целевые показатели для production-биржи:
| Эндпоинт | Целевое значение | Приемлемое |
|---|---|---|
| Ответ API (размещение ордера) | <100 мс p95 | <200 мс p99 |
| Задержка WebSocket-сообщений | <50 мс | <100 мс |
| Загрузка страницы (торговый интерфейс) | <2 с | <3 с |
| Одновременные WebSocket-соединения | 5 000+ | 2 000+ |
| Ордеров в секунду (матчинговый движок) | 1 000+ | 500+ |
Если какой-либо эндпоинт превышает пороговые значения, проведите профилирование с помощью php-fpm-slow.log, лога медленных запросов MySQL или EXPLAIN для «горячих» запросов — прежде чем наращивать железо.
Шаг 14: Чек-лист запуска
Пройдите этот чек-лист перед открытием регистрации:
Инфраструктура:
- Все серверы защищены (только SSH-ключи, правила файрвола, fail2ban)
- SSL-сертификаты установлены, автопродление проверено
- Распространение DNS завершено
- Защита от DDoS активна (Cloudflare или аналог)
- Скрипты резервного копирования работают и проверены тестовым восстановлением
Приложение:
- Конфигурация окружения переведена в production (debug выключен, отображение ошибок выключено)
- OPcache включён, validate_timestamps выключен
- Все чувствительные пути заблокированы в Nginx (
.git,.env,runtime/) - Заголовки безопасности настроены
- Ограничение частоты запросов активно на API-эндпоинтах
- CORS настроен только для вашего домена
Кошельки:
- Все демоны кошельков синхронизированы до актуальной высоты блока
- Горячий кошелёк пополнен начальными операционными балансами
- Адреса холодных кошельков сгенерированы, ключи надёжно хранятся офлайн
- Генерация депозитных адресов протестирована для каждой монеты
- Поток вывода средств протестирован end-to-end для каждой монеты
- Настроены пороги и оповещения для горячего кошелька
Торговля:
- Торговые пары настроены с правильной точностью цен
- Установлены тарифы комиссий (ставки maker/taker)
- Матчинговый движок протестирован с симулированными ордерами
- Глубина стакана отображается корректно
- WebSocket-ленты транслируют данные в реальном времени
Комплаенс:
- KYC-провайдер интегрирован и протестирован
- Настроены уровни верификации
- Применяются лимиты вывода по уровням
- Активен AML-мониторинг транзакций
Мониторинг:
- Все дашборды работают в Grafana
- Каналы оповещений настроены и протестированы (отправьте тестовое оповещение)
- Установлено дежурное расписание (on-call)
Эксплуатация после запуска
Первые 30 дней после запуска требуют пристального внимания:
Ежедневные задачи:
- Проверяйте балансы горячих кошельков по всем сетям
- Контролируйте очередь ожидающих выводов (должна очищаться за считанные минуты)
- Отслеживайте логи ошибок на предмет новых паттернов
- Просматривайте лог медленных запросов для поиска возможностей оптимизации
Еженедельные задачи:
- Проверяйте целостность резервных копий (тестовое восстановление на staging)
- Просматривайте логи безопасности (неудачные входы, заблокированные IP)
- Обновляйте ПО демонов кошельков при выходе новых версий
- Анализируйте паттерны нагрузки PHP-FPM и Nginx для планирования мощностей
Триггеры масштабирования:
- PHP-FPM
max_childrenпостоянно на пределе → добавьте сервер приложений за балансировщиком нагрузки - CPU MySQL устойчиво выше 70% → добавьте реплики на чтение или обновите железо
- Память Redis выше 80% → увеличьте maxmemory или добавьте узлы кластера
- WebSocket-сервер выше 3 000 одновременных соединений → добавьте второй WS-узел с Redis pub/sub
Это руководство охватывает техническое развёртывание. О бизнес-стороне — лицензировании, расходах, моделях монетизации и стратегии выхода на рынок — читайте в бизнес-плане криптобиржи. Полный обзор процесса от начала до конца смотрите в статье как запустить криптобиржу.
Готовы к развёртыванию? Запросите живое демо, чтобы протестировать весь стек, ознакомьтесь с ценами на варианты лицензий или свяжитесь с командой для поддержки при развёртывании.
Codono Team
Codono builds enterprise-grade crypto exchange software deployed by 250+ operators across 40+ countries. Our team writes from production experience running spot, derivatives, custody, and compliance at scale.
View all posts by Codono Team →