概述

如何对早期的想法或者应用进行价值共识,并参与投资?这在去中心化世界是一个巨大的挑战。ERC7527 遵循“信贷创造货币”的共识,提出了一种基于 Premium 驱动的去中心化定价的范式。

在本文中,我们将深入介绍 ERC7527 的原理及协议细节,进一步介绍连续报价模型的运作原理及其巨大优势。同时,我们也会介绍一些基于 ERC7527 的可编程性和可组合性而产生的拓展应用。

ERC7527

上一篇文章 中,我们介绍了目前常见的纯链上定价模型,其中也介绍了 ERC7527 的特殊的连续报价模型并给出了该模型的数学表示,但上一篇文章对于 ERC7527 的介绍是较为简单的,在本节中,我们将着重介绍 ERC7527 的原理、协议细节。

ERC7527 提出了一种通过发行 ERC7527 代币 给应用价值共识的新范式。ERC7527 代币的价格实际上就量化了应用的市值($\text{应用市值} = \text{ERC7527 价格} \times \text{数量}$)。这种方法将对应用的价值共识转化为了对 ERC7527 代币的定价。ERC7527 代币的定价分为以下两个部分:

  1. 报价。ERC7527 提供了对外买入(wrap)和卖出(unwrap)报价的接口,允许开发者自己实现
  2. 定价。基于 ERC7527 的 FOAMM(Function Oracle Automated Market Maker) 通过 wrap 添加内部流动性实现了买入定价,或通过 unwrap 移除内部流动性实现了卖出定价。这种方案无需依赖外部的流动性提供者

对于 ERC7527 代币的买入报价和定价的问题,ERC7527 则充分提供了可编程性。具体来说,用户可以调用以下函数获取报价:

function getWrapOracle(bytes memory data) external view returns (uint256 price, uint256 fee);

而 ERC7527 开发者则需要在开发过程中设计报价模型来最终给出报价。当用户调用 getWrapOracle 获得当前的报价后,用户可以选择向 ERC7527 的池子内注入流动性以实现报价到定价的转化。具体来说,用户可以调用 FOAMM 内的 wrap 函数来注入流动性:

function wrap(address to, bytes calldata data) external payable returns (uint256);

对于 ERC7527 代币的卖出报价和定价问题,ERC7527 使用了 FOAMM 构建的池子解决了卖出报价到定价的转化,用户可以通过池子将资产销毁、移除内部流动性实现退出。这里可能存在一个问题,即池子内的流动性由谁提供的问题。在上文中,我们提到 FOAMM 通过 wrap 添加内部流动性,这部分就是池子内流动性的来源。ERC7527 使用 FOAMM 将用户买入资产所支付的流动性注入到池子内以充当退出流动性。对于开发者而言,只需要给出卖出报价就可以,由于池子内存在流动性,卖出报价就是卖出定价。具体来说,开发者需要实现以下函数实现卖出报价功能:

function getUnwrapOracle(bytes memory data) external view returns (uint256 price, uint256 fee);

开发者可以基于池子的流动性构造任意的卖出报价函数,需要注意的是,卖出报价最终应当保持池子的清算平衡。用户可以随时调用 getUnwrapOracle 获取当前的 ERC7527 代币的卖出报价,并可以选择进一步调用 FOAMM 的 unwrap 函数来销毁 ERC7527 代币以获取池子内的卖出报价数量的代币:

function unwrap(address to, uint256 tokenId, bytes calldata data) external payable;

总结来说,对于用户而言,ERC7527 的交互仅有两部分:

  1. 调用 getWrapOracle 函数读取当前的买入报价,假如买入报价合适则调用 wrap 函数注入代币获得 ERC7527 代币
  2. 调用 getUnwrapOracle 函数读取当前的卖出定价,假如卖出定价合适则调用 unwrap 函数销毁持有的 ERC7527 代币提取池子内的卖出报价数量的代币

在上文给出的 getWrapOraclegetUnwrapOracle 函数的返回值内都出现了 pricefee 选项,其中 price 代表当前 wrap 或者 unwrap ERC7527 代币所需要支付的代币数量,而 fee 则代表手续费,无论是 wrapunwrap 操作,用户都需要支付一定数量的手续费,这些手续费最终被指定用户提取。

