使用Zama的fhEVM构建具有密封投标的链上保密单价代币销售拍卖

  • ZamaFHE
  • 发布于 2025-03-19 18:35
  • 阅读 12

本文介绍了使用Zama的fhEVM构建链上保密单价拍卖的方案,用于代币销售。文章重点介绍了Palra提交的获胜方案,该方案在保密性和可扩展性之间取得了平衡,通过使用Fenwick树数据结构和部分隐藏(加密数量,价格可见)来实现。该方案使用Zama的fhEVM的编程隐私功能,允许参与者提交保密的竞标,从而实现更公平的代币销售。

使用 Zama 的 fhEVM 构建用于代币销售的链上保密单一价格拍卖,采用密封投标

Zama 的 fhEVM 的可编程隐私功能对于金融和代币应用尤其有用,例如代币销售拍卖,其中参与者的决策受到其他人的影响。保密拍卖是 Zama 赏金计划第 7 季的重点。

本季的赏金挑战开发者构建一个 Solidity 智能合约系统,用于启动单一价格拍卖 (SPA),采用密封投标的方式出售一定数量的可替代资产。

我们收到了许多高质量的提交,选择获胜者并非易事。但经过仔细评估,有三个项目脱颖而出:

这篇文章重点介绍了社区成员 Palra 提交的获奖作品,该作品在保密性和可扩展性之间找到了平衡。

关注赏金挑战

该赏金挑战开发者构建一个单一价格拍卖,采用密封投标出售一定数量的可替代资产。参与者提交保密投标,指定他们想要购买的代币数量和他们愿意支付的价格。

结算价格由出售的最后一个代币决定——它是中标中的最低价格。中标者是在可用代币限制内出价最高的人,所有中标均以相同的价格结算。

例如,假设有 10 个资产待售,有 4 个竞标者:

  • 竞标者 A: 4 个代币,价格为 100 USDC
  • 竞标者 B: 7 个代币,价格为 10 USDC
  • 竞标者 C: 8 个代币,价格为 42 USDC
  • 竞标者 D: 9 个代币,价格为 7 USDC

结算价格为 42 USDC。竞标者 A 获得 4 个代币,而竞标者 C 获得 6 个代币(在要求的 8 个代币中)。两者均支付每个代币 42 USDC。拍卖组织者收取 420 USDC (10 * 42)。

如果拍卖没有售罄,开发者必须定义一个解决方案,例如退款或以最低价格执行。除了处理边缘情况外,主要的技术挑战是计算结算价格。在 Solidity 中使用 TFHE 对保密投标进行排序和排序在计算上是昂贵的,并且受到 gas 限制(即,区块大小限制)的约束。

大多数提交都优先考虑保密性,但这通常以大型拍卖中的可扩展性为代价。Palra 提交的获奖作品在这两者之间取得了有趣的平衡。

关注获奖作品

获奖作品引入了两个关键的设计选择:(1)使用专用数据结构存储投标,以及(2)选择部分隐藏 - 加密数量,同时保持价格可见。

该提交使用了 Fenwick 树,这是一种非常适合 EVM 的数据结构。它支持三个关键操作——询问、更新和搜索——每个操作的复杂度均为 O(log n),其中 n 是竞标者的数量。这使得它在拍卖中非常有效,同时避免了代价高昂的初始化。该实现利用了其中两个操作:

  1. 更新操作插入新的投标。
  2. 搜索操作计算结算价格。
    function update(Storage storage _this, uint16 atKey, euint128 quantity) internal {
        if (atKey == 0) revert FT_InvalidPriceRange();

        _this.largestIndex = TFHE.select(
            TFHE.eq(quantity, 0),
            _this.largestIndex,
            TFHE.select(TFHE.gt(atKey, _this.largestIndex), TFHE.asEuint16(atKey), _this.largestIndex)
        );
        TFHE.allowThis(_this.largestIndex);

        uint16 index = atKey;

        while (index >= atKey) {
            _this.tree[index] = TFHE.add(_this.tree[index], quantity);
            TFHE.allowThis(_this.tree[index]);

            unchecked {
                index += lsb(index);
            }
        }

        _this.tree[0] = TFHE.add(_this.tree[0], quantity);
        TFHE.allowThis(_this.tree[0]);
    }

要更深入地了解此功能的工作原理,请查看我们的文档

在计算结算价格时,如果在树中未找到拍卖的总代币,系统将默认为注册的最低价格。每个投标的添加还会单独跟踪 Fenwick 树中的最低投标价。

