Topo DApp 开发者架构指南
本文面向合约、后端、前端、事件消费者、搜索、运维和测试开发者,说明在 Topo 链上建设生产级 DApp 的推荐工程形态。
开发者实现 Topo DApp 时,应先统一链上事实、链下体验和 POC 可信贡献边界,再设计具体合约模块、交易入口、事件同步和读模型。
工程原则
- 链上合约维护资产、权限、关键状态机和可信事件。
- 后端负责入口安全、交易语义校验、幂等和读 API,不替代链上事实。
- 前端负责交易体验和状态展示,不保存私钥、生产 API key 或管理员密钥。
- 事件消费者只投影链上事实,不制造链上事实。
- 读模型可以异步落后,但必须可重放、可修复、可对账。
- POC power 只能来自 PowerStore committed power,本地积分、预估贡献和普通事件都不能当作 power。
- 交易型 DApp 的业务结算和 POC 贡献发放应解耦,POC 异常不能阻塞资金结算。
推荐工程架构
职责边界:
| 层 | 应承担 | 不应承担 |
|---|---|---|
| Frontend | 钱包连接、交易构造、状态展示、错误恢复 | 私钥保存、绕过后端语义校验 |
| Gateway | Host/Profile 分流、限流、路径封禁、日志脱敏 | 业务状态判断 |
| Backend | 登录、签名交易校验、tx hash 幂等、读 API、异步任务入口 | 覆盖链上资产和状态事实 |
| Move 合约 | 资产、权限、核心状态机、事件、view | 大列表搜索、运营报表、复杂聚合 |
| Consumer | 链上事件解析、读模型同步、重试、对账 | 伪造链上事实 |
| POC Engine | 周期结算、价格快照、贡献聚合、账本 | 实时逐笔修改用户 power |
| POC Writer | 写回下一周期 staged power、链上对账 | 修改当前周期 committed power |
Move 合约模块拆分
| 模块 | 职责 | 关键约束 |
|---|---|---|
permission_manager | 管理角色、管理员、多签或治理权限 | 不写业务状态 |
config_manager | 费率、上限、白名单、pause、延迟生效 | 参数变更必须可审计 |
asset_registry | 支付资产和权益资产白名单、精度、metadata | 禁止临时传入未登记资产 |
domain_manager | 业务对象资源和状态机 | 每个 entry function 推动明确状态转移 |
vault_manager | 托管、支付、退款、提现、结算 | 资产流必须和状态流一致 |
contribution_manager | 成熟贡献识别、发放、重复发放保护 | 只发放贡献,不计算 POC power |
events | 事件结构、版本字段、公共契约 | 字段变更必须同步后端、消费者和测试 |
views | 前端、后端和对账所需链上查询 | 不做复杂链下聚合 |
状态机设计
状态机应先于 entry function 设计。所有业务动作都应能解释为从一个明确状态进入另一个明确状态。
设计规则:
- 所有状态必须定义允许的下一状态。
- 所有 entry function 必须校验 signer、权限、状态、金额和资产。
- 资产转移、状态更新和事件输出应在同一交易内保持原子性。
- 批处理入口必须设置数量上限,避免无界循环。
- 贡献发放必须基于成熟事实,不基于支付成功或前端展示状态。
- 退款、仲裁、暂停、恢复和治理修正必须在状态机中预留路径。
事件契约
事件不是日志,而是跨前端、后端、消费者、搜索、审计和 POC 的公共契约。
事件字段建议:
| 字段 | 说明 |
|---|---|
event_version | 事件结构版本 |
app_id / domain | 应用或业务域 |
object_id | 业务对象 ID |
actor | 发起人或 signer |
beneficiary | 资产或贡献受益人 |
asset_type | 支付或权益资产 |
amount | 金额或数量,使用统一精度 |
old_state / new_state | 状态变化 |
reason_code | 业务原因码 |
tx_context | 可关联 tx hash、event version 或链上版本 |
poc_ref | 需要接入 POC 时关联贡献来源事实 |
兼容规则:
- 新增字段优先使用新版本事件,不破坏旧消费者。
- 删除或改名字段必须同步 ABI 清单、消费者解析、测试和文档。
- 消费者不能只依赖本地 payload,应能回链上查询完整事实。
View 设计
View 用于读取链上事实,不用于做复杂报表。
推荐 view:
| View | 用途 |
|---|---|
| 业务对象状态 | 前端和后端确认当前状态 |
| 资产托管余额 | 对账资产流 |
| 配置和 pause 状态 | 前端提示和后台治理 |
| 成熟贡献状态 | 判断是否可发放 POC 贡献 |
| POC 发放状态 | 判断是否已经产生 ContributionEvent |
Signed Transaction 入口
后端不能只转发 signed transaction。它必须在提交链上前完成身份、交易目标、参数语义和幂等校验。
必须校验的内容:
| 类别 | 校验项 |
|---|---|
| 身份 | 当前 session、钱包地址、wallet binding、后台角色 |
| 链参数 | chain id、合约地址、module、function、过期时间 |
| 交易结构 | 参数数量、泛型参数、目标 entry function |
| 参数语义 | 业务对象归属、金额、资产、数量、商户、受益人、状态 |
| 幂等 | tx hash、业务 ID、pending/processed 状态 |
| 风控 | 频率、额度、pause、黑白名单、重复提交 |
不要只验证“能反序列化”。合法交易仍可能携带错误订单、错误资产、错误商户或错误金额。
每个会提交链上交易的 API 都应维护 API 到 ABI 清单:
| 字段 | 说明 |
|---|---|
| API 名称 | 业务动作名称,不要求对外暴露路径 |
| Move function | 目标 module 和 entry function |
| sender 要求 | 用户、商户、管理员、任务账号或多签 |
| 参数顺序 | 每个参数的类型、顺序、精度 |
| 泛型参数 | 资产类型、权益类型 |
| 后端语义校验 | 需要和读模型或业务草稿比对的字段 |
| 合约校验 | 合约内必须重新验证的规则 |
| 成功事件 | 链上事件名和版本 |
| 本地异步任务 | 只写最小 payload,例如 tx hash 和业务 ID |
| 幂等键 | tx hash 和业务 ID 的组合规则 |
| 测试 | 成功、重复提交、参数篡改、链上失败、本地失败 |
事件同步和读模型
如果使用 event_bus 驱动异步消费者,handle_status 语义必须保持:
| 状态 | 含义 |
|---|---|
0 | unhandled,待处理 |
1 | handling,处理中 |
2 | handled,已处理 |
处理规则:
- claim 必须原子化,避免多个消费者同时处理同一事件。
handle_status=1必须有 lease 或超时回收。- 消费者必须支持重复事件、重复 tx hash 和已处理业务对象。
- 失败要区分可重试、永久错误和需要人工 hold。
- 消费者保留 last_error、retry_count、updated_at 和审计上下文。
读模型原则:
- 读模型字段必须标注来源:链上事实、本地投影、预估值或运营配置。
- 链上事件是最终事实,本地 DB 不能覆盖链上状态。
- 搜索投影必须从完整读模型生成,不能直接把 event payload 当文档真相。
- 所有读模型更新要可重放、可修复、可追踪。
- 对账链路必须能从用户地址追到业务对象、tx hash、链上事件、读模型、ContributionEvent 和 PowerStore。
推荐对账链:
wallet address
-> local member
-> business object id
-> tx hash
-> chain event
-> read model state
-> mature contribution
-> ContributionEvent
-> POC period
-> staged power
-> committed power
DApp 侧 POC 贡献模块
DApp 应在自身合约包内设计原生 contribution_manager,让成熟业务事实以可信方式进入 POC。
contribution_manager 负责:
- 识别成熟贡献事实。
- 记录待发放和已发放状态。
- 防止重复发放。
- 校验 pause 和权限。
- 调用
poc_contribution可信路径发放 equity token。 - 发出 DApp 自身贡献状态事件。
contribution_manager 不负责:
- 计算 POC power。
- 写 PowerStore。
- 绕过
poc_contribution自行发 ContributionEvent。 - 把支付成功直接变成 POC power。
前端必须区分以下状态:
| 状态 | 含义 |
|---|---|
| 业务已完成 | DApp 业务状态成熟,但未必可贡献 |
| 贡献已成熟 | 可以发放 equity token |
| 贡献已发放 | 已产生可信 ContributionEvent |
| 周期结算中 | Engine 正在结算或等待写回 |
| staged power | 已写入下一周期,尚未生效 |
| committed power | 当前周期已生效,可被下游读取 |
总结
Topo DApp 的工程实现应围绕三条主线展开:链上合约保护关键事实,链下系统提供可恢复的用户体验和读模型,POC 贡献路径只接受成熟且可审计的业务事实。只要这三条主线保持清晰,DApp 就可以在保留产品体验的同时进入可组合的 POC 生态。