千家信息网

Story DAO的白名单和测试方法是什么

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,本篇内容主要讲解"Story DAO的白名单和测试方法是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Story DAO的白名单和测试方法是什么"吧!
千家信息网最后更新 2026年11月01日Story DAO的白名单和测试方法是什么

本篇内容主要讲解"Story DAO的白名单和测试方法是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Story DAO的白名单和测试方法是什么"吧!

合约大纲

让我们用这个骨架创建一个新的合约StoryDao.sol:

pragma solidity ^0.4.24;import "../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol";import "../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol";contract StoryDao is Ownable {    using SafeMath for uint256;    mapping(address => bool) whitelist;    uint256 public whitelistedNumber = 0;    mapping(address => bool) blacklist;    event Whitelisted(address addr, bool status);    event Blacklisted(address addr, bool status);    uint256 public daofee = 100; // hundredths of a percent, i.e. 100 is 1%    uint256 public whitelistfee = 10000000000000000; // in Wei, this is 0.01 ether    event SubmissionCommissionChanged(uint256 newFee);    event WhitelistFeeChanged(uint256 newFee);    uint256 public durationDays = 21; // duration of story's chapter in days    uint256 public durationSubmissions = 1000; // duration of story's chapter in entries    function changedaofee(uint256 _fee) onlyOwner external {        require(_fee < daofee, "New fee must be lower than old fee.");        daofee = _fee;        emit SubmissionCommissionChanged(_fee);    }    function changewhitelistfee(uint256 _fee) onlyOwner external {        require(_fee < whitelistfee, "New fee must be lower than old fee.");        whitelistfee = _fee;        emit WhitelistFeeChanged(_fee);    }    function lowerSubmissionFee(uint256 _fee) onlyOwner external {        require(_fee < submissionZeroFee, "New fee must be lower than old fee.");        submissionZeroFee = _fee;        emit SubmissionFeeChanged(_fee);    }    function changeDurationDays(uint256 _days) onlyOwner external {        require(_days >= 1);        durationDays = _days;    }    function changeDurationSubmissions(uint256 _subs) onlyOwner external {        require(_subs > 99);        durationSubmissions = _subs;    }}

我们正在导入SafeMath以便再次进行安全计算,但这次我们还使用了Zeppelin的Ownable合约,该合约允许某人"拥有"故事并执行某些仅限管理员的功能。简单地说我们的StoryDao is Ownable就够了;随时检查合约,看看它是如何工作的。

我们还使用此合约中的onlyOwner修饰符。函数修饰符基本上是函数扩展和插件。onlyOwner修饰符如下所示:

modifier onlyOwner() {  require(msg.sender == owner);  _;}

当onlyOwner被添加到一个函数中时,那个函数的体被粘贴到_;所在的部分,并且它比其他的一切内容都先执行。因此,通过使用此修饰符,该函数会自动检查邮件发件人是否也是合约的所有者,然后照常继续(如果是)。如果没有,它会崩溃。

通过在改变我们的Story DAO的费用和其他参数的函数上使用onlyOwner修饰符,我们确保只有管理员才能进行这些更改。

测试

让我们测试一下初始函数。

如果文件夹test不存在,请创建它。然后在其中创建文件TestStoryDao.sol和TestStoryDao.js。因为在Truffle中没有本地方法来测试异常,所以也可以使用以下内容创建helpers/expectThrow.js:

export default async promise => {    try {      await promise;    } catch (error) {      const invalidOpcode = error.message.search('invalid opcode') >= 0;      const outOfGas = error.message.search('out of gas') >= 0;      const revert = error.message.search('revert') >= 0;      assert(        invalidOpcode || outOfGas || revert,        'Expected throw, got \'' + error + '\' instead',      );      return;    }    assert.fail('Expected throw not received');  };

注意:Solidity测试通常用于测试基于合约的低级函数,即智能合约的内部。JS测试通常用于测试合约是否可以与外部进行正确的交互,这是我们最终用户将要做的事情。

在TestStoryDao.sol,输入以下内容:

pragma solidity ^0.4.24;import "truffle/Assert.sol";import "truffle/DeployedAddresses.sol";import "../contracts/StoryDao.sol";contract TestStoryDao {    function testDeploymentIsFine() public {        StoryDao sd = StoryDao(DeployedAddresses.StoryDao());        uint256 daofee = 100; // hundredths of a percent, i.e. 100 is 1%        uint256 whitelistfee = 10000000000000000; // in Wei, this is 0.01 ether        uint256 durationDays = 21; // duration of story's chapter in days        uint256 durationSubmissions = 1000; // duration of story's chapter in entries        Assert.equal(sd.daofee(), daofee, "Initial DAO fee should be 100");        Assert.equal(sd.whitelistfee(), whitelistfee, "Initial whitelisting fee should be 0.01 ether");        Assert.equal(sd.durationDays(), durationDays, "Initial day duration should be set to 3 weeks");        Assert.equal(sd.durationSubmissions(), durationSubmissions, "Initial submission duration should be set to 1000 entries");    }}

这将检查StoryDao合约是否正确部署,并提供正确的费用和持续时间。第一行确保通过从已部署地址列表中读取它来部署它,并且最后一节做了一些断言--检查声明是真还是假。在我们的例子中,我们将数字与已部署合约的初始值进行比较。每当它为"true"时,Assert.equals部分将发出一个"True"的事件,这是Truffle在测试时正在监听的事件。

在TestStoryDao.js,输入以下内容:

import expectThrow from './helpers/expectThrow';const StoryDao = artifacts.require("StoryDao");contract('StoryDao Test', async (accounts) => {    it("should make sure environment is OK by checking that the first 3 accounts have over 20 eth", async () =>{        assert.equal(web3.eth.getBalance(accounts[0]).toNumber() > 2e+19, true, "Account 0 has more than 20 eth");        assert.equal(web3.eth.getBalance(accounts[1]).toNumber() > 2e+19, true, "Account 1 has more than 20 eth");        assert.equal(web3.eth.getBalance(accounts[2]).toNumber() > 2e+19, true, "Account 2 has more than 20 eth");    });    it("should make the deployer the owner", async () => {        let instance = await StoryDao.deployed();        assert.equal(await instance.owner(), accounts[0]);    });    it("should let owner change fee and duration", async () => {        let instance = await StoryDao.deployed();        let newDaoFee = 50;        let newWhitelistFee = 1e+10; // 1 ether        let newDayDuration = 42;        let newSubsDuration = 1500;        instance.changedaofee(newDaoFee, {from: accounts[0]});        instance.changewhitelistfee(newWhitelistFee, {from: accounts[0]});        instance.changedurationdays(newDayDuration, {from: accounts[0]});        instance.changedurationsubmissions(newSubsDuration, {from: accounts[0]});        assert.equal(await instance.daofee(), newDaoFee);        assert.equal(await instance.whitelistfee(), newWhitelistFee);        assert.equal(await instance.durationDays(), newDayDuration);        assert.equal(await instance.durationSubmissions(), newSubsDuration);    });    it("should forbid non-owners from changing fee and duration", async () => {        let instance = await StoryDao.deployed();        let newDaoFee = 50;        let newWhitelistFee = 1e+10; // 1 ether        let newDayDuration = 42;        let newSubsDuration = 1500;        await expectThrow(instance.changedaofee(newDaoFee, {from: accounts[1]}));        await expectThrow(instance.changewhitelistfee(newWhitelistFee, {from: accounts[1]}));        await expectThrow(instance.changedurationdays(newDayDuration, {from: accounts[1]}));        await expectThrow(instance.changedurationsubmissions(newSubsDuration, {from: accounts[1]}));    });    it("should make sure the owner can only change fees and duration to valid values", async () =>{        let instance = await StoryDao.deployed();        let invalidDaoFee = 20000;        let invalidDayDuration = 0;        let invalidSubsDuration = 98;        await expectThrow(instance.changedaofee(invalidDaoFee, {from: accounts[0]}));        await expectThrow(instance.changedurationdays(invalidDayDuration, {from: accounts[0]}));        await expectThrow(instance.changedurationsubmissions(invalidSubsDuration, {from: accounts[0]}));    })});

为了使我们的测试成功运行,我们还需要告诉Truffle我们想要部署StoryDao--因为它不会为我们做。因此,让我们在migrations创建3_deploy_storydao.js,其内容几乎与我们之前编写的迁移相同:

var Migrations = artifacts.require("./Migrations.sol");var StoryDao = artifacts.require("./StoryDao.sol");module.exports = function(deployer, network, accounts) {  if (network == "development") {    deployer.deploy(StoryDao, {from: accounts[0]});  } else {    deployer.deploy(StoryDao);  }};

此时,我们还应该在项目文件夹的根目录中更新(或创建,如果它不存在)package.json文件,其中包含我们目前所需的依赖项,并且可能在不久的将来需要:

{  "name": "storydao",  "devDependencies": {    "babel-preset-es2015": "^6.18.0",    "babel-preset-stage-2": "^6.24.1",    "babel-preset-stage-3": "^6.17.0",    "babel-polyfill": "^6.26.0",    "babel-register": "^6.23.0",    "dotenv": "^6.0.0",    "truffle": "^4.1.12",    "openzeppelin-solidity": "^1.10.0",    "openzeppelin-solidity-metadata": "^1.2.0",    "openzeppelin-zos": "",    "truffle-wallet-provider": "^0.0.5",    "ethereumjs-wallet": "^0.6.0",    "web3": "^1.0.0-beta.34",    "truffle-assertions": "^0.3.1"  }}

和.babelrc文件的内容:

{  "presets": ["es2015", "stage-2", "stage-3"]}

我们还需要在我们的Truffle配置中要求Babel,因此它知道它应该在编译时使用它。

注意:Babel是NodeJS的一个附加组件,它允许我们在当前一代NodeJS中使用下一代JavaScript,因此我们可以编写诸如import。如果这超出了你的理解范围,只需忽略它,然后只需逐字粘贴即可。在以这种方式安装后,你可能永远不必再处理这个问题。

require('dotenv').config();================== ADD THESE TWO LINES ================require('babel-register');require('babel-polyfill');=======================================================const WalletProvider = require("truffle-wallet-provider");const Wallet = require('ethereumjs-wallet');// ...

现在,终于进行truffle test。输出应该类似于这个:

有关测试的更多信息,请参阅本教程,该教程专门用于测试智能合约。

在本课程的后续部分中,我们将跳过测试,因为输入它们会使教程太长,但请参考项目的最终源代码来检查它们。我们刚刚完成的过程已经设置了测试环境,因此你可以在进一步设置的情况下编写测试。

白名单

现在让我们构建一个白名单机制,让用户参与构建Story。将以下函数框架添加到StoryDao.sol:

function whitelistAddress(address _add) public payable {    // whitelist sender if enough money was sent}function() external payable {    // if not whitelisted, whitelist if paid enough    // if whitelisted, but X tokens at X price for amount}

未命名的函数function()被称为回调函数,这是在没有特定指令的情况下将钱发送到此合约时被调用的函数(即,没有专门调用其他函数)。这可以让人们加入StoryDao,只需将以太发送到DAO并立即将其列入白名单,或者购买代币,具体取决于它们是否已经列入白名单。

whitelistSender功能用于白名单,可以直接调用,但是如果发送方尚未列入白名单,我们将确保当收到一些以太时,后备功能会自动调用它。whitelistAddress函数被声明为public因为它也应该可以从其他合约中调用,并且回调函数是external函数,因为money将仅从外部地址转到此地址。调用此合约的合约可以直接轻松调用所需的功能。

让我们首先处理回调函数。

function() external payable {    if (!whitelist[msg.sender]) {        whitelistAddress(msg.sender);    } else {        // buyTokens(msg.sender, msg.value);    }}

我们检查发件人是否已经在白名单中,并将调用委托给whitelistAddress函数。请注意,我们已经注释掉了buyTokens函数,因为我们还没有它。

接下来,让我们处理白名单。

function whitelistAddress(address _add) public payable {    require(!whitelist[_add], "Candidate must not be whitelisted.");    require(!blacklist[_add], "Candidate must not be blacklisted.");    require(msg.value >= whitelistfee, "Sender must send enough ether to cover the whitelisting fee.");    whitelist[_add] = true;    whitelistedNumber++;    emit Whitelisted(_add, true);    if (msg.value > whitelistfee) {        // buyTokens(_add, msg.value.sub(whitelistfee));    }}

请注意,此函数接受地址作为参数,并且不从消息中提取它(来自交易)。如果有人无法承担加入DAO的费用,这还有一个额外的好处,即人们可以将其他人列入白名单。

我们通过一些健壮性检查启动该功能:发件人不得列入白名单或列入黑名单(禁止),并且必须已发送足够的费用以支付费用。如果这些条件令人满意,则将地址添加到白名单中,发出白名单事件,最后,如果发送的以太数量大于覆盖白名单费用所需的以太数量,则剩余部分用于买这些代币。

注意:我们使用sub而不是-来减,因为这是一个安全计算的SafeMath函数。

用户现在可以将自己或其他人列入白名单,只要他们向StoryDao合约发送0.01以太或更多。

到此,相信大家对"Story DAO的白名单和测试方法是什么"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

函数 合约 名单 测试 内容 检查 费用 方法 功能 地址 文件 以太 部分 事件 发件人 只需 教程 更多 用户 这是 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技 广州淘业互联网络科技 西安纸贵互联网科技有限公司 北京路客互联网科技有限公司 互联网 科技公司 互联网未来科技 中国互联网金融科技基金 互联网金融科技公司干啥的 浙江互联网科技研学营 苏州五指互联网络科技有限 链环科技传统企业怎么转型互联网 互联网科技创新的路径 2021互联网科技公司排名 江苏苏星互联网科技有限公司 张召忠谈中国互联网科技 下一代互联网重大应用科技园 绵阳真晨互联网科技有限公司 长沙易易互联网科技有限公司 安徽九吞吴互联网科技有限公司 上海旺乐尼互联网科技有限公司 河南真二互联网科技有限公司 互联网的科技创新 深圳互联网络科技有限公司 深圳齐家互联网科技 佩信高科技互联网 深圳市运趣互联网科技有限公司 中盈科技互联网信息有限公司 佛山市翊博互联网络科技有限公司 上海科技产业互联网平台 承德科技产业互联网平台
0