ERC7527 是一种标准代币,与 ERC20 代币等类似,也有其代币地址。ERC7527 存在如下定义字段:

/**
 * @dev The settings of the agency.
 * @param currency The address of the currency. If `currency` is 0, the currency is Ether.
 * @param premium The base premium of the currency.
 * @param feeRecipient The address of the fee recipient.
 * @param mintFeePercent The fee of minting.
 * @param burnFeePercent The fee of burning.
 */
struct Asset {
    address currency;
    uint256 premium;
    address feeRecipient;
    uint16 mintFeePercent;
    uint16 burnFeePercent;
}

上述结构体定义了 ERC7527 最核心的属性,其中 currency 代表用户提供哪种代币来铸造 ERC7527 代币,premium 指 ERC7527 代币的初始报价,feeRecipient 代表 wrapunwrap 交互过程中的手续费接收地址,而 mintFeePercentburnFeePercent 则代表 wrapunwrap 的手续费率。

ERC7527 代币具有权利金(premium)的波动特征,在上文函数定义内使用了 price 一词,即 Asset 结构体内的 premium

ERC7527 定义了三种不同的模块:

  1. App App 合约地址是 ERC7527 代币合约地址。ERC7527 要求 App 合约需要继承 ERC721Metadata 的相关接口。而且该合约需要暴露 mint 和 burn 接口以方便池子调用,且 mint 和 burn 接口仅能由池子调用以避免恶意铸造 ERC7527 代币导致池子清算不平衡
  2. Agency Agency 是上文频繁提到的池子和 FOAMM 所处的合约,也是与用户交互的核心合约,上文提到的 getWrapOracle/wrap/getUnwrapOracle/unwrap 函数都位于此合约内,该合约存储用户买入(wrap)时注入的代币以备用户退出(unwrap)时使用。该合约是 ERC7527 代币清算的合约
  3. Factory 这是一个辅助合约,该合约的功能是简化 App 和 Agency 的部署以方便用户部署 ERC7527 代币

三种组件之间的关系可以参考下图:

ERC7527 Flow

ERC7527 内的 App 和 Agency 是存在双向绑定关系的。从代码角度看,App 的 mintburn 函数仅能由 Agency 调用,而且 ERC7527 也约定了一系列函数以方便用户在已知 App 的情况查询 Agency 地址(getAgency 函数),和已知 Agency 的情况下查询 App 的地址(getStrategy 函数)。从流动性角度来看,App 内的每一个 ERC7527 代币都有对应的池子内的的代币,这保证了池子的清算平衡。

这种使用 ERC7527 代币对应用进行去中心化价值共识的方案是一种革命性的创新,这种方案引入了一种先发货币后建立应用的新范式。对于最早期的应用,开发者就可以直接使用 ERC7527 的 Factory 进行 ERC7527 代币部署。用户可以调用 wrap 函数铸造 ERC7527 代币来参与项目的早期投资,也可以调用 unwrap 函数来退出投资。对于开发者而言,ERC7527 代币的价格可以为早期应用提供有效的市值。随着应用开发和 ERC7527 代币持有者增加,应用市值增长,ERC7527 代币的持有者和应用开发者都可以获得市值增长的激励。

连续报价模型

在上一节中,我们充分讨论 ERC7527 的运作原理,但上一节内并没有详细介绍买入报价模型的构造。ERC7527 在此处仅提供了 getWrapOracle 接口,而报价模型具体实现完全依靠开发者。在本节中,本文将提出一种较为通用的买入报价模型。

ERC7527 的买入报价应当同时考虑微观和宏观两种角度。

宏观来看,我们预期 ERC7527 代币的报价应当伴随着 ERC7527 代币持有量的增加而增加。更加具体来说,调用 getWrapOracle 获得的当前 ERC7527 代币的报价不应当低于定价(或称为“上一次的买入成交价”)。

ERC7527 代币的报价应随着 ERC7527 代币持有量的增加而增加会带来一个很有趣的结果,即 ERC7527 代币本身将具有信用扩张机制。更加具体来说,会出现 ERC7527 代币市值大于 TPL (Total Premium Locked)。这种信用扩张机制会使得每一个 ERC7527 代币的持有人获得信用的增长。

