Alert Source Discuss
⚠️ Draft Standards Track: ERC

ERC-7649: 适用于 NFT 的嵌入式联合曲线流动性

将流动性嵌入到非同质化代币(NFT)中,无需修改 ERC-721。

Authors Arif Khan <arif@alethea.ai>, Ahmad Matyana <ahmad@alethea.ai>, Basil Gorin (@vgorin), Vijay Bhayani (@unblocktechie)
Created 2024-02-28
Discussion Link https://ethereum-magicians.org/t/erc-7649-bonding-curve-embedded-liquidity-for-erc-721-non-fungible-tokens-nfts/19079
Requires EIP-721

摘要

本提案介绍了一种将类联合曲线流动性嵌入到 非同质化代币(NFT)中的标准,而无需修改 ERC-721 标准。 拟议的标准允许将嵌入式流动性合约(称为可交易份额) 连接到 ERC-721 NFT。可交易份额利用类联合曲线方法来吸引流动性,从而能够基于联合曲线价格公式交易 份额。

动机

ERC-721 标准缺乏嵌入基于联合曲线的流动性的特定机制,限制了基于 NFT 的项目的创意 可能性。本 EIP 解决了对标准化方法的需求,该方法可以将联合曲线 合约无缝集成到 ERC-721 NFT 中,从而无需修改 ERC-721 标准即可实现多样化和创新的实现。

拟议的标准侧重于通过引入一个框架来增强 ERC-721 标准,该框架用于将基于联合曲线的流动性嵌入到 NFT 中。这种方法为创建者提供了一个灵活且可定制的工具,可以通过联合曲线机制吸引 流动性,同时确保创建者因其贡献而获得有保障的费用。

适用于 NFT 的嵌入式联合曲线流动性标准在不同的行业中找到了引人注目的用例,为将类联合曲线流动性嵌入到 NFT 中提供了 动态解决方案。一个突出的用例围绕着 AI 服务的交叉领域,其中 NFT 模拟 AI 模型、GPU 资源池和存储资源池。让我们探讨 该领域中的两个具体用例:

  1. AI 模型市场:
    • 代表 AI 模型的 NFT 利用嵌入式流动性标准来嵌入类联合曲线流动性。 AI 模型提供商将其可交易份额合约附加到其 NFT,从而无需修改 ERC-721 标准即可无缝集成流动性 功能。
    • 联合曲线机制允许根据 AI 模型的供需对份额(或密钥)进行定价。 随着 AI 模型越来越受欢迎或展示出卓越的性能,流动性提供商将受到激励来买卖 份额,从而促进竞争性市场。
    • 创建者可以自定义联合曲线参数(例如斜率和截距),从而定制流动性机制以 匹配 AI 模型不断变化的性质。这确保了一个公平且适应性强的市场,流动性提供商被 有前途的 AI 模型所吸引,从而在流动性和 AI 创新之间建立了一种共生关系。
  2. 去中心化 GPU 和存储资源分配:
    • 在去中心化生态系统中,GPU 和存储资源池被表示为具有嵌入式可交易份额 合约的 NFT。这使资源提供商能够基于 联合曲线机制吸引流动性并竞争资源分配。
    • 联合曲线确定与 GPU 和存储资源相关的份额价格,反映了当前的 供需关系。提供商可以自定义联合曲线参数以优化其资源池的 吸引力,同时考虑可用资源、性能指标和历史使用情况等因素。
    • 有保障的创作费用激励资源提供商不断增强和优化其服务。 随着对 GPU 和存储资源的需求不断发展,嵌入式流动性标准确保提供商 因其贡献而获得公平的补偿,从而维持一个具有竞争力和响应能力的市场。

在这两种用例中,该标准都为提供商吸引和保留流动性提供了强大的激励。 类联合曲线机制的动态特性与 AI 模型和资源 池不断变化的格局相一致,从而在去中心化 AI 服务领域内促进了创新、竞争和流动性驱动的增长。

规范

