Back to Blog

Platform / B08

从构想到上线:30 天构建 MERX

MERX 从概念到上线的生产系统用了 30 天。不是一个落地页。不是一个原型。而是一个完整运营的区块链资源交易所,集成了七个供应商、实时价格聚合、链上订单执行、复式记账、完整文档、两种语言的 SDK,以及一个拥有 52 个工具的 MCP 服务器用于 AI 代理集成。

本文是这一切如何发生的技术故事——架构决策、我们解决的问题、我们刻意没有走的捷径,以及在不牺牲重要事项的前提下快速构建金融平台的经验教训。


第 0 天:问题陈述

TRON 能量市场是碎片化的。七个或更多供应商提供能量委托服务,每个都有自己的 API、定价和可靠性特征。如果你想获得最优价格,你需要与所有供应商集成。如果你想要故障转移,你需要构建路由逻辑。如果你想要透明度,你需要构建监控。

每个在 TRON 上发送 USDT 的企业都面临这个集成税。解决方案是一个聚合层——一个处理多供应商路由、最优价格选择和自动故障转移的单一 API。

还没有人构建过。我们决定来做。


第 1 周:基础

先做架构

在编写一行代码之前,我们花了两天时间做架构设计。成果是一份涵盖 40 个章节的架构文档,从数据库模式到 API 错误格式再到颜色色值,应有尽有。这份文档成为每个实现决策的唯一真相来源。

在那两天做出的关键架构决策:

决策 1:从第一天起就用微服务。

不是因为微服务时髦,而是因为金融系统需要隔离。资金库签名器不能被 API 服务访问。价格监控不能对用户余额有写入权限。Docker 容器天然提供这种隔离。

services/
  api/              HTTP/WebSocket API
  price-monitor/    Provider price polling
  order-executor/   Order routing and execution
  ledger/           Double-entry accounting
  deposit-monitor/  Incoming payment detection
  treasury-signer/  Transaction signing (isolated)

决策 2:PostgreSQL + Redis,不用特殊数据库。

PostgreSQL 用于所有需要 ACID 保证的内容(余额、订单、账本记录)。Redis 用于所有需要速度的内容(价格缓存、pub/sub、限频)。两者都久经考验、文档完善、运维简单。

决策 3:所有金额使用 SUN。

每个金融值以 SUN 整数存储(1 TRX = 1,000,000 SUN)。金融路径中没有任何浮点数。这在我们编写第一个函数之前就消除了一整类错误。

决策 4:服务使用 Node.js + TypeScript,匹配引擎使用 Go。

TypeScript 用于系统的大部分——快速开发、强类型、出色的异步 I/O 适合 API 和监控工作负载。Go 保留给原始性能重要的匹配引擎。

数据库模式

数据库迁移在第 3 天编写。每个表都以金融完整性为核心设计:

-- Core principle: every balance mutation creates a ledger entry
CREATE TABLE ledger (
  id BIGSERIAL PRIMARY KEY,
  user_id UUID NOT NULL REFERENCES users(id),
  type VARCHAR(50) NOT NULL,
  amount_sun BIGINT NOT NULL,
  direction VARCHAR(6) NOT NULL CHECK (direction IN ('DEBIT', 'CREDIT')),
  reference_type VARCHAR(50),
  reference_id UUID,
  balance_before BIGINT NOT NULL,
  balance_after BIGINT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- No UPDATE or DELETE triggers - ledger is append-only

每个迁移一个文件,命名为 YYYYMMDD_description.sql。到 30 天结束时,有 14 个迁移文件,每个都是增量的,没有破坏性的。

供应商接口

IEnergyProvider 接口在第 4 天定义。这是每个供应商适配器将实现的约定:

interface IEnergyProvider {
  name: string;
  getPrices(): Promise<ProviderPriceResponse>;
  createOrder(params: OrderParams): Promise<OrderResult>;
  getOrderStatus(orderId: string): Promise<OrderStatus>;
  healthCheck(): Promise<boolean>;
}

这个接口从未变过。七个供应商在随后几周内基于它完成了集成,每个都在自己的文件中,没有一个需要更改核心系统。


第 2 周:核心服务

价格监控

价格监控是第一个上线的服务。它每 30 秒轮询每个供应商,规范化价格,发布到 Redis,并将历史存储到 PostgreSQL。实现大约是三个文件共 180 行 TypeScript。

最困难的部分不是轮询逻辑——而是规范化。每个供应商返回的价格格式略有不同:

每个适配器将其供应商的格式转换为标准的 ProviderPriceResponse。价格监控不关心供应商的差异;它只看到规范化的数据。

订单执行器

订单执行器是最复杂的服务。它从 Redis 读取价格,确定最优路由,向供应商提交订单,监控链上确认,并发布结算事件。

故障转移链是关键设计元素。如果供应商 A 失败,尝试供应商 B。如果 B 失败,尝试 C。只要任何供应商可用,买家的 API 调用就会成功。

Order received -> Read prices -> Select cheapest
  -> Execute at Provider A
    -> Success? Verify on-chain -> Settle
    -> Failure? Try Provider B
      -> Success? Verify on-chain -> Settle
      -> Failure? Try Provider C
        -> ... and so on

账本服务

账本服务强制执行复式记账约束。每次余额变更创建配对记录。服务每小时运行一次对账检查:

SELECT SUM(CASE direction
  WHEN 'DEBIT' THEN amount_sun
  WHEN 'CREDIT' THEN -amount_sun
END) FROM ledger;
-- Must be 0. If not: alert immediately.

在 30 天的开发和测试中,这个检查从未触发。约束从未被违反,因为架构使违反在结构上不可能,而不仅仅是不太可能。


第 3 周:API、前端和链上验证

API 设计

API 遵循 REST 规范,严格版本化(/api/v1/...)。每个端点在实现前先设计:

GET    /api/v1/prices          Current prices from all providers
GET    /api/v1/prices/best     Best current price
POST   /api/v1/orders          Create a new order
GET    /api/v1/orders/:id      Get order status
GET    /api/v1/balance          Get account balance
POST   /api/v1/deposit         Get deposit address
POST   /api/v1/withdraw        Request withdrawal

错误响应使用一致的格式:

{
  "error": {
    "code": "INSUFFICIENT_BALANCE",
    "message": "Account balance (5.2 TRX) is insufficient for this order (8.1 TRX)",
    "details": {
      "balance": 5200000,
      "required": 8100000
    }
  }
}

没有端点在所有输入都经过 Zod 验证之前发布。

前端

前端是 Next.js 应用,具有严格的设计系统:仅深色主题、圆角不超过 2px、无渐变、无阴影、标题使用 Cormorant Garamond 字体、其他所有内容使用 IBM Plex Mono 字体。视觉身份在架构文档中定义并忠实实现。

链上验证

每笔订单都在 TRON 区块链上验证。验证服务监视委托交易并确认能量到达目标地址。这是最具挑战性的集成,因为区块链确认时间是可变的,供应商交易格式各不相同。

在测试阶段验证了八笔主网交易,确认了从 API 调用到链上委托的端到端流程与真实 TRX 和真实供应商正确运作。


第 4 周:SDK、MCP 服务器和文档

JavaScript SDK

JavaScript SDK 为 Node.js 和浏览器环境构建:

import { MerxClient } from 'merx-sdk';

const client = new MerxClient({ apiKey: 'your-key' });
const prices = await client.getPrices({ energy: 65000 });
const order = await client.createOrder({
  energy: 65000,
  targetAddress: 'TAddress...',
  duration: '1h'
});

源代码:https://github.com/Hovsteder/merx-sdk-js

Python SDK

Python SDK 与 JavaScript SDK 的 API 接口保持一致:

from merx import MerxClient

client = MerxClient(api_key='your-key')
prices = client.get_prices(energy=65000)
order = client.create_order(
    energy=65000,
    target_address='TAddress...',
    duration='1h'
)

源代码:https://github.com/Hovsteder/merx-sdk-python

MCP 服务器:52 个工具

MCP(Model Context Protocol)服务器可能是最具前瞻性的组件。它将 MERX 功能作为工具暴露给 AI 代理直接使用。

MCP 服务器从初始版本的 7 个工具增长到 30 天结束时的 52 个工具:

Account management:    create_account, login, get_balance, get_deposit_info
Price data:            get_prices, get_best_price, compare_providers, analyze_prices
Order management:      create_order, get_order, list_orders, create_standing_order
Resource monitoring:   check_address_resources, estimate_transaction_cost
TRON utilities:        validate_address, convert_address, get_trx_balance
On-chain operations:   transfer_trx, transfer_trc20, approve_trc20
Analytics:             calculate_savings, get_price_history, suggest_duration
... and 30 more

源代码:https://github.com/Hovsteder/merx-mcp

文档

文档从 5 页重建为 36 页,涵盖完整的 API 参考、SDK 指南、TRON 概念和集成教程。文档位于 https://merx.exchange/docs

此外,发布了 4 个 SEO 指南页面和 7 个供应商对比页面,使站点地图达到 53 个 URL。


我们没有妥协的地方

速度创造了走捷径的压力。以下是我们明确没有走的捷径:

不对货币使用浮点数

对所有金融值使用整数(SUN)增加了显示格式化的复杂性,但完全消除了舍入误差。每个测试用例都精确匹配预期值。

不对 SQL 使用字符串拼接

每个数据库查询使用参数化语句。这是从第一天起的不可协商规则。SQL 注入是一个已解决的问题,我们保持了它的解决状态。

不硬编码密钥

从第一天起就使用环境变量。资金库密钥使用 Docker secret。.gitignore 在第一次提交之前就设置好了。

不让服务之间直接共享状态

服务通过 Redis pub/sub 或 REST API 调用通信。服务之间没有直接导入。这使独立部署成为可能并防止了级联故障。

不修改账本

从第一个迁移开始就是仅追加账本。账本表上没有 UPDATE 或 DELETE。修正创建新记录,而不是修改。


我们学到的

经验 1:架构文档物有所值

花在架构上的两天节省了数周的返工。每个开发者问题都能在文档中找到答案。每个设计分歧都通过引用规范解决。40 个章节不是官僚式的开销;它们是在问题变成错误之前强制思考问题的工具。

经验 2:供应商 API 不可靠

在集成的七个供应商中,至少有两个在 30 天构建期间经历了宕机。故障转移链不是理论上的优雅之举——它在测试的第一周内就被实际使用了。

经验 3:适配器模式值得其样板代码

编写七个都实现相同接口的适配器感觉很重复。但当供应商 C 在第 22 天更改了他们的 API 响应格式时,我们更新了一个文件,其他什么都没变。花 10 分钟更新适配器与花数天更新每个调用处相比,该模式的价值不言自明。

经验 4:MCP 是服务集成的未来

MCP 服务器最初是一个实验。但看着 AI 代理使用 MERX 工具自主管理能量采购令人震撼。这就是未来服务被消费的方式——不是通过人类开发者编写集成代码,而是通过 AI 代理直接调用工具 API。

经验 5:200 行文件限制是一个功能

我们在整个项目中强制执行了严格的 200 行/文件限制。这迫使我们不断分解。函数保持小巧。职责保持清晰。当文件接近 200 行时,就是拆分的时候,而拆分总是改善了清晰度。


数据一览

Architecture document:     40 sections
Services:                  9 Docker containers
Provider integrations:     7
Database migrations:       14
API endpoints:             20+
MCP tools:                 52 (from initial 7)
SDK languages:             2 (JavaScript, Python)
Documentation pages:       36 (from initial 5)
Sitemap URLs:              53
Mainnet transactions:      8 verified
Commission rate:           0%
Days to production:        30

下一步

平台已在 https://merx.exchange 上线。当前重点是测试、优化和引入第一批生产用户。基础是坚实的——架构支持水平扩展,新供应商可以在数小时内添加,零佣金模式消除了用户采纳的摩擦。

TRON 上的能量聚合市场正在等待一个让它变得简单的平台。MERX 就是那个平台。


MERX 是首个区块链资源交易所。在 https://merx.exchange 探索平台。文档请访问 https://merx.exchange/docs。开源 SDK 和 MCP 服务器请访问 GitHub。


All Articles