在上文,我们没有提及 unwrap 卖出交易,unwrap 卖出交易会直接使得买入交易的报价下降。我们可以使用一种最简单的基于栈的系统来实现卖出推动买入报价下降的方案:

Wrap Stack

我们将 ERC7527 内所有的历史定价存储在栈内部,当每一次新的定价 new price 形成时,我们就将其推入栈内,买入报价模型会依赖于栈内最新的定价给出买入报价。而当用户卖出时,我们直接将最新的买入定价 new price 作为卖出定价,从 Agency 内向用户转出代币并同时将该定价从栈内弹出。此时报价模型还是依赖于栈内最新的定价 price 2 对外给出报价。由于 price 2 是小于 new price 的,所以此时报价模型在 unwrap 后,对外给出的基于 price 2 的报价也会低于过去以 new price 为基础给出的报价。当然,这种基于栈的卖出报价只是一种最简单的卖出报价方案。

从微观上,报价模型应该具有某种类似荷兰式拍卖的价格调整机制。荷兰式拍卖最大的特点是将时间引入了报价模型,随着长时间的无人成交,价格应当自动下降。但荷兰式拍卖具有一个较为严重的缺点,由于随着时间推移价格一定会下降,存在等待博弈的囚徒困境,最终导致报价不断下降。一个良好的报价模型在微观层面上应当包含时间因子,且也应该存在上涨和下降两段。

综上所述,一个良好的报价模型应当符合以下要求:

  1. 给出的买入报价不应当低于已形成的定价。这是为了保证宏观上随着 ERC7527 代币的保有量增加,买入报价和定价都上涨
  2. 具体的报价函数应该具有时间因子,且应当同时包含上涨和下降两阶段

除此外,我们还希望报价模型可以满足以下应用的成长规律:

  1. 早期阶段具有高成长性
  2. 中后期阶段具有较为稳健的成长性

我们会在后文具体介绍解决方案。

首先,满足宏观要求实际上很简单,我们需要在报价模型内纳入定价($p_{n-1}$)作为因子。然后,对于微观需求,我们可以将函数分段来解决问题。最终,我们可以获得以下报价函数:

$$ p_n = \begin{cases} \frac{2}{1+e^{\lambda_{up} \Delta_{m}}} \cdot p_{n-1} + c & \Delta_m \le \Delta_{target} \\ p_{max}e^{-\lambda_{down} \Delta_{m}} &\Delta_m > \Delta_{target} \end{cases} $$

关于此报价函数的参数的具体含义,读者可以参考 上一篇文章 内给出的介绍。我们在此处直接给出此定价函数的图像:

ERC7527 Auction

在上图内,x 轴代表当前时间距离上一次成交的时间间隔单位,而 y 轴代表当前报价与上一次成交价格之间的比值,值得注意的是,当价格下降到低于上一次成交价时,报价模型只会报出上一次等于上一次成交价的报价,这是为了满足报价模型的宏观要求。我们直观看到上述报价模型既存在早期的上涨阶段,又存在后期的类似荷兰拍卖的下降阶段,这有效满足了报价模型的微观要求。此处,我们可以看到在上涨阶段的早期存在跳跃式上涨,这是为了避免在连续铸造过程中出现的 ERC7527 的持有量上涨但价格没有发生显著变化的情况。

我们建立一个环境来模拟上述报价模型,模拟结果如下:

Auction Step 1 Result

在模拟的走势 K 线图中,第一栏代表当前的 ERC7527 代币的价格走势,而第二栏则代表当前 ERC7527 代币的持有数量,此数量会随着 wrap 操作而增加,随着 unwrap 操作而减少。从代码层面来说,第二栏实际上是调用 App 的 totalSupply 函数获得的。第三栏则代表当前 wrapunwrap 的次数,其中绿线则代表 wrap 的次数,而红线代表 unwrap 的次数。

上图展示了部分池子的早期运作情况,可能早期由于共识不足等原因,用户进进出出而导致定价长时间在初始价格左右波动,直到一些利好产生,用户选择买入但随后被早期用户砸盘返回初始价格,最后随着 ERC7527 代币持有人增加,定价在波动中震荡上行。

