├── .gitattributes
├── .gitignore
├── .travis.yml
├── DAO.sol
├── DAOTokenCreationProxyTransferer.sol
├── DTHPool.sol
├── LICENSE
├── Offer.sol
├── PFOffer.sol
├── README.md
├── README_DTHPool.md
├── RewardOffer.sol
├── Token.sol
├── TokenCreation.sol
├── USNRewardPayOut.sol
├── deploy
├── README.md
├── deploy.js
├── deployOffer.js
├── interface
│ ├── README.md
│ ├── full.json
│ ├── intermediate.json
│ └── minimal.json
└── prepare.py
├── libs
└── oraclize.sol
├── paper
├── Biblio.bib
├── Paper.tex
└── Paper.zh-CN.tex
├── simpleWithdraw.sol
├── simpleWithdrawTrustee.sol
├── tests
├── README.md
├── __init__.py
├── args.py
├── jsutils.py
├── scenarios
│ ├── __init__.py
│ ├── colmattack
│ │ ├── __init__.py
│ │ ├── arguments.json
│ │ ├── run.py
│ │ └── template.js
│ ├── curator_halveminquorum_fueling
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── deploy
│ │ ├── __init__.py
│ │ ├── arguments.json
│ │ ├── deploy_dao_creator_template.js
│ │ ├── deploy_dao_template.js
│ │ ├── deploy_dthpool_template.js
│ │ ├── deploy_offer_template.js
│ │ ├── deploy_pfoffer_template.js
│ │ ├── deploy_usn_template.js
│ │ ├── run.py
│ │ └── template.js
│ ├── deposit
│ │ ├── __init__.py
│ │ ├── arguments.json
│ │ ├── run.py
│ │ └── template.js
│ ├── depositnofunds
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── dthpool
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── extrabalance
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── firecontractor
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── fuel
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── fuel_fail
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── fuel_fail2
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── fuel_fail_extrabalance
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── fuel_predictive
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── multisplitrewards
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── newcontract
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── newcontractfail
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── pfoffer
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── pfoffer_checkvotestatus_fail
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── pfoffer_payment
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── proposal
│ │ ├── __init__.py
│ │ ├── arguments.json
│ │ ├── run.py
│ │ └── template.js
│ ├── rewards
│ │ ├── __init__.py
│ │ ├── arguments.json
│ │ ├── run.py
│ │ └── template.js
│ ├── sampleoffer_changeclient
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── sampleoffer_dailypayment
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── sampleoffer_gettersvt
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── sampleoffer_setrewardvars
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── singlesplit
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── spendall
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
│ ├── split
│ │ ├── __init__.py
│ │ ├── arguments.json
│ │ ├── run.py
│ │ └── template.js
│ └── stealextrabalance
│ │ ├── __init__.py
│ │ ├── run.py
│ │ └── template.js
├── sha3.py
├── templates
│ └── accounts.template.js
├── test.py
└── utils.py
├── withdraw.sol
└── withdrawBlack.sol
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.sol linguist-language=Solidity
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Tests related chain files
2 | tests/data/chaindata/
3 | tests/data/dapp/
4 | tests/data/nodekey
5 | tests/data/history
6 | tests/data/keystore
7 | tests/genesis_block.json
8 |
9 | # Tests save files and output
10 | tests/data/saved
11 | tests/out.log.geth
12 |
13 | # Ignore created javascript files
14 | tests/deploy.js
15 | tests/deploy_dao_creator.js
16 | tests/deploy_dao.js
17 | tests/deploy_offer.js
18 | tests/deploy_pfoffer.js
19 | tests/deploy_usn.js
20 | tests/deploy_dthpool.js
21 | tests/deposit.js
22 | tests/depositnofunds.js
23 | tests/fund.js
24 | tests/fund_fail.js
25 | tests/fund_fail2.js
26 | tests/fuel.js
27 | tests/fuel_fail.js
28 | tests/fuel_fail2.js
29 | tests/fuel_fail_extrabalance.js
30 | tests/proposal.js
31 | tests/accounts.js
32 | tests/rewards.js
33 | tests/split.js
34 | tests/singlesplit.js
35 | tests/colmattack.js
36 | tests/newcontract.js
37 | tests/newcontractfail.js
38 | tests/multisplitrewards.js
39 | tests/spendall.js
40 | tests/extrabalance.js
41 | tests/stealextrabalance.js
42 | tests/firecontractor.js
43 | tests/dthpool.js
44 | tests/fuel_predictive.js
45 | tests/sampleoffer_dailypayment.js
46 | tests/sampleoffer_daopayownrewards.js
47 | tests/sampleoffer_setrewardvars.js
48 | tests/sampleoffer_changeclient.js
49 | tests/sampleoffer_gettersvt.js
50 | tests/curator_halveminquorum_fueling.js
51 | tests/pfoffer.js
52 | tests/pfoffer_payment.js
53 | tests/pfoffer_checkvotestatus_fail.js
54 |
55 | # Ignore deployment related file
56 | deploy/code.js
57 | deploy/prepare.js
58 |
59 | # python metadata in tests
60 | *.pyc
61 |
62 | # git ignore output of the paper generation
63 | paper/*.aux
64 | paper/*.log
65 | paper/*.out
66 | paper/*.pdf
67 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | dist: trusty
3 |
4 | notifications:
5 | email: false
6 |
7 | before_install:
8 | # for g++4.8 and C++11
9 | - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
10 | # for solc
11 | - sudo add-apt-repository -y ppa:ethereum/ethereum
12 | - sudo add-apt-repository -y ppa:ethereum/ethereum-dev
13 |
14 | # solc setup
15 | - sudo apt-get update -y -qq
16 | - sudo apt-get install -yqq solc
17 |
18 | script: cd tests && ./test.py --compile-test
19 |
--------------------------------------------------------------------------------
/DAOTokenCreationProxyTransferer.sol:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the DAO.
3 |
4 | The DAO is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU lesser General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | The DAO is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU lesser General Public License for more details.
13 |
14 | You should have received a copy of the GNU lesser General Public License
15 | along with the DAO. If not, see .
16 | */
17 |
18 |
19 | /*
20 | * By default, token creation can be executed on behalf of another address using
21 | * the TokenCreation.sol createTokenProxy() function This contract is used as a
22 | * fall back in case an exchange doesn't implement the "add data to a
23 | * transaction" feature in a timely manner, preventing it from calling
24 | * createTokenProxy(). Calling this contract automatically triggers a call to
25 | * createTokenProxy() using the correct parameters for a given participant in
26 | * the token creation. A unique instance of such a contract would have to be
27 | * deployed per participant, usually using a middleware layer on a webserver,
28 | * for example.
29 | */
30 |
31 | import "./TokenCreation.sol";
32 |
33 | contract DAOTokenCreationProxyTransferer {
34 | address public owner;
35 | address public dao;
36 |
37 | //constructor
38 | function DAOTokenCreationProxyTransferer(address _owner, address _dao) {
39 | owner = _owner;
40 | dao = _dao;
41 |
42 | // just in case somebody already added values to this address,
43 | // we will forward it right now.
44 | sendValues();
45 | }
46 |
47 | // default-function called when values are sent.
48 | function () {
49 | sendValues();
50 | }
51 |
52 | function sendValues() {
53 | if (this.balance == 0)
54 | return;
55 |
56 | TokenCreationInterface fueling = TokenCreationInterface(dao);
57 | if (now > fueling.closingTime() ||
58 | !fueling.createTokenProxy.value(this.balance)(owner)) {
59 |
60 | owner.send(this.balance);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Decentralized Autonomous Organization (DAO) Framework
2 |
3 | [](https://travis-ci.org/slockit/DAO)
4 |
5 | ## What is it?
6 |
7 | Note: this is currently not maintained - do not use it as is.
8 |
9 | A Standard Decentralized Autonomous Organization (DAO) framework written in Solidity to run on the Ethereum blockchain.
10 |
11 | Feel free to reuse this framework to create your own Decentralized Autonomous Organization.
12 |
13 | **Reference:** *"Decentralized autonomous organization to automate governance" -* [White Paper](https://download.slock.it/public/DAO/WhitePaper.pdf) - [Primer](https://blog.slock.it/a-primer-to-the-decentralized-autonomous-organization-dao-69fb125bd3cd)
14 |
15 |
16 |
17 | ## Disclaimer
18 |
19 | The future remains a work in progress. Our vision exists in a world where laws vary widely. It is important to remember that anyone who uses the generic DAO framework including the DAO refered to as 'The DAO' or any other DAO will do so at their own risk. One can only speculate about the legal status of DAOs worldwide. Whatever one’s personal beliefs may be, people must draw their own conclusions, relying on legal advice where appropriate. The authors are not a law firm and are not in the business of offering legal advice.
20 |
21 | **If you create a DAO it will be your DAO, and you will be responsible for its operation.**
22 |
23 |
24 |
25 |
26 |
27 |
28 | ## Overview
29 |
30 | Our Standard DAO Framework allows people to create Decentralized Autonomous Organizations (DAOs) governed by the code in this repository written immutably to the blockchain.
31 |
32 | We are making the Standard DAO Framework we developed free and open source, so it can be reused by anyone wishing to put together a transparent organization where governance and decision making systems are immutably programmed in the Ethereum blockchain. This code been reviewed by hundreds of pairs of eyes from our community and by one of the most respected auditing companies in the world, Deja Vu.
33 |
34 | This DAO model is open source under the LGPL, so it can be reused by anyone wishing to put together a transparent organization where governance and decision making system are immutably programmed in the Blockchain.
35 |
36 | Note: Although the word "contract" is used in the DAO’s framework code, the term is a programming convention and is not being used as a legal term of art. The term is a programming convention, not a representation that the code is in and of itself a legally binding and enforceable contract. If you have questions about legal enforceability, consult with legal counsel.
37 |
38 |
39 |
40 |
41 |
42 |
43 | ## Solidity files
44 |
45 | ### DAO.sol:
46 | Standard smart contract for any generated Decentralized Autonomous Organization (DAO) to automate organizational governance and decision-making.
47 |
48 | ### Token.sol:
49 | Defines the functions to check token balances, send tokens, send tokens on behalf of a 3rd party and its corresponding approval process.
50 |
51 | ### TokenCreation.sol:
52 | Token Creation contract, used by the DAO generated by the framework to sell its tokens and initialize its ether.
53 |
54 | ### SampleOffer.sol
55 | Sample Proposal from a Contractor to the DAO generated by the framework. Feel free to use as a template for your own proposal.
56 |
57 | ### ManagedAccount.sol
58 | Basic account, used by the DAO contract generated by the framework to separately manage both the rewards and the extraBalance accounts.
59 |
60 | ### DAOTokenCreationProxyTransferer.sol
61 | This contract is used as a fall back in case an exchange doesn't implement the "add data to a transaction" feature in a timely manner, preventing it from calling createTokenProxy().
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | ## Licensing
70 | The DAO framework is free software: you can redistribute it and/or modify it under the terms of the GNU lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
71 |
72 | The DAO framework is distributed in the hope that it will be useful,
73 | but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU lesser General Public License for more details.
74 |
75 | A copy of the GNU lesser General Public License is included
76 | along with the DAO framework. See LICENSE.
77 |
78 |
79 |
80 |
81 |
82 |
83 | ## Additional Disclaimers
84 |
85 | NEITHER THE SOFTWARE NOR ITS CREATORS PROVIDE LEGAL ADVICE AND THIS CODE WAS NOT CREATED TO PROVIDE LEGAL ADVICE OR AS A SUBSTITUTE FOR LEGAL ADVICE. BY USING THIS CODE YOU ALSO AGREE:
86 |
87 | a. The creators of the Software and its contributors are not your lawyers.
88 |
89 | b. The Software is not a lawyer.
90 |
91 | c. Your use of the Software does not, in and of itself, create a legally binding contract in any jurisdiction and does not establish a lawyer-client relationship. Your communication with a non-lawyer will not be subject to the attorney-client privilege and (depending on your jurisdiction) may not be entitled to protection as confidential communication.
92 |
93 | d. The dissemination, distribution, or usage of this software shall not constitute the provision of legal advice within your jurisdiction. Unless you are legally authorized and licensed to do so, you will not use the Software to provide or assist in the provision of legal advice.
94 |
95 | e. You acknowledge and understand that each jurisdiction has its own particular rules regarding the practice of law. IF YOU USE THIS SOFTWARE TO PROVIDE LEGAL ADVICE YOU MAY BE SUBJECT TO CIVIL AND CRIMINAL LIABILITY. PRACTICING LAW WITHOUT A LICENSE IS A VIOLATION OF CRIMINAL LAW IN SOME JURISDICTIONS. CONSULT A LAWYER LICENSED IN YOUR JURISDICTION IF YOU HAVE ANY QUESTIONS ABOUT WHAT DOES OR DOES NOT CONSTITUTE THE PRACTICE OF LAW.
96 |
97 | f. The providers of this software neither warrant nor guarantee this software shall meet the requirements of any particular legal system to form a legally binding contract, nor it it their intention to directly or indirectly facilitate or encourage the unauthorized practice of law.
98 |
99 | g. You agree that in order for you to form a legally binding contract that you shall seek legal advice from an appropriately qualified and experienced lawyer within your jurisdiction.
100 |
101 | h. Issuance of DAO tokens may constitute the sale of securities in certain jurisdictions. Seek appropriate legal advice before deploying DAO code.
102 |
103 |
104 |
--------------------------------------------------------------------------------
/README_DTHPool.md:
--------------------------------------------------------------------------------
1 | # DTHPool contract
2 |
3 | 
4 |
5 | The DTHPool contract allows a DTH to lend their DAO Tokens to a delegate in order to vote in his name without losing the control of his DAO tokens.
6 |
7 | ## Normal procedures
8 |
9 | ### Delegate the votes.
10 |
11 | To delegate the votes the DTH needs to call these two functions in two separated transactions:
12 |
13 | 1. DAO.approve(DTHPoolAdress, [amount of Ð that you want to delegate])
14 | 2. DTHPool.delegateDAOTokens([amount Ð that you want to delegate])
15 |
16 | Once the delegation is finished, you will exchange normal DAO tokens ( Ð ) by the same
17 | number of delegate dao tokens ( dÐ ) .
18 |
19 | It is convenient that in mist you watch both contracts and both tokens.
20 |
21 | ### Undelegate the votes
22 |
23 | To undelegate the vote the DTH just call:
24 |
25 | DTHPool.undelegateDAOTokens([amount Ð that you want to undelegate])
26 |
27 | The DTH will be able to undelegate and so restore his original DAO tokens at any time except in the last moments before the voting period of each proposal.
28 |
29 | ### Voting mecanism
30 |
31 | When a new regular proposal is made to the DAO, the delegate can set his voting intention.
32 |
33 | setVoteIntention(
34 | uint _proposalID,
35 | bool _willVote,
36 | bool _supportsProposal,
37 | string _motivation
38 | )
39 |
40 | * **_proposalID**: the proposal that wants to set the position for.
41 | * **_willVote**: true if this contract will vote to this proposa.
42 | * **_supportsProposal**: true if it will vote to accept the proposal and false if it will not accept.
43 | * **_motivation** free text where the delegate can explain why he set this position.
44 |
45 | The delegate can not vote in split proposals.
46 |
47 | The vote will not effectivelly send the vote to the DAO until the last moment before the
48 | debatingPeriod closes.
49 |
50 | In the testing DTHPool this parameter is set to 2 minutes.
51 |
52 | The contract will make the vote automatically, no action is needed by the user.
53 |
54 | ### Query the delegate positions.
55 |
56 | Users can query the delegate position of any proposal by calling:
57 |
58 | DTHPool.proposalStatuses(proposalId)
59 |
60 |
61 | ## Test and practice
62 |
63 | In order to test and practice with DTHPool contract, I just deployed a test DAO contract and DTHPool contract in the test net.
64 |
65 | * DAO address: 0x0b1aef3ea19bd816e689b7a2a373459170bd8e6e
66 | * DTHPool address: 0x840b7ac7deb5b7441921568a3baa3572e638fecd
67 |
68 | Feel free to contact me ( @jbaylina ) or any member in the #art_of_the_dao channel in thedao.slack.com
69 |
70 | You can get an free invitation here: http://slack.slock.it:3000/
71 |
72 | There you can get testDAOs, testEther, support and love ;)
73 |
74 | ## Q&A
75 |
76 | Q: What happens if somebody sends the DAO tokens directly to the contract?
77 |
78 | A: If the delegate is a nice guy, he can return them back to the clumsy DTH. The delegate may call fixTokens() to return those tokens back to the sender.
79 |
80 | ---
81 | Q: I want to be a delegate. How can I deploy my own contract?
82 |
83 | A: You just deploy the DTHPool with the following parameters in the constructor:
84 |
85 | * _daoAddress : The Address of the DAO token smart contract -- 0xbb9bc244d798123fde783fcc1c72d3bb8c189413 is TheDAO's
86 | * _delegate : Your own address (If you are the delegate)
87 | * _maxTimeBlocked : Time in seconds before the debate closing time when the vote will be triggered automatically.
88 | * _delegateName : Your name (optional string)
89 | * _delegateUrl : A URL for more information about yourself (optional string)
90 | * _tokenSymbol : Symbol for your delegate tokens. Example jbÐ
91 |
92 | **IMPORTANT:** The automatic timer call in _maxTimeBlocked is done via Oraclize service, so it is important that during the construct or in another transaction after the construction you send some ether to this contract.
93 |
94 | ---
95 | Q: Can a delegate change his vote intention?
96 |
97 | A: NO. They are free to change and communicate any details up until the moment before setting their intention; but, once set it cannot be changed.
98 |
99 | ---
100 | Q: How can a user vote different that his delegate?
101 |
102 | A: He must first undelegate his tokens by calling undelegateDAOTokens then cast his vote directly to the DAO. After the voting period ends for that proposal, he is able to safely delegate back his tokens.
103 |
104 | ---
105 | Q: Can the delegate tokens be transfered?
106 |
107 | A: Yes, like any other token.
108 |
109 |
--------------------------------------------------------------------------------
/RewardOffer.sol:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the DAO.
3 |
4 | The DAO is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU lesser General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | The DAO is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU lesser General Public License for more details.
13 |
14 | You should have received a copy of the GNU lesser General Public License
15 | along with the DAO. If not, see .
16 | */
17 |
18 |
19 | /*
20 | Sample Proposal from a Contractor to the DAO including a reward towards the
21 | DAO.
22 |
23 | Feel free to use as a template for your own proposal.
24 | */
25 |
26 | import "./Offer.sol";
27 |
28 | contract RewardOffer is Offer {
29 |
30 | uint rewardDivisor;
31 | uint deploymentReward;
32 |
33 | function RewardOffer(
34 | address _contractor,
35 | address _client,
36 | bytes32 _hashOfTheProposalDocument,
37 | uint _totalCost,
38 | uint _initialWithdrawal,
39 | uint128 _minDailyWithdrawalLimit,
40 | uint _payoutFreezePeriod
41 | ) Offer(
42 | _contractor,
43 | _client,
44 | _hashOfTheProposalDocument,
45 | _totalCost,
46 | _initialWithdrawal,
47 | _minDailyWithdrawalLimit,
48 | _payoutFreezePeriod) {
49 | }
50 |
51 | function setRewardDivisor(uint _rewardDivisor) onlyClient noEther {
52 | rewardDivisor = _rewardDivisor;
53 | }
54 |
55 | function setDeploymentReward(uint _deploymentReward) onlyClient noEther {
56 | deploymentReward = _deploymentReward;
57 | }
58 |
59 | // non-value-transfer getters
60 | function getRewardDivisor() noEther constant returns (uint) {
61 | return rewardDivisor;
62 | }
63 |
64 | function getDeploymentReward() noEther constant returns (uint) {
65 | return deploymentReward;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Token.sol:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the DAO.
3 |
4 | The DAO is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU lesser General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | The DAO is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU lesser General Public License for more details.
13 |
14 | You should have received a copy of the GNU lesser General Public License
15 | along with the DAO. If not, see .
16 | */
17 |
18 |
19 | /*
20 | Basic, standardized Token contract with no "premine". Defines the functions to
21 | check token balances, send tokens, send tokens on behalf of a 3rd party and the
22 | corresponding approval process. Tokens need to be created by a derived
23 | contract (e.g. TokenCreation.sol).
24 |
25 | Thank you ConsenSys, this contract originated from:
26 | https://github.com/ConsenSys/Tokens/blob/master/Token_Contracts/contracts/Standard_Token.sol
27 | Which is itself based on the Ethereum standardized contract APIs:
28 | https://github.com/ethereum/wiki/wiki/Standardized_Contract_APIs
29 | */
30 |
31 | /// @title Standard Token Contract.
32 |
33 | pragma solidity ^0.4.6;
34 |
35 | contract Plutocracy {
36 | function getOrModifyBlocked(address _account) returns (bool);
37 | }
38 |
39 | contract TokenInterface {
40 | mapping (address => uint256) balances;
41 | mapping (address => mapping (address => uint256)) allowed;
42 |
43 | string public name;
44 | string public symbol;
45 | uint public decimals;
46 |
47 | /// Total amount of tokens
48 | uint256 public totalSupply;
49 |
50 | /// Governance contract
51 | Plutocracy plutocracy;
52 |
53 | /// @param _owner The address from which the balance will be retrieved
54 | /// @return The balance
55 | function balanceOf(address _owner) constant returns (uint256 balance);
56 |
57 | /// @notice Send `_amount` tokens to `_to` from `msg.sender`
58 | /// @param _to The address of the recipient
59 | /// @param _amount The amount of tokens to be transferred
60 | /// @return Whether the transfer was successful or not
61 | function transfer(address _to, uint256 _amount) returns (bool success);
62 |
63 | /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
64 | /// is approved by `_from`
65 | /// @param _from The address of the origin of the transfer
66 | /// @param _to The address of the recipient
67 | /// @param _amount The amount of tokens to be transferred
68 | /// @return Whether the transfer was successful or not
69 | function transferFrom(address _from, address _to, uint256 _amount) returns (bool success);
70 |
71 | /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
72 | /// its behalf
73 | /// @param _spender The address of the account able to transfer the tokens
74 | /// @param _amount The amount of tokens to be approved for transfer
75 | /// @return Whether the approval was successful or not
76 | function approve(address _spender, uint256 _amount) returns (bool success);
77 |
78 | /// @param _owner The address of the account owning tokens
79 | /// @param _spender The address of the account able to transfer the tokens
80 | /// @return Amount of remaining tokens of _owner that _spender is allowed
81 | /// to spend
82 | function allowance(
83 | address _owner,
84 | address _spender
85 | ) constant returns (uint256 remaining);
86 |
87 | event Transfer(address indexed _from, address indexed _to, uint256 _amount);
88 | event Approval(
89 | address indexed _owner,
90 | address indexed _spender,
91 | uint256 _amount
92 | );
93 | }
94 |
95 |
96 | contract Token is TokenInterface {
97 |
98 | function Token (Plutocracy _plutocracy) {
99 | plutocracy = _plutocracy;
100 | }
101 |
102 | function balanceOf(address _owner) constant returns (uint256 balance) {
103 | return balances[_owner];
104 | }
105 |
106 | function transfer(address _to, uint256 _amount) returns (bool success) {
107 | if (balances[msg.sender] >= _amount
108 | && _amount > 0
109 | && plutocracy.getOrModifyBlocked(_to)) {
110 |
111 | balances[msg.sender] -= _amount;
112 | balances[_to] += _amount;
113 | Transfer(msg.sender, _to, _amount);
114 | return true;
115 | } else {
116 | return false;
117 | }
118 | }
119 |
120 | function transferFrom(
121 | address _from,
122 | address _to,
123 | uint256 _amount
124 | ) returns (bool success) {
125 |
126 | if (balances[_from] >= _amount
127 | && allowed[_from][msg.sender] >= _amount
128 | && _amount > 0
129 | && plutocracy.getOrModifyBlocked(_to)
130 | && plutocracy.getOrModifyBlocked(_from)) {
131 |
132 | balances[_to] += _amount;
133 | balances[_from] -= _amount;
134 | allowed[_from][msg.sender] -= _amount;
135 | Transfer(_from, _to, _amount);
136 | return true;
137 | } else {
138 | return false;
139 | }
140 | }
141 |
142 | function approve(address _spender, uint256 _amount) returns (bool success) {
143 | allowed[msg.sender][_spender] = _amount;
144 | Approval(msg.sender, _spender, _amount);
145 | return true;
146 | }
147 |
148 | function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
149 | return allowed[_owner][_spender];
150 | }
151 | }
152 |
153 |
--------------------------------------------------------------------------------
/TokenCreation.sol:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the DAO.
3 |
4 | The DAO is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU lesser General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | The DAO is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU lesser General Public License for more details.
13 |
14 | You should have received a copy of the GNU lesser General Public License
15 | along with the DAO. If not, see .
16 | */
17 |
18 |
19 | /*
20 | * Token Creation contract, used by the DAO to create its tokens and initialize
21 | * its ether. Feel free to modify the divisor method to implement different
22 | * Token Creation parameters
23 | */
24 |
25 | import "./Token.sol";
26 |
27 | pragma solidity ^0.4.4;
28 |
29 | contract TokenCreationInterface {
30 | /// @dev Constructor setting the minimum fueling goal and the
31 | /// end of the Token Creation
32 | /// (the address can also create Tokens on behalf of other accounts)
33 | // This is the constructor: it can not be overloaded so it is commented out
34 | // function TokenCreation(
35 | // string _tokenName,
36 | // string _tokenSymbol,
37 | // uint _decimalPlaces
38 | // );
39 |
40 | /// @notice Create Token with `_tokenHolder` as the initial owner of the Token
41 | /// @param _tokenHolder The address of the Tokens's recipient
42 | /// @return Whether the token creation was successful
43 | function createTokenProxy(address _tokenHolder) payable returns (bool success);
44 | event CreatedToken(address indexed to, uint amount);
45 | }
46 |
47 |
48 | contract TokenCreation is TokenCreationInterface, Token {
49 | function TokenCreation(
50 | string _tokenName,
51 | string _tokenSymbol,
52 | uint _decimalPlaces,
53 | Plutocracy _plutocracy) Token(_plutocracy) {
54 | name = _tokenName;
55 | symbol = _tokenSymbol;
56 | decimals = _decimalPlaces;
57 | }
58 |
59 | function createTokenProxy(address _tokenHolder) payable returns (bool success) {
60 | if (msg.value > 0 && this.balance + msg.value > 100000 ether) {
61 | balances[_tokenHolder] += msg.value;
62 | totalSupply += msg.value;
63 | CreatedToken(_tokenHolder, msg.value);
64 | return true;
65 | }
66 | throw;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/USNRewardPayOut.sol:
--------------------------------------------------------------------------------
1 | import "./RewardOffer.sol";
2 |
3 |
4 | contract USNRewardPayOut {
5 |
6 | RewardOffer public usnContract;
7 |
8 | function USNRewardPayOut(RewardOffer _usnContract) {
9 | usnContract = _usnContract;
10 | }
11 |
12 | // interface for USN
13 | function payOneTimeReward() returns(bool) {
14 | if (msg.value < usnContract.getDeploymentReward())
15 | throw;
16 |
17 | if (usnContract.getOriginalClient().DAOrewardAccount().call.value(msg.value)()) {
18 | return true;
19 | } else {
20 | throw;
21 | }
22 | }
23 |
24 | // pay reward
25 | function payReward() returns(bool) {
26 | if (usnContract.getOriginalClient().DAOrewardAccount().call.value(msg.value)()) {
27 | return true;
28 | } else {
29 | throw;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/deploy/README.md:
--------------------------------------------------------------------------------
1 | # Scripts for DAO deployment using geth
2 |
3 | ## Introduction
4 |
5 | `prepare.py` compiles `DAO.sol` and populates some helper variables inside `prepare.js`
6 |
7 | 1. `loadScript("prepare.js")` loads these variables into geth.
8 | 2. `loadScript("deploy.js")` deploys them.
9 |
10 | ## Example usage
11 |
12 | ```
13 | usage: prepare.py [-h] [--solc SOLC]
14 | [--creation-duration-mins CREATION_DURATION_MINS]
15 | [--contracts-dir CONTRACTS_DIR] [--no-limits]
16 | [--curator CURATOR]
17 | [--default-proposal-deposit DEFAULT_PROPOSAL_DEPOSIT]
18 | [--split-execution-period SPLIT_EXECUTION_PERIOD]
19 |
20 | DAO deployment script
21 |
22 | optional arguments:
23 | -h, --help show this help message and exit
24 | --solc SOLC Full path to the solc binary to use
25 | --creation-duration-mins CREATION_DURATION_MINS
26 | Deployed DAO creation duration in minutes
27 | --contracts-dir CONTRACTS_DIR
28 | The directory where the contracts are located
29 | --no-limits If given then a version of DAO.sol without limits is
30 | compiled
31 | --curator CURATOR Account to set as the curator
32 | --default-proposal-deposit DEFAULT_PROPOSAL_DEPOSIT
33 | The proposal deposit (in ether) for every proposal of
34 | the DAO
35 | --split-execution-period SPLIT_EXECUTION_PERIOD
36 | Number of seconds after the voting deadline for which
37 | a split proposal is executable
38 | ```
39 | You can for example call the script with a specifically compiled solc and set the creation to end in 15 mins by doing:
40 | ```
41 | ./prepare.py --solc ~/ew/solidity/build/solc/solc --creation-duration-mins 15
42 | ```
43 |
--------------------------------------------------------------------------------
/deploy/deploy.js:
--------------------------------------------------------------------------------
1 | // first run prepare.js to import the compiled source code and some other helper variables
2 | // before you do that run prepare.py to compile the latest version of the software in DAO
3 | // and populate the helper variables
4 |
5 | personal.unlockAccount(eth.accounts[0]);
6 | var daoContract = web3.eth.contract(dao_abi);
7 | var min_tokens_to_create = 1;
8 | var closing_time = Math.floor(Date.now() / 1000) + seconds_from_now;
9 |
10 | var creatorContract = web3.eth.contract(creator_abi);
11 | console.log("Creating DAOCreator Contract");
12 | var _daoCreatorContract = creatorContract.new(
13 | {
14 | from: web3.eth.accounts[0],
15 | data: creator_bin,
16 | gas: 4000000
17 | }, function (e, contract){
18 | if (e) {
19 | console.log(e+ " at DAOCreator creation!");
20 | } else if (typeof contract.address != 'undefined') {
21 | console.log("Creating the actual DAO");
22 | var dao = daoContract.new(
23 | curator,
24 | contract.address,
25 | web3.toWei(default_proposal_deposit, "ether"),
26 | web3.toWei(min_tokens_to_create, "ether"),
27 | closing_time,
28 | 0,
29 | {
30 | from: web3.eth.accounts[0],
31 | data: dao_bin,
32 | gas: 4000000
33 | }, function (e, our_contract) {
34 | // funny thing, without this geth hangs
35 | console.log("At DAO creation callback");
36 | if (typeof our_contract.address != 'undefined') {
37 | console.log("our new DAO address is: " + our_contract.address);
38 | }
39 | });
40 |
41 | }
42 | });
43 |
--------------------------------------------------------------------------------
/deploy/deployOffer.js:
--------------------------------------------------------------------------------
1 | // first run prepare.js to import the compiled source code and some other helper variables
2 | // before you do that run prepare.py to compile the latest version of the software in DAO
3 | // and populate the helper variables
4 |
5 | personal.unlockAccount(eth.accounts[0]);
6 | var offerContract = web3.eth.contract(offer_abi);
7 |
8 | var _offerrContract = offerContract.new(
9 | contractor,
10 | offer_client_dao_address,
11 | "0x0",
12 | offer_total_costs,
13 | offer_onetime_costs,
14 | offer_min_daily_withdraw,
15 | {
16 | from: web3.eth.accounts[0],
17 | data: offer_bin,
18 | gas: 4000000
19 | }, function (e, contract){
20 | if (e) {
21 | console.log(e+ " at DAOCreator creation!");
22 | } else if (typeof contract.address != 'undefined') {
23 | console.log("The Deployed Offer address is:" + contract.address);
24 |
25 | }
26 | });
27 |
--------------------------------------------------------------------------------
/deploy/interface/README.md:
--------------------------------------------------------------------------------
1 | ## JSON Interface
2 |
3 | This directory contains 2 versions of the interface with which to interact with the DAO. One is the full DAO generate by the Solidity compiler and the other one is a minimal one containing only the minimum amount of functions that a simple user would want in order to interact with the DAO.
4 |
5 | To link to them from an html webpage all one has to do is wrap the
6 | file's URL like below:
7 | ```
8 |
9 | ```
10 |
--------------------------------------------------------------------------------
/deploy/interface/intermediate.json:
--------------------------------------------------------------------------------
1 | [{"type":"function","outputs":[{"type":"bool","name":"success"}],"name":"approve","inputs":[{"type":"address","name":"_spender"},{"type":"uint256","name":"_amount"}],"constant":false},{"type":"function","outputs":[{"type":"uint256","name":""}],"name":"minTokensToCreate","inputs":[],"constant":true},{"type":"function","outputs":[{"type":"uint256","name":""}],"name":"totalSupply","inputs":[],"constant":true},{"type":"function","outputs":[{"type":"address","name":"_newDAO"}],"name":"getNewDAOAddress","inputs":[{"type":"uint256","name":"_proposalID"}],"constant":true},{"type":"function","outputs":[{"type":"bool","name":"success"}],"name":"transferFrom","inputs":[{"type":"address","name":"_from"},{"type":"address","name":"_to"},{"type":"uint256","name":"_value"}],"constant":false},{"type":"function","outputs":[{"type":"uint256","name":"_actualBalance"}],"name":"actualBalance","inputs":[],"constant":true},{"type":"function","outputs":[{"type":"uint256","name":""}],"name":"closingTime","inputs":[],"constant":true},{"type":"function","outputs":[{"type":"bool","name":"success"}],"name":"transferWithoutReward","inputs":[{"type":"address","name":"_to"},{"type":"uint256","name":"_value"}],"constant":false},{"type":"function","outputs":[],"name":"refund","inputs":[],"constant":false},{"type":"function","outputs":[{"type":"uint256","name":"balance"}],"name":"balanceOf","inputs":[{"type":"address","name":"_owner"}],"constant":true},{"type":"function","outputs":[{"type":"uint256","name":"_numberOfProposals"}],"name":"numberOfProposals","inputs":[],"constant":true},{"type":"function","outputs":[{"type":"bool","name":"success"}],"name":"transfer","inputs":[{"type":"address","name":"_to"},{"type":"uint256","name":"_value"}],"constant":false},{"type":"function","outputs":[{"type":"bool","name":""}],"name":"isFueled","inputs":[],"constant":true},{"type":"function","outputs":[{"type":"bool","name":"success"}],"name":"createTokenProxy","inputs":[{"type":"address","name":"_tokenHolder"}],"constant":false},{"type":"function","outputs":[{"type":"uint256","name":"_voteID"}],"name":"vote","inputs":[{"type":"uint256","name":"_proposalID"},{"type":"bool","name":"_supportsProposal"}],"constant":false},{"type":"function","outputs":[{"type":"bool","name":"_success"}],"name":"getMyReward","inputs":[],"constant":false},{"type":"function","outputs":[{"type":"bool","name":"success"}],"name":"transferFromWithoutReward","inputs":[{"type":"address","name":"_from"},{"type":"address","name":"_to"},{"type":"uint256","name":"_value"}],"constant":false},{"type":"function","outputs":[{"type":"uint256","name":"remaining"}],"name":"allowance","inputs":[{"type":"address","name":"_owner"},{"type":"address","name":"_spender"}],"constant":true},{"type":"function","outputs":[{"type":"uint256","name":""}],"name":"blocked","inputs":[{"type":"address","name":""}],"constant":true},{"type":"function","outputs":[{"type":"address","name":""}],"name":"curator","inputs":[],"constant":true},{"type":"function","outputs":[{"type":"bool","name":"_codeChecksOut"}],"name":"checkProposalCode","inputs":[{"type":"uint256","name":"_proposalID"},{"type":"address","name":"_recipient"},{"type":"uint256","name":"_amount"},{"type":"bytes","name":"_transactionData"}],"constant":true},{"type":"constructor","inputs":[{"type":"address","name":"_curator"},{"type":"address","name":"_daoCreator"},{"type":"uint256","name":"_proposalDeposit"},{"type":"uint256","name":"_minTokensToCreate"},{"type":"uint256","name":"_closingTime"},{"type":"address","name":"_privateCreation"}]},{"type":"event","name":"FuelingToDate","inputs":[{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"ProposalAdded","inputs":[{"type":"uint256","name":"proposalID","indexed":true},{"type":"address","name":"recipient","indexed":false},{"type":"uint256","name":"amount","indexed":false},{"type":"bool","name":"newCurator","indexed":false},{"type":"string","name":"description","indexed":false}],"anonymous":false},{"type":"event","name":"ProposalTallied","inputs":[{"type":"uint256","name":"proposalID","indexed":true},{"type":"bool","name":"result","indexed":false},{"type":"uint256","name":"quorum","indexed":false}],"anonymous":false},{"type":"event","name":"NewCurator","inputs":[{"type":"address","name":"_newCurator","indexed":true}],"anonymous":false},{"type":"event","name":"AllowedRecipientChanged","inputs":[{"type":"address","name":"_recipient","indexed":true},{"type":"bool","name":"_allowed","indexed":false}],"anonymous":false}]
2 |
--------------------------------------------------------------------------------
/deploy/interface/minimal.json:
--------------------------------------------------------------------------------
1 | [{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proposals","outputs":[{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"},{"name":"description","type":"string"},{"name":"votingDeadline","type":"uint256"},{"name":"open","type":"bool"},{"name":"proposalPassed","type":"bool"},{"name":"proposalHash","type":"bytes32"},{"name":"proposalDeposit","type":"uint256"},{"name":"newCurator","type":"bool"},{"name":"yea","type":"uint256"},{"name":"nay","type":"uint256"},{"name":"creator","type":"address"}],"type":"function"},{"type":"function","outputs":[{"type":"uint256","name":""}],"name":"totalSupply","inputs":[],"constant":true},{"type":"function","outputs":[{"type":"uint256","name":""}],"name":"closingTime","inputs":[],"constant":true},{"type":"function","outputs":[{"type":"address","name":""}],"name":"curator","inputs":[],"constant":true},{"type":"function","outputs":[{"type":"uint256","name":"balance"}],"name":"balanceOf","inputs":[{"type":"address","name":"_owner"}],"constant":true},{"type":"function","outputs":[{"type":"uint256","name":"_numberOfProposals"}],"name":"numberOfProposals","inputs":[],"constant":true},{"type":"function","outputs":[{"type":"address","name":""}],"name":"extraBalance","inputs":[],"constant":true},{"type":"function","outputs":[{"type":"bool","name":"success"}],"name":"createTokenProxy","inputs":[{"type":"address","name":"_tokenHolder"}],"constant":false},{"type":"function","outputs":[{"type":"uint256","name":"_voteID"}],"name":"vote","inputs":[{"type":"uint256","name":"_proposalID"},{"type":"bool","name":"_supportsProposal"}],"constant":false},{"type":"event","name":"FuelingToDate","inputs":[{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"ProposalAdded","inputs":[{"type":"uint256","name":"proposalID","indexed":true},{"type":"address","name":"recipient","indexed":false},{"type":"uint256","name":"amount","indexed":false},{"type":"bool","name":"newCurator","indexed":false},{"type":"string","name":"description","indexed":false}],"anonymous":false},{"type":"event","name":"ProposalTallied","inputs":[{"type":"uint256","name":"proposalID","indexed":true},{"type":"bool","name":"result","indexed":false},{"type":"uint256","name":"quorum","indexed":false}],"anonymous":false}]
2 |
--------------------------------------------------------------------------------
/deploy/prepare.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python2
2 |
3 | import json
4 | import subprocess
5 | import argparse
6 | import os
7 | import inspect
8 |
9 | contracts_dir = "../"
10 | currentdir = os.path.dirname(
11 | os.path.abspath(inspect.getfile(inspect.currentframe()))
12 | )
13 | os.sys.path.insert(0, os.path.dirname(currentdir))
14 | from tests.utils import determine_binary, edit_dao_source, rm_file, to_wei
15 |
16 |
17 | class TestDeployContext():
18 | def __init__(self, args):
19 | self.args = args
20 | self.args.solc = determine_binary(args.solc, 'solc', True)
21 |
22 | def compile_contract(self, contract_name):
23 | if self.args.no_limits and contract_name == "DAO.sol":
24 | contract_path = edit_dao_source(
25 | self.args.contracts_dir,
26 | False, # keep limits
27 | self.args.min_proposal_debate,
28 | self.args.min_split_debate,
29 | True, # halve min quorum test, remove year limit
30 | self.args.split_execution_period,
31 | True, # Normal pricing
32 | True, # Don't edit creationGracePeriod
33 | )
34 | else:
35 | contract_path = os.path.join(
36 | self.args.contracts_dir,
37 | contract_name
38 | )
39 | print(" Compiling {}...".format(contract_path))
40 | data = subprocess.check_output([
41 | self.args.solc,
42 | contract_path,
43 | "--optimize",
44 | "--combined-json",
45 | "abi,bin"
46 | ])
47 | return json.loads(data)
48 |
49 | def cleanup(self):
50 | try:
51 | rm_file(os.path.join(self.args.contracts_dir, "DAOcopy.sol"))
52 | rm_file(
53 | os.path.join(self.args.contracts_dir, "TokenCreationCopy.sol")
54 | )
55 | except:
56 | pass
57 |
58 |
59 | if __name__ == "__main__":
60 | p = argparse.ArgumentParser(description='DAO deployment script')
61 | p.add_argument(
62 | '--solc',
63 | help='Full path to the solc binary to use'
64 | )
65 | p.add_argument(
66 | '--creation-duration-mins',
67 | type=int,
68 | default=60,
69 | help='Deployed DAO creation duration in minutes'
70 | )
71 | p.add_argument(
72 | '--contracts-dir',
73 | default="..",
74 | help='The directory where the contracts are located'
75 | )
76 | p.add_argument(
77 | '--no-limits',
78 | action='store_true',
79 | help='If given then a version of DAO.sol without limits is compiled'
80 | )
81 | p.add_argument(
82 | '--curator',
83 | default="0x08144824954c65b12f68b75072488e634ac4e67a", # Griff testnet
84 | help='Account to set as the curator'
85 | )
86 | p.add_argument(
87 | '--default-proposal-deposit',
88 | type=int,
89 | default=1,
90 | help='The proposal deposit (in ether) for every proposal of the DAO'
91 | )
92 | p.add_argument(
93 | '--split-execution-period',
94 | type=int,
95 | default=20,
96 | help=(
97 | 'Number of seconds after the voting deadline for which a split '
98 | 'proposal is executable'
99 | )
100 | )
101 | p.add_argument(
102 | '--min-proposal-debate',
103 | type=int,
104 | default=3600,
105 | help=(
106 | 'Minumum number of seconds that a generic proposal can have'
107 | )
108 | )
109 | p.add_argument(
110 | '--min-split-debate',
111 | type=int,
112 | default=3600,
113 | help=(
114 | 'Minumum number of seconds that a split proposal can have'
115 | )
116 | )
117 | p.add_argument(
118 | '--offer-contractor',
119 | default="0x08144824954c65b12f68b75072488e634ac4e67a", # Griff testnet
120 | help='Account to set as the SampleOffer contractor'
121 | )
122 | p.add_argument(
123 | '--offer-total-costs',
124 | type=int,
125 | default=50,
126 | help='Total costs of the SampleOffer in ether'
127 | )
128 | p.add_argument(
129 | '--offer-onetime-costs',
130 | type=int,
131 | default=10,
132 | help='Onetime costs of the SampleOffer in ether'
133 | )
134 | p.add_argument(
135 | '--offer-min-daily-withdraw',
136 | type=int,
137 | default=1,
138 | help='Minimum daily withrdawal limit'
139 | )
140 | p.add_argument(
141 | '--offer-client-dao-address',
142 | default="0x159fe90ac850c895e4fd144e705923cfa042d974", # A testnet DAO
143 | help='The address of the DAO to set as the client of the SampleOffer'
144 | )
145 | args = p.parse_args()
146 | ctx = TestDeployContext(args)
147 | comp = ctx.compile_contract("DAO.sol")
148 | comp2 = ctx.compile_contract("SampleOffer.sol")
149 |
150 | with open("prepare.js", "w") as f:
151 | f.write("dao_abi = {};\n".format(comp['contracts']['DAO']['abi']))
152 | f.write("dao_bin = '{}';\n".format(comp['contracts']['DAO']['bin']))
153 | f.write("creator_abi = {};\n".format(
154 | comp['contracts']['DAO_Creator']['abi'])
155 | )
156 | f.write("creator_bin = '{}';\n".format(
157 | comp['contracts']['DAO_Creator']['bin'])
158 | )
159 | f.write("offer_abi = {};\n".format(
160 | comp2['contracts']['SampleOffer']['abi'])
161 | )
162 | f.write("offer_bin = '{}';\n".format(
163 | comp2['contracts']['SampleOffer']['bin'])
164 | )
165 | f.write("seconds_from_now = {};\n".format(
166 | args.creation_duration_mins * 60)
167 | )
168 | f.write("curator = \"{}\";\n".format(args.curator))
169 | f.write("default_proposal_deposit = {};\n".format(
170 | args.default_proposal_deposit)
171 | )
172 | f.write("contractor = \"{}\";\n".format(args.offer_contractor))
173 | f.write("offer_total_costs = {};\n".format(
174 | to_wei(args.offer_total_costs)
175 | ))
176 | f.write("offer_onetime_costs = {};\n".format(
177 | to_wei(args.offer_onetime_costs)
178 | ))
179 | f.write("offer_min_daily_withdraw = {};\n".format(
180 | to_wei(args.offer_min_daily_withdraw)
181 | ))
182 | f.write("offer_client_dao_address = '{}';\n".format(
183 | args.offer_client_dao_address
184 | ))
185 |
186 | ctx.cleanup()
187 |
--------------------------------------------------------------------------------
/paper/Biblio.bib:
--------------------------------------------------------------------------------
1 | @article{CrowdfundingFailTC,
2 | url = {{http://techcrunch.com/2015/11/19/when-crowdfunding-fails-the-backers-are-left-with-no-way-out/}},
3 | author = {John Biggs},
4 | title = {{When Crowdfunding Fails The Backers Are Left With No Way Out}},
5 | year = {{2015}},
6 | }
7 |
8 | @article{buterin2013ethereum,
9 | url = {{https://github.com/ethereum/wiki/wiki/White-Paper}},
10 | author = {Vitalik Buterin},
11 | title = {{Ethereum: A Next-Generation Smart Contract and Decentralized Application Platform}},
12 | year = {{2013}},
13 | }
14 |
15 | @article{Vitalik2015subjectivity,
16 | url = {{https://blog.ethereum.org/2015/02/14/subjectivity-exploitability-tradeoff/}},
17 | author = {Buterin, Vitalik},
18 | title = {{The Subjectivity / Exploitability Tradeoff}},
19 | year = {{2015}},
20 | }
21 |
22 | @article{GriffDiscussion,
23 | author = {Griff Green},
24 | title = {{private discussion}},
25 | year = {{2016}},
26 | }
27 |
28 | @article{9MostDisgracefulCrowdFundings,
29 | url = {{http://gizmodo.com/the-9-most-disgraceful-crowdfunding-failures-of-2015-1747957776}},
30 | author = {Kate Knibbs},
31 | title = {{The 9 Most Disgraceful Crowdfunding Failures of 2015}},
32 | year = {{2015}},
33 | }
34 |
35 | @article{2015CFReport,
36 | url = {{http://reports.crowdsourcing.org/index.php?route=product/product&path=0_20&product_id=54}},
37 | author = {Massolution},
38 | title = {{2015CF - Crowdfunding Industry Report}},
39 | year = {{2015}},
40 | }
41 |
42 | @InProceedings{miller1997future,
43 | BookTitle = {{paper delivered at the Extro 3 Conference (August 9)}},
44 | author = {Miller, Mark},
45 | title = {{The Future of Law}},
46 | year = {{1997}},
47 | }
48 |
49 | @article{ReitwiessnerWoodSolidity,
50 | url = {{http://solidity.readthedocs.org/}},
51 | author = {Reitwiessner, Christian and Wood, Gavin},
52 | title = {{Solidity}},
53 | year = {{2015}},
54 | }
55 |
56 | @Article{szabo1997formalizing,
57 | author = {Szabo, Nick},
58 | title = {{Formalizing and securing relationships on public networks}},
59 | journal = {{First Monday}},
60 | volume = {{2}},
61 | number = {{9}},
62 | year = {{1997}},
63 | }
64 |
65 | @article{Wood2014ethereum,
66 | url = {{http://gavwood.com/paper.pdf}},
67 | author = {Gavin Wood},
68 | title = {{Ethereum: A Secure Decentralised Generalised Transaction Ledger}},
69 | year = {{2014}},
70 | }
71 |
--------------------------------------------------------------------------------
/simpleWithdraw.sol:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the DAO.
3 |
4 | The DAO is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU lesser General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | The DAO is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU lesser General Public License for more details.
13 |
14 | You should have received a copy of the GNU lesser General Public License
15 | along with the DAO. If not, see .
16 | */
17 |
18 | // TODO: all constants need to be double checked
19 | import "github.com/slockit/DAO/DAO.sol";
20 |
21 | contract Withdraw {
22 | DAO constant public mainDAO = DAO(0xbb9bc244d798123fde783fcc1c72d3bb8c189413);
23 | uint constant public totalSupply = 11538165987024671407837618;
24 | uint constant public totalWeiSupply = 11898333978710775162018627;
25 |
26 | function withdraw(address donateExtraBalanceTo){
27 | uint balance = mainDAO.balanceOf(msg.sender);
28 |
29 | // The msg.sender must call approve(this, balance) beforehand so that
30 | // transferFrom() will work and not throw. We need transferFrom()
31 | // instead of transfer() due to the msg.sender in the latter ending
32 | // up to be the contract
33 | if (!mainDAO.transferFrom(msg.sender, this, balance)
34 | || !msg.sender.send(balance)
35 | || !donateExtraBalanceTo.send(balance * totalWeiSupply / totalSupply - balance)) {
36 |
37 | throw;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/simpleWithdrawTrustee.sol:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the DAO.
3 |
4 | The DAO is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU lesser General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | The DAO is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU lesser General Public License for more details.
13 |
14 | You should have received a copy of the GNU lesser General Public License
15 | along with the DAO. If not, see .
16 | */
17 |
18 | contract DAO {
19 | function balanceOf(address addr) returns (uint);
20 | function transferFrom(address from, address to, uint balance) returns (bool);
21 | uint public totalSupply;
22 | }
23 |
24 | contract WithdrawDAO {
25 | DAO constant public mainDAO = DAO(0xbb9bc244d798123fde783fcc1c72d3bb8c189413);
26 | address public trustee = 0xDa4a4626d3E16e094De3225A751aAb7128e96526; // curator multisig
27 |
28 | function withdraw(){
29 | uint balance = mainDAO.balanceOf(msg.sender);
30 |
31 | if (!mainDAO.transferFrom(msg.sender, this, balance) || !msg.sender.send(balance))
32 | throw;
33 | }
34 |
35 | function trusteeWithdraw() {
36 | trustee.send((this.balance + mainDAO.balanceOf(this)) - mainDAO.totalSupply());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tests/README.md:
--------------------------------------------------------------------------------
1 | # Tests for the DAO contracts
2 |
3 | ## Using the test framework
4 |
5 | For the full array of arguments available run `test.py --help`
6 |
7 | ```
8 | usage: test.py [-h] [--solc SOLC] [--geth GETH] [--keep-limits]
9 | [--clean-chain] [--verbose] [--closing-time CLOSING_TIME]
10 | [--scenario {none,deploy,fund}]
11 |
12 | DAO contracts test framework
13 |
14 | optional arguments:
15 | -h, --help show this help message and exit
16 | --solc SOLC Full path to the solc binary to use
17 | --geth GETH Full path to the geth binary to use
18 | --keep-limits If given then the debate limits of the original
19 | contracts will not be removed
20 | --clean-chain If given then the blockchain is deleted before any
21 | test scenario is executed
22 | --verbose If given then all test checks are printed in the
23 | console
24 | --closing-time CLOSING_TIME
25 | Number of minutes from now when the newly created DAO
26 | creation ends
27 | --scenario {none,deploy,fund}
28 | Test scenario to play out
29 | ```
30 |
31 | An example scenario you can run is the deploy scenario. Below you can see a sample test command showcasing many of the arguments:
32 |
33 | ```
34 | ./test.py --solc ~/ew/solidity/build/solc/solc --clean-chain --closing-time 60 --min-value 50 --scenario deploy --geth $GOPATH/src/github.com/ethereum/go-ethereum/build/bin/geth --verbose
35 | ```
36 |
37 | ## Scenarios
38 |
39 | You can get a list of the available scenario by calling `test.py --describe-scenarios`. At
40 | the time of writting this readme the following scenarios are available:
41 |
42 | - *singlesplit*
43 | An 'angry' user decides to get out of the DAO and take his money with
44 | him. He creates a proposal to split into an one-member DAO with
45 | himself as the Curator. Then he makes a proposal to this new DAO to
46 | transfer all of the money to himself. Assert that the money he gets
47 | back in the end is equal to the money he put in the original DAO.
48 |
49 | - *rewards*
50 | A kind soul donates to the DAO so the DAO has rewards for
51 | distribution. Create a proposal to send the rewards to the
52 | RewardsAccount, vote and execute it. Subsequently claim rewards and
53 | assert that they are proportional to the tokens held by the account
54 | claiming the reward.
55 |
56 | - *newcontract*
57 | A test of the DAO contract upgrade. We create a new contract with a
58 | completely different code and vote to transfer everything to the new
59 | contract.
60 |
61 | - *deploy*
62 | Deploying of the DAO, DAOcreator and SampleOffer contracts in the
63 | blockchain and noting down of their addresses.
64 |
65 | - *multisplitrewards*
66 | Split out of an already split DAO thus generating a grancdchild DAO.
67 | Subsequently test that rewards can be appropriately claimed for all of
68 | these DAOs by their participants as expected.
69 |
70 | - *proposal*
71 | Create a proposal to send an amount of ether to the SampleOffer
72 | contract. Vote on that proposal, wait for the debating period and then
73 | execute it. Assert that the proposal deposit is returned to its
74 | creator, and that the amount is sent to the SampleOffer and the
75 | promise is valid.
76 |
77 | - *extrabalance*
78 | The DAO spends all its money and has to resort to retrieving money
79 | from the extra balance account. This test checks that this is
80 | succesful.
81 |
82 | - *newcontractfail*
83 | A test of the DAO contract upgrade where the proposal's quorum ends up
84 | being insufficient (<53.3%) and the proposal gets rejected.
85 |
86 | - *split*
87 | Testing an equal split, with a new Curator. Half of the token holders
88 | vote for a split to a new DAO and half vote to stay with the old one.
89 | Assert that the split happens, a new DAO is created and that the
90 | tokens are burned from the old DAO and moved to the new DAO
91 | succesfully. Also assert that the reward tokens are succesfully
92 | transferred.
93 |
94 | - *fuel_fail2*
95 | During the fueling period of the DAO, create DAO tokens from all accounts
96 | with both normal creation and with createTokenProxy(). When the goal is
97 | not reached make sure that the refunds when having used
98 | createTokenProxy() are distributed back to the users correctly.
99 |
100 | - *fuel_fail*
101 | During the fueling period of the DAO, send insufficient ether and
102 | assert that the DAO is not fueled. Then assert that each user can get
103 | a full refund.
104 |
105 | - *fuel*
106 | During the fueling period of the DAO, send enough ether from all
107 | accounts to create tokens and then assert that the user's balance is
108 | indeed correct and that the minimum fueling goal has been reached.
109 |
110 | - *deposit*
111 | Make a proposal to change the default proposal deposit, vote for it
112 | and then assure that the DAO's proposal deposit did indeed change.
113 |
114 | - *colmattack*
115 | Before commit 842ce13aedca6365d1f6f4b62c215d4e9b265ffa an attacker
116 | could create a proposal with a huge deposit. Then he could create a
117 | split DAO proposal to get his share of ether plus his share of the
118 | deposit he gave. Then if the original proposal meets the quorum the
119 | attacker will also get his deposit back.
120 |
121 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/__init__.py
--------------------------------------------------------------------------------
/tests/args.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python2
2 | import argparse
3 | import sys
4 | import os
5 | import json
6 | from utils import available_scenarios, calculate_bytecode
7 | from itertools import izip
8 |
9 |
10 | def pairwise(iterable):
11 | "s -> (s0, s1), (s2, s3), (s4, s5), ..."
12 | a = iter(iterable)
13 | return izip(a, a)
14 |
15 |
16 | def make_bool(val):
17 | if isinstance(val, basestring):
18 | if val.lower() in ["false", "0", "no"]:
19 | return False
20 | elif val.lower() in ["true", "1", "yes"]:
21 | return True
22 | else:
23 | print(
24 | "ERROR: Given string '{}' can not be converted to bool".format(
25 | val
26 | ))
27 | sys.exit(1)
28 | else:
29 | return bool(val)
30 |
31 |
32 | def read_scenario_options(args):
33 | """ Iterate scenarios and load all argument options """
34 | dir = "scenarios"
35 | for name in os.listdir(dir):
36 | argfile = os.path.join(dir, name, "arguments.json")
37 | if os.path.isfile(argfile):
38 | with open(argfile, 'r') as f:
39 | data = json.loads(f.read())
40 |
41 | for arg in data:
42 | arg_type = None # interpret as simple string
43 | if 'type' in arg:
44 | if arg['type'] == "int":
45 | arg_type = int
46 | elif arg['type'] == "float":
47 | arg_type = float
48 | elif arg['type'] == "bool":
49 | arg_type = make_bool
50 | else:
51 | print(
52 | "ERROR: Unrecognized type '{}' given for argument"
53 | "'{}'".format(arg['type'], arg['name'])
54 | )
55 | sys.exit(1)
56 |
57 | if 'type' in arg:
58 | args.add_argument(
59 | "--{}-{}".format(name, arg['name']).replace("_", "-"),
60 | help=arg['description'],
61 | default=arg['default'],
62 | type=arg_type
63 | )
64 | else:
65 | args.add_argument(
66 | "--{}-{}".format(name, arg['name']).replace("_", "-"),
67 | help=arg['description'],
68 | default=arg['default']
69 | )
70 |
71 |
72 | def test_args():
73 | """ Parse the test arguments and create and return the arguments object"""
74 | p = argparse.ArgumentParser(description='DAO contracts test framework')
75 | read_scenario_options(p)
76 |
77 | p.add_argument(
78 | '--solc',
79 | help='Full path to the solc binary to use'
80 | )
81 | p.add_argument(
82 | '--geth',
83 | help='Full path to the geth binary to use'
84 | )
85 | p.add_argument(
86 | '--keep-limits',
87 | action='store_true',
88 | help=(
89 | 'If given then the debate limits of the original '
90 | 'contracts will not be removed'
91 | )
92 | )
93 | p.add_argument(
94 | '--clean-chain',
95 | action='store_true',
96 | help=(
97 | 'If given then the blockchain is deleted before any '
98 | 'test scenario is executed'
99 | )
100 | )
101 | p.add_argument(
102 | '--verbose',
103 | action='store_true',
104 | help='If given then all test checks are printed in the console'
105 | )
106 | p.add_argument(
107 | '--proposal-fail',
108 | action='store_true',
109 | help='If given, then in the proposal scenario the voting will fail'
110 | )
111 | p.add_argument(
112 | '--compile-test',
113 | action='store_true',
114 | help='If given, then tests will only try to compile the contracts'
115 | )
116 | p.add_argument(
117 | '--users-num',
118 | type=int,
119 | help='The number of user accounts to create for the scenarios.'
120 | 'Should be at least 3',
121 | default=5
122 | )
123 | p.add_argument(
124 | '--scenario',
125 | choices=['none'] + available_scenarios(),
126 | default='none',
127 | help='Available test scenario to play out'
128 | )
129 | p.add_argument(
130 | '--describe-scenarios',
131 | action='store_true',
132 | help='Print the description of all scenarios and then quit'
133 | )
134 | p.add_argument(
135 | '--abi',
136 | type=str,
137 | default="",
138 | help=(
139 | "If given then don't run any tests but print the abi of the given "
140 | "function with the arguments provided. Example call:"
141 | "test.py --abi \"transfer address foo uint256 5\""
142 | )
143 | )
144 | p.add_argument(
145 | '--dao-version',
146 | type=str,
147 | default="v1.0",
148 | choices=["v1.0", "master"],
149 | help="The version of the DAO code to run the tests against."
150 | )
151 | args = p.parse_args()
152 |
153 | # Argument verification
154 | if args.users_num < 3:
155 | print("ERROR: Tests need 3 or more users")
156 | sys.exit(1)
157 |
158 | # if it's an abi test call then just show bytecode and exit
159 | if args.abi != "":
160 | arglist = args.abi.split(" ")
161 | function_args = []
162 | for type_name, value in pairwise(arglist[1:]):
163 | function_args.append((type_name, value))
164 | bytecode = calculate_bytecode(arglist[0], *function_args)
165 | print("Requested bytecode is:\n{}\n.Exiting ...".format(bytecode))
166 | sys.exit(0)
167 |
168 | if args.compile_test:
169 | # if we are asking for compile_test then it should always be against
170 | # the latest version of the contracts
171 | args.dao_version = "master"
172 |
173 | return args
174 |
--------------------------------------------------------------------------------
/tests/jsutils.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python2
2 |
3 |
4 | def js_common_intro(accounts_num):
5 | """Common functions, variables to add to all js scripts"""
6 | s = "console.log('unlocking accounts');\n"
7 | for i in range(0, accounts_num):
8 | s += "personal.unlockAccount(eth.accounts[{}], '123');\n".format(i)
9 | s += """// set the basic accounts, coinbase should be random so mining rewards don't pollute results
10 | var curator = eth.accounts[0];
11 | var proposalCreator = eth.accounts[1];
12 | var contractor = eth.accounts[2];
13 | var etherBase = '0x9999999999999999999999999999999999999999';
14 | web3.miner.setEtherbase(etherBase);
15 |
16 | var testMap = {};
17 |
18 | function checkWork() {
19 | miner.start(1);
20 | admin.sleepBlocks(3);
21 | miner.stop();
22 | }
23 |
24 | function time_now() {
25 | return Math.floor(Date.now() / 1000);
26 | }
27 |
28 | function bigDiff(astr, bstr) {
29 | return new BigNumber(astr).minus(new BigNumber(bstr));
30 | }
31 |
32 | function bigDiffRound(astr, bstr) {
33 | return Math.round(bigDiff(astr, bstr));
34 | }
35 |
36 | function addToTest(name, value) {
37 | testMap[name] = value;
38 | console.log("'" + name + "' = " + value);
39 | }
40 |
41 | function testResults() {
42 | console.log("Test Results: " + JSON.stringify(testMap));
43 | }
44 |
45 | function testFail(str) {
46 | console.log("TEST FAIL: " + str);
47 | throw ' ';
48 | }
49 |
50 | function attempt_proposal(
51 | argdao,
52 | recipient,
53 | proposal_creator,
54 | ether_amount,
55 | desc,
56 | bytecode,
57 | debating_period,
58 | ether_deposit,
59 | is_split_proposal
60 | ) {
61 |
62 | dao_closing_time = argdao.closingTime();
63 |
64 | if (!argdao.isFueled()) {
65 | testFail(
66 | "Failed to create a proposal to: '" + desc + "' because the DAO "
67 | + "is not fueled."
68 | );
69 | }
70 | if (dao_closing_time.gt(time_now())) {
71 | testFail(
72 | "Failed to create a proposal to: '" + desc + "' because the DAO's "
73 | + "creation time has not yet closed.\\ndao_closing_time: "
74 | + dao_closing_time + "\\nnow(): " + time_now()
75 | );
76 | }
77 | proposals_num_before = argdao.numberOfProposals();
78 | console.log("Creating a new proposal to: '" + desc + "'");
79 | argdao.newProposal.sendTransaction(
80 | recipient,
81 | web3.toWei(ether_amount, "ether"),
82 | desc,
83 | bytecode,
84 | debating_period,
85 | is_split_proposal,
86 | {
87 | from: proposal_creator,
88 | value: web3.toWei(ether_deposit, "ether"),
89 | gas: 1000000
90 | });
91 | checkWork();
92 | proposals_num_now = argdao.numberOfProposals();
93 |
94 | if (!proposals_num_now.equals(proposals_num_before.add(1))) {
95 | testFail("Failed to create a proposal to: " + desc + "'");
96 | } else {
97 | console.log("Proposal succesfully created");
98 | }
99 | return proposals_num_now;
100 | }
101 |
102 | function attempt_split(argdao, prop_id, user, new_curator, split_exec_period) {
103 | console.log("Account '" + user + "' is calling splitDAO()");
104 | var vote_deadline = argdao.proposals(prop_id)[3];
105 | if (vote_deadline.gt(time_now())) {
106 | testFail("Can't split the DAO while the proposal is still debated.");
107 | }
108 | var prop_deadline = vote_deadline.add(split_exec_period);
109 | console.log("prop_deadline: " + prop_deadline);
110 | console.log("now(): " + time_now());
111 | if (prop_deadline.lessThan(time_now() + 5)) {
112 | testFail("Can no longer vote to split the DAO. 'now > p.votingDeadline + splitExecutionPeriod'");
113 | }
114 | argdao.splitDAO.sendTransaction(
115 | prop_id,
116 | new_curator,
117 | {from:user, gas: 4700000});
118 | checkWork();
119 | console.log("Account '" + user + "' called splitDAO() succesfully");
120 | }
121 |
122 | function attempt_execute_proposal(
123 | argdao,
124 | prop_id,
125 | bytecode,
126 | prop_creator,
127 | expect_closed,
128 | expect_pass) {
129 | desc = argdao.proposals(prop_id)[2];
130 | vote_deadline = argdao.proposals(prop_id)[3];
131 | console.log("Attempting to execute proposal for: '" +desc +"'.");
132 |
133 | if (vote_deadline.gt(time_now())) {
134 | testFail("Can't execute a proposal while it is is still debated.");
135 | }
136 |
137 | argdao.executeProposal.sendTransaction(
138 | prop_id,
139 | bytecode,
140 | {from: prop_creator, gas:4700000}
141 | );
142 | checkWork();
143 | var should_quit = false;
144 | if (argdao.proposals(prop_id)[4] == expect_closed) {
145 | should_quit = true;
146 | console.log(
147 | "Expected the proposal to be " + (expect_closed ? "closed" : "open") +
148 | " but it's not"
149 | );
150 | }
151 | if (argdao.proposals(prop_id)[5] != expect_pass) {
152 | should_quit = true;
153 | console.log(
154 | "Expected the proposal for: '" +desc +" to " +
155 | (expect_pass ? "pass" : "fail") + "."
156 | );
157 | }
158 | if (should_quit) {
159 | testFail("Failed to execute proposal for: '" +desc +"'.");
160 | }
161 | console.log("Executed proposal: '" + desc + "'.");
162 | }
163 | """
164 | return s
165 |
--------------------------------------------------------------------------------
/tests/scenarios/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/colmattack/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/scenarios/colmattack/arguments.json:
--------------------------------------------------------------------------------
1 | [{
2 | "name": "attack_debate_secs",
3 | "default": 15,
4 | "description": "Number of seconds the proposal with the large deposit should be debated",
5 | "type": "int"
6 | }, {
7 | "name": "split_debate_secs",
8 | "default": 20,
9 | "description": "Number of seconds the attacker's split proposal should be debated",
10 | "type": "int"
11 | }, {
12 | "name": "attack_deposit",
13 | "default": 600,
14 | "description": "Amount of ether given as deposit in the attack.",
15 | "type": "int"
16 | }]
17 |
--------------------------------------------------------------------------------
/tests/scenarios/colmattack/run.py:
--------------------------------------------------------------------------------
1 | # Big thanks to @colm from our slack chat for thinking of this attack !!!
2 | scenario_description = (
3 | "Before commit 842ce13aedca6365d1f6f4b62c215d4e9b265ffa an attacker could "
4 | "create a proposal with a huge deposit. Then he could create a split DAO "
5 | "proposal to get his share of ether plus his share of the deposit he gave."
6 | " Then if the original proposal meets the quorum the attacker will also "
7 | "get his deposit back."
8 | )
9 |
10 |
11 | def run(ctx):
12 | ctx.assert_scenario_ran('fuel')
13 |
14 | ctx.create_js_file(substitutions={
15 | "dao_abi": ctx.dao_abi,
16 | "dao_address": ctx.dao_address,
17 | "offer_address": ctx.offer_address,
18 | "attack_debating_period": ctx.args.colmattack_attack_debate_secs,
19 | "split_debating_period": ctx.args.colmattack_split_debate_secs,
20 | "attack_deposit": ctx.args.colmattack_attack_deposit,
21 | })
22 |
23 | ctx.execute(expected={
24 | "attacker_eth_balance_diff": 0,
25 | "attacker_dao_balance_diff": 0,
26 | "split_dao_total_supply": ctx.token_amounts[2]
27 | })
28 |
--------------------------------------------------------------------------------
/tests/scenarios/colmattack/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 |
3 | var attacker = eth.accounts[2];
4 | addToTest('attacker_balance_before', web3.fromWei(eth.getBalance(attacker)));
5 | addToTest('attacker_dao_balance_before', web3.fromWei(dao.balanceOf(attacker)));
6 |
7 | // add curator to the whitelist
8 | dao.changeAllowedRecipients.sendTransaction(curator, true, {from:curator, gas:200000});
9 |
10 | var attack_proposal_id = attempt_proposal(
11 | dao, // DAO in question
12 | curator, // recipient
13 | attacker, // proposal creator
14 | 0, // proposal amount in ether
15 | 'The colm attack proposal with a big deposit', // description
16 | '', //bytecode
17 | $attack_debating_period, // debating period
18 | $attack_deposit, // proposal deposit in ether
19 | false // whether it's a split proposal or not
20 | );
21 |
22 | var split_proposal_id = attempt_proposal(
23 | dao, // DAO in question
24 | attacker, // recipient
25 | attacker, // proposal creator
26 | 0, // proposal amount in ether
27 | 'attacker wants to split out', // description
28 | '', //bytecode
29 | $split_debating_period, // debating period
30 | 0, // proposal deposit in ether
31 | true // whether it's a split proposal or not
32 | );
33 |
34 | console.log("Vote on proposals");
35 | // everyone votes on the attack proposal
36 | for (i = 0; i < eth.accounts.length; i++) {
37 | dao.vote.sendTransaction(
38 | attack_proposal_id,
39 | true,
40 | {
41 | from: eth.accounts[i],
42 | gas: 1000000
43 | }
44 | );
45 | }
46 | // our attacker also votes on his split
47 | dao.vote.sendTransaction(split_proposal_id, true, {from: attacker, gas: 1000000});
48 | checkWork();
49 |
50 |
51 | setTimeout(function() {
52 | miner.stop();
53 | console.log("Attack debate period over.");
54 |
55 | setTimeout(function() {
56 | miner.stop();
57 |
58 | console.log("Split debate period over. Executing the split proposal...");
59 | // now the attacker splits
60 | dao.splitDAO.sendTransaction(
61 | split_proposal_id,
62 | attacker,
63 | {from:attacker, gas: 4700000}
64 | );
65 | checkWork();
66 |
67 | console.log("Right after the split, execute the attack proposal to get the deposit back");
68 | attempt_execute_proposal(
69 | dao, // target DAO
70 | attack_prop_id, // proposal ID
71 | '', // transaction bytecode
72 | attacker, // proposal creator
73 | true, // should the proposal be closed after this call?
74 | true // should the proposal pass?
75 | );
76 |
77 | addToTest('split_proposal_id', split_proposal_id);
78 | addToTest('split_proposal_passed', dao.proposals(split_proposal_id)[5]);
79 | addToTest('split_dao', dao.splitProposalNewAddress(split_proposal_id, 0));
80 | var splitdao = web3.eth.contract($dao_abi).at(testMap['split_dao']);
81 | addToTest('split_dao_total_supply', web3.fromWei(eth.getBalance(splitdao.address)));
82 | addToTest('attacker_balance_after', web3.fromWei(eth.getBalance(attacker)));
83 |
84 | // now comes the check. His balance should be the same but so should be the amount
85 | // balance of the split DAO and the balance he owned in the previous DAO. With the
86 | // colm attack that would not be the case as he would also get part of his proposal
87 | // deposit into the new DAO and thus make profit.
88 | addToTest(
89 | 'attacker_eth_balance_diff',
90 | bigDiffRound(testMap['attacker_balance_after'], testMap['attacker_balance_before'])
91 | );
92 | addToTest(
93 | 'attacker_dao_balance_diff',
94 | bigDiffRound(testMap['split_dao_total_supply'], testMap['attacker_dao_balance_before'])
95 | );
96 | testResults();
97 | }, ($split_debating_period - $attack_debating_period) * 1000);
98 |
99 | miner.start(1);
100 | console.log("Waiting until the split proposal debate is over");
101 | }, $attack_debating_period * 1000);
102 | miner.start(1);
103 | console.log("Waiting for the split debate period.");
104 |
--------------------------------------------------------------------------------
/tests/scenarios/curator_halveminquorum_fueling/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/scenarios/curator_halveminquorum_fueling/run.py:
--------------------------------------------------------------------------------
1 | import random
2 | from utils import constrained_sum_sample_pos, arr_str
3 |
4 |
5 | scenario_description = (
6 | "During the fueling period of the DAO, the curator should not be able "
7 | "to call halveMinQuorum(). This is a test to make sure this can't happen "
8 | "and to assert that the fix introduced by PR: "
9 | "https://github.com/slockit/DAO/pull/152 works as expected"
10 | )
11 |
12 |
13 | def run(ctx):
14 | ctx.assert_scenario_ran('deploy')
15 |
16 | ctx.total_supply = (
17 | ctx.args.deploy_min_tokens_to_create + random.randint(1, 100)
18 | )
19 | ctx.token_amounts = constrained_sum_sample_pos(
20 | len(ctx.accounts), ctx.total_supply
21 | )
22 | ctx.create_js_file(substitutions={
23 | "dao_abi": ctx.dao_abi,
24 | "dao_address": ctx.dao_address,
25 | "amounts": arr_str(ctx.token_amounts)
26 | }
27 | )
28 |
29 | ctx.execute(expected={
30 | "min_quorum_same": True
31 | })
32 |
--------------------------------------------------------------------------------
/tests/scenarios/curator_halveminquorum_fueling/template.js:
--------------------------------------------------------------------------------
1 | var amounts = $amounts;
2 |
3 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
4 | console.log("Creating DAO tokens");
5 | for (i = 0; i < eth.accounts.length; i++) {
6 | web3.eth.sendTransaction({
7 | from:eth.accounts[i],
8 | to: dao.address,
9 | gas:200000,
10 | value:web3.toWei(amounts[i], "ether")
11 | });
12 | }
13 | checkWork();
14 |
15 |
16 | addToTest('min_quorum_before', dao.extMinQuorum(0));
17 | dao.halveMinQuorum.sendTransaction({from:curator, gas:120000});
18 | checkWork();
19 | addToTest('min_quorum_after', dao.extMinQuorum(0));
20 | addToTest(
21 | 'min_quorum_same',
22 | testMap['min_quorum_after'].eq(testMap['min_quorum_before'])
23 | );
24 | testResults();
25 |
--------------------------------------------------------------------------------
/tests/scenarios/deploy/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/deploy/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/deploy/arguments.json:
--------------------------------------------------------------------------------
1 | [{
2 | "name": "creation_seconds",
3 | "default": 50,
4 | "description":"Number of seconds from now when the newly created DAO creation ends",
5 | "type":"int"
6 | }, {
7 | "name": "min_tokens_to_create",
8 | "default": 40,
9 | "description": "Minimum value in tokens for the DAO to create in order to be considered fueled",
10 | "type": "int"
11 | },{
12 | "name": "onetime_costs",
13 | "default": 5,
14 | "description": "The one time costs (in ether) in the offer to the DAO",
15 | "type":"int"
16 | }, {
17 | "name": "total_costs",
18 | "default": 20,
19 | "description": "The total costs (in ether) in the offer to the DAO",
20 | "type":"int"
21 | }, {
22 | "name": "offer_payment_period",
23 | "default": 20,
24 | "description": "Edits the Offer contract to consider a period of X seconds as a day",
25 | "type":"int"
26 | }, {
27 | "name": "pfoffer_payout_freeze_period",
28 | "default": 20,
29 | "description": "Edits the PFOffer contract to consider a period of X seconds as the payout freeze period",
30 | "type":"int"
31 | }, {
32 | "name": "pfoffer_vote_status_deadline",
33 | "default": 1,
34 | "description": "Sets the VoteStatusDeadline of the PFOffer contract",
35 | "type":"int"
36 | },{
37 | "name": "proposal_deposit",
38 | "default": 20,
39 | "description": "The default proposal deposit for every proposal of the DAO",
40 | "type":"int"
41 | }]
42 |
--------------------------------------------------------------------------------
/tests/scenarios/deploy/deploy_dao_creator_template.js:
--------------------------------------------------------------------------------
1 | console.log("Creating DAOCreator Contract");
2 | var creatorContract = web3.eth.contract($creator_abi);
3 | var _daoCreatorContract = creatorContract.new(
4 | {
5 | from: web3.eth.accounts[0],
6 | data: '$creator_bin',
7 | gas: 4700000
8 | }, function (e, contract){
9 | if (e) {
10 | console.log(e+" at DAOCreator creation!");
11 | } else if (typeof contract.address != 'undefined') {
12 | addToTest('dao_creator_address', contract.address);
13 | testResults();
14 | }
15 | });
16 | checkWork();
17 |
--------------------------------------------------------------------------------
/tests/scenarios/deploy/deploy_dao_template.js:
--------------------------------------------------------------------------------
1 | var _curator = web3.eth.accounts[0];
2 | console.log("Creating DAO Contract");
3 | var daoContract = web3.eth.contract($dao_abi);
4 | if ($using_old_dao) {
5 | daoContract.new(
6 | _curator,
7 | "$dao_creator_address",
8 | $default_proposal_deposit,
9 | web3.toWei($min_tokens_to_create, "ether"),
10 | $closing_time,
11 | 0,
12 | {
13 | from: web3.eth.accounts[0],
14 | data: '$dao_bin',
15 | gas: 4700000
16 | }, function (e, contract){
17 | if (e) {
18 | console.log(e+" at DAO creation!");
19 | } else if (typeof contract.address != 'undefined') {
20 | addToTest('dao_address', contract.address);
21 | testResults();
22 | }
23 | });
24 | } else {
25 | daoContract.new(
26 | _curator,
27 | "$dao_creator_address",
28 | $default_proposal_deposit,
29 | web3.toWei($min_tokens_to_create, "ether"),
30 | $closing_time,
31 | 0,
32 | "Test DAO token", // DAO Token name
33 | "A", // DAO Token symbol
34 | 16,
35 | {
36 | from: web3.eth.accounts[0],
37 | data: '$dao_bin',
38 | gas: 4700000
39 | }, function (e, contract){
40 | if (e) {
41 | console.log(e+" at DAO creation!");
42 | } else if (typeof contract.address != 'undefined') {
43 | addToTest('dao_address', contract.address);
44 | testResults();
45 | }
46 | });
47 | }
48 | checkWork();
49 |
50 |
--------------------------------------------------------------------------------
/tests/scenarios/deploy/deploy_dthpool_template.js:
--------------------------------------------------------------------------------
1 | console.log("Creating DTHPool Contract");
2 | var dthContract = web3.eth.contract($dthpool_abi);
3 | var _dthContract = dthContract.new(
4 | "$dao_address", // client DAO address
5 | eth.accounts[0], // delegate
6 | 30, // maxTimeBlocked
7 | "John Doe", //delegateName
8 | "delegate.daohub.org", //delegateURL
9 | "T", //tokenSymbol
10 | {
11 | from: contractor,
12 | data: '$dthpool_bin',
13 | gas: 3000000
14 | }, function (e, contract){
15 | if (e) {
16 | console.log(e+" at DTHPool creation!");
17 | } else if (typeof contract.address != 'undefined') {
18 | addToTest('dthpool_address', contract.address);
19 | testResults();
20 | }
21 | });
22 | checkWork();
23 |
24 |
--------------------------------------------------------------------------------
/tests/scenarios/deploy/deploy_offer_template.js:
--------------------------------------------------------------------------------
1 | console.log("Creating Offer Contract");
2 | var offerContract = web3.eth.contract($offer_abi);
3 | var _offerContract = offerContract.new(
4 | contractor,
5 | "$dao_address", // client DAO address
6 | '0x0', // This is a hash of the paper contract. Does not matter for testing
7 | web3.toWei($offer_total, "ether"), //total costs
8 | web3.toWei($offer_onetime, "ether"), //one time costs
9 | web3.toWei(1, "ether"), //min daily costs
10 | {
11 | from: contractor,
12 | data: '$offer_bin',
13 | gas: 3000000
14 | }, function (e, contract){
15 | if (e) {
16 | console.log(e+" at Offer creation!");
17 | } else if (typeof contract.address != 'undefined') {
18 | addToTest('offer_address', contract.address);
19 | testResults();
20 | }
21 | });
22 | checkWork();
23 |
24 |
--------------------------------------------------------------------------------
/tests/scenarios/deploy/deploy_pfoffer_template.js:
--------------------------------------------------------------------------------
1 | console.log("Creating PFOffer Contract");
2 | var offerContract = web3.eth.contract($pfoffer_abi);
3 | var _offerContract = offerContract.new(
4 | contractor,
5 | "$dao_address", // client DAO address
6 | '0x0', // This is a hash of the paper contract. Does not matter for testing
7 | web3.toWei($offer_total, "ether"), //total costs
8 | web3.toWei($offer_onetime, "ether"), //one time costs
9 | web3.toWei(1, "ether"), //min daily costs
10 | {
11 | from: contractor,
12 | data: '$pfoffer_bin',
13 | gas: 3000000
14 | }, function (e, contract){
15 | if (e) {
16 | console.log(e+" at PFOffer creation!");
17 | } else if (typeof contract.address != 'undefined') {
18 | addToTest('pfoffer_address', contract.address);
19 | testResults();
20 | }
21 | });
22 | checkWork();
23 |
24 |
--------------------------------------------------------------------------------
/tests/scenarios/deploy/deploy_usn_template.js:
--------------------------------------------------------------------------------
1 | console.log("Creating USNRewardPayout Contract");
2 | var usnContract = web3.eth.contract($usn_abi);
3 | var _usnContract = usnContract.new(
4 | contractor,
5 | "$offer_address", // offer address to work with
6 | {
7 | from: contractor,
8 | data: '$usn_bin',
9 | gas: 3000000
10 | }, function (e, contract){
11 | if (e) {
12 | console.log(e+" at USNRewardPayout creation!");
13 | } else if (typeof contract.address != 'undefined') {
14 | addToTest('usn_address', contract.address);
15 | testResults();
16 | }
17 | });
18 | checkWork();
19 |
20 |
--------------------------------------------------------------------------------
/tests/scenarios/deploy/run.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import json
3 | from utils import extract_test_dict, seconds_in_future, bool_to_str
4 |
5 |
6 | scenario_description = (
7 | "Deploying of the DAO, DAOcreator and SampleOffer contracts in the "
8 | "blockchain and noting down of their addresses"
9 | )
10 |
11 |
12 | def calculate_closing_time(obj, script_name, substitutions):
13 | obj.closing_time = seconds_in_future(obj.args.deploy_creation_seconds)
14 | substitutions['closing_time'] = obj.closing_time
15 | return substitutions
16 |
17 |
18 | def deploy_contract(ctx, substitutions, name, result, json_dict, cb=None):
19 | ctx.create_js_file(
20 | substitutions=substitutions,
21 | specific_name=name,
22 | cb_before_creation=cb
23 | )
24 | output = ctx.run_script('{}.js'.format(name))
25 | results = extract_test_dict(name, output)
26 |
27 | try:
28 | setattr(ctx, result, results[result])
29 | except:
30 | print(
31 | "ERROR: Could not find '{}' in the deploy scenario"
32 | ". The output was:\n{}".format(result, output)
33 | )
34 | sys.exit(1)
35 |
36 | print("{} is: {}".format(result, getattr(ctx, result)))
37 | json_dict[result] = getattr(ctx, result)
38 |
39 |
40 | def run(ctx):
41 | json_dict = {}
42 | deploy_contract(
43 | ctx,
44 | substitutions={
45 | "creator_abi": ctx.creator_abi,
46 | "creator_bin": ctx.creator_bin
47 | },
48 | name='deploy_dao_creator',
49 | result='dao_creator_address',
50 | json_dict=json_dict
51 | )
52 | deploy_contract(
53 | ctx,
54 | substitutions={
55 | "dao_abi": ctx.dao_abi,
56 | "dao_bin": ctx.dao_bin,
57 | "dao_creator_address": ctx.dao_creator_address,
58 | "min_tokens_to_create": ctx.args.deploy_min_tokens_to_create,
59 | "default_proposal_deposit": ctx.args.deploy_proposal_deposit,
60 | "using_old_dao": bool_to_str(ctx.args.dao_version != "master")
61 | },
62 | name='deploy_dao',
63 | result='dao_address',
64 | json_dict=json_dict,
65 | cb=calculate_closing_time
66 | )
67 | deploy_contract(
68 | ctx,
69 | substitutions={
70 | "dao_address": ctx.dao_address,
71 | "offer_abi": ctx.offer_abi,
72 | "offer_bin": ctx.offer_bin,
73 | "offer_onetime": ctx.args.deploy_onetime_costs,
74 | "offer_total": ctx.args.deploy_total_costs,
75 | },
76 | name='deploy_offer',
77 | result='offer_address',
78 | json_dict=json_dict
79 | )
80 |
81 | if ctx.scenario_uses_pfoffer():
82 | deploy_contract(
83 | ctx,
84 | substitutions={
85 | "dao_address": ctx.dao_address,
86 | "pfoffer_abi": ctx.pfoffer_abi,
87 | "pfoffer_bin": ctx.pfoffer_bin,
88 | "offer_onetime": ctx.args.deploy_onetime_costs,
89 | "offer_total": ctx.args.deploy_total_costs,
90 | },
91 | name='deploy_pfoffer',
92 | result='pfoffer_address',
93 | json_dict=json_dict
94 | )
95 |
96 | deploy_contract(
97 | ctx,
98 | substitutions={
99 | "offer_address": ctx.offer_address,
100 | "usn_abi": ctx.usn_abi,
101 | "usn_bin": ctx.usn_bin
102 | },
103 | name='deploy_usn',
104 | result='usn_address',
105 | json_dict=json_dict
106 | )
107 |
108 | if ctx.scenario_uses_dthpool():
109 | deploy_contract(
110 | ctx,
111 | substitutions={
112 | "dao_address": ctx.dao_address,
113 | "dthpool_abi": ctx.dthpool_abi,
114 | "dthpool_bin": ctx.dthpool_bin
115 | },
116 | name='deploy_dthpool',
117 | result='dthpool_address',
118 | json_dict=json_dict
119 | )
120 |
121 | with open(ctx.save_file, "w") as f:
122 | f.write(json.dumps(json_dict))
123 |
124 | # after deployment recalculate for the subsequent tests what the min
125 | # amount of tokens is in the case of extrabalance tests
126 | if ctx.scenario_uses_extrabalance():
127 | ctx.args.deploy_min_tokens_to_create = (
128 | int(ctx.args.deploy_min_tokens_to_create * 1.5)
129 | )
130 |
--------------------------------------------------------------------------------
/tests/scenarios/deploy/template.js:
--------------------------------------------------------------------------------
1 | var _curator = web3.eth.accounts[0];
2 | var daoContract = web3.eth.contract($dao_abi);
3 | console.log("Creating DAOCreator Contract");
4 | var creatorContract = web3.eth.contract($creator_abi);
5 | var _daoCreatorContract = creatorContract.new(
6 | {
7 | from: web3.eth.accounts[0],
8 | data: '$creator_bin',
9 | gas: 4700000
10 | }, function (e, contract){
11 | if (e) {
12 | console.log(e+" at DAOCreator creation!");
13 | } else if (typeof contract.address != 'undefined') {
14 | addToTest('dao_creator_address', contract.address);
15 | checkWork();
16 | var dao = daoContract.new(
17 | _curator,
18 | contract.address,
19 | $default_proposal_deposit,
20 | web3.toWei($min_tokens_to_create, "ether"),
21 | $closing_time,
22 | 0,
23 | {
24 | from: web3.eth.accounts[0],
25 | data: '$dao_bin',
26 | gas: 4700000
27 | }, function (e, contract) {
28 | // funny thing, without this geth hangs
29 | console.log("At DAO creation callback");
30 | if (typeof contract.address != 'undefined') {
31 | addToTest('dao_address', contract.address);
32 |
33 | // now deploy the PFOffer
34 | var pfofferContract = web3.eth.contract($pfoffer_abi);
35 | var pfoffer = pfofferContract.new(
36 | contractor,
37 | contract.address, // client DAO address
38 | '0x0', // This is a hash of the paper contract. Does not matter for testing
39 | web3.toWei($offer_total, "ether"), //total costs
40 | web3.toWei($offer_onetime, "ether"), //one time costs
41 | web3.toWei(1, "ether"), //min daily costs
42 | {
43 | from: contractor,
44 | data: '$pfoffer_bin',
45 | gas: 3000000
46 | }, function (e, pfoffer_contract) {
47 | if (e) {
48 | console.log(e + " at PFOffer Contract creation!");
49 | } else if (typeof pfoffer_contract.address != 'undefined') {
50 | addToTest('pfoffer_address', pfoffer_contract.address);
51 | }
52 | });
53 | checkWork();
54 |
55 | // now deploy the Sample Offer
56 | var offerContract = web3.eth.contract($offer_abi);
57 | var offer = offerContract.new(
58 | contractor,
59 | contract.address, // client DAO address
60 | '0x0', // This is a hash of the paper contract. Does not matter for testing
61 | web3.toWei($offer_total, "ether"), //total costs
62 | web3.toWei($offer_onetime, "ether"), //one time costs
63 | web3.toWei(1, "ether"), //min daily costs
64 | {
65 | from: contractor,
66 | data: '$offer_bin',
67 | gas: 3000000
68 | }, function (e, offer_contract) {
69 | if (e) {
70 | console.log(e + " at Offer Contract creation!");
71 | } else if (typeof offer_contract.address != 'undefined') {
72 | addToTest('offer_address', offer_contract.address);
73 |
74 | // finally now deploy the USNRewardPAyout contract
75 | var usnContract = web3.eth.contract($usn_abi);
76 | var usn = usnContract.new(
77 | offer_contract.address,
78 | {
79 | from: contractor,
80 | data: '$usn_bin',
81 | gas: 3000000
82 | }, function (e, usn_contract) {
83 | if (e) {
84 | console.log(e + " at USNRewardpayout Contract creation!");
85 | } else if (typeof usn_contract.address != 'undefined') {
86 | addToTest('usn_address', usn_contract.address);
87 | testResults();
88 | }
89 | }
90 | );
91 | checkWork();
92 | }
93 | });
94 | checkWork();
95 | }
96 | });
97 | checkWork();
98 | }
99 | });
100 | checkWork();
101 |
102 |
--------------------------------------------------------------------------------
/tests/scenarios/deposit/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/deposit/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/deposit/arguments.json:
--------------------------------------------------------------------------------
1 | [{
2 | "name": "debate_seconds",
3 | "default": 15,
4 | "description": "Number of seconds that the deposit change proposal should be open for voting",
5 | "type": "int"
6 | }, {
7 | "name": "new_value",
8 | "default": 2,
9 | "description": "The proposed new deposit value.",
10 | "type": "int"
11 | }]
12 |
--------------------------------------------------------------------------------
/tests/scenarios/deposit/run.py:
--------------------------------------------------------------------------------
1 | from utils import calculate_bytecode
2 |
3 | scenario_description = (
4 | "Make a proposal to change the default proposal deposit, vote for it and "
5 | "then assure that the DAO's proposal deposit did indeed change"
6 | )
7 |
8 |
9 | def run(ctx):
10 | ctx.assert_scenario_ran('fuel')
11 |
12 | bytecode = calculate_bytecode(
13 | 'changeProposalDeposit',
14 | ('uint256', ctx.args.deposit_new_value)
15 | )
16 | ctx.create_js_file(substitutions={
17 | "dao_abi": ctx.dao_abi,
18 | "dao_address": ctx.dao_address,
19 | "proposal_deposit": ctx.args.proposal_deposit,
20 | "transaction_bytecode": bytecode,
21 | "debating_period": ctx.args.deposit_debate_seconds
22 | }
23 | )
24 | print(
25 | "Notice: Debate period is {} seconds so the test will wait "
26 | "as much".format(ctx.args.proposal_debate_seconds)
27 | )
28 |
29 | ctx.execute(expected={
30 | "deposit_after_vote": ctx.args.deposit_new_value
31 | })
32 |
--------------------------------------------------------------------------------
/tests/scenarios/deposit/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 | var prop_id = attempt_proposal(
3 | dao, // DAO in question
4 | dao.address, // recipient
5 | proposalCreator, // proposal creator
6 | 0, // proposal amount in ether
7 | 'Changing proposal deposit', // description
8 | '$transaction_bytecode', //bytecode
9 | $debating_period, // debating period
10 | $proposal_deposit, // proposal deposit in ether
11 | false // whether it's a split proposal or not
12 | );
13 |
14 | // in this scenario all users vote for the change
15 | for (i = 0; i < eth.accounts.length; i++) {
16 | dao.vote.sendTransaction(
17 | prop_id,
18 | true,
19 | {
20 | from: eth.accounts[i],
21 | gas: 1000000
22 | }
23 | );
24 | }
25 | checkWork();
26 | setTimeout(function() {
27 | miner.stop();
28 | attempt_execute_proposal(
29 | dao, // target DAO
30 | prop_id, // proposal ID
31 | '$transaction_bytecode', // transaction bytecode
32 | curator, // proposal creator
33 | true, // should the proposal be closed after this call?
34 | true // should the proposal pass?
35 | );
36 |
37 | addToTest('deposit_after_vote', parseInt(dao.proposalDeposit()));
38 | testResults();
39 | }, $debating_period * 1000);
40 | miner.start(1);
41 |
--------------------------------------------------------------------------------
/tests/scenarios/depositnofunds/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/depositnofunds/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/depositnofunds/run.py:
--------------------------------------------------------------------------------
1 | from utils import calculate_bytecode
2 |
3 | scenario_description = (
4 | "After the DAO has spent all of its money, make a proposal to change "
5 | "the default proposal deposit, vote for it and then assure that the DAO's "
6 | "proposal deposit did indeed change. Effectively test that things work "
7 | "fine after commit: 92beee5d27f66793689448903872302d0f4a6287"
8 | )
9 |
10 |
11 | def run(ctx):
12 | ctx.assert_scenario_ran('spendall')
13 |
14 | bytecode = calculate_bytecode(
15 | 'changeProposalDeposit',
16 | ('uint256', ctx.args.deposit_new_value)
17 | )
18 | ctx.create_js_file(substitutions={
19 | "dao_abi": ctx.dao_abi,
20 | "dao_address": ctx.dao_address,
21 | "proposal_deposit": ctx.args.proposal_deposit,
22 | "transaction_bytecode": bytecode,
23 | "debating_period": ctx.args.deposit_debate_seconds
24 | }
25 | )
26 | print(
27 | "Notice: Debate period is {} seconds so the test will wait "
28 | "as much".format(ctx.args.proposal_debate_seconds)
29 | )
30 |
31 | ctx.execute(expected={
32 | "deposit_after_vote": ctx.args.deposit_new_value
33 | })
34 |
--------------------------------------------------------------------------------
/tests/scenarios/depositnofunds/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 | var prop_id = attempt_proposal(
3 | dao, // DAO in question
4 | dao.address, // recipient
5 | proposalCreator, // proposal creator
6 | 0, // proposal amount in ether
7 | 'Changing proposal deposit', // description
8 | '$transaction_bytecode', //bytecode
9 | $debating_period, // debating period
10 | $proposal_deposit, // proposal deposit in ether
11 | false // whether it's a split proposal or not
12 | );
13 |
14 | // in this scenario all users vote for the change
15 | for (i = 0; i < eth.accounts.length; i++) {
16 | dao.vote.sendTransaction(
17 | prop_id,
18 | true,
19 | {
20 | from: eth.accounts[i],
21 | gas: 1000000
22 | }
23 | );
24 | }
25 | checkWork();
26 | setTimeout(function() {
27 | miner.stop();
28 | attempt_execute_proposal(
29 | dao, // target DAO
30 | prop_id, // proposal ID
31 | '$transaction_bytecode', // transaction bytecode
32 | curator, // proposal creator
33 | true, // should the proposal be closed after this call?
34 | true // should the proposal pass?
35 | );
36 |
37 | addToTest('deposit_after_vote', parseInt(dao.proposalDeposit()));
38 | testResults();
39 | }, $debating_period * 1000);
40 | miner.start(1);
41 |
--------------------------------------------------------------------------------
/tests/scenarios/dthpool/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/dthpool/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/dthpool/run.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | scenario_description = (
4 | "This scenario alternates various createProposal, vote, transfer,"
5 | " setDelegate in various tokenHolders/delegates."
6 | " It checks that all the votes are counted in the correct way after each"
7 | " action."
8 | )
9 |
10 |
11 | def run(ctx):
12 | ctx.assert_scenario_ran('fuel_predictive')
13 |
14 | minamount = 2 # is determined by the total costs + one time costs
15 | amount = random.randint(minamount, sum(ctx.token_amounts))
16 | ctx.create_js_file(substitutions={
17 | "dao_abi": ctx.dao_abi,
18 | "dao_address": ctx.dao_address,
19 | "offer_abi": ctx.offer_abi,
20 | "offer_address": ctx.offer_address,
21 | "offer_amount": amount,
22 | "offer_desc": 'Test Proposal',
23 | "dthpool_abi": ctx.dthpool_abi,
24 | "dthpool_address": ctx.dthpool_address,
25 | "proposal_deposit": ctx.args.proposal_deposit,
26 | "transaction_bytecode": '0x2ca15122' # solc --hashes SampleOffer.sol
27 | })
28 |
29 | ctx.execute(expected={
30 | "notDelegated": 8,
31 | "delegated": 2,
32 | "voteSet1": True,
33 | "willVote1": True,
34 | "supportsProposal1": True,
35 | "executed1": False,
36 | "y6": 2,
37 | "n6": 0
38 | })
39 |
--------------------------------------------------------------------------------
/tests/scenarios/dthpool/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 | var dthpool = web3.eth.contract($dthpool_abi).at('$dthpool_address');
3 |
4 | checkWork();
5 |
6 | var filter = web3.eth.filter('latest');
7 |
8 | var pendingWaits = [];
9 | filter.watch(function (error, blockHash) {
10 | var block = eth.getBlock(blockHash);
11 | bn = block.number;
12 |
13 | var i=0;
14 | while (i cur.time )) ||
17 | ((cur.time) && (!cur.block) && ((new Date()).getTime() > cur.time )))
18 | {
19 | var last = pendingWaits.pop();
20 | if (last !== cur) {
21 | pendingWaits[i] = last;
22 | }
23 | cur.cb();
24 | } else {
25 | i+=1;
26 | }
27 | }
28 | });
29 |
30 | function waitBlock(cb) {
31 | var pendingWait = {
32 | block: eth.blockNumber + 6,
33 | time: (new Date()).getTime() + 5*1000,
34 | cb: cb
35 | };
36 | pendingWaits.push(pendingWait);
37 | }
38 |
39 | function waitTime(t, cb) {
40 | var pendingWait = {
41 | time: (new Date()).getTime() + t*1000,
42 | cb: cb
43 | };
44 | pendingWaits.push(pendingWait);
45 | }
46 |
47 |
48 | var data_newDefaultDelegate;
49 |
50 | function run(actions, cb) {
51 |
52 | var endAction = function(err, res) {
53 | if (idx >=0) {
54 | if (err) {
55 | console.log("Error in step: " + idx + "err:" + err);
56 | return cb(err);
57 | }
58 | if (actions[idx].action==="V") {
59 | addToTest('y' + actions[idx].step, parseInt(web3.fromWei(dao.proposals(actions[idx].proposal)[9])));
60 | addToTest('n' + actions[idx].step, parseInt(web3.fromWei(dao.proposals(actions[idx].proposal)[10])));
61 | }
62 | if (typeof actions[idx].test === "function") {
63 | actions[idx].test(actions[idx]);
64 | }
65 | }
66 | idx += 1;
67 | if (idx == actions.length) {
68 | return cb();
69 | }
70 | exec_pos(idx);
71 | };
72 |
73 |
74 | var exec_pos = function(idx) {
75 | if (actions[idx].action === "Aprobe") {
76 | console.log("Aprobe Step: " + actions[idx].step);
77 | dao.approve.sendTransaction( dthpool.address , web3.toWei(actions[idx].amount), {from: eth.accounts[actions[idx].account], gas: 1000000}, function(err) {
78 | if (err) return endAction(err);
79 | waitBlock(endAction);
80 | });
81 | } else if (actions[idx].action === "Delegate") {
82 | console.log("Delegating step: " + actions[idx].step);
83 | dthpool.delegateDAOTokens.sendTransaction( web3.toWei(actions[idx].amount) , {from: eth.accounts[actions[idx].account], gas: 1000000 }, function(err) {
84 | if (err) return endAction(err);
85 | waitBlock(endAction);
86 | });
87 | } else if (actions[idx].action === "CreateProposal") {
88 | console.log("Creating Proposal: " + actions[idx].step);
89 | dao.newProposal.sendTransaction(eth.accounts[0], web3.toWei(20,'ether'), "proposal1", 0, 60, false, {from: eth.accounts[0], gas: 1000000, value: web3.toWei(25,'ether')}, function(err) {
90 | if (err) return endAction(err);
91 | waitBlock(endAction);
92 | });
93 | } else if (actions[idx].action === "SetVoteIntention") {
94 | console.log("Set vote intention step: " + actions[idx].step);
95 | dthpool.setVoteIntention.sendTransaction( actions[idx].proposal , actions[idx].willVote , actions[idx].supportsProposal, "test motivation", {from: eth.accounts[actions[idx].account], gas: 1000000 }, function(err) {
96 | if (err) return endAction(err);
97 | waitBlock(endAction);
98 | });
99 | } else if (actions[idx].action === "executeAllVotes") {
100 | console.log("Set executeAllVotes step: " + actions[idx].step);
101 | dthpool.executeAllVotes.sendTransaction({from: eth.accounts[actions[idx].account], gas: 1000000 }, function(err) {
102 | if (err) return endAction(err);
103 | waitBlock(endAction);
104 | });
105 | } else if (actions[idx].action === "Wait") {
106 | console.log("Waiting step: " + actions[idx].step);
107 | waitTime(actions[idx].time, endAction);
108 | }
109 | };
110 |
111 | var idx =-1;
112 | endAction();
113 | }
114 |
115 |
116 | var steps = [
117 | { step: 1, action:"Aprobe", account: 0, amount: 2},
118 | { step: 2, action:"Delegate", account: 0 , amount: 2, test: function() {
119 | addToTest("notDelegated",web3.fromWei(dao.balanceOf(eth.accounts[0])));
120 | addToTest("delegated",web3.fromWei(dthpool.balanceOf(eth.accounts[0])));
121 | }},
122 | { step: 3, action:"CreateProposal", account: 1 , proposal: 1, supports: false},
123 | { step: 4, action:"SetVoteIntention", account: 0 , proposal: 1, willVote: true, supportsProposal: true, test: function() {
124 | addToTest( "voteSet1", dthpool.proposalStatuses(1)[0]);
125 | addToTest( "willVote1", dthpool.proposalStatuses(1)[1]);
126 | addToTest( "supportsProposal1", dthpool.proposalStatuses(1)[2]);
127 | addToTest( "executed1", dthpool.proposalStatuses(1)[3]);
128 | }},
129 | { step: 5, action:"Wait", time: 30},
130 | { step: 6, action:"executeAllVotes", account: 1 ,proposal: 1, test: function() {
131 | addToTest('y6' , parseInt(web3.fromWei(dao.proposals(1)[9])));
132 | addToTest('n6' , parseInt(web3.fromWei(dao.proposals(1)[10])));
133 | }}
134 |
135 | ];
136 |
137 | miner.start(2);
138 |
139 | run(steps, function() {
140 | filter.stopWatching();
141 | testResults();
142 | miner.stop();
143 | });
144 |
145 | console.log("Executing steps");
146 |
147 |
--------------------------------------------------------------------------------
/tests/scenarios/extrabalance/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/scenarios/extrabalance/run.py:
--------------------------------------------------------------------------------
1 | from utils import calculate_bytecode, to_wei
2 |
3 | scenario_description = (
4 | "The DAO spent all its money and has to resort to retrieving money from "
5 | "the extra balance account. This test checks that this is succesful."
6 | )
7 |
8 |
9 | def run(ctx):
10 | ctx.assert_scenario_ran('spendall')
11 | extra_balance_ether_to_get = 5
12 | bytecode = calculate_bytecode(
13 | 'payOut',
14 | ('address', ctx.dao_address),
15 | ('uint256', to_wei(extra_balance_ether_to_get))
16 | )
17 | ctx.create_js_file(substitutions={
18 | "dao_abi": ctx.dao_abi,
19 | "dao_address": ctx.dao_address,
20 | "proposal_deposit": ctx.args.proposal_deposit,
21 | "debating_period": ctx.args.proposal_debate_seconds,
22 | "transaction_bytecode": bytecode
23 | })
24 |
25 | ctx.execute(expected={
26 | "dao_balance_diff_after_claim": extra_balance_ether_to_get
27 | })
28 |
--------------------------------------------------------------------------------
/tests/scenarios/extrabalance/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 |
3 | addToTest('dao_total_balance_before', web3.fromWei(dao.actualBalance()));
4 |
5 | var extraBalance = dao.extraBalance();
6 | var claim_prop_id = attempt_proposal(
7 | dao, // DAO in question
8 | extraBalance, // recipient
9 | proposalCreator, // proposal creator
10 | 0, // proposal amount in ether
11 | 'Ask the extraBalance account to pay out to the DAO', // description
12 | '$transaction_bytecode', // transaction bytecode
13 | $debating_period, // debating period
14 | $proposal_deposit, // proposal deposit in ether
15 | false // whether it's a split proposal or not
16 | );
17 | console.log("Voting on the extra balance payout proposal");
18 | for (i = 0; i < eth.accounts.length; i++) {
19 | dao.vote.sendTransaction(
20 | claim_prop_id,
21 | true,
22 | {
23 | from: eth.accounts[i],
24 | gas: 1000000
25 | }
26 | );
27 | }
28 | checkWork();
29 |
30 | setTimeout(function() {
31 | miner.stop();
32 | console.log("After extra balance payout debating period. NOW is: " + Math.floor(Date.now() / 1000));
33 | attempt_execute_proposal(
34 | dao, // target DAO
35 | claim_prop_id, // proposal ID
36 | '$transaction_bytecode', // transaction bytecode
37 | proposalCreator, // proposal creator
38 | true, // should the proposal be closed after this call?
39 | true // should the proposal pass?
40 | );
41 |
42 | addToTest('dao_total_balance_after_claim', web3.fromWei(dao.actualBalance()));
43 | addToTest('dao_balance_diff_after_claim',
44 | testMap['dao_total_balance_after_claim'].sub(
45 | testMap['dao_total_balance_before']
46 | ).round());
47 |
48 | testResults();
49 | }, $debating_period * 1000);
50 | console.log("Wait for end of debating period for claiming extraBalance payout");
51 | miner.start(1);
52 |
53 |
--------------------------------------------------------------------------------
/tests/scenarios/firecontractor/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/firecontractor/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/firecontractor/run.py:
--------------------------------------------------------------------------------
1 | from utils import calculate_bytecode
2 |
3 | scenario_description = (
4 | "Test that the contractor can be fired once the contract has been signed"
5 | " and that all the remaining money is returned to the DAO."
6 | )
7 |
8 |
9 | def run(ctx):
10 | ctx.assert_scenario_ran('proposal')
11 | bytecode = calculate_bytecode('returnRemainingEther')
12 | ctx.create_js_file(substitutions={
13 | "dao_abi": ctx.dao_abi,
14 | "dao_address": ctx.dao_address,
15 | "offer_abi": ctx.offer_abi,
16 | "offer_address": ctx.offer_address,
17 | "proposal_deposit": ctx.args.proposal_deposit,
18 | "transaction_bytecode": bytecode,
19 | "debating_period": ctx.args.proposal_debate_seconds,
20 | })
21 | print(
22 | "Notice: Debate period is {} seconds so the test will wait "
23 | "as much".format(ctx.args.proposal_debate_seconds)
24 | )
25 |
26 | ctx.execute(expected={
27 | "got_back_all_money": True,
28 | "bad_proposal_failed": True,
29 | "offer_contract_valid": False
30 | })
31 |
--------------------------------------------------------------------------------
/tests/scenarios/firecontractor/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 | var offer = web3.eth.contract($offer_abi).at('$offer_address');
3 |
4 | var prop_id = attempt_proposal(
5 | dao, // DAO in question
6 | '$offer_address', // recipient
7 | proposalCreator, // proposal creator
8 | 0, // proposal amount in ether
9 | 'Give us back our money!', // description
10 | '$transaction_bytecode', //bytecode
11 | $debating_period, // debating period
12 | $proposal_deposit, // proposal deposit in ether
13 | false // whether it's a split proposal or not
14 | );
15 |
16 | var bad_prop_id = attempt_proposal(
17 | dao, // DAO in question
18 | '$offer_address', // recipient
19 | proposalCreator, // proposal creator
20 | 10, // proposal amount in ether
21 | 'Give us back our money - bad!', // description
22 | '$transaction_bytecode', //bytecode
23 | $debating_period, // debating period
24 | $proposal_deposit, // proposal deposit in ether
25 | false // whether it's a split proposal or not
26 | );
27 |
28 |
29 | console.log("Voting for the proposal to fire the contractor");
30 | for (i = 0; i < eth.accounts.length; i++) {
31 | dao.vote.sendTransaction(
32 | prop_id,
33 | true, //omg it's unanimous!
34 | {
35 | from: eth.accounts[i],
36 | gas: 1000000
37 | }
38 | );
39 | dao.vote.sendTransaction(
40 | bad_prop_id,
41 | true, //omg it's unanimous!
42 | {
43 | from: eth.accounts[i],
44 | gas: 1000000
45 | }
46 | );
47 | }
48 | checkWork();
49 | var offer_balance_before = eth.getBalance(offer.address);
50 | var dao_rewardaccount_before = eth.getBalance(dao.DAOrewardAccount());
51 |
52 | setTimeout(function() {
53 | miner.stop();
54 | console.log("After debating period. NOW is: " + Math.floor(Date.now() / 1000));
55 | // first of all attempt to execute the proposal that sneaks in a value
56 | attempt_execute_proposal(
57 | dao, // target DAO
58 | bad_prop_id, // proposal ID
59 | '$transaction_bytecode', // transaction bytecode
60 | proposalCreator, // proposal creator
61 | false, // should the proposal be closed after this call?
62 | false // should the proposal pass?
63 | );
64 | var offer_balance_after = eth.getBalance(offer.address);
65 | addToTest('bad_proposal_failed', offer_balance_after.eq(offer_balance_before));
66 | // addToTest('bad_proposal_failed', true);
67 | addToTest('after_bad_proposal_offer_has', web3.fromWei(eth.getBalance(offer.address)));
68 | addToTest('after_bad_contract_valid', offer.getIsContractValid());
69 |
70 | attempt_execute_proposal(
71 | dao, // target DAO
72 | prop_id, // proposal ID
73 | '$transaction_bytecode', // transaction bytecode
74 | proposalCreator, // proposal creator
75 | true, // should the proposal be closed after this call?
76 | true // should the proposal pass?
77 | );
78 |
79 | offer_balance_after = eth.getBalance(offer.address);
80 | var dao_rewardaccount_after = eth.getBalance(dao.DAOrewardAccount());
81 |
82 | var offer_diff = offer_balance_after.sub(offer_balance_before);
83 | var rewards_diff = dao_rewardaccount_before.sub(dao_rewardaccount_after);
84 |
85 | addToTest('got_back_all_money', rewards_diff.eq(offer_diff));
86 | addToTest('offer_contract_valid', offer.getIsContractValid());
87 |
88 | testResults();
89 | }, $debating_period * 1000);
90 | console.log("Wait for end of debating period");
91 | miner.start(1);
92 |
--------------------------------------------------------------------------------
/tests/scenarios/fuel/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/fuel/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/fuel/run.py:
--------------------------------------------------------------------------------
1 | import random
2 | from utils import constrained_sum_sample_pos, arr_str
3 |
4 |
5 | scenario_description = (
6 | "During the fueling period of the DAO, send enough ether from all "
7 | "accounts to create tokens and then assert that the user's balance is "
8 | "indeed correct and that the minimum fueling goal has been reached"
9 | )
10 |
11 |
12 | def run(ctx):
13 | ctx.assert_scenario_ran('deploy')
14 |
15 | creation_secs = ctx.remaining_time()
16 | ctx.total_supply = (
17 | ctx.args.deploy_min_tokens_to_create + random.randint(1, 100)
18 | )
19 | ctx.token_amounts = constrained_sum_sample_pos(
20 | len(ctx.accounts), ctx.total_supply
21 | )
22 | ctx.create_js_file(substitutions={
23 | "dao_abi": ctx.dao_abi,
24 | "dao_address": ctx.dao_address,
25 | "wait_ms": (creation_secs-3)*1000,
26 | "amounts": arr_str(ctx.token_amounts)
27 | }
28 | )
29 | print(
30 | "Notice: Fueling period is {} seconds so the test will wait "
31 | "as much".format(creation_secs)
32 | )
33 |
34 | adjusted_amounts = (
35 | [x/1.5 for x in ctx.token_amounts]
36 | if ctx.scenario_uses_extrabalance() else ctx.token_amounts
37 | )
38 | adjusted_supply = (
39 | ctx.total_supply / 1.5
40 | if ctx.scenario_uses_extrabalance() else ctx.total_supply
41 | )
42 |
43 | ctx.execute(expected={
44 | "dao_fueled": True,
45 | "total_supply": adjusted_supply,
46 | "balances": adjusted_amounts,
47 | "user0_after": adjusted_amounts[0]
48 | })
49 |
--------------------------------------------------------------------------------
/tests/scenarios/fuel/template.js:
--------------------------------------------------------------------------------
1 | var amounts = $amounts;
2 |
3 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
4 | console.log("Creating DAO tokens");
5 | for (i = 0; i < eth.accounts.length; i++) {
6 | web3.eth.sendTransaction({
7 | from:eth.accounts[i],
8 | to: dao.address,
9 | gas:200000,
10 | value:web3.toWei(amounts[i], "ether")
11 | });
12 | }
13 |
14 | checkWork();
15 |
16 | setTimeout(function() {
17 | miner.stop();
18 | addToTest('dao_fueled', dao.isFueled());
19 | addToTest('total_supply', parseFloat(web3.fromWei(dao.totalSupply())));
20 | var balances = [];
21 | for (i = 0; i < eth.accounts.length; i++) {
22 | balances.push(parseFloat(web3.fromWei(dao.balanceOf(eth.accounts[i]))));
23 | }
24 | addToTest('balances', balances);
25 |
26 | // now also try to create some extra tokens after the creation ended
27 | // note we use createTokenProxy() directly because with the edited code
28 | // for the test the fallback function becomes a DAO donation code right
29 | // after the end of the creation period
30 | dao.createTokenProxy.sendTransaction(eth.accounts[0],{
31 | from:eth.accounts[0],
32 | to: dao.address,
33 | gas:200000,
34 | value:web3.toWei(20, "ether")
35 | });
36 | // and confirm balance is still the same
37 | checkWork();
38 | addToTest('user0_after', parseFloat(web3.fromWei(dao.balanceOf(eth.accounts[0]))));
39 | testResults();
40 | }, $wait_ms);
41 | console.log("Wait for end of creation");
42 | miner.start(1);
43 |
--------------------------------------------------------------------------------
/tests/scenarios/fuel_fail/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/fuel_fail/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/fuel_fail/run.py:
--------------------------------------------------------------------------------
1 | import random
2 | from utils import constrained_sum_sample_pos, arr_str
3 |
4 |
5 | scenario_description = (
6 | "During the fueling period of the DAO, send insufficient ether "
7 | "and assert that the DAO is not fueled. Then assert that each user can "
8 | "get a full refund"
9 | )
10 |
11 |
12 | def run(ctx):
13 | ctx.assert_scenario_ran('deploy')
14 |
15 | accounts_num = len(ctx.accounts)
16 | creation_secs = ctx.remaining_time()
17 | ctx.total_supply = random.randint(
18 | 5, ctx.args.deploy_min_tokens_to_create - 4
19 | )
20 | ctx.token_amounts = constrained_sum_sample_pos(
21 | accounts_num, ctx.total_supply
22 | )
23 | ctx.create_js_file(substitutions={
24 | "dao_abi": ctx.dao_abi,
25 | "dao_address": ctx.dao_address,
26 | "wait_ms": (creation_secs-3)*1000,
27 | "amounts": arr_str(ctx.token_amounts)
28 | }
29 | )
30 | print(
31 | "Notice: Fueling period is {} seconds so the test will wait "
32 | "as much".format(creation_secs)
33 | )
34 | ctx.execute(expected={
35 | "dao_fueled": False,
36 | "total_supply": ctx.total_supply,
37 | "refund": ctx.token_amounts
38 | })
39 |
--------------------------------------------------------------------------------
/tests/scenarios/fuel_fail/template.js:
--------------------------------------------------------------------------------
1 | var amounts = $amounts;
2 |
3 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
4 | console.log("Creating DAO tokens");
5 | for (i = 0; i < eth.accounts.length; i++) {
6 | web3.eth.sendTransaction({
7 | from:eth.accounts[i],
8 | to: dao.address,
9 | gas:200000,
10 | value:web3.toWei(amounts[i], "ether")
11 | });
12 | }
13 |
14 | checkWork();
15 |
16 | setTimeout(function() {
17 | miner.stop();
18 | addToTest('dao_min_tokens_to_create', dao.minTokensToCreate());
19 | addToTest('dao_fueled', dao.isFueled());
20 | addToTest('total_supply', parseFloat(web3.fromWei(dao.totalSupply())));
21 |
22 | // since fueling failed let's get a refund
23 | var eth_balance_before_refund = [];
24 | for (i = 0; i < eth.accounts.length; i++) {
25 | eth_balance_before_refund.push(web3.fromWei(eth.getBalance(eth.accounts[i])));
26 | }
27 | addToTest('eth_balance_before_refund', eth_balance_before_refund);
28 |
29 | for (i = 0; i < eth.accounts.length; i++) {
30 | dao.refund.sendTransaction({
31 | from:eth.accounts[i],
32 | gas:200000
33 | });
34 | }
35 | checkWork();
36 | // try to ask for a refund again and see if we get more (we shouldn't)
37 | for (i = 0; i < eth.accounts.length; i++) {
38 | dao.refund.sendTransaction({
39 | from:eth.accounts[i],
40 | gas:200000
41 | });
42 | }
43 | checkWork();
44 | var eth_balance_after_refund = [];
45 | for (i = 0; i < eth.accounts.length; i++) {
46 | eth_balance_after_refund.push(web3.fromWei(eth.getBalance(eth.accounts[i])));
47 | }
48 | addToTest('eth_balance_after_refund', eth_balance_after_refund);
49 |
50 | var refund = [];
51 | for (i = 0; i < eth.accounts.length; i++) {
52 | refund.push((bigDiffRound(
53 | testMap['eth_balance_after_refund'][i],
54 | testMap['eth_balance_before_refund'][i]
55 | )));
56 | }
57 | addToTest('refund', refund);
58 |
59 | testResults();
60 | }, $wait_ms);
61 | console.log("Wait for end of creation");
62 | miner.start(1);
63 |
--------------------------------------------------------------------------------
/tests/scenarios/fuel_fail2/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/fuel_fail2/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/fuel_fail2/run.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from utils import constrained_sum_sample_pos, arr_str
3 |
4 |
5 | scenario_description = (
6 | "During the fueling period of the DAO, create DAO tokens from all accounts "
7 | "with both normal creation and with createTokenProxy(). When the goal "
8 | "is not reached make sure that the refunds when having used "
9 | "createTokenProxy() are distributed back to the users correctly"
10 | )
11 |
12 |
13 | def run(ctx):
14 | ctx.assert_scenario_ran('deploy')
15 |
16 | accounts_num = len(ctx.accounts)
17 | if accounts_num * 2 >= ctx.args.deploy_min_tokens_to_create - 4:
18 | print("Please increase the minimum fueling goal for the scenario.")
19 | sys.exit(1)
20 |
21 | creation_secs = ctx.remaining_time()
22 | total_supply = ctx.args.deploy_min_tokens_to_create - 4
23 | proxy_amounts = constrained_sum_sample_pos(
24 | accounts_num, total_supply / 2
25 | )
26 | normal_amounts = constrained_sum_sample_pos(
27 | accounts_num, total_supply / 2
28 | )
29 | ctx.token_amounts = [
30 | sum(x) for x in zip(proxy_amounts[::-1], normal_amounts)
31 | ]
32 | ctx.total_supply = sum(ctx.token_amounts)
33 | ctx.create_js_file(
34 | substitutions={
35 | "dao_abi": ctx.dao_abi,
36 | "dao_address": ctx.dao_address,
37 | "wait_ms": (creation_secs-3)*1000,
38 | "proxy_amounts": arr_str(proxy_amounts),
39 | "normal_amounts": arr_str(normal_amounts)
40 | }
41 | )
42 | print(
43 | "Notice: Fueling period is {} seconds so the test will wait "
44 | "as much".format(creation_secs)
45 | )
46 | ctx.execute(expected={
47 | "dao_fueled": False,
48 | "total_supply": ctx.total_supply,
49 | "refund": ctx.token_amounts
50 | })
51 |
--------------------------------------------------------------------------------
/tests/scenarios/fuel_fail2/template.js:
--------------------------------------------------------------------------------
1 | var proxy_amounts = $proxy_amounts;
2 | var normal_amounts = $normal_amounts;
3 |
4 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
5 | console.log("Creating DAO tokens");
6 | for (i = 0; i < eth.accounts.length; i++) {
7 | dao.createTokenProxy.sendTransaction(
8 | eth.accounts[eth.accounts.length - 1 - i],
9 | {
10 | from:eth.accounts[i],
11 | gas:200000,
12 | value:web3.toWei(proxy_amounts[i], "ether")
13 | });
14 | }
15 | for (i = 0; i < eth.accounts.length; i++) {
16 | web3.eth.sendTransaction({
17 | from:eth.accounts[i],
18 | to: dao.address,
19 | gas:200000,
20 | value:web3.toWei(normal_amounts[i], "ether")
21 | });
22 | }
23 |
24 | checkWork();
25 |
26 | setTimeout(function() {
27 | miner.stop();
28 | addToTest('dao_min_tokens_to_create', dao.minTokensToCreate());
29 | addToTest('dao_fueled', dao.isFueled());
30 | addToTest('total_supply', parseInt(web3.fromWei(dao.totalSupply())));
31 |
32 | // since fueling failed let's get a refund
33 | var eth_balance_before_refund = [];
34 | for (i = 0; i < eth.accounts.length; i++) {
35 | eth_balance_before_refund.push(web3.fromWei(eth.getBalance(eth.accounts[i])));
36 | }
37 | addToTest('eth_balance_before_refund', eth_balance_before_refund);
38 |
39 | for (i = 0; i < eth.accounts.length; i++) {
40 | dao.refund.sendTransaction({
41 | from:eth.accounts[i],
42 | gas:200000
43 | });
44 | }
45 | checkWork();
46 | // try to ask for a refund again and see if we get more (we shouldn't)
47 | for (i = 0; i < eth.accounts.length; i++) {
48 | dao.refund.sendTransaction({
49 | from:eth.accounts[i],
50 | gas:200000
51 | });
52 | }
53 | checkWork();
54 | var eth_balance_after_refund = [];
55 | for (i = 0; i < eth.accounts.length; i++) {
56 | eth_balance_after_refund.push(web3.fromWei(eth.getBalance(eth.accounts[i])));
57 | }
58 | addToTest('eth_balance_after_refund', eth_balance_after_refund);
59 |
60 | var refund = [];
61 | for (i = 0; i < eth.accounts.length; i++) {
62 | refund.push((bigDiffRound(
63 | testMap['eth_balance_after_refund'][i],
64 | testMap['eth_balance_before_refund'][i]
65 | )));
66 | }
67 | addToTest('refund', refund);
68 |
69 | testResults();
70 | }, $wait_ms);
71 | console.log("Wait for end of creation");
72 | miner.start(1);
73 |
--------------------------------------------------------------------------------
/tests/scenarios/fuel_fail_extrabalance/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/scenarios/fuel_fail_extrabalance/run.py:
--------------------------------------------------------------------------------
1 | import random
2 | from utils import constrained_sum_sample_pos, arr_str
3 |
4 |
5 | scenario_description = (
6 | "During the fueling period of the DAO, using the extra balance, send"
7 | "insufficient ether and assert that the DAO is not fueled. Then assert "
8 | "that each user can get a full refund including the portion that was sent "
9 | "to the extra balance account. Essentially test that commit "
10 | "9ebf64b44bf5948a2df48a7072168106fcb1f69b does its job correctly."
11 | )
12 |
13 |
14 | def run(ctx):
15 | ctx.assert_scenario_ran('deploy')
16 |
17 | accounts_num = len(ctx.accounts)
18 | creation_secs = ctx.remaining_time()
19 | ctx.total_supply = random.randint(
20 | 5, ctx.args.deploy_min_tokens_to_create - 4
21 | )
22 | ctx.token_amounts = constrained_sum_sample_pos(
23 | accounts_num, ctx.total_supply
24 | )
25 | ctx.create_js_file(substitutions={
26 | "dao_abi": ctx.dao_abi,
27 | "dao_address": ctx.dao_address,
28 | "wait_ms": (creation_secs)*1000,
29 | "amounts": arr_str(ctx.token_amounts)
30 | }
31 | )
32 | print(
33 | "Notice: Fueling period is {} seconds so the test will wait "
34 | "as much".format(creation_secs)
35 | )
36 | adjusted_supply = ctx.total_supply / 1.5
37 |
38 | ctx.execute(expected={
39 | "dao_fueled": False,
40 | "total_supply": adjusted_supply,
41 | "refund": ctx.token_amounts
42 | })
43 |
--------------------------------------------------------------------------------
/tests/scenarios/fuel_fail_extrabalance/template.js:
--------------------------------------------------------------------------------
1 | var amounts = $amounts;
2 |
3 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
4 | console.log("Creating DAO tokens");
5 | for (i = 0; i < eth.accounts.length; i++) {
6 | web3.eth.sendTransaction({
7 | from:eth.accounts[i],
8 | to: dao.address,
9 | gas:200000,
10 | value:web3.toWei(amounts[i], "ether")
11 | });
12 | }
13 |
14 | checkWork();
15 |
16 | setTimeout(function() {
17 | miner.stop();
18 | addToTest('dao_min_tokens_to_create', dao.minTokensToCreate());
19 | addToTest('dao_fueled', dao.isFueled());
20 | addToTest('total_supply', parseFloat(web3.fromWei(dao.totalSupply())));
21 |
22 | // since fueling failed let's get a refund
23 | var eth_balance_before_refund = [];
24 | for (i = 0; i < eth.accounts.length; i++) {
25 | eth_balance_before_refund.push(web3.fromWei(eth.getBalance(eth.accounts[i])));
26 | }
27 | addToTest('eth_balance_before_refund', eth_balance_before_refund);
28 |
29 | for (i = 0; i < eth.accounts.length; i++) {
30 | dao.refund.sendTransaction({
31 | from:eth.accounts[i],
32 | gas:200000
33 | });
34 | }
35 | checkWork();
36 | // try to ask for a refund again and see if we get more (we shouldn't)
37 | for (i = 0; i < eth.accounts.length; i++) {
38 | dao.refund.sendTransaction({
39 | from:eth.accounts[i],
40 | gas:200000
41 | });
42 | }
43 | checkWork();
44 | var eth_balance_after_refund = [];
45 | for (i = 0; i < eth.accounts.length; i++) {
46 | eth_balance_after_refund.push(web3.fromWei(eth.getBalance(eth.accounts[i])));
47 | }
48 | addToTest('eth_balance_after_refund', eth_balance_after_refund);
49 |
50 | var refund = [];
51 | for (i = 0; i < eth.accounts.length; i++) {
52 | refund.push((bigDiffRound(
53 | testMap['eth_balance_after_refund'][i],
54 | testMap['eth_balance_before_refund'][i]
55 | )));
56 | }
57 | addToTest('refund', refund);
58 |
59 | testResults();
60 | }, $wait_ms);
61 | console.log("Wait for end of creation");
62 | miner.start(1);
63 |
--------------------------------------------------------------------------------
/tests/scenarios/fuel_predictive/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/fuel_predictive/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/fuel_predictive/run.py:
--------------------------------------------------------------------------------
1 | from utils import constrained_sum_sample_pos, arr_str
2 |
3 |
4 | scenario_description = (
5 | "This sccenario fuels the DAO with 5 tokenHollders with 10,20,30,40,50 tokens each"
6 | )
7 |
8 |
9 | def run(ctx):
10 | ctx.assert_scenario_ran('deploy')
11 |
12 | creation_secs = ctx.remaining_time()
13 | ctx.total_supply = 150
14 | ctx.token_amounts = [10 , 20 , 30, 40, 50]
15 | ctx.create_js_file(substitutions={
16 | "dao_abi": ctx.dao_abi,
17 | "dao_address": ctx.dao_address,
18 | "wait_ms": (creation_secs-3)*1000,
19 | "amounts": arr_str(ctx.token_amounts)
20 | }
21 | )
22 | print(
23 | "Notice: Fueling period is {} seconds so the test will wait "
24 | "as much".format(creation_secs)
25 | )
26 |
27 | ctx.execute(expected={
28 | "dao_fueled": True,
29 | "total_supply": 150,
30 | "balances": [10,20,30,40,50]
31 | })
32 |
--------------------------------------------------------------------------------
/tests/scenarios/fuel_predictive/template.js:
--------------------------------------------------------------------------------
1 | var amounts = $amounts;
2 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
3 | console.log("Creating DAO tokens");
4 |
5 | if (eth.accounts.length<5) {
6 | console.log("For this test, at least 5 accounts must be created.");
7 | }
8 | for (i = 0; i < amounts.length; i++) {
9 | web3.eth.sendTransaction({
10 | from:eth.accounts[i],
11 | to: dao.address,
12 | gas:1000000,
13 | value:web3.toWei(amounts[i], "ether")
14 | } /* , function(err, res) {
15 | if (err) {
16 | console.log(err);
17 | }
18 | console.log("succes: " + res);
19 | } */);
20 | }
21 |
22 | checkWork();
23 |
24 | setTimeout(function() {
25 | miner.stop();
26 | addToTest('dao_fueled', dao.isFueled());
27 | addToTest('total_supply', parseFloat(web3.fromWei(dao.totalSupply())));
28 | var balances = [];
29 | for (i = 0; i < amounts.length; i++) {
30 | balances.push(parseFloat(web3.fromWei(dao.balanceOf(eth.accounts[i]))));
31 | }
32 | addToTest('balances', balances);
33 |
34 | testResults();
35 | }, $wait_ms);
36 | console.log("Wait for end of creation");
37 | miner.start(1);
38 |
--------------------------------------------------------------------------------
/tests/scenarios/multisplitrewards/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/scenarios/multisplitrewards/run.py:
--------------------------------------------------------------------------------
1 | from utils import arr_str
2 | import time
3 |
4 | scenario_description = (
5 | """Split out of an already split DAO thus generating a grancdchild DAO.
6 | Subsequently test that rewards can be appropriately claimed for all of
7 | these DAOs by their participants as expected."""
8 | )
9 |
10 |
11 | def run(ctx):
12 | ctx.assert_scenario_ran('split')
13 | # right after the split scenario ran, wait sufficient time for the
14 | # child_dao closingTime() to be reached.
15 | time_now = round(time.time())
16 | if time_now < ctx.child_dao_closing_time:
17 | wait_for_secs = ctx.child_dao_closing_time - time_now
18 | print(
19 | "The child DAO's closing time is not yet reached. Test will wait "
20 | "for {} seconds.".format(wait_for_secs)
21 | )
22 | time.sleep(wait_for_secs)
23 | ctx.create_js_file(substitutions={
24 | "dao_abi": ctx.dao_abi,
25 | "dao_address": ctx.dao_address,
26 | "split_execution_period": ctx.args.split_execution_period,
27 | "child_dao_curator": ctx.child_dao_curator,
28 | "grandchild_dao_curator": ctx.grandchild_dao_curator,
29 | "child_dao_address": ctx.child_dao_address,
30 | "child_dao_members": arr_str(ctx.child_dao_members),
31 | "proposal_deposit": ctx.args.proposal_deposit,
32 | "debating_period": ctx.args.proposal_debate_seconds
33 | }
34 | )
35 | print(
36 | "Notice: Debate period is {} seconds so the test will wait "
37 | "as much".format(ctx.args.proposal_debate_seconds)
38 | )
39 |
40 | ctx.execute(expected={
41 | "grandchild_curator_dao_balance": ctx.grandchild_dao_curator_before,
42 | "split_proposal_passed": True
43 | })
44 |
--------------------------------------------------------------------------------
/tests/scenarios/multisplitrewards/template.js:
--------------------------------------------------------------------------------
1 | var dao_abi = $dao_abi;
2 | var dao = eth.contract(dao_abi).at('$dao_address');
3 | var child_dao = eth.contract(dao_abi).at('$child_dao_address');
4 | var child_curator = '$child_dao_curator';
5 | var child_dao_members = $child_dao_members;
6 | var grandchild_curator = '$grandchild_dao_curator';
7 | var split_execution_period = $split_execution_period;
8 | addToTest('grandchild_curator_childdao_balance', web3.fromWei(child_dao.balanceOf(grandchild_curator)).ceil());
9 | if (child_curator == grandchild_curator) {
10 | testFail("Child curator can't also be grandchild curator");
11 | }
12 |
13 | var child_prop_id = attempt_proposal(
14 | child_dao, // DAO in question
15 | grandchild_curator, // recipient
16 | grandchild_curator, // proposal creator
17 | 0, // proposal amount in ether
18 | 'Proposal to split the child DAO to the grand child DAO', // description
19 | '', //bytecode
20 | $debating_period, // debating period
21 | 0, // proposal deposit in ether
22 | true // whether it's a split proposal or not
23 | );
24 |
25 | console.log("Vote to split to grandchild DAO.");
26 | child_dao.vote.sendTransaction(child_prop_id, true, {from: grandchild_curator, gas: 1000000});
27 | checkWork();
28 | console.log("After vote to split call");
29 | setTimeout(function() {
30 | miner.stop();
31 | console.log("Executing grandchild DAO split proposal...");
32 | // now each user who voted for the split should call splitDAO to execute the proposal
33 | attempt_split(
34 | child_dao,
35 | child_prop_id,
36 | grandchild_curator,
37 | grandchild_curator,
38 | split_execution_period
39 | );
40 | checkWork();
41 | console.log("After split execution");
42 | addToTest('split_proposal_passed', child_dao.proposals(child_prop_id)[5]);
43 | addToTest('proposal_newdao', child_dao.splitProposalNewAddress(child_prop_id, 0));
44 |
45 |
46 | var grandchild_dao = web3.eth.contract(dao_abi).at(testMap['proposal_newdao']);
47 | addToTest('grandchild_dao_total_supply', parseInt(web3.fromWei(grandchild_dao.totalSupply())));
48 | addToTest('grandchild_dao_proposal_deposit', parseInt(web3.fromWei(grandchild_dao.proposalDeposit())));
49 | addToTest('grandchild_curator_dao_balance', web3.fromWei(grandchild_dao.balanceOf(grandchild_curator)).ceil());
50 | testResults();
51 | }, $debating_period * 1000);
52 | console.log("Wait for end of debating period");
53 |
--------------------------------------------------------------------------------
/tests/scenarios/newcontract/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/newcontract/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/newcontract/run.py:
--------------------------------------------------------------------------------
1 | from utils import calculate_bytecode
2 |
3 | scenario_description = (
4 | """A test of the DAO contract upgrade. We create a new contract with a
5 | completely different code and vote to transfer everything to the new
6 | contract.
7 | """
8 | )
9 |
10 |
11 | def run(ctx):
12 | ctx.assert_scenario_ran('rewards')
13 |
14 | # let's just use an existing account
15 | newAddress = ctx.accounts[4]
16 | bytecode = calculate_bytecode('newContract', ('address', ctx.accounts[4]))
17 | ctx.create_js_file(substitutions={
18 | "dao_abi": ctx.dao_abi,
19 | "dao_address": ctx.dao_address,
20 | "new_contract_address": newAddress,
21 | "proposal_deposit": ctx.args.proposal_deposit,
22 | "transaction_bytecode": bytecode,
23 | "debating_period": ctx.args.proposal_debate_seconds
24 | })
25 | print(
26 | "Notice: Debate period is {} seconds so the test will wait "
27 | "as much".format(ctx.args.proposal_debate_seconds)
28 | )
29 |
30 | ctx.execute(expected={
31 | "dao_balance_after": 0,
32 | "money_transferred": True,
33 | "reward_tokens_transferred": True
34 | })
35 |
--------------------------------------------------------------------------------
/tests/scenarios/newcontract/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 |
3 | // No need to have an actual contract for the purpose of the test
4 | var newContract = '$new_contract_address';
5 | addToTest('new_contract_balance_before', web3.fromWei(eth.getBalance(newContract)));
6 | addToTest('dao_balance_before', web3.fromWei(eth.getBalance(dao.address)));
7 | addToTest('dao_reward_token_before', web3.fromWei(dao.rewardToken(dao.address)));
8 | addToTest('new_contract_reward_token_before', web3.fromWei(dao.rewardToken(newContract)));
9 | console.log("Add new contract as allowed recipient");
10 | dao.changeAllowedRecipients.sendTransaction(newContract, true, {from: curator, gas: 1000000});
11 | checkWork();
12 |
13 | var prop_id = attempt_proposal(
14 | dao, // DAO in question
15 | dao.address, // recipient
16 | proposalCreator, // proposal creator
17 | 0, // proposal amount in ether
18 | 'Move all funds to a new contract', // description
19 | '$transaction_bytecode', //bytecode
20 | $debating_period, // debating period
21 | $proposal_deposit, // proposal deposit in ether
22 | false // whether it's a split proposal or not
23 | );
24 |
25 | console.log("Vote on the proposal to update");
26 | for (i = 0; i < eth.accounts.length; i++) {
27 | dao.vote.sendTransaction(
28 | prop_id,
29 | true,
30 | {
31 | from: eth.accounts[i],
32 | gas: 4000000
33 | }
34 | );
35 | }
36 | checkWork();
37 |
38 | setTimeout(function() {
39 | miner.stop();
40 | attempt_execute_proposal(
41 | dao, // target DAO
42 | prop_id, // proposal ID
43 | '$transaction_bytecode', // transaction bytecode
44 | curator, // proposal creator
45 | true, // should the proposal be closed after this call?
46 | true // should the proposal pass?
47 | );
48 |
49 | addToTest('new_contract_balance_after', web3.fromWei(eth.getBalance(newContract)));
50 | addToTest('dao_balance_after', web3.fromWei(eth.getBalance(dao.address)));
51 | addToTest('dao_reward_token_after', web3.fromWei(dao.rewardToken(dao.address)));
52 | addToTest('new_contract_reward_token_after', web3.fromWei(dao.rewardToken(newContract)));
53 |
54 | addToTest('new_contract_balance', bigDiff(
55 | testMap['new_contract_balance_after'],
56 | testMap['new_contract_balance_before']
57 | ));
58 | addToTest(
59 | 'money_transferred',
60 | testMap['new_contract_balance'].ceil().equals(testMap['dao_balance_before'].ceil())
61 | );
62 | addToTest(
63 | 'reward_tokens_transferred',
64 | testMap['new_contract_reward_token_after'].ceil().equals(testMap['dao_reward_token_before'].ceil())
65 | );
66 |
67 |
68 | testResults();
69 | }, $debating_period * 1000);
70 | console.log("Wait for end of debating period");
71 | miner.start(1);
72 |
--------------------------------------------------------------------------------
/tests/scenarios/newcontractfail/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/newcontractfail/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/newcontractfail/run.py:
--------------------------------------------------------------------------------
1 | from utils import calculate_bytecode, create_votes_array_for_quorum, arr_str
2 |
3 | scenario_description = (
4 | """A test of the DAO contract upgrade where the proposal's quorum ends up
5 | being insufficient (<53.3%) and the proposal gets rejected.
6 | """
7 | )
8 |
9 |
10 | def run(ctx):
11 | ctx.assert_scenario_ran('fuel')
12 |
13 | votes = create_votes_array_for_quorum(ctx.token_amounts, 0.4, True, False)
14 | # let's just use an existing account
15 | newAddress = ctx.accounts[4]
16 | bytecode = calculate_bytecode('newContract', ("address", newAddress))
17 | ctx.create_js_file(substitutions={
18 | "dao_abi": ctx.dao_abi,
19 | "dao_address": ctx.dao_address,
20 | "new_contract_address": newAddress,
21 | "proposal_deposit": ctx.args.proposal_deposit,
22 | "votes": arr_str(votes),
23 | "transaction_bytecode": bytecode,
24 | "debating_period": ctx.args.proposal_debate_seconds
25 | })
26 | print(
27 | "Notice: Debate period is {} seconds so the test will wait "
28 | "as much".format(ctx.args.proposal_debate_seconds)
29 | )
30 |
31 | ctx.execute(expected={
32 | "new_contract_balance": 0,
33 | "dao_balance_diff": 0
34 | })
35 |
--------------------------------------------------------------------------------
/tests/scenarios/newcontractfail/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 |
3 | // No need to have an actual contract for the purpose of the test
4 | var newContract = '$new_contract_address';
5 | addToTest('new_contract_balance_before', web3.fromWei(eth.getBalance(newContract)));
6 | addToTest('dao_balance_before', web3.fromWei(eth.getBalance(dao.address)));
7 | console.log("Add new contract as allowed recipient");
8 | dao.changeAllowedRecipients.sendTransaction(newContract, true, {from: curator, gas: 1000000});
9 | checkWork();
10 |
11 | var prop_id = attempt_proposal(
12 | dao, // DAO in question
13 | dao.address, // recipient
14 | proposalCreator, // proposal creator
15 | 0, // proposal amount in ether
16 | 'Move all funds to a new contract', // description
17 | '$transaction_bytecode', //bytecode
18 | $debating_period, // debating period
19 | $proposal_deposit, // proposal deposit in ether
20 | false // whether it's a split proposal or not
21 | );
22 |
23 | console.log("Vote on the proposal to update");
24 | var votes = $votes;
25 | for (i = 0; i < votes.length; i++) {
26 | dao.vote.sendTransaction(
27 | prop_id,
28 | votes[i],
29 | {
30 | from: eth.accounts[i],
31 | gas: 4000000
32 | }
33 | );
34 | }
35 | checkWork();
36 |
37 | setTimeout(function() {
38 | miner.stop();
39 | attempt_execute_proposal(
40 | dao, // target DAO
41 | prop_id, // proposal ID
42 | '$transaction_bytecode', // transaction bytecode
43 | curator, // proposal creator
44 | false, // should the proposal be closed after this call?
45 | false // should the proposal pass?
46 | );
47 |
48 | addToTest('new_contract_balance_after', web3.fromWei(eth.getBalance(newContract)));
49 | addToTest('new_contract_balance', bigDiff(
50 | testMap['new_contract_balance_after'],
51 | testMap['new_contract_balance_before']
52 | ));
53 | addToTest('dao_balance_after', web3.fromWei(eth.getBalance(dao.address)));
54 | addToTest('dao_balance_diff', bigDiff(
55 | testMap['dao_balance_after'],
56 | testMap['dao_balance_before']
57 | ));
58 |
59 | testResults();
60 | }, $debating_period * 1000);
61 | console.log("Wait for end of debating period");
62 | miner.start(1);
63 |
--------------------------------------------------------------------------------
/tests/scenarios/pfoffer/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/pfoffer/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/pfoffer/run.py:
--------------------------------------------------------------------------------
1 | from utils import calculate_bytecode
2 |
3 | scenario_description = (
4 | "Make a proposal to sign the PFOFfer and make sure that no money is "
5 | "transferred during the signing of the proposal. Also assert that "
6 | "calling getDailyPayment immediately after signing and within the "
7 | "payoutFreezePeriod fails."
8 | )
9 |
10 |
11 | def run(ctx):
12 | ctx.assert_scenario_ran('fuel')
13 | bytecode = calculate_bytecode('sign')
14 | ctx.create_js_file(substitutions={
15 | "dao_abi": ctx.dao_abi,
16 | "dao_address": ctx.dao_address,
17 | "pfoffer_abi": ctx.pfoffer_abi,
18 | "pfoffer_address": ctx.pfoffer_address,
19 | "offer_amount": ctx.args.deploy_total_costs,
20 | "proposal_deposit": ctx.args.proposal_deposit,
21 | "transaction_bytecode": bytecode,
22 | "debating_period": ctx.args.proposal_debate_seconds,
23 | "vote_status_deadline": ctx.args.deploy_pfoffer_vote_status_deadline
24 | })
25 | print(
26 | "Notice: Debate period is {} seconds so the test will wait "
27 | "as much".format(ctx.args.proposal_debate_seconds)
28 | )
29 |
30 | ctx.execute(expected={
31 | "only_contractor_can_watch_proposal": True,
32 | "proposal_succesfully_watched": True,
33 | "approved_before_deadline": True,
34 | "no_money_at_sign": True,
35 | "contract_valid": True,
36 | "onetime_payment_failed": True
37 | })
38 |
--------------------------------------------------------------------------------
/tests/scenarios/pfoffer/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 | var pfoffer = web3.eth.contract($pfoffer_abi).at('$pfoffer_address');
3 |
4 | console.log("Add pfoffer contract as allowed recipient");
5 | dao.changeAllowedRecipients.sendTransaction('$pfoffer_address', true, {from: curator, gas: 1000000});
6 | checkWork();
7 |
8 | var prop_id = attempt_proposal(
9 | dao, // DAO in question
10 | '$pfoffer_address', // recipient
11 | proposalCreator, // proposal creator
12 | $offer_amount, // proposal amount in ether
13 | 'PFOffer Description', // description
14 | '$transaction_bytecode', //bytecode
15 | $debating_period, // debating period
16 | $proposal_deposit, // proposal deposit in ether
17 | false // whether it's a split proposal or not
18 | );
19 |
20 | // the contractor should now make the offer contract watch the proposal votes
21 | pfoffer.watchProposal.sendTransaction(prop_id, {from:curator, gas: 400000});
22 | checkWork();
23 | addToTest('only_contractor_can_watch_proposal', pfoffer.getProposalID() == 0);
24 | pfoffer.watchProposal.sendTransaction(prop_id, {from:contractor, gas: 400000});
25 | checkWork();
26 | addToTest('proposal_succesfully_watched', pfoffer.getProposalID().eq(prop_id));
27 |
28 |
29 | console.log("Vote on the proposals");
30 | for (i = 0; i < eth.accounts.length; i++) {
31 | dao.vote.sendTransaction(
32 | prop_id,
33 | true,
34 | {
35 | from: eth.accounts[i],
36 | gas: 4000000
37 | }
38 | );
39 | }
40 | checkWork();
41 |
42 | //perform the vote status check
43 | pfoffer.checkVoteStatus.sendTransaction({from: curator, gas: 400000});
44 | checkWork();
45 | addToTest('approved_before_deadline', pfoffer.getWasApprovedBeforeDeadline());
46 |
47 |
48 | setTimeout(function() {
49 | miner.stop();
50 | console.log("After debating period. NOW is: " + Math.floor(Date.now() / 1000));
51 | var contractor_before = eth.getBalance(contractor);
52 | // execute the sign()
53 | attempt_execute_proposal(
54 | dao, // target DAO
55 | prop_id, // proposal ID
56 | '$transaction_bytecode', // transaction bytecode
57 | proposalCreator, // proposal creator
58 | true, // should the proposal be closed after this call?
59 | true // should the proposal pass?
60 | );
61 | var contractor_after = eth.getBalance(contractor);
62 | addToTest('no_money_at_sign', contractor_after.eq(contractor_before));
63 | addToTest('contract_valid', pfoffer.getIsContractValid());
64 | // now attempt to execute getOneTimePayment and expect it to fail
65 | pfoffer.performInitialWithdrawal.sendTransaction({from: contractor, gas: 300000});
66 | checkWork();
67 | var contractor_after_onetime = eth.getBalance(contractor);
68 | addToTest('onetime_payment_failed', contractor_after_onetime.sub(contractor_after).lt(web3.toWei(1)));
69 |
70 | testResults();
71 | }, $debating_period * 1000);
72 | console.log("Wait for end of debating period");
73 | miner.start(1);
74 |
--------------------------------------------------------------------------------
/tests/scenarios/pfoffer_checkvotestatus_fail/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/pfoffer_checkvotestatus_fail/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/pfoffer_checkvotestatus_fail/run.py:
--------------------------------------------------------------------------------
1 | from utils import calculate_bytecode
2 |
3 | scenario_description = (
4 | "Work on a PFOFfer contract with a very big vote status deadline which "
5 | "will guarantee failure of the checkVoteStatus() call due to the "
6 | "aforementioned deadline. Check that the failure indeed happens."
7 | )
8 |
9 |
10 | def run(ctx):
11 | ctx.assert_scenario_ran('fuel')
12 | bytecode = calculate_bytecode('sign')
13 | ctx.create_js_file(substitutions={
14 | "dao_abi": ctx.dao_abi,
15 | "dao_address": ctx.dao_address,
16 | "pfoffer_abi": ctx.pfoffer_abi,
17 | "pfoffer_address": ctx.pfoffer_address,
18 | "offer_amount": ctx.args.deploy_total_costs,
19 | "proposal_deposit": ctx.args.proposal_deposit,
20 | "transaction_bytecode": bytecode,
21 | "debating_period": ctx.args.proposal_debate_seconds,
22 | "vote_status_deadline": ctx.args.deploy_pfoffer_vote_status_deadline
23 | })
24 |
25 | ctx.execute(expected={
26 | "proposal_succesfully_watched": True,
27 | "approved_before_deadline": False,
28 | })
29 |
--------------------------------------------------------------------------------
/tests/scenarios/pfoffer_checkvotestatus_fail/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 | var pfoffer = web3.eth.contract($pfoffer_abi).at('$pfoffer_address');
3 |
4 | console.log("Add pfoffer contract as allowed recipient");
5 | dao.changeAllowedRecipients.sendTransaction('$pfoffer_address', true, {from: curator, gas: 1000000});
6 | checkWork();
7 |
8 | var prop_id = attempt_proposal(
9 | dao, // DAO in question
10 | '$pfoffer_address', // recipient
11 | proposalCreator, // proposal creator
12 | $offer_amount, // proposal amount in ether
13 | 'PFOffer Description', // description
14 | '$transaction_bytecode', //bytecode
15 | $debating_period, // debating period
16 | $proposal_deposit, // proposal deposit in ether
17 | false // whether it's a split proposal or not
18 | );
19 |
20 | // the contractor should now make the offer contract watch the proposal votes
21 | pfoffer.watchProposal.sendTransaction(prop_id, {from:contractor, gas: 400000});
22 | checkWork();
23 | addToTest('proposal_succesfully_watched', pfoffer.getProposalID().eq(prop_id));
24 |
25 |
26 | console.log("Vote on the proposals");
27 | for (i = 0; i < eth.accounts.length; i++) {
28 | dao.vote.sendTransaction(
29 | prop_id,
30 | true,
31 | {
32 | from: eth.accounts[i],
33 | gas: 4000000
34 | }
35 | );
36 | }
37 | checkWork();
38 |
39 | //perform the vote status check
40 | pfoffer.checkVoteStatus.sendTransaction({from: curator, gas: 400000});
41 | checkWork();
42 | addToTest('approved_before_deadline', pfoffer.getWasApprovedBeforeDeadline());
43 | testResults();
44 |
--------------------------------------------------------------------------------
/tests/scenarios/pfoffer_payment/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/pfoffer_payment/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/pfoffer_payment/run.py:
--------------------------------------------------------------------------------
1 | from utils import calculate_bytecode
2 |
3 | scenario_description = (
4 | "Get the onetime payment from the PFOffer contract after the payoutFreeze "
5 | "period has passed."
6 | )
7 |
8 |
9 | def run(ctx):
10 | ctx.assert_scenario_ran('pfoffer')
11 | ctx.create_js_file(substitutions={
12 | "dao_abi": ctx.dao_abi,
13 | "dao_address": ctx.dao_address,
14 | "pfoffer_abi": ctx.pfoffer_abi,
15 | "pfoffer_address": ctx.pfoffer_address,
16 | "offer_amount": ctx.args.deploy_total_costs,
17 | "expected_onetime": ctx.args.deploy_onetime_costs,
18 | "proposal_deposit": ctx.args.proposal_deposit,
19 | "debating_period": ctx.args.proposal_debate_seconds,
20 | "payout_freeze_period": ctx.args.deploy_pfoffer_payout_freeze_period
21 | })
22 |
23 | ctx.execute(expected={
24 | "one_time_paid": True,
25 | "one_time_costs_amount_as_expected": True
26 | })
27 |
--------------------------------------------------------------------------------
/tests/scenarios/pfoffer_payment/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 | var pfoffer = web3.eth.contract($pfoffer_abi).at('$pfoffer_address');
3 |
4 | // assert the time is right
5 | var now = new BigNumber(time_now());
6 | var sign_time = pfoffer.getDateOfSignature();
7 | var wait_time = now.sub(sign_time.add($payout_freeze_period));
8 | if (wait_time < 0) {
9 | wait_time = 0;
10 | }
11 | setTimeout(function() {
12 | var contractor_before = eth.getBalance(contractor);
13 | pfoffer.performInitialWithdrawal.sendTransaction({from: curator, gas: 300000});
14 | checkWork();
15 | var contractor_after = eth.getBalance(contractor);
16 | addToTest('only_contractor_can_call', !pfoffer.getInitialWithdrawalDone());
17 | pfoffer.performInitialWithdrawal.sendTransaction({from: contractor, gas: 500000});
18 | checkWork();
19 | var contractor_after2 = eth.getBalance(contractor);
20 | addToTest('one_time_paid', pfoffer.getInitialWithdrawalDone());
21 | addToTest(
22 | 'one_time_costs_amount_as_expected',
23 | contractor_after2.sub(contractor_after).sub(web3.toWei($expected_onetime)).abs().lt(new BigNumber(100000000000000000))
24 | );
25 | testResults();
26 | }, wait_time * 1000);
27 | console.log("Waiting for " + wait_time + " seconds until the payoutfreezeperiod is over");
28 |
29 |
30 |
--------------------------------------------------------------------------------
/tests/scenarios/proposal/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/proposal/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/proposal/arguments.json:
--------------------------------------------------------------------------------
1 | [{
2 | "name": "debate_seconds",
3 | "default": 20,
4 | "description": "Number of seconds that a proposal should be open for voting",
5 | "type": "int"
6 | }, {
7 | "name": "deposit",
8 | "default": 25,
9 | "description": "The proposal deposit. Has to be more than 20 ether",
10 | "type": "int"
11 | }, {
12 | "name": "halveminquorum",
13 | "default": false,
14 | "description": "If true then halveMinQuorum() is called before voting on the proposal.",
15 | "type": "bool"
16 | }]
17 |
--------------------------------------------------------------------------------
/tests/scenarios/proposal/run.py:
--------------------------------------------------------------------------------
1 | import random
2 | from utils import arr_str, create_votes_array, bool_to_str
3 |
4 | scenario_description = (
5 | "Create a proposal to send an amount of ether to the SampleOffer contract."
6 | " Vote on that proposal, wait for the debating period and then execute it."
7 | " Assert that the proposal deposit is returned to its creator, and that "
8 | "the amount is sent to the SampleOffer and the promise is valid"
9 | )
10 |
11 |
12 | def count_token_votes(amounts, votes):
13 | """Returns how many tokens votes yay and how many voted nay"""
14 | yay = 0
15 | nay = 0
16 | for idx, amount in enumerate(amounts):
17 | if votes[idx]:
18 | yay += amount
19 | else:
20 | nay += amount
21 | return yay, nay
22 |
23 |
24 | def run(ctx):
25 | ctx.assert_scenario_ran('fuel')
26 |
27 | votes = create_votes_array(
28 | ctx.token_amounts,
29 | not ctx.args.proposal_fail,
30 | False
31 | )
32 | yay, nay = count_token_votes(ctx.token_amounts, votes)
33 | ctx.create_js_file(substitutions={
34 | "dao_abi": ctx.dao_abi,
35 | "dao_address": ctx.dao_address,
36 | "offer_abi": ctx.offer_abi,
37 | "offer_address": ctx.offer_address,
38 | "offer_amount": ctx.args.deploy_total_costs,
39 | "offer_desc": 'Test Proposal',
40 | "proposal_deposit": ctx.args.proposal_deposit,
41 | "transaction_bytecode": '0x2ca15122', # solc --hashes SampleOffer.sol
42 | "debating_period": ctx.args.proposal_debate_seconds,
43 | "votes": arr_str(votes),
44 | "should_halve_minquorum": bool_to_str(ctx.args.proposal_halveminquorum)
45 | })
46 | print(
47 | "Notice: Debate period is {} seconds so the test will wait "
48 | "as much".format(ctx.args.proposal_debate_seconds)
49 | )
50 |
51 | ctx.execute(expected={
52 | "dao_proposals_number": "1",
53 | "proposal_yay": yay,
54 | "proposal_nay": nay,
55 | "calculated_deposit": ctx.args.proposal_deposit,
56 | "onetime_costs": ctx.args.deploy_onetime_costs,
57 | "deposit_returned": True,
58 | "offer_promise_valid": True
59 | })
60 |
--------------------------------------------------------------------------------
/tests/scenarios/proposal/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 | var offer = web3.eth.contract($offer_abi).at('$offer_address');
3 |
4 | console.log("Add offer contract as allowed recipient");
5 | dao.changeAllowedRecipients.sendTransaction('$offer_address', true, {from: curator, gas: 1000000});
6 | checkWork();
7 |
8 | if ($should_halve_minquorum) {
9 | console.log("Calling dao.halveMinQuorum()");
10 | dao.halveMinQuorum.sendTransaction({from: eth.accounts[0], gas: 1000000});
11 | }
12 |
13 | addToTest('creator_balance_before', eth.getBalance(proposalCreator));
14 | var prop_id = attempt_proposal(
15 | dao, // DAO in question
16 | '$offer_address', // recipient
17 | proposalCreator, // proposal creator
18 | $offer_amount, // proposal amount in ether
19 | '$offer_desc', // description
20 | '$transaction_bytecode', //bytecode
21 | $debating_period, // debating period
22 | $proposal_deposit, // proposal deposit in ether
23 | false // whether it's a split proposal or not
24 | );
25 |
26 | addToTest('creator_balance_after_proposal', eth.getBalance(proposalCreator));
27 | addToTest(
28 | 'calculated_deposit',
29 | web3.fromWei(testMap['creator_balance_before'].sub(testMap['creator_balance_after_proposal']))
30 | );
31 | addToTest('dao_proposals_number', dao.numberOfProposals());
32 |
33 | var votes = $votes;
34 | console.log("Deadline is: " + dao.proposals(prop_id)[3] + " Voting ... ");
35 | for (i = 0; i < votes.length; i++) {
36 | console.log("User " + i +" is voting ["+ votes[i] +"]. His token balance is: " + web3.fromWei(dao.balanceOf(eth.accounts[i])) + " ether and NOW is: " + Math.floor(Date.now() / 1000));
37 | dao.vote.sendTransaction(
38 | prop_id,
39 | votes[i],
40 | {
41 | from: eth.accounts[i],
42 | gas: 1000000
43 | }
44 | );
45 | }
46 | checkWork();
47 | addToTest('proposal_yay', parseInt(web3.fromWei(dao.proposals(prop_id)[9])));
48 | addToTest('proposal_nay', parseInt(web3.fromWei(dao.proposals(prop_id)[10])));
49 | addToTest('contractor_balance_before', eth.getBalance(contractor));
50 |
51 | setTimeout(function() {
52 | miner.stop();
53 | console.log("After debating period. NOW is: " + Math.floor(Date.now() / 1000));
54 | attempt_execute_proposal(
55 | dao, // target DAO
56 | prop_id, // proposal ID
57 | '$transaction_bytecode', // transaction bytecode
58 | proposalCreator, // proposal creator
59 | true, // should the proposal be closed after this call?
60 | true // should the proposal pass?
61 | );
62 |
63 | addToTest('creator_balance_after_execution', eth.getBalance(proposalCreator));
64 | addToTest('contractor_balance_after', eth.getBalance(contractor));
65 |
66 | addToTest(
67 | 'onetime_costs',
68 | web3.fromWei(testMap['contractor_balance_after'].sub(testMap['contractor_balance_before']))
69 | );
70 | addToTest(
71 | 'deposit_returned',
72 | testMap['creator_balance_after_execution'].sub(testMap['creator_balance_before']).lt(new BigNumber(100000000000000000))
73 | );
74 | addToTest('offer_promise_valid', offer.getIsContractValid());
75 |
76 | testResults();
77 | }, $debating_period * 1000);
78 | console.log("Wait for end of debating period");
79 | miner.start(1);
80 |
--------------------------------------------------------------------------------
/tests/scenarios/rewards/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/rewards/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/rewards/arguments.json:
--------------------------------------------------------------------------------
1 | [{
2 | "name": "total_amount",
3 | "default": 200,
4 | "description": "Amount of ether a kind soul will donate to the DAO in the rewards scenario.",
5 | "type": "int"
6 | }]
7 |
--------------------------------------------------------------------------------
/tests/scenarios/rewards/run.py:
--------------------------------------------------------------------------------
1 | from utils import calculate_bytecode
2 |
3 | scenario_description = (
4 | " A kind soul donates to the DAO so the DAO has rewards for distribution. "
5 | "Create a proposal to send the rewards to the RewardsAccount, vote and "
6 | "execute it. Subsequently claim rewards and assert that they are "
7 | "proportional to the tokens held by the account claiming the reward."
8 | )
9 |
10 |
11 | def calculate_reward(tokens, total_tokens, total_rewards):
12 | result = (tokens * float(total_rewards)) / float(total_tokens)
13 | return result
14 |
15 |
16 | def run(ctx):
17 | ctx.assert_scenario_ran('proposal')
18 |
19 | bytecode = calculate_bytecode('retrieveDAOReward', ("bool", True))
20 | ctx.create_js_file(substitutions={
21 | "dao_abi": ctx.dao_abi,
22 | "dao_address": ctx.dao_address,
23 | "total_rewards": ctx.args.rewards_total_amount,
24 | "proposal_deposit": ctx.args.proposal_deposit,
25 | "transaction_bytecode": bytecode,
26 | "debating_period": ctx.args.proposal_debate_seconds
27 | }
28 | )
29 | print(
30 | "Notice: Debate period is {} seconds so the test will wait "
31 | "as much".format(ctx.args.proposal_debate_seconds)
32 | )
33 |
34 | results = ctx.execute(expected={
35 | "curator_reward_portion": calculate_reward(
36 | ctx.token_amounts[0],
37 | ctx.total_supply,
38 | ctx.args.rewards_total_amount)
39 | })
40 | ctx.dao_balance_after_rewards = results['DAO_balance']
41 | ctx.dao_rewardToken_after_rewards = results['DAO_rewardToken']
42 |
--------------------------------------------------------------------------------
/tests/scenarios/rewards/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 |
3 | // some kind soul makes a donation to the DAO, so rewards get populated
4 | console.log("Donating to DAO...");
5 | eth.sendTransaction({
6 | from:eth.accounts[1],
7 | to: dao.DAOrewardAccount(),
8 | gas: 210000,
9 | value: web3.toWei($total_rewards, "ether")
10 | });
11 | checkWork();
12 |
13 | var prop_id = attempt_proposal(
14 | dao, // DAO in question
15 | dao.address, // recipient
16 | proposalCreator, // proposal creator
17 | 0, // proposal amount in ether
18 | 'Ask the DAO to retrieveDAOReward()', // description
19 | '$transaction_bytecode', //bytecode
20 | $debating_period, // debating period
21 | $proposal_deposit + 1, // proposal deposit in ether
22 | false // whether it's a split proposal or not
23 | );
24 |
25 | console.log("Voting for proposal '" + prop_id + "' ...");
26 | // in this scenario let's just say everyone votes 100% in favour
27 | for (i = 0; i < eth.accounts.length; i++) {
28 | dao.vote.sendTransaction(
29 | prop_id,
30 | true,
31 | {
32 | from: eth.accounts[i],
33 | gas: 1000000
34 | }
35 | );
36 | }
37 | checkWork();
38 |
39 | setTimeout(function() {
40 | miner.stop();
41 |
42 | // now execute the proposal
43 | attempt_execute_proposal(
44 | dao, // target DAO
45 | prop_id, // proposal ID
46 | '$transaction_bytecode', // transaction bytecode
47 | curator, // proposal creator
48 | true, // should the proposal be closed after this call?
49 | true // should the proposal pass?
50 | );
51 |
52 | addToTest('curator_balance_before_claim', eth.getBalance(curator));
53 | console.log("Claiming the reward...");
54 | dao.getMyReward.sendTransaction({from: curator, gas: 1000000});
55 | checkWork();
56 | addToTest('curator_balance_after_claim', eth.getBalance(curator));
57 | addToTest(
58 | 'curator_reward_portion',
59 | parseFloat(web3.fromWei(bigDiff(
60 | testMap['curator_balance_after_claim'], testMap['curator_balance_before_claim']
61 | )))
62 | );
63 | addToTest('DAO_balance', parseFloat(web3.fromWei(eth.getBalance('$dao_address'))));
64 | addToTest('DAO_rewardToken', parseFloat(web3.fromWei(dao.rewardToken('$dao_address'))));
65 | testResults();
66 | }, $debating_period * 1000);
67 | console.log("Wait for end of debating period");
68 |
--------------------------------------------------------------------------------
/tests/scenarios/sampleoffer_changeclient/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/scenarios/sampleoffer_changeclient/run.py:
--------------------------------------------------------------------------------
1 | from utils import arr_str, calculate_bytecode
2 | import time
3 |
4 | scenario_description = (
5 | """Test that the offer's client can be properly changed to a split DAO."""
6 | )
7 |
8 |
9 | def run(ctx):
10 | ctx.assert_scenario_ran('split')
11 | # right after the split scenario ran, wait sufficient time for the
12 | # child_dao closingTime() to be reached.
13 | time_now = round(time.time())
14 | if time_now < ctx.child_dao_closing_time:
15 | wait_for_secs = ctx.child_dao_closing_time - time_now
16 | print(
17 | "The child DAO's closing time is not yet reached. Test will wait "
18 | "for {} seconds.".format(wait_for_secs)
19 | )
20 | time.sleep(wait_for_secs)
21 | transaction_bytecode = calculate_bytecode(
22 | 'updateClientAddress', ('address', ctx.child_dao_address)
23 | )
24 | ctx.create_js_file(substitutions={
25 | "dao_abi": ctx.dao_abi,
26 | "dao_address": ctx.dao_address,
27 | "split_execution_period": ctx.args.split_execution_period,
28 | "child_dao_curator": ctx.child_dao_curator,
29 | "child_dao_address": ctx.child_dao_address,
30 | "offer_abi": ctx.offer_abi,
31 | "offer_address": ctx.offer_address,
32 | "child_dao_members": arr_str(ctx.child_dao_members),
33 | "proposal_deposit": ctx.args.proposal_deposit,
34 | "debating_period": ctx.args.proposal_debate_seconds,
35 | "transaction_bytecode": transaction_bytecode
36 | }
37 | )
38 | print(
39 | "Notice: Debate period is {} seconds so the test will wait "
40 | "as much".format(ctx.args.proposal_debate_seconds)
41 | )
42 |
43 | ctx.execute(expected={
44 | "offer_client": ctx.child_dao_address,
45 | "offer_original_client": ctx.dao_address
46 | })
47 |
--------------------------------------------------------------------------------
/tests/scenarios/sampleoffer_changeclient/template.js:
--------------------------------------------------------------------------------
1 | var dao_abi = $dao_abi;
2 | var dao = eth.contract(dao_abi).at('$dao_address');
3 | var child_dao = eth.contract(dao_abi).at('$child_dao_address');
4 | var child_curator = '$child_dao_curator';
5 | var child_dao_members = $child_dao_members;
6 | var offer = web3.eth.contract($offer_abi).at('$offer_address');
7 |
8 | // The DAO will now propose for the child DAO to be the new client
9 | var prop_id = attempt_proposal(
10 | dao, // DAO in question
11 | '$offer_address', // recipient
12 | curator, // proposal creator
13 | 0, // proposal amount in ether
14 | 'Change the client of this Sampleoffer', // description
15 | '$transaction_bytecode', //bytecode
16 | $debating_period, // debating period
17 | $proposal_deposit, // proposal deposit in ether
18 | false // whether it's a split proposal or not
19 | );
20 |
21 | console.log("Voting for the proposal to change client");
22 | for (i = 0; i < eth.accounts.length; i++) {
23 | dao.vote.sendTransaction(
24 | prop_id,
25 | true, //omg it's unanimous!
26 | {
27 | from: eth.accounts[i],
28 | gas: 1000000
29 | }
30 | );
31 | }
32 | checkWork();
33 |
34 | setTimeout(function() {
35 | miner.stop();
36 | console.log("After debating period. NOW is: " + Math.floor(Date.now() / 1000));
37 | attempt_execute_proposal(
38 | dao, // target DAO
39 | prop_id, // proposal ID
40 | '$transaction_bytecode', // transaction bytecode
41 | curator, // proposal creator
42 | true, // should the proposal be closed after this call?
43 | true // should the proposal pass?
44 | );
45 |
46 | addToTest('offer_original_client', offer.getOriginalClient());
47 | addToTest('offer_client', offer.getClient());
48 |
49 | console.log("Add offer contract as allowed recipient for the Child DAO");
50 | child_dao.changeAllowedRecipients.sendTransaction('$offer_address', true, {from: child_curator, gas: 1000000});
51 | testResults();
52 |
53 | }, $debating_period * 1000);
54 | miner.start(1);
55 | console.log("Wait for end of debating period");
56 |
--------------------------------------------------------------------------------
/tests/scenarios/sampleoffer_dailypayment/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/scenarios/sampleoffer_dailypayment/run.py:
--------------------------------------------------------------------------------
1 | from utils import calculate_bytecode, to_wei
2 |
3 | scenario_description = (
4 | "Test a normal usage of the SampleOffer contract where there is a payment "
5 | "coming in from a deployed USN node and it goes to the DAO Reward account."
6 | "Also test that the contractor can properly withdraw the daily payment, "
7 | "calculating how much Wei he entitlted to depend in the 'day-periods' "
8 | "that have passed since signing the contract."
9 | )
10 |
11 |
12 | def run(ctx):
13 | ctx.assert_scenario_ran('proposal')
14 | daily_limit_in_ether = 5
15 | pay_reward_amount = 10
16 | bytecode = calculate_bytecode('setDailyWithdrawLimit', ('uint128', to_wei(daily_limit_in_ether)))
17 | ctx.create_js_file(substitutions={
18 | "dao_abi": ctx.dao_abi,
19 | "dao_address": ctx.dao_address,
20 | "offer_abi": ctx.offer_abi,
21 | "offer_address": ctx.offer_address,
22 | "usn_abi": ctx.usn_abi,
23 | "usn_address": ctx.usn_address,
24 | "proposal_deposit": ctx.args.proposal_deposit,
25 | "pay_reward_amount": pay_reward_amount,
26 | "transaction_bytecode": bytecode,
27 | "debating_period": ctx.args.proposal_debate_seconds,
28 | "offer_payment_period": ctx.args.deploy_offer_payment_period
29 | })
30 | print(
31 | "Notice: Debate period is {} seconds so the test will wait "
32 | "as much".format(ctx.args.proposal_debate_seconds)
33 | )
34 |
35 | ctx.execute(expected={
36 | "offer_daily_withdraw_limit": daily_limit_in_ether,
37 | "contractor_paid_expected": True,
38 | "dao_rewardaccount_diff": pay_reward_amount,
39 | "sample_offer_no_donations": True,
40 | })
41 |
--------------------------------------------------------------------------------
/tests/scenarios/sampleoffer_dailypayment/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 | var offer = web3.eth.contract($offer_abi).at('$offer_address');
3 | var usn = web3.eth.contract($usn_abi).at('$usn_address');
4 |
5 | addToTest('dao_rewardaccount_before', eth.getBalance(dao.DAOrewardAccount()));
6 | // 'emulate' a USN node payment
7 | usn.payReward.sendTransaction({from:eth.accounts[3], value: web3.toWei($pay_reward_amount), gas: 100000});
8 | checkWork();
9 | addToTest('dao_rewardaccount_after', eth.getBalance(dao.DAOrewardAccount()));
10 | addToTest(
11 | 'dao_rewardaccount_diff',
12 | web3.fromWei(bigDiff(testMap['dao_rewardaccount_after'], testMap['dao_rewardaccount_before']))
13 | );
14 |
15 |
16 | var offer_balance_before = eth.getBalance(offer.address);
17 | // also let's sneak in a check that SampleOffer does not accept random donations
18 | web3.eth.sendTransaction({from:eth.accounts[3], to:offer.address, value:web3.toWei(10), gas:24000});
19 | var offer_balance_after = eth.getBalance(offer.address);
20 | addToTest('sample_offer_no_donations', offer_balance_after.eq(offer_balance_before));
21 |
22 |
23 | // The DAO will now set the daily withdrawal limit
24 | var prop_id = attempt_proposal(
25 | dao, // DAO in question
26 | '$offer_address', // recipient
27 | proposalCreator, // proposal creator
28 | 0, // proposal amount in ether
29 | 'Set the daily withdrawal limit of SampleOffer', // description
30 | '$transaction_bytecode', //bytecode
31 | $debating_period, // debating period
32 | $proposal_deposit, // proposal deposit in ether
33 | false // whether it's a split proposal or not
34 | );
35 |
36 |
37 | console.log("Voting for the proposal to set the Daily withdraw limit");
38 | for (i = 0; i < eth.accounts.length; i++) {
39 | dao.vote.sendTransaction(
40 | prop_id,
41 | true, //omg it's unanimous!
42 | {
43 | from: eth.accounts[i],
44 | gas: 1000000
45 | }
46 | );
47 | }
48 | checkWork();
49 |
50 | setTimeout(function() {
51 | miner.stop();
52 | console.log("After debating period. NOW is: " + Math.floor(Date.now() / 1000));
53 | attempt_execute_proposal(
54 | dao, // target DAO
55 | prop_id, // proposal ID
56 | '$transaction_bytecode', // transaction bytecode
57 | proposalCreator, // proposal creator
58 | true, // should the proposal be closed after this call?
59 | true // should the proposal pass?
60 | );
61 |
62 | addToTest('offer_daily_withdraw_limit', web3.fromWei(offer.getDailyWithdrawalLimit()));
63 |
64 | addToTest('contractor_before', eth.getBalance(contractor));
65 | // now the contractor can attempt to withdraw some money and we should check that this
66 | // occurs and is equal to the daily limit
67 | console.log("-->OfferBalance: " + web3.fromWei(eth.getBalance(offer.address)));
68 | offer.withdraw.sendTransaction({from: contractor, gas: 100000});
69 | var withdrawTime = new BigNumber(Math.floor(Date.now() / 1000));
70 | checkWork();
71 | var expectedWei = ((withdrawTime.sub(offer.getDateOfSignature())).mul(offer.getDailyWithdrawalLimit()))
72 | .div(new BigNumber($offer_payment_period));
73 | console.log("-->ExpectedWei: " + expectedWei);
74 | console.log("-->OfferBalanceAfter: " + web3.fromWei(eth.getBalance(offer.address)));
75 | addToTest('contractor_after', eth.getBalance(contractor));
76 | addToTest('contractor_diff',
77 | bigDiff(testMap['contractor_after'], testMap['contractor_before'])
78 | );
79 | // check that the contractor gets the Wei expected, within a 0.1 Ether difference
80 | var contractor_profit = testMap['contractor_diff'].sub(expectedWei).abs();
81 | console.log("-->contractor_profit: " + contractor_profit);
82 | addToTest('contractor_paid_expected', contractor_profit.lt(new BigNumber(100000000000000000)));
83 | testResults();
84 | }, $debating_period * 1000);
85 | console.log("Wait for end of debating period");
86 | miner.start(1);
87 |
--------------------------------------------------------------------------------
/tests/scenarios/sampleoffer_gettersvt/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/sampleoffer_gettersvt/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/sampleoffer_gettersvt/run.py:
--------------------------------------------------------------------------------
1 | from utils import arr_str, calculate_bytecode
2 | import time
3 |
4 | scenario_description = (
5 | """Test that the offer's contract can't receive any money through its
6 | getter functions."""
7 | )
8 |
9 |
10 | def run(ctx):
11 | ctx.assert_scenario_ran('proposal')
12 | ctx.create_js_file(substitutions={
13 | "offer_abi": ctx.offer_abi,
14 | "offer_address": ctx.offer_address,
15 | })
16 |
17 | ctx.execute(expected={
18 | "sample_offer_no_donations": True,
19 | })
20 |
--------------------------------------------------------------------------------
/tests/scenarios/sampleoffer_gettersvt/template.js:
--------------------------------------------------------------------------------
1 | var offer = web3.eth.contract($offer_abi).at('$offer_address');
2 | var offer_balance_before = eth.getBalance(offer.address);
3 |
4 | offer.getTotalCost.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
5 | checkWork();
6 | offer.getInitialWithdrawal.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
7 | checkWork();
8 | offer.getDailyWithdrawalLimit.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
9 | checkWork();
10 | offer.getMinDailyWithdrawalLimit.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
11 | checkWork();
12 | offer.getPayoutFreezePeriod.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
13 | checkWork();
14 | offer.getContractor.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
15 | checkWork();
16 | offer.getHashOfTheProposalDocument.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
17 | checkWork();
18 | offer.getLastWithdrawal.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
19 | checkWork();
20 | offer.getDateOfSignature.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
21 | checkWork();
22 | offer.getClient.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
23 | checkWork();
24 | offer.getOriginalClient.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
25 | checkWork();
26 | offer.getIsContractValid.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
27 | checkWork();
28 | offer.getRewardDivisor.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
29 | checkWork();
30 | offer.getDeploymentReward.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
31 | checkWork();
32 | offer.getInitialWithdrawalDone.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
33 | checkWork();
34 | offer.getVotingDeadline.sendTransaction({from:eth.accounts[0], value: web3.toWei(10), gas: 200000});
35 | checkWork();
36 |
37 | var offer_balance_after = eth.getBalance(offer.address);
38 | addToTest('sample_offer_no_donations', offer_balance_after.eq(offer_balance_before));
39 | testResults();
40 |
41 |
--------------------------------------------------------------------------------
/tests/scenarios/sampleoffer_setrewardvars/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/scenarios/sampleoffer_setrewardvars/run.py:
--------------------------------------------------------------------------------
1 | from utils import calculate_bytecode
2 |
3 | scenario_description = (
4 | "Test that the DAO can properly set rewardDivisor and "
5 | "deploymentReward variables. After that call payOneTimeRewards()"
6 | "both with a value less than deploymentReward and a value greater "
7 | "than it and check that the results are as expected."
8 | )
9 |
10 |
11 | def run(ctx):
12 | ctx.assert_scenario_ran('proposal')
13 | reward_divisor = 50000
14 | deployment_reward = 85200
15 | test_deployment_payment = deployment_reward + 10000
16 | set_div_bytecode = calculate_bytecode(
17 | 'setRewardDivisor', ('uint256', reward_divisor)
18 | )
19 | set_deploy_bytecode = calculate_bytecode(
20 | 'setDeploymentReward', ('uint256', deployment_reward)
21 | )
22 | ctx.create_js_file(substitutions={
23 | "dao_abi": ctx.dao_abi,
24 | "dao_address": ctx.dao_address,
25 | "offer_abi": ctx.offer_abi,
26 | "offer_address": ctx.offer_address,
27 | "usn_abi": ctx.usn_abi,
28 | "usn_address": ctx.usn_address,
29 | "proposal_deposit": ctx.args.proposal_deposit,
30 | "set_div_bytecode": set_div_bytecode,
31 | "set_deploy_bytecode": set_deploy_bytecode,
32 | "debating_period": ctx.args.proposal_debate_seconds,
33 | "deployment_reward": deployment_reward,
34 | "test_deployment_payment": test_deployment_payment
35 | })
36 | print(
37 | "Notice: Debate period is {} seconds so the test will wait "
38 | "as much".format(ctx.args.proposal_debate_seconds)
39 | )
40 |
41 | ctx.execute(expected={
42 | "offer_reward_divisor": reward_divisor,
43 | "offer_deployment_reward": deployment_reward,
44 | "pay_less_fails": True,
45 | "reward_payment": test_deployment_payment
46 | })
47 |
--------------------------------------------------------------------------------
/tests/scenarios/sampleoffer_setrewardvars/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 | var offer = web3.eth.contract($offer_abi).at('$offer_address');
3 | var usn = web3.eth.contract($usn_abi).at('$usn_address');
4 |
5 | var dao_rewardaccount_before = eth.getBalance(dao.DAOrewardAccount());
6 | var dao_balance_before = eth.getBalance(dao.address);
7 |
8 | // make proposals to set both the rewardDivisor and the deploymentReward
9 | var div_prop_id = attempt_proposal(
10 | dao, // DAO in question
11 | '$offer_address', // recipient
12 | proposalCreator, // proposal creator
13 | 0, // proposal amount in ether
14 | 'Set the reward divisor variable', // description
15 | '$set_div_bytecode', //bytecode
16 | $debating_period, // debating period
17 | $proposal_deposit, // proposal deposit in ether
18 | false // whether it's a split proposal or not
19 | );
20 | var deploy_prop_id = attempt_proposal(
21 | dao, // DAO in question
22 | '$offer_address', // recipient
23 | proposalCreator, // proposal creator
24 | 0, // proposal amount in ether
25 | 'Set the deployment reward proposal', // description
26 | '$set_deploy_bytecode', //bytecode
27 | $debating_period, // debating period
28 | $proposal_deposit, // proposal deposit in ether
29 | false // whether it's a split proposal or not
30 | );
31 |
32 |
33 | console.log("Voting for both proposals");
34 | for (i = 0; i < eth.accounts.length; i++) {
35 | dao.vote.sendTransaction(
36 | div_prop_id,
37 | true, //omg it's unanimous!
38 | {
39 | from: eth.accounts[i],
40 | gas: 1000000
41 | }
42 | );
43 | dao.vote.sendTransaction(
44 | deploy_prop_id,
45 | true, //omg it's unanimous!
46 | {
47 | from: eth.accounts[i],
48 | gas: 1000000
49 | }
50 | );
51 | }
52 | checkWork();
53 |
54 | setTimeout(function() {
55 | miner.stop();
56 | console.log("After debating period. NOW is: " + Math.floor(Date.now() / 1000));
57 | attempt_execute_proposal(
58 | dao, // target DAO
59 | div_prop_id, // proposal ID
60 | '$set_div_bytecode', // transaction bytecode
61 | proposalCreator, // proposal creator
62 | true, // should the proposal be closed after this call?
63 | true // should the proposal pass?
64 | );
65 | attempt_execute_proposal(
66 | dao, // target DAO
67 | deploy_prop_id, // proposal ID
68 | '$set_deploy_bytecode', // transaction bytecode
69 | proposalCreator, // proposal creator
70 | true, // should the proposal be closed after this call?
71 | true // should the proposal pass?
72 | );
73 |
74 | // test that the variables are set appropriately
75 | addToTest('offer_reward_divisor', offer.getRewardDivisor());
76 | addToTest('offer_deployment_reward', offer.getDeploymentReward());
77 |
78 | var actor = eth.accounts[0];
79 | // emulate a USN node with onetimerward payment smaller than the set deployment reward.
80 | var dao_rewardaccount_before = eth.getBalance(dao.DAOrewardAccount());
81 | usn.payOneTimeReward.sendTransaction({from:actor, value: $deployment_reward - 10000, gas: 200000});
82 | checkWork();
83 | var dao_rewardaccount_after = eth.getBalance(dao.DAOrewardAccount());
84 | addToTest('pay_less_fails', dao_rewardaccount_after.eq(dao_rewardaccount_before));
85 |
86 | // emulate a USN node with onetimerward payment bigger than the set deployment reward.
87 | dao_rewardaccount_before = eth.getBalance(dao.DAOrewardAccount());
88 | usn.payOneTimeReward.sendTransaction({from:actor, value: $test_deployment_payment, gas: 200000});
89 | checkWork();
90 | dao_rewardaccount_after = eth.getBalance(dao.DAOrewardAccount());
91 | addToTest('reward_payment', dao_rewardaccount_after.sub(dao_rewardaccount_before));
92 |
93 | testResults();
94 | }, $debating_period * 1000);
95 | console.log("Wait for end of debating period");
96 | miner.start(1);
97 |
--------------------------------------------------------------------------------
/tests/scenarios/singlesplit/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/singlesplit/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/singlesplit/run.py:
--------------------------------------------------------------------------------
1 | scenario_description = (
2 | " An 'angry' user decides to get out of the DAO and take his money with "
3 | "him. He creates a proposal to split into an one-member DAO with himself "
4 | "as the Curator. Then he makes a proposal to this new DAO to "
5 | "transfer all of the money to himself. Assert that the money he gets back "
6 | "in the end is equal to the money he put in the original DAO."
7 | )
8 |
9 |
10 | def run(ctx):
11 | ctx.assert_scenario_ran('fuel')
12 |
13 | ctx.create_js_file(substitutions={
14 | "dao_abi": ctx.dao_abi,
15 | "dao_address": ctx.dao_address,
16 | "proposal_deposit": ctx.args.proposal_deposit,
17 | "debating_period": ctx.args.proposal_debate_seconds,
18 | "split_execution_period": ctx.args.split_execution_period
19 | })
20 | print(
21 | "Notice: Debate period is {} seconds so the test will wait "
22 | "as much".format(ctx.args.proposal_debate_seconds)
23 | )
24 |
25 | ctx.execute(expected={
26 | "newdao_proposals_num": 1,
27 | "angry_user_profit": ctx.token_amounts[1] + ctx.args.proposal_deposit
28 | })
29 |
--------------------------------------------------------------------------------
/tests/scenarios/singlesplit/template.js:
--------------------------------------------------------------------------------
1 | var dao_abi = $dao_abi;
2 | var dao = web3.eth.contract(dao_abi).at('$dao_address');
3 | var split_execution_period = $split_execution_period;
4 | var new_curator = eth.accounts[1];
5 |
6 | var prop_id = attempt_proposal(
7 | dao, // DAO in question
8 | new_curator, // recipient
9 | new_curator, // proposal creator
10 | 0, // proposal amount in ether
11 | 'Our disgruntled user wants to split out', // description
12 | '', //bytecode
13 | $debating_period, // debating period
14 | 0, // proposal deposit in ether
15 | true // whether it's a split proposal or not
16 | );
17 |
18 | console.log("Voting for split proposal '" + prop_id + "' ...");
19 | for (i = 0; i < eth.accounts.length; i++) {
20 | dao.vote.sendTransaction(
21 | prop_id,
22 | i == 1 ? true : false,
23 | {
24 | from: eth.accounts[i],
25 | gas: 1000000
26 | }
27 | );
28 | }
29 | checkWork();
30 | addToTest('proposal_yay', parseInt(web3.fromWei(dao.proposals(prop_id)[9])));
31 | addToTest('proposal_nay', parseInt(web3.fromWei(dao.proposals(prop_id)[10])));
32 |
33 | setTimeout(function() {
34 | miner.stop();
35 | // now our disgruntled user is the only one to execute the splitDAO function
36 | attempt_split(dao, prop_id, new_curator, new_curator, split_execution_period);
37 |
38 | console.log("After split execution");
39 | addToTest('proposal_passed', dao.proposals(prop_id)[5]);
40 | addToTest('proposal_newdao', dao.splitProposalNewAddress(prop_id, 0));
41 |
42 | var newdao = web3.eth.contract(dao_abi).at(testMap['proposal_newdao']);
43 | // check token balance of each user in both DAOs
44 | oldDAOBalance = [];
45 | newDAOBalance = [];
46 | for (i = 0; i < eth.accounts.length; i++) {
47 | oldDAOBalance.push(parseInt(web3.fromWei(dao.balanceOf(eth.accounts[i]))));
48 | newDAOBalance.push(parseInt(web3.fromWei(newdao.balanceOf(eth.accounts[i]))));
49 | }
50 | addToTest('oldDAOBalance', oldDAOBalance);
51 | addToTest('newDAOBalance', newDAOBalance);
52 | addToTest('newDAOTotalSupply', parseInt(web3.fromWei(newdao.totalSupply())));
53 |
54 | setTimeout(function() {
55 | console.log("MINQUORUM REQUIRED: " + newdao.extMinQuorum(newdao.totalSupply()));
56 | // now our disgruntled user has his own DAO and is the SP of that DAO so ...
57 | var new_prop_id = attempt_proposal(
58 | newdao, // DAO in question
59 | new_curator, // recipient
60 | new_curator, // proposal creator
61 | testMap['newDAOTotalSupply'], // proposal amount in ether
62 | 'Send all money to myself!! Screw you guys ... I am going home!', // description
63 | '', //bytecode
64 | $debating_period, // debating period
65 | $proposal_deposit, // proposal deposit in ether
66 | false // whether it's a split proposal or not
67 | );
68 |
69 | console.log("Angry user votes in his own DAO...");
70 | newdao.vote.sendTransaction(
71 | new_prop_id,
72 | true,
73 | {
74 | from: new_curator,
75 | gas: 1000000
76 | });
77 | checkWork();
78 | addToTest('newdao_proposals_num', newdao.numberOfProposals());
79 | addToTest('angry_user_before', web3.fromWei(eth.getBalance(new_curator)));
80 | setTimeout(function() {
81 | // now execute the proposal
82 | attempt_execute_proposal(
83 | newdao, // target DAO
84 | new_prop_id, // proposal ID
85 | '', // transaction bytecode
86 | new_curator, // proposal creator
87 | true, // should the proposal be closed after this call?
88 | true // should the proposal pass?
89 | );
90 |
91 | addToTest('angry_user_after', web3.fromWei(eth.getBalance(new_curator)));
92 | addToTest(
93 | 'angry_user_profit',
94 | bigDiffRound(testMap['angry_user_after'], testMap['angry_user_before'])
95 | );
96 | testResults();
97 | }, $debating_period * 1000);
98 | console.log("Wait for end of second debating period");
99 | }, split_execution_period * 1000);
100 | console.log("Wait for new DAO fueling period to end");
101 | }, $debating_period * 1000);
102 | console.log("Wait for end of first debating period");
103 |
--------------------------------------------------------------------------------
/tests/scenarios/spendall/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/scenarios/spendall/run.py:
--------------------------------------------------------------------------------
1 | scenario_description = (
2 | "The DAO spends all its money. This scenario is but a pivot used "
3 | " by all the other scenarios that want to deal with extra balance."
4 | )
5 |
6 |
7 | def run(ctx):
8 | ctx.assert_scenario_ran('fuel')
9 | ctx.create_js_file(substitutions={
10 | "dao_abi": ctx.dao_abi,
11 | "dao_address": ctx.dao_address,
12 | "proposal_deposit": ctx.args.proposal_deposit,
13 | "debating_period": ctx.args.proposal_debate_seconds,
14 | })
15 |
16 | ctx.execute(expected={
17 | "dao_total_balance_after_spend": 0
18 | })
19 |
--------------------------------------------------------------------------------
/tests/scenarios/spendall/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 |
3 | addToTest('dao_total_balance_before_spend', web3.fromWei(dao.actualBalance()));
4 |
5 | var prop_id = attempt_proposal(
6 | dao, // DAO in question
7 | curator, // recipient
8 | proposalCreator, // proposal creator
9 | web3.fromWei(dao.totalSupply()), // proposal amount in ether
10 | 'Spend almost all of the DAOs money', // description
11 | '', //bytecode
12 | $debating_period, // debating period
13 | $proposal_deposit, // proposal deposit in ether
14 | false // whether it's a split proposal or not
15 | );
16 |
17 |
18 | console.log("Deadline is: " + dao.proposals(prop_id)[3] + " Voting ... ");
19 | for (i = 0; i < eth.accounts.length; i++) {
20 | dao.vote.sendTransaction(
21 | prop_id,
22 | true,
23 | {
24 | from: eth.accounts[i],
25 | gas: 1000000
26 | }
27 | );
28 | }
29 | checkWork();
30 |
31 | setTimeout(function() {
32 | miner.stop();
33 | console.log("After spending debating period. NOW is: " + Math.floor(Date.now() / 1000));
34 | attempt_execute_proposal(
35 | dao, // target DAO
36 | prop_id, // proposal ID
37 | '', // transaction bytecode
38 | proposalCreator, // proposal creator
39 | true, // should the proposal be closed after this call?
40 | true // should the proposal pass?
41 | );
42 |
43 | addToTest('dao_total_balance_after_spend', web3.fromWei(dao.actualBalance()));
44 | testResults();
45 | }, ($debating_period) * 1000);
46 | console.log("Wait for end of debating period for spending all of the DAO's money");
47 | miner.start(1);
48 |
--------------------------------------------------------------------------------
/tests/scenarios/split/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockchainsllc/DAO/e50d3bc008cfe0bbe4285de9dda54d3a541cb0b4/tests/scenarios/split/__init__.py
--------------------------------------------------------------------------------
/tests/scenarios/split/arguments.json:
--------------------------------------------------------------------------------
1 | [{
2 | "name": "debate_seconds",
3 | "default": 15,
4 | "description":"Number of seconds to debate the split proposal",
5 | "type": "int"
6 | }, {
7 | "name": "execution_period",
8 | "default": 50,
9 | "description":"Number of seconds after the voting deadline for which a split proposal is executable",
10 | "type": "int"
11 | }]
12 |
--------------------------------------------------------------------------------
/tests/scenarios/split/run.py:
--------------------------------------------------------------------------------
1 | from utils import arr_str, create_votes_array
2 |
3 |
4 | scenario_description = (
5 | " Testing an equal split, with a new Curator. Half of the token holders "
6 | "vote for a split to a new DAO and half vote to stay with the old one. "
7 | "Assert that the split happens, a new DAO is created and that the tokens "
8 | "are burned from the old DAO and moved to the new DAO succesfully. Also "
9 | "assert that the reward tokens are succesfully transferred"
10 | )
11 |
12 |
13 | def tokens_after_split(votes, original_balance, dao_balance, reward_tokens):
14 | """
15 | Create expected token and reward token results after the split scenario
16 | Parameters
17 | ----------
18 | votes : array of booleans
19 | The votes array of what each user voted
20 |
21 | original_balance : array of ints
22 | The original amount of tokens each user had before the split
23 |
24 | dao_balance : int
25 | The balance of ether left in the DAO before the scenario started
26 |
27 | reward_tokens : float
28 | Amount of reward tokens generated in the DAO before the scenario.
29 |
30 | Returns
31 | ----------
32 | old_dao_balance : array of ints
33 | The balance of tokens left in the old dao.
34 |
35 | new_dao_balance : array of ints
36 | The balance of tokens left in the new dao.
37 |
38 | old_reward_tokens : float
39 | The amount of reward tokens left in the old dao.
40 |
41 | new_reward_tokens : float
42 | The amount of reward tokens left in the new dao.
43 | """
44 |
45 | old_dao_balance = []
46 | new_dao_balance = []
47 | totalSupply = sum(original_balance)
48 | old_reward_tokens = reward_tokens
49 | new_reward_tokens = 0
50 |
51 | for vote, orig in zip(votes, original_balance):
52 | if vote:
53 | new_dao_balance.append(orig * dao_balance / float(totalSupply))
54 | old_dao_balance.append(0)
55 | rewardToMove = float(orig) * reward_tokens / float(totalSupply)
56 | old_reward_tokens -= float(rewardToMove)
57 | new_reward_tokens += float(rewardToMove)
58 | else:
59 | old_dao_balance.append(orig)
60 | new_dao_balance.append(0)
61 | return (
62 | old_dao_balance,
63 | new_dao_balance,
64 | old_reward_tokens,
65 | new_reward_tokens
66 | )
67 |
68 |
69 | def prepare_test_split(ctx, split_gas):
70 | ctx.assert_scenario_ran('rewards')
71 |
72 | votes = create_votes_array(
73 | ctx.token_amounts,
74 | not ctx.args.proposal_fail,
75 | True
76 | )
77 | # remember the account information of the first True votes. They will be
78 | # the child dao curator in this scenario and grandchild curator in the next
79 | iterator = (
80 | (ctx.accounts[i], ctx.token_amounts[i])
81 | for i, vote in enumerate(votes) if vote is True
82 | )
83 | (ctx.child_dao_curator, _) = next(iterator)
84 | (ctx.grandchild_dao_curator, ctx.grandchild_dao_curator_before) = next(iterator)
85 | ctx.create_js_file(substitutions={
86 | "dao_abi": ctx.dao_abi,
87 | "dao_address": ctx.dao_address,
88 | "debating_period": ctx.args.split_debate_seconds,
89 | "split_execution_period": ctx.args.split_execution_period,
90 | "split_gas": split_gas,
91 | "votes": arr_str(votes),
92 | "child_dao_curator": ctx.child_dao_curator
93 | }
94 | )
95 | print(
96 | "Notice: Debate period is {} seconds so the test will wait "
97 | "as much".format(ctx.args.split_debate_seconds)
98 | )
99 | return votes
100 |
101 |
102 | def run(ctx):
103 | # Use the split_gas variable to test that splitting with insufficient gas,
104 | # will fail reliably and will not leave an empty contract in the state,
105 | # burning away user tokens in the process.
106 | # This should happen with the latest homestead changes:
107 | # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.mediawiki#specification
108 | split_gas = 4700000
109 |
110 | votes = prepare_test_split(ctx, split_gas)
111 | oldBalance, newBalance, oldDAORewards, newDAORewards = tokens_after_split(
112 | votes,
113 | ctx.token_amounts,
114 | ctx.dao_balance_after_rewards,
115 | ctx.dao_rewardToken_after_rewards
116 | )
117 |
118 | results = ctx.execute(expected={
119 | "newDAOProposalDeposit": 0,
120 | "oldDAOBalance": oldBalance,
121 | "newDAOBalance": newBalance,
122 | "oldDaoRewardTokens": oldDAORewards,
123 | "newDaoRewardTokens": newDAORewards
124 | })
125 |
126 | # remember some variables so they can be used in later tests
127 | ctx.child_dao_closing_time = results['new_dao_closing_time']
128 | ctx.child_dao_address = results['proposal_newdao']
129 | ctx.child_dao_members = [
130 | ctx.accounts[idx] for idx, x in enumerate(votes) if x is True
131 | ]
132 | ctx.child_dao_balance_at_creation = results['new_dao_balance']
133 | ctx.child_dao_total_supply_at_creation = results['new_dao_total_supply']
134 |
--------------------------------------------------------------------------------
/tests/scenarios/split/template.js:
--------------------------------------------------------------------------------
1 | var dao_abi = $dao_abi;
2 | var dao = web3.eth.contract(dao_abi).at('$dao_address');
3 | var split_execution_period = $split_execution_period;
4 | var child_dao_curator = '$child_dao_curator';
5 |
6 | var prop_id = attempt_proposal(
7 | dao, // DAO in question
8 | child_dao_curator, // recipient
9 | proposalCreator, // proposal creator
10 | 0, // proposal amount in ether
11 | 'Voting to split and change Curator', // description
12 | '', //bytecode
13 | $debating_period, // debating period
14 | 0, // proposal deposit in ether
15 | true // whether it's a split proposal or not
16 | );
17 |
18 | var votes = $votes;
19 | console.log("Voting for split proposal '" + prop_id + "' ...");
20 | for (i = 0; i < votes.length; i++) {
21 | console.log("User [" + i + "] is voting '" + votes[i] + "'for split proposal");
22 | dao.vote.sendTransaction(
23 | prop_id,
24 | votes[i],
25 | {
26 | from: eth.accounts[i],
27 | gas: 1000000
28 | }
29 | );
30 | }
31 | checkWork();
32 | addToTest('proposal_yay', parseInt(web3.fromWei(dao.proposals(prop_id)[9])));
33 | addToTest('proposal_nay', parseInt(web3.fromWei(dao.proposals(prop_id)[10])));
34 |
35 | setTimeout(function() {
36 | miner.stop();
37 | console.log("Executing the split proposal...");
38 | // now each user who voted for the split should call splitDAO to execute the proposal
39 | for (i = 0; i < votes.length; i++) {
40 | if (votes[i]) {
41 | console.log("User [" + i + "] is calling splitDAO()");
42 | attempt_split(dao, prop_id, eth.accounts[i], child_dao_curator, split_execution_period);
43 | }
44 | }
45 | console.log("After split execution");
46 | addToTest('proposal_passed', dao.proposals(prop_id)[5]);
47 | addToTest('proposal_newdao', dao.splitProposalNewAddress(prop_id, 0));
48 |
49 | var newdao = web3.eth.contract(dao_abi).at(testMap['proposal_newdao']);
50 | // check token balance of each user in both DAOs
51 | oldDAOBalance = [];
52 | newDAOBalance = [];
53 | for (i = 0; i < eth.accounts.length; i++) {
54 | oldDAOBalance.push(parseFloat(web3.fromWei(dao.balanceOf(eth.accounts[i]))));
55 | newDAOBalance.push(parseFloat(web3.fromWei(newdao.balanceOf(eth.accounts[i]))));
56 | }
57 | addToTest('oldDAOBalance', oldDAOBalance);
58 | addToTest('newDAOBalance', newDAOBalance);
59 | addToTest('oldDaoRewardTokens', parseFloat(web3.fromWei(dao.rewardToken('$dao_address'))));
60 | addToTest('newDaoRewardTokens', parseFloat(web3.fromWei(dao.rewardToken(testMap['proposal_newdao']))));
61 |
62 | addToTest('new_dao_balance', web3.fromWei(eth.getBalance(newdao.address)).ceil());
63 | addToTest('new_dao_total_supply', web3.fromWei(newdao.totalSupply()).ceil());
64 | addToTest('newDAOProposalDeposit', parseInt(web3.fromWei(newdao.proposalDeposit())));
65 | addToTest('new_dao_closing_time', parseInt(newdao.closingTime()));
66 |
67 | testResults();
68 | }, $debating_period * 1000);
69 | console.log("Wait for end of debating period");
70 |
--------------------------------------------------------------------------------
/tests/scenarios/stealextrabalance/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/scenarios/stealextrabalance/run.py:
--------------------------------------------------------------------------------
1 | from utils import calculate_bytecode, to_wei
2 |
3 | scenario_description = (
4 | "The DAO spent all its money and has to resort to retrieving money from "
5 | "the extra balance account. In the meantime a bad guy tries to pass a "
6 | "proposal to send all of the extraBalance money to himself. Assert that "
7 | "this is impossible."
8 | )
9 |
10 |
11 | def run(ctx):
12 | ctx.assert_scenario_ran('spendall')
13 | attacker_address = ctx.accounts[3]
14 | bytecode = calculate_bytecode(
15 | 'payOut',
16 | ('address', attacker_address),
17 | ('uint256', to_wei(5))
18 | )
19 | ctx.create_js_file(substitutions={
20 | "dao_abi": ctx.dao_abi,
21 | "dao_address": ctx.dao_address,
22 | "attacker_address": attacker_address,
23 | "proposal_deposit": ctx.args.proposal_deposit,
24 | "debating_period": ctx.args.proposal_debate_seconds,
25 | "transaction_bytecode": bytecode
26 | })
27 |
28 | ctx.execute(expected={
29 | "extra_balance_diff_after_attack": 0
30 | })
31 |
--------------------------------------------------------------------------------
/tests/scenarios/stealextrabalance/template.js:
--------------------------------------------------------------------------------
1 | var dao = web3.eth.contract($dao_abi).at('$dao_address');
2 | var attacker = '$attacker_address';
3 | var extraBalance = dao.extraBalance();
4 |
5 | addToTest('extra_balance_before', web3.fromWei(eth.getBalance(extraBalance)));
6 |
7 | var claim_prop_id = attempt_proposal(
8 | dao, // DAO in question
9 | extraBalance, // recipient
10 | attacker, // proposal creator
11 | 0, // proposal amount in ether
12 | 'Ask the extraBalance account to pay out to the DAO', // description
13 | '$transaction_bytecode', // transaction bytecode
14 | $debating_period, // debating period
15 | $proposal_deposit, // proposal deposit in ether
16 | false // whether it's a split proposal or not
17 | );
18 | console.log("Voting on the extra balance attack payout proposal");
19 | for (i = 0; i < eth.accounts.length; i++) {
20 | dao.vote.sendTransaction(
21 | claim_prop_id,
22 | true,
23 | {
24 | from: eth.accounts[i],
25 | gas: 1000000
26 | }
27 | );
28 | }
29 | checkWork();
30 |
31 | setTimeout(function() {
32 | miner.stop();
33 | console.log("After extra balance payout attack debating period");
34 | attempt_execute_proposal(
35 | dao, // target DAO
36 | claim_prop_id, // proposal ID
37 | '$transaction_bytecode', // transaction bytecode
38 | attacker, // proposal creator
39 | false, // should the proposal be closed after this call?
40 | false // should the proposal pass?
41 | );
42 |
43 | addToTest('extra_balance_after', web3.fromWei(eth.getBalance(extraBalance)));
44 | addToTest('extra_balance_diff_after_attack',
45 | testMap['extra_balance_after'].sub(
46 | testMap['extra_balance_before']
47 | ).round());
48 |
49 | testResults();
50 | }, $debating_period * 1000);
51 | console.log("Wait for end of debating period for claiming extraBalance payout attack");
52 | miner.start(1);
53 |
54 |
--------------------------------------------------------------------------------
/tests/templates/accounts.template.js:
--------------------------------------------------------------------------------
1 | for (i = 0; i < $accounts_number; i++) {
2 | personal.newAccount("123");
3 | }
4 | console.log(JSON.stringify(eth.accounts));
5 |
--------------------------------------------------------------------------------
/withdraw.sol:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the DAO.
3 |
4 | The DAO is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU lesser General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | The DAO is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU lesser General Public License for more details.
13 |
14 | You should have received a copy of the GNU lesser General Public License
15 | along with the DAO. If not, see .
16 | */
17 |
18 | // TODO: all constants need to be double checked
19 | import "github.com/slockit/DAO/DAO.sol";
20 |
21 | contract Withdraw {
22 | DAO constant public mother = DAO(0xbb9bc244d798123fde783fcc1c72d3bb8c189413);
23 | mapping (address => bool) public whiteList;
24 | uint constant public totalSupply = 11712722930974665882186911;
25 | uint constant public totalWeiSupply = 12072858342395652843028271;
26 | uint constant public fixChildDAOsListTime = 1468057560; // 09.07.2016 - 11:46:00 CEST
27 |
28 | function Withdraw(){
29 | // whitelist all childDAO except of attacker DAO (commented out)
30 | whiteList[0xd4fe7bc31cedb7bfb8a345f31e668033056b2728] = true;
31 | whiteList[0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f] = true;
32 | whiteList[0x1975bd06d486162d5dc297798dfc41edd5d160a7] = true;
33 | whiteList[0x319f70bab6845585f412ec7724b744fec6095c85] = true;
34 | whiteList[0x5c8536898fbb74fc7445814902fd08422eac56d0] = true;
35 | whiteList[0x779543a0491a837ca36ce8c635d6154e3c4911a6] = true;
36 | whiteList[0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5] = true;
37 | whiteList[0x200450f06520bdd6c527622a273333384d870efb] = true;
38 | whiteList[0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb] = true;
39 | whiteList[0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091] = true;
40 |
41 | whiteList[0x51e0ddd9998364a2eb38588679f0d2c42653e4a6] = true;
42 | whiteList[0xf0b1aa0eb660754448a7937c022e30aa692fe0c5] = true;
43 | whiteList[0x9f27daea7aca0aa0446220b98d028715e3bc803d] = true;
44 | whiteList[0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b] = true;
45 | whiteList[0x6f6704e5a10332af6672e50b3d9754dc460dfa4d] = true;
46 | whiteList[0x492ea3bb0f3315521c31f273e565b868fc090f17] = true;
47 | whiteList[0x9ea779f907f0b315b364b0cfc39a0fde5b02a416] = true;
48 | whiteList[0xcc34673c6c40e791051898567a1222daf90be287] = true;
49 | whiteList[0xe308bd1ac5fda103967359b2712dd89deffb7973] = true;
50 | whiteList[0xac1ecab32727358dba8962a0f3b261731aad9723] = true;
51 |
52 | whiteList[0x440c59b325d2997a134c2c7c60a8c61611212bad] = true;
53 | whiteList[0x9c15b54878ba618f494b38f0ae7443db6af648ba] = true;
54 | whiteList[0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241] = true;
55 | whiteList[0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b] = true;
56 | whiteList[0x6131c42fa982e56929107413a9d526fd99405560] = true;
57 | whiteList[0x542a9515200d14b68e934e9830d91645a980dd7a] = true;
58 | whiteList[0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4] = true;
59 | whiteList[0x3ba4d81db016dc2890c81f3acec2454bff5aada5] = true;
60 | whiteList[0xe4ae1efdfc53b73893af49113d8694a057b9c0d1] = true;
61 | whiteList[0x0737a6b837f97f46ebade41b9bc3e1c509c85c53] = true;
62 |
63 | whiteList[0x52c5317c848ba20c7504cb2c8052abd1fde29d03] = true;
64 | whiteList[0x5d2b2e6fcbe3b11d26b525e085ff818dae332479] = true;
65 | whiteList[0x057b56736d32b86616a10f619859c6cd6f59092a] = true;
66 | // whiteList[0x304a554a310c7e546dfe434669c62820b7d83490] = true;
67 | whiteList[0x4deb0033bb26bc534b197e61d19e0733e5679784] = true;
68 | whiteList[0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b] = true;
69 | whiteList[0x9da397b9e80755301a3b32173283a91c0ef6c87e] = true;
70 | whiteList[0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9] = true;
71 | whiteList[0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76] = true;
72 | whiteList[0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7] = true;
73 |
74 | whiteList[0xd164b088bd9108b60d0ca3751da4bceb207b0782] = true;
75 | whiteList[0x1cba23d343a983e9b5cfd19496b9a9701ada385f] = true;
76 | whiteList[0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339] = true;
77 | whiteList[0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d] = true;
78 | whiteList[0xbc07118b9ac290e4622f5e77a0853539789effbe] = true;
79 | whiteList[0xacd87e28b0c9d1254e868b81cba4cc20d9a32225] = true;
80 | whiteList[0x5524c55fb03cf21f549444ccbecb664d0acad706] = true;
81 | // whiteList[0xfe24cdd8648121a43a7c86d289be4dd2951ed49f] = true;
82 | whiteList[0x253488078a4edf4d6f42f113d1e62836a942cf1a] = true;
83 | // whiteList[0xb136707642a4ea12fb4bae820f03d2562ebff487] = true;
84 |
85 | whiteList[0xf14c14075d6c4ed84b86798af0956deef67365b5] = true;
86 | // whiteList[0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c] = true;
87 | whiteList[0x6d87578288b6cb5549d5076a207456a1f6a63dc0] = true;
88 | whiteList[0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6] = true;
89 | // whiteList[0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a] = true;
90 | // whiteList[0x84ef4b2357079cd7a7c69fd7a37cd0609a679106] = true;
91 | // whiteList[0xf4c64518ea10f995918a454158c6b61407ea345c] = true;
92 | }
93 |
94 | function withdrawFromChildDAO(DAO _child) {
95 | // to be replaced by a time which allows the direct withdraw to be finished before the childDAO withdraw starts
96 | if (now < fixChildDAOsListTime + 4 weeks) throw;
97 | if (!whiteList[_child]
98 | || _child.lastTimeMinQuorumMet() > fixChildDAOsListTime
99 | || _child.privateCreation() != address(mother))
100 | throw;
101 |
102 | withdraw(_child);
103 | }
104 |
105 | function withdraw(){
106 | withdraw(mother);
107 | }
108 |
109 | function withdraw(DAO _dao) internal {
110 | uint balance = _dao.balanceOf(msg.sender);
111 |
112 | // The msg.sender must call approve(this, balance) beforehand so that
113 | // transferFrom() will work and not throw. We need transferFrom()
114 | // instead of transfer() due to the msg.sender in the latter ending
115 | // up to be the contract
116 | if (!_dao.transferFrom(msg.sender, this, balance)
117 | || !msg.sender.send(balance * totalWeiSupply / totalSupply)) {
118 |
119 | throw;
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/withdrawBlack.sol:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the DAO.
3 |
4 | The DAO is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU lesser General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | The DAO is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU lesser General Public License for more details.
13 |
14 | You should have received a copy of the GNU lesser General Public License
15 | along with the DAO. If not, see .
16 | */
17 |
18 | // TODO: all constants need to be double checked
19 | import "github.com/slockit/DAO/DAO.sol";
20 |
21 | contract Withdraw {
22 | DAO constant public mother = DAO(0xbb9bc244d798123fde783fcc1c72d3bb8c189413);
23 | mapping (address => bool) public blackList;
24 | uint constant public totalSupply = 11712722930974665882186911;
25 | uint constant public totalWeiSupply = 12072858342395652843028271;
26 | uint constant public fixChildDAOsListTime = 1468057560; // 09.07.2016 - 11:46:00 CEST
27 |
28 | function Withdraw(){
29 | // These are the child DAOs where the recursive call exploit was used,
30 | // their token balances are invalid.
31 | blackList[0xb136707642a4ea12fb4bae820f03d2562ebff487] = true;
32 | blackList[0x304a554a310c7e546dfe434669c62820b7d83490] = true;
33 | blackList[0x84ef4b2357079cd7a7c69fd7a37cd0609a679106] = true;
34 | blackList[0xf4c64518ea10f995918a454158c6b61407ea345c] = true;
35 | blackList[0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a] = true;
36 | blackList[0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c] = true;
37 | blackList[0xfe24cdd8648121a43a7c86d289be4dd2951ed49f] = true;
38 | }
39 |
40 | /// This function can be used to redeem child dao tokens.
41 | /// It can only be called 4 weeks after the blacklist was fixed.
42 | /// The reason is that if this more complicated mechanism has a flaw,
43 | /// people will hopefully already have withdrawn most of the ether
44 | /// through the simpler mechanism below.
45 | function withdrawFromChildDAO(uint _childProposalID) {
46 | if (now < fixChildDAOsListTime + 4 weeks) throw;
47 | DAO child = DAO(mother.getNewDAOAddress(_childProposalID));
48 | // If the child is blacklisted or too new, this does not work.
49 | if (address(child) == 0 || blackList[child] || child.lastTimeMinQuorumMet() > fixChildDAOsListTime)
50 | throw;
51 |
52 | withdraw(child);
53 | }
54 |
55 | /// Withdraw your share of the Ether.
56 | /// Prior to calling this function, you have to approve allow the withdraw
57 | /// contract to transfer your DAO tokens to it.
58 | function withdraw() {
59 | withdraw(mother);
60 | }
61 |
62 | function withdraw(DAO dao) internal {
63 | uint balance = dao.balanceOf(msg.sender);
64 |
65 | // The msg.sender must call approve(this, balance) beforehand so that
66 | // transferFrom() will work and not throw. We need transferFrom()
67 | // instead of transfer() due to the msg.sender in the latter ending
68 | // up to be the contract
69 | if (!dao.transferFrom(msg.sender, this, balance)
70 | || !msg.sender.send(balance * totalWeiSupply / totalSupply)) {
71 |
72 | throw;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------