本文档中的关键词“必须(MUST)”、“禁止(MUST NOT)”、“必需(REQUIRED)”、“应(SHALL)”、“不应(SHALL NOT)”、“应该(SHOULD)”、“不应该(SHOULD NOT)”、“推荐(RECOMMENDED)”、“不推荐(NOT RECOMMENDED)”、“可以(MAY)”和“可选(OPTIONAL)”应按照 RFC 2119 和 RFC 8174 中的描述进行解释。

  1. 联合曲线嵌入式流动性/可交易份额:
    • 嵌入式基于联合曲线的流动性__应该__通过单独的合约附加到 NFT。
    • 嵌入式基于联合曲线的流动性__禁止__嵌入到或修改 ERC-721 标准中。
    • 联合曲线合约__必须__通过联合曲线机制管理关联 NFT 的流动性。
  2. 联合曲线机制:
    • 联合曲线确定 NFT“密钥”(有时也称为“份额”)相对于其供应量的价格,从而鼓励流动性提供商基于曲线公式买卖 NFT 份额。
    • 实现__可以__允许创建者自定义联合曲线参数,例如斜率、截距 或任何其他相关参数。
    • 实现__可以__允许创建者自定义联合曲线的形状(曲线的公式)。
  3. 有保障的创作费用:
    • 该实现__必须__包括保证 NFT 创建者创作费用的机制,即 它__必须__保证创建者在买卖操作期间收到嵌入式流动性 合约产生的交易费用的百分比。
    • 该实现__可以__允许创建者定义交易费用。
  4. 支付机制:
    • 嵌入式流动性合约__必须__支持 ERC-20 代币或原生 ETH 作为支付, 它__可以__同时支持两者。

BondingCurve 接口

/**
 * @title Bonding Curve
 *
 * @notice A bonding curve definition
 *
 * @notice Bonding curve defines the price of the smallest unit of the asset as a function
 *      of the asset supply
 */
interface BondingCurve {
	/**
	 * @notice Bonding curve function definition. The function calculating the price
	 *      of the `amount` of shares given the current total supply `supply`
	 *
	 * @param supply total shares supply
	 * @param amount number of shares to buy/sell
	 * @return the price of the shares (all `amount` amount)
	 */
	function getPrice(uint256 supply, uint256 amount) external pure returns(uint256);
}

联合曲线嵌入式流动性 / TradeableShares 接口

/**
 * @title Tradeable Shares
 *
 * @notice Tradeable shares is a non-transferable, but buyable/sellable fungible token-like asset,
 *      which is sold/bought solely by the shares contract at the predefined by
 *      the bonding curve function price
 *
 * @notice The shares is bound to its "subject" – an NFT; the NFT owner gets the subject fee
 *      emerging in every buy/sell operation
 */
interface TradeableShares is BondingCurve {
	/**
	 * @notice Shares subject is an NFT defined by its ERC-721 contract address and NFT ID
	 *       Shares subject is an NFT the liquidity is embedded to
	 */
	struct SharesSubject {
		/// @dev ERC-721 contract address
		address tokenAddress;

		/// @dev NFT ID
		uint256 tokenId;
	}

	/**
	 * @dev Fired in `buyShares` and `sellShares` functions, this event logs
	 *      the entire trading activity happening on the curve
	 *
	 * @dev Trader, that is the buyer or seller, depending on the operation type is the transaction sender
	 *
	 * @param beneficiary the address which receives shares or funds, usually this is the trader itself
	 * @param issuer subject issuer, usually an owner of the NFT defined by the subject
	 * @param isBuy true if the event comes from the `buyShares` and represents the buy operation,
	 *      false if the event comes from the `sellShares` and represents the sell operation
	 * @param sharesAmount amount of the shares bought or sold (see `isBuy`)
	 * @param paidAmount amount of ETH spent or gained by the buyer or seller;
	 *      this is implementation dependent and can represent an amount of ERC-20 payment token
	 * @param feeAmount amount of all the fees paid, if any
	 * @param supply total shares supply after the operation
	 */
	event Trade(
		address indexed beneficiary,
		address indexed issuer,
		bool indexed isBuy,
		uint256 sharesAmount,
		uint256 paidAmount,
		uint256 feeAmount,
		uint256 supply
	);

	/**
	 * @notice Shares subject, usually defined as NFT (ERC-721 contract address + NFT ID)
	 *
	 * @dev Immutable, client applications may cache this value
	 *
	 * @return Shares subject as a SharesSubject struct, this is an NFT if all currently known implementations
	 */
	function getSharesSubject() external view returns(SharesSubject calldata);

	/**
	 * @notice Cumulative fee percent, applied to all the buy and sell operations;
	 *      the fee percent is defined with the 18 decimals, 10^18 corresponds to 100%
	 *
	 * @notice The fee can be combined from multiple fees which are sent to the various destinations
	 *
	 * @dev Immutable, client applications may cache this value
	 *
	 * @return protocol fee percent with the 18 decimals (10^18 is 100%)
	 */
	function getFeePercent() external view returns(uint256);

	/**
	 * @notice Shares issuer, the receiver of the shares fees
	 *
	 * @dev Mutable, changes (potentially frequently and unpredictably) when the NFT owner changes;
	 *      subject to the front-run attacks, off-chain client applications must not rely on this address
	 *      in anyway
	 *
	 * @return nftOwner subject issuer, the owner of the NFT
	 */
	function getSharesIssuer() external view returns(address nftOwner);

