Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the whitelist and test method of Story DAO

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly explains "what is the whitelist and test method of Story DAO". Interested friends may wish to have a look. The method introduced in this paper is simple, fast and practical. Next, let the editor take you to learn "what is the whitelist and test method of Story DAO"?

Contract outline

Let's create a new contract StoryDao.sol with this skeleton:

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 / / 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;}}

We are importing SafeMath for security calculations again, but this time we are also using Zeppelin's Ownable contract, which allows someone to "own" the story and perform certain administrator-only functions. To put it simply, our StoryDao is Ownable is enough; check the contract at any time to see how it works.

We also use the onlyOwner modifier in this contract. Function modifiers are basically function extensions and plug-ins. The onlyOwner modifier is as follows:

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

When onlyOwner is added to a function, the body of that function is pasted to the section where _; is located, and it executes before everything else. Therefore, by using this modifier, the function automatically checks whether the sender of the message is also the owner of the contract, and then continues as usual, if so. If not, it will collapse.

By using the onlyOwner modifier on functions that change the cost and other parameters of our Story DAO, we ensure that only administrators can make these changes.

test

Let's test the initial function.

If the folder test does not exist, create it. Then create the files TestStoryDao.sol and TestStoryDao.js in it. Because there is no native method in Truffle to test for exceptions, you can also create a helpers/expectThrow.js with the following:

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');}

Note: Solidity tests are typically used to test low-level contract-based functions, that is, the interior of smart contracts. JS testing is often used to test whether contracts can interact correctly with the outside world, which is what our end users are going to do.

In TestStoryDao.sol, enter the following:

Pragma solidity ^ 0.4.24 StoryDao sd 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 = 100000000000000; / / 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");}}

This will check that the StoryDao contract is deployed correctly and provide the correct cost and duration. The first line ensures that it is deployed by reading it from the list of deployed addresses, and the last section makes some assertions-- check whether the declaration is true or false. In our example, we compare the number with the initial value of the deployed contract. Whenever it is "true", the Assert.equals section emits an event of "True", which is the event that Truffle was listening for during the test.

In TestStoryDao.js, enter the following:

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 = 1eS10; / / 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 = 1eF10; / / 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]});}))

In order for our test to run successfully, we also need to tell Truffle that we want to deploy StoryDao-- because it won't do it for us. So let's create a 3_deploy_storydao.js in migrations with almost the same content as the migration we wrote earlier:

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);}}

At this point, we should also update (or create, if it does not exist) the package.json file in the root of the project folder, which contains the dependencies we need now, and may need it in the near future:

{"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"}}

And .babelrc file contents:

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

We also need to require Babel in our Truffle configuration, so it knows it should use it at compile time.

Note: Babel is an add-on to NodeJS that allows us to use the next generation of JavaScript in the current generation of NodeJS, so we can write things like import. If this is beyond your understanding, just ignore it and paste it word for word. After installing in this way, you may never have to deal with this problem again.

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

Now, truffle test is finally going on. The output should look like this:

For more information about testing, see this tutorial, which is designed to test smart contracts.

We will skip tests later in this course because entering them will make the tutorials too long, but please refer to the final source code of the project to check them. The process we just completed has set up the test environment, so you can write tests with further settings.

White list

Now let's build a whitelist mechanism that allows users to participate in building Story. Add the following function framework to 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}

The unnamed function function () is called the callback function, which is the function that is called when money is sent to this contract without a specific instruction (that is, no other function is specifically called). This allows people to join StoryDao by sending an ether to DAO and whitelisting it immediately, or buying tokens, depending on whether they are already on the whitelist or not.

The whitelistSender function is used for the whitelist and can be called directly, but if the sender is not on the whitelist, we will make sure that the backup function automatically invokes it when some ether is received. The whitelistAddress function is declared as public because it should also be callable from other contracts, and the callback function is the external function, because money will only go to this address from the outside address. The contract that invokes this contract can easily invoke the required functionality directly.

Let's deal with the callback function first.

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

We check that the sender is already in the whitelist and delegate the call to the whitelistAddress function. Notice that we have commented out the buyTokens function because we don't have it yet.

Next, let's deal with the whitelist.

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));}}

Note that this function takes the address as an argument and does not extract it from the message (from the transaction). If someone can't afford to join the DAO, there is an added benefit that people can whitelist others.

We activate this feature through some robustness checks: the sender must not be whitelisted or blacklisted (prohibited) and must have sent sufficient fees to pay the fee. If these conditions are satisfactory, the address is added to the whitelist, the whitelist event is issued, and finally, if the number of ethers sent is greater than the number of ethers required to cover the whitelist fee, the rest is used to buy these tokens.

Note: we use sub instead of-to subtract, because this is a safely calculated SafeMath function.

Users can now whitelist themselves or others, as long as they send 0.01ethernet or more to the StoryDao contract.

At this point, I believe you have a deeper understanding of "what is the whitelist and test methods of Story DAO". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report