├── .babelrc ├── .gitignore ├── .jshintrc ├── .solcover.js ├── .soliumignore ├── .soliumrc.json ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── audit └── ZeppelinAudit.md ├── contracts ├── Bounty.sol ├── DayLimit.sol ├── ECRecovery.sol ├── LimitBalance.sol ├── MerkleProof.sol ├── ReentrancyGuard.sol ├── crowdsale │ ├── CappedCrowdsale.sol │ ├── Crowdsale.sol │ ├── FinalizableCrowdsale.sol │ ├── LimitedTokenCrowdsale.sol │ ├── LimitedTokenDirectCrowdsale.sol │ ├── RefundVault.sol │ └── RefundableCrowdsale.sol ├── examples │ ├── SampleCrowdsale.sol │ └── SimpleToken.sol ├── lifecycle │ ├── Destructible.sol │ ├── Migrations.sol │ ├── Pausable.sol │ └── TokenDestructible.sol ├── math │ ├── Math.sol │ └── SafeMath.sol ├── ownership │ ├── CanReclaimToken.sol │ ├── Claimable.sol │ ├── Contactable.sol │ ├── DelayedClaimable.sol │ ├── HasNoContracts.sol │ ├── HasNoEther.sol │ ├── HasNoTokens.sol │ ├── NoOwner.sol │ └── Ownable.sol ├── payment │ └── PullPayment.sol └── token │ ├── BasicToken.sol │ ├── BurnableToken.sol │ ├── ERC20.sol │ ├── ERC20Basic.sol │ ├── MintableToken.sol │ ├── PausableToken.sol │ ├── SafeERC20.sol │ ├── StandardToken.sol │ ├── TokenTimelock.sol │ └── TokenVesting.sol ├── docs ├── Makefile └── source │ ├── basictoken.rst │ ├── bounty.rst │ ├── claimable.rst │ ├── conf.py │ ├── contract-security-patterns.rst │ ├── developer-resources.rst │ ├── ecrecovery.rst │ ├── getting-started.rst │ ├── index.rst │ ├── killable.rst │ ├── license.rst │ ├── limitbalance.rst │ ├── math.rst │ ├── merkleproof.rst │ ├── migrations.rst │ ├── ownable.rst │ ├── pausable.rst │ ├── pullpayment.rst │ ├── safemath.rst │ └── standardtoken.rst ├── ethpm.json ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── scripts ├── coverage.sh └── test.sh ├── test ├── BasicToken.js ├── Bounty.js ├── BurnableToken.js ├── CanReclaimToken.js ├── CappedCrowdsale.js ├── Claimable.js ├── Contactable.js ├── Crowdsale.js ├── DayLimit.js ├── DelayedClaimble.js ├── Destructible.js ├── ECRecovery.js ├── FinalizableCrowdsale.js ├── HasNoContracts.js ├── HasNoEther.js ├── HasNoTokens.js ├── LimitBalance.js ├── LimitedTokenCrowdsale.js ├── MerkleProof.js ├── MintableToken.js ├── Ownable.js ├── Pausable.js ├── PausableToken.js ├── PullPayment.js ├── ReentrancyGuard.js ├── RefundVault.js ├── RefundableCrowdsale.js ├── SafeERC20.js ├── SafeMath.js ├── SampleCrowdsale.js ├── StandardToken.js ├── TokenDestructible.js ├── TokenTimelock.js ├── TokenVesting.js └── helpers │ ├── BasicTokenMock.sol │ ├── BurnableTokenMock.sol │ ├── CappedCrowdsaleImpl.sol │ ├── DayLimitMock.sol │ ├── ERC23TokenMock.sol │ ├── EVMThrow.js │ ├── FinalizableCrowdsaleImpl.sol │ ├── ForceEther.sol │ ├── HasNoEtherTest.sol │ ├── InsecureTargetBounty.sol │ ├── LimitBalanceMock.sol │ ├── PausableMock.sol │ ├── PausableTokenMock.sol │ ├── PullPaymentMock.sol │ ├── ReentrancyAttack.sol │ ├── ReentrancyMock.sol │ ├── RefundableCrowdsaleImpl.sol │ ├── SafeERC20Helper.sol │ ├── SafeMathMock.sol │ ├── SecureTargetBounty.sol │ ├── StandardTokenMock.sol │ ├── advanceToBlock.js │ ├── assertJump.js │ ├── ether.js │ ├── expectThrow.js │ ├── hashMessage.js │ ├── increaseTime.js │ ├── latestTime.js │ ├── merkleTree.js │ ├── timer.js │ ├── toPromise.js │ └── transactionMined.js ├── truffle-config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2", "stage-3"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | node_modules/ 4 | build/ 5 | .DS_Store/ 6 | /coverage 7 | coverage.json 8 | allFiredEvents 9 | scTopics 10 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": false, // Prohibit bitwise operators (&, |, ^, etc.). 3 | "browser": true, // Standard browser globals e.g. `window`, `document`. 4 | "camelcase": false, // Permit only camelcase for `var` and `object indexes`. 5 | "curly": true, // Require {} for every new block or scope. 6 | "devel": false, // Allow development statements e.g. `console.log();`. 7 | "eqeqeq": true, // Require triple equals i.e. `===`. 8 | "esnext": true, // Allow ES.next specific features such as `const` and `let`. 9 | "freeze": true, // Forbid overwriting prototypes of native objects such as Array, Date and so on. 10 | "immed": true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` 11 | "indent": 2, // Specify indentation spacing 12 | "latedef": true, // Prohibit variable use before definition. 13 | "newcap": false, // Require capitalization of all constructor functions e.g. `new F()`. 14 | "noarg": true, // Prohibit use of `arguments.caller` and `arguments.callee`. 15 | "node": true, // Enable globals available when code is running inside of the NodeJS runtime environment. 16 | "noempty": true, // Prohibit use of empty blocks. 17 | "nonew": true, // Prohibits the use of constructor functions for side-effects 18 | "quotmark": "single", // Define quotes to string values. 19 | "regexp": true, // Prohibit `.` and `[^...]` in regular expressions. 20 | "smarttabs": false, // Supress warnings about mixed tabs and spaces 21 | "strict": true, // Require `use strict` pragma in every file. 22 | "trailing": true, // Prohibit trailing whitespaces. 23 | "undef": true, // Require all non-global variables be declared before they are used. 24 | "unused": true, // Warn unused variables. 25 | 26 | "maxparams": 4, // Maximum number of parameters for a function 27 | "maxstatements": 15, // Maximum number of statements in a function 28 | "maxcomplexity": 10, // Cyclomatic complexity (http://en.wikipedia.org/wiki/Cyclomatic_complexity) 29 | "maxdepth": 4, // Maximum depth of nested control structures 30 | "maxlen": 120, // Maximum number of cols in a line 31 | "multistr": true, // Allow use of multiline EOL escaping 32 | "experimental": ["asyncawait", "asyncreqawait"], 33 | 34 | "predef": [ // Extra globals. 35 | "after", 36 | "afterEach", 37 | "before", 38 | "beforeEach", 39 | "define", 40 | "describe", 41 | "exports", 42 | "it", 43 | "web3", 44 | "artifacts", 45 | "contract", 46 | "assert" 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /.solcover.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | norpc: true, 3 | testCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle test --network coverage', 4 | skipFiles: ['lifecycle/Migrations.sol'] 5 | } 6 | -------------------------------------------------------------------------------- /.soliumignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.soliumrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "custom-rules-filename": null, 3 | "rules": { 4 | "imports-on-top": true, 5 | "variable-declarations": true, 6 | "array-declarations": true, 7 | "operator-whitespace": true, 8 | "lbrace": true, 9 | "mixedcase": false, 10 | "camelcase": true, 11 | "uppercase": true, 12 | "no-with": true, 13 | "no-empty-blocks": true, 14 | "no-unused-vars": true, 15 | "double-quotes": true, 16 | "blank-lines": true, 17 | "indentation": true, 18 | "whitespace": true, 19 | "deprecated-suicide": true, 20 | "pragma-on-top": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | sudo: required 3 | group: beta 4 | language: node_js 5 | node_js: 6 | - "6" 7 | cache: 8 | yarn: true 9 | env: 10 | - 11 | - SOLIDITY_COVERAGE=true 12 | matrix: 13 | fast_finish: true 14 | allow_failures: 15 | - env: SOLIDITY_COVERAGE=true 16 | script: 17 | - yarn test 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to Zeppelin 2 | ======= 3 | 4 | ## Design Guidelines 5 | 6 | These are some global design goals in Zeppelin. 7 | 8 | ### D0 - Security in Depth 9 | We strive to provide secure, tested, audited code. To achieve this, we need to match intention with function. Thus, documentation, code clarity, community review and security discussions are fundamental. 10 | 11 | ### D1 - Simple and Modular 12 | Simpler code means easier audits, and better understanding of what each component does. We look for small files, small contracts, and small functions. If you can separate a contract into two independent functionalities you should probably do it. 13 | 14 | ### D2 - Naming Matters 15 | 16 | We take our time with picking names. Code is going to be written once, and read hundreds of times. Renaming for clarity is encouraged. 17 | 18 | ### D3 - Tests 19 | 20 | Write tests for all your code. We encourage Test Driven Development so we know when our code is right. Even though not all code in the repository is tested at the moment, we aim to test every line of code in the future. 21 | 22 | ### D4 - Check preconditions and post-conditions 23 | 24 | A very important way to prevent vulnerabilities is to catch a contract’s inconsistent state as early as possible. This is why we want functions to check pre- and post-conditions for executing its logic. When writing code, ask yourself what you are expecting to be true before and after the function runs, and express it in code. 25 | 26 | ### D5 - Code Consistency 27 | 28 | Consistency on the way classes are used is paramount to an easier understanding of the library. The codebase should be as unified as possible. Read existing code and get inspired before you write your own. Follow the style guidelines. Don’t hesitate to ask for help on how to best write a specific piece of code. 29 | 30 | ### D6 - Regular Audits 31 | Following good programming practices is a way to reduce the risk of vulnerabilities, but professional code audits are still needed. We will perform regular code audits on major releases, and hire security professionals to provide independent review. 32 | 33 | ## Style Guidelines 34 | 35 | The design guidelines have quite a high abstraction level. These style guidelines are more concrete and easier to apply, and also more opinionated. 36 | 37 | ### General 38 | 39 | #### G0 - Default to Solidity's official style guide. 40 | 41 | Follow the official Solidity style guide: http://solidity.readthedocs.io/en/latest/style-guide.html 42 | 43 | #### G1 - No Magic Constants 44 | 45 | Avoid constants in the code as much as possible. Magic strings are also magic constants. 46 | 47 | #### G2 - Code that Fails Early 48 | 49 | We ask our code to fail as soon as possible when an unexpected input was provided or unexpected state was found. 50 | 51 | #### G3 - Internal Amounts Must be Signed Integers and Represent the Smallest Units. 52 | 53 | Avoid representation errors by always dealing with weis when handling ether. GUIs can convert to more human-friendly representations. Use Signed Integers (int) to prevent underflow problems. 54 | 55 | 56 | ### Testing 57 | 58 | #### T1 - Tests Must be Written Elegantly 59 | 60 | Style guidelines are not relaxed for tests. Tests are a good way to show how to use the library, and maintaining them is extremely necessary. 61 | 62 | Don't write long tests, write helper functions to make them be as short and concise as possible (they should take just a few lines each), and use good variable names. 63 | 64 | #### T2 - Tests Must not be Random 65 | 66 | Inputs for tests should not be generated randomly. Accounts used to create test contracts are an exception, those can be random. Also, the type and structure of outputs should be checked. 67 | 68 | 69 | ### Documentation 70 | 71 | TODO 72 | 73 | ## Pull Request Workflow 74 | 75 | Our workflow is based on GitHub's pull requests. We use feature branches, prepended with: `test`, `feature`, `fix`, `refactor`, or `remove` according to the change the branch introduces. Some examples for such branches are: 76 | ```sh 77 | git checkout -b test/some-module 78 | git checkout -b feature/some-new-stuff 79 | git checkout -b fix/some-bug 80 | git checkout -b remove/some-file 81 | ``` 82 | 83 | We expect pull requests to be rebased to the master branch before merging: 84 | ```sh 85 | git remote add zep git@github.com:OpenZeppelin/zeppelin-solidity.git 86 | git pull --rebase zep master 87 | ``` 88 | 89 | Note that we require rebasing your branch instead of merging it, for commit readability reasons. 90 | 91 | After that, you can push the changes to your fork, by doing: 92 | ```sh 93 | git push origin your_branch_name 94 | git push origin feature/some-new-stuff 95 | git push origin fix/some-bug 96 | ``` 97 | 98 | Finally go to [github.com/OpenZeppelin/zeppelin-solidity](https://github.com/OpenZeppelin/zeppelin-solidity) in your web browser and issue a new pull request. 99 | 100 | Main contributors will review your code and possibly ask for changes before your code is pulled in to the main repository. We'll check that all tests pass, review the coding style, and check for general code correctness. If everything is OK, we'll merge your pull request and your code will be part of Zeppelin. 101 | 102 | If you have any questions feel free to post them to 103 | [github.com/OpenZeppelin/zeppelin-solidity/issues](https://github.com/OpenZeppelin/zeppelin-solidity/issues). 104 | 105 | Finally, if you're looking to collaborate and want to find easy tasks to start, [look at the issues we marked as easy](https://github.com/OpenZeppelin/zeppelin-solidity/labels/easy). 106 | 107 | Thanks for your time and code! 108 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Smart Contract Solutions, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gimmer Fork of Zeppelin Solidity 2 | 3 | ## Changes 4 | SafeMath: On Solidity 0.4.17 we are able to use the pure modifier instead of constant, because we are neither reading nor modifying the contract state. 5 | Ownable: Added explicit public to constructor 6 | 7 | ## New 8 | LimitedTokenCrowdSale: All of Zeppelin crowdsales models use Mintable Tokens, which does not fit the pattern that Gimmer Token is going to use - which is a fixed cap token, where nobody can mint new tokens after initial distribution. There came the need for a LimitedTokenCrowdsale, which basically acts as a pre-sale exchange: you stablish a price, users can buy the token and stay logged for later withdrawal. 9 | LimitedTokenDirectCrowdsale: Inherits from LimitedTokenCrowdSale, but implements functions for direct acquisition of tokens (no withdrawal patterns, so users that send Wei to the contract will receive tokens directly - this is useful for contracts that morph from crowdsales into direct-sale) 10 | 11 | Started writing initial unit tests for LimitedTokenCrowdSale 12 | 13 | ## Original Readme 14 | [![NPM Package](https://img.shields.io/npm/v/zeppelin-solidity.svg?style=flat-square)](https://www.npmjs.org/package/zeppelin-solidity) 15 | [![Build Status](https://img.shields.io/travis/OpenZeppelin/zeppelin-solidity.svg?branch=master&style=flat-square)](https://travis-ci.org/OpenZeppelin/zeppelin-solidity) 16 | [![Coverage Status](https://coveralls.io/repos/github/OpenZeppelin/zeppelin-solidity/badge.svg?branch=master)](https://coveralls.io/github/OpenZeppelin/zeppelin-solidity?branch=master) 17 | 18 | OpenZeppelin is a library for writing secure [Smart Contracts](https://en.wikipedia.org/wiki/Smart_contract) on Ethereum. 19 | 20 | With OpenZeppelin, you can build distributed applications, protocols and organizations: 21 | - using common contract security patterns (See [Onward with Ethereum Smart Contract Security](https://medium.com/bitcorps-blog/onward-with-ethereum-smart-contract-security-97a827e47702#.y3kvdetbz)) 22 | - in the [Solidity language](http://solidity.readthedocs.io/en/develop/). 23 | 24 | > NOTE: New to smart contract development? Check our [introductory guide](https://medium.com/zeppelin-blog/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05#.cox40d2ut). 25 | 26 | ## Getting Started 27 | 28 | OpenZeppelin integrates with [Truffle](https://github.com/ConsenSys/truffle), an Ethereum development environment. Please install Truffle and initialize your project with `truffle init`. 29 | 30 | ```sh 31 | npm install -g truffle 32 | mkdir myproject && cd myproject 33 | truffle init 34 | ``` 35 | 36 | To install the OpenZeppelin library, run: 37 | ```sh 38 | npm install zeppelin-solidity 39 | 40 | # If you are using yarn, add dependency like this - 41 | yarn add zeppelin-solidity 42 | ``` 43 | 44 | After that, you'll get all the library's contracts in the `node_modules/zeppelin-solidity/contracts` folder. You can use the contracts in the library like so: 45 | 46 | ```js 47 | import 'zeppelin-solidity/contracts/ownership/Ownable.sol'; 48 | 49 | contract MyContract is Ownable { 50 | ... 51 | } 52 | ``` 53 | 54 | 55 | ## Security 56 | OpenZeppelin is meant to provide secure, tested and community-audited code, but please use common sense when doing anything that deals with real money! We take no responsibility for your implementation decisions and any security problem you might experience. 57 | 58 | If you find a security issue, please email [security@openzeppelin.org](mailto:security@openzeppelin.org). 59 | 60 | ## Developer Resources 61 | 62 | Building a distributed application, protocol or organization with OpenZeppelin? 63 | 64 | - Read documentation: http://zeppelin-solidity.readthedocs.io/en/latest/ 65 | 66 | - Ask for help and follow progress at: https://slack.openzeppelin.org/ 67 | 68 | Interested in contributing to OpenZeppelin? 69 | 70 | - Framework proposal and roadmap: https://medium.com/zeppelin-blog/zeppelin-framework-proposal-and-development-roadmap-fdfa9a3a32ab#.iain47pak 71 | - Issue tracker: https://github.com/OpenZeppelin/zeppelin-solidity/issues 72 | - Contribution guidelines: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/CONTRIBUTING.md 73 | 74 | ## Collaborating organizations and audits by OpenZeppelin 75 | - [Golem](https://golem.network/) 76 | - [Mediachain](http://www.mediachain.io/) 77 | - [Truffle](http://truffleframework.com/) 78 | - [Firstblood](http://firstblood.io/) 79 | - [Rootstock](http://www.rsk.co/) 80 | - [Consensys](https://consensys.net/) 81 | - [DigixGlobal](https://www.dgx.io/) 82 | - [Coinfund](https://coinfund.io/) 83 | - [DemocracyEarth](http://democracy.earth/) 84 | - [Signatura](https://signatura.co/) 85 | - [Ether.camp](http://www.ether.camp/) 86 | - [Aragon](https://aragon.one/) 87 | - [Wings](https://wings.ai/) 88 | 89 | among others... 90 | 91 | 92 | ## License 93 | Code released under the [MIT License](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/LICENSE). 94 | -------------------------------------------------------------------------------- /contracts/Bounty.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import './payment/PullPayment.sol'; 5 | import './lifecycle/Destructible.sol'; 6 | 7 | 8 | /** 9 | * @title Bounty 10 | * @dev This bounty will pay out to a researcher if they break invariant logic of the contract. 11 | */ 12 | contract Bounty is PullPayment, Destructible { 13 | bool public claimed; 14 | mapping(address => address) public researchers; 15 | 16 | event TargetCreated(address createdAddress); 17 | 18 | /** 19 | * @dev Fallback function allowing the contract to receive funds, if they haven't already been claimed. 20 | */ 21 | function() payable { 22 | require(!claimed); 23 | } 24 | 25 | /** 26 | * @dev Create and deploy the target contract (extension of Target contract), and sets the 27 | * msg.sender as a researcher 28 | * @return A target contract 29 | */ 30 | function createTarget() public returns(Target) { 31 | Target target = Target(deployContract()); 32 | researchers[target] = msg.sender; 33 | TargetCreated(target); 34 | return target; 35 | } 36 | 37 | /** 38 | * @dev Internal function to deploy the target contract. 39 | * @return A target contract address 40 | */ 41 | function deployContract() internal returns(address); 42 | 43 | /** 44 | * @dev Sends the contract funds to the researcher that proved the contract is broken. 45 | * @param target contract 46 | */ 47 | function claim(Target target) public { 48 | address researcher = researchers[target]; 49 | require(researcher != 0); 50 | // Check Target contract invariants 51 | require(!target.checkInvariant()); 52 | asyncSend(researcher, this.balance); 53 | claimed = true; 54 | } 55 | 56 | } 57 | 58 | 59 | /** 60 | * @title Target 61 | * @dev Your main contract should inherit from this class and implement the checkInvariant method. 62 | */ 63 | contract Target { 64 | 65 | /** 66 | * @dev Checks all values a contract assumes to be true all the time. If this function returns 67 | * false, the contract is broken in some way and is in an inconsistent state. 68 | * In order to win the bounty, security researchers will try to cause this broken state. 69 | * @return True if all invariant values are correct, false otherwise. 70 | */ 71 | function checkInvariant() public returns(bool); 72 | } 73 | -------------------------------------------------------------------------------- /contracts/DayLimit.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | /** 4 | * @title DayLimit 5 | * @dev Base contract that enables methods to be protected by placing a linear limit (specifiable) 6 | * on a particular resource per calendar day. Is multiowned to allow the limit to be altered. 7 | */ 8 | contract DayLimit { 9 | 10 | uint256 public dailyLimit; 11 | uint256 public spentToday; 12 | uint256 public lastDay; 13 | 14 | /** 15 | * @dev Constructor that sets the passed value as a dailyLimit. 16 | * @param _limit uint256 to represent the daily limit. 17 | */ 18 | function DayLimit(uint256 _limit) { 19 | dailyLimit = _limit; 20 | lastDay = today(); 21 | } 22 | 23 | /** 24 | * @dev sets the daily limit. Does not alter the amount already spent today. 25 | * @param _newLimit uint256 to represent the new limit. 26 | */ 27 | function _setDailyLimit(uint256 _newLimit) internal { 28 | dailyLimit = _newLimit; 29 | } 30 | 31 | /** 32 | * @dev Resets the amount already spent today. 33 | */ 34 | function _resetSpentToday() internal { 35 | spentToday = 0; 36 | } 37 | 38 | /** 39 | * @dev Checks to see if there is enough resource to spend today. If true, the resource may be expended. 40 | * @param _value uint256 representing the amount of resource to spend. 41 | * @return A boolean that is True if the resource was spent and false otherwise. 42 | */ 43 | function underLimit(uint256 _value) internal returns (bool) { 44 | // reset the spend limit if we're on a different day to last time. 45 | if (today() > lastDay) { 46 | spentToday = 0; 47 | lastDay = today(); 48 | } 49 | // check to see if there's enough left - if so, subtract and return true. 50 | // overflow protection // dailyLimit check 51 | if (spentToday + _value >= spentToday && spentToday + _value <= dailyLimit) { 52 | spentToday += _value; 53 | return true; 54 | } 55 | return false; 56 | } 57 | 58 | /** 59 | * @dev Private function to determine today's index 60 | * @return uint256 of today's index. 61 | */ 62 | function today() private constant returns (uint256) { 63 | return now / 1 days; 64 | } 65 | 66 | /** 67 | * @dev Simple modifier for daily limit. 68 | */ 69 | modifier limitedDaily(uint256 _value) { 70 | require(underLimit(_value)); 71 | _; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /contracts/ECRecovery.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | /** 5 | * @title Eliptic curve signature operations 6 | * 7 | * @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d 8 | */ 9 | 10 | library ECRecovery { 11 | 12 | /** 13 | * @dev Recover signer address from a message by using his signature 14 | * @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address. 15 | * @param sig bytes signature, the signature is generated using web3.eth.sign() 16 | */ 17 | function recover(bytes32 hash, bytes sig) public constant returns (address) { 18 | bytes32 r; 19 | bytes32 s; 20 | uint8 v; 21 | 22 | //Check the signature length 23 | if (sig.length != 65) { 24 | return (address(0)); 25 | } 26 | 27 | // Divide the signature in r, s and v variables 28 | assembly { 29 | r := mload(add(sig, 32)) 30 | s := mload(add(sig, 64)) 31 | v := byte(0, mload(add(sig, 96))) 32 | } 33 | 34 | // Version of signature should be 27 or 28, but 0 and 1 are also possible versions 35 | if (v < 27) { 36 | v += 27; 37 | } 38 | 39 | // If the version is correct return the signer address 40 | if (v != 27 && v != 28) { 41 | return (address(0)); 42 | } else { 43 | return ecrecover(hash, v, r, s); 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /contracts/LimitBalance.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | /** 5 | * @title LimitBalance 6 | * @dev Simple contract to limit the balance of child contract. 7 | * @dev Note this doesn't prevent other contracts to send funds by using selfdestruct(address); 8 | * @dev See: https://github.com/ConsenSys/smart-contract-best-practices#remember-that-ether-can-be-forcibly-sent-to-an-account 9 | */ 10 | contract LimitBalance { 11 | 12 | uint256 public limit; 13 | 14 | /** 15 | * @dev Constructor that sets the passed value as a limit. 16 | * @param _limit uint256 to represent the limit. 17 | */ 18 | function LimitBalance(uint256 _limit) { 19 | limit = _limit; 20 | } 21 | 22 | /** 23 | * @dev Checks if limit was reached. Case true, it throws. 24 | */ 25 | modifier limitedPayable() { 26 | require(this.balance <= limit); 27 | _; 28 | 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /contracts/MerkleProof.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | /* 4 | * @title MerkleProof 5 | * @dev Merkle proof verification 6 | * @note Based on https://github.com/ameensol/merkle-tree-solidity/blob/master/src/MerkleProof.sol 7 | */ 8 | library MerkleProof { 9 | /* 10 | * @dev Verifies a Merkle proof proving the existence of a leaf in a Merkle tree. Assumes that each pair of leaves 11 | * and each pair of pre-images is sorted. 12 | * @param _proof Merkle proof containing sibling hashes on the branch from the leaf to the root of the Merkle tree 13 | * @param _root Merkle root 14 | * @param _leaf Leaf of Merkle tree 15 | */ 16 | function verifyProof(bytes _proof, bytes32 _root, bytes32 _leaf) constant returns (bool) { 17 | // Check if proof length is a multiple of 32 18 | if (_proof.length % 32 != 0) return false; 19 | 20 | bytes32 proofElement; 21 | bytes32 computedHash = _leaf; 22 | 23 | for (uint256 i = 32; i <= _proof.length; i += 32) { 24 | assembly { 25 | // Load the current element of the proof 26 | proofElement := mload(add(_proof, i)) 27 | } 28 | 29 | if (computedHash < proofElement) { 30 | // Hash(current computed hash + current element of the proof) 31 | computedHash = keccak256(computedHash, proofElement); 32 | } else { 33 | // Hash(current element of the proof + current computed hash) 34 | computedHash = keccak256(proofElement, computedHash); 35 | } 36 | } 37 | 38 | // Check if the computed hash (root) is equal to the provided root 39 | return computedHash == _root; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /contracts/ReentrancyGuard.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | /** 4 | * @title Helps contracts guard agains rentrancy attacks. 5 | * @author Remco Bloemen 6 | * @notice If you mark a function `nonReentrant`, you should also 7 | * mark it `external`. 8 | */ 9 | contract ReentrancyGuard { 10 | 11 | /** 12 | * @dev We use a single lock for the whole contract. 13 | */ 14 | bool private rentrancy_lock = false; 15 | 16 | /** 17 | * @dev Prevents a contract from calling itself, directly or indirectly. 18 | * @notice If you mark a function `nonReentrant`, you should also 19 | * mark it `external`. Calling one nonReentrant function from 20 | * another is not supported. Instead, you can implement a 21 | * `private` function doing the actual work, and a `external` 22 | * wrapper marked as `nonReentrant`. 23 | */ 24 | modifier nonReentrant() { 25 | require(!rentrancy_lock); 26 | rentrancy_lock = true; 27 | _; 28 | rentrancy_lock = false; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /contracts/crowdsale/CappedCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import '../math/SafeMath.sol'; 4 | import './Crowdsale.sol'; 5 | 6 | /** 7 | * @title CappedCrowdsale 8 | * @dev Extension of Crowdsale with a max amount of funds raised 9 | */ 10 | contract CappedCrowdsale is Crowdsale { 11 | using SafeMath for uint256; 12 | 13 | uint256 public cap; 14 | 15 | function CappedCrowdsale(uint256 _cap) { 16 | require(_cap > 0); 17 | cap = _cap; 18 | } 19 | 20 | // overriding Crowdsale#validPurchase to add extra cap logic 21 | // @return true if investors can buy at the moment 22 | function validPurchase() internal constant returns (bool) { 23 | bool withinCap = weiRaised.add(msg.value) <= cap; 24 | return super.validPurchase() && withinCap; 25 | } 26 | 27 | // overriding Crowdsale#hasEnded to add cap logic 28 | // @return true if crowdsale event has ended 29 | function hasEnded() public constant returns (bool) { 30 | bool capReached = weiRaised >= cap; 31 | return super.hasEnded() || capReached; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /contracts/crowdsale/Crowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import '../token/MintableToken.sol'; 4 | import '../math/SafeMath.sol'; 5 | 6 | /** 7 | * @title Crowdsale 8 | * @dev Crowdsale is a base contract for managing a token crowdsale. 9 | * Crowdsales have a start and end timestamps, where investors can make 10 | * token purchases and the crowdsale will assign them tokens based 11 | * on a token per ETH rate. Funds collected are forwarded to a wallet 12 | * as they arrive. 13 | */ 14 | contract Crowdsale { 15 | using SafeMath for uint256; 16 | 17 | // The token being sold 18 | MintableToken public token; 19 | 20 | // start and end timestamps where investments are allowed (both inclusive) 21 | uint256 public startTime; 22 | uint256 public endTime; 23 | 24 | // address where funds are collected 25 | address public wallet; 26 | 27 | // how many token units a buyer gets per wei 28 | uint256 public rate; 29 | 30 | // amount of raised money in wei 31 | uint256 public weiRaised; 32 | 33 | /** 34 | * event for token purchase logging 35 | * @param purchaser who paid for the tokens 36 | * @param beneficiary who got the tokens 37 | * @param value weis paid for purchase 38 | * @param amount amount of tokens purchased 39 | */ 40 | event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount); 41 | 42 | 43 | function Crowdsale(uint256 _startTime, uint256 _endTime, uint256 _rate, address _wallet) { 44 | require(_startTime >= now); 45 | require(_endTime >= _startTime); 46 | require(_rate > 0); 47 | require(_wallet != address(0)); 48 | 49 | token = createTokenContract(); 50 | startTime = _startTime; 51 | endTime = _endTime; 52 | rate = _rate; 53 | wallet = _wallet; 54 | } 55 | 56 | // creates the token to be sold. 57 | // override this method to have crowdsale of a specific mintable token. 58 | function createTokenContract() internal returns (MintableToken) { 59 | return new MintableToken(); 60 | } 61 | 62 | 63 | // fallback function can be used to buy tokens 64 | function () payable { 65 | buyTokens(msg.sender); 66 | } 67 | 68 | // low level token purchase function 69 | function buyTokens(address beneficiary) public payable { 70 | require(beneficiary != address(0)); 71 | require(validPurchase()); 72 | 73 | uint256 weiAmount = msg.value; 74 | 75 | // calculate token amount to be created 76 | uint256 tokens = weiAmount.mul(rate); 77 | 78 | // update state 79 | weiRaised = weiRaised.add(weiAmount); 80 | 81 | token.mint(beneficiary, tokens); 82 | TokenPurchase(msg.sender, beneficiary, weiAmount, tokens); 83 | 84 | forwardFunds(); 85 | } 86 | 87 | // send ether to the fund collection wallet 88 | // override to create custom fund forwarding mechanisms 89 | function forwardFunds() internal { 90 | wallet.transfer(msg.value); 91 | } 92 | 93 | // @return true if the transaction can buy tokens 94 | function validPurchase() internal constant returns (bool) { 95 | bool withinPeriod = now >= startTime && now <= endTime; 96 | bool nonZeroPurchase = msg.value != 0; 97 | return withinPeriod && nonZeroPurchase; 98 | } 99 | 100 | // @return true if crowdsale event has ended 101 | function hasEnded() public constant returns (bool) { 102 | return now > endTime; 103 | } 104 | 105 | 106 | } 107 | -------------------------------------------------------------------------------- /contracts/crowdsale/FinalizableCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import '../math/SafeMath.sol'; 4 | import '../ownership/Ownable.sol'; 5 | import './Crowdsale.sol'; 6 | 7 | /** 8 | * @title FinalizableCrowdsale 9 | * @dev Extension of Crowdsale where an owner can do extra work 10 | * after finishing. 11 | */ 12 | contract FinalizableCrowdsale is Crowdsale, Ownable { 13 | using SafeMath for uint256; 14 | 15 | bool public isFinalized = false; 16 | 17 | event Finalized(); 18 | 19 | /** 20 | * @dev Must be called after crowdsale ends, to do some extra finalization 21 | * work. Calls the contract's finalization function. 22 | */ 23 | function finalize() onlyOwner public { 24 | require(!isFinalized); 25 | require(hasEnded()); 26 | 27 | finalization(); 28 | Finalized(); 29 | 30 | isFinalized = true; 31 | } 32 | 33 | /** 34 | * @dev Can be overridden to add finalization logic. The overriding function 35 | * should call super.finalization() to ensure the chain of finalization is 36 | * executed entirely. 37 | */ 38 | function finalization() internal { 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /contracts/crowdsale/LimitedTokenCrowdsale.sol: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * @section DESCRIPTION 4 | * 5 | * Contract for a Limited Token Crowdsale: at it's core, it's an exchange of tokens. 6 | * Uses StandardToken instead of MintTokens. 7 | * Provides functionality for tracking how much each supporter helped with, 8 | * who has permissiong to buy higher values and uses withdrawal logic for the payment system. 9 | * 10 | * Wei withdrawal by default is to the wallet provided at construction. 11 | * Inherit from this contract and override the payment and pricing functions to deploy a valid contract 12 | */ 13 | pragma solidity ^0.4.17; 14 | 15 | import '../token/StandardToken.sol'; 16 | import '../math/SafeMath.sol'; 17 | 18 | /** 19 | * @title Limited Token Crowdsale 20 | */ 21 | contract LimitedTokenCrowdSale { 22 | // Use safemath for the .add, .mul used everywhere that deals with tokens/eth 23 | using SafeMath for uint256; 24 | 25 | // The token being sold 26 | StandardToken public token; 27 | 28 | // Supporter structure, which allows us to track 29 | // how much the user has bought so far, if he's allowed to buy more 30 | // than the max limit for no KYC, or if he has any money frozen 31 | 32 | /** 33 | * Supporter structure, which allows us to track 34 | * how much the user has bought so far, if he's allowed to buy more 35 | * than the max limit for no KYC, or if he has any money frozen 36 | */ 37 | struct Supporter { 38 | // the current amount this user has left to withdraw 39 | uint256 tokenBalance; 40 | // the total amount of tokens this user has bought from this contract 41 | uint256 tokensBought; 42 | // the total amount of Wei that is currently frozen in the system 43 | // because the user has not yet provided KYC (know-your-customer, money laundering protection) 44 | // (this happens when the user buys more tokens than he is allowed without KYC - so neither the user nor 45 | // the owner of the contract can withdraw the Wei/Tokens until approveUserKYC(user) is called by the owner.) 46 | uint256 weiFrozen; 47 | // if the user has KYC flagged 48 | bool hasKYC; 49 | } 50 | 51 | // Mapping with all the campaign supporters 52 | mapping(address => Supporter) public supportersMap; 53 | 54 | // Address where funds are collected 55 | address public wallet; 56 | 57 | // Amount of total wei raised 58 | uint256 public weiRaised; 59 | 60 | // Amount of wei that is currently frozen and cannot be withdrawn by the owner 61 | uint256 public weiFrozen; 62 | 63 | // Amount of total tokens sold 64 | uint256 public tokensSold; 65 | 66 | // Amount of tokens that have already been paid for, but not withdrawn 67 | uint256 public tokensToWithdraw; 68 | 69 | // The minimum amount of tokens a user is allowed to buy 70 | uint256 public minTokenTransaction; 71 | 72 | // The limit of Wei that someone can spend on this contract before needing KYC approval 73 | uint256 public weiSaleLimitWithoutKYC; 74 | 75 | /** 76 | * Event for token purchase logging 77 | * @param purchaser Who paid for the tokens 78 | * @param value Weis paid for purchase 79 | * @param amount Amount of tokens purchased 80 | * @param price Price user paid for tokens 81 | */ 82 | event TokenPurchase(address indexed purchaser, uint256 value, uint256 amount, uint256 price); 83 | 84 | /** 85 | * Event for user that purchased more than the contract allows 86 | * for users with no KYC approval 87 | * @param purchaser Who paid for the tokens 88 | * @param value Weis paid for purchases 89 | * @param amount Amount of tokens purchased 90 | */ 91 | event KYCPending(address indexed purchaser, uint256 value, uint256 amount); 92 | 93 | function LimitedTokenCrowdSale(address _tokenAddress, uint256 _minTokenTransaction, 94 | uint256 _weiSaleLimitWithoutKYC, address _wallet) public { 95 | require(_tokenAddress != address(0)); 96 | require(_minTokenTransaction >= 0); 97 | require(_weiSaleLimitWithoutKYC != 0); 98 | require(_wallet != address(0)); 99 | 100 | token = StandardToken(_tokenAddress); 101 | minTokenTransaction = _minTokenTransaction; 102 | weiSaleLimitWithoutKYC = _weiSaleLimitWithoutKYC; 103 | wallet = _wallet; 104 | } 105 | 106 | /** 107 | * @dev Send all the funds currently in the wallet to 108 | * the organization wallet provided at the contract creation. 109 | */ 110 | function internalWithdrawFunds() internal { 111 | require(this.balance > 0); 112 | 113 | // only withdraw money that is not frozen 114 | uint256 available = this.balance.sub(weiFrozen); 115 | require(available > 0); 116 | 117 | wallet.transfer(available); 118 | } 119 | 120 | /** 121 | * @dev Approves an User's KYC, unfreezing any Wei/Tokens 122 | * to be withdrawn 123 | */ 124 | function internalApproveUserKYC(address user) internal { 125 | Supporter storage sup = supportersMap[user]; 126 | weiFrozen = weiFrozen.sub(sup.weiFrozen); 127 | sup.weiFrozen = 0; 128 | sup.hasKYC = true; 129 | } 130 | 131 | /** 132 | * @dev Payment function: explicitly reverts as this class needs to be inherited and 133 | * shouldn't receive Wei without handling it 134 | */ 135 | function () public payable { 136 | revert(); 137 | } 138 | 139 | /** 140 | * @dev Override to return the token priced used 141 | */ 142 | function internalGetTokenPrice() internal constant returns (uint256); 143 | 144 | /** 145 | * @dev Saves how much the user bought in tokens for later withdrawal 146 | */ 147 | function internalBuyToken(uint256 weiAmount, address sender) internal { 148 | require(weiAmount != 0); 149 | require(sender != address(0)); 150 | 151 | // give a chance to an inheriting contract to have 152 | // its own options for token pricing 153 | uint256 price = internalGetTokenPrice(); 154 | 155 | // calculate token amount to be given to user 156 | // (Solidity always truncates on division) 157 | uint256 tokens = weiAmount.div(price); 158 | 159 | // must have more tokens than min transaction.. 160 | require(tokens > minTokenTransaction); 161 | // ..and the contract must have tokens available to sell 162 | require(token.balanceOf(this).sub(tokensToWithdraw) > tokens); 163 | 164 | // add to the balance of the user, to be paid later 165 | Supporter storage sup = supportersMap[sender]; 166 | uint256 totalBought = sup.tokensBought.add(tokens); 167 | if (!sup.hasKYC && totalBought > weiSaleLimitWithoutKYC) { 168 | // money is frozen as user has no KYC, 169 | // and bought in total more than is allowed 170 | weiFrozen = weiFrozen.add(weiAmount); 171 | sup.weiFrozen = sup.weiFrozen.add(weiAmount); 172 | 173 | KYCPending(sender, weiAmount, tokens); 174 | } 175 | // add to the total to be withdrawn 176 | sup.tokenBalance = sup.tokenBalance.add(tokens); 177 | 178 | // update the total amount of tokens bought 179 | sup.tokensBought = totalBought; 180 | // updates the total amount of tokens we have to still withdraw, 181 | // this will be subtracted each time an user withdraws 182 | tokensToWithdraw = tokensToWithdraw.add(tokens); 183 | 184 | // update how much Wei we have raised 185 | weiRaised = weiAmount.add(weiRaised); 186 | // update the total amount of tokens we have sold 187 | tokensSold = tokensSold.add(tokens); 188 | // send an event for a Token Purchase 189 | TokenPurchase(sender, weiAmount, tokens, price); 190 | } 191 | 192 | /** 193 | * @dev Returns if an users has KYC approval or not 194 | * @return A boolean representing the user's KYC status 195 | */ 196 | function userHasKYC(address user) public constant returns (bool) { 197 | return supportersMap[user].hasKYC; 198 | } 199 | 200 | /** 201 | * @dev Returns the total amount an user has bought from this contract 202 | * @return An uint256 representing the total amount of tokens the user bought 203 | */ 204 | function userTotalBought(address user) public constant returns (uint256) { 205 | return supportersMap[user].tokensBought; 206 | } 207 | 208 | /** 209 | * @dev Gets the balance left to withdraw of the specified address. 210 | * @param _owner The address to query the the balance of. 211 | * @return An uint256 representing the amount owned by the passed address. 212 | */ 213 | function tokenBalanceOf(address _owner) public constant returns (uint256) { 214 | return supportersMap[_owner].tokenBalance; 215 | } 216 | 217 | /** 218 | * @dev Withdraws the tokens that the sender owns 219 | */ 220 | function withdrawTokens() public { 221 | address to = msg.sender; 222 | Supporter storage sup = supportersMap[to]; 223 | uint256 balance = sup.tokenBalance; 224 | require(balance > 0); 225 | require(sup.weiFrozen == 0); 226 | 227 | if (token.transfer(to, balance)) { 228 | // only remove from the amount to withdraw if transfer returned true 229 | sup.tokenBalance = 0; 230 | tokensToWithdraw = tokensToWithdraw.sub(balance); 231 | } else { 232 | // transfer failed, balance is stuck 233 | revert(); 234 | } 235 | } 236 | } -------------------------------------------------------------------------------- /contracts/crowdsale/LimitedTokenDirectCrowdsale.sol: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * @section DESCRIPTION 4 | * 5 | * Contract for a Limited Token Crowdsale where eventually 6 | * after the crowdsale ends (user set) we become a basically a store 7 | * where the tokens the contract has left are sold directly to the end user, 8 | * without the use of withdrawing logic. 9 | */ 10 | pragma solidity ^0.4.17; 11 | 12 | import '../crowdsale/LimitedTokenCrowdsale.sol'; 13 | import '../math/SafeMath.sol'; 14 | 15 | /** 16 | * @title Limited Token Direct Crowdsale 17 | */ 18 | contract LimitedTokenDirectCrowdsale is LimitedTokenCrowdSale { 19 | function LimitedTokenDirectCrowdsale(address _tokenAddress, uint256 _minTokenTransaction, 20 | uint256 _weiSaleLimitWithoutKYC, address _wallet) 21 | LimitedTokenCrowdSale(_tokenAddress, _minTokenTransaction, 22 | _weiSaleLimitWithoutKYC, _wallet) public { 23 | } 24 | 25 | /** 26 | * @dev The current price of the Token for this contract 27 | * Override to return the token priced used 28 | * @return An uint256 representing the current token price. 29 | */ 30 | function getDirectTokenPrice() public constant returns (uint256); 31 | 32 | /** 33 | * @dev Buys tokens and sends them directly to the end user 34 | */ 35 | function internalBuyTokenDirect(uint256 weiAmount, address sender) internal { 36 | require(sender != 0x0); 37 | require(weiAmount != 0); 38 | 39 | // give a chance to an inheriting contract to have 40 | // its own options for token pricing 41 | uint256 price = getDirectTokenPrice(); 42 | 43 | // calculate token amount to be given to user 44 | // (Solidity always truncates on division) 45 | uint256 tokens = weiAmount / price; 46 | 47 | // must have more tokens than min transaction.. 48 | require(tokens > minTokenTransaction); 49 | // ..and the contract must have tokens to sell 50 | require(token.balanceOf(this) > tokens); 51 | 52 | // add to the balance of the user, to be paid later 53 | Supporter storage sup = supportersMap[sender]; 54 | if (!sup.hasKYC && tokens > weiSaleLimitWithoutKYC) { 55 | revert(); // no KYC + too much Wei at after sale = no tokens 56 | } 57 | 58 | // add to the balance of the user, to be paid later 59 | if (token.transfer(sender, tokens)) { 60 | sup.tokensBought = sup.tokensBought.add(tokens); 61 | 62 | // update how much Wei we have raised 63 | weiRaised = weiAmount.add(weiRaised); 64 | // update the total amount of tokens we have sold 65 | // (this value never goes down) 66 | tokensSold = tokensSold.add(tokens); 67 | // send an event for a Token Purchase 68 | TokenPurchase(sender, weiAmount, tokens, price); 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /contracts/crowdsale/RefundVault.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import '../math/SafeMath.sol'; 4 | import '../ownership/Ownable.sol'; 5 | 6 | /** 7 | * @title RefundVault 8 | * @dev This contract is used for storing funds while a crowdsale 9 | * is in progress. Supports refunding the money if crowdsale fails, 10 | * and forwarding it if crowdsale is successful. 11 | */ 12 | contract RefundVault is Ownable { 13 | using SafeMath for uint256; 14 | 15 | enum State { Active, Refunding, Closed } 16 | 17 | mapping (address => uint256) public deposited; 18 | address public wallet; 19 | State public state; 20 | 21 | event Closed(); 22 | event RefundsEnabled(); 23 | event Refunded(address indexed beneficiary, uint256 weiAmount); 24 | 25 | function RefundVault(address _wallet) { 26 | require(_wallet != 0x0); 27 | wallet = _wallet; 28 | state = State.Active; 29 | } 30 | 31 | function deposit(address investor) onlyOwner public payable { 32 | require(state == State.Active); 33 | deposited[investor] = deposited[investor].add(msg.value); 34 | } 35 | 36 | function close() onlyOwner public { 37 | require(state == State.Active); 38 | state = State.Closed; 39 | Closed(); 40 | wallet.transfer(this.balance); 41 | } 42 | 43 | function enableRefunds() onlyOwner public { 44 | require(state == State.Active); 45 | state = State.Refunding; 46 | RefundsEnabled(); 47 | } 48 | 49 | function refund(address investor) public { 50 | require(state == State.Refunding); 51 | uint256 depositedValue = deposited[investor]; 52 | deposited[investor] = 0; 53 | investor.transfer(depositedValue); 54 | Refunded(investor, depositedValue); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /contracts/crowdsale/RefundableCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import '../math/SafeMath.sol'; 5 | import './FinalizableCrowdsale.sol'; 6 | import './RefundVault.sol'; 7 | 8 | 9 | /** 10 | * @title RefundableCrowdsale 11 | * @dev Extension of Crowdsale contract that adds a funding goal, and 12 | * the possibility of users getting a refund if goal is not met. 13 | * Uses a RefundVault as the crowdsale's vault. 14 | */ 15 | contract RefundableCrowdsale is FinalizableCrowdsale { 16 | using SafeMath for uint256; 17 | 18 | // minimum amount of funds to be raised in weis 19 | uint256 public goal; 20 | 21 | // refund vault used to hold funds while crowdsale is running 22 | RefundVault public vault; 23 | 24 | function RefundableCrowdsale(uint256 _goal) { 25 | require(_goal > 0); 26 | vault = new RefundVault(wallet); 27 | goal = _goal; 28 | } 29 | 30 | // We're overriding the fund forwarding from Crowdsale. 31 | // In addition to sending the funds, we want to call 32 | // the RefundVault deposit function 33 | function forwardFunds() internal { 34 | vault.deposit.value(msg.value)(msg.sender); 35 | } 36 | 37 | // if crowdsale is unsuccessful, investors can claim refunds here 38 | function claimRefund() public { 39 | require(isFinalized); 40 | require(!goalReached()); 41 | 42 | vault.refund(msg.sender); 43 | } 44 | 45 | // vault finalization task, called when owner calls finalize() 46 | function finalization() internal { 47 | if (goalReached()) { 48 | vault.close(); 49 | } else { 50 | vault.enableRefunds(); 51 | } 52 | 53 | super.finalization(); 54 | } 55 | 56 | function goalReached() public constant returns (bool) { 57 | return weiRaised >= goal; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /contracts/examples/SampleCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import "../crowdsale/CappedCrowdsale.sol"; 4 | import "../crowdsale/RefundableCrowdsale.sol"; 5 | import "../token/MintableToken.sol"; 6 | 7 | /** 8 | * @title SampleCrowdsaleToken 9 | * @dev Very simple ERC20 Token that can be minted. 10 | * It is meant to be used in a crowdsale contract. 11 | */ 12 | contract SampleCrowdsaleToken is MintableToken { 13 | 14 | string public constant name = "Sample Crowdsale Token"; 15 | string public constant symbol = "SCT"; 16 | uint8 public constant decimals = 18; 17 | 18 | } 19 | 20 | /** 21 | * @title SampleCrowdsale 22 | * @dev This is an example of a fully fledged crowdsale. 23 | * The way to add new features to a base crowdsale is by multiple inheritance. 24 | * In this example we are providing following extensions: 25 | * CappedCrowdsale - sets a max boundary for raised funds 26 | * RefundableCrowdsale - set a min goal to be reached and returns funds if it's not met 27 | * 28 | * After adding multiple features it's good practice to run integration tests 29 | * to ensure that subcontracts works together as intended. 30 | */ 31 | contract SampleCrowdsale is CappedCrowdsale, RefundableCrowdsale { 32 | 33 | function SampleCrowdsale(uint256 _startTime, uint256 _endTime, uint256 _rate, uint256 _goal, uint256 _cap, address _wallet) 34 | CappedCrowdsale(_cap) 35 | FinalizableCrowdsale() 36 | RefundableCrowdsale(_goal) 37 | Crowdsale(_startTime, _endTime, _rate, _wallet) 38 | { 39 | //As goal needs to be met for a successful crowdsale 40 | //the value needs to less or equal than a cap which is limit for accepted funds 41 | require(_goal <= _cap); 42 | } 43 | 44 | function createTokenContract() internal returns (MintableToken) { 45 | return new SampleCrowdsaleToken(); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /contracts/examples/SimpleToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import "../token/StandardToken.sol"; 5 | 6 | 7 | /** 8 | * @title SimpleToken 9 | * @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator. 10 | * Note they can later distribute these tokens as they wish using `transfer` and other 11 | * `StandardToken` functions. 12 | */ 13 | contract SimpleToken is StandardToken { 14 | 15 | string public constant name = "SimpleToken"; 16 | string public constant symbol = "SIM"; 17 | uint8 public constant decimals = 18; 18 | 19 | uint256 public constant INITIAL_SUPPLY = 10000 * (10 ** uint256(decimals)); 20 | 21 | /** 22 | * @dev Constructor that gives msg.sender all of existing tokens. 23 | */ 24 | function SimpleToken() { 25 | totalSupply = INITIAL_SUPPLY; 26 | balances[msg.sender] = INITIAL_SUPPLY; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /contracts/lifecycle/Destructible.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import "../ownership/Ownable.sol"; 5 | 6 | 7 | /** 8 | * @title Destructible 9 | * @dev Base contract that can be destroyed by owner. All funds in contract will be sent to the owner. 10 | */ 11 | contract Destructible is Ownable { 12 | 13 | function Destructible() payable { } 14 | 15 | /** 16 | * @dev Transfers the current balance to the owner and terminates the contract. 17 | */ 18 | function destroy() onlyOwner public { 19 | selfdestruct(owner); 20 | } 21 | 22 | function destroyAndSend(address _recipient) onlyOwner public { 23 | selfdestruct(_recipient); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /contracts/lifecycle/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import '../ownership/Ownable.sol'; 5 | 6 | /** 7 | * @title Migrations 8 | * @dev This is a truffle contract, needed for truffle integration, not meant for use by Zeppelin users. 9 | */ 10 | contract Migrations is Ownable { 11 | uint256 public lastCompletedMigration; 12 | 13 | function setCompleted(uint256 completed) onlyOwner public { 14 | lastCompletedMigration = completed; 15 | } 16 | 17 | function upgrade(address newAddress) onlyOwner public { 18 | Migrations upgraded = Migrations(newAddress); 19 | upgraded.setCompleted(lastCompletedMigration); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/lifecycle/Pausable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import "../ownership/Ownable.sol"; 5 | 6 | 7 | /** 8 | * @title Pausable 9 | * @dev Base contract which allows children to implement an emergency stop mechanism. 10 | */ 11 | contract Pausable is Ownable { 12 | event Pause(); 13 | event Unpause(); 14 | 15 | bool public paused = false; 16 | 17 | 18 | /** 19 | * @dev Modifier to make a function callable only when the contract is not paused. 20 | */ 21 | modifier whenNotPaused() { 22 | require(!paused); 23 | _; 24 | } 25 | 26 | /** 27 | * @dev Modifier to make a function callable only when the contract is paused. 28 | */ 29 | modifier whenPaused() { 30 | require(paused); 31 | _; 32 | } 33 | 34 | /** 35 | * @dev called by the owner to pause, triggers stopped state 36 | */ 37 | function pause() onlyOwner whenNotPaused public { 38 | paused = true; 39 | Pause(); 40 | } 41 | 42 | /** 43 | * @dev called by the owner to unpause, returns to normal state 44 | */ 45 | function unpause() onlyOwner whenPaused public { 46 | paused = false; 47 | Unpause(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contracts/lifecycle/TokenDestructible.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import "../ownership/Ownable.sol"; 5 | import "../token/ERC20Basic.sol"; 6 | 7 | /** 8 | * @title TokenDestructible: 9 | * @author Remco Bloemen 10 | * @dev Base contract that can be destroyed by owner. All funds in contract including 11 | * listed tokens will be sent to the owner. 12 | */ 13 | contract TokenDestructible is Ownable { 14 | 15 | function TokenDestructible() payable { } 16 | 17 | /** 18 | * @notice Terminate contract and refund to owner 19 | * @param tokens List of addresses of ERC20 or ERC20Basic token contracts to 20 | refund. 21 | * @notice The called token contracts could try to re-enter this contract. Only 22 | supply token contracts you trust. 23 | */ 24 | function destroy(address[] tokens) onlyOwner public { 25 | 26 | // Transfer tokens to owner 27 | for(uint256 i = 0; i < tokens.length; i++) { 28 | ERC20Basic token = ERC20Basic(tokens[i]); 29 | uint256 balance = token.balanceOf(this); 30 | token.transfer(owner, balance); 31 | } 32 | 33 | // Transfer Eth to owner and terminate contract 34 | selfdestruct(owner); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contracts/math/Math.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | /** 4 | * @title Math 5 | * @dev Assorted math operations 6 | */ 7 | 8 | library Math { 9 | function max64(uint64 a, uint64 b) internal constant returns (uint64) { 10 | return a >= b ? a : b; 11 | } 12 | 13 | function min64(uint64 a, uint64 b) internal constant returns (uint64) { 14 | return a < b ? a : b; 15 | } 16 | 17 | function max256(uint256 a, uint256 b) internal constant returns (uint256) { 18 | return a >= b ? a : b; 19 | } 20 | 21 | function min256(uint256 a, uint256 b) internal constant returns (uint256) { 22 | return a < b ? a : b; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/math/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | /** 5 | * @title SafeMath 6 | * @dev Math operations with safety checks that throw on error 7 | */ 8 | library SafeMath { 9 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 10 | uint256 c = a * b; 11 | assert(a == 0 || c / a == b); 12 | return c; 13 | } 14 | 15 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 16 | // assert(b > 0); // Solidity automatically throws when dividing by 0 17 | uint256 c = a / b; 18 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 19 | return c; 20 | } 21 | 22 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 23 | assert(b <= a); 24 | return a - b; 25 | } 26 | 27 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 28 | uint256 c = a + b; 29 | assert(c >= a); 30 | return c; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /contracts/ownership/CanReclaimToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import "./Ownable.sol"; 4 | import "../token/ERC20Basic.sol"; 5 | import "../token/SafeERC20.sol"; 6 | 7 | /** 8 | * @title Contracts that should be able to recover tokens 9 | * @author SylTi 10 | * @dev This allow a contract to recover any ERC20 token received in a contract by transferring the balance to the contract owner. 11 | * This will prevent any accidental loss of tokens. 12 | */ 13 | contract CanReclaimToken is Ownable { 14 | using SafeERC20 for ERC20Basic; 15 | 16 | /** 17 | * @dev Reclaim all ERC20Basic compatible tokens 18 | * @param token ERC20Basic The address of the token contract 19 | */ 20 | function reclaimToken(ERC20Basic token) external onlyOwner { 21 | uint256 balance = token.balanceOf(this); 22 | token.safeTransfer(owner, balance); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /contracts/ownership/Claimable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import './Ownable.sol'; 5 | 6 | 7 | /** 8 | * @title Claimable 9 | * @dev Extension for the Ownable contract, where the ownership needs to be claimed. 10 | * This allows the new owner to accept the transfer. 11 | */ 12 | contract Claimable is Ownable { 13 | address public pendingOwner; 14 | 15 | /** 16 | * @dev Modifier throws if called by any account other than the pendingOwner. 17 | */ 18 | modifier onlyPendingOwner() { 19 | require(msg.sender == pendingOwner); 20 | _; 21 | } 22 | 23 | /** 24 | * @dev Allows the current owner to set the pendingOwner address. 25 | * @param newOwner The address to transfer ownership to. 26 | */ 27 | function transferOwnership(address newOwner) onlyOwner public { 28 | pendingOwner = newOwner; 29 | } 30 | 31 | /** 32 | * @dev Allows the pendingOwner address to finalize the transfer. 33 | */ 34 | function claimOwnership() onlyPendingOwner public { 35 | OwnershipTransferred(owner, pendingOwner); 36 | owner = pendingOwner; 37 | pendingOwner = address(0); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /contracts/ownership/Contactable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import './Ownable.sol'; 4 | 5 | /** 6 | * @title Contactable token 7 | * @dev Basic version of a contactable contract, allowing the owner to provide a string with their 8 | * contact information. 9 | */ 10 | contract Contactable is Ownable{ 11 | 12 | string public contactInformation; 13 | 14 | /** 15 | * @dev Allows the owner to set a string with their contact information. 16 | * @param info The contact information to attach to the contract. 17 | */ 18 | function setContactInformation(string info) onlyOwner public { 19 | contactInformation = info; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/ownership/DelayedClaimable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import './Claimable.sol'; 5 | 6 | 7 | /** 8 | * @title DelayedClaimable 9 | * @dev Extension for the Claimable contract, where the ownership needs to be claimed before/after 10 | * a certain block number. 11 | */ 12 | contract DelayedClaimable is Claimable { 13 | 14 | uint256 public end; 15 | uint256 public start; 16 | 17 | /** 18 | * @dev Used to specify the time period during which a pending 19 | * owner can claim ownership. 20 | * @param _start The earliest time ownership can be claimed. 21 | * @param _end The latest time ownership can be claimed. 22 | */ 23 | function setLimits(uint256 _start, uint256 _end) onlyOwner public { 24 | require(_start <= _end); 25 | end = _end; 26 | start = _start; 27 | } 28 | 29 | 30 | /** 31 | * @dev Allows the pendingOwner address to finalize the transfer, as long as it is called within 32 | * the specified start and end time. 33 | */ 34 | function claimOwnership() onlyPendingOwner public { 35 | require((block.number <= end) && (block.number >= start)); 36 | OwnershipTransferred(owner, pendingOwner); 37 | owner = pendingOwner; 38 | pendingOwner = address(0); 39 | end = 0; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /contracts/ownership/HasNoContracts.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import "./Ownable.sol"; 4 | 5 | /** 6 | * @title Contracts that should not own Contracts 7 | * @author Remco Bloemen 8 | * @dev Should contracts (anything Ownable) end up being owned by this contract, it allows the owner 9 | * of this contract to reclaim ownership of the contracts. 10 | */ 11 | contract HasNoContracts is Ownable { 12 | 13 | /** 14 | * @dev Reclaim ownership of Ownable contracts 15 | * @param contractAddr The address of the Ownable to be reclaimed. 16 | */ 17 | function reclaimContract(address contractAddr) external onlyOwner { 18 | Ownable contractInst = Ownable(contractAddr); 19 | contractInst.transferOwnership(owner); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/ownership/HasNoEther.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import "./Ownable.sol"; 4 | 5 | /** 6 | * @title Contracts that should not own Ether 7 | * @author Remco Bloemen 8 | * @dev This tries to block incoming ether to prevent accidental loss of Ether. Should Ether end up 9 | * in the contract, it will allow the owner to reclaim this ether. 10 | * @notice Ether can still be send to this contract by: 11 | * calling functions labeled `payable` 12 | * `selfdestruct(contract_address)` 13 | * mining directly to the contract address 14 | */ 15 | contract HasNoEther is Ownable { 16 | 17 | /** 18 | * @dev Constructor that rejects incoming Ether 19 | * @dev The `payable` flag is added so we can access `msg.value` without compiler warning. If we 20 | * leave out payable, then Solidity will allow inheriting contracts to implement a payable 21 | * constructor. By doing it this way we prevent a payable constructor from working. Alternatively 22 | * we could use assembly to access msg.value. 23 | */ 24 | function HasNoEther() payable { 25 | require(msg.value == 0); 26 | } 27 | 28 | /** 29 | * @dev Disallows direct send by settings a default function without the `payable` flag. 30 | */ 31 | function() external { 32 | } 33 | 34 | /** 35 | * @dev Transfer all Ether held by the contract to the owner. 36 | */ 37 | function reclaimEther() external onlyOwner { 38 | assert(owner.send(this.balance)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /contracts/ownership/HasNoTokens.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import "./CanReclaimToken.sol"; 4 | 5 | /** 6 | * @title Contracts that should not own Tokens 7 | * @author Remco Bloemen 8 | * @dev This blocks incoming ERC23 tokens to prevent accidental loss of tokens. 9 | * Should tokens (any ERC20Basic compatible) end up in the contract, it allows the 10 | * owner to reclaim the tokens. 11 | */ 12 | contract HasNoTokens is CanReclaimToken { 13 | 14 | /** 15 | * @dev Reject all ERC23 compatible tokens 16 | * @param from_ address The address that is transferring the tokens 17 | * @param value_ uint256 the amount of the specified token 18 | * @param data_ Bytes The data passed from the caller. 19 | */ 20 | function tokenFallback(address from_, uint256 value_, bytes data_) external { 21 | revert(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /contracts/ownership/NoOwner.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import "./HasNoEther.sol"; 4 | import "./HasNoTokens.sol"; 5 | import "./HasNoContracts.sol"; 6 | 7 | /** 8 | * @title Base contract for contracts that should not own things. 9 | * @author Remco Bloemen 10 | * @dev Solves a class of errors where a contract accidentally becomes owner of Ether, Tokens or 11 | * Owned contracts. See respective base contracts for details. 12 | */ 13 | contract NoOwner is HasNoEther, HasNoTokens, HasNoContracts { 14 | } 15 | -------------------------------------------------------------------------------- /contracts/ownership/Ownable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | /** 5 | * @title Ownable 6 | * @dev The Ownable contract has an owner address, and provides basic authorization control 7 | * functions, this simplifies the implementation of "user permissions". 8 | */ 9 | contract Ownable { 10 | address public owner; 11 | 12 | 13 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 14 | 15 | 16 | /** 17 | * @dev The Ownable constructor sets the original `owner` of the contract to the sender 18 | * account. 19 | */ 20 | function Ownable() public { 21 | owner = msg.sender; 22 | } 23 | 24 | 25 | /** 26 | * @dev Throws if called by any account other than the owner. 27 | */ 28 | modifier onlyOwner() { 29 | require(msg.sender == owner); 30 | _; 31 | } 32 | 33 | 34 | /** 35 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 36 | * @param newOwner The address to transfer ownership to. 37 | */ 38 | function transferOwnership(address newOwner) onlyOwner public { 39 | require(newOwner != address(0)); 40 | OwnershipTransferred(owner, newOwner); 41 | owner = newOwner; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /contracts/payment/PullPayment.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import '../math/SafeMath.sol'; 5 | 6 | 7 | /** 8 | * @title PullPayment 9 | * @dev Base contract supporting async send for pull payments. Inherit from this 10 | * contract and use asyncSend instead of send. 11 | */ 12 | contract PullPayment { 13 | using SafeMath for uint256; 14 | 15 | mapping(address => uint256) public payments; 16 | uint256 public totalPayments; 17 | 18 | /** 19 | * @dev Called by the payer to store the sent amount as credit to be pulled. 20 | * @param dest The destination address of the funds. 21 | * @param amount The amount to transfer. 22 | */ 23 | function asyncSend(address dest, uint256 amount) internal { 24 | payments[dest] = payments[dest].add(amount); 25 | totalPayments = totalPayments.add(amount); 26 | } 27 | 28 | /** 29 | * @dev withdraw accumulated balance, called by payee. 30 | */ 31 | function withdrawPayments() public { 32 | address payee = msg.sender; 33 | uint256 payment = payments[payee]; 34 | 35 | require(payment != 0); 36 | require(this.balance >= payment); 37 | 38 | totalPayments = totalPayments.sub(payment); 39 | payments[payee] = 0; 40 | 41 | assert(payee.send(payment)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/token/BasicToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import './ERC20Basic.sol'; 5 | import '../math/SafeMath.sol'; 6 | 7 | 8 | /** 9 | * @title Basic token 10 | * @dev Basic version of StandardToken, with no allowances. 11 | */ 12 | contract BasicToken is ERC20Basic { 13 | using SafeMath for uint256; 14 | 15 | mapping(address => uint256) balances; 16 | 17 | /** 18 | * @dev transfer token for a specified address 19 | * @param _to The address to transfer to. 20 | * @param _value The amount to be transferred. 21 | */ 22 | function transfer(address _to, uint256 _value) public returns (bool) { 23 | require(_to != address(0)); 24 | require(_value <= balances[msg.sender]); 25 | 26 | // SafeMath.sub will throw if there is not enough balance. 27 | balances[msg.sender] = balances[msg.sender].sub(_value); 28 | balances[_to] = balances[_to].add(_value); 29 | Transfer(msg.sender, _to, _value); 30 | return true; 31 | } 32 | 33 | /** 34 | * @dev Gets the balance of the specified address. 35 | * @param _owner The address to query the the balance of. 36 | * @return An uint256 representing the amount owned by the passed address. 37 | */ 38 | function balanceOf(address _owner) public constant returns (uint256 balance) { 39 | return balances[_owner]; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /contracts/token/BurnableToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.13; 2 | 3 | import './StandardToken.sol'; 4 | 5 | /** 6 | * @title Burnable Token 7 | * @dev Token that can be irreversibly burned (destroyed). 8 | */ 9 | contract BurnableToken is StandardToken { 10 | 11 | event Burn(address indexed burner, uint256 value); 12 | 13 | /** 14 | * @dev Burns a specific amount of tokens. 15 | * @param _value The amount of token to be burned. 16 | */ 17 | function burn(uint256 _value) public { 18 | require(_value > 0); 19 | require(_value <= balances[msg.sender]); 20 | // no need to require value <= totalSupply, since that would imply the 21 | // sender's balance is greater than the totalSupply, which *should* be an assertion failure 22 | 23 | address burner = msg.sender; 24 | balances[burner] = balances[burner].sub(_value); 25 | totalSupply = totalSupply.sub(_value); 26 | Burn(burner, _value); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /contracts/token/ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import './ERC20Basic.sol'; 4 | 5 | /** 6 | * @title ERC20 interface 7 | * @dev see https://github.com/ethereum/EIPs/issues/20 8 | */ 9 | contract ERC20 is ERC20Basic { 10 | function allowance(address owner, address spender) public constant returns (uint256); 11 | function transferFrom(address from, address to, uint256 value) public returns (bool); 12 | function approve(address spender, uint256 value) public returns (bool); 13 | event Approval(address indexed owner, address indexed spender, uint256 value); 14 | } 15 | -------------------------------------------------------------------------------- /contracts/token/ERC20Basic.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | /** 5 | * @title ERC20Basic 6 | * @dev Simpler version of ERC20 interface 7 | * @dev see https://github.com/ethereum/EIPs/issues/179 8 | */ 9 | contract ERC20Basic { 10 | uint256 public totalSupply; 11 | function balanceOf(address who) public constant returns (uint256); 12 | function transfer(address to, uint256 value) public returns (bool); 13 | event Transfer(address indexed from, address indexed to, uint256 value); 14 | } 15 | -------------------------------------------------------------------------------- /contracts/token/MintableToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import './StandardToken.sol'; 5 | import '../ownership/Ownable.sol'; 6 | 7 | 8 | 9 | /** 10 | * @title Mintable token 11 | * @dev Simple ERC20 Token example, with mintable token creation 12 | * @dev Issue: * https://github.com/OpenZeppelin/zeppelin-solidity/issues/120 13 | * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol 14 | */ 15 | 16 | contract MintableToken is StandardToken, Ownable { 17 | event Mint(address indexed to, uint256 amount); 18 | event MintFinished(); 19 | 20 | bool public mintingFinished = false; 21 | 22 | 23 | modifier canMint() { 24 | require(!mintingFinished); 25 | _; 26 | } 27 | 28 | /** 29 | * @dev Function to mint tokens 30 | * @param _to The address that will receive the minted tokens. 31 | * @param _amount The amount of tokens to mint. 32 | * @return A boolean that indicates if the operation was successful. 33 | */ 34 | function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) { 35 | totalSupply = totalSupply.add(_amount); 36 | balances[_to] = balances[_to].add(_amount); 37 | Mint(_to, _amount); 38 | Transfer(address(0), _to, _amount); 39 | return true; 40 | } 41 | 42 | /** 43 | * @dev Function to stop minting new tokens. 44 | * @return True if the operation was successful. 45 | */ 46 | function finishMinting() onlyOwner public returns (bool) { 47 | mintingFinished = true; 48 | MintFinished(); 49 | return true; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /contracts/token/PausableToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import './StandardToken.sol'; 4 | import '../lifecycle/Pausable.sol'; 5 | 6 | /** 7 | * @title Pausable token 8 | * 9 | * @dev StandardToken modified with pausable transfers. 10 | **/ 11 | 12 | contract PausableToken is StandardToken, Pausable { 13 | 14 | function transfer(address _to, uint256 _value) public whenNotPaused returns (bool) { 15 | return super.transfer(_to, _value); 16 | } 17 | 18 | function transferFrom(address _from, address _to, uint256 _value) public whenNotPaused returns (bool) { 19 | return super.transferFrom(_from, _to, _value); 20 | } 21 | 22 | function approve(address _spender, uint256 _value) public whenNotPaused returns (bool) { 23 | return super.approve(_spender, _value); 24 | } 25 | 26 | function increaseApproval(address _spender, uint _addedValue) public whenNotPaused returns (bool success) { 27 | return super.increaseApproval(_spender, _addedValue); 28 | } 29 | 30 | function decreaseApproval(address _spender, uint _subtractedValue) public whenNotPaused returns (bool success) { 31 | return super.decreaseApproval(_spender, _subtractedValue); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contracts/token/SafeERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import './ERC20Basic.sol'; 4 | import './ERC20.sol'; 5 | 6 | /** 7 | * @title SafeERC20 8 | * @dev Wrappers around ERC20 operations that throw on failure. 9 | * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, 10 | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. 11 | */ 12 | library SafeERC20 { 13 | function safeTransfer(ERC20Basic token, address to, uint256 value) internal { 14 | assert(token.transfer(to, value)); 15 | } 16 | 17 | function safeTransferFrom(ERC20 token, address from, address to, uint256 value) internal { 18 | assert(token.transferFrom(from, to, value)); 19 | } 20 | 21 | function safeApprove(ERC20 token, address spender, uint256 value) internal { 22 | assert(token.approve(spender, value)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/token/StandardToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import './BasicToken.sol'; 4 | import './ERC20.sol'; 5 | 6 | /** 7 | * @title Standard ERC20 token 8 | * 9 | * @dev Implementation of the basic standard token. 10 | * @dev https://github.com/ethereum/EIPs/issues/20 11 | * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol 12 | */ 13 | contract StandardToken is ERC20, BasicToken { 14 | 15 | mapping (address => mapping (address => uint256)) internal allowed; 16 | 17 | 18 | /** 19 | * @dev Transfer tokens from one address to another 20 | * @param _from address The address which you want to send tokens from 21 | * @param _to address The address which you want to transfer to 22 | * @param _value uint256 the amount of tokens to be transferred 23 | */ 24 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { 25 | require(_to != address(0)); 26 | require(_value <= balances[_from]); 27 | require(_value <= allowed[_from][msg.sender]); 28 | 29 | balances[_from] = balances[_from].sub(_value); 30 | balances[_to] = balances[_to].add(_value); 31 | allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); 32 | Transfer(_from, _to, _value); 33 | return true; 34 | } 35 | 36 | /** 37 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. 38 | * 39 | * Beware that changing an allowance with this method brings the risk that someone may use both the old 40 | * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this 41 | * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: 42 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 43 | * @param _spender The address which will spend the funds. 44 | * @param _value The amount of tokens to be spent. 45 | */ 46 | function approve(address _spender, uint256 _value) public returns (bool) { 47 | allowed[msg.sender][_spender] = _value; 48 | Approval(msg.sender, _spender, _value); 49 | return true; 50 | } 51 | 52 | /** 53 | * @dev Function to check the amount of tokens that an owner allowed to a spender. 54 | * @param _owner address The address which owns the funds. 55 | * @param _spender address The address which will spend the funds. 56 | * @return A uint256 specifying the amount of tokens still available for the spender. 57 | */ 58 | function allowance(address _owner, address _spender) public constant returns (uint256 remaining) { 59 | return allowed[_owner][_spender]; 60 | } 61 | 62 | /** 63 | * approve should be called when allowed[_spender] == 0. To increment 64 | * allowed value is better to use this function to avoid 2 calls (and wait until 65 | * the first transaction is mined) 66 | * From MonolithDAO Token.sol 67 | */ 68 | function increaseApproval (address _spender, uint _addedValue) public returns (bool success) { 69 | allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue); 70 | Approval(msg.sender, _spender, allowed[msg.sender][_spender]); 71 | return true; 72 | } 73 | 74 | function decreaseApproval (address _spender, uint _subtractedValue) public returns (bool success) { 75 | uint oldValue = allowed[msg.sender][_spender]; 76 | if (_subtractedValue > oldValue) { 77 | allowed[msg.sender][_spender] = 0; 78 | } else { 79 | allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); 80 | } 81 | Approval(msg.sender, _spender, allowed[msg.sender][_spender]); 82 | return true; 83 | } 84 | } -------------------------------------------------------------------------------- /contracts/token/TokenTimelock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import './ERC20Basic.sol'; 5 | import "../token/SafeERC20.sol"; 6 | 7 | /** 8 | * @title TokenTimelock 9 | * @dev TokenTimelock is a token holder contract that will allow a 10 | * beneficiary to extract the tokens after a given release time 11 | */ 12 | contract TokenTimelock { 13 | using SafeERC20 for ERC20Basic; 14 | 15 | // ERC20 basic token contract being held 16 | ERC20Basic public token; 17 | 18 | // beneficiary of tokens after they are released 19 | address public beneficiary; 20 | 21 | // timestamp when token release is enabled 22 | uint64 public releaseTime; 23 | 24 | function TokenTimelock(ERC20Basic _token, address _beneficiary, uint64 _releaseTime) { 25 | require(_releaseTime > now); 26 | token = _token; 27 | beneficiary = _beneficiary; 28 | releaseTime = _releaseTime; 29 | } 30 | 31 | /** 32 | * @notice Transfers tokens held by timelock to beneficiary. 33 | * Deprecated: please use TokenTimelock#release instead. 34 | */ 35 | function claim() public { 36 | require(msg.sender == beneficiary); 37 | release(); 38 | } 39 | 40 | /** 41 | * @notice Transfers tokens held by timelock to beneficiary. 42 | */ 43 | function release() public { 44 | require(now >= releaseTime); 45 | 46 | uint256 amount = token.balanceOf(this); 47 | require(amount > 0); 48 | 49 | token.safeTransfer(beneficiary, amount); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /contracts/token/TokenVesting.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import './ERC20Basic.sol'; 4 | import './SafeERC20.sol'; 5 | import '../ownership/Ownable.sol'; 6 | import '../math/Math.sol'; 7 | import '../math/SafeMath.sol'; 8 | 9 | /** 10 | * @title TokenVesting 11 | * @dev A token holder contract that can release its token balance gradually like a 12 | * typical vesting scheme, with a cliff and vesting period. Optionally revocable by the 13 | * owner. 14 | */ 15 | contract TokenVesting is Ownable { 16 | using SafeMath for uint256; 17 | using SafeERC20 for ERC20Basic; 18 | 19 | event Released(uint256 amount); 20 | event Revoked(); 21 | 22 | // beneficiary of tokens after they are released 23 | address public beneficiary; 24 | 25 | uint256 public cliff; 26 | uint256 public start; 27 | uint256 public duration; 28 | 29 | bool public revocable; 30 | 31 | mapping (address => uint256) public released; 32 | mapping (address => bool) public revoked; 33 | 34 | /** 35 | * @dev Creates a vesting contract that vests its balance of any ERC20 token to the 36 | * _beneficiary, gradually in a linear fashion until _start + _duration. By then all 37 | * of the balance will have vested. 38 | * @param _beneficiary address of the beneficiary to whom vested tokens are transferred 39 | * @param _cliff duration in seconds of the cliff in which tokens will begin to vest 40 | * @param _duration duration in seconds of the period in which the tokens will vest 41 | * @param _revocable whether the vesting is revocable or not 42 | */ 43 | function TokenVesting(address _beneficiary, uint256 _start, uint256 _cliff, uint256 _duration, bool _revocable) { 44 | require(_beneficiary != address(0)); 45 | require(_cliff <= _duration); 46 | 47 | beneficiary = _beneficiary; 48 | revocable = _revocable; 49 | duration = _duration; 50 | cliff = _start.add(_cliff); 51 | start = _start; 52 | } 53 | 54 | /** 55 | * @notice Transfers vested tokens to beneficiary. 56 | * @param token ERC20 token which is being vested 57 | */ 58 | function release(ERC20Basic token) public { 59 | uint256 unreleased = releasableAmount(token); 60 | 61 | require(unreleased > 0); 62 | 63 | released[token] = released[token].add(unreleased); 64 | 65 | token.safeTransfer(beneficiary, unreleased); 66 | 67 | Released(unreleased); 68 | } 69 | 70 | /** 71 | * @notice Allows the owner to revoke the vesting. Tokens already vested 72 | * remain in the contract, the rest are returned to the owner. 73 | * @param token ERC20 token which is being vested 74 | */ 75 | function revoke(ERC20Basic token) public onlyOwner { 76 | require(revocable); 77 | require(!revoked[token]); 78 | 79 | uint256 balance = token.balanceOf(this); 80 | 81 | uint256 unreleased = releasableAmount(token); 82 | uint256 refund = balance.sub(unreleased); 83 | 84 | revoked[token] = true; 85 | 86 | token.safeTransfer(owner, refund); 87 | 88 | Revoked(); 89 | } 90 | 91 | /** 92 | * @dev Calculates the amount that has already vested but hasn't been released yet. 93 | * @param token ERC20 token which is being vested 94 | */ 95 | function releasableAmount(ERC20Basic token) public constant returns (uint256) { 96 | return vestedAmount(token).sub(released[token]); 97 | } 98 | 99 | /** 100 | * @dev Calculates the amount that has already vested. 101 | * @param token ERC20 token which is being vested 102 | */ 103 | function vestedAmount(ERC20Basic token) public constant returns (uint256) { 104 | uint256 currentBalance = token.balanceOf(this); 105 | uint256 totalBalance = currentBalance.add(released[token]); 106 | 107 | if (now < cliff) { 108 | return 0; 109 | } else if (now >= start.add(duration) || revoked[token]) { 110 | return totalBalance; 111 | } else { 112 | return totalBalance.mul(now.sub(start)).div(duration); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = zeppelin-solidity 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/source/basictoken.rst: -------------------------------------------------------------------------------- 1 | BasicToken 2 | ============================================= 3 | 4 | Simpler version of StandardToken, with no allowances 5 | 6 | balanceOf(address _owner) constant returns (uint balance) 7 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 8 | Returns the token balance of the passed address. 9 | 10 | function transfer(address _to, uint _value) returns (bool success) 11 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 12 | Transfers tokens from sender's account. Amount must not be greater than sender's balance. 13 | -------------------------------------------------------------------------------- /docs/source/bounty.rst: -------------------------------------------------------------------------------- 1 | Bounty 2 | ============================================= 3 | 4 | To create a bounty for your contract, inherit from the base `Bounty` contract and provide an implementation for ```deployContract()``` returning the new contract address.:: 5 | 6 | import {Bounty, Target} from "./zeppelin/Bounty.sol"; 7 | import "./YourContract.sol"; 8 | 9 | contract YourBounty is Bounty { 10 | function deployContract() internal returns(address) { 11 | return new YourContract() 12 | } 13 | } 14 | 15 | 16 | Next, implement invariant logic into your smart contract. 17 | Your main contract should inherit from the Target class and implement the checkInvariant method. This is a function that should check everything your contract assumes to be true all the time. If this function returns false, it means your contract was broken in some way and is in an inconsistent state. This is what security researchers will try to acomplish when trying to get the bounty. 18 | 19 | At contracts/YourContract.sol:: 20 | 21 | 22 | import {Bounty, Target} from "./zeppelin/Bounty.sol"; 23 | contract YourContract is Target { 24 | function checkInvariant() returns(bool) { 25 | // Implement your logic to make sure that none of the invariants are broken. 26 | } 27 | } 28 | 29 | Next, deploy your bounty contract along with your main contract to the network. 30 | 31 | At ```migrations/2_deploy_contracts.js```:: 32 | 33 | module.exports = function(deployer) { 34 | deployer.deploy(YourContract); 35 | deployer.deploy(YourBounty); 36 | }; 37 | 38 | Next, add a reward to the bounty contract 39 | 40 | After deploying the contract, send reward funds into the bounty contract. 41 | 42 | From ```truffle console```:: 43 | 44 | bounty = YourBounty.deployed(); 45 | address = 0xb9f68f96cde3b895cc9f6b14b856081b41cb96f1; // your account address 46 | reward = 5; // reward to pay to a researcher who breaks your contract 47 | 48 | web3.eth.sendTransaction({ 49 | from: address, 50 | to: bounty.address, 51 | value: web3.toWei(reward, "ether") 52 | }) 53 | 54 | If researchers break the contract, they can claim their reward. 55 | 56 | For each researcher who wants to hack the contract and claims the reward, refer to our `Test `_ for the detail. 57 | 58 | Finally, if you manage to protect your contract from security researchers, you can reclaim the bounty funds. To end the bounty, destroy the contract so that all the rewards go back to the owner.:: 59 | 60 | bounty.destroy(); 61 | -------------------------------------------------------------------------------- /docs/source/claimable.rst: -------------------------------------------------------------------------------- 1 | Claimable 2 | ============================================= 3 | 4 | Extension for the Ownable contract, where the ownership needs to be claimed 5 | 6 | transfer(address newOwner) onlyOwner 7 | """""""""""""""""""""""""""""""""""""" 8 | 9 | Sets the passed address as the pending owner. 10 | 11 | modifier onlyPendingOwner 12 | """""""""""""""""""""""""""""""""""""" 13 | 14 | Function only runs if called by pending owner. 15 | 16 | claimOwnership( ) onlyPendingOwner 17 | """""""""""""""""""""""""""""""""""""" 18 | 19 | Completes transfer of ownership by setting pending owner as the new owner. 20 | 21 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # zeppelin-solidity documentation build configuration file, created by 4 | # sphinx-quickstart on Tue Dec 13 11:35:05 2016. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | # If extensions (or modules to document with autodoc) are in another directory, 16 | # add these directories to sys.path here. If the directory is relative to the 17 | # documentation root, use os.path.abspath to make it absolute, like shown here. 18 | # 19 | # import os 20 | # import sys 21 | # sys.path.insert(0, os.path.abspath('.')) 22 | 23 | 24 | # -- General configuration ------------------------------------------------ 25 | 26 | # If your documentation needs a minimal Sphinx version, state it here. 27 | # 28 | # needs_sphinx = '1.0' 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [] 34 | 35 | # Add any paths that contain templates here, relative to this directory. 36 | templates_path = ['_templates'] 37 | 38 | # The suffix(es) of source filenames. 39 | # You can specify multiple suffix as a list of string: 40 | # 41 | # source_suffix = ['.rst', '.md'] 42 | source_suffix = '.rst' 43 | 44 | # The master toctree document. 45 | master_doc = 'index' 46 | 47 | # General information about the project. 48 | project = u'zeppelin-solidity' 49 | copyright = u'2016, Smart Contract Solutions, Inc' 50 | author = u'Smart Contract Solutions, Inc' 51 | 52 | # The version info for the project you're documenting, acts as replacement for 53 | # |version| and |release|, also used in various other places throughout the 54 | # built documents. 55 | # 56 | # The short X.Y version. 57 | version = u'1.0.0' 58 | # The full version, including alpha/beta/rc tags. 59 | release = u'1.0.0' 60 | 61 | # The language for content autogenerated by Sphinx. Refer to documentation 62 | # for a list of supported languages. 63 | # 64 | # This is also used if you do content translation via gettext catalogs. 65 | # Usually you set "language" from the command line for these cases. 66 | language = None 67 | 68 | # List of patterns, relative to source directory, that match files and 69 | # directories to ignore when looking for source files. 70 | # This patterns also effect to html_static_path and html_extra_path 71 | exclude_patterns = [] 72 | 73 | # The name of the Pygments (syntax highlighting) style to use. 74 | pygments_style = 'sphinx' 75 | 76 | # If true, `todo` and `todoList` produce output, else they produce nothing. 77 | todo_include_todos = False 78 | 79 | 80 | # -- Options for HTML output ---------------------------------------------- 81 | 82 | # The theme to use for HTML and HTML Help pages. See the documentation for 83 | # a list of builtin themes. 84 | # 85 | import sphinx_rtd_theme 86 | 87 | html_theme = "sphinx_rtd_theme" 88 | 89 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 90 | 91 | # Theme options are theme-specific and customize the look and feel of a theme 92 | # further. For a list of options available for each theme, see the 93 | # documentation. 94 | # 95 | # html_theme_options = {} 96 | 97 | # Add any paths that contain custom static files (such as style sheets) here, 98 | # relative to this directory. They are copied after the builtin static files, 99 | # so a file named "default.css" will overwrite the builtin "default.css". 100 | html_static_path = ['_static'] 101 | 102 | 103 | # -- Options for HTMLHelp output ------------------------------------------ 104 | 105 | # Output file base name for HTML help builder. 106 | htmlhelp_basename = 'zeppelin-soliditydoc' 107 | 108 | 109 | # -- Options for LaTeX output --------------------------------------------- 110 | 111 | latex_elements = { 112 | # The paper size ('letterpaper' or 'a4paper'). 113 | # 114 | # 'papersize': 'letterpaper', 115 | 116 | # The font size ('10pt', '11pt' or '12pt'). 117 | # 118 | # 'pointsize': '10pt', 119 | 120 | # Additional stuff for the LaTeX preamble. 121 | # 122 | # 'preamble': '', 123 | 124 | # Latex figure (float) alignment 125 | # 126 | # 'figure_align': 'htbp', 127 | } 128 | 129 | # Grouping the document tree into LaTeX files. List of tuples 130 | # (source start file, target name, title, 131 | # author, documentclass [howto, manual, or own class]). 132 | latex_documents = [ 133 | (master_doc, 'zeppelin-solidity.tex', u'zeppelin-solidity Documentation', 134 | u'Zeppelin', 'manual'), 135 | ] 136 | 137 | 138 | # -- Options for manual page output --------------------------------------- 139 | 140 | # One entry per manual page. List of tuples 141 | # (source start file, name, description, authors, manual section). 142 | man_pages = [ 143 | (master_doc, 'zeppelin-solidity', u'zeppelin-solidity Documentation', 144 | [author], 1) 145 | ] 146 | 147 | 148 | # -- Options for Texinfo output ------------------------------------------- 149 | 150 | # Grouping the document tree into Texinfo files. List of tuples 151 | # (source start file, target name, title, author, 152 | # dir menu entry, description, category) 153 | texinfo_documents = [ 154 | (master_doc, 'zeppelin-solidity', u'zeppelin-solidity Documentation', 155 | author, 'zeppelin-solidity', 'One line description of project.', 156 | 'Miscellaneous'), 157 | ] 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /docs/source/contract-security-patterns.rst: -------------------------------------------------------------------------------- 1 | Common Contract Security Patterns 2 | ============================================= 3 | 4 | Zeppelin smart contracts are developed using industry standard contract security patterns and best practices. To learn more, please see `Onward with Ethereum Smart Contract Security `_. 5 | -------------------------------------------------------------------------------- /docs/source/developer-resources.rst: -------------------------------------------------------------------------------- 1 | Developer Resources 2 | ============================================= 3 | 4 | Building a distributed application, protocol or organization with Zeppelin? 5 | 6 | Ask for help and follow progress at: https://zeppelin-slackin.herokuapp.com/ 7 | 8 | Interested in contributing to Zeppelin? 9 | 10 | * Framework proposal and roadmap: https://medium.com/zeppelin-blog/zeppelin-framework-proposal-and-development-roadmap-fdfa9a3a32ab#.iain47pak 11 | * Issue tracker: https://github.com/OpenZeppelin/zeppelin-solidity/issues 12 | * Contribution guidelines: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/CONTRIBUTING.md 13 | -------------------------------------------------------------------------------- /docs/source/ecrecovery.rst: -------------------------------------------------------------------------------- 1 | ECReovery 2 | ============================================= 3 | 4 | Returns the signer of the the hash using the signature divided in v, r, and s values. 5 | 6 | recover(bytes32 hash, bytes sig) internal returns (address) 7 | """"""""""""""""""""""""""""""""""""""""""""""""" 8 | 9 | Returns the signer of the the hash using the signature that provides the web3.eth.sign() method. 10 | -------------------------------------------------------------------------------- /docs/source/getting-started.rst: -------------------------------------------------------------------------------- 1 | Getting Started 2 | ============================================= 3 | 4 | Zeppelin integrates with `Truffle `_, an Ethereum development environment. Please install Truffle and initialize your project with ``truffle init``:: 5 | 6 | npm install -g truffle 7 | mkdir myproject && cd myproject 8 | truffle init 9 | 10 | To install the Zeppelin library, run:: 11 | 12 | npm i zeppelin-solidity 13 | 14 | After that, you'll get all the library's contracts in the contracts/zeppelin folder. You can use the contracts in the library like so:: 15 | 16 | import "zeppelin-solidity/contracts/Ownable.sol"; 17 | 18 | contract MyContract is Ownable { 19 | ... 20 | } 21 | 22 | .. epigraph:: 23 | 24 | NOTE: The current distribution channel is npm, which is not ideal. `We're looking into providing a better tool for code distribution `_ , and ideas are welcome. 25 | 26 | Truffle Beta Support 27 | """""""""""""""""""""""" 28 | We also support Truffle Beta npm integration. If you're using Truffle Beta, the contracts in ``node_modules`` will be enough, so feel free to delete the copies at your ``contracts`` folder. If you're using Truffle Beta, you can use Zeppelin contracts like so:: 29 | 30 | import "zeppelin-solidity/contracts/Ownable.sol"; 31 | 32 | contract MyContract is Ownable { 33 | ... 34 | } 35 | 36 | For more info see the `Truffle Beta package management tutorial `_. 37 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. zeppelin-solidity documentation master file, created by 2 | sphinx-quickstart on Tue Dec 13 11:35:05 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Zeppelin-Solidity 7 | ============================================= 8 | 9 | Zeppelin is a library for writing secure Smart Contracts on Ethereum. 10 | 11 | With Zeppelin, you can build distributed applications, protocols and organizations: 12 | 13 | * using :doc:`contract-security-patterns` 14 | * in the `Solidity language `_. 15 | 16 | The code is open-source, and `available on github `_. 17 | 18 | .. toctree:: 19 | :maxdepth: 2 20 | 21 | getting-started 22 | 23 | 24 | .. toctree:: 25 | :maxdepth: 2 26 | :caption: Smart Contracts 27 | 28 | ownable 29 | Pausable 30 | destructible 31 | claimable 32 | migrations 33 | safemath 34 | limitbalance 35 | pullpayment 36 | standardtoken 37 | basictoken 38 | crowdsaletoken 39 | bounty 40 | 41 | .. toctree:: 42 | :maxdepth: 2 43 | :caption: Developer Resources 44 | 45 | contract-security-patterns 46 | developer-resources 47 | license 48 | -------------------------------------------------------------------------------- /docs/source/killable.rst: -------------------------------------------------------------------------------- 1 | Destructible 2 | ============================================= 3 | 4 | Base contract that can be destroyed by owner. 5 | 6 | Inherits from contract Ownable. 7 | 8 | destroy( ) onlyOwner 9 | """"""""""""""""""" 10 | 11 | Destroys the contract and sends funds back to the owner. 12 | 13 | destroyAndSend(address _recipient) onlyOwner 14 | """"""""""""""""""" 15 | 16 | Destroys the contract and sends funds back to the _recepient. 17 | -------------------------------------------------------------------------------- /docs/source/license.rst: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ============================================= 3 | 4 | Copyright (c) 2016 Smart Contract Solutions, Inc. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /docs/source/limitbalance.rst: -------------------------------------------------------------------------------- 1 | LimitBalance 2 | ============================================= 3 | 4 | Base contract that provides mechanism for limiting the amount of funds a contract can hold. 5 | 6 | LimitBalance(unit _limit) 7 | """""""""""""""""""""""""""" 8 | Constructor takes an unsigned integer and sets it as the limit of funds this contract can hold. 9 | 10 | modifier limitedPayable() 11 | """""""""""""""""""""""""""" 12 | Throws an error if this contract's balance is already above the limit. 13 | -------------------------------------------------------------------------------- /docs/source/math.rst: -------------------------------------------------------------------------------- 1 | Math 2 | ============================================= 3 | 4 | Provides assorted low-level math operations. 5 | 6 | max64(uint64 a, uint64 b) internal constant returns (uint64) 7 | """"""""""""""""""""""""""""""""""""""""""""""""" 8 | 9 | Returns the largest of two uint64 numbers. 10 | 11 | min64(uint64 a, uint64 b) internal constant returns (uint64) 12 | """"""""""""""""""""""""""""""""""""""""""""""""" 13 | 14 | Returns the smallest of two uint64 numbers. 15 | 16 | max64(uint256 a, uint256 b) internal constant returns (uint256) 17 | """"""""""""""""""""""""""""""""""""""""""""""""" 18 | 19 | Returns the largest of two uint256 numbers. 20 | 21 | min64(uint256 a, uint256 b) internal constant returns (uint256) 22 | """"""""""""""""""""""""""""""""""""""""""""""""" 23 | 24 | Returns the smallest of two uint256 numbers. 25 | -------------------------------------------------------------------------------- /docs/source/merkleproof.rst: -------------------------------------------------------------------------------- 1 | MerkleProof 2 | ============================================= 3 | 4 | Merkle proof verification for leaves of a Merkle tree. 5 | 6 | verifyProof(bytes _proof, bytes32 _root, bytes32 _leaf) internal constant returns (bool) 7 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 8 | 9 | Verifies a Merkle proof proving the existence of a leaf in a Merkle tree. Assumes that each pair of leaves and each pair of pre-images is sorted. 10 | -------------------------------------------------------------------------------- /docs/source/migrations.rst: -------------------------------------------------------------------------------- 1 | Migrations 2 | ============================================= 3 | 4 | Base contract that allows for a new instance of itself to be created at a different address. 5 | 6 | Inherits from contract Ownable. 7 | 8 | upgrade(address new_address) onlyOwner 9 | """""""""""""""""""""""""""""""""""""""" 10 | 11 | Creates a new instance of the contract at the passed address. 12 | 13 | setCompleted(uint completed) onlyOwner** 14 | """""""""""""""""""""""""""""""""""""""" 15 | 16 | Sets the last time that a migration was completed. 17 | -------------------------------------------------------------------------------- /docs/source/ownable.rst: -------------------------------------------------------------------------------- 1 | Ownable 2 | ============================================= 3 | 4 | Base contract with an owner. 5 | 6 | Ownable( ) 7 | """""""""""""""""""""""""""""""""""""" 8 | Sets the address of the creator of the contract as the owner. 9 | 10 | modifier onlyOwner( ) 11 | """""""""""""""""""""""""""""""""""""" 12 | Prevents function from running if it is called by anyone other than the owner. 13 | 14 | transferOwnership(address newOwner) onlyOwner 15 | """""""""""""""""""""""""""""""""""""" 16 | Transfers ownership of the contract to the passed address. 17 | -------------------------------------------------------------------------------- /docs/source/pausable.rst: -------------------------------------------------------------------------------- 1 | Pausable 2 | ============================================= 3 | 4 | Base contract that provides a pause mechanism. 5 | 6 | Inherits from contract Ownable. 7 | 8 | pause() onlyOwner whenNotPaused returns (bool) 9 | """"""""""""""""""""""""""""""""""""" 10 | 11 | Triggers pause mechanism on the contract. After this function is called (by the owner of the contract), any function with modifier whenNotPaused will not run. 12 | 13 | 14 | modifier whenNotPaused() 15 | """"""""""""""""""""""""""""""""""""" 16 | 17 | Prevents function from running if pause mechanism is activated. 18 | 19 | modifier whenPaused() 20 | """"""""""""""""""""""""""""""""""""" 21 | 22 | Only runs if pause mechanism is activated. 23 | 24 | unpause() onlyOwner whenPaused returns (bool) 25 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 26 | 27 | Deactivates the pause mechanism. 28 | -------------------------------------------------------------------------------- /docs/source/pullpayment.rst: -------------------------------------------------------------------------------- 1 | PullPayment 2 | ============================================= 3 | 4 | Base contract supporting async send for pull payments. Inherit from this contract and use asyncSend instead of send. 5 | 6 | asyncSend(address dest, uint amount) internal 7 | """"""""""""""""""""""""""""""""""""""""""""""" 8 | Adds sent amount to available balance that payee can pull from this contract, called by payer. 9 | 10 | withdrawPayments( ) 11 | """"""""""""""""""""""""""""""""""""""""""""""" 12 | Sends designated balance to payee calling the contract. Throws error if designated balance is 0, if contract does not hold enough funds to pay the payee, or if the send transaction is not successful. 13 | -------------------------------------------------------------------------------- /docs/source/safemath.rst: -------------------------------------------------------------------------------- 1 | SafeMath 2 | ============================================= 3 | 4 | Provides functions of mathematical operations with safety checks. 5 | 6 | assert(bool assertion) internal 7 | """"""""""""""""""""""""""""""""""""""""""""""""" 8 | 9 | Throws an error if the passed result is false. Used in this contract by checking mathematical expressions. 10 | 11 | mul(uint256 a, uint256 b) internal returns (uint256) 12 | """"""""""""""""""""""""""""""""""""""""""""""""" 13 | 14 | Multiplies two unsigned integers. Asserts that dividing the product by the non-zero multiplicand results in the multiplier. 15 | 16 | sub(uint256 a, uint256 b) internal returns (uint256) 17 | """"""""""""""""""""""""""""""""""""""""""""""""" 18 | 19 | Checks that b is not greater than a before subtracting. 20 | 21 | add(uint256 a, uint256 b) internal returns (uint256) 22 | """"""""""""""""""""""""""""""""""""""""""""""""" 23 | 24 | Checks that the result is greater than both a and b. 25 | -------------------------------------------------------------------------------- /docs/source/standardtoken.rst: -------------------------------------------------------------------------------- 1 | StandardToken 2 | ============================================= 3 | 4 | Based on code by FirstBlood: `Link FirstBloodToken.sol `_ 5 | 6 | Inherits from contract SafeMath. Implementation of abstract contract ERC20 (see https://github.com/ethereum/EIPs/issues/20) 7 | 8 | approve(address _spender, uint _value) returns (bool success) 9 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 10 | Sets the amount of the sender's token balance that the passed address is approved to use. 11 | 12 | allowance(address _owner, address _spender) constant returns (uint remaining) 13 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 14 | Returns the approved amount of the owner's balance that the spender can use. 15 | 16 | balanceOf(address _owner) constant returns (uint balance) 17 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 18 | Returns the token balance of the passed address. 19 | 20 | transferFrom(address _from, address _to, uint _value) returns (bool success) 21 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 22 | Transfers tokens from an account that the sender is approved to transfer from. Amount must not be greater than the approved amount or the account's balance. 23 | 24 | function transfer(address _to, uint _value) returns (bool success) 25 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 26 | Transfers tokens from sender's account. Amount must not be greater than sender's balance. 27 | -------------------------------------------------------------------------------- /ethpm.json: -------------------------------------------------------------------------------- 1 | { 2 | "package_name": "zeppelin", 3 | "version": "1.3.0", 4 | "description": "Secure Smart Contract library for Solidity", 5 | "authors": [ 6 | "Manuel Araoz " 7 | ], 8 | "keywords": [ 9 | "solidity", 10 | "ethereum", 11 | "smart", 12 | "contracts", 13 | "security", 14 | "zeppelin" 15 | ], 16 | "license": "MIT" 17 | } 18 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | //var Ownable = artifacts.require("ownership/Ownable.sol"); 2 | 3 | module.exports = function(deployer) { 4 | //deployer.deploy(Ownable); 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zeppelin-solidity", 3 | "version": "1.3.0", 4 | "description": "Secure Smart Contract library for Solidity", 5 | "scripts": { 6 | "test": "scripts/test.sh", 7 | "console": "truffle console", 8 | "coverage": "scripts/coverage.sh" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/OpenZeppelin/zeppelin-solidity.git" 13 | }, 14 | "keywords": [ 15 | "solidity", 16 | "ethereum", 17 | "smart", 18 | "contracts", 19 | "security", 20 | "zeppelin" 21 | ], 22 | "author": "Manuel Araoz ", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/OpenZeppelin/zeppelin-solidity/issues" 26 | }, 27 | "homepage": "https://github.com/OpenZeppelin/zeppelin-solidity", 28 | "devDependencies": { 29 | "babel-polyfill": "^6.23.0", 30 | "babel-preset-es2015": "^6.18.0", 31 | "babel-preset-stage-2": "^6.18.0", 32 | "babel-preset-stage-3": "^6.17.0", 33 | "babel-register": "^6.23.0", 34 | "chai": "^4.0.2", 35 | "chai-as-promised": "^7.0.0", 36 | "chai-bignumber": "^2.0.0", 37 | "coveralls": "^2.13.1", 38 | "ethereumjs-util": "^5.1.2", 39 | "ethereumjs-testrpc": "^4.1.1", 40 | "mocha-lcov-reporter": "^1.3.0", 41 | "solidity-coverage": "^0.2.2", 42 | "truffle": "^3.4.6", 43 | "truffle-hdwallet-provider": "0.0.3" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /scripts/coverage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SOLIDITY_COVERAGE=true scripts/test.sh 4 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Exit script as soon as a command fails. 4 | set -o errexit 5 | 6 | # Executes cleanup function at script exit. 7 | trap cleanup EXIT 8 | 9 | cleanup() { 10 | # Kill the testrpc instance that we started (if we started one and if it's still running). 11 | if [ -n "$testrpc_pid" ] && ps -p $testrpc_pid > /dev/null; then 12 | kill -9 $testrpc_pid 13 | fi 14 | } 15 | 16 | if [ "$SOLIDITY_COVERAGE" = true ]; then 17 | testrpc_port=8555 18 | else 19 | testrpc_port=8545 20 | fi 21 | 22 | testrpc_running() { 23 | nc -z localhost "$testrpc_port" 24 | } 25 | 26 | start_testrpc() { 27 | # We define 10 accounts with balance 1M ether, needed for high-value tests. 28 | local accounts=( 29 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501200,1000000000000000000000000" 30 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501201,1000000000000000000000000" 31 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501202,1000000000000000000000000" 32 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501203,1000000000000000000000000" 33 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501204,1000000000000000000000000" 34 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501205,1000000000000000000000000" 35 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501206,1000000000000000000000000" 36 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501207,1000000000000000000000000" 37 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501208,1000000000000000000000000" 38 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501209,1000000000000000000000000" 39 | ) 40 | 41 | if [ "$SOLIDITY_COVERAGE" = true ]; then 42 | node_modules/.bin/testrpc-sc --gasLimit 0xfffffffffff --port "$testrpc_port" "${accounts[@]}" > /dev/null & 43 | else 44 | node_modules/.bin/testrpc "${accounts[@]}" > /dev/null & 45 | fi 46 | 47 | testrpc_pid=$! 48 | } 49 | 50 | if testrpc_running; then 51 | echo "Using existing testrpc instance" 52 | else 53 | echo "Starting our own testrpc instance" 54 | start_testrpc 55 | fi 56 | 57 | if [ "$SOLIDITY_COVERAGE" = true ]; then 58 | node_modules/.bin/solidity-coverage 59 | 60 | if [ "$CONTINUOUS_INTEGRATION" = true ]; then 61 | cat coverage/lcov.info | node_modules/.bin/coveralls 62 | fi 63 | else 64 | node_modules/.bin/truffle test "$@" 65 | fi 66 | -------------------------------------------------------------------------------- /test/BasicToken.js: -------------------------------------------------------------------------------- 1 | const assertJump = require('./helpers/assertJump'); 2 | 3 | var BasicTokenMock = artifacts.require("./helpers/BasicTokenMock.sol"); 4 | 5 | contract('BasicToken', function(accounts) { 6 | 7 | it("should return the correct totalSupply after construction", async function() { 8 | let token = await BasicTokenMock.new(accounts[0], 100); 9 | let totalSupply = await token.totalSupply(); 10 | 11 | assert.equal(totalSupply, 100); 12 | }) 13 | 14 | it("should return correct balances after transfer", async function(){ 15 | let token = await BasicTokenMock.new(accounts[0], 100); 16 | let transfer = await token.transfer(accounts[1], 100); 17 | 18 | let firstAccountBalance = await token.balanceOf(accounts[0]); 19 | assert.equal(firstAccountBalance, 0); 20 | 21 | let secondAccountBalance = await token.balanceOf(accounts[1]); 22 | assert.equal(secondAccountBalance, 100); 23 | }); 24 | 25 | it('should throw an error when trying to transfer more than balance', async function() { 26 | let token = await BasicTokenMock.new(accounts[0], 100); 27 | try { 28 | let transfer = await token.transfer(accounts[1], 101); 29 | assert.fail('should have thrown before'); 30 | } catch(error) { 31 | assertJump(error); 32 | } 33 | }); 34 | 35 | it('should throw an error when trying to transfer to 0x0', async function() { 36 | let token = await BasicTokenMock.new(accounts[0], 100); 37 | try { 38 | let transfer = await token.transfer(0x0, 100); 39 | assert.fail('should have thrown before'); 40 | } catch(error) { 41 | assertJump(error); 42 | } 43 | }); 44 | 45 | }); 46 | -------------------------------------------------------------------------------- /test/Bounty.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let sendReward = function(sender, receiver, value){ 4 | web3.eth.sendTransaction({ 5 | from:sender, 6 | to:receiver, 7 | value: value 8 | }); 9 | }; 10 | var SecureTargetBounty = artifacts.require('helpers/SecureTargetBounty.sol'); 11 | var InsecureTargetBounty = artifacts.require('helpers/InsecureTargetBounty.sol'); 12 | 13 | function awaitEvent(event, handler) { 14 | return new Promise((resolve, reject) => { 15 | function wrappedHandler(...args) { 16 | Promise.resolve(handler(...args)).then(resolve).catch(reject); 17 | } 18 | 19 | event.watch(wrappedHandler); 20 | }); 21 | } 22 | 23 | contract('Bounty', function(accounts) { 24 | 25 | it('sets reward', async function() { 26 | let owner = accounts[0]; 27 | let reward = web3.toWei(1, 'ether'); 28 | let bounty = await SecureTargetBounty.new(); 29 | sendReward(owner, bounty.address, reward); 30 | 31 | assert.equal(reward, web3.eth.getBalance(bounty.address).toNumber()); 32 | }); 33 | 34 | it('empties itself when destroyed', async function(){ 35 | let owner = accounts[0]; 36 | let reward = web3.toWei(1, 'ether'); 37 | let bounty = await SecureTargetBounty.new(); 38 | sendReward(owner, bounty.address, reward); 39 | 40 | assert.equal(reward, web3.eth.getBalance(bounty.address).toNumber()); 41 | 42 | await bounty.destroy(); 43 | assert.equal(0, web3.eth.getBalance(bounty.address).toNumber()); 44 | }); 45 | 46 | describe('Against secure contract', function(){ 47 | 48 | it('cannot claim reward', async function(){ 49 | let owner = accounts[0]; 50 | let researcher = accounts[1]; 51 | let reward = web3.toWei(1, 'ether'); 52 | let bounty = await SecureTargetBounty.new(); 53 | let event = bounty.TargetCreated({}); 54 | 55 | let watcher = async function(err, result) { 56 | event.stopWatching(); 57 | if (err) { throw err; } 58 | 59 | var targetAddress = result.args.createdAddress; 60 | sendReward(owner, bounty.address, reward); 61 | 62 | assert.equal(reward, 63 | web3.eth.getBalance(bounty.address).toNumber()); 64 | 65 | try { 66 | await bounty.claim(targetAddress, {from:researcher}); 67 | assert.isTrue(false); // should never reach here 68 | } catch(error) { 69 | let reClaimedBounty = await bounty.claimed.call(); 70 | assert.isFalse(reClaimedBounty); 71 | 72 | } 73 | try { 74 | await bounty.withdrawPayments({from:researcher}); 75 | assert.isTrue(false); // should never reach here 76 | } catch (err) { 77 | assert.equal(reward, 78 | web3.eth.getBalance(bounty.address).toNumber()); 79 | } 80 | }; 81 | bounty.createTarget({from:researcher}); 82 | await awaitEvent(event, watcher); 83 | }); 84 | }); 85 | 86 | describe('Against broken contract', function(){ 87 | it('claims reward', async function() { 88 | let owner = accounts[0]; 89 | let researcher = accounts[1]; 90 | let reward = web3.toWei(1, 'ether'); 91 | let bounty = await InsecureTargetBounty.new(); 92 | let event = bounty.TargetCreated({}); 93 | 94 | let watcher = async function(err, result) { 95 | event.stopWatching(); 96 | if (err) { throw err; } 97 | let targetAddress = result.args.createdAddress; 98 | sendReward(owner, bounty.address, reward); 99 | 100 | assert.equal(reward, web3.eth.getBalance(bounty.address).toNumber()); 101 | 102 | await bounty.claim(targetAddress, {from:researcher}); 103 | let claim = await bounty.claimed.call(); 104 | 105 | assert.isTrue(claim); 106 | 107 | await bounty.withdrawPayments({from:researcher}); 108 | 109 | assert.equal(0, web3.eth.getBalance(bounty.address).toNumber()); 110 | }; 111 | bounty.createTarget({from:researcher}); 112 | await awaitEvent(event, watcher); 113 | }); 114 | }); 115 | }); 116 | -------------------------------------------------------------------------------- /test/BurnableToken.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const EVMThrow = require('./helpers/EVMThrow.js') 4 | const BurnableTokenMock = artifacts.require("./helpers/BurnableTokenMock.sol") 5 | const BigNumber = web3.BigNumber 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | const expect = require('chai').expect 13 | 14 | contract('BurnableToken', function (accounts) { 15 | let token 16 | let expectedTokenSupply = new BigNumber(999) 17 | 18 | beforeEach(async function () { 19 | token = await BurnableTokenMock.new(accounts[0], 1000) 20 | }) 21 | 22 | it('owner should be able to burn tokens', async function () { 23 | const { logs } = await token.burn(1, { from: accounts[0] }) 24 | 25 | const balance = await token.balanceOf(accounts[0]) 26 | balance.should.be.bignumber.equal(expectedTokenSupply) 27 | 28 | const totalSupply = await token.totalSupply() 29 | totalSupply.should.be.bignumber.equal(expectedTokenSupply) 30 | 31 | const event = logs.find(e => e.event === 'Burn') 32 | expect(event).to.exist 33 | }) 34 | 35 | it('cannot burn more tokens than your balance', async function () { 36 | await token.burn(2000, { from: accounts[0] }) 37 | .should.be.rejectedWith(EVMThrow) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /test/CanReclaimToken.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import expectThrow from './helpers/expectThrow'; 3 | import toPromise from './helpers/toPromise'; 4 | const CanReclaimToken = artifacts.require('../contracts/ownership/CanReclaimToken.sol'); 5 | const BasicTokenMock = artifacts.require("./helpers/BasicTokenMock.sol"); 6 | 7 | contract('CanReclaimToken', function(accounts) { 8 | let token = null; 9 | let canReclaimToken = null; 10 | 11 | beforeEach(async function() { 12 | // Create contract and token 13 | token = await BasicTokenMock.new(accounts[0], 100); 14 | canReclaimToken = await CanReclaimToken.new(); 15 | // Force token into contract 16 | await token.transfer(canReclaimToken.address, 10); 17 | const startBalance = await token.balanceOf(canReclaimToken.address); 18 | assert.equal(startBalance, 10); 19 | }); 20 | 21 | it('should allow owner to reclaim tokens', async function() { 22 | const ownerStartBalance = await token.balanceOf(accounts[0]); 23 | await canReclaimToken.reclaimToken(token.address); 24 | const ownerFinalBalance = await token.balanceOf(accounts[0]); 25 | const finalBalance = await token.balanceOf(canReclaimToken.address); 26 | assert.equal(finalBalance, 0); 27 | assert.equal(ownerFinalBalance - ownerStartBalance, 10); 28 | }); 29 | 30 | it('should allow only owner to reclaim tokens', async function() { 31 | await expectThrow( 32 | canReclaimToken.reclaimToken(token.address, {from: accounts[1]}), 33 | ); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/CappedCrowdsale.js: -------------------------------------------------------------------------------- 1 | import ether from './helpers/ether' 2 | import {advanceBlock} from './helpers/advanceToBlock' 3 | import {increaseTimeTo, duration} from './helpers/increaseTime' 4 | import latestTime from './helpers/latestTime' 5 | import EVMThrow from './helpers/EVMThrow' 6 | 7 | const BigNumber = web3.BigNumber 8 | 9 | require('chai') 10 | .use(require('chai-as-promised')) 11 | .use(require('chai-bignumber')(BigNumber)) 12 | .should() 13 | 14 | const CappedCrowdsale = artifacts.require('./helpers/CappedCrowdsaleImpl.sol') 15 | const MintableToken = artifacts.require('MintableToken') 16 | 17 | contract('CappedCrowdsale', function ([_, wallet]) { 18 | 19 | const rate = new BigNumber(1000) 20 | 21 | const cap = ether(300) 22 | const lessThanCap = ether(60) 23 | 24 | before(async function() { 25 | //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc 26 | await advanceBlock() 27 | }) 28 | 29 | beforeEach(async function () { 30 | this.startTime = latestTime() + duration.weeks(1); 31 | this.endTime = this.startTime + duration.weeks(1); 32 | 33 | this.crowdsale = await CappedCrowdsale.new(this.startTime, this.endTime, rate, wallet, cap) 34 | 35 | this.token = MintableToken.at(await this.crowdsale.token()) 36 | }) 37 | 38 | describe('creating a valid crowdsale', function () { 39 | 40 | it('should fail with zero cap', async function () { 41 | await CappedCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0).should.be.rejectedWith(EVMThrow); 42 | }) 43 | 44 | }); 45 | 46 | describe('accepting payments', function () { 47 | 48 | beforeEach(async function () { 49 | await increaseTimeTo(this.startTime) 50 | }) 51 | 52 | it('should accept payments within cap', async function () { 53 | await this.crowdsale.send(cap.minus(lessThanCap)).should.be.fulfilled 54 | await this.crowdsale.send(lessThanCap).should.be.fulfilled 55 | }) 56 | 57 | it('should reject payments outside cap', async function () { 58 | await this.crowdsale.send(cap) 59 | await this.crowdsale.send(1).should.be.rejectedWith(EVMThrow) 60 | }) 61 | 62 | it('should reject payments that exceed cap', async function () { 63 | await this.crowdsale.send(cap.plus(1)).should.be.rejectedWith(EVMThrow) 64 | }) 65 | 66 | }) 67 | 68 | describe('ending', function () { 69 | 70 | beforeEach(async function () { 71 | await increaseTimeTo(this.startTime) 72 | }) 73 | 74 | it('should not be ended if under cap', async function () { 75 | let hasEnded = await this.crowdsale.hasEnded() 76 | hasEnded.should.equal(false) 77 | await this.crowdsale.send(lessThanCap) 78 | hasEnded = await this.crowdsale.hasEnded() 79 | hasEnded.should.equal(false) 80 | }) 81 | 82 | it('should not be ended if just under cap', async function () { 83 | await this.crowdsale.send(cap.minus(1)) 84 | let hasEnded = await this.crowdsale.hasEnded() 85 | hasEnded.should.equal(false) 86 | }) 87 | 88 | it('should be ended if cap reached', async function () { 89 | await this.crowdsale.send(cap) 90 | let hasEnded = await this.crowdsale.hasEnded() 91 | hasEnded.should.equal(true) 92 | }) 93 | 94 | }) 95 | 96 | }) 97 | -------------------------------------------------------------------------------- /test/Claimable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const assertJump = require('./helpers/assertJump'); 3 | 4 | var Claimable = artifacts.require('../contracts/ownership/Claimable.sol'); 5 | 6 | contract('Claimable', function(accounts) { 7 | let claimable; 8 | 9 | beforeEach(async function() { 10 | claimable = await Claimable.new(); 11 | }); 12 | 13 | it('should have an owner', async function() { 14 | let owner = await claimable.owner(); 15 | assert.isTrue(owner !== 0); 16 | }); 17 | 18 | it('changes pendingOwner after transfer', async function() { 19 | let newOwner = accounts[1]; 20 | await claimable.transferOwnership(newOwner); 21 | let pendingOwner = await claimable.pendingOwner(); 22 | 23 | assert.isTrue(pendingOwner === newOwner); 24 | }); 25 | 26 | it('should prevent to claimOwnership from no pendingOwner', async function() { 27 | try { 28 | await claimable.claimOwnership({from: accounts[2]}); 29 | assert.fail('should have thrown before'); 30 | } catch(error) { 31 | assertJump(error); 32 | } 33 | }); 34 | 35 | it('should prevent non-owners from transfering', async function() { 36 | const other = accounts[2]; 37 | const owner = await claimable.owner.call(); 38 | assert.isTrue(owner !== other); 39 | try { 40 | await claimable.transferOwnership(other, {from: other}); 41 | assert.fail('should have thrown before'); 42 | } catch(error) { 43 | assertJump(error); 44 | } 45 | }); 46 | 47 | describe('after initiating a transfer', function () { 48 | let newOwner; 49 | 50 | beforeEach(async function () { 51 | newOwner = accounts[1]; 52 | await claimable.transferOwnership(newOwner); 53 | }); 54 | 55 | it('changes allow pending owner to claim ownership', async function() { 56 | await claimable.claimOwnership({from: newOwner}); 57 | let owner = await claimable.owner(); 58 | 59 | assert.isTrue(owner === newOwner); 60 | }); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /test/Contactable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const assertJump = require('./helpers/assertJump'); 3 | 4 | var Contactable = artifacts.require('../contracts/ownership/Contactable.sol'); 5 | 6 | contract('Contactable', function(accounts) { 7 | let contactable; 8 | 9 | beforeEach(async function() { 10 | contactable = await Contactable.new(); 11 | }); 12 | 13 | it('should have an empty contact info', async function() { 14 | let info = await contactable.contactInformation(); 15 | assert.isTrue(info == ""); 16 | }); 17 | 18 | describe('after setting the contact information', function () { 19 | let contactInfo = "contact information" 20 | 21 | beforeEach(async function () { 22 | await contactable.setContactInformation(contactInfo); 23 | }); 24 | 25 | it('should return the setted contact information', async function() { 26 | let info = await contactable.contactInformation(); 27 | assert.isTrue(info === contactInfo); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/Crowdsale.js: -------------------------------------------------------------------------------- 1 | import ether from './helpers/ether' 2 | import {advanceBlock} from './helpers/advanceToBlock' 3 | import {increaseTimeTo, duration} from './helpers/increaseTime' 4 | import latestTime from './helpers/latestTime' 5 | import EVMThrow from './helpers/EVMThrow' 6 | 7 | const BigNumber = web3.BigNumber 8 | 9 | const should = require('chai') 10 | .use(require('chai-as-promised')) 11 | .use(require('chai-bignumber')(BigNumber)) 12 | .should() 13 | 14 | const Crowdsale = artifacts.require('Crowdsale') 15 | const MintableToken = artifacts.require('MintableToken') 16 | 17 | contract('Crowdsale', function ([_, investor, wallet, purchaser]) { 18 | 19 | const rate = new BigNumber(1000) 20 | const value = ether(42) 21 | 22 | const expectedTokenAmount = rate.mul(value) 23 | 24 | before(async function() { 25 | //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc 26 | await advanceBlock() 27 | }) 28 | 29 | beforeEach(async function () { 30 | this.startTime = latestTime() + duration.weeks(1); 31 | this.endTime = this.startTime + duration.weeks(1); 32 | this.afterEndTime = this.endTime + duration.seconds(1) 33 | 34 | 35 | this.crowdsale = await Crowdsale.new(this.startTime, this.endTime, rate, wallet) 36 | 37 | this.token = MintableToken.at(await this.crowdsale.token()) 38 | }) 39 | 40 | it('should be token owner', async function () { 41 | const owner = await this.token.owner() 42 | owner.should.equal(this.crowdsale.address) 43 | }) 44 | 45 | it('should be ended only after end', async function () { 46 | let ended = await this.crowdsale.hasEnded() 47 | ended.should.equal(false) 48 | await increaseTimeTo(this.afterEndTime) 49 | ended = await this.crowdsale.hasEnded() 50 | ended.should.equal(true) 51 | }) 52 | 53 | describe('accepting payments', function () { 54 | 55 | it('should reject payments before start', async function () { 56 | await this.crowdsale.send(value).should.be.rejectedWith(EVMThrow) 57 | await this.crowdsale.buyTokens(investor, {from: purchaser, value: value}).should.be.rejectedWith(EVMThrow) 58 | }) 59 | 60 | it('should accept payments after start', async function () { 61 | await increaseTimeTo(this.startTime) 62 | await this.crowdsale.send(value).should.be.fulfilled 63 | await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}).should.be.fulfilled 64 | }) 65 | 66 | it('should reject payments after end', async function () { 67 | await increaseTimeTo(this.afterEndTime) 68 | await this.crowdsale.send(value).should.be.rejectedWith(EVMThrow) 69 | await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}).should.be.rejectedWith(EVMThrow) 70 | }) 71 | 72 | }) 73 | 74 | describe('high-level purchase', function () { 75 | 76 | beforeEach(async function() { 77 | await increaseTimeTo(this.startTime) 78 | }) 79 | 80 | it('should log purchase', async function () { 81 | const {logs} = await this.crowdsale.sendTransaction({value: value, from: investor}) 82 | 83 | const event = logs.find(e => e.event === 'TokenPurchase') 84 | 85 | should.exist(event) 86 | event.args.purchaser.should.equal(investor) 87 | event.args.beneficiary.should.equal(investor) 88 | event.args.value.should.be.bignumber.equal(value) 89 | event.args.amount.should.be.bignumber.equal(expectedTokenAmount) 90 | }) 91 | 92 | it('should increase totalSupply', async function () { 93 | await this.crowdsale.send(value) 94 | const totalSupply = await this.token.totalSupply() 95 | totalSupply.should.be.bignumber.equal(expectedTokenAmount) 96 | }) 97 | 98 | it('should assign tokens to sender', async function () { 99 | await this.crowdsale.sendTransaction({value: value, from: investor}) 100 | let balance = await this.token.balanceOf(investor); 101 | balance.should.be.bignumber.equal(expectedTokenAmount) 102 | }) 103 | 104 | it('should forward funds to wallet', async function () { 105 | const pre = web3.eth.getBalance(wallet) 106 | await this.crowdsale.sendTransaction({value, from: investor}) 107 | const post = web3.eth.getBalance(wallet) 108 | post.minus(pre).should.be.bignumber.equal(value) 109 | }) 110 | 111 | }) 112 | 113 | describe('low-level purchase', function () { 114 | 115 | beforeEach(async function() { 116 | await increaseTimeTo(this.startTime) 117 | }) 118 | 119 | it('should log purchase', async function () { 120 | const {logs} = await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}) 121 | 122 | const event = logs.find(e => e.event === 'TokenPurchase') 123 | 124 | should.exist(event) 125 | event.args.purchaser.should.equal(purchaser) 126 | event.args.beneficiary.should.equal(investor) 127 | event.args.value.should.be.bignumber.equal(value) 128 | event.args.amount.should.be.bignumber.equal(expectedTokenAmount) 129 | }) 130 | 131 | it('should increase totalSupply', async function () { 132 | await this.crowdsale.buyTokens(investor, {value, from: purchaser}) 133 | const totalSupply = await this.token.totalSupply() 134 | totalSupply.should.be.bignumber.equal(expectedTokenAmount) 135 | }) 136 | 137 | it('should assign tokens to beneficiary', async function () { 138 | await this.crowdsale.buyTokens(investor, {value, from: purchaser}) 139 | const balance = await this.token.balanceOf(investor) 140 | balance.should.be.bignumber.equal(expectedTokenAmount) 141 | }) 142 | 143 | it('should forward funds to wallet', async function () { 144 | const pre = web3.eth.getBalance(wallet) 145 | await this.crowdsale.buyTokens(investor, {value, from: purchaser}) 146 | const post = web3.eth.getBalance(wallet) 147 | post.minus(pre).should.be.bignumber.equal(value) 148 | }) 149 | 150 | }) 151 | 152 | }) 153 | -------------------------------------------------------------------------------- /test/DayLimit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const assertJump = require('./helpers/assertJump'); 3 | const timer = require('./helpers/timer'); 4 | 5 | var DayLimitMock = artifacts.require('./helpers/DayLimitMock.sol'); 6 | 7 | contract('DayLimit', function(accounts) { 8 | const day = 60 * 60 * 24; 9 | 10 | let dayLimit; 11 | let initLimit = 10; 12 | 13 | beforeEach( async function() { 14 | dayLimit = await DayLimitMock.new(initLimit); 15 | }); 16 | 17 | it('should construct with the passed daily limit', async function() { 18 | let dailyLimit = await dayLimit.dailyLimit(); 19 | assert.equal(initLimit, dailyLimit); 20 | }); 21 | 22 | it('should be able to spend if daily limit is not reached', async function() { 23 | await dayLimit.attemptSpend(8); 24 | let spentToday = await dayLimit.spentToday(); 25 | assert.equal(spentToday, 8); 26 | 27 | await dayLimit.attemptSpend(2); 28 | spentToday = await dayLimit.spentToday(); 29 | assert.equal(spentToday, 10); 30 | }); 31 | 32 | it('should prevent spending if daily limit is reached', async function() { 33 | await dayLimit.attemptSpend(8); 34 | let spentToday = await dayLimit.spentToday(); 35 | assert.equal(spentToday, 8); 36 | 37 | try { 38 | await dayLimit.attemptSpend(3); 39 | assert.fail('should have thrown before'); 40 | } catch(error) { 41 | assertJump(error); 42 | } 43 | }); 44 | 45 | it('should allow spending if daily limit is reached and then set higher', async function() { 46 | await dayLimit.attemptSpend(8); 47 | let spentToday = await dayLimit.spentToday(); 48 | assert.equal(spentToday, 8); 49 | 50 | try { 51 | await dayLimit.attemptSpend(3); 52 | assert.fail('should have thrown before'); 53 | } catch(error) { 54 | assertJump(error); 55 | } 56 | spentToday = await dayLimit.spentToday(); 57 | assert.equal(spentToday, 8); 58 | 59 | await dayLimit.setDailyLimit(15); 60 | await dayLimit.attemptSpend(3); 61 | spentToday = await dayLimit.spentToday(); 62 | assert.equal(spentToday, 11); 63 | }); 64 | 65 | it('should allow spending if daily limit is reached and then amount spent is reset', async function() { 66 | await dayLimit.attemptSpend(8); 67 | let spentToday = await dayLimit.spentToday(); 68 | assert.equal(spentToday, 8); 69 | 70 | try { 71 | await dayLimit.attemptSpend(3); 72 | assert.fail('should have thrown before'); 73 | } catch(error) { 74 | assertJump(error); 75 | } 76 | spentToday = await dayLimit.spentToday(); 77 | assert.equal(spentToday, 8); 78 | 79 | await dayLimit.resetSpentToday(); 80 | await dayLimit.attemptSpend(3); 81 | spentToday = await dayLimit.spentToday(); 82 | assert.equal(spentToday, 3); 83 | }); 84 | 85 | it('should allow spending if daily limit is reached and then the next has come', async function() { 86 | let limit = 10; 87 | let dayLimit = await DayLimitMock.new(limit); 88 | 89 | await dayLimit.attemptSpend(8); 90 | let spentToday = await dayLimit.spentToday(); 91 | assert.equal(spentToday, 8); 92 | 93 | try { 94 | await dayLimit.attemptSpend(3); 95 | assert.fail('should have thrown before'); 96 | } catch(error) { 97 | assertJump(error); 98 | } 99 | spentToday = await dayLimit.spentToday(); 100 | assert.equal(spentToday, 8); 101 | 102 | await timer(day); 103 | 104 | await dayLimit.attemptSpend(3); 105 | spentToday = await dayLimit.spentToday(); 106 | assert.equal(spentToday, 3); 107 | }); 108 | 109 | }); 110 | -------------------------------------------------------------------------------- /test/DelayedClaimble.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var DelayedClaimable = artifacts.require('../contracts/ownership/DelayedClaimable.sol'); 4 | 5 | contract('DelayedClaimable', function(accounts) { 6 | var delayedClaimable; 7 | 8 | beforeEach(function() { 9 | return DelayedClaimable.new().then(function(deployed) { 10 | delayedClaimable = deployed; 11 | }); 12 | }); 13 | 14 | it('can set claim blocks', async function() { 15 | await delayedClaimable.transferOwnership(accounts[2]); 16 | await delayedClaimable.setLimits(0, 1000); 17 | let end = await delayedClaimable.end(); 18 | assert.equal(end, 1000); 19 | let start = await delayedClaimable.start(); 20 | assert.equal(start, 0); 21 | }); 22 | 23 | it('changes pendingOwner after transfer successful', async function() { 24 | await delayedClaimable.transferOwnership(accounts[2]); 25 | await delayedClaimable.setLimits(0, 1000); 26 | let end = await delayedClaimable.end(); 27 | assert.equal(end, 1000); 28 | let start = await delayedClaimable.start(); 29 | assert.equal(start, 0); 30 | let pendingOwner = await delayedClaimable.pendingOwner(); 31 | assert.equal(pendingOwner, accounts[2]); 32 | await delayedClaimable.claimOwnership({from: accounts[2]}); 33 | let owner = await delayedClaimable.owner(); 34 | assert.equal(owner, accounts[2]); 35 | }); 36 | 37 | it('changes pendingOwner after transfer fails', async function() { 38 | await delayedClaimable.transferOwnership(accounts[1]); 39 | await delayedClaimable.setLimits(100, 110); 40 | let end = await delayedClaimable.end(); 41 | assert.equal(end, 110); 42 | let start = await delayedClaimable.start(); 43 | assert.equal(start, 100); 44 | let pendingOwner = await delayedClaimable.pendingOwner(); 45 | assert.equal(pendingOwner, accounts[1]); 46 | var err = null; 47 | try { 48 | await delayedClaimable.claimOwnership({from: accounts[1]}); 49 | } catch (error) { 50 | err = error; 51 | } 52 | assert.isFalse(err.message.search('invalid opcode') === -1); 53 | let owner = await delayedClaimable.owner(); 54 | assert.isTrue(owner !== accounts[1]); 55 | }); 56 | 57 | it('set end and start invalid values fail', async function() { 58 | await delayedClaimable.transferOwnership(accounts[1]); 59 | var err = null; 60 | try { 61 | await delayedClaimable.setLimits(1001, 1000); 62 | } catch (error) { 63 | err = error; 64 | } 65 | assert.isFalse(err.message.search('invalid opcode') === -1); 66 | }); 67 | 68 | }); 69 | -------------------------------------------------------------------------------- /test/Destructible.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Destructible = artifacts.require('../contracts/lifecycle/Destructible.sol'); 4 | require('./helpers/transactionMined.js'); 5 | 6 | contract('Destructible', function(accounts) { 7 | 8 | it('should send balance to owner after destruction', async function() { 9 | let destructible = await Destructible.new({from: accounts[0], value: web3.toWei('10','ether')}); 10 | let owner = await destructible.owner(); 11 | let initBalance = web3.eth.getBalance(owner); 12 | await destructible.destroy({from: owner}); 13 | let newBalance = web3.eth.getBalance(owner); 14 | assert.isTrue(newBalance > initBalance); 15 | }); 16 | 17 | it('should send balance to recepient after destruction', async function() { 18 | let destructible = await Destructible.new({from: accounts[0], value: web3.toWei('10','ether')}); 19 | let owner = await destructible.owner(); 20 | let initBalance = web3.eth.getBalance(accounts[1]); 21 | await destructible.destroyAndSend(accounts[1], {from: owner} ); 22 | let newBalance = web3.eth.getBalance(accounts[1]); 23 | assert.isTrue(newBalance.greaterThan(initBalance)); 24 | }); 25 | 26 | }); 27 | -------------------------------------------------------------------------------- /test/ECRecovery.js: -------------------------------------------------------------------------------- 1 | var ECRecovery = artifacts.require("../contracts/ECRecovery.sol"); 2 | var utils = require('ethereumjs-util'); 3 | var hashMessage = require('./helpers/hashMessage.js'); 4 | 5 | contract('ECRecovery', function(accounts) { 6 | 7 | let ecrecovery; 8 | 9 | before(async function() { 10 | ecrecovery = await ECRecovery.new(); 11 | }); 12 | 13 | it("recover v0", async function() { 14 | // Signature generated outside testrpc with method web3.eth.sign(signer, message) 15 | let signer = '0x2cc1166f6212628a0deef2b33befb2187d35b86c'; 16 | let message = '0x7dbaf558b0a1a5dc7a67202117ab143c1d8605a983e4a743bc06fcc03162dc0d'; // web3.sha3('OpenZeppelin') 17 | let signature = '0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be89200'; 18 | assert.equal(signer, await ecrecovery.recover(message, signature)); 19 | }); 20 | 21 | it("recover v1", async function() { 22 | // Signature generated outside testrpc with method web3.eth.sign(signer, message) 23 | let signer = '0x1e318623ab09fe6de3c9b8672098464aeda9100e'; 24 | let message = '0x7dbaf558b0a1a5dc7a67202117ab143c1d8605a983e4a743bc06fcc03162dc0d'; // web3.sha3('OpenZeppelin') 25 | let signature = '0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e001'; 26 | assert.equal(signer, await ecrecovery.recover(message, signature)); 27 | }); 28 | 29 | it("recover using web3.eth.sign()", async function() { 30 | // Create the signature using account[0] 31 | const signature = web3.eth.sign(web3.eth.accounts[0], web3.sha3('OpenZeppelin')); 32 | 33 | // Recover the signer address form the generated message and signature. 34 | assert.equal(web3.eth.accounts[0], await ecrecovery.recover(hashMessage('OpenZeppelin'), signature)); 35 | }); 36 | 37 | it("recover using web3.eth.sign() should return wrong signer", async function() { 38 | // Create the signature using account[0] 39 | const signature = web3.eth.sign(web3.eth.accounts[0], web3.sha3('OpenZeppelin')); 40 | 41 | // Recover the signer address form the generated message and wrong signature. 42 | assert.notEqual(web3.eth.accounts[0], await ecrecovery.recover(hashMessage('Test'), signature)); 43 | }); 44 | 45 | it("recover should fail when a wrong hash is sent", async function() { 46 | // Create the signature using account[0] 47 | let signature = web3.eth.sign(web3.eth.accounts[0], web3.sha3('OpenZeppelin')); 48 | 49 | // Recover the signer address form the generated message and wrong signature. 50 | assert.equal('0x0000000000000000000000000000000000000000', 51 | await ecrecovery.recover(hashMessage('OpenZeppelin').substring(2), signature) 52 | ); 53 | }); 54 | 55 | }); 56 | -------------------------------------------------------------------------------- /test/FinalizableCrowdsale.js: -------------------------------------------------------------------------------- 1 | import {advanceBlock} from './helpers/advanceToBlock' 2 | import {increaseTimeTo, duration} from './helpers/increaseTime' 3 | import latestTime from './helpers/latestTime' 4 | import EVMThrow from './helpers/EVMThrow' 5 | 6 | const BigNumber = web3.BigNumber 7 | 8 | const should = require('chai') 9 | .use(require('chai-as-promised')) 10 | .use(require('chai-bignumber')(BigNumber)) 11 | .should() 12 | 13 | const FinalizableCrowdsale = artifacts.require('./helpers/FinalizableCrowdsaleImpl.sol') 14 | const MintableToken = artifacts.require('MintableToken') 15 | 16 | contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) { 17 | 18 | const rate = new BigNumber(1000) 19 | 20 | before(async function() { 21 | //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc 22 | await advanceBlock() 23 | }) 24 | 25 | beforeEach(async function () { 26 | this.startTime = latestTime() + duration.weeks(1) 27 | this.endTime = this.startTime + duration.weeks(1) 28 | this.afterEndTime = this.endTime + duration.seconds(1) 29 | 30 | 31 | this.crowdsale = await FinalizableCrowdsale.new(this.startTime, this.endTime, rate, wallet, {from: owner}) 32 | 33 | this.token = MintableToken.at(await this.crowdsale.token()) 34 | }) 35 | 36 | it('cannot be finalized before ending', async function () { 37 | await this.crowdsale.finalize({from: owner}).should.be.rejectedWith(EVMThrow) 38 | }) 39 | 40 | it('cannot be finalized by third party after ending', async function () { 41 | await increaseTimeTo(this.afterEndTime) 42 | await this.crowdsale.finalize({from: thirdparty}).should.be.rejectedWith(EVMThrow) 43 | }) 44 | 45 | it('can be finalized by owner after ending', async function () { 46 | await increaseTimeTo(this.afterEndTime) 47 | await this.crowdsale.finalize({from: owner}).should.be.fulfilled 48 | }) 49 | 50 | it('cannot be finalized twice', async function () { 51 | await increaseTimeTo(this.afterEndTime) 52 | await this.crowdsale.finalize({from: owner}) 53 | await this.crowdsale.finalize({from: owner}).should.be.rejectedWith(EVMThrow) 54 | }) 55 | 56 | it('logs finalized', async function () { 57 | await increaseTimeTo(this.afterEndTime) 58 | const {logs} = await this.crowdsale.finalize({from: owner}) 59 | const event = logs.find(e => e.event === 'Finalized') 60 | should.exist(event) 61 | }) 62 | 63 | }) 64 | -------------------------------------------------------------------------------- /test/HasNoContracts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import expectThrow from './helpers/expectThrow'; 3 | import toPromise from './helpers/toPromise'; 4 | const Ownable = artifacts.require('../contracts/ownership/Ownable.sol'); 5 | const HasNoContracts = artifacts.require( 6 | '../contracts/ownership/HasNoContracts.sol', 7 | ); 8 | 9 | contract('HasNoContracts', function(accounts) { 10 | let hasNoContracts = null; 11 | let ownable = null; 12 | 13 | beforeEach(async () => { 14 | // Create contract and token 15 | hasNoContracts = await HasNoContracts.new(); 16 | ownable = await Ownable.new(); 17 | 18 | // Force ownership into contract 19 | await ownable.transferOwnership(hasNoContracts.address); 20 | const owner = await ownable.owner(); 21 | assert.equal(owner, hasNoContracts.address); 22 | }); 23 | 24 | it('should allow owner to reclaim contracts', async function() { 25 | await hasNoContracts.reclaimContract(ownable.address); 26 | const owner = await ownable.owner(); 27 | assert.equal(owner, accounts[0]); 28 | }); 29 | 30 | it('should allow only owner to reclaim contracts', async function() { 31 | await expectThrow( 32 | hasNoContracts.reclaimContract(ownable.address, {from: accounts[1]}), 33 | ); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/HasNoEther.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import expectThrow from './helpers/expectThrow'; 3 | import toPromise from './helpers/toPromise'; 4 | const HasNoEther = artifacts.require('../contracts/lifecycle/HasNoEther.sol'); 5 | const HasNoEtherTest = artifacts.require('../helpers/HasNoEtherTest.sol'); 6 | const ForceEther = artifacts.require('../helpers/ForceEther.sol'); 7 | 8 | contract('HasNoEther', function(accounts) { 9 | const amount = web3.toWei('1', 'ether'); 10 | 11 | it('should be constructorable', async function() { 12 | let hasNoEther = await HasNoEtherTest.new(); 13 | }); 14 | 15 | it('should not accept ether in constructor', async function() { 16 | await expectThrow(HasNoEtherTest.new({value: amount})); 17 | }); 18 | 19 | it('should not accept ether', async function() { 20 | let hasNoEther = await HasNoEtherTest.new(); 21 | 22 | await expectThrow( 23 | toPromise(web3.eth.sendTransaction)({ 24 | from: accounts[1], 25 | to: hasNoEther.address, 26 | value: amount, 27 | }), 28 | ); 29 | }); 30 | 31 | it('should allow owner to reclaim ether', async function() { 32 | // Create contract 33 | let hasNoEther = await HasNoEtherTest.new(); 34 | const startBalance = await web3.eth.getBalance(hasNoEther.address); 35 | assert.equal(startBalance, 0); 36 | 37 | // Force ether into it 38 | let forceEther = await ForceEther.new({value: amount}); 39 | await forceEther.destroyAndSend(hasNoEther.address); 40 | const forcedBalance = await web3.eth.getBalance(hasNoEther.address); 41 | assert.equal(forcedBalance, amount); 42 | 43 | // Reclaim 44 | const ownerStartBalance = await web3.eth.getBalance(accounts[0]); 45 | await hasNoEther.reclaimEther(); 46 | const ownerFinalBalance = await web3.eth.getBalance(accounts[0]); 47 | const finalBalance = await web3.eth.getBalance(hasNoEther.address); 48 | assert.equal(finalBalance, 0); 49 | assert.isAbove(ownerFinalBalance, ownerStartBalance); 50 | }); 51 | 52 | it('should allow only owner to reclaim ether', async function() { 53 | // Create contract 54 | let hasNoEther = await HasNoEtherTest.new({from: accounts[0]}); 55 | 56 | // Force ether into it 57 | let forceEther = await ForceEther.new({value: amount}); 58 | await forceEther.destroyAndSend(hasNoEther.address); 59 | const forcedBalance = await web3.eth.getBalance(hasNoEther.address); 60 | assert.equal(forcedBalance, amount); 61 | 62 | // Reclaim 63 | await expectThrow(hasNoEther.reclaimEther({from: accounts[1]})); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /test/HasNoTokens.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import expectThrow from './helpers/expectThrow'; 3 | import toPromise from './helpers/toPromise'; 4 | const HasNoTokens = artifacts.require('../contracts/lifecycle/HasNoTokens.sol'); 5 | const ERC23TokenMock = artifacts.require('./helpers/ERC23TokenMock.sol'); 6 | 7 | contract('HasNoTokens', function(accounts) { 8 | let hasNoTokens = null; 9 | let token = null; 10 | 11 | beforeEach(async () => { 12 | // Create contract and token 13 | hasNoTokens = await HasNoTokens.new(); 14 | token = await ERC23TokenMock.new(accounts[0], 100); 15 | 16 | // Force token into contract 17 | await token.transfer(hasNoTokens.address, 10); 18 | const startBalance = await token.balanceOf(hasNoTokens.address); 19 | assert.equal(startBalance, 10); 20 | }); 21 | 22 | it('should not accept ERC23 tokens', async function() { 23 | await expectThrow(token.transferERC23(hasNoTokens.address, 10, '')); 24 | }); 25 | 26 | it('should allow owner to reclaim tokens', async function() { 27 | const ownerStartBalance = await token.balanceOf(accounts[0]); 28 | await hasNoTokens.reclaimToken(token.address); 29 | const ownerFinalBalance = await token.balanceOf(accounts[0]); 30 | const finalBalance = await token.balanceOf(hasNoTokens.address); 31 | assert.equal(finalBalance, 0); 32 | assert.equal(ownerFinalBalance - ownerStartBalance, 10); 33 | }); 34 | 35 | it('should allow only owner to reclaim tokens', async function() { 36 | await expectThrow( 37 | hasNoTokens.reclaimToken(token.address, {from: accounts[1]}), 38 | ); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test/LimitBalance.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var LimitBalanceMock = artifacts.require('helpers/LimitBalanceMock.sol'); 4 | const assertJump = require('./helpers/assertJump'); 5 | 6 | contract('LimitBalance', function(accounts) { 7 | let lb; 8 | 9 | beforeEach(async function() { 10 | lb = await LimitBalanceMock.new(); 11 | }); 12 | 13 | let LIMIT = 1000; 14 | 15 | it('should expose limit', async function() { 16 | let limit = await lb.limit(); 17 | assert.equal(limit, LIMIT); 18 | }); 19 | 20 | it('should allow sending below limit', async function() { 21 | let amount = 1; 22 | await lb.limitedDeposit({value: amount}); 23 | 24 | assert.equal(web3.eth.getBalance(lb.address), amount); 25 | }); 26 | 27 | it('shouldnt allow sending above limit', async function() { 28 | let amount = 1110; 29 | try { 30 | await lb.limitedDeposit({value: amount}); 31 | assert.fail('should have thrown before'); 32 | } catch(error) { 33 | assertJump(error); 34 | } 35 | }); 36 | 37 | it('should allow multiple sends below limit', async function() { 38 | let amount = 500; 39 | await lb.limitedDeposit({value: amount}); 40 | 41 | assert.equal(web3.eth.getBalance(lb.address), amount); 42 | 43 | await lb.limitedDeposit({value: amount}); 44 | assert.equal(web3.eth.getBalance(lb.address), amount*2); 45 | }); 46 | 47 | it('shouldnt allow multiple sends above limit', async function() { 48 | let amount = 500; 49 | await lb.limitedDeposit({value: amount}); 50 | 51 | assert.equal(web3.eth.getBalance(lb.address), amount); 52 | 53 | try { 54 | await lb.limitedDeposit({value: amount+1}); 55 | assert.fail('should have thrown before'); 56 | } catch(error) { 57 | assertJump(error); 58 | } 59 | }); 60 | 61 | }); 62 | -------------------------------------------------------------------------------- /test/LimitedTokenCrowdsale.js: -------------------------------------------------------------------------------- 1 | import {advanceBlock} from '../submodules/zeppelin-gimmer/test/helpers/advanceToBlock' 2 | import {increaseTimeTo, duration} from '../submodules/zeppelin-gimmer/test/helpers/increaseTime' 3 | import latestTime from '../submodules/zeppelin-gimmer/test/helpers/latestTime' 4 | import EVMThrow from '../submodules/zeppelin-gimmer/test/helpers/EVMThrow' 5 | const BigNumber = web3.BigNumber 6 | 7 | const should = require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | var LimitedTokenCrowdsale = artifacts.require("./LimitedTokenCrowdsale.sol"); 13 | 14 | contract ('LimitedTokenCrowdsale', function (caccounts) { 15 | var mainAcc = caccounts[0]; 16 | 17 | 18 | }); -------------------------------------------------------------------------------- /test/MerkleProof.js: -------------------------------------------------------------------------------- 1 | var MerkleProof = artifacts.require("./MerkleProof.sol"); 2 | 3 | import MerkleTree from "./helpers/merkleTree.js"; 4 | import { sha3, bufferToHex } from "ethereumjs-util"; 5 | 6 | contract('MerkleProof', function(accounts) { 7 | let merkleProof; 8 | 9 | before(async function() { 10 | merkleProof = await MerkleProof.new(); 11 | }); 12 | 13 | describe("verifyProof", function() { 14 | it("should return true for a valid Merkle proof", async function() { 15 | const elements = ["a", "b", "c", "d"]; 16 | const merkleTree = new MerkleTree(elements); 17 | 18 | const root = merkleTree.getHexRoot(); 19 | 20 | const proof = merkleTree.getHexProof(elements[0]); 21 | 22 | const leaf = bufferToHex(sha3(elements[0])); 23 | 24 | const result = await merkleProof.verifyProof(proof, root, leaf); 25 | assert.isOk(result, "verifyProof did not return true for a valid proof"); 26 | }); 27 | 28 | it("should return false for an invalid Merkle proof", async function() { 29 | const correctElements = ["a", "b", "c"] 30 | const correctMerkleTree = new MerkleTree(correctElements); 31 | 32 | const correctRoot = correctMerkleTree.getHexRoot(); 33 | 34 | const correctLeaf = bufferToHex(sha3(correctElements[0])); 35 | 36 | const badElements = ["d", "e", "f"] 37 | const badMerkleTree = new MerkleTree(badElements) 38 | 39 | const badProof = badMerkleTree.getHexProof(badElements[0]) 40 | 41 | const result = await merkleProof.verifyProof(badProof, correctRoot, correctLeaf); 42 | assert.isNotOk(result, "verifyProof did not return false for an invalid proof"); 43 | }); 44 | 45 | it("should return false for a Merkle proof of invalid length", async function() { 46 | const elements = ["a", "b", "c"] 47 | const merkleTree = new MerkleTree(elements); 48 | 49 | const root = merkleTree.getHexRoot(); 50 | 51 | const proof = merkleTree.getHexProof(elements[0]); 52 | const badProof = proof.slice(0, proof.length - 5); 53 | 54 | const leaf = bufferToHex(sha3(elements[0])); 55 | 56 | const result = await merkleProof.verifyProof(badProof, root, leaf); 57 | assert.isNotOk(result, "verifyProof did not return false for proof of invalid length"); 58 | }) 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /test/MintableToken.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import expectThrow from './helpers/expectThrow'; 4 | var MintableToken = artifacts.require('../contracts/Tokens/MintableToken.sol'); 5 | 6 | contract('Mintable', function(accounts) { 7 | let token; 8 | 9 | beforeEach(async function() { 10 | token = await MintableToken.new(); 11 | }); 12 | 13 | it('should start with a totalSupply of 0', async function() { 14 | let totalSupply = await token.totalSupply(); 15 | 16 | assert.equal(totalSupply, 0); 17 | }); 18 | 19 | it('should return mintingFinished false after construction', async function() { 20 | let mintingFinished = await token.mintingFinished(); 21 | 22 | assert.equal(mintingFinished, false); 23 | }); 24 | 25 | it('should mint a given amount of tokens to a given address', async function() { 26 | const result = await token.mint(accounts[0], 100); 27 | assert.equal(result.logs[0].event, 'Mint'); 28 | assert.equal(result.logs[0].args.to.valueOf(), accounts[0]); 29 | assert.equal(result.logs[0].args.amount.valueOf(), 100); 30 | assert.equal(result.logs[1].event, 'Transfer'); 31 | assert.equal(result.logs[1].args.from.valueOf(), 0x0); 32 | 33 | let balance0 = await token.balanceOf(accounts[0]); 34 | assert(balance0, 100); 35 | 36 | let totalSupply = await token.totalSupply(); 37 | assert(totalSupply, 100); 38 | }) 39 | 40 | it('should fail to mint after call to finishMinting', async function () { 41 | await token.finishMinting(); 42 | assert.equal(await token.mintingFinished(), true); 43 | await expectThrow(token.mint(accounts[0], 100)); 44 | }) 45 | 46 | }); 47 | -------------------------------------------------------------------------------- /test/Ownable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const assertJump = require('./helpers/assertJump'); 3 | 4 | var Ownable = artifacts.require('../contracts/ownership/Ownable.sol'); 5 | 6 | contract('Ownable', function(accounts) { 7 | let ownable; 8 | 9 | beforeEach(async function() { 10 | ownable = await Ownable.new(); 11 | }); 12 | 13 | it('should have an owner', async function() { 14 | let owner = await ownable.owner(); 15 | assert.isTrue(owner !== 0); 16 | }); 17 | 18 | it('changes owner after transfer', async function() { 19 | let other = accounts[1]; 20 | await ownable.transferOwnership(other); 21 | let owner = await ownable.owner(); 22 | 23 | assert.isTrue(owner === other); 24 | }); 25 | 26 | it('should prevent non-owners from transfering', async function() { 27 | const other = accounts[2]; 28 | const owner = await ownable.owner.call(); 29 | assert.isTrue(owner !== other); 30 | try { 31 | await ownable.transferOwnership(other, {from: other}); 32 | assert.fail('should have thrown before'); 33 | } catch(error) { 34 | assertJump(error); 35 | } 36 | }); 37 | 38 | it('should guard ownership against stuck state', async function() { 39 | let originalOwner = await ownable.owner(); 40 | try { 41 | await ownable.transferOwnership(null, {from: originalOwner}); 42 | assert.fail(); 43 | } catch(error) { 44 | assertJump(error); 45 | } 46 | }); 47 | 48 | }); 49 | -------------------------------------------------------------------------------- /test/Pausable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assertJump = require('./helpers/assertJump'); 4 | const PausableMock = artifacts.require('helpers/PausableMock.sol'); 5 | 6 | contract('Pausable', function(accounts) { 7 | 8 | it('can perform normal process in non-pause', async function() { 9 | let Pausable = await PausableMock.new(); 10 | let count0 = await Pausable.count(); 11 | assert.equal(count0, 0); 12 | 13 | await Pausable.normalProcess(); 14 | let count1 = await Pausable.count(); 15 | assert.equal(count1, 1); 16 | }); 17 | 18 | it('can not perform normal process in pause', async function() { 19 | let Pausable = await PausableMock.new(); 20 | await Pausable.pause(); 21 | let count0 = await Pausable.count(); 22 | assert.equal(count0, 0); 23 | 24 | try { 25 | await Pausable.normalProcess(); 26 | assert.fail('should have thrown before'); 27 | } catch(error) { 28 | assertJump(error); 29 | } 30 | let count1 = await Pausable.count(); 31 | assert.equal(count1, 0); 32 | }); 33 | 34 | 35 | it('can not take drastic measure in non-pause', async function() { 36 | let Pausable = await PausableMock.new(); 37 | try { 38 | await Pausable.drasticMeasure(); 39 | assert.fail('should have thrown before'); 40 | } catch(error) { 41 | assertJump(error); 42 | } 43 | const drasticMeasureTaken = await Pausable.drasticMeasureTaken(); 44 | assert.isFalse(drasticMeasureTaken); 45 | }); 46 | 47 | it('can take a drastic measure in a pause', async function() { 48 | let Pausable = await PausableMock.new(); 49 | await Pausable.pause(); 50 | await Pausable.drasticMeasure(); 51 | let drasticMeasureTaken = await Pausable.drasticMeasureTaken(); 52 | 53 | assert.isTrue(drasticMeasureTaken); 54 | }); 55 | 56 | it('should resume allowing normal process after pause is over', async function() { 57 | let Pausable = await PausableMock.new(); 58 | await Pausable.pause(); 59 | await Pausable.unpause(); 60 | await Pausable.normalProcess(); 61 | let count0 = await Pausable.count(); 62 | 63 | assert.equal(count0, 1); 64 | }); 65 | 66 | it('should prevent drastic measure after pause is over', async function() { 67 | let Pausable = await PausableMock.new(); 68 | await Pausable.pause(); 69 | await Pausable.unpause(); 70 | try { 71 | await Pausable.drasticMeasure(); 72 | assert.fail('should have thrown before'); 73 | } catch(error) { 74 | assertJump(error); 75 | } 76 | 77 | const drasticMeasureTaken = await Pausable.drasticMeasureTaken(); 78 | assert.isFalse(drasticMeasureTaken); 79 | }); 80 | 81 | }); 82 | -------------------------------------------------------------------------------- /test/PausableToken.js: -------------------------------------------------------------------------------- 1 | 'user strict'; 2 | 3 | const assertJump = require('./helpers/assertJump'); 4 | var PausableTokenMock = artifacts.require('./helpers/PausableTokenMock.sol'); 5 | 6 | contract('PausableToken', function(accounts) { 7 | let token; 8 | 9 | beforeEach(async function() { 10 | token = await PausableTokenMock.new(accounts[0], 100); 11 | }); 12 | 13 | it('should return paused false after construction', async function() { 14 | let paused = await token.paused(); 15 | 16 | assert.equal(paused, false); 17 | }); 18 | 19 | it('should return paused true after pause', async function() { 20 | await token.pause(); 21 | let paused = await token.paused(); 22 | 23 | assert.equal(paused, true); 24 | }); 25 | 26 | it('should return paused false after pause and unpause', async function() { 27 | await token.pause(); 28 | await token.unpause(); 29 | let paused = await token.paused(); 30 | 31 | assert.equal(paused, false); 32 | }); 33 | 34 | it('should be able to transfer if transfers are unpaused', async function() { 35 | await token.transfer(accounts[1], 100); 36 | let balance0 = await token.balanceOf(accounts[0]); 37 | assert.equal(balance0, 0); 38 | 39 | let balance1 = await token.balanceOf(accounts[1]); 40 | assert.equal(balance1, 100); 41 | }); 42 | 43 | it('should be able to transfer after transfers are paused and unpaused', async function() { 44 | await token.pause(); 45 | await token.unpause(); 46 | await token.transfer(accounts[1], 100); 47 | let balance0 = await token.balanceOf(accounts[0]); 48 | assert.equal(balance0, 0); 49 | 50 | let balance1 = await token.balanceOf(accounts[1]); 51 | assert.equal(balance1, 100); 52 | }); 53 | 54 | it('should throw an error trying to transfer while transactions are paused', async function() { 55 | await token.pause(); 56 | try { 57 | await token.transfer(accounts[1], 100); 58 | assert.fail('should have thrown before'); 59 | } catch (error) { 60 | assertJump(error); 61 | } 62 | }); 63 | 64 | it('should throw an error trying to transfer from another account while transactions are paused', async function() { 65 | await token.pause(); 66 | try { 67 | await token.transferFrom(accounts[0], accounts[1], 100); 68 | assert.fail('should have thrown before'); 69 | } catch (error) { 70 | assertJump(error); 71 | } 72 | }); 73 | }) 74 | -------------------------------------------------------------------------------- /test/PullPayment.js: -------------------------------------------------------------------------------- 1 | var PullPaymentMock = artifacts.require("./helpers/PullPaymentMock.sol"); 2 | 3 | contract('PullPayment', function(accounts) { 4 | let ppce; 5 | let amount = 17*1e18; 6 | 7 | beforeEach(async function() { 8 | ppce = await PullPaymentMock.new({value: amount}); 9 | }); 10 | 11 | it("can't call asyncSend externally", async function() { 12 | assert.isUndefined(ppce.asyncSend); 13 | }); 14 | 15 | it("can record an async payment correctly", async function() { 16 | let AMOUNT = 100; 17 | let callSend = await ppce.callSend(accounts[0], AMOUNT); 18 | let paymentsToAccount0 = await ppce.payments(accounts[0]); 19 | let totalPayments = await ppce.totalPayments(); 20 | 21 | assert.equal(totalPayments, AMOUNT); 22 | assert.equal(paymentsToAccount0, AMOUNT); 23 | }); 24 | 25 | it("can add multiple balances on one account", async function() { 26 | let call1 = await ppce.callSend(accounts[0], 200); 27 | let call2 = await ppce.callSend(accounts[0], 300); 28 | let paymentsToAccount0 = await ppce.payments(accounts[0]); 29 | let totalPayments = await ppce.totalPayments(); 30 | 31 | assert.equal(totalPayments, 500); 32 | assert.equal(paymentsToAccount0, 500); 33 | }); 34 | 35 | it("can add balances on multiple accounts", async function() { 36 | let call1 = await ppce.callSend(accounts[0], 200); 37 | let call2 = await ppce.callSend(accounts[1], 300); 38 | 39 | let paymentsToAccount0 = await ppce.payments(accounts[0]); 40 | assert.equal(paymentsToAccount0, 200); 41 | 42 | let paymentsToAccount1 = await ppce.payments(accounts[1]); 43 | assert.equal(paymentsToAccount1, 300); 44 | 45 | let totalPayments = await ppce.totalPayments(); 46 | assert.equal(totalPayments, 500); 47 | }); 48 | 49 | it("can withdraw payment", async function() { 50 | let payee = accounts[1]; 51 | let initialBalance = web3.eth.getBalance(payee); 52 | 53 | let call1 = await ppce.callSend(payee, amount); 54 | 55 | let payment1 = await ppce.payments(payee); 56 | assert.equal(payment1, amount); 57 | 58 | let totalPayments = await ppce.totalPayments(); 59 | assert.equal(totalPayments, amount); 60 | 61 | let withdraw = await ppce.withdrawPayments({from: payee}); 62 | let payment2 = await ppce.payments(payee); 63 | assert.equal(payment2, 0); 64 | 65 | totalPayments = await ppce.totalPayments(); 66 | assert.equal(totalPayments, 0); 67 | 68 | let balance = web3.eth.getBalance(payee); 69 | assert(Math.abs(balance-initialBalance-amount) < 1e16); 70 | }); 71 | 72 | }); 73 | -------------------------------------------------------------------------------- /test/ReentrancyGuard.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import expectThrow from './helpers/expectThrow'; 3 | const ReentrancyMock = artifacts.require('./helper/ReentrancyMock.sol'); 4 | const ReentrancyAttack = artifacts.require('./helper/ReentrancyAttack.sol'); 5 | 6 | contract('ReentrancyGuard', function(accounts) { 7 | let reentrancyMock; 8 | 9 | beforeEach(async function() { 10 | reentrancyMock = await ReentrancyMock.new(); 11 | let initialCounter = await reentrancyMock.counter(); 12 | assert.equal(initialCounter, 0); 13 | }); 14 | 15 | it('should not allow remote callback', async function() { 16 | let attacker = await ReentrancyAttack.new(); 17 | await expectThrow(reentrancyMock.countAndCall(attacker.address)); 18 | }); 19 | 20 | // The following are more side-effects that intended behaviour: 21 | // I put them here as documentation, and to monitor any changes 22 | // in the side-effects. 23 | 24 | it('should not allow local recursion', async function() { 25 | await expectThrow(reentrancyMock.countLocalRecursive(10)); 26 | }); 27 | 28 | it('should not allow indirect local recursion', async function() { 29 | await expectThrow(reentrancyMock.countThisRecursive(10)); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/RefundVault.js: -------------------------------------------------------------------------------- 1 | const BigNumber = web3.BigNumber 2 | 3 | require('chai') 4 | .use(require('chai-as-promised')) 5 | .use(require('chai-bignumber')(BigNumber)) 6 | .should() 7 | 8 | import ether from './helpers/ether' 9 | import EVMThrow from './helpers/EVMThrow' 10 | 11 | const RefundVault = artifacts.require('RefundVault') 12 | 13 | contract('RefundVault', function ([_, owner, wallet, investor]) { 14 | 15 | const value = ether(42) 16 | 17 | beforeEach(async function () { 18 | this.vault = await RefundVault.new(wallet, {from: owner}) 19 | }) 20 | 21 | it('should accept contributions', async function () { 22 | await this.vault.deposit(investor, {value, from: owner}).should.be.fulfilled 23 | }) 24 | 25 | it('should not refund contribution during active state', async function () { 26 | await this.vault.deposit(investor, {value, from: owner}) 27 | await this.vault.refund(investor).should.be.rejectedWith(EVMThrow) 28 | }) 29 | 30 | it('only owner can enter refund mode', async function () { 31 | await this.vault.enableRefunds({from: _}).should.be.rejectedWith(EVMThrow) 32 | await this.vault.enableRefunds({from: owner}).should.be.fulfilled 33 | }) 34 | 35 | it('should refund contribution after entering refund mode', async function () { 36 | await this.vault.deposit(investor, {value, from: owner}) 37 | await this.vault.enableRefunds({from: owner}) 38 | 39 | const pre = web3.eth.getBalance(investor) 40 | await this.vault.refund(investor) 41 | const post = web3.eth.getBalance(investor) 42 | 43 | post.minus(pre).should.be.bignumber.equal(value) 44 | }) 45 | 46 | it('only owner can close', async function () { 47 | await this.vault.close({from: _}).should.be.rejectedWith(EVMThrow) 48 | await this.vault.close({from: owner}).should.be.fulfilled 49 | }) 50 | 51 | it('should forward funds to wallet after closing', async function () { 52 | await this.vault.deposit(investor, {value, from: owner}) 53 | 54 | const pre = web3.eth.getBalance(wallet) 55 | await this.vault.close({from: owner}) 56 | const post = web3.eth.getBalance(wallet) 57 | 58 | post.minus(pre).should.be.bignumber.equal(value) 59 | }) 60 | 61 | }) 62 | -------------------------------------------------------------------------------- /test/RefundableCrowdsale.js: -------------------------------------------------------------------------------- 1 | import ether from './helpers/ether' 2 | import {advanceBlock} from './helpers/advanceToBlock' 3 | import {increaseTimeTo, duration} from './helpers/increaseTime' 4 | import latestTime from './helpers/latestTime' 5 | import EVMThrow from './helpers/EVMThrow' 6 | 7 | const BigNumber = web3.BigNumber 8 | 9 | require('chai') 10 | .use(require('chai-as-promised')) 11 | .use(require('chai-bignumber')(BigNumber)) 12 | .should() 13 | 14 | const RefundableCrowdsale = artifacts.require('./helpers/RefundableCrowdsaleImpl.sol') 15 | 16 | contract('RefundableCrowdsale', function ([_, owner, wallet, investor]) { 17 | 18 | const rate = new BigNumber(1000) 19 | const goal = ether(800) 20 | const lessThanGoal = ether(750) 21 | 22 | before(async function() { 23 | //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc 24 | await advanceBlock() 25 | }) 26 | 27 | beforeEach(async function () { 28 | this.startTime = latestTime() + duration.weeks(1) 29 | this.endTime = this.startTime + duration.weeks(1) 30 | this.afterEndTime = this.endTime + duration.seconds(1) 31 | 32 | this.crowdsale = await RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, goal, {from: owner}) 33 | }) 34 | 35 | describe('creating a valid crowdsale', function () { 36 | 37 | it('should fail with zero goal', async function () { 38 | await RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0, {from: owner}).should.be.rejectedWith(EVMThrow); 39 | }) 40 | 41 | }); 42 | 43 | it('should deny refunds before end', async function () { 44 | await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow) 45 | await increaseTimeTo(this.startTime) 46 | await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow) 47 | }) 48 | 49 | it('should deny refunds after end if goal was reached', async function () { 50 | await increaseTimeTo(this.startTime) 51 | await this.crowdsale.sendTransaction({value: goal, from: investor}) 52 | await increaseTimeTo(this.afterEndTime) 53 | await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow) 54 | }) 55 | 56 | it('should allow refunds after end if goal was not reached', async function () { 57 | await increaseTimeTo(this.startTime) 58 | await this.crowdsale.sendTransaction({value: lessThanGoal, from: investor}) 59 | await increaseTimeTo(this.afterEndTime) 60 | 61 | await this.crowdsale.finalize({from: owner}) 62 | 63 | const pre = web3.eth.getBalance(investor) 64 | await this.crowdsale.claimRefund({from: investor, gasPrice: 0}) 65 | .should.be.fulfilled 66 | const post = web3.eth.getBalance(investor) 67 | 68 | post.minus(pre).should.be.bignumber.equal(lessThanGoal) 69 | }) 70 | 71 | it('should forward funds to wallet after end if goal was reached', async function () { 72 | await increaseTimeTo(this.startTime) 73 | await this.crowdsale.sendTransaction({value: goal, from: investor}) 74 | await increaseTimeTo(this.afterEndTime) 75 | 76 | const pre = web3.eth.getBalance(wallet) 77 | await this.crowdsale.finalize({from: owner}) 78 | const post = web3.eth.getBalance(wallet) 79 | 80 | post.minus(pre).should.be.bignumber.equal(goal) 81 | }) 82 | 83 | }) 84 | -------------------------------------------------------------------------------- /test/SafeERC20.js: -------------------------------------------------------------------------------- 1 | import EVMThrow from './helpers/EVMThrow'; 2 | 3 | require('chai') 4 | .use(require('chai-as-promised')) 5 | .should(); 6 | 7 | const SafeERC20Helper = artifacts.require('./helpers/SafeERC20Helper.sol'); 8 | 9 | contract('SafeERC20', function () { 10 | 11 | beforeEach(async function () { 12 | this.helper = await SafeERC20Helper.new(); 13 | }); 14 | 15 | it('should throw on failed transfer', async function () { 16 | await this.helper.doFailingTransfer().should.be.rejectedWith(EVMThrow); 17 | }); 18 | 19 | it('should throw on failed transferFrom', async function () { 20 | await this.helper.doFailingTransferFrom().should.be.rejectedWith(EVMThrow); 21 | }); 22 | 23 | it('should throw on failed approve', async function () { 24 | await this.helper.doFailingApprove().should.be.rejectedWith(EVMThrow); 25 | }); 26 | 27 | it('should not throw on succeeding transfer', async function () { 28 | await this.helper.doSucceedingTransfer().should.be.fulfilled; 29 | }); 30 | 31 | it('should not throw on succeeding transferFrom', async function () { 32 | await this.helper.doSucceedingTransferFrom().should.be.fulfilled; 33 | }); 34 | 35 | it('should not throw on succeeding approve', async function () { 36 | await this.helper.doSucceedingApprove().should.be.fulfilled; 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/SafeMath.js: -------------------------------------------------------------------------------- 1 | const assertJump = require('./helpers/assertJump'); 2 | var SafeMathMock = artifacts.require("./helpers/SafeMathMock.sol"); 3 | 4 | contract('SafeMath', function(accounts) { 5 | 6 | let safeMath; 7 | 8 | before(async function() { 9 | safeMath = await SafeMathMock.new(); 10 | }); 11 | 12 | it("multiplies correctly", async function() { 13 | let a = 5678; 14 | let b = 1234; 15 | let mult = await safeMath.multiply(a, b); 16 | let result = await safeMath.result(); 17 | assert.equal(result, a*b); 18 | }); 19 | 20 | it("adds correctly", async function() { 21 | let a = 5678; 22 | let b = 1234; 23 | let add = await safeMath.add(a, b); 24 | let result = await safeMath.result(); 25 | 26 | assert.equal(result, a+b); 27 | }); 28 | 29 | it("subtracts correctly", async function() { 30 | let a = 5678; 31 | let b = 1234; 32 | let subtract = await safeMath.subtract(a, b); 33 | let result = await safeMath.result(); 34 | 35 | assert.equal(result, a-b); 36 | }); 37 | 38 | it("should throw an error if subtraction result would be negative", async function () { 39 | let a = 1234; 40 | let b = 5678; 41 | try { 42 | let subtract = await safeMath.subtract(a, b); 43 | assert.fail('should have thrown before'); 44 | } catch(error) { 45 | assertJump(error); 46 | } 47 | }); 48 | 49 | it("should throw an error on addition overflow", async function() { 50 | let a = 115792089237316195423570985008687907853269984665640564039457584007913129639935; 51 | let b = 1; 52 | try { 53 | let add = await safeMath.add(a, b); 54 | assert.fail('should have thrown before'); 55 | } catch(error) { 56 | assertJump(error); 57 | } 58 | }); 59 | 60 | it("should throw an error on multiplication overflow", async function() { 61 | let a = 115792089237316195423570985008687907853269984665640564039457584007913129639933; 62 | let b = 2; 63 | try { 64 | let multiply = await safeMath.multiply(a, b); 65 | assert.fail('should have thrown before'); 66 | } catch(error) { 67 | assertJump(error); 68 | } 69 | }); 70 | 71 | }); 72 | -------------------------------------------------------------------------------- /test/SampleCrowdsale.js: -------------------------------------------------------------------------------- 1 | import ether from './helpers/ether' 2 | import {advanceBlock} from './helpers/advanceToBlock' 3 | import {increaseTimeTo, duration} from './helpers/increaseTime' 4 | import latestTime from './helpers/latestTime' 5 | import EVMThrow from './helpers/EVMThrow' 6 | 7 | const BigNumber = web3.BigNumber; 8 | 9 | const should = require('chai') 10 | .use(require('chai-as-promised')) 11 | .use(require('chai-bignumber')(BigNumber)) 12 | .should(); 13 | 14 | const SampleCrowdsale = artifacts.require('SampleCrowdsale'); 15 | const SampleCrowdsaleToken = artifacts.require('SampleCrowdsaleToken'); 16 | 17 | contract('Crowdsale', function ([owner, wallet, investor]) { 18 | 19 | const RATE = new BigNumber(10); 20 | const GOAL = ether(10); 21 | const CAP = ether(20); 22 | 23 | before(async function() { 24 | //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc 25 | await advanceBlock() 26 | }) 27 | 28 | beforeEach(async function () { 29 | this.startTime = latestTime() + duration.weeks(1); 30 | this.endTime = this.startTime + duration.weeks(1); 31 | this.afterEndTime = this.endTime + duration.seconds(1); 32 | 33 | this.crowdsale = await SampleCrowdsale.new(this.startTime, this.endTime, RATE, GOAL, CAP, wallet); 34 | this.token = SampleCrowdsaleToken.at(await this.crowdsale.token()); 35 | }); 36 | 37 | 38 | it('should create crowdsale with correct parameters', async function () { 39 | this.crowdsale.should.exist; 40 | this.token.should.exist; 41 | 42 | (await this.crowdsale.startTime()).should.be.bignumber.equal(this.startTime); 43 | (await this.crowdsale.endTime()).should.be.bignumber.equal(this.endTime); 44 | (await this.crowdsale.rate()).should.be.bignumber.equal(RATE); 45 | (await this.crowdsale.wallet()).should.be.equal(wallet); 46 | (await this.crowdsale.goal()).should.be.bignumber.equal(GOAL); 47 | (await this.crowdsale.cap()).should.be.bignumber.equal(CAP); 48 | }); 49 | 50 | it('should not accept payments before start', async function () { 51 | await this.crowdsale.send(ether(1)).should.be.rejectedWith(EVMThrow); 52 | await this.crowdsale.buyTokens(investor, {from: investor, value: ether(1)}).should.be.rejectedWith(EVMThrow); 53 | }); 54 | 55 | it('should accept payments during the sale', async function () { 56 | const investmentAmount = ether(1); 57 | const expectedTokenAmount = RATE.mul(investmentAmount); 58 | 59 | await increaseTimeTo(this.startTime); 60 | await this.crowdsale.buyTokens(investor, {value: investmentAmount, from: investor}).should.be.fulfilled; 61 | 62 | (await this.token.balanceOf(investor)).should.be.bignumber.equal(expectedTokenAmount); 63 | (await this.token.totalSupply()).should.be.bignumber.equal(expectedTokenAmount); 64 | }); 65 | 66 | it('should reject payments after end', async function () { 67 | await increaseTimeTo(this.afterEnd); 68 | await this.crowdsale.send(ether(1)).should.be.rejectedWith(EVMThrow); 69 | await this.crowdsale.buyTokens(investor, {value: ether(1), from: investor}).should.be.rejectedWith(EVMThrow); 70 | }); 71 | 72 | it('should reject payments over cap', async function () { 73 | await increaseTimeTo(this.startTime); 74 | await this.crowdsale.send(CAP); 75 | await this.crowdsale.send(1).should.be.rejectedWith(EVMThrow); 76 | }); 77 | 78 | it('should allow finalization and transfer funds to wallet if the goal is reached', async function () { 79 | await increaseTimeTo(this.startTime); 80 | await this.crowdsale.send(GOAL); 81 | 82 | const beforeFinalization = web3.eth.getBalance(wallet); 83 | await increaseTimeTo(this.afterEndTime); 84 | await this.crowdsale.finalize({from: owner}); 85 | const afterFinalization = web3.eth.getBalance(wallet); 86 | 87 | afterFinalization.minus(beforeFinalization).should.be.bignumber.equal(GOAL); 88 | }); 89 | 90 | it('should allow refunds if the goal is not reached', async function () { 91 | const balanceBeforeInvestment = web3.eth.getBalance(investor); 92 | 93 | await increaseTimeTo(this.startTime); 94 | await this.crowdsale.sendTransaction({value: ether(1), from: investor, gasPrice: 0}); 95 | await increaseTimeTo(this.afterEndTime); 96 | 97 | await this.crowdsale.finalize({from: owner}); 98 | await this.crowdsale.claimRefund({from: investor, gasPrice: 0}).should.be.fulfilled; 99 | 100 | const balanceAfterRefund = web3.eth.getBalance(investor); 101 | balanceBeforeInvestment.should.be.bignumber.equal(balanceAfterRefund); 102 | }); 103 | 104 | }); 105 | -------------------------------------------------------------------------------- /test/StandardToken.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assertJump = require('./helpers/assertJump'); 4 | const expectThrow = require('./helpers/expectThrow'); 5 | var StandardTokenMock = artifacts.require('./helpers/StandardTokenMock.sol'); 6 | 7 | contract('StandardToken', function(accounts) { 8 | 9 | let token; 10 | 11 | beforeEach(async function() { 12 | token = await StandardTokenMock.new(accounts[0], 100); 13 | }); 14 | 15 | it('should return the correct totalSupply after construction', async function() { 16 | let totalSupply = await token.totalSupply(); 17 | 18 | assert.equal(totalSupply, 100); 19 | }); 20 | 21 | it('should return the correct allowance amount after approval', async function() { 22 | let token = await StandardTokenMock.new(); 23 | await token.approve(accounts[1], 100); 24 | let allowance = await token.allowance(accounts[0], accounts[1]); 25 | 26 | assert.equal(allowance, 100); 27 | }); 28 | 29 | it('should return correct balances after transfer', async function() { 30 | let token = await StandardTokenMock.new(accounts[0], 100); 31 | await token.transfer(accounts[1], 100); 32 | let balance0 = await token.balanceOf(accounts[0]); 33 | assert.equal(balance0, 0); 34 | 35 | let balance1 = await token.balanceOf(accounts[1]); 36 | assert.equal(balance1, 100); 37 | }); 38 | 39 | it('should throw an error when trying to transfer more than balance', async function() { 40 | let token = await StandardTokenMock.new(accounts[0], 100); 41 | try { 42 | await token.transfer(accounts[1], 101); 43 | assert.fail('should have thrown before'); 44 | } catch(error) { 45 | assertJump(error); 46 | } 47 | }); 48 | 49 | it('should return correct balances after transfering from another account', async function() { 50 | let token = await StandardTokenMock.new(accounts[0], 100); 51 | await token.approve(accounts[1], 100); 52 | await token.transferFrom(accounts[0], accounts[2], 100, {from: accounts[1]}); 53 | 54 | let balance0 = await token.balanceOf(accounts[0]); 55 | assert.equal(balance0, 0); 56 | 57 | let balance1 = await token.balanceOf(accounts[2]); 58 | assert.equal(balance1, 100); 59 | 60 | let balance2 = await token.balanceOf(accounts[1]); 61 | assert.equal(balance2, 0); 62 | }); 63 | 64 | it('should throw an error when trying to transfer more than allowed', async function() { 65 | await token.approve(accounts[1], 99); 66 | try { 67 | await token.transferFrom(accounts[0], accounts[2], 100, {from: accounts[1]}); 68 | assert.fail('should have thrown before'); 69 | } catch (error) { 70 | assertJump(error); 71 | } 72 | }); 73 | 74 | it('should throw an error when trying to transferFrom more than _from has', async function() { 75 | let balance0 = await token.balanceOf(accounts[0]); 76 | await token.approve(accounts[1], 99); 77 | try { 78 | await token.transferFrom(accounts[0], accounts[2], balance0+1, {from: accounts[1]}); 79 | assert.fail('should have thrown before'); 80 | } catch (error) { 81 | assertJump(error); 82 | } 83 | }); 84 | 85 | describe('validating allowance updates to spender', function() { 86 | let preApproved; 87 | 88 | it('should start with zero', async function() { 89 | preApproved = await token.allowance(accounts[0], accounts[1]); 90 | assert.equal(preApproved, 0); 91 | }) 92 | 93 | it('should increase by 50 then decrease by 10', async function() { 94 | await token.increaseApproval(accounts[1], 50); 95 | let postIncrease = await token.allowance(accounts[0], accounts[1]); 96 | preApproved.plus(50).should.be.bignumber.equal(postIncrease); 97 | await token.decreaseApproval(accounts[1], 10); 98 | let postDecrease = await token.allowance(accounts[0], accounts[1]); 99 | postIncrease.minus(10).should.be.bignumber.equal(postDecrease); 100 | }) 101 | }); 102 | 103 | it('should increase by 50 then set to 0 when decreasing by more than 50', async function() { 104 | await token.approve(accounts[1], 50); 105 | await token.decreaseApproval(accounts[1], 60); 106 | let postDecrease = await token.allowance(accounts[0], accounts[1]); 107 | postDecrease.should.be.bignumber.equal(0); 108 | }); 109 | 110 | it('should throw an error when trying to transfer to 0x0', async function() { 111 | let token = await StandardTokenMock.new(accounts[0], 100); 112 | try { 113 | let transfer = await token.transfer(0x0, 100); 114 | assert.fail('should have thrown before'); 115 | } catch(error) { 116 | assertJump(error); 117 | } 118 | }); 119 | 120 | it('should throw an error when trying to transferFrom to 0x0', async function() { 121 | let token = await StandardTokenMock.new(accounts[0], 100); 122 | await token.approve(accounts[1], 100); 123 | try { 124 | let transfer = await token.transferFrom(accounts[0], 0x0, 100, {from: accounts[1]}); 125 | assert.fail('should have thrown before'); 126 | } catch(error) { 127 | assertJump(error); 128 | } 129 | }); 130 | 131 | }); 132 | -------------------------------------------------------------------------------- /test/TokenDestructible.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var TokenDestructible = artifacts.require('../contracts/lifecycle/TokenDestructible.sol'); 4 | var StandardTokenMock = artifacts.require("./helpers/StandardTokenMock.sol"); 5 | require('./helpers/transactionMined.js'); 6 | 7 | contract('TokenDestructible', function(accounts) { 8 | let destructible; 9 | 10 | beforeEach(async function() { 11 | destructible = await TokenDestructible.new({fron: accounts[0], value: web3.toWei('10', 'ether')}); 12 | }); 13 | 14 | it('should send balance to owner after destruction', async function() { 15 | let owner = await destructible.owner(); 16 | let initBalance = web3.eth.getBalance(owner); 17 | await destructible.destroy([], {from: owner}); 18 | let newBalance = web3.eth.getBalance(owner); 19 | assert.isTrue(newBalance > initBalance); 20 | }); 21 | 22 | it('should send tokens to owner after destruction', async function() { 23 | let owner = await destructible.owner(); 24 | let token = await StandardTokenMock.new(destructible.address, 100); 25 | let initContractBalance = await token.balanceOf(destructible.address); 26 | let initOwnerBalance = await token.balanceOf(owner); 27 | assert.equal(initContractBalance, 100); 28 | assert.equal(initOwnerBalance, 0); 29 | await destructible.destroy([token.address], {from: owner}); 30 | let newContractBalance = await token.balanceOf(destructible.address); 31 | let newOwnerBalance = await token.balanceOf(owner); 32 | assert.equal(newContractBalance, 0); 33 | assert.equal(newOwnerBalance, 100); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/TokenTimelock.js: -------------------------------------------------------------------------------- 1 | const BigNumber = web3.BigNumber 2 | 3 | require('chai') 4 | .use(require('chai-as-promised')) 5 | .use(require('chai-bignumber')(BigNumber)) 6 | .should() 7 | 8 | 9 | import latestTime from './helpers/latestTime' 10 | import {increaseTimeTo, duration} from './helpers/increaseTime' 11 | 12 | const MintableToken = artifacts.require('MintableToken') 13 | const TokenTimelock = artifacts.require('TokenTimelock') 14 | 15 | contract('TokenTimelock', function ([_, owner, beneficiary]) { 16 | 17 | const amount = new BigNumber(100) 18 | 19 | beforeEach(async function () { 20 | this.token = await MintableToken.new({from: owner}) 21 | this.releaseTime = latestTime() + duration.years(1) 22 | this.timelock = await TokenTimelock.new(this.token.address, beneficiary, this.releaseTime) 23 | await this.token.mint(this.timelock.address, amount, {from: owner}) 24 | }) 25 | 26 | it('cannot be released before time limit', async function () { 27 | await this.timelock.release().should.be.rejected 28 | }) 29 | 30 | it('cannot be released just before time limit', async function () { 31 | await increaseTimeTo(this.releaseTime - duration.seconds(3)) 32 | await this.timelock.release().should.be.rejected 33 | }) 34 | 35 | it('can be released just after limit', async function () { 36 | await increaseTimeTo(this.releaseTime + duration.seconds(1)) 37 | await this.timelock.release().should.be.fulfilled 38 | const balance = await this.token.balanceOf(beneficiary) 39 | balance.should.be.bignumber.equal(amount) 40 | }) 41 | 42 | it('can be released after time limit', async function () { 43 | await increaseTimeTo(this.releaseTime + duration.years(1)) 44 | await this.timelock.release().should.be.fulfilled 45 | const balance = await this.token.balanceOf(beneficiary) 46 | balance.should.be.bignumber.equal(amount) 47 | }) 48 | 49 | it('cannot be released twice', async function () { 50 | await increaseTimeTo(this.releaseTime + duration.years(1)) 51 | await this.timelock.release().should.be.fulfilled 52 | await this.timelock.release().should.be.rejected 53 | const balance = await this.token.balanceOf(beneficiary) 54 | balance.should.be.bignumber.equal(amount) 55 | }) 56 | 57 | }) 58 | -------------------------------------------------------------------------------- /test/TokenVesting.js: -------------------------------------------------------------------------------- 1 | const BigNumber = web3.BigNumber 2 | 3 | require('chai') 4 | .use(require('chai-as-promised')) 5 | .use(require('chai-bignumber')(BigNumber)) 6 | .should(); 7 | 8 | import EVMThrow from './helpers/EVMThrow' 9 | import latestTime from './helpers/latestTime'; 10 | import {increaseTimeTo, duration} from './helpers/increaseTime'; 11 | 12 | const MintableToken = artifacts.require('MintableToken'); 13 | const TokenVesting = artifacts.require('TokenVesting'); 14 | 15 | contract('TokenVesting', function ([_, owner, beneficiary]) { 16 | 17 | const amount = new BigNumber(1000); 18 | 19 | beforeEach(async function () { 20 | this.token = await MintableToken.new({ from: owner }); 21 | 22 | this.start = latestTime() + duration.minutes(1); // +1 minute so it starts after contract instantiation 23 | this.cliff = duration.years(1); 24 | this.duration = duration.years(2); 25 | 26 | this.vesting = await TokenVesting.new(beneficiary, this.start, this.cliff, this.duration, true, { from: owner }); 27 | 28 | await this.token.mint(this.vesting.address, amount, { from: owner }); 29 | }); 30 | 31 | it('cannot be released before cliff', async function () { 32 | await this.vesting.release(this.token.address).should.be.rejectedWith(EVMThrow); 33 | }); 34 | 35 | it('can be released after cliff', async function () { 36 | await increaseTimeTo(this.start + this.cliff + duration.weeks(1)); 37 | await this.vesting.release(this.token.address).should.be.fulfilled; 38 | }); 39 | 40 | it('should release proper amount after cliff', async function () { 41 | await increaseTimeTo(this.start + this.cliff); 42 | 43 | const { receipt } = await this.vesting.release(this.token.address); 44 | const releaseTime = web3.eth.getBlock(receipt.blockNumber).timestamp; 45 | 46 | const balance = await this.token.balanceOf(beneficiary); 47 | balance.should.bignumber.equal(amount.mul(releaseTime - this.start).div(this.duration).floor()); 48 | }); 49 | 50 | it('should linearly release tokens during vesting period', async function () { 51 | const vestingPeriod = this.duration - this.cliff; 52 | const checkpoints = 4; 53 | 54 | for (let i = 1; i <= checkpoints; i++) { 55 | const now = this.start + this.cliff + i * (vestingPeriod / checkpoints); 56 | await increaseTimeTo(now); 57 | 58 | await this.vesting.release(this.token.address); 59 | const balance = await this.token.balanceOf(beneficiary); 60 | const expectedVesting = amount.mul(now - this.start).div(this.duration).floor(); 61 | 62 | balance.should.bignumber.equal(expectedVesting); 63 | } 64 | }); 65 | 66 | it('should have released all after end', async function () { 67 | await increaseTimeTo(this.start + this.duration); 68 | await this.vesting.release(this.token.address); 69 | const balance = await this.token.balanceOf(beneficiary); 70 | balance.should.bignumber.equal(amount); 71 | }); 72 | 73 | it('should be revoked by owner if revocable is set', async function () { 74 | await this.vesting.revoke(this.token.address, { from: owner }).should.be.fulfilled; 75 | }); 76 | 77 | it('should fail to be revoked by owner if revocable not set', async function () { 78 | const vesting = await TokenVesting.new(beneficiary, this.start, this.cliff, this.duration, false, { from: owner } ); 79 | await vesting.revoke(this.token.address, { from: owner }).should.be.rejectedWith(EVMThrow); 80 | }); 81 | 82 | it('should return the non-vested tokens when revoked by owner', async function () { 83 | await increaseTimeTo(this.start + this.cliff + duration.weeks(12)); 84 | 85 | const vested = await this.vesting.vestedAmount(this.token.address); 86 | 87 | await this.vesting.revoke(this.token.address, { from: owner }); 88 | 89 | const ownerBalance = await this.token.balanceOf(owner); 90 | ownerBalance.should.bignumber.equal(amount.sub(vested)); 91 | }); 92 | 93 | it('should keep the vested tokens when revoked by owner', async function () { 94 | await increaseTimeTo(this.start + this.cliff + duration.weeks(12)); 95 | 96 | const vestedPre = await this.vesting.vestedAmount(this.token.address); 97 | 98 | await this.vesting.revoke(this.token.address, { from: owner }); 99 | 100 | const vestedPost = await this.vesting.vestedAmount(this.token.address); 101 | 102 | vestedPre.should.bignumber.equal(vestedPost); 103 | }); 104 | 105 | it('should fail to be revoked a second time', async function () { 106 | await increaseTimeTo(this.start + this.cliff + duration.weeks(12)); 107 | 108 | const vested = await this.vesting.vestedAmount(this.token.address); 109 | 110 | await this.vesting.revoke(this.token.address, { from: owner }); 111 | 112 | await this.vesting.revoke(this.token.address, { from: owner }).should.be.rejectedWith(EVMThrow); 113 | }); 114 | 115 | }); 116 | -------------------------------------------------------------------------------- /test/helpers/BasicTokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import '../../contracts/token/BasicToken.sol'; 5 | 6 | 7 | // mock class using BasicToken 8 | contract BasicTokenMock is BasicToken { 9 | 10 | function BasicTokenMock(address initialAccount, uint256 initialBalance) { 11 | balances[initialAccount] = initialBalance; 12 | totalSupply = initialBalance; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /test/helpers/BurnableTokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.13; 2 | 3 | import '../../contracts/token/BurnableToken.sol'; 4 | 5 | contract BurnableTokenMock is BurnableToken { 6 | 7 | function BurnableTokenMock(address initialAccount, uint initialBalance) { 8 | balances[initialAccount] = initialBalance; 9 | totalSupply = initialBalance; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /test/helpers/CappedCrowdsaleImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import '../../contracts/crowdsale/CappedCrowdsale.sol'; 5 | 6 | 7 | contract CappedCrowdsaleImpl is CappedCrowdsale { 8 | 9 | function CappedCrowdsaleImpl ( 10 | uint256 _startTime, 11 | uint256 _endTime, 12 | uint256 _rate, 13 | address _wallet, 14 | uint256 _cap 15 | ) 16 | Crowdsale(_startTime, _endTime, _rate, _wallet) 17 | CappedCrowdsale(_cap) 18 | { 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /test/helpers/DayLimitMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | import "../../contracts/DayLimit.sol"; 3 | 4 | contract DayLimitMock is DayLimit { 5 | uint256 public totalSpending; 6 | 7 | function DayLimitMock(uint256 _value) DayLimit(_value) { 8 | totalSpending = 0; 9 | } 10 | 11 | function attemptSpend(uint256 _value) external limitedDaily(_value) { 12 | totalSpending += _value; 13 | } 14 | 15 | function setDailyLimit(uint256 _newLimit) external { 16 | _setDailyLimit(_newLimit); 17 | } 18 | 19 | function resetSpentToday() external { 20 | _resetSpentToday(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /test/helpers/ERC23TokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import '../../contracts/token/BasicToken.sol'; 5 | 6 | 7 | contract ERC23ContractInterface { 8 | function tokenFallback(address _from, uint256 _value, bytes _data) external; 9 | } 10 | 11 | contract ERC23TokenMock is BasicToken { 12 | 13 | function ERC23TokenMock(address initialAccount, uint256 initialBalance) { 14 | balances[initialAccount] = initialBalance; 15 | totalSupply = initialBalance; 16 | } 17 | 18 | // ERC23 compatible transfer function (except the name) 19 | function transferERC23(address _to, uint256 _value, bytes _data) 20 | returns (bool success) 21 | { 22 | transfer(_to, _value); 23 | bool is_contract = false; 24 | assembly { 25 | is_contract := not(iszero(extcodesize(_to))) 26 | } 27 | if(is_contract) { 28 | ERC23ContractInterface receiver = ERC23ContractInterface(_to); 29 | receiver.tokenFallback(msg.sender, _value, _data); 30 | } 31 | return true; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/helpers/EVMThrow.js: -------------------------------------------------------------------------------- 1 | export default 'invalid opcode' 2 | -------------------------------------------------------------------------------- /test/helpers/FinalizableCrowdsaleImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import '../../contracts/crowdsale/FinalizableCrowdsale.sol'; 5 | 6 | 7 | contract FinalizableCrowdsaleImpl is FinalizableCrowdsale { 8 | 9 | function FinalizableCrowdsaleImpl ( 10 | uint256 _startTime, 11 | uint256 _endTime, 12 | uint256 _rate, 13 | address _wallet 14 | ) 15 | Crowdsale(_startTime, _endTime, _rate, _wallet) 16 | FinalizableCrowdsale() 17 | { 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /test/helpers/ForceEther.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | // @title Force Ether into a contract. 4 | // @notice even 5 | // if the contract is not payable. 6 | // @notice To use, construct the contract with the target as argument. 7 | // @author Remco Bloemen 8 | contract ForceEther { 9 | 10 | function ForceEther() payable { } 11 | 12 | function destroyAndSend(address _recipient) { 13 | selfdestruct(_recipient); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/helpers/HasNoEtherTest.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import "../../contracts/ownership/HasNoEther.sol"; 4 | 5 | contract HasNoEtherTest is HasNoEther { 6 | 7 | // Constructor with explicit payable — should still fail 8 | function HasNoEtherTest() payable { 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /test/helpers/InsecureTargetBounty.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import {Bounty, Target} from "../../contracts/Bounty.sol"; 5 | 6 | 7 | contract InsecureTargetMock is Target { 8 | function checkInvariant() returns(bool){ 9 | return false; 10 | } 11 | } 12 | 13 | contract InsecureTargetBounty is Bounty { 14 | function deployContract() internal returns (address) { 15 | return new InsecureTargetMock(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/helpers/LimitBalanceMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import '../../contracts/LimitBalance.sol'; 5 | 6 | 7 | // mock class using LimitBalance 8 | contract LimitBalanceMock is LimitBalance(1000) { 9 | 10 | function limitedDeposit() payable limitedPayable { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /test/helpers/PausableMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import '../../contracts/lifecycle/Pausable.sol'; 5 | 6 | 7 | // mock class using Pausable 8 | contract PausableMock is Pausable { 9 | bool public drasticMeasureTaken; 10 | uint256 public count; 11 | 12 | function PausableMock() { 13 | drasticMeasureTaken = false; 14 | count = 0; 15 | } 16 | 17 | function normalProcess() external whenNotPaused { 18 | count++; 19 | } 20 | 21 | function drasticMeasure() external whenPaused { 22 | drasticMeasureTaken = true; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /test/helpers/PausableTokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import '../../contracts/token/PausableToken.sol'; 4 | 5 | // mock class using PausableToken 6 | contract PausableTokenMock is PausableToken { 7 | 8 | function PausableTokenMock(address initialAccount, uint initialBalance) { 9 | balances[initialAccount] = initialBalance; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /test/helpers/PullPaymentMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import '../../contracts/payment/PullPayment.sol'; 5 | 6 | 7 | // mock class using PullPayment 8 | contract PullPaymentMock is PullPayment { 9 | 10 | function PullPaymentMock() payable { } 11 | 12 | // test helper function to call asyncSend 13 | function callSend(address dest, uint256 amount) { 14 | asyncSend(dest, amount); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /test/helpers/ReentrancyAttack.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | contract ReentrancyAttack { 4 | 5 | function callSender(bytes4 data) { 6 | if(!msg.sender.call(data)) { 7 | throw; 8 | } 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /test/helpers/ReentrancyMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import '../../contracts/ReentrancyGuard.sol'; 4 | import './ReentrancyAttack.sol'; 5 | 6 | contract ReentrancyMock is ReentrancyGuard { 7 | 8 | uint256 public counter; 9 | 10 | function ReentrancyMock() { 11 | counter = 0; 12 | } 13 | 14 | function count() private { 15 | counter += 1; 16 | } 17 | 18 | function countLocalRecursive(uint256 n) public nonReentrant { 19 | if(n > 0) { 20 | count(); 21 | countLocalRecursive(n - 1); 22 | } 23 | } 24 | 25 | function countThisRecursive(uint256 n) public nonReentrant { 26 | bytes4 func = bytes4(keccak256("countThisRecursive(uint256)")); 27 | if(n > 0) { 28 | count(); 29 | bool result = this.call(func, n - 1); 30 | if(result != true) { 31 | throw; 32 | } 33 | } 34 | } 35 | 36 | function countAndCall(ReentrancyAttack attacker) public nonReentrant { 37 | count(); 38 | bytes4 func = bytes4(keccak256("callback()")); 39 | attacker.callSender(func); 40 | } 41 | 42 | function callback() external nonReentrant { 43 | count(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /test/helpers/RefundableCrowdsaleImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import '../../contracts/crowdsale/RefundableCrowdsale.sol'; 5 | 6 | 7 | contract RefundableCrowdsaleImpl is RefundableCrowdsale { 8 | 9 | function RefundableCrowdsaleImpl ( 10 | uint256 _startTime, 11 | uint256 _endTime, 12 | uint256 _rate, 13 | address _wallet, 14 | uint256 _goal 15 | ) 16 | Crowdsale(_startTime, _endTime, _rate, _wallet) 17 | RefundableCrowdsale(_goal) 18 | { 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /test/helpers/SafeERC20Helper.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import '../../contracts/token/ERC20.sol'; 4 | import '../../contracts/token/SafeERC20.sol'; 5 | 6 | contract ERC20FailingMock is ERC20 { 7 | function transfer(address, uint256) returns (bool) { 8 | return false; 9 | } 10 | 11 | function transferFrom(address, address, uint256) returns (bool) { 12 | return false; 13 | } 14 | 15 | function approve(address, uint256) returns (bool) { 16 | return false; 17 | } 18 | 19 | function balanceOf(address) constant returns (uint256) { 20 | return 0; 21 | } 22 | 23 | function allowance(address, address) constant returns (uint256) { 24 | return 0; 25 | } 26 | } 27 | 28 | contract ERC20SucceedingMock is ERC20 { 29 | function transfer(address, uint256) returns (bool) { 30 | return true; 31 | } 32 | 33 | function transferFrom(address, address, uint256) returns (bool) { 34 | return true; 35 | } 36 | 37 | function approve(address, uint256) returns (bool) { 38 | return true; 39 | } 40 | 41 | function balanceOf(address) constant returns (uint256) { 42 | return 0; 43 | } 44 | 45 | function allowance(address, address) constant returns (uint256) { 46 | return 0; 47 | } 48 | } 49 | 50 | contract SafeERC20Helper { 51 | using SafeERC20 for ERC20; 52 | 53 | ERC20 failing; 54 | ERC20 succeeding; 55 | 56 | function SafeERC20Helper() { 57 | failing = new ERC20FailingMock(); 58 | succeeding = new ERC20SucceedingMock(); 59 | } 60 | 61 | function doFailingTransfer() { 62 | failing.safeTransfer(0, 0); 63 | } 64 | 65 | function doFailingTransferFrom() { 66 | failing.safeTransferFrom(0, 0, 0); 67 | } 68 | 69 | function doFailingApprove() { 70 | failing.safeApprove(0, 0); 71 | } 72 | 73 | function doSucceedingTransfer() { 74 | succeeding.safeTransfer(0, 0); 75 | } 76 | 77 | function doSucceedingTransferFrom() { 78 | succeeding.safeTransferFrom(0, 0, 0); 79 | } 80 | 81 | function doSucceedingApprove() { 82 | succeeding.safeApprove(0, 0); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /test/helpers/SafeMathMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import '../../contracts/math/SafeMath.sol'; 5 | 6 | 7 | contract SafeMathMock { 8 | uint256 public result; 9 | 10 | function multiply(uint256 a, uint256 b) { 11 | result = SafeMath.mul(a, b); 12 | } 13 | 14 | function subtract(uint256 a, uint256 b) { 15 | result = SafeMath.sub(a, b); 16 | } 17 | 18 | function add(uint256 a, uint256 b) { 19 | result = SafeMath.add(a, b); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/helpers/SecureTargetBounty.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import {Bounty, Target} from "../../contracts/Bounty.sol"; 5 | 6 | 7 | contract SecureTargetMock is Target { 8 | function checkInvariant() returns(bool) { 9 | return true; 10 | } 11 | } 12 | 13 | contract SecureTargetBounty is Bounty { 14 | function deployContract() internal returns (address) { 15 | return new SecureTargetMock(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/helpers/StandardTokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import '../../contracts/token/StandardToken.sol'; 5 | 6 | 7 | // mock class using StandardToken 8 | contract StandardTokenMock is StandardToken { 9 | 10 | function StandardTokenMock(address initialAccount, uint256 initialBalance) { 11 | balances[initialAccount] = initialBalance; 12 | totalSupply = initialBalance; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /test/helpers/advanceToBlock.js: -------------------------------------------------------------------------------- 1 | export function advanceBlock() { 2 | return new Promise((resolve, reject) => { 3 | web3.currentProvider.sendAsync({ 4 | jsonrpc: '2.0', 5 | method: 'evm_mine', 6 | id: Date.now(), 7 | }, (err, res) => { 8 | return err ? reject(err) : resolve(res) 9 | }) 10 | }) 11 | } 12 | 13 | // Advances the block number so that the last mined block is `number`. 14 | export default async function advanceToBlock(number) { 15 | if (web3.eth.blockNumber > number) { 16 | throw Error(`block number ${number} is in the past (current is ${web3.eth.blockNumber})`) 17 | } 18 | 19 | while (web3.eth.blockNumber < number) { 20 | await advanceBlock() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/helpers/assertJump.js: -------------------------------------------------------------------------------- 1 | module.exports = function(error) { 2 | assert.isAbove(error.message.search('invalid opcode'), -1, 'Invalid opcode error must be returned'); 3 | } 4 | -------------------------------------------------------------------------------- /test/helpers/ether.js: -------------------------------------------------------------------------------- 1 | export default function ether(n) { 2 | return new web3.BigNumber(web3.toWei(n, 'ether')) 3 | } 4 | -------------------------------------------------------------------------------- /test/helpers/expectThrow.js: -------------------------------------------------------------------------------- 1 | export default async promise => { 2 | try { 3 | await promise; 4 | } catch (error) { 5 | // TODO: Check jump destination to destinguish between a throw 6 | // and an actual invalid jump. 7 | const invalidOpcode = error.message.search('invalid opcode') >= 0; 8 | // TODO: When we contract A calls contract B, and B throws, instead 9 | // of an 'invalid jump', we get an 'out of gas' error. How do 10 | // we distinguish this from an actual out of gas event? (The 11 | // testrpc log actually show an 'invalid jump' event.) 12 | const outOfGas = error.message.search('out of gas') >= 0; 13 | assert( 14 | invalidOpcode || outOfGas, 15 | "Expected throw, got '" + error + "' instead", 16 | ); 17 | return; 18 | } 19 | assert.fail('Expected throw not received'); 20 | }; 21 | -------------------------------------------------------------------------------- /test/helpers/hashMessage.js: -------------------------------------------------------------------------------- 1 | import utils from 'ethereumjs-util'; 2 | 3 | // Hash and add same prefix to the hash that testrpc use. 4 | module.exports = function(message) { 5 | const messageHex = new Buffer(utils.sha3(message).toString('hex'), 'hex'); 6 | const prefix = utils.toBuffer('\u0019Ethereum Signed Message:\n' + messageHex.length.toString()); 7 | return utils.bufferToHex( utils.sha3(Buffer.concat([prefix, messageHex])) ); 8 | }; 9 | -------------------------------------------------------------------------------- /test/helpers/increaseTime.js: -------------------------------------------------------------------------------- 1 | import latestTime from './latestTime' 2 | 3 | // Increases testrpc time by the passed duration in seconds 4 | export default function increaseTime(duration) { 5 | const id = Date.now() 6 | 7 | return new Promise((resolve, reject) => { 8 | web3.currentProvider.sendAsync({ 9 | jsonrpc: '2.0', 10 | method: 'evm_increaseTime', 11 | params: [duration], 12 | id: id, 13 | }, err1 => { 14 | if (err1) return reject(err1) 15 | 16 | web3.currentProvider.sendAsync({ 17 | jsonrpc: '2.0', 18 | method: 'evm_mine', 19 | id: id+1, 20 | }, (err2, res) => { 21 | return err2 ? reject(err2) : resolve(res) 22 | }) 23 | }) 24 | }) 25 | } 26 | 27 | /** 28 | * Beware that due to the need of calling two separate testrpc methods and rpc calls overhead 29 | * it's hard to increase time precisely to a target point so design your test to tolerate 30 | * small fluctuations from time to time. 31 | * 32 | * @param target time in seconds 33 | */ 34 | export function increaseTimeTo(target) { 35 | let now = latestTime(); 36 | if (target < now) throw Error(`Cannot increase current time(${now}) to a moment in the past(${target})`); 37 | let diff = target - now; 38 | return increaseTime(diff); 39 | } 40 | 41 | export const duration = { 42 | seconds: function(val) { return val}, 43 | minutes: function(val) { return val * this.seconds(60) }, 44 | hours: function(val) { return val * this.minutes(60) }, 45 | days: function(val) { return val * this.hours(24) }, 46 | weeks: function(val) { return val * this.days(7) }, 47 | years: function(val) { return val * this.days(365)} 48 | }; 49 | -------------------------------------------------------------------------------- /test/helpers/latestTime.js: -------------------------------------------------------------------------------- 1 | // Returns the time of the last mined block in seconds 2 | export default function latestTime() { 3 | return web3.eth.getBlock('latest').timestamp; 4 | } 5 | -------------------------------------------------------------------------------- /test/helpers/merkleTree.js: -------------------------------------------------------------------------------- 1 | import { sha3, bufferToHex } from "ethereumjs-util"; 2 | 3 | export default class MerkleTree { 4 | constructor(elements) { 5 | // Filter empty strings and hash elements 6 | this.elements = elements.filter(el => el).map(el => sha3(el)); 7 | 8 | // Deduplicate elements 9 | this.elements = this.bufDedup(this.elements); 10 | // Sort elements 11 | this.elements.sort(Buffer.compare); 12 | 13 | // Create layers 14 | this.layers = this.getLayers(this.elements); 15 | } 16 | 17 | getLayers(elements) { 18 | if (elements.length == 0) { 19 | return [[""]]; 20 | } 21 | 22 | const layers = []; 23 | layers.push(elements); 24 | 25 | // Get next layer until we reach the root 26 | while (layers[layers.length - 1].length > 1) { 27 | layers.push(this.getNextLayer(layers[layers.length - 1])); 28 | } 29 | 30 | return layers; 31 | } 32 | 33 | getNextLayer(elements) { 34 | return elements.reduce((layer, el, idx, arr) => { 35 | if (idx % 2 === 0) { 36 | // Hash the current element with its pair element 37 | layer.push(this.combinedHash(el, arr[idx + 1])); 38 | } 39 | 40 | return layer; 41 | }, []); 42 | } 43 | 44 | combinedHash(first, second) { 45 | if (!first) { return second; } 46 | if (!second) { return first; } 47 | 48 | return sha3(this.sortAndConcat(first, second)); 49 | } 50 | 51 | getRoot() { 52 | return this.layers[this.layers.length - 1][0]; 53 | } 54 | 55 | getHexRoot() { 56 | return bufferToHex(this.getRoot()); 57 | } 58 | 59 | getProof(el) { 60 | let idx = this.bufIndexOf(el, this.elements); 61 | 62 | if (idx === -1) { 63 | throw new Error("Element does not exist in Merkle tree"); 64 | } 65 | 66 | return this.layers.reduce((proof, layer) => { 67 | const pairElement = this.getPairElement(idx, layer); 68 | 69 | if (pairElement) { 70 | proof.push(pairElement); 71 | } 72 | 73 | idx = Math.floor(idx / 2); 74 | 75 | return proof; 76 | }, []); 77 | } 78 | 79 | getHexProof(el) { 80 | const proof = this.getProof(el); 81 | 82 | return this.bufArrToHex(proof); 83 | } 84 | 85 | getPairElement(idx, layer) { 86 | const pairIdx = idx % 2 === 0 ? idx + 1 : idx - 1; 87 | 88 | if (pairIdx < layer.length) { 89 | return layer[pairIdx]; 90 | } else { 91 | return null; 92 | } 93 | } 94 | 95 | bufIndexOf(el, arr) { 96 | let hash; 97 | 98 | // Convert element to 32 byte hash if it is not one already 99 | if (el.length !== 32 || !Buffer.isBuffer(el)) { 100 | hash = sha3(el); 101 | } else { 102 | hash = el; 103 | } 104 | 105 | for (let i = 0; i < arr.length; i++) { 106 | if (hash.equals(arr[i])) { 107 | return i; 108 | } 109 | } 110 | 111 | return -1; 112 | } 113 | 114 | bufDedup(elements) { 115 | return elements.filter((el, idx) => { 116 | return this.bufIndexOf(el, elements) === idx; 117 | }); 118 | } 119 | 120 | bufArrToHex(arr) { 121 | if (arr.some(el => !Buffer.isBuffer(el))) { 122 | throw new Error("Array is not an array of buffers"); 123 | } 124 | 125 | return "0x" + arr.map(el => el.toString("hex")).join(""); 126 | } 127 | 128 | sortAndConcat(...args) { 129 | return Buffer.concat([...args].sort(Buffer.compare)); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /test/helpers/timer.js: -------------------------------------------------------------------------------- 1 | // timer for tests specific to testrpc 2 | module.exports = s => { 3 | return new Promise((resolve, reject) => { 4 | web3.currentProvider.sendAsync({ 5 | jsonrpc: '2.0', 6 | method: 'evm_increaseTime', 7 | params: [s], // 60 seaconds, may need to be hex, I forget 8 | id: new Date().getTime() // Id of the request; anything works, really 9 | }, function(err) { 10 | if (err) return reject(err); 11 | resolve(); 12 | }); 13 | //setTimeout(() => resolve(), s * 1000 + 600) // 600ms breathing room for testrpc to sync 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /test/helpers/toPromise.js: -------------------------------------------------------------------------------- 1 | export default func => 2 | (...args) => 3 | new Promise((accept, reject) => 4 | func(...args, (error, data) => error ? reject(error) : accept(data))); 5 | -------------------------------------------------------------------------------- /test/helpers/transactionMined.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //from https://gist.github.com/xavierlepretre/88682e871f4ad07be4534ae560692ee6 4 | module.export = web3.eth.transactionMined = function (txnHash, interval) { 5 | var transactionReceiptAsync; 6 | interval = interval ? interval : 500; 7 | transactionReceiptAsync = function(txnHash, resolve, reject) { 8 | try { 9 | var receipt = web3.eth.getTransactionReceipt(txnHash); 10 | if (receipt === null) { 11 | setTimeout(function () { 12 | transactionReceiptAsync(txnHash, resolve, reject); 13 | }, interval); 14 | } else { 15 | resolve(receipt); 16 | } 17 | } catch(e) { 18 | reject(e); 19 | } 20 | }; 21 | 22 | if (Array.isArray(txnHash)) { 23 | var promises = []; 24 | txnHash.forEach(function (oneTxHash) { 25 | promises.push( 26 | web3.eth.getTransactionReceiptMined(oneTxHash, interval)); 27 | }); 28 | return Promise.all(promises); 29 | } else { 30 | return new Promise(function (resolve, reject) { 31 | transactionReceiptAsync(txnHash, resolve, reject); 32 | }); 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | require('babel-register'); 2 | require('babel-polyfill'); 3 | 4 | var provider; 5 | var HDWalletProvider = require('truffle-hdwallet-provider'); 6 | var mnemonic = '[REDACTED]'; 7 | 8 | if (!process.env.SOLIDITY_COVERAGE){ 9 | provider = new HDWalletProvider(mnemonic, 'https://ropsten.infura.io/') 10 | } 11 | 12 | 13 | module.exports = { 14 | networks: { 15 | development: { 16 | host: 'localhost', 17 | port: 8545, 18 | network_id: '*' 19 | }, 20 | ropsten: { 21 | provider: provider, 22 | network_id: 3 // official id of the ropsten network 23 | }, 24 | coverage: { 25 | host: "localhost", 26 | network_id: "*", 27 | port: 8555, 28 | gas: 0xfffffffffff, 29 | gasPrice: 0x01 30 | } 31 | } 32 | }; 33 | --------------------------------------------------------------------------------