通过上述简单的模拟,我们可以看到基于连续报价模型的一个极其重要的优点,即用户的买入操作直接影响到了报价流程,这导致几乎没有可能两种 ERC7527 代币走出相同的 K 线图,极大提高了系统的博弈复杂度。

下图展示了一段具体的报价变化,其中 B 代表买入(wrap),而 S 代表卖出(unwrap)。我们可以看到整个报价模型在宏观上每一次买入的成交价都不低于上一次的成交价,而每一次卖出都使用了之前已存在的买入定价,因此这个图像具有一定的对称性。

Auction Step 1 BS Result

我们实际上解决了上述报价模型的宏观和微观要求,同时在报价上也满足了“早期阶段具有高成长性”的成长规律。接下来,我们需要解决一个问题,即如何在报价上实现应用后期的稳健成长性。早期报价的高涨幅是与应用的早期高成长相匹配。中后期的报价需要与应用的稳健发展相匹配,所以我们需要在中后期构建稳健成长的报价系统。

由此,我们决定通过分段解决此问题,即在早期报价内使用高成长性的报价系统,而在后期使用稳健成长的报价系统。当然,除了本文介绍的早期和后期的两段分割外,开发者可以根据自身情况进行更多段的分割,比如在早期、中期、后期使用不同的成长函数。

事实上,我们还是使用了与早期一致的报价函数,但修改了其部分参数,修改后的报价函数曲线如下:

Auction Step 2

相比于早期报价函数,我们可以看到后期报价函数的初始涨幅更低。上图的 x 轴依旧使用了与上次成交间隔的时间单位作为 x 轴,但需要注意此处的时间单位是小于早期报价函数的。

我们尝试模拟 ERC7527 代币供应量从 0 达到 20000 期间的成交价格变化情况,我们获得了以下走势 K 线图:

Auction Large Result

上述走势 K 线图的设定的最初报价为 0.1。在供应量达到 20000 时,价格从最初的 0.1 上涨为 300,涨幅达到了 3000 倍。

当然,有些应用可能无法一帆风顺的走向成功。以下走势 K 线图展示了在早期蓬勃发展,突然遭遇危机导致用户退出的价格变化情况:

Auction Desc

上述几个案例证明我们所提出的报价模型是有效的,其满足了应用的成长规律,既存在早期的高成长,也存在后期的稳健成长。这些优势是因为我们采用了分段的报价模型,在早期和后期使用了参数不同的报价函数。另一方面,因为报价函数是连续的,所以用户可以等待报价函数给出预期的报价,而且报价的具体情况会随着用户的行为发生变化。这使得在本节介绍的报价模型内,不仅存在用户与报价模型的博弈,也存在的是用户之间博弈。而用户之间博弈是极其复杂,这导致很难根据报价模型反向推导出一种策略以获取无风险收益。

拓展应用

在本节中,我们将介绍 ERC7527 的以下几种拓展应用:

  1. ERC7527 作为 AI 应用的激励层
  2. ERC7527 作为其他应用,特别是借贷应用的原子性预言机

AI 应用激励层

AI 应用需要全新的激励层,而 ERC7527 可以为 AI 应用带来系统化的激励层,而 ERC7527 代币则是激励层的核心资产。

AI 应用在发展的最早期部署 ERC7527 代币对其应用进行价值共识,此时 AI 应用就有了一个市场认可的估值,而用户也可以直接通过 wrap 操作来持有 ERC7527 代币投资 AI 应用。从市值角度来看,伴随着 AI 应用的发展和 ERC7527 持有量的增加,AI 应用的开发者和 ERC7527 代币的持有者都会获得市值上涨所带来的巨大激励。

AI 应用也可以进一步使用分红措施激励用户。AI 应用直接在以太坊二层要求用户使用代币进行支付。用户可以调用合约来支付 AI 应用的费用。这些锁定在支付合约内的费用定期被划转到分红合约内,ERC7527 代币的持有者可以直接在分红合约内提取收益,而 AI 应用开发者也可以在分红合约内部提取另一部分收益。

