模块化智能合约实操指南:钻石标准(EIP2535)

  • BuildBear
  • 发布于 2024-02-27 10:51
  • 阅读 80

本文深入探讨了EIP-2535(Diamond标准)在区块链上创建模块化智能合约的原理与实践,介绍了其核心组件和特性,重点强调了智能合约的可升级性和模块化设计。通过一个实际操作示例,展示了如何使用Hardhat创建和部署基于Diamond标准的智能合约。

使用 Diamond 标准 (EIP2535) 进行模块化智能合约的实践指南

模块化智能合约系统允许在像以太坊这样的区块链平台上创建灵活且可扩展的去中心化应用 (DApps)。ERC-2535 支持创建模块化智能合约,使开发人员能够在部署后扩展和升级功能。

在本教程中,我们将深入探讨这个 Diamond 标准,解释其核心智能合约及其实际应用。让我们开始吧!

Diamond 标准究竟是什么?

Nick Mudge 提出了 EIP-2535,引入了函数选择器、面和钻石合约的概念。该标准通过将合约细分为称为 Facets 的较小组件,彻底改变了智能合约架构,实现了模块化和可升级性。这些 Facets 为一个单一的智能合约实体(称为 Diamond)提供了专业化功能。使用 Solidity 的 delegateCall 函数,Diamond 合约可以从其 Facets 执行逻辑,允许开发人员轻松地添加、替换或移除功能,而不会影响整体合约。

对于那些对委托调用感到好奇的人,委托调用是 Solidity 中的一项特性,它允许一个合约从另一个合约调用函数,同时保持调用合约的数据存储。

现在,你可能在想,为什么叫“Diamond”?我们知道,Diamond 不仅仅是一块宝石,而是一种由许多面组成的复杂结构,每个面都对它的整体美丽和强度做出了贡献。同样,在智能合约的世界中,diamond 是一个由多个较小的合约(称为 facets)组成的单一合约。每个 facet 都有特定的目的或功能,就像钻石的每个面在其外观中发挥作用一样。

那么,Diamond 标准如何与传统的代理标准不同呢?与传统的代理标准不同,Diamond 标准提供无与伦比的模块化和灵活性,使智能合约开发能够无缝适应不断变化的需求,并简化管理流程。

主要特征

  • 可升级性和扩展性:Diamond 标准使开发人员能够在部署后持续升级和扩展智能合约的功能。这促进了迭代开发,确保合约能够随着时间的推移而演变,以满足不断变化的需求。
  • 无合约大小限制:与传统智能合约不同,钻石没有最大合约大小的限制。这使得多个功能可以聚合到一个合约地址中,从而简化了部署和集成。
  • 降低Gas费用:钻石通过将多个合约压缩为一个实体并优化函数调用来促进Gas效率。这为复杂的 DApps 节省了成本,尤其是具有广泛功能的 DApps。
  • 模块化和灵活性:钻石的模块化架构允许将合约代码组织为称为 facets 的单独单元。Facets 可以独立部署和升级,增强了代码的可维护性和可重用性。

Diamond 标准的核心组件

Diamond

此接口设定了对 facets 进行修改的规则。简单来说,它概述了如何在钻石合约中添加、替换或移除功能,确保修改过程中的一致性和清晰性。

interface IDiamond {
enum FacetCutAction {Add, Replace, Remove}
// Add=0, Replace=1, Remove=2

struct FacetCut {
    address facetAddress;
    FacetCutAction action;
    bytes4[] functionSelectors;
}

event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}

IDiamondCut

通过实现此接口,合约确保可以通过灵活和可升级的方式添加、替换或移除函数,来修改其功能。

interface IDiamondCut is IDiamond {
    function diamondCut(
        FacetCut[] calldata _diamondCut,
        address _init,
        bytes calldata _calldata
    ) external;
}

IDiamondLoupe

这是一个提供查看和检索钻石合约方面信息的方法的接口。它提供了一种探索和查询钻石合约的 facets 的方法,使开发人员能够理解其结构和可用功能。

interface IDiamondLoupe {

    struct Facet {
        address facetAddress;
        bytes4[] functionSelectors;
    }

    function facets() external view returns (Facet[] memory facets_);
    function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_);

    function facetAddresses() external view returns (address[] memory facetAddresses_);
    function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_);
}

Diamond 存储

该库实现了遵循 Diamond 标准的钻石合约的存储管理,使开发人员能够轻松访问和操纵特定于钻石的存储变量。

library LibDiamond {
    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");struct FacetAddressAndSelectorPosition {
        address facetAddress;
        uint16 selectorPosition;
    }struct DiamondStorage {
        // 函数选择器 => facet 地址和选择器在选择器数组中的位置
        mapping(bytes4 => FacetAddressAndSelectorPosition) facetAddressAndSelectorPosition;
        bytes4[] selectors;
        mapping(bytes4 => bool) supportedInterfaces;
        // 合约的所有者
        address contractOwner;
    }function diamondStorage() internal pure returns (DiamondStorage storage ds) {
        bytes32 position = DIAMOND_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
    }
}

实现 Diamond 标准智能合约

以下是使用 Hardhat x BuildBear 创建简单的实现 Diamond 标准的逐步过程,它允许你创建自己的以主网为基础的私有测试网,并设置自己的原生和 ERC20 代币水龙头及区块链浏览器。

  • 在终端运行命令克隆仓库
git clone https://github.com/sanamummer/diamond.git
  • 现在更改目录并安装依赖项
cd diamond
npm install
  • 通过运行创建你的私有测试网
npm run createTestnet

一旦测试网上线,RPC、浏览器和水龙头的详细信息将添加到 testnet.json 文件中。

我们将创建一个示例存储 facet,用于更新和返回消息字符串,这将帮助我们理解钻石的工作原理以及状态变量如何在钻石和其 facet 之间共享。

现在,在 facet 文件夹中创建一个新文件,命名为 Storage.sol,并将以下代码添加到其中。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Storage {

    function getMessage() public view returns (string memory) {
        return libStorage.getMessage();
    }

    function setMessage(string memory _newMsg) public {
        libStorage.setMessage(_newMsg);
    }
}

library libStorage {
    bytes32 constant STORAGE_POSITION = keccak256("diamond.standard.storage");

    struct MStorage {
        string message;
    }

    function getMessage() internal view returns (string memory) {
        return diamondStorage().message;
    }

    function setMessage(string memory _newMsg) internal {
        diamondStorage().message = _newMsg;
    }

    function diamondStorage() internal pure returns (MStorage storage ds) {
        bytes32 position = STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
    }
}
  • 通过运行脚本部署合约
npx hardhat run scripts/deploy.js

耶!我们的钻石合约已部署并在 etherscan 上验证,成功部署后你将获得如下输出。

现在请转到 testnet.json 获取重要的 URL,比如水龙头,或者直接通过浏览器 URL 进行导航。使用 BuildBear 水龙头为你的账户添加资金,并使用读写功能与合约进行交互。

结论

Diamond 标准通过实现模块化和可升级性彻底改变了智能合约开发。它帮助开发人员在合约部署后添加新功能和修复错误。这在构建更加动态和适应性强的区块链解决方案方面迈出了重要的一步。

关于 BuildBear:

BuildBear 是一个专为 DApp 开发和测试而定制的平台。开发人员可以自由创建一个个性化的私有测试网沙箱,跨多个区块链网络。铸造无限的原生和 ERC20 代币的自由,加上 BuildBear 上快速的交易时间(不足 3 秒!),大大增强了 DApp 开发生命周期。该平台配备了旨在实时测试和调试的工具,确保开发人员能够毫不费力地跟踪复杂的区块链交易。

在以下平台与我们联系 Twitter | LinkedIn | Telegram | GitHub

作者:Sana

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

0 条评论

请先 登录 后评论