	/**
	 * @notice Shares balance of the given holder; this function is similar to ERC20.balanceOf()
	 *
	 * @param holder the address to check the balance for
	 *
	 * @return balance number of shares the holder has
	 */
	function getSharesBalance(address holder) external view returns(uint256 balance);

	/**
	 * @notice Total amount of the shares in existence, the sum of all individual shares balances;
	 *      this function is similar to ERC20.totalSupply()
	 *
	 * @return supply total shares supply
	 */
	function getSharesSupply() external view returns(uint256 supply);

	/**
	 * @notice The price of the `amount` of shares to buy calculated based on
	 *      the specified total shares supply
	 *
	 * @param supply total shares supply
	 * @param amount number of shares to buy
	 * @return the price of the shares to buy
	 */
	function getBuyPrice(uint256 supply, uint256 amount) external pure returns(uint256);

	/**
	 * @notice The price of the `amount` of shares to sell calculated based on
	 *      the specified total shares supply
	 *
	 * @param supply total shares supply
	 * @param amount number of shares to sell
	 * @return the price of the shares to sell
	 */
	function getSellPrice(uint256 supply, uint256 amount) external pure returns(uint256);

	/**
	 * @notice The price of the `amount` of shares to buy, including all fees;
	 *      calculated based on the specified total shares supply and fees percentages
	 *
	 * @param supply total shares supply
	 * @param amount number of shares to buy
	 * @param protocolFeePercent protocol fee percent
	 * @param holdersFeePercent shares holders fee percent
	 * @param subjectFeePercent protocol fee percent
	 * @return the price of the shares to buy
	 */
	function getBuyPriceAfterFee(
		uint256 supply,
		uint256 amount,
		uint256 protocolFeePercent,
		uint256 holdersFeePercent,
		uint256 subjectFeePercent
	) external pure returns(uint256);

	/**
	 * @notice The price of the `amount` of shares to sell, including all fees;
	 *      calculated based on the specified total shares supply and fees percentages
	 *
	 * @param supply total shares supply
	 * @param amount number of shares to sell
	 * @param protocolFeePercent protocol fee percent
	 * @param holdersFeePercent shares holders fee percent
	 * @param subjectFeePercent protocol fee percent
	 * @return the price of the shares to sell
	 */
	function getSellPriceAfterFee(
		uint256 supply,
		uint256 amount,
		uint256 protocolFeePercent,
		uint256 holdersFeePercent,
		uint256 subjectFeePercent
	) external pure returns(uint256);

	/**
	 * @notice Current price of the `amount` of shares to buy; calculated based on
	 *      the current total shares supply
	 *
	 * @param amount number of shares to buy
	 * @return the price of the shares to buy
	 */
	function getBuyPrice(uint256 amount) external view returns(uint256);

	/**
	 * @notice Current price of the `amount` of shares to sell; calculated based on
	 *      the current total shares supply
	 *
	 * @param amount number of shares to sell
	 * @return the price of the shares to sell
	 */
	function getSellPrice(uint256 amount) external view returns(uint256);

	/**
	 * @notice Current price of the `amount` of shares to buy, including all fees;
	 *      calculated based on the current total shares supply and fees percentages
	 *
	 * @param amount number of shares to buy
	 * @return the price of the shares to buy
	 */
	function getBuyPriceAfterFee(uint256 amount) external view returns(uint256);

	/**
	 * @notice Current price of the `amount` of shares to sell, including all fees;
	 *      calculated based on the current total shares supply and fees percentages
	 *
	 * @param amount number of shares to sell
	 * @return the price of the shares to sell
	 */
	function getSellPriceAfterFee(uint256 amount) external view returns(uint256);

	/**
	 * @notice Buy `amount` of shares. Sender has to supply `getBuyPriceAfterFee(amount)` ETH.
	 *      First share can be bought only by current subject issuer.
	 *
	 * @dev Depending on the implementation, ERC-20 token payment may be required instead of ETH.
	 *      In such a case, implementation must through if ETH is sent, effectively overriding
	 *      the function definition as non-payable
	 *
	 * @param amount amount of the shares to buy
	 */
	function buyShares(uint256 amount) external payable;

	/**
	 * @notice Buy `amount` of shares in the favor of the address specified (beneficiary).
	 *      Sender has to supply `getBuyPriceAfterFee(amount)` ETH.
	 *      First share can be bought only by current subject issuer.
	 *
	 * @dev Depending on the implementation, ERC-20 token payment may be required instead of ETH.
	 *      In such a case, implementation must through if ETH is sent, effectively overriding
	 *      the function definition as non-payable
	 *
	 * @param amount amount of the shares to buy
	 * @param beneficiary an address receiving the shares
	 */
	function buySharesTo(uint256 amount, address beneficiary) external payable;