在技术实现上,ERC7527 代币存在对 ERC721 的继承,这意味着 ERC7527 代币可以借助 ERC6551 协议生成 ERC6551 账户合约。而我们可以通过一些技术方案将 ERC7527 代币的 ERC6551 账户跨链到以太坊二层。具体技术实现路径如下:

ERC6551 Bridge

当用户持有 ERC7527 代币后,可以调用位于以太坊主网内的 ERC6551 工厂合约来为 ERC7527 代币部署 ERC6551 账户,然后使用 ERC6551 账户调用部署在主网内的 ERC6551 桥接合约,桥合约会通过跨链桥调用位于以太坊二层内的 ERC6551 工厂合约为用户部署一个位于二层的 ERC6551 账户。ERC6551 跨链部分存在一个最简实现,开发者可以参考 ERC6551Mirror 内的代码,此仓库使用 Chainlink CCIP 实现了 ERC6551 的跨链操作。

当 ERC6551 跨链完成后,用户可以使用该 ERC6551 账户提取分红合约内的奖励。

原子性预言机

ERC7615 是有趣的 ERC,其具体内容是约定了一种原子性的通用的合约之间的推送关系。这种简单的推送协议可以构造出原子性的预言机,使得借贷协议等协议的开发难度显著降低。

ERC7615 的运作原理如下图:

ERC7615 Flow

当用户 (Client) 调用发送合约 (Publisher) 的某些函数时,发送合约会查询该函数是否存在一些订阅合约,如果存在则调用订阅合约的 exec 函数来推送一些内容。上述流程最大的特点是原子性。假如订阅合约对于推送数据的处理出现问题,那么调用推送合约的交易(即上图内的 Call somefunc(...) 交易)也会直接报错。

在 ERC7527 内,我们多次提到 ERC7527 给出的卖出报价实际上就是卖出定价,任意持有 ERC7527 代币的用户都可以以卖出定价提取 Agency 内的代币。那么,我们是否可以将 ERC7527 的卖出定价推送给借贷协议来实现接借贷协议内的清算?

ERC7527 With ERC7615

答案是可以的。而且由于连续报价模型在宏观上遵循买出报价随着 ERC7527 保有量上涨而上涨的属性,借贷协议并不需要关心 ERC7527 内的 wrap 操作,而只需要关心会导致价格下降的 unwrap 交易。我们可以在 unwrap 函数内部嵌入 ERC7615 的推送,将当前的 unwrap 的卖出定价直接推送给借贷协议,当借贷协议获得推送的 unwrap 定价时,就可以根据其价格信息对借贷协议内使用 ERC7527 代币作为担保品的头寸进行清算。一旦某一借贷头寸需要被清算,那么借贷协议可以执行 unwrap 操作提取 ERC7527 Agency 内的代币来平仓借贷头寸。

比较令人兴奋的是,上述操作是原子性的,即假如借贷协议的清算失败,那么 ERC7527 的 unwrap 操作也不会成功,这意味着借贷协议完全规避了穿仓风险。

事实上,任何协议都可以在 ERC7527 内获取其推送的卖出定价,这意味着开发者只需要编写一个 ERC7615 的接受接口,就可以获得一个资产的定价并进一步完成其他操作。

在 ERC7527 内,因为 ERC7527 代币在合约上存在对 ERC721 的继承,所以开发者可以对 ERC7527 代币进行其他赋能。当用户使用传统质押方案,比如直接将 ERC7527 转移给质押合约时,用户就丧失了 ERC7527 代币的其他权益,所以 ERC7527 代币需要一种全新的无需资产转移的质押方案。

基于 ERC7615 的推送机制,可以设计出这种无需资产转移的质押方案。具体来说,建立 ERC7527 Agency 合约内的 unwrap 与质押合约的推送关系。质押的用户可以与 ERC7527 质押合约交互进行 ERC7527 代币的质押,但这一过程并不需要将 ERC7527 代币转移进质押合约。此时,ERC7527 代币可以获得质押合约内分红。当用户 unwrap 已质押的 ERC7527 代币时,Agency 合约会使用 ERC7615 将此消息推送给质押合约,质押合约将解除指定 ERC7527 代币的质押状态并进行最终清算。

在此过程中,ERC7615 保证了质押系统的清算问题,确保了已销毁的 ERC7527 代币不可能获得质押收益。