2017 年 6 月 21 日
May 27, 2025

adToken 发布合约

你好。我是迈克·戈尔丁。我是 ConsenSys 的一名软件开发人员,我撰写了 adToken 的发布合同。

发行代币的压力非常大!在很短的时间内,您的申请会被推送数百万美元,并且每个 Wei 都需要得到正确处理或拒绝。在区块链上,如果出现问题,你不能简单地 “重启服务器”;如果你损失了某人的钱,它就会永远消失,他们不会对你感到满意。

AdToken 的发布非常简单。我们以固定价格出售有限数量的代币。MetaX的目标是通过此次出售实现1000万美元的收入,而1000万美元的数字是硬上限。我们将在发行前一天根据当时的汇率对代币进行定价,这样,如果全部售出5亿个代币,MetaX将以该汇率实现1000万美元的收入。

没有动态定价或异国情调的拍卖机制。AdToken的发布是固定价格、有限供应的销售。这里没有发生任何花哨的事情。MetaX将实现非常接近1000万美元的收入,具体取决于我们设定销售价格和开始销售之间当天以太币价格的波动。

让我们来看看合同!

不要相信我,相信机器!

这是部署在主网上的销售合同,以及 这是源代码。首先来看看名为 startBlock 和 FreezeBlock 的存储变量。在 SaleStarted 修改器中使用 StartBlock 来拒绝在销售开始之前尝试的购买。在 isFrozen 修改器中使用 FreezeBlock 来阻止合同所有者(我!)从更改价格和 StartBlock 低于 StartBlock-FreezeBlock 区块 StartBlock 在 StartBlock 之前的区块。如果你在Etherscan上查看,你会看到我们的起始区块当前设置为3939181,这是一个质数,因此是一个很好的启动代币的区块。3939181区块应在美国东部标准时间6月26日中午左右发布。我们的 FreezeBlock 设置为 3937741,这应该在 StartBlock 之前大约六个小时发布。

我们计划提前大约一天设定最终销售价格,除非以太币价格出现疯狂波动,否则可能不会在最后一刻进行调整。但是对于您来说,作为买家,您可以放心,我们 不能 在销售开始前不到六小时更改价格,这样您就可以知道要支付的价格。

如果我们决定更改起始区块,请注意在 ChangeStartBlock 函数中,FreezeBlock 会自动遮盖新的 StartBlock。因此,如果我们确实更改了StartBlock,您仍然可以放心,在销售前六个小时,最终参数将被锁定,甚至我们也无法对其进行更改。

EmergencyToggle 是一个重要的仅限所有者的功能,它没有被 isFrozen 修改器修改。如果在 任何点 我们在发射合同中发现了一些问题,我们可以激活EmergencyToggle来阻止销售继续进行。

关键之路

销售合同长达242行,但有31行(减去注释和空白处的16行)确实处于关键路径。这是 PurchaseTokens 函数。首先请注意,这是合约中唯一指定为应付的功能,这意味着向合约发送的原始发送将恢复。实际上,发送到除PurchaseTokense之外的任何功能的包含以太币余额的消息都将恢复。除了应付修改量外,PurchaseTokens 函数的修改器还要求销售已经开始、紧急标志未切换以及合约的设置已完成(设置) 完成,在 Etherscan 上自己寻找吧!)。

好的,修改器看起来很简单。购买代币功能中会发生什么?

在第 178—180 行中,我们将确定发件人是否发送了多余的以太币。遗憾的是,如果 adToken 定价为 2 Wei,而用户向我们发送了 3 个 Wei,我们很遗憾无法给用户半个 AdToken。我们必须把他们的一些钱还给他们!这就是我们在以下几行中所做的:确定是否发送了多余的以太币,以便我们可以将其寄回给他们。

完成后,我们确切地知道发件人可以购买多少 adToken,考虑到他们发送给我们的以太币数量。在第 183 行,我们确保实际上还有足够的 adToken 可供出售,如果没有,则还原交易。如果有 足够的 adToken 可供购买者购买他们指定的金额,然后我们在第 187 行将他们发送给我们的任何多余的以太币退还给他们,然后再继续。

好吧,我们差不多完成了!在第191行,我们将发件人发送给我们的以太币转移到我们的钱包中。之后,我们将发件人刚刚购买的代币转移到他们发送的账户中。

请注意,我们使用转账而不是在 191 号线上发送。转账和发送都只会将2300 gas转发到接收地址,这可以防止重入,诸如此类的行为使DAO陷入困境,但是如果接收方回退功能中出现耗尽的错误,则转账实际上会恢复整个交易。

在第 194 行我们完成了代币转账(不同于以太币转账!)在断言声明中。我们使用的 ERC-20 代币合约在失败时返回 false,如果代币转移因任何原因失败,我们将希望恢复整个交易。

最后,我们在第 196 行发布了一个活动,让全世界知道购买成功!

注意事项:一旦销售一空,PurchaseTokense的所有交易都应由于第183行的支票而丢失。这意味着一旦销售结束,就无法向销售合约提供以太币。同样的逻辑还意味着,即使在销售完全售罄之前,购买比可用数量更多的代币就会失败——小额购买可能会让你更有机会在代币售完之前获得代币!也可以写一个包装合约,买入恰当数量的代币并结束销售,同时将多余的余额返还给发件人,但是我们把它留给读者做个练习(一定要写一个让自己提取代币的函数!代币归因于 msg.sender,这将是你的合约!除非你指定提款功能,否则你将锁定你的代币!)。

测试关键任务代码

我的一位实习生最近问我如何去测试这些关键代码。答案:非常小心!我们有 950 行单元测试(42 行全部通过!)并且已经对林克比和科万进行了三次现场测试,目前正在进行第四次测试,确定最终的部署参数。撰写这些合同,生活在知道自己可能要为烧掉很多人的钱负责的压力之下,这使我非常热衷于重新审视用用于 EVM 编程和部署脚手架的函数语言。如果知道编译器已经消除了所有类别的错误,那就太好了。但那将是下次。现在我们已经有了不错的(动态类型的)JavaScript 和(命令式)Solidity。

让我对这次代币发行的安全性感到满意的最后一步是... 公开漏洞赏金!

AdToken 发布合约漏洞赏金!

我们的合同已经部署 在 Kovan 上 还有主网,我们正在提供巨额赏金(500,000 个 adToken!)对于可能出现的错误:

  1. 锁定/烧毁以太币或 adToken
  2. 启用盗窃以太币或 adToken

对于产生意外行为、未达到资产盗窃程度的漏洞,我们将提供较小的赏金。如果你需要Kovan ETH或者想与其他赏金猎人沟通, 加入 AdChain slack!

请将所有错误发送到 bugs@metax.io