	/**
	 * @notice Sell `amount` of shares. Sender gets `getSellPriceAfterFee(amount)` of ETH.
	 *      Last share cannot be sold.
	 *
	 * @dev Depending on the implementation, ERC-20 token may be payed instead of ETH.
	 *
	 * @param amount amount of the shares to sell
	 */
	function sellShares(uint256 amount) external;

	/**
	 * @notice Sell `amount` of shares in the favor of the address specified (beneficiary).
	 *      The beneficiary gets `getSellPriceAfterFee(amount)` of ETH.
	 *      Last share cannot be sold.
	 *
	 * @dev Depending on the implementation, ERC-20 token may be payed instead of ETH.
	 *
	 * @param amount amount of the shares to sell
	 * @param beneficiary an address receiving the funds from the sale
	 */
	function sellSharesTo(uint256 amount, address payable beneficiary) external;

	/**
	 * @notice Cumulative value of all trades; allows to derive cumulative fees paid
	 *
	 * @dev This value cannot decrease over time; it can increase or remain constant
	 *      if no trades are happening
	 *
	 * @return Sum of the modulo of all trading operations
	 */
	function getTradeVolume() external view returns(uint256);

原理

嵌入式流动性标准的设计选择背后的基本原理深深植根于为将类联合曲线流动性嵌入到 NFT 中提供一个强大而通用的框架。以下主要考虑因素影响了技术决策:

  1. 联合曲线嵌入式流动性 / 可交易份额合约:
    • 无缝集成:允许将嵌入式基于联合曲线的流动性合约连接到 NFT 而无需更改 ERC-721 标准的决定源于对无缝集成的期望。 这种方法确保 NFT 开发人员可以使用流动性机制增强他们的创作,而无需引入复杂性或要求修改广泛采用的 ERC-721 标准。

    • 流动性管理:联合曲线合约在通过联合曲线机制管理流动性中的作用至关重要。 这种设计选择促进了基于供需的动态和自动定价模型,从而有助于 NFT 份额的整体流动性和可交易性。

  2. 联合曲线机制:
    • 动态定价:采用联合曲线机制来确定可交易份额的价格符合鼓励流动性提供商参与买卖 NFT 份额的目标。 受曲线公式影响的动态定价确保了可交易份额的市场对不断变化的条件保持响应。

    • 创建者自定义:允许创建者自定义联合曲线参数(例如斜率和截距)的决定使他们能够根据 其项目的独特需求和特征定制流动性机制。这种自定义促进了 NFT 空间内的创造力和创新。

  3. 有保障的创作费用:
    • 创建者激励:强调保证 NFT 创建者的创作费用是维持蓬勃发展的生态系统的基础。通过使创建者能够指定和收取交易费用的一定百分比,该标准 协调了激励措施并奖励了创建者的贡献,从而营造了一个可持续且对创建者友好的环境。
  4. 支付机制:
    • 开发者自由:该标准的实现不可知方法的动机是为 开发者提供自由,让他们为其 NFT 项目选择和设计最合适的流动性机制。 无论是与 ERC-20 代币还是原生 ETH 交互,这种独立性都确保了开发者可以根据其项目的具体要求做出明智的选择。

这些设计选择背后的基本原理是创建一个可交易份额标准,该标准不仅在技术上合理,而且 灵活、适应性强,并且支持 ERC-721 生态系统内的多样化和创造性实现。

另请参阅:联合型同质化代币 (1671)

安全注意事项

  1. 智能合约安全:智能合约的实现应经过彻底的安全审计,以确保 抵御漏洞和攻击。

  2. 创作费用处理:处理和分配创作费用的机制应安全透明,以 防止任何恶意活动。

  3. 兼容性:开发者应确保与现有 ERC-721 实现的兼容性,从而 可以平滑集成嵌入式流动性标准。

  4. 用户体验:应考虑维护积极的用户体验,避免可能 阻碍采用利用嵌入式流动性的 NFT 项目的复杂性。

本安全注意事项部分反映了在实施中预测和解决潜在安全 挑战的重要性,从而确保其稳健性、兼容性和用户友好性。

版权

版权和相关权利通过 CC0 放弃。

Citation

Please cite this document as:

Arif Khan <arif@alethea.ai>, Ahmad Matyana <ahmad@alethea.ai>, Basil Gorin (@vgorin), Vijay Bhayani (@unblocktechie), "ERC-7649: 适用于 NFT 的嵌入式联合曲线流动性 [DRAFT]," Ethereum Improvement Proposals, no. 7649, February 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7649.