关于以太坊智能合约ERC20代币精度

浮点和精度

1. 浮点和精度

在撰写本文时(Solidity v0.4.24),Solidity 不支持定点或浮点数。这意味着浮点表示必须用 Solidity 中的整数类型进行表示。如果没有正确实施,这可能会导致错误/漏洞。

如需进一步阅读,请参阅以太坊合约安全技术和提示:整数除法的舍入。

1.1 漏洞

由于 Solidity 中没有固定小数点类型,因此开发人员需要使用标准整数数据类型来实现它们自己的类型。在这个过程中,开发人员可能遇到一些陷阱。我将尝试在本节中重点介绍其中的一些内容。

让我们从一个代码示例开始(为简单起见,忽略任何数值上溢/下溢问题)。

这个简单的合约在代币的买卖中存在一些明显的问题。虽然买卖代币的数学计算是正确的,但浮点数的缺乏会给出错误的结果。例如,当在 [7]行 上购买令牌时,如果该值小于1 ether,最初的除法将产生0,并使得最后的乘法结果也是0(即200 wei除以1e18weiPerEth等于0)。同样,当销售代币时,如果代币数量小于10,就只能得到0 ether。事实上,这里四舍五入总是舍去,所以销售29 tokens只能得到2 ether。

这个合约的问题是精度只能到最近的 ether(即1e18 wei)。如果您在处理ERC20代币的decimals时需要更高的精度,有时会有点棘手。

1.2 预防技术

保持智能合约的正确精确度非常重要,尤其是在处理反映经济决策的比率时。

您应该确保您使用的任何比率都可以在分数中使用大数。例如,我们在示例中使用了费率tokensPerEth。但是使用weiPerTokens这样的很大的数字会更好。为求出代币的数量我们可以使用msg.sender/weiPerTokens。这样做会给出更精确的结果。

要记住的另一个策略是注意操作的顺序。在上面的例子中,代币购买量的计算是msg.value/weiPerEth * tokenPerEth。请注意,除法发生在乘法之前。如果计算首先进行乘法,然后再进行除法,即msg.value * tokenPerEth/weiPerEth,那么这个例子会达到更高的精度,。

最后,为数字定义精度时,这样做可能是一个好主意:将变量转换为更高精度,执行所有数学运算,最后在需要时将其转换回所需的输出精度。一般来说,uint256是最常见的数据类型(因为这种类型使用的 Gas 最少),它们的范围约为 60 个数量级,其中一些是可用于数学运算的精确度。有意义的是:最好让 Solidity 中的所有变量都保持高精度,而在外部应用程序中转换回较低的精度(这实际上是 ERC20 代币合约中变量decimals的工作原理)。要查看如何完成此操作的示例以及执行此操作的库,我建议查看Maker DAO DSMath。他们的命名可能不尽合理,但这个概念是非常有用的。

1.3 真实世界的例子:Ethstick

我无法找到一个舍入问题导致合约漏洞的好例子,但我相信这里有很多。如果你有一个好的想法,请随时更新。

由于缺乏一个很好的例子,我希望读者能关注Ethstick,主要是因为我喜欢合约中的酷命名。但是,这个合约并没有使用任何扩展的精确度,它是用wei来处理的。所以这个合约会有四舍五入的问题,但只会在wei的层级上出现。它有一些更严重的缺陷,但这些都与区块链上的熵源难题有关。关于 Ethstick 合约的进一步讨论,我推荐你阅读 Peter Venesses 的另一篇文章:许多以太坊合约就是黑客的糖果。

免责声明:本文由信比特作者原创文章,不构成投资建议,请谨慎对待。

版权声明:信比特作者保留原创权利。文章为作者独立观点,转载请注明出处

原文链接:http://www.bitpoa.com/BlockchainCollege/128.html

生成海报
收藏

相关推荐

0 条评论

微信扫一扫

微信扫一扫

微信扫一扫,分享到朋友圈

关于以太坊智能合约ERC20代币精度