1Do App
Dex
maker 链下固定资产、数量、期限和 nonce;buyer 按订单类型用一次性 Token Pull 或原生币完成全额结算。
7 个章节onedo-dex
01
交易模型
Dex 是签名订单式交换应用。maker 不需要把资产存入池子或链上订单簿,而是在链下签署一份完整报价;只有 buyer 成交或 maker 取消时,maker 钱包才写入 consumed 状态。
价格直接由 amountIn / amountOut 或 nativeAmount / tokenAmount 表达。当前合约没有 AMM 曲线、流动性池、部分成交、撮合优先级或协议交易费。
- maker 资产在成交前始终留在 maker 钱包。
- buyer 的 ERC-20 支付只在当前结算交易中开放给 maker 钱包拉取。
- 订单必须一次性全额成交;成交与取消都会永久消费同一订单。
- 任何地址都可以提交有效成交,但不能改写 maker 已签署的资产与数量。
02
三类订单
- TokenForTokenOrder:maker 从钱包转出 tokenIn / amountIn,buyer 支付 tokenOut / amountOut。
- NativeForTokenOrder:maker 从钱包转出 nativeAmount,buyer 支付 erc20 / tokenAmount。
- TokenForNativeOrder:maker 从钱包转出 erc20 / tokenAmount,buyer 支付精确的 nativeAmount。
- expiry 为 0 时没有合约级到期限制;非零时,超过该时间戳的订单会失败。生产订单应使用明确期限。
- nonce 是签名订单的一部分,用于区分报价,但不是合约自动递增的账户 nonce;真正的防重放状态是订单被标记 consumed。
Signed order fields
struct TokenForTokenOrder {
address tokenIn;
address tokenOut;
uint256 amountIn;
uint256 amountOut;
uint256 expiry;
uint256 nonce;
}
struct NativeForTokenOrder {
address erc20;
uint256 nativeAmount;
uint256 tokenAmount;
uint256 expiry;
uint256 nonce;
}
struct TokenForNativeOrder {
address erc20;
uint256 nativeAmount;
uint256 tokenAmount;
uint256 expiry;
uint256 nonce;
}03
通用结算流程
步骤 1
构造并签署订单
maker 使用 EIP-712 域 Dex Order on 1Do / 1 签名,verifyingContract 是 maker 钱包地址。
步骤 2
选择正确付款入口
ERC-20 付款由 buyer 钱包建立 Token Pull;原生币付款则把精确 msg.value 直接发送到 maker 钱包的 Runtime 调用。
步骤 3
在 maker 钱包执行
Runtime 检查应用状态后 delegatecall Dex;应用验证参数、expiry、consumed 状态与 maker 的 ERC-1271 签名。
步骤 4
完成原子交换
应用锁定订单消费状态,移动双方资产并发出 Filled 事件;任一校验或转账失败都会回滚全部变化。
04
不同订单的资产路径
- Token → Token:buyer.executeWithTokenPull 以 maker 钱包为 target;Dex 从 buyer 拉取 tokenOut,再把 maker 的 tokenIn 转给 buyer。
- 原生币 → Token:buyer 同样用 Token Pull 支付 erc20;Dex 从 maker 钱包把原生币发送给 buyer。
- Token → 原生币:不使用 Pull。buyer 向 maker 钱包的 executeRuntimeApp 附带 msg.value,且金额必须与 nativeAmount 完全一致;随后 Dex 把 maker 的 Token 转给 buyer。
- 前两条 Pull 路径要求 buyer 钱包支持 Token Pull,但不要求 buyer 自己启用 Dex;原生币付款路径可直接调用 maker Runtime。maker 钱包必须启用当前 Dex logic,且 Registry 仍允许该地址。
- ERC-20 转账使用 SafeERC20;原生币收款方拒收时整笔结算失败。当前实现按常规 ERC-20 余额语义设计。
05
签名、取消与重放保护
- EIP-712 domain 绑定当前 chainId 与 maker 钱包。共享 Dex logic 地址不是 verifyingContract。
- maker 签名通过 maker 钱包的 ERC-1271 校验;签名覆盖订单类型中的全部字段。
- 订单不绑定指定 buyer,也不把 app logic 地址放入签名结构;任何 buyer 都可成交,切换兼容 logic 版本前应评估旧签名是否仍可使用。
- 成交状态保存在 maker 钱包的 ERC-7201 命名空间中,因此不同 maker 的订单状态彼此隔离。
- 三类 cancelSigned... 函数只能由 maker 钱包 self-call;取消与成交都把订单标记为 consumed。
- 合约当前没有公开 consumedOrders getter。前端应结合订单、模拟调用和 Filled / Cancelled 事件维护状态。
- TokenForToken 的事件与 consumed key 使用完整 EIP-712 digest;两类原生币订单使用 struct hash。索引方不应把三类 orderHash 按同一种算法计算。
- 从链下订单服务删除报价不等于链上取消;禁用应用也不会抹除订单,未来重新启用后,未过期且未消费的签名仍可能有效。
06
事件与主要失败条件
- 每种订单都有独立的 ...Filled(orderHash, buyer) 与 ...Cancelled(orderHash) 事件;通过 Runtime 执行时,日志 emitter 是 maker 钱包地址。
- 零 Token 地址、零数量、过期订单、已消费订单或错误 maker 签名都会失败。
- TokenForNativeOrder 的 msg.value 不精确会返回 InvalidNativeValue。
- Token 或原生币转账失败会回滚订单消费状态,不会留下半完成成交。
07
当前边界
不是 AMM 或链上订单簿
Dex 当前只处理三类 full-fill 签名订单,不提供部分成交、批量撮合、池内定价、链上报价发现或订单状态查询接口。前端和索引服务负责保存链下订单并跟踪成交与取消事件。