智能合约
本页介绍 Protocol v1.1.0 中主要的资金池和代金券合约。合约行为提供结算机制,但不能取代特定用途所适用的发行方披露、资金池规则或其他交易条款。
请通过 概念和术语 区分受治理的承诺资金池与 SwapPool,并区分交换结算与兑付出示、履约和核销。
代金券(GiftableToken)
GiftableToken 是一种 ERC20 代币,包含发行方可用于代金券的机制:
- 授权铸造——所有者可以指定写入方,由其通过
mintTo发行代币。 - 可选到期时间——到期时间为
0表示合约层面永不过期。否则,在配置的时间戳到达或超过后,转移、铸造和销毁都会回滚。任何人都可以直接调用expired,永久记录最终的applyExpiry状态。 - 供应量记账——
totalMinted和totalBurned显示累计供应活动。仅所有者可调用的burn函数会销毁所有者地址持有的代币。
代币合约 不会 说明发行方提供哪些商品或服务、设定兑付价值、证明发行方能力,或承诺现金兑换。GiftableToken 只有在发行方另行公布条款并依照条款行事时,才成为可兑付的承诺。发行方仍须准确说明并履行这些条款。
承诺资金池(SwapPool)
SwapPool 是代币保管库和交换结算引擎。它虽然公开资金池名称、符号和小数位等 ERC20 元数据,但 v1.1.0 合约不会铸造资金池份额代币。流动性通过把代币转入资金池来提供,合约所有者可以提取可用流动性。
组成与可选依赖项
| 配置 | 未配置时 | 可封存地址槽位 |
|---|---|---|
tokenRegistry | 任何代币都能通过资金池筛选检查 | 是 |
tokenLimiter | 存入没有合约层面的余额上限 | 是 |
quoter | 原始输入数量被视为原始报价输出数量 | 是 |
feePolicy | 资金池费用为零 | 是 |
feeAddress | 资金池费用不会累计为指定接收方可提取的费用 | 是 |
protocolFeeController | 不收取协议费 | 否 |
五个封存位会永久锁定当前的 feePolicy、feeAddress、quoter、tokenRegistry 和 tokenLimiter 地址,使相应设置函数无法替换它们。protocolFeeController 和 feesDecoupled 是初始化值,不在这五个封存位之内。
封存地址槽位不会冻结该地址上的合约。已封存的注册表、限制器、报价器或费用政策,以及已配置的协议费控制器,如果自身治理允许,仍然可以发生变化。ERC-1967 代理管理员也能升级资金池实现。因此,任何有意义的不可变性声明都取决于资金池所有者、代理管理员以及每个已配置依赖项的治理。
交换结算
进行交换时,SwapPool 会:
- 检查输入和输出代币是否通过可选注册表,并对请求的输入应用可选的资金池余额限制。
- 从调用者处转入输入代币,并测量实际收到的数量。定价使用这一实收数量,包括收取转账费的代币。
- 从已配置报价器获取总报价;如未配置报价器,则使用实际收到的原始数量。
- 计算资金池费用和任何额外协议费,然后检查输出代币的可用流动性。
- 把协议费直接发送给已配置的协议费接收方,把名义净输出转给接收方,并在已配置费用地址时记录资金池费用。
- 发出旧版
Swap事件以及信息更详细的SwapSettlement事件。
SwapSettlement 会记录发起方、两种代币、实收输入、总报价输出、发送的名义输出、接收方实际观察到的输出、资金池费用和协议费。如果输出代币本身收取转账费,名义输出和实收输出可能不同。旧版 fee 事件中的 Swap 字段只表示资金池费用。
六参数重载 withdraw(tokenOut, tokenIn, value, recipient, minAmountOut, deadline) 是带边界保护的执行路径。如果超过截止时间,或接收方观察到的余额增量低于 minAmountOut,它就会回滚。集成方应优先使用此重载,因为界面显示的报价只是暂时的:报价器状态、费用政策、流动性、限制和预言机数据都可能在执行前变化。较旧的三参数和四参数重载不提供这些资金池层面的边界。
叠加费用计算
资金池费用和协议费都会从总报价输出中扣除。协议费 不是从资金池费用中划出;资金池仍保留其完整计算费用。
例如,总报价为 100 个单位时:
- 2% 的资金池费用会为资金池累计 2 个单位;
- 如果协议费率为资金池费用的 10%,则另有 0.2 个单位直接发送给协议费接收方;以及
- 用户收到 97.8 个单位。
协议费计算以计算出的资金池费用和假设的 1% 费用基数两者中较高者为准。这样可以防止过低的资金池费用把协议费计算降到接近零。无效的合并费率会以 FeeTooHigh 回滚,而结算输出为零的报价会以 InsufficientOutput 回滚。
所有者与升级权限
合约所有者可以收取已累计的资金池费用,并调用 withdrawLiquidity,把任意可用的资金池代币转移到所选的非零地址。费用解耦时,已累计费用会从该流动性提取路径中预留;否则,它们仍属于资金池余额的一部分。除非另有可验证的治理控制建立这一结果,参与者不应把已存入的流动性理解为永久锁定。
配置封存不会移除这项流动性提取权限,也不会移除 ERC-1967 代理管理员单独拥有的升级权限。
估值模块
三个报价器都实现了 SwapPool 和 SwapRouter 使用的正向与反向报价函数:
DecimalQuoter——在价值按一比一对应的假设下进行无状态的小数位标准化。RelativeQuoter——进行小数位标准化,并应用由所有者管理的相对价格指数。未设置的代币指数默认按一比一对应。OracleQuoter——通过已配置的预言机为每种代币定价,使用全局或逐代币的陈旧度上限,并可选应用 0.9 至 1.0 的输出乘数。
OracleQuoter 的可靠性取决于数据源选择和管理。数据源的计价单位和方向必须一致,小数位必须正确,更新值必须为正且足够新;治理方可以替换数据源或更改新鲜度设置。数据源被操纵、更新延迟、网络中断、交易对配置错误或预言机所有者密钥丢失,都可能导致错误报价或使交换回滚。
OracleRelay 是可选的单数据源最新轮次中继器,与预言机接口兼容。指定写入方重新发布源数据;这里没有跨链证明,也不会存储轮次历史。中继器除检查时间戳不能在未来外,会接受写入方提交的数值。OracleQuoter 会另行拒绝非正数或陈旧答案,而中继器所有者可以更换写入方或使当前轮次失效。因此,用户必须评估源数据、写入方、中继器所有者和监测流程。
费用政策与限制
FeePolicy 以百万分之一为单位存储默认费率,并可为特定方向的交易对设置覆盖费率。除非合约外治理限制该权限,其所有者可以更改这些费率。
Limiter 存储特定资金池地址中某种代币的最大余额。所有者或获授权写入方可以更改上限。限制器启用时,上限为零会阻止存入;未配置限制器时,存入不设上限。
这些限制描述资金池中已配置的 代币风险敞口。它们本身不能把代币余额归类为贷款或法律债务,不能证明发行方能力,也不能保证履约。这些问题取决于发行方条款、资金池规则、向用户显示的交易以及适用法律。
协议费控制器
ProtocolFeeController 是可选的部署级费用组件。其所有者可以更改协议费率和接收方,或停用费用。多个资金池可以共用一个控制器,但协议并不要求每个网络只能使用一个控制器。
当控制器已启用并正确配置时,每次交换成功都会直接以输出代币向接收方支付费用。接收方如何使用这些资金——例如用于运营、监测、流动性支持或其他已公布目的——属于治理事项,不是合约作出的保证。