获奖作品引入了一个自定义 Solidity 库,HalfEncryptedFenwickTree。这种数据结构通过避免在结算拍卖时进行完全排序来提高可扩展性。值得注意的是,该库用途广泛,可以重新用于其他用例。

该提交还包含来自 Zama 的 fhevm-contracts 存储库的关键构建块,包括:

关注拍卖过程

拍卖创建和初始化

首先,拍卖所有者部署一个具有以下参数的合约:

  • auctionToken – 正在出售的代币(必须遵循 IConfidentialERC20 接口)。
  • auctionTokenSupply – 可供出售的总供应量。
  • baseToken – 用于投标的代币(也遵循 IConfidentialERC20 接口)。
  • auctionEnd – 拍卖结束的时间戳。
  • minPrice – 最低投标价。
  • maxPrice – 最高投标价。
    constructor(
        address _auctioneer,
        IConfidentialERC20 _auctionToken,
        uint64 _auctionTokenSupply,
        IConfidentialERC20 _baseToken,
        uint256 _auctionEnd,
        uint64 _minPrice,
        uint64 _maxPrice
    ) Ownable(_auctioneer) EncryptedErrors(uint8(type(ErrorCodes).max))

创建拍卖后,所有者(组织者)必须存入拍卖的代币。这会触发对网关的请求,网关会验证存入的金额是否足以开始拍卖。

主动竞标阶段。

用户通过指定价格(以明文形式)和数量(加密形式)来提交投标。由于价格保持公开,因此确保拍卖保密性需要提交多个投标,包括0 值投标——加密数量为 0 的投标。

    function bid(
        uint64 _price,
        einput _encryptedQuantity,
        bytes calldata _inputProof
    ) external onlyState(AuctionState.Active) nonReentrant {

例如,竞标者 A 可能会以 10 USDC、50 USDC、100 USDC 和 1000 USDC 提交投标,所有这些都具有加密的数量。只有 100 USDC 的投标才会有非零数量。观察者会看到可能的价格,但不知道哪个投标是真实的。

该合约还包括错误处理,并在记录加密金额之前验证投标数量是否已正确转移。

拍卖结算。

拍卖结算阶段确定结算价格。

虽然将值插入 HalfEncryptedFenwickTree 不需要解密,但结算是一个迭代过程,涉及索引加密数量。在树上执行二进制搜索,根据加密值向左或向右分支。

结算依赖于异步解密方案,该方案的工作方式如下:

  1. 合约请求解密加密值。
  2. 网关触发回调,返回明文值。
    function stepWithdrawalDecryption()
        external
        onlyState(AuctionState.WithdrawalPending)
        checkTimeLockTag(TL_TAG_COMPUTE_SETTLEMENT_STEP)
    {
        uint256[] memory cts = new uint256[](1);
        bytes4 selector;
        if (TFHE.isInitialized(_searchIterator.foundIdx)) {
            cts[0] = Gateway.toUint256(_searchIterator.foundIdx);
            selector = this.callbackWithdrawalDecryptionFinal.selector;
        } else {
            cts[0] = Gateway.toUint256(_searchIterator.idx);
            selector = this.callbackWithdrawalDecryptionStep.selector;
        }

        Gateway.requestDecryption(cts, selector, 0, block.timestamp + CALLBACK_MAX_DURATION, false);
        _startTimeLockForDuration(TL_TAG_COMPUTE_SETTLEMENT_STEP, CALLBACK_MAX_DURATION);
    }

认领阶段。

认领过程是拍卖的最后阶段。

  • 以等于或高于结算价格的投标的用户可以根据其加密的投标数量认领拍卖资产。
  • 拍卖所有者可以提取收取的资金。
  • 未中标的参与者——以低于结算价格的投标的用户——可以收回其转移的代币。

结论

虽然未经审计,但此实现提出了一种在 EVM 约束内进行密封拍卖的有前途的方法,利用 Zama 的 fhEVM 实现保密性。你可以在以下位置查看本赛季获奖赏金的完整实现:GitHub – palra/zama-bounty-confidential-auction。如果你希望了解代码的架构设计,请查看用户指南文档。请记住,智能合约存在风险,此提交是外部贡献者的概念证明。

附加链接

  • 原文链接: zama.ai/post/onchain-con...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
ZamaFHE
ZamaFHE
Zama是一家开源密码学公司,专注于为区块链和人工智能构建最先进的完全同态加密(FHE)解决方案。