全面掌握Solidity智能合约开发

2024年09月25日更新 796 人订阅
原价: ¥ 46 限时优惠
专栏简介 跟我学 Solidity :开发环境 跟我学 Solidity:关于变量 跟我学 Solidity : 变量的存储 跟我学 Solidity :引用变量 跟我学 Solidity :函数 跟我学 Solidity :合约的创建和继承 跟我学 Solidity :工厂模式 用Web3.js构建第一个Dapp 跟我学Solidity:事件 Solidity 中 immutable (不可变量)与constant(常量) [译] Solidity 0.6.x更新:继承 解析 Solidity 0.6 新引入的 try/catch 特性 探究新的 Solidity 0.8 版本 探索以太坊合约委托调用(DelegateCall) 停止使用Solidity的transfer() 使用工厂提高智能合约安全性 Solidity 怎样写出最节省Gas的智能合约[译] Solidity 优化 - 编写 O(1) 复杂度的可迭代映射 Solidity 优化 - 控制 gas 成本 Solidity 优化 - 减少智能合约的 gas 消耗的8种方法 Solidity 优化 - 如何维护排序列表 Solidity 优化:打包变量优化 gas 使用 Solidity 瞬态存储操作码 在 Solidity中使用值数组以降低 gas 消耗 Gas 优化:Solidity 中的使用动态值数组 计算Solidity 函数的Gas 消耗 Solidity 技巧:如何减少字节码大小及节省 gas 一些简单的 Gas 优化基础 "Stack Too Deep(堆栈太深)" 解决方案 智能合约Gas 优化的几个技术 合约实践:避免区块Gas限制导致问题 如何缩减合约以规避合约大小限制 Solidity 类特性 无需gas代币和ERC20-Permit还任重而道远 智能合约实现白名单的3个机制 Solidity智能合约安全:防止重入攻击的4种方法 Solidity 十大常见安全问题 [译]更好Solidity合约调试工具: console.log 智能合约开发的最佳实践 - 强烈推荐 全面理解智能合约升级 Solidity可升级代理模式: 透明代理与UUPS代理 使用OpenZeppelin编写可升级的智能合约 实战:调整NFT智能合约,减少70%的铸币Gas成本 Solidity 优化 - 隐藏的 Gas 成本 Gas 技巧:Solidity 中利用位图大幅节省Gas费 Solidity Gas 优化 - 理解不同变量 Gas 差异 关于Solidity 事件,我希望早一点了解到这些 Solidity 编码规范推荐标准 深入了解 Solidity bytes OpenZeppelin Contracts 5.0 版本发布 Solidity Gas优化:高效的智能合约策略 智能合约安全的新最低测试标准:Fuzz / Invariant Test 智能合约的白名单技术 模糊测试利器 - Echidna 简介 智能合约设计模式:代理 离线授权 NFT EIP-4494:ERC721 -Permit

Solidity 类特性

本文讨论 Solidity 的类特性

本文讨论 Solidity 的类特性,Solidity 是以太坊区块链的默认智能合约语言。

背景

在 Datona 实验室的 Solidity Smart-Data-Access-Contract(S-DAC)模板的开发和测试过程中,我们探索了使用类的技术,就像在传统的面向对象的编程(OOP)语言中一样。例如,我们希望能写出类似这样的代码:

import "ContractOwner.sol";
import "Partners.sol";
contract EasyShare ... {
    ContractOwner contractOwner;
    Partners partners;

    ...
    function addPartner(...) public onlyContractOwner {
        partners.add(...);
    }
    ...
}

在这个例子中,ContractOwnerPartners 是我们想要使用的类。

一个类将相关的代码和数据封装在一个实体中。

关于这个的实现将在下面的例子中进一步探讨。

为什么在 Solidity 中使用类?

因为我们很习惯在 OOP 开发中使用类,并且想要继续以这种方式来开发,因为它很好用。

对于为什么要用 OOP 编程,其可能的原因有很多。参考wiki中的面向对象编程

在 Solidity 中使用类有什么好处?

我们发现,OOP 是非常熟悉、自然的,通常可以减少错误率,便于独立测试,并能重用。

在 Solidity 中使用类的缺点是什么?

主要的缺点是可能会使我们不去完全使用 Solidity 的编程范式。

还有人担心,大量导入文件会成为维护的噩梦。

最后,Solidity 合约通常非常简单,而导入文件可能会增加不必要的复杂性、成本和文件管理。

尽管如此,我们认为值得探索各种可能性,即使只是为了拒绝它们。

Solidity 类特性

Solidity 已经有很多与现代 OOP 语言非常不同的特性,如:合约、可支付账号(payable account);执行的 Gas 消耗;永久存储;全局执行等等。

然而,合约不是类,因为Solidity有函数调度程序和其他开销,调用其他合约的函数是非常昂贵的。我在另一篇文章中有提到过“Solidity 函数的 Gas 消耗 ”。

Solidity 提供了哪些功能来实现将代码和数据封装在类里呢?

下面我们将开始探讨:

1) 导入文件
2) 合约继承
3) 将库附加到结构体

在所有这些功能中,数据和函数都可以使用类似类的点符号。例如:myClass.myFunction(myArgument)。在某些情况下,也可以不用指定类。

1)导入文件

有一下几种情况,我们应该作为一个单独的实体文件保存,然后再导入它们,例如:

1.1) 其他合约

在 Solidity 中,合约有可能创建其他合约。除了为测试而创建的临时合约外,那些其他合约似乎很有可能是在不同的文件中被定义:

import "OtherContract.sol";
contract MyContract ... {
    OtherContract otherContract;
    constructor(...) public ... {
        otherContract = new OtherContract(...);
    }
    ...
}

1.2) 继承的合约

在 Solidity 中,也可以继承合约。并且,除了为测试而创建的临时合约外,继承的合约似乎很有可能被重复使用,所以在一个单独的文件中定义很重要,在下面(2)会进一步探讨。

1.3)库

在 Solidity 中也可以创建库,库函数可以是外部或内部的。任何包含外部函数的库大概都是为了被其他合约重用,所以应该在一个独立的文件中定义。

import "SortLibray.sol";
contract MyContract ... {
    MyStruct data;
    ...
    function sortData(...) internal ... {
        SortLibrary.sort(data);
    }
    ...
}

包含内部函数的库将与合约的字节码一起被打包。这些将在(3)中讨论。

2) 合约继承

在 Solidity 中,有两种方式可以有效地提供类特性,一种是继承基础合约

被继承的基础合约是一个普通合约,包含数据和可以作用于这些数据的函数,但通常是不完整的,或者说只是完整合约的一个片段。恰当的文件命名习惯是很有用,可以清楚知道哪些合约是作为可继承的基础合约。

我们还可以把继承当做对象组合来使用,这在下面的例子中会讲到。

3) 将库附加到结构体

这是另一种有效提供类特性的方式,这种方式是创建一个结构体并附加一个库,库中的函数接受该结构体。这就是将一个库附加到一个类型(通常是一个结构体)。

在希望使用该类的合约中,声明了结构体的变量,并可提供结构体作为参数来调用库函数。

Solidity 提供了一个编译器指令,以支持使用点符号调用库函数,这就是using for( using library for struct)。这个功能也可以用于扩展标准类型,例如, using NumbersLib for uint

看看下面的例子。

一些使用 Solidity 类特性的例子

我们用一个简单的合约来演示类特性技术。

这个版本的合约,使用一个叫做ContractOwner的基础合约和一个叫做Partners的组件类。


import "ContractOwner.sol";
import "Partners.sol";
co...

剩余50%的内容订阅专栏后可查看

点赞 3
收藏 2
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论