├── .babelrc ├── .env.example ├── .eslintrc ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .jshintrc ├── .node-version ├── .solcover.js ├── .soliumignore ├── .soliumrc.json ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── audit └── ZeppelinAudit.md ├── contracts ├── .npmignore ├── AddressUtils.sol ├── Bounty.sol ├── DayLimit.sol ├── ECRecovery.sol ├── LimitBalance.sol ├── MerkleProof.sol ├── ReentrancyGuard.sol ├── access │ └── SignatureBouncer.sol ├── crowdsale │ ├── Crowdsale.sol │ ├── distribution │ │ ├── FinalizableCrowdsale.sol │ │ ├── PostDeliveryCrowdsale.sol │ │ ├── RefundableCrowdsale.sol │ │ └── utils │ │ │ └── RefundVault.sol │ ├── emission │ │ ├── AllowanceCrowdsale.sol │ │ └── MintedCrowdsale.sol │ ├── price │ │ └── IncreasingPriceCrowdsale.sol │ └── validation │ │ ├── CappedCrowdsale.sol │ │ ├── IndividuallyCappedCrowdsale.sol │ │ ├── TimedCrowdsale.sol │ │ └── WhitelistedCrowdsale.sol ├── examples │ ├── SampleCrowdsale.sol │ ├── SimpleSavingsWallet.sol │ └── SimpleToken.sol ├── lifecycle │ ├── Destructible.sol │ ├── Pausable.sol │ └── TokenDestructible.sol ├── math │ ├── Math.sol │ └── SafeMath.sol ├── mocks │ ├── AllowanceCrowdsaleImpl.sol │ ├── BasicTokenMock.sol │ ├── BouncerMock.sol │ ├── BurnableTokenMock.sol │ ├── CappedCrowdsaleImpl.sol │ ├── DayLimitMock.sol │ ├── DetailedERC20Mock.sol │ ├── ECRecoveryMock.sol │ ├── ERC223TokenMock.sol │ ├── ERC721BasicTokenMock.sol │ ├── ERC721ReceiverMock.sol │ ├── ERC721TokenMock.sol │ ├── ERC827TokenMock.sol │ ├── FinalizableCrowdsaleImpl.sol │ ├── ForceEther.sol │ ├── HasNoEtherTest.sol │ ├── IncreasingPriceCrowdsaleImpl.sol │ ├── IndividuallyCappedCrowdsaleImpl.sol │ ├── InsecureTargetBounty.sol │ ├── LimitBalanceMock.sol │ ├── MathMock.sol │ ├── MerkleProofWrapper.sol │ ├── MessageHelper.sol │ ├── MintedCrowdsaleImpl.sol │ ├── PausableMock.sol │ ├── PausableTokenMock.sol │ ├── PostDeliveryCrowdsaleImpl.sol │ ├── PullPaymentMock.sol │ ├── RBACMock.sol │ ├── ReentrancyAttack.sol │ ├── ReentrancyMock.sol │ ├── RefundableCrowdsaleImpl.sol │ ├── SafeERC20Helper.sol │ ├── SafeMathMock.sol │ ├── SecureTargetBounty.sol │ ├── StandardBurnableTokenMock.sol │ ├── StandardTokenMock.sol │ ├── TimedCrowdsaleImpl.sol │ ├── WhitelistMock.sol │ └── WhitelistedCrowdsaleImpl.sol ├── ownership │ ├── CanReclaimToken.sol │ ├── Claimable.sol │ ├── Contactable.sol │ ├── DelayedClaimable.sol │ ├── HasNoContracts.sol │ ├── HasNoEther.sol │ ├── HasNoTokens.sol │ ├── Heritable.sol │ ├── NoOwner.sol │ ├── Ownable.sol │ ├── Whitelist.sol │ └── rbac │ │ ├── RBAC.sol │ │ ├── RBACWithAdmin.sol │ │ └── Roles.sol ├── payment │ ├── PullPayment.sol │ └── SplitPayment.sol └── token │ ├── ERC20 │ ├── BasicToken.sol │ ├── BurnableToken.sol │ ├── CappedToken.sol │ ├── DetailedERC20.sol │ ├── ERC20.sol │ ├── ERC20Basic.sol │ ├── MintableToken.sol │ ├── PausableToken.sol │ ├── RBACMintableToken.sol │ ├── SafeERC20.sol │ ├── StandardBurnableToken.sol │ ├── StandardToken.sol │ ├── TokenTimelock.sol │ └── TokenVesting.sol │ ├── ERC721 │ ├── DeprecatedERC721.sol │ ├── ERC721.sol │ ├── ERC721Basic.sol │ ├── ERC721BasicToken.sol │ ├── ERC721Holder.sol │ ├── ERC721Receiver.sol │ └── ERC721Token.sol │ └── ERC827 │ ├── ERC827.sol │ └── ERC827Token.sol ├── ethpm.json ├── migrations └── .gitkeep ├── package-lock.json ├── package.json ├── scripts ├── coverage.sh ├── test.sh └── version.js ├── test ├── .eslintrc ├── Bounty.test.js ├── DayLimit.test.js ├── Heritable.test.js ├── LimitBalance.test.js ├── ReentrancyGuard.test.js ├── SimpleSavingsWallet.test.js ├── access │ └── SignatureBouncer.test.js ├── crowdsale │ ├── AllowanceCrowdsale.test.js │ ├── CappedCrowdsale.test.js │ ├── Crowdsale.test.js │ ├── FinalizableCrowdsale.test.js │ ├── IncreasingPriceCrowdsale.test.js │ ├── IndividuallyCappedCrowdsale.test.js │ ├── MintedCrowdsale.behaviour.js │ ├── MintedCrowdsale.test.js │ ├── PostDeliveryCrowdsale.test.js │ ├── RefundVault.test.js │ ├── RefundableCrowdsale.test.js │ ├── TimedCrowdsale.test.js │ └── WhitelistedCrowdsale.test.js ├── examples │ ├── SampleCrowdsale.test.js │ └── SimpleToken.test.js ├── helpers │ ├── EVMRevert.js │ ├── EVMThrow.js │ ├── advanceToBlock.js │ ├── assertJump.js │ ├── assertRevert.js │ ├── decodeLogs.js │ ├── ether.js │ ├── expectEvent.js │ ├── expectThrow.js │ ├── increaseTime.js │ ├── latestTime.js │ ├── merkleTree.js │ ├── sendTransaction.js │ ├── sign.js │ ├── toPromise.js │ └── transactionMined.js ├── library │ ├── ECRecovery.test.js │ ├── Math.test.js │ └── MerkleProof.test.js ├── lifecycle │ ├── Destructible.test.js │ ├── Pausable.test.js │ └── TokenDestructible.test.js ├── math │ └── SafeMath.test.js ├── ownership │ ├── CanReclaimToken.test.js │ ├── Claimable.test.js │ ├── Contactable.test.js │ ├── DelayedClaimable.test.js │ ├── HasNoContracts.test.js │ ├── HasNoEther.test.js │ ├── HasNoTokens.test.js │ ├── Ownable.behaviour.js │ ├── Ownable.test.js │ ├── Whitelist.test.js │ └── rbac │ │ └── RBAC.test.js ├── payment │ ├── PullPayment.test.js │ └── SplitPayment.test.js └── token │ ├── ERC20 │ ├── BasicToken.test.js │ ├── BurnableToken.behaviour.js │ ├── BurnableToken.test.js │ ├── CappedToken.test.js │ ├── DetailedERC20.test.js │ ├── MintableToken.behaviour.js │ ├── MintableToken.test.js │ ├── PausableToken.test.js │ ├── RBACMintableToken.test.js │ ├── SafeERC20.test.js │ ├── StandardBurnableToken.test.js │ ├── StandardToken.test.js │ ├── TokenTimelock.test.js │ └── TokenVesting.test.js │ ├── ERC721 │ ├── ERC721BasicToken.behaviour.js │ ├── ERC721BasicToken.test.js │ ├── ERC721MintBurn.behaviour.js │ └── ERC721Token.test.js │ └── ERC827 │ └── ERC827Token.js └── truffle-config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2", "stage-3"] 3 | } 4 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # configure your infura api key (not technically required) 2 | INFURA_API_KEY= 3 | 4 | # change the mnemonic that your hd wallet is seeded with 5 | MNEMONIC= 6 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends" : [ 3 | "standard", 4 | "plugin:promise/recommended" 5 | ], 6 | "plugins": [ 7 | "promise" 8 | ], 9 | "env": { 10 | "browser" : true, 11 | "node" : true, 12 | "mocha" : true, 13 | "jest" : true 14 | }, 15 | "globals" : { 16 | "artifacts": false, 17 | "contract": false, 18 | "assert": false, 19 | "web3": false 20 | }, 21 | "rules": { 22 | 23 | // Strict mode 24 | "strict": [2, "global"], 25 | 26 | // Code style 27 | "indent": [2, 2], 28 | "quotes": [2, "single"], 29 | "semi": ["error", "always"], 30 | "space-before-function-paren": ["error", "always"], 31 | "no-use-before-define": 0, 32 | "eqeqeq": [2, "smart"], 33 | "dot-notation": [2, {"allowKeywords": true, "allowPattern": ""}], 34 | "no-redeclare": [2, {"builtinGlobals": true}], 35 | "no-trailing-spaces": [2, { "skipBlankLines": true }], 36 | "eol-last": 1, 37 | "comma-spacing": [2, {"before": false, "after": true}], 38 | "camelcase": [2, {"properties": "always"}], 39 | "no-mixed-spaces-and-tabs": [2, "smart-tabs"], 40 | "comma-dangle": [1, "always-multiline"], 41 | "no-dupe-args": 2, 42 | "no-dupe-keys": 2, 43 | "no-debugger": 0, 44 | "no-undef": 2, 45 | "object-curly-spacing": [2, "always"], 46 | "max-len": [2, 120, 2], 47 | "generator-star-spacing": ["error", "before"], 48 | "promise/avoid-new": 0, 49 | "promise/always-return": 0 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## 🎉 Description 2 | 3 | 4 | 5 | - [ ] 🐛 This is a bug report. 6 | - [ ] 📈 This is a feature request. 7 | 8 | 9 | 10 | ## 💻 Environment 11 | 12 | Next, we need to know what your environment looks like. 13 | 14 | - Which version of OpenZeppelin are you using? 15 | - What network are you deploying to? Ganache? Ropsten? 16 | - How are you deploying your OpenZeppelin-backed contracts? truffle? Remix? Let us know! 17 | 18 | ## 📝 Details 19 | 20 | Describe the problem you have been experiencing in more detail. Include as much information as you think is relevant. Keep in mind that transactions can fail for many reasons; context is key here. 21 | 22 | ## 🔢 Code To Reproduce Issue [ Good To Have ] 23 | 24 | Please remember that with sample code it's easier to reproduce the bug and it's much faster to fix it. 25 | 26 | ``` 27 | insert short code snippets here 28 | ``` 29 | 30 | 31 | 32 | ## 👍 Other Information 33 | 34 | 35 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Fixes # 6 | 7 | # 🚀 Description 8 | 9 | 10 | 11 | 12 | 13 | 14 | - [ ] 📘 I've reviewed the [OpenZeppelin Contributor Guidelines](../blob/master/CONTRIBUTING.md) 15 | - [ ] ✅ I've added tests where applicable to test my new functionality. 16 | - [ ] 📖 I've made sure that my contracts are well-documented. 17 | - [ ] 🎨 I've run the JS/Solidity linters and fixed any issues (`npm run lint:all:fix`). 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | 4 | # Logs 5 | logs 6 | *.log 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | allFiredEvents 13 | scTopics 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | coverage.json 18 | coverageEnv 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Dependency directory 24 | node_modules 25 | 26 | # Debug log from npm 27 | npm-debug.log 28 | 29 | # local env variables 30 | .env 31 | 32 | # truffle build directory 33 | build/ 34 | 35 | # lol macs 36 | .DS_Store/ 37 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | v8.9.1 2 | -------------------------------------------------------------------------------- /.solcover.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | norpc: true, 3 | testCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle test --network coverage', 4 | compileCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle compile --network coverage', 5 | skipFiles: [ 6 | 'lifecycle/Migrations.sol', 7 | 'mocks' 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.soliumignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.soliumrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solium:all", 3 | "plugins": ["security"], 4 | "rules": { 5 | "quotes": ["error", "double"], 6 | "no-empty-blocks": "off", 7 | "indentation": ["error", 2], 8 | "max-len": ["warning", 79], 9 | "no-constant": ["error"], 10 | "security/enforce-explicit-visibility": ["error"], 11 | "security/no-block-members": ["warning"], 12 | "security/no-inline-assembly": ["warning"] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | sudo: required 3 | group: beta 4 | language: node_js 5 | node_js: 6 | - "8" 7 | cache: 8 | directories: 9 | - node_modules 10 | env: 11 | - 12 | - SOLIDITY_COVERAGE=true 13 | - SOLC_NIGHTLY=true 14 | matrix: 15 | fast_finish: true 16 | allow_failures: 17 | - env: SOLIDITY_COVERAGE=true 18 | - env: SOLC_NIGHTLY=true 19 | before_script: 20 | - truffle version 21 | script: 22 | - npm run lint 23 | - npm run lint:sol 24 | - npm run test 25 | notifications: 26 | slack: 27 | rooms: 28 | - secure: uEhwUkuwJp5pBNh+VTEytPHz3FDKsnPrKO+8MTAKv5hKi4PCRoVhLv6pklr82HUpL6pvSvJbUPA0HVebOXA+MMSxdny/BHZTh2mtw5Y78l2Ad0svDTWuV2Lus2pmhYigRhT0Wo00/SRX9+pxm0kg4EIFJSTS+uR9G76x0l9NljpEGXrqxlDxjxoHBgk8Ciru2LHaLzX/utE3jlABts4Sb1F3wc2BwFkjd6BDCRTGAPhVJwwFk41ZfnmLVbgSNUyk46Cb38oG5oXHb0FI3d3jV/k1OUhRyFfmA2fLXRk0wavibW8TG1gGJJWZ7xTCKzw/Cvup6mpehSAeQef8eekMdjpWEhF9hYRq1BvOs0384UU8NQ0O+BtdXU+X3Nyr84TMJN/iIfgN7gYX7AsvXH3jC0JfNUcIkWlJvyXdE6l2GV1hMmhL09GFEBbSpuSXRIWlOXTcYBlp5NbvE8xO8PUW+T6N5RG2XXjv1g8wCpr6Wwk1+LmRkX5trv8MFBZ2pM8p4H5da5++Ov8egLonNGK2jbx6aBLBX3tPf+g70LZEkiQ4eBfZw8VIgXIvKreisicppNuCD27gNmSEPNt0NkwiEBcTCJ9GSVAO0CU2g4ggvHDX2A+RW5XPET9bGkBXKLfFyV7Qe+MSQjXkCnW3bIRh7Wo1V31XiUiYOLuZPIiH3EQ= 29 | on_success: change 30 | on_failure: always 31 | on_pull_requests: false 32 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to OpenZeppelin 2 | ======= 3 | 4 | We really appreciate and value contributions to OpenZeppelin. Please take 5' to review the items listed below to make sure that your contributions are merged as soon as possible. 5 | 6 | ## Contribution guidelines 7 | 8 | Smart contracts manage value and are highly vulnerable to errors and attacks. We have very strict guidelines, please make sure to review them: ["Contribution guidelines wiki entry"](https://github.com/OpenZeppelin/openzeppelin-solidity/wiki/Contribution-guidelines). 9 | 10 | ## Creating Pull Requests (PRs) 11 | 12 | As a contributor, you are expected to fork this repository, work on your own fork and then submit pull requests. The pull requests will be reviewed and eventually merged into the main repo. See ["Fork-a-Repo"](https://help.github.com/articles/fork-a-repo/) for how this works. 13 | 14 | *IMPORTANT* 15 | * Please see ["Git flow wiki entry"](https://github.com/OpenZeppelin/openzeppelin-solidity/wiki/Git-flow) for understanding how to use branches in this repository. 16 | 17 | ## A typical workflow 18 | 19 | 1) Make sure your fork is up to date with the main repository: 20 | 21 | ``` 22 | cd openzeppelin-solidity 23 | git fetch upstream 24 | git checkout development 25 | git pull --rebase upstream development 26 | ``` 27 | NOTE: The directory `openzeppelin-solidity` represents your fork's local copy. 28 | 29 | 2) Branch out from `development` into `fix/some-bug-#123`: 30 | (Postfixing #123 will associate your PR with the issue #123 and make everyone's life easier =D) 31 | ``` 32 | git checkout -b fix/some-bug-#123 33 | ``` 34 | 35 | 3) Make your changes, add your files, commit and push to your fork. 36 | 37 | ``` 38 | git add SomeFile.js 39 | git commit "Fix some bug #123" 40 | git push origin fix/some-bug-#123 41 | ``` 42 | 43 | 4) Go to [github.com/OpenZeppelin/openzeppelin-solidity](https://github.com/OpenZeppelin/zeppelin-solidity) in your web browser and issue a new pull request. 44 | 45 | *IMPORTANT* Read the PR template very carefully and make sure to follow all the instructions. These instructions 46 | refer to some very important conditions that your PR must meet in order to be accepted, such as making sure that all tests pass, JS linting tests pass, solidity linting tests pass, etc. 47 | 48 | 5) Maintainers 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 OpenZeppelin. 49 | 50 | *IMPORTANT* Please pay attention to the maintainer's feedback, since its a necessary step to keep up with the standards OpenZeppelin attains to. 51 | 52 | ## All set! 53 | 54 | If you have any questions feel free to post them to github.com/OpenZeppelin/openzeppelin-solidity/issues. 55 | 56 | Finally, if you're looking to collaborate and want to find easy tasks to start, look at the issues we marked as ["Good first issue"](https://github.com/OpenZeppelin/openzeppelin-solidity/labels/good%20first%20issue). 57 | 58 | Thanks for your time and code! 59 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /contracts/.npmignore: -------------------------------------------------------------------------------- 1 | mocks 2 | examples 3 | -------------------------------------------------------------------------------- /contracts/AddressUtils.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | /** 5 | * Utility library of inline functions on addresses 6 | */ 7 | library AddressUtils { 8 | 9 | /** 10 | * Returns whether the target address is a contract 11 | * @dev This function will return false if invoked during the constructor of a contract, 12 | * as the code is not actually created until after the constructor finishes. 13 | * @param addr address to check 14 | * @return whether the target address is a contract 15 | */ 16 | function isContract(address addr) internal view returns (bool) { 17 | uint256 size; 18 | // XXX Currently there is no better way to check if there is a contract in an address 19 | // than to check the size of the code at that address. 20 | // See https://ethereum.stackexchange.com/a/14016/36603 21 | // for more details about how this works. 22 | // TODO Check this again before the Serenity release, because all addresses will be 23 | // contracts then. 24 | // solium-disable-next-line security/no-inline-assembly 25 | assembly { size := extcodesize(addr) } 26 | return size > 0; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /contracts/Bounty.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 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() external 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 | emit TargetCreated(target); 34 | return target; 35 | } 36 | 37 | /** 38 | * @dev Sends the contract funds to the researcher that proved the contract is broken. 39 | * @param target contract 40 | */ 41 | function claim(Target target) public { 42 | address researcher = researchers[target]; 43 | require(researcher != 0); 44 | // Check Target contract invariants 45 | require(!target.checkInvariant()); 46 | asyncSend(researcher, address(this).balance); 47 | claimed = true; 48 | } 49 | 50 | /** 51 | * @dev Internal function to deploy the target contract. 52 | * @return A target contract address 53 | */ 54 | function deployContract() internal returns(address); 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.23; 2 | 3 | 4 | /** 5 | * @title DayLimit 6 | * @dev Base contract that enables methods to be protected by placing a linear limit (specifiable) 7 | * on a particular resource per calendar day. Is multiowned to allow the limit to be altered. 8 | */ 9 | contract DayLimit { 10 | 11 | uint256 public dailyLimit; 12 | uint256 public spentToday; 13 | uint256 public lastDay; 14 | 15 | /** 16 | * @dev Constructor that sets the passed value as a dailyLimit. 17 | * @param _limit uint256 to represent the daily limit. 18 | */ 19 | constructor(uint256 _limit) public { 20 | dailyLimit = _limit; 21 | lastDay = today(); 22 | } 23 | 24 | /** 25 | * @dev sets the daily limit. Does not alter the amount already spent today. 26 | * @param _newLimit uint256 to represent the new limit. 27 | */ 28 | function _setDailyLimit(uint256 _newLimit) internal { 29 | dailyLimit = _newLimit; 30 | } 31 | 32 | /** 33 | * @dev Resets the amount already spent today. 34 | */ 35 | function _resetSpentToday() internal { 36 | spentToday = 0; 37 | } 38 | 39 | /** 40 | * @dev Checks to see if there is enough resource to spend today. If true, the resource may be expended. 41 | * @param _value uint256 representing the amount of resource to spend. 42 | * @return A boolean that is True if the resource was spent and false otherwise. 43 | */ 44 | function underLimit(uint256 _value) internal returns (bool) { 45 | // reset the spend limit if we're on a different day to last time. 46 | if (today() > lastDay) { 47 | spentToday = 0; 48 | lastDay = today(); 49 | } 50 | // check to see if there's enough left - if so, subtract and return true. 51 | // overflow protection // dailyLimit check 52 | if ( 53 | spentToday + _value >= spentToday && 54 | spentToday + _value <= dailyLimit 55 | ) { 56 | spentToday += _value; 57 | return true; 58 | } 59 | return false; 60 | } 61 | 62 | /** 63 | * @dev Private function to determine today's index 64 | * @return uint256 of today's index. 65 | */ 66 | function today() private view returns (uint256) { 67 | // solium-disable-next-line security/no-block-members 68 | return block.timestamp / 1 days; 69 | } 70 | 71 | /** 72 | * @dev Simple modifier for daily limit. 73 | */ 74 | modifier limitedDaily(uint256 _value) { 75 | require(underLimit(_value)); 76 | _; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /contracts/ECRecovery.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | /** 5 | * @title Eliptic curve signature operations 6 | * 7 | * @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d 8 | * 9 | * TODO Remove this library once solidity supports passing a signature to ecrecover. 10 | * See https://github.com/ethereum/solidity/issues/864 11 | * 12 | */ 13 | 14 | library ECRecovery { 15 | 16 | /** 17 | * @dev Recover signer address from a message by using their signature 18 | * @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address. 19 | * @param sig bytes signature, the signature is generated using web3.eth.sign() 20 | */ 21 | function recover(bytes32 hash, bytes sig) 22 | internal 23 | pure 24 | returns (address) 25 | { 26 | bytes32 r; 27 | bytes32 s; 28 | uint8 v; 29 | 30 | // Check the signature length 31 | if (sig.length != 65) { 32 | return (address(0)); 33 | } 34 | 35 | // Divide the signature in r, s and v variables 36 | // ecrecover takes the signature parameters, and the only way to get them 37 | // currently is to use assembly. 38 | // solium-disable-next-line security/no-inline-assembly 39 | assembly { 40 | r := mload(add(sig, 32)) 41 | s := mload(add(sig, 64)) 42 | v := byte(0, mload(add(sig, 96))) 43 | } 44 | 45 | // Version of signature should be 27 or 28, but 0 and 1 are also possible versions 46 | if (v < 27) { 47 | v += 27; 48 | } 49 | 50 | // If the version is correct return the signer address 51 | if (v != 27 && v != 28) { 52 | return (address(0)); 53 | } else { 54 | // solium-disable-next-line arg-overflow 55 | return ecrecover(hash, v, r, s); 56 | } 57 | } 58 | 59 | /** 60 | * toEthSignedMessageHash 61 | * @dev prefix a bytes32 value with "\x19Ethereum Signed Message:" 62 | * @dev and hash the result 63 | */ 64 | function toEthSignedMessageHash(bytes32 hash) 65 | internal 66 | pure 67 | returns (bytes32) 68 | { 69 | // 32 is the length in bytes of hash, 70 | // enforced by the type signature above 71 | return keccak256( 72 | "\x19Ethereum Signed Message:\n32", 73 | hash 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /contracts/LimitBalance.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 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 | constructor(uint256 _limit) public { 19 | limit = _limit; 20 | } 21 | 22 | /** 23 | * @dev Checks if limit was reached. Case true, it throws. 24 | */ 25 | modifier limitedPayable() { 26 | require(address(this).balance <= limit); 27 | _; 28 | 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /contracts/MerkleProof.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | /* 5 | * @title MerkleProof 6 | * @dev Merkle proof verification 7 | * @note Based on https://github.com/ameensol/merkle-tree-solidity/blob/master/src/MerkleProof.sol 8 | */ 9 | library MerkleProof { 10 | /* 11 | * @dev Verifies a Merkle proof proving the existence of a leaf in a Merkle tree. Assumes that each pair of leaves 12 | * and each pair of pre-images is sorted. 13 | * @param _proof Merkle proof containing sibling hashes on the branch from the leaf to the root of the Merkle tree 14 | * @param _root Merkle root 15 | * @param _leaf Leaf of Merkle tree 16 | */ 17 | function verifyProof( 18 | bytes32[] _proof, 19 | bytes32 _root, 20 | bytes32 _leaf 21 | ) 22 | internal 23 | pure 24 | returns (bool) 25 | { 26 | bytes32 computedHash = _leaf; 27 | 28 | for (uint256 i = 0; i < _proof.length; i++) { 29 | bytes32 proofElement = _proof[i]; 30 | 31 | if (computedHash < proofElement) { 32 | // Hash(current computed hash + current element of the proof) 33 | computedHash = keccak256(computedHash, proofElement); 34 | } else { 35 | // Hash(current element of the proof + current computed hash) 36 | computedHash = keccak256(proofElement, computedHash); 37 | } 38 | } 39 | 40 | // Check if the computed hash (root) is equal to the provided root 41 | return computedHash == _root; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/ReentrancyGuard.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | /** 5 | * @title Helps contracts guard agains reentrancy attacks. 6 | * @author Remco Bloemen 7 | * @notice If you mark a function `nonReentrant`, you should also 8 | * mark it `external`. 9 | */ 10 | contract ReentrancyGuard { 11 | 12 | /** 13 | * @dev We use a single lock for the whole contract. 14 | */ 15 | bool private reentrancyLock = false; 16 | 17 | /** 18 | * @dev Prevents a contract from calling itself, directly or indirectly. 19 | * @notice If you mark a function `nonReentrant`, you should also 20 | * mark it `external`. Calling one nonReentrant function from 21 | * another is not supported. Instead, you can implement a 22 | * `private` function doing the actual work, and a `external` 23 | * wrapper marked as `nonReentrant`. 24 | */ 25 | modifier nonReentrant() { 26 | require(!reentrancyLock); 27 | reentrancyLock = true; 28 | _; 29 | reentrancyLock = false; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /contracts/access/SignatureBouncer.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../ownership/Ownable.sol"; 4 | import "../ownership/rbac/RBAC.sol"; 5 | import "../ECRecovery.sol"; 6 | 7 | 8 | /** 9 | * @title SignatureBouncer 10 | * @author PhABC and Shrugs 11 | * @dev Bouncer allows users to submit a signature as a permission to do an action. 12 | * @dev If the signature is from one of the authorized bouncer addresses, the signature 13 | * @dev is valid. The owner of the contract adds/removes bouncers. 14 | * @dev Bouncer addresses can be individual servers signing grants or different 15 | * @dev users within a decentralized club that have permission to invite other members. 16 | * @dev 17 | * @dev This technique is useful for whitelists and airdrops; instead of putting all 18 | * @dev valid addresses on-chain, simply sign a grant of the form 19 | * @dev keccak256(`:contractAddress` + `:granteeAddress`) using a valid bouncer address. 20 | * @dev Then restrict access to your crowdsale/whitelist/airdrop using the 21 | * @dev `onlyValidSignature` modifier (or implement your own using isValidSignature). 22 | * @dev 23 | * @dev See the tests Bouncer.test.js for specific usage examples. 24 | */ 25 | contract SignatureBouncer is Ownable, RBAC { 26 | using ECRecovery for bytes32; 27 | 28 | string public constant ROLE_BOUNCER = "bouncer"; 29 | 30 | /** 31 | * @dev requires that a valid signature of a bouncer was provided 32 | */ 33 | modifier onlyValidSignature(bytes _sig) 34 | { 35 | require(isValidSignature(msg.sender, _sig)); 36 | _; 37 | } 38 | 39 | /** 40 | * @dev allows the owner to add additional bouncer addresses 41 | */ 42 | function addBouncer(address _bouncer) 43 | onlyOwner 44 | public 45 | { 46 | require(_bouncer != address(0)); 47 | addRole(_bouncer, ROLE_BOUNCER); 48 | } 49 | 50 | /** 51 | * @dev allows the owner to remove bouncer addresses 52 | */ 53 | function removeBouncer(address _bouncer) 54 | onlyOwner 55 | public 56 | { 57 | require(_bouncer != address(0)); 58 | removeRole(_bouncer, ROLE_BOUNCER); 59 | } 60 | 61 | /** 62 | * @dev is the signature of `this + sender` from a bouncer? 63 | * @return bool 64 | */ 65 | function isValidSignature(address _address, bytes _sig) 66 | internal 67 | view 68 | returns (bool) 69 | { 70 | return isValidDataHash( 71 | keccak256(address(this), _address), 72 | _sig 73 | ); 74 | } 75 | 76 | /** 77 | * @dev internal function to convert a hash to an eth signed message 78 | * @dev and then recover the signature and check it against the bouncer role 79 | * @return bool 80 | */ 81 | function isValidDataHash(bytes32 hash, bytes _sig) 82 | internal 83 | view 84 | returns (bool) 85 | { 86 | address signer = hash 87 | .toEthSignedMessageHash() 88 | .recover(_sig); 89 | return hasRole(signer, ROLE_BOUNCER); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /contracts/crowdsale/distribution/FinalizableCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../../math/SafeMath.sol"; 4 | import "../../ownership/Ownable.sol"; 5 | import "../validation/TimedCrowdsale.sol"; 6 | 7 | 8 | /** 9 | * @title FinalizableCrowdsale 10 | * @dev Extension of Crowdsale where an owner can do extra work 11 | * after finishing. 12 | */ 13 | contract FinalizableCrowdsale is TimedCrowdsale, Ownable { 14 | using SafeMath for uint256; 15 | 16 | bool public isFinalized = false; 17 | 18 | event Finalized(); 19 | 20 | /** 21 | * @dev Must be called after crowdsale ends, to do some extra finalization 22 | * work. Calls the contract's finalization function. 23 | */ 24 | function finalize() onlyOwner public { 25 | require(!isFinalized); 26 | require(hasClosed()); 27 | 28 | finalization(); 29 | emit Finalized(); 30 | 31 | isFinalized = true; 32 | } 33 | 34 | /** 35 | * @dev Can be overridden to add finalization logic. The overriding function 36 | * should call super.finalization() to ensure the chain of finalization is 37 | * executed entirely. 38 | */ 39 | function finalization() internal { 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../validation/TimedCrowdsale.sol"; 4 | import "../../token/ERC20/ERC20.sol"; 5 | import "../../math/SafeMath.sol"; 6 | 7 | 8 | /** 9 | * @title PostDeliveryCrowdsale 10 | * @dev Crowdsale that locks tokens from withdrawal until it ends. 11 | */ 12 | contract PostDeliveryCrowdsale is TimedCrowdsale { 13 | using SafeMath for uint256; 14 | 15 | mapping(address => uint256) public balances; 16 | 17 | /** 18 | * @dev Withdraw tokens only after crowdsale ends. 19 | */ 20 | function withdrawTokens() public { 21 | require(hasClosed()); 22 | uint256 amount = balances[msg.sender]; 23 | require(amount > 0); 24 | balances[msg.sender] = 0; 25 | _deliverTokens(msg.sender, amount); 26 | } 27 | 28 | /** 29 | * @dev Overrides parent by storing balances instead of issuing tokens right away. 30 | * @param _beneficiary Token purchaser 31 | * @param _tokenAmount Amount of tokens purchased 32 | */ 33 | function _processPurchase( 34 | address _beneficiary, 35 | uint256 _tokenAmount 36 | ) 37 | internal 38 | { 39 | balances[_beneficiary] = balances[_beneficiary].add(_tokenAmount); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /contracts/crowdsale/distribution/RefundableCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | import "../../math/SafeMath.sol"; 5 | import "./FinalizableCrowdsale.sol"; 6 | import "./utils/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 | /** 25 | * @dev Constructor, creates RefundVault. 26 | * @param _goal Funding goal 27 | */ 28 | constructor(uint256 _goal) public { 29 | require(_goal > 0); 30 | vault = new RefundVault(wallet); 31 | goal = _goal; 32 | } 33 | 34 | /** 35 | * @dev Investors can claim refunds here if crowdsale is unsuccessful 36 | */ 37 | function claimRefund() public { 38 | require(isFinalized); 39 | require(!goalReached()); 40 | 41 | vault.refund(msg.sender); 42 | } 43 | 44 | /** 45 | * @dev Checks whether funding goal was reached. 46 | * @return Whether funding goal was reached 47 | */ 48 | function goalReached() public view returns (bool) { 49 | return weiRaised >= goal; 50 | } 51 | 52 | /** 53 | * @dev vault finalization task, called when owner calls finalize() 54 | */ 55 | function finalization() internal { 56 | if (goalReached()) { 57 | vault.close(); 58 | } else { 59 | vault.enableRefunds(); 60 | } 61 | 62 | super.finalization(); 63 | } 64 | 65 | /** 66 | * @dev Overrides Crowdsale fund forwarding, sending funds to vault. 67 | */ 68 | function _forwardFunds() internal { 69 | vault.deposit.value(msg.value)(msg.sender); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /contracts/crowdsale/distribution/utils/RefundVault.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../../../math/SafeMath.sol"; 4 | import "../../../ownership/Ownable.sol"; 5 | 6 | 7 | /** 8 | * @title RefundVault 9 | * @dev This contract is used for storing funds while a crowdsale 10 | * is in progress. Supports refunding the money if crowdsale fails, 11 | * and forwarding it if crowdsale is successful. 12 | */ 13 | contract RefundVault is Ownable { 14 | using SafeMath for uint256; 15 | 16 | enum State { Active, Refunding, Closed } 17 | 18 | mapping (address => uint256) public deposited; 19 | address public wallet; 20 | State public state; 21 | 22 | event Closed(); 23 | event RefundsEnabled(); 24 | event Refunded(address indexed beneficiary, uint256 weiAmount); 25 | 26 | /** 27 | * @param _wallet Vault address 28 | */ 29 | constructor(address _wallet) public { 30 | require(_wallet != address(0)); 31 | wallet = _wallet; 32 | state = State.Active; 33 | } 34 | 35 | /** 36 | * @param investor Investor address 37 | */ 38 | function deposit(address investor) onlyOwner public payable { 39 | require(state == State.Active); 40 | deposited[investor] = deposited[investor].add(msg.value); 41 | } 42 | 43 | function close() onlyOwner public { 44 | require(state == State.Active); 45 | state = State.Closed; 46 | emit Closed(); 47 | wallet.transfer(address(this).balance); 48 | } 49 | 50 | function enableRefunds() onlyOwner public { 51 | require(state == State.Active); 52 | state = State.Refunding; 53 | emit RefundsEnabled(); 54 | } 55 | 56 | /** 57 | * @param investor Investor address 58 | */ 59 | function refund(address investor) public { 60 | require(state == State.Refunding); 61 | uint256 depositedValue = deposited[investor]; 62 | deposited[investor] = 0; 63 | investor.transfer(depositedValue); 64 | emit Refunded(investor, depositedValue); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /contracts/crowdsale/emission/AllowanceCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../Crowdsale.sol"; 4 | import "../../token/ERC20/ERC20.sol"; 5 | import "../../math/SafeMath.sol"; 6 | 7 | 8 | /** 9 | * @title AllowanceCrowdsale 10 | * @dev Extension of Crowdsale where tokens are held by a wallet, which approves an allowance to the crowdsale. 11 | */ 12 | contract AllowanceCrowdsale is Crowdsale { 13 | using SafeMath for uint256; 14 | 15 | address public tokenWallet; 16 | 17 | /** 18 | * @dev Constructor, takes token wallet address. 19 | * @param _tokenWallet Address holding the tokens, which has approved allowance to the crowdsale 20 | */ 21 | constructor(address _tokenWallet) public { 22 | require(_tokenWallet != address(0)); 23 | tokenWallet = _tokenWallet; 24 | } 25 | 26 | /** 27 | * @dev Checks the amount of tokens left in the allowance. 28 | * @return Amount of tokens left in the allowance 29 | */ 30 | function remainingTokens() public view returns (uint256) { 31 | return token.allowance(tokenWallet, this); 32 | } 33 | 34 | /** 35 | * @dev Overrides parent behavior by transferring tokens from wallet. 36 | * @param _beneficiary Token purchaser 37 | * @param _tokenAmount Amount of tokens purchased 38 | */ 39 | function _deliverTokens( 40 | address _beneficiary, 41 | uint256 _tokenAmount 42 | ) 43 | internal 44 | { 45 | token.transferFrom(tokenWallet, _beneficiary, _tokenAmount); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/crowdsale/emission/MintedCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../Crowdsale.sol"; 4 | import "../../token/ERC20/MintableToken.sol"; 5 | 6 | 7 | /** 8 | * @title MintedCrowdsale 9 | * @dev Extension of Crowdsale contract whose tokens are minted in each purchase. 10 | * Token ownership should be transferred to MintedCrowdsale for minting. 11 | */ 12 | contract MintedCrowdsale is Crowdsale { 13 | 14 | /** 15 | * @dev Overrides delivery by minting tokens upon purchase. 16 | * @param _beneficiary Token purchaser 17 | * @param _tokenAmount Number of tokens to be minted 18 | */ 19 | function _deliverTokens( 20 | address _beneficiary, 21 | uint256 _tokenAmount 22 | ) 23 | internal 24 | { 25 | require(MintableToken(token).mint(_beneficiary, _tokenAmount)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contracts/crowdsale/price/IncreasingPriceCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../validation/TimedCrowdsale.sol"; 4 | import "../../math/SafeMath.sol"; 5 | 6 | 7 | /** 8 | * @title IncreasingPriceCrowdsale 9 | * @dev Extension of Crowdsale contract that increases the price of tokens linearly in time. 10 | * Note that what should be provided to the constructor is the initial and final _rates_, that is, 11 | * the amount of tokens per wei contributed. Thus, the initial rate must be greater than the final rate. 12 | */ 13 | contract IncreasingPriceCrowdsale is TimedCrowdsale { 14 | using SafeMath for uint256; 15 | 16 | uint256 public initialRate; 17 | uint256 public finalRate; 18 | 19 | /** 20 | * @dev Constructor, takes intial and final rates of tokens received per wei contributed. 21 | * @param _initialRate Number of tokens a buyer gets per wei at the start of the crowdsale 22 | * @param _finalRate Number of tokens a buyer gets per wei at the end of the crowdsale 23 | */ 24 | constructor(uint256 _initialRate, uint256 _finalRate) public { 25 | require(_initialRate >= _finalRate); 26 | require(_finalRate > 0); 27 | initialRate = _initialRate; 28 | finalRate = _finalRate; 29 | } 30 | 31 | /** 32 | * @dev Returns the rate of tokens per wei at the present time. 33 | * Note that, as price _increases_ with time, the rate _decreases_. 34 | * @return The number of tokens a buyer gets per wei at a given time 35 | */ 36 | function getCurrentRate() public view returns (uint256) { 37 | // solium-disable-next-line security/no-block-members 38 | uint256 elapsedTime = block.timestamp.sub(openingTime); 39 | uint256 timeRange = closingTime.sub(openingTime); 40 | uint256 rateRange = initialRate.sub(finalRate); 41 | return initialRate.sub(elapsedTime.mul(rateRange).div(timeRange)); 42 | } 43 | 44 | /** 45 | * @dev Overrides parent method taking into account variable rate. 46 | * @param _weiAmount The value in wei to be converted into tokens 47 | * @return The number of tokens _weiAmount wei will buy at present time 48 | */ 49 | function _getTokenAmount(uint256 _weiAmount) 50 | internal view returns (uint256) 51 | { 52 | uint256 currentRate = getCurrentRate(); 53 | return currentRate.mul(_weiAmount); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /contracts/crowdsale/validation/CappedCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../../math/SafeMath.sol"; 4 | import "../Crowdsale.sol"; 5 | 6 | 7 | /** 8 | * @title CappedCrowdsale 9 | * @dev Crowdsale with a limit for total contributions. 10 | */ 11 | contract CappedCrowdsale is Crowdsale { 12 | using SafeMath for uint256; 13 | 14 | uint256 public cap; 15 | 16 | /** 17 | * @dev Constructor, takes maximum amount of wei accepted in the crowdsale. 18 | * @param _cap Max amount of wei to be contributed 19 | */ 20 | constructor(uint256 _cap) public { 21 | require(_cap > 0); 22 | cap = _cap; 23 | } 24 | 25 | /** 26 | * @dev Checks whether the cap has been reached. 27 | * @return Whether the cap was reached 28 | */ 29 | function capReached() public view returns (bool) { 30 | return weiRaised >= cap; 31 | } 32 | 33 | /** 34 | * @dev Extend parent behavior requiring purchase to respect the funding cap. 35 | * @param _beneficiary Token purchaser 36 | * @param _weiAmount Amount of wei contributed 37 | */ 38 | function _preValidatePurchase( 39 | address _beneficiary, 40 | uint256 _weiAmount 41 | ) 42 | internal 43 | { 44 | super._preValidatePurchase(_beneficiary, _weiAmount); 45 | require(weiRaised.add(_weiAmount) <= cap); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /contracts/crowdsale/validation/IndividuallyCappedCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../../math/SafeMath.sol"; 4 | import "../Crowdsale.sol"; 5 | import "../../ownership/Ownable.sol"; 6 | 7 | 8 | /** 9 | * @title IndividuallyCappedCrowdsale 10 | * @dev Crowdsale with per-user caps. 11 | */ 12 | contract IndividuallyCappedCrowdsale is Crowdsale, Ownable { 13 | using SafeMath for uint256; 14 | 15 | mapping(address => uint256) public contributions; 16 | mapping(address => uint256) public caps; 17 | 18 | /** 19 | * @dev Sets a specific user's maximum contribution. 20 | * @param _beneficiary Address to be capped 21 | * @param _cap Wei limit for individual contribution 22 | */ 23 | function setUserCap(address _beneficiary, uint256 _cap) external onlyOwner { 24 | caps[_beneficiary] = _cap; 25 | } 26 | 27 | /** 28 | * @dev Sets a group of users' maximum contribution. 29 | * @param _beneficiaries List of addresses to be capped 30 | * @param _cap Wei limit for individual contribution 31 | */ 32 | function setGroupCap( 33 | address[] _beneficiaries, 34 | uint256 _cap 35 | ) 36 | external 37 | onlyOwner 38 | { 39 | for (uint256 i = 0; i < _beneficiaries.length; i++) { 40 | caps[_beneficiaries[i]] = _cap; 41 | } 42 | } 43 | 44 | /** 45 | * @dev Returns the cap of a specific user. 46 | * @param _beneficiary Address whose cap is to be checked 47 | * @return Current cap for individual user 48 | */ 49 | function getUserCap(address _beneficiary) public view returns (uint256) { 50 | return caps[_beneficiary]; 51 | } 52 | 53 | /** 54 | * @dev Returns the amount contributed so far by a sepecific user. 55 | * @param _beneficiary Address of contributor 56 | * @return User contribution so far 57 | */ 58 | function getUserContribution(address _beneficiary) 59 | public view returns (uint256) 60 | { 61 | return contributions[_beneficiary]; 62 | } 63 | 64 | /** 65 | * @dev Extend parent behavior requiring purchase to respect the user's funding cap. 66 | * @param _beneficiary Token purchaser 67 | * @param _weiAmount Amount of wei contributed 68 | */ 69 | function _preValidatePurchase( 70 | address _beneficiary, 71 | uint256 _weiAmount 72 | ) 73 | internal 74 | { 75 | super._preValidatePurchase(_beneficiary, _weiAmount); 76 | require(contributions[_beneficiary].add(_weiAmount) <= caps[_beneficiary]); 77 | } 78 | 79 | /** 80 | * @dev Extend parent behavior to update user contributions 81 | * @param _beneficiary Token purchaser 82 | * @param _weiAmount Amount of wei contributed 83 | */ 84 | function _updatePurchasingState( 85 | address _beneficiary, 86 | uint256 _weiAmount 87 | ) 88 | internal 89 | { 90 | super._updatePurchasingState(_beneficiary, _weiAmount); 91 | contributions[_beneficiary] = contributions[_beneficiary].add(_weiAmount); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /contracts/crowdsale/validation/TimedCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../../math/SafeMath.sol"; 4 | import "../Crowdsale.sol"; 5 | 6 | 7 | /** 8 | * @title TimedCrowdsale 9 | * @dev Crowdsale accepting contributions only within a time frame. 10 | */ 11 | contract TimedCrowdsale is Crowdsale { 12 | using SafeMath for uint256; 13 | 14 | uint256 public openingTime; 15 | uint256 public closingTime; 16 | 17 | /** 18 | * @dev Reverts if not in crowdsale time range. 19 | */ 20 | modifier onlyWhileOpen { 21 | // solium-disable-next-line security/no-block-members 22 | require(block.timestamp >= openingTime && block.timestamp <= closingTime); 23 | _; 24 | } 25 | 26 | /** 27 | * @dev Constructor, takes crowdsale opening and closing times. 28 | * @param _openingTime Crowdsale opening time 29 | * @param _closingTime Crowdsale closing time 30 | */ 31 | constructor(uint256 _openingTime, uint256 _closingTime) public { 32 | // solium-disable-next-line security/no-block-members 33 | require(_openingTime >= block.timestamp); 34 | require(_closingTime >= _openingTime); 35 | 36 | openingTime = _openingTime; 37 | closingTime = _closingTime; 38 | } 39 | 40 | /** 41 | * @dev Checks whether the period in which the crowdsale is open has already elapsed. 42 | * @return Whether crowdsale period has elapsed 43 | */ 44 | function hasClosed() public view returns (bool) { 45 | // solium-disable-next-line security/no-block-members 46 | return block.timestamp > closingTime; 47 | } 48 | 49 | /** 50 | * @dev Extend parent behavior requiring to be within contributing period 51 | * @param _beneficiary Token purchaser 52 | * @param _weiAmount Amount of wei contributed 53 | */ 54 | function _preValidatePurchase( 55 | address _beneficiary, 56 | uint256 _weiAmount 57 | ) 58 | internal 59 | onlyWhileOpen 60 | { 61 | super._preValidatePurchase(_beneficiary, _weiAmount); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /contracts/crowdsale/validation/WhitelistedCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../Crowdsale.sol"; 4 | import "../../ownership/Ownable.sol"; 5 | 6 | 7 | /** 8 | * @title WhitelistedCrowdsale 9 | * @dev Crowdsale in which only whitelisted users can contribute. 10 | */ 11 | contract WhitelistedCrowdsale is Crowdsale, Ownable { 12 | 13 | mapping(address => bool) public whitelist; 14 | 15 | /** 16 | * @dev Reverts if beneficiary is not whitelisted. Can be used when extending this contract. 17 | */ 18 | modifier isWhitelisted(address _beneficiary) { 19 | require(whitelist[_beneficiary]); 20 | _; 21 | } 22 | 23 | /** 24 | * @dev Adds single address to whitelist. 25 | * @param _beneficiary Address to be added to the whitelist 26 | */ 27 | function addToWhitelist(address _beneficiary) external onlyOwner { 28 | whitelist[_beneficiary] = true; 29 | } 30 | 31 | /** 32 | * @dev Adds list of addresses to whitelist. Not overloaded due to limitations with truffle testing. 33 | * @param _beneficiaries Addresses to be added to the whitelist 34 | */ 35 | function addManyToWhitelist(address[] _beneficiaries) external onlyOwner { 36 | for (uint256 i = 0; i < _beneficiaries.length; i++) { 37 | whitelist[_beneficiaries[i]] = true; 38 | } 39 | } 40 | 41 | /** 42 | * @dev Removes single address from whitelist. 43 | * @param _beneficiary Address to be removed to the whitelist 44 | */ 45 | function removeFromWhitelist(address _beneficiary) external onlyOwner { 46 | whitelist[_beneficiary] = false; 47 | } 48 | 49 | /** 50 | * @dev Extend parent behavior requiring beneficiary to be in whitelist. 51 | * @param _beneficiary Token beneficiary 52 | * @param _weiAmount Amount of wei contributed 53 | */ 54 | function _preValidatePurchase( 55 | address _beneficiary, 56 | uint256 _weiAmount 57 | ) 58 | internal 59 | isWhitelisted(_beneficiary) 60 | { 61 | super._preValidatePurchase(_beneficiary, _weiAmount); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /contracts/examples/SampleCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../crowdsale/validation/CappedCrowdsale.sol"; 4 | import "../crowdsale/distribution/RefundableCrowdsale.sol"; 5 | import "../crowdsale/emission/MintedCrowdsale.sol"; 6 | import "../token/ERC20/MintableToken.sol"; 7 | 8 | 9 | /** 10 | * @title SampleCrowdsaleToken 11 | * @dev Very simple ERC20 Token that can be minted. 12 | * It is meant to be used in a crowdsale contract. 13 | */ 14 | contract SampleCrowdsaleToken is MintableToken { 15 | 16 | // solium-disable-next-line uppercase 17 | string public constant name = "Sample Crowdsale Token"; 18 | string public constant symbol = "SCT"; // solium-disable-line uppercase 19 | uint8 public constant decimals = 18; // solium-disable-line uppercase 20 | 21 | } 22 | 23 | 24 | /** 25 | * @title SampleCrowdsale 26 | * @dev This is an example of a fully fledged crowdsale. 27 | * The way to add new features to a base crowdsale is by multiple inheritance. 28 | * In this example we are providing following extensions: 29 | * CappedCrowdsale - sets a max boundary for raised funds 30 | * RefundableCrowdsale - set a min goal to be reached and returns funds if it's not met 31 | * 32 | * After adding multiple features it's good practice to run integration tests 33 | * to ensure that subcontracts works together as intended. 34 | */ 35 | // XXX There doesn't seem to be a way to split this line that keeps solium 36 | // happy. See: 37 | // https://github.com/duaraghav8/Solium/issues/205 38 | // --elopio - 2018-05-10 39 | // solium-disable-next-line max-len 40 | contract SampleCrowdsale is CappedCrowdsale, RefundableCrowdsale, MintedCrowdsale { 41 | 42 | constructor( 43 | uint256 _openingTime, 44 | uint256 _closingTime, 45 | uint256 _rate, 46 | address _wallet, 47 | uint256 _cap, 48 | MintableToken _token, 49 | uint256 _goal 50 | ) 51 | public 52 | Crowdsale(_rate, _wallet, _token) 53 | CappedCrowdsale(_cap) 54 | TimedCrowdsale(_openingTime, _closingTime) 55 | RefundableCrowdsale(_goal) 56 | { 57 | //As goal needs to be met for a successful crowdsale 58 | //the value needs to less or equal than a cap which is limit for accepted funds 59 | require(_goal <= _cap); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /contracts/examples/SimpleSavingsWallet.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../ownership/Heritable.sol"; 4 | 5 | 6 | /** 7 | * @title SimpleSavingsWallet 8 | * @dev Simplest form of savings wallet whose ownership can be claimed by a heir 9 | * if owner dies. 10 | * In this example, we take a very simple savings wallet providing two operations 11 | * (to send and receive funds) and extend its capabilities by making it Heritable. 12 | * The account that creates the contract is set as owner, who has the authority to 13 | * choose an heir account. Heir account can reclaim the contract ownership in the 14 | * case that the owner dies. 15 | */ 16 | contract SimpleSavingsWallet is Heritable { 17 | 18 | event Sent(address indexed payee, uint256 amount, uint256 balance); 19 | event Received(address indexed payer, uint256 amount, uint256 balance); 20 | 21 | 22 | constructor(uint256 _heartbeatTimeout) Heritable(_heartbeatTimeout) public {} 23 | 24 | /** 25 | * @dev wallet can receive funds. 26 | */ 27 | function () public payable { 28 | emit Received(msg.sender, msg.value, address(this).balance); 29 | } 30 | 31 | /** 32 | * @dev wallet can send funds 33 | */ 34 | function sendTo(address payee, uint256 amount) public onlyOwner { 35 | require(payee != 0 && payee != address(this)); 36 | require(amount > 0); 37 | payee.transfer(amount); 38 | emit Sent(payee, amount, address(this).balance); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /contracts/examples/SimpleToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | import "../token/ERC20/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"; // solium-disable-line uppercase 16 | string public constant symbol = "SIM"; // solium-disable-line uppercase 17 | uint8 public constant decimals = 18; // solium-disable-line uppercase 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 | constructor() public { 25 | totalSupply_ = INITIAL_SUPPLY; 26 | balances[msg.sender] = INITIAL_SUPPLY; 27 | emit Transfer(0x0, msg.sender, INITIAL_SUPPLY); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /contracts/lifecycle/Destructible.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 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 | constructor() public 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/Pausable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 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 | emit 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 | emit Unpause(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contracts/lifecycle/TokenDestructible.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../ownership/Ownable.sol"; 4 | import "../token/ERC20/ERC20Basic.sol"; 5 | 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 | constructor() public 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.23; 2 | 3 | 4 | /** 5 | * @title Math 6 | * @dev Assorted math operations 7 | */ 8 | library Math { 9 | function max64(uint64 a, uint64 b) internal pure returns (uint64) { 10 | return a >= b ? a : b; 11 | } 12 | 13 | function min64(uint64 a, uint64 b) internal pure returns (uint64) { 14 | return a < b ? a : b; 15 | } 16 | 17 | function max256(uint256 a, uint256 b) internal pure returns (uint256) { 18 | return a >= b ? a : b; 19 | } 20 | 21 | function min256(uint256 a, uint256 b) internal pure returns (uint256) { 22 | return a < b ? a : b; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/math/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | /** 5 | * @title SafeMath 6 | * @dev Math operations with safety checks that throw on error 7 | */ 8 | library SafeMath { 9 | 10 | /** 11 | * @dev Multiplies two numbers, throws on overflow. 12 | */ 13 | function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { 14 | if (a == 0) { 15 | return 0; 16 | } 17 | c = a * b; 18 | assert(c / a == b); 19 | return c; 20 | } 21 | 22 | /** 23 | * @dev Integer division of two numbers, truncating the quotient. 24 | */ 25 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 26 | // assert(b > 0); // Solidity automatically throws when dividing by 0 27 | // uint256 c = a / b; 28 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 29 | return a / b; 30 | } 31 | 32 | /** 33 | * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). 34 | */ 35 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 36 | assert(b <= a); 37 | return a - b; 38 | } 39 | 40 | /** 41 | * @dev Adds two numbers, throws on overflow. 42 | */ 43 | function add(uint256 a, uint256 b) internal pure returns (uint256 c) { 44 | c = a + b; 45 | assert(c >= a); 46 | return c; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /contracts/mocks/AllowanceCrowdsaleImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/ERC20.sol"; 4 | import "../crowdsale/emission/AllowanceCrowdsale.sol"; 5 | 6 | 7 | contract AllowanceCrowdsaleImpl is AllowanceCrowdsale { 8 | 9 | constructor ( 10 | uint256 _rate, 11 | address _wallet, 12 | ERC20 _token, 13 | address _tokenWallet 14 | ) 15 | public 16 | Crowdsale(_rate, _wallet, _token) 17 | AllowanceCrowdsale(_tokenWallet) 18 | { 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /contracts/mocks/BasicTokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | import "../token/ERC20/BasicToken.sol"; 5 | 6 | 7 | // mock class using BasicToken 8 | contract BasicTokenMock is BasicToken { 9 | 10 | constructor(address initialAccount, uint256 initialBalance) public { 11 | balances[initialAccount] = initialBalance; 12 | totalSupply_ = initialBalance; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /contracts/mocks/BouncerMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../access/SignatureBouncer.sol"; 4 | 5 | 6 | contract SignatureBouncerMock is SignatureBouncer { 7 | function checkValidSignature(address _address, bytes _sig) 8 | public 9 | view 10 | returns (bool) 11 | { 12 | return isValidSignature(_address, _sig); 13 | } 14 | 15 | function onlyWithValidSignature(bytes _sig) 16 | onlyValidSignature(_sig) 17 | public 18 | view 19 | { 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contracts/mocks/BurnableTokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/BurnableToken.sol"; 4 | 5 | 6 | contract BurnableTokenMock is BurnableToken { 7 | 8 | constructor(address initialAccount, uint initialBalance) public { 9 | balances[initialAccount] = initialBalance; 10 | totalSupply_ = initialBalance; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /contracts/mocks/CappedCrowdsaleImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/ERC20.sol"; 4 | import "../crowdsale/validation/CappedCrowdsale.sol"; 5 | 6 | 7 | contract CappedCrowdsaleImpl is CappedCrowdsale { 8 | 9 | constructor ( 10 | uint256 _rate, 11 | address _wallet, 12 | ERC20 _token, 13 | uint256 _cap 14 | ) 15 | public 16 | Crowdsale(_rate, _wallet, _token) 17 | CappedCrowdsale(_cap) 18 | { 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /contracts/mocks/DayLimitMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../../contracts/DayLimit.sol"; 4 | 5 | 6 | contract DayLimitMock is DayLimit { 7 | uint256 public totalSpending; 8 | 9 | constructor(uint256 _value) public DayLimit(_value) { 10 | totalSpending = 0; 11 | } 12 | 13 | function attemptSpend(uint256 _value) external limitedDaily(_value) { 14 | totalSpending += _value; 15 | } 16 | 17 | function setDailyLimit(uint256 _newLimit) external { 18 | _setDailyLimit(_newLimit); 19 | } 20 | 21 | function resetSpentToday() external { 22 | _resetSpentToday(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /contracts/mocks/DetailedERC20Mock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/StandardToken.sol"; 4 | import "../token/ERC20/DetailedERC20.sol"; 5 | 6 | 7 | contract DetailedERC20Mock is StandardToken, DetailedERC20 { 8 | constructor( 9 | string _name, 10 | string _symbol, 11 | uint8 _decimals 12 | ) 13 | DetailedERC20(_name, _symbol, _decimals) 14 | public 15 | {} 16 | } 17 | -------------------------------------------------------------------------------- /contracts/mocks/ECRecoveryMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | import "../ECRecovery.sol"; 5 | 6 | 7 | contract ECRecoveryMock { 8 | using ECRecovery for bytes32; 9 | 10 | function recover(bytes32 hash, bytes sig) 11 | public 12 | pure 13 | returns (address) 14 | { 15 | return hash.recover(sig); 16 | } 17 | 18 | function toEthSignedMessageHash(bytes32 hash) 19 | public 20 | pure 21 | returns (bytes32) 22 | { 23 | return hash.toEthSignedMessageHash(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /contracts/mocks/ERC223TokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/BasicToken.sol"; 4 | 5 | 6 | contract ERC223ContractInterface { 7 | function tokenFallback(address _from, uint256 _value, bytes _data) external; 8 | } 9 | 10 | 11 | contract ERC223TokenMock is BasicToken { 12 | 13 | constructor(address initialAccount, uint256 initialBalance) public { 14 | balances[initialAccount] = initialBalance; 15 | totalSupply_ = initialBalance; 16 | } 17 | 18 | // ERC223 compatible transfer function (except the name) 19 | function transferERC223(address _to, uint256 _value, bytes _data) public 20 | returns (bool success) 21 | { 22 | transfer(_to, _value); 23 | bool isContract = false; 24 | // solium-disable-next-line security/no-inline-assembly 25 | assembly { 26 | isContract := not(iszero(extcodesize(_to))) 27 | } 28 | if (isContract) { 29 | ERC223ContractInterface receiver = ERC223ContractInterface(_to); 30 | receiver.tokenFallback(msg.sender, _value, _data); 31 | } 32 | return true; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /contracts/mocks/ERC721BasicTokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC721/ERC721BasicToken.sol"; 4 | 5 | 6 | /** 7 | * @title ERC721BasicTokenMock 8 | * This mock just provides a public mint and burn functions for testing purposes 9 | */ 10 | contract ERC721BasicTokenMock is ERC721BasicToken { 11 | function mint(address _to, uint256 _tokenId) public { 12 | super._mint(_to, _tokenId); 13 | } 14 | 15 | function burn(uint256 _tokenId) public { 16 | super._burn(ownerOf(_tokenId), _tokenId); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/mocks/ERC721ReceiverMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC721/ERC721Receiver.sol"; 4 | 5 | 6 | contract ERC721ReceiverMock is ERC721Receiver { 7 | bytes4 retval; 8 | bool reverts; 9 | 10 | event Received( 11 | address _address, 12 | uint256 _tokenId, 13 | bytes _data, 14 | uint256 _gas 15 | ); 16 | 17 | constructor(bytes4 _retval, bool _reverts) public { 18 | retval = _retval; 19 | reverts = _reverts; 20 | } 21 | 22 | function onERC721Received( 23 | address _address, 24 | uint256 _tokenId, 25 | bytes _data 26 | ) 27 | public 28 | returns(bytes4) 29 | { 30 | require(!reverts); 31 | emit Received( 32 | _address, 33 | _tokenId, 34 | _data, 35 | gasleft() // msg.gas was deprecated in solidityv0.4.21 36 | ); 37 | return retval; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /contracts/mocks/ERC721TokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC721/ERC721Token.sol"; 4 | 5 | 6 | /** 7 | * @title ERC721TokenMock 8 | * This mock just provides a public mint and burn functions for testing purposes, 9 | * and a public setter for metadata URI 10 | */ 11 | contract ERC721TokenMock is ERC721Token { 12 | constructor(string name, string symbol) public 13 | ERC721Token(name, symbol) 14 | { } 15 | 16 | function mint(address _to, uint256 _tokenId) public { 17 | super._mint(_to, _tokenId); 18 | } 19 | 20 | function burn(uint256 _tokenId) public { 21 | super._burn(ownerOf(_tokenId), _tokenId); 22 | } 23 | 24 | function setTokenURI(uint256 _tokenId, string _uri) public { 25 | super._setTokenURI(_tokenId, _uri); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contracts/mocks/ERC827TokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | import "../token/ERC827/ERC827Token.sol"; 5 | 6 | 7 | // mock class using ERC827 Token 8 | contract ERC827TokenMock is ERC827Token { 9 | 10 | constructor(address initialAccount, uint256 initialBalance) public { 11 | balances[initialAccount] = initialBalance; 12 | totalSupply_ = initialBalance; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /contracts/mocks/FinalizableCrowdsaleImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/MintableToken.sol"; 4 | import "../crowdsale/distribution/FinalizableCrowdsale.sol"; 5 | 6 | 7 | contract FinalizableCrowdsaleImpl is FinalizableCrowdsale { 8 | 9 | constructor ( 10 | uint256 _openingTime, 11 | uint256 _closingTime, 12 | uint256 _rate, 13 | address _wallet, 14 | MintableToken _token 15 | ) 16 | public 17 | Crowdsale(_rate, _wallet, _token) 18 | TimedCrowdsale(_openingTime, _closingTime) 19 | { 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /contracts/mocks/ForceEther.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | // @title Force Ether into a contract. 5 | // @notice even 6 | // if the contract is not payable. 7 | // @notice To use, construct the contract with the target as argument. 8 | // @author Remco Bloemen 9 | contract ForceEther { 10 | 11 | constructor() public payable { } 12 | 13 | function destroyAndSend(address _recipient) public { 14 | selfdestruct(_recipient); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /contracts/mocks/HasNoEtherTest.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../../contracts/ownership/HasNoEther.sol"; 4 | 5 | 6 | contract HasNoEtherTest is HasNoEther { 7 | 8 | // Constructor with explicit payable — should still fail 9 | constructor() public payable { 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /contracts/mocks/IncreasingPriceCrowdsaleImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../crowdsale/price/IncreasingPriceCrowdsale.sol"; 4 | import "../math/SafeMath.sol"; 5 | 6 | 7 | contract IncreasingPriceCrowdsaleImpl is IncreasingPriceCrowdsale { 8 | 9 | constructor ( 10 | uint256 _openingTime, 11 | uint256 _closingTime, 12 | address _wallet, 13 | ERC20 _token, 14 | uint256 _initialRate, 15 | uint256 _finalRate 16 | ) 17 | public 18 | Crowdsale(_initialRate, _wallet, _token) 19 | TimedCrowdsale(_openingTime, _closingTime) 20 | IncreasingPriceCrowdsale(_initialRate, _finalRate) 21 | { 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /contracts/mocks/IndividuallyCappedCrowdsaleImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/ERC20.sol"; 4 | import "../crowdsale/validation/IndividuallyCappedCrowdsale.sol"; 5 | 6 | 7 | contract IndividuallyCappedCrowdsaleImpl is IndividuallyCappedCrowdsale { 8 | 9 | constructor ( 10 | uint256 _rate, 11 | address _wallet, 12 | ERC20 _token 13 | ) 14 | public 15 | Crowdsale(_rate, _wallet, _token) 16 | { 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /contracts/mocks/InsecureTargetBounty.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import {Bounty, Target} from "../../contracts/Bounty.sol"; 4 | 5 | 6 | contract InsecureTargetMock is Target { 7 | function checkInvariant() public returns(bool) { 8 | return false; 9 | } 10 | } 11 | 12 | 13 | contract InsecureTargetBounty is Bounty { 14 | function deployContract() internal returns (address) { 15 | return new InsecureTargetMock(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contracts/mocks/LimitBalanceMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | import "../LimitBalance.sol"; 5 | 6 | 7 | // mock class using LimitBalance 8 | contract LimitBalanceMock is LimitBalance(1000) { 9 | 10 | function limitedDeposit() public payable limitedPayable { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /contracts/mocks/MathMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | import "../../contracts/math/Math.sol"; 5 | 6 | 7 | contract MathMock { 8 | uint64 public result64; 9 | uint256 public result256; 10 | 11 | function max64(uint64 a, uint64 b) public { 12 | result64 = Math.max64(a, b); 13 | } 14 | 15 | function min64(uint64 a, uint64 b) public { 16 | result64 = Math.min64(a, b); 17 | } 18 | 19 | function max256(uint256 a, uint256 b) public { 20 | result256 = Math.max256(a, b); 21 | } 22 | 23 | function min256(uint256 a, uint256 b) public { 24 | result256 = Math.min256(a, b); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/mocks/MerkleProofWrapper.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import { MerkleProof } from "../MerkleProof.sol"; 4 | 5 | 6 | contract MerkleProofWrapper { 7 | 8 | function verifyProof( 9 | bytes32[] _proof, 10 | bytes32 _root, 11 | bytes32 _leaf 12 | ) 13 | public 14 | pure 15 | returns (bool) 16 | { 17 | return MerkleProof.verifyProof(_proof, _root, _leaf); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/mocks/MessageHelper.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | contract MessageHelper { 5 | 6 | event Show(bytes32 b32, uint256 number, string text); 7 | event Buy(bytes32 b32, uint256 number, string text, uint256 value); 8 | 9 | function showMessage( 10 | bytes32 message, 11 | uint256 number, 12 | string text 13 | ) 14 | public 15 | returns (bool) 16 | { 17 | emit Show(message, number, text); 18 | return true; 19 | } 20 | 21 | function buyMessage( 22 | bytes32 message, 23 | uint256 number, 24 | string text 25 | ) 26 | public 27 | payable 28 | returns (bool) 29 | { 30 | emit Buy( 31 | message, 32 | number, 33 | text, 34 | msg.value); 35 | return true; 36 | } 37 | 38 | function fail() public { 39 | require(false); 40 | } 41 | 42 | function call(address to, bytes data) public returns (bool) { 43 | // solium-disable-next-line security/no-low-level-calls 44 | if (to.call(data)) 45 | return true; 46 | else 47 | return false; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /contracts/mocks/MintedCrowdsaleImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/MintableToken.sol"; 4 | import "../crowdsale/emission/MintedCrowdsale.sol"; 5 | 6 | 7 | contract MintedCrowdsaleImpl is MintedCrowdsale { 8 | 9 | constructor ( 10 | uint256 _rate, 11 | address _wallet, 12 | MintableToken _token 13 | ) 14 | public 15 | Crowdsale(_rate, _wallet, _token) 16 | { 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /contracts/mocks/PausableMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | import "../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 | constructor() public { 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 | -------------------------------------------------------------------------------- /contracts/mocks/PausableTokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/PausableToken.sol"; 4 | 5 | 6 | // mock class using PausableToken 7 | contract PausableTokenMock is PausableToken { 8 | 9 | constructor(address initialAccount, uint initialBalance) public { 10 | balances[initialAccount] = initialBalance; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /contracts/mocks/PostDeliveryCrowdsaleImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/ERC20.sol"; 4 | import "../crowdsale/distribution/PostDeliveryCrowdsale.sol"; 5 | 6 | 7 | contract PostDeliveryCrowdsaleImpl is PostDeliveryCrowdsale { 8 | 9 | constructor ( 10 | uint256 _openingTime, 11 | uint256 _closingTime, 12 | uint256 _rate, 13 | address _wallet, 14 | ERC20 _token 15 | ) 16 | public 17 | TimedCrowdsale(_openingTime, _closingTime) 18 | Crowdsale(_rate, _wallet, _token) 19 | { 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /contracts/mocks/PullPaymentMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | import "../payment/PullPayment.sol"; 5 | 6 | 7 | // mock class using PullPayment 8 | contract PullPaymentMock is PullPayment { 9 | 10 | constructor() public payable { } 11 | 12 | // test helper function to call asyncSend 13 | function callSend(address dest, uint256 amount) public { 14 | asyncSend(dest, amount); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /contracts/mocks/RBACMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../ownership/rbac/RBACWithAdmin.sol"; 4 | 5 | 6 | contract RBACMock is RBACWithAdmin { 7 | 8 | string constant ROLE_ADVISOR = "advisor"; 9 | 10 | modifier onlyAdminOrAdvisor() 11 | { 12 | require( 13 | hasRole(msg.sender, ROLE_ADMIN) || 14 | hasRole(msg.sender, ROLE_ADVISOR) 15 | ); 16 | _; 17 | } 18 | 19 | constructor(address[] _advisors) 20 | public 21 | { 22 | addRole(msg.sender, ROLE_ADVISOR); 23 | 24 | for (uint256 i = 0; i < _advisors.length; i++) { 25 | addRole(_advisors[i], ROLE_ADVISOR); 26 | } 27 | } 28 | 29 | function onlyAdminsCanDoThis() 30 | onlyAdmin 31 | view 32 | external 33 | { 34 | } 35 | 36 | function onlyAdvisorsCanDoThis() 37 | onlyRole(ROLE_ADVISOR) 38 | view 39 | external 40 | { 41 | } 42 | 43 | function eitherAdminOrAdvisorCanDoThis() 44 | onlyAdminOrAdvisor 45 | view 46 | external 47 | { 48 | } 49 | 50 | function nobodyCanDoThis() 51 | onlyRole("unknown") 52 | view 53 | external 54 | { 55 | } 56 | 57 | // admins can remove advisor's role 58 | function removeAdvisor(address _addr) 59 | onlyAdmin 60 | public 61 | { 62 | // revert if the user isn't an advisor 63 | // (perhaps you want to soft-fail here instead?) 64 | checkRole(_addr, ROLE_ADVISOR); 65 | 66 | // remove the advisor's role 67 | removeRole(_addr, ROLE_ADVISOR); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /contracts/mocks/ReentrancyAttack.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | contract ReentrancyAttack { 5 | 6 | function callSender(bytes4 data) public { 7 | // solium-disable-next-line security/no-low-level-calls 8 | require(msg.sender.call(data)); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /contracts/mocks/ReentrancyMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../ReentrancyGuard.sol"; 4 | import "./ReentrancyAttack.sol"; 5 | 6 | 7 | contract ReentrancyMock is ReentrancyGuard { 8 | 9 | uint256 public counter; 10 | 11 | constructor() public { 12 | counter = 0; 13 | } 14 | 15 | function callback() external nonReentrant { 16 | count(); 17 | } 18 | 19 | function countLocalRecursive(uint256 n) public nonReentrant { 20 | if (n > 0) { 21 | count(); 22 | countLocalRecursive(n - 1); 23 | } 24 | } 25 | 26 | function countThisRecursive(uint256 n) public nonReentrant { 27 | bytes4 func = bytes4(keccak256("countThisRecursive(uint256)")); 28 | if (n > 0) { 29 | count(); 30 | // solium-disable-next-line security/no-low-level-calls 31 | bool result = address(this).call(func, n - 1); 32 | require(result == true); 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 count() private { 43 | counter += 1; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /contracts/mocks/RefundableCrowdsaleImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/MintableToken.sol"; 4 | import "../crowdsale/distribution/RefundableCrowdsale.sol"; 5 | 6 | 7 | contract RefundableCrowdsaleImpl is RefundableCrowdsale { 8 | 9 | constructor ( 10 | uint256 _openingTime, 11 | uint256 _closingTime, 12 | uint256 _rate, 13 | address _wallet, 14 | MintableToken _token, 15 | uint256 _goal 16 | ) 17 | public 18 | Crowdsale(_rate, _wallet, _token) 19 | TimedCrowdsale(_openingTime, _closingTime) 20 | RefundableCrowdsale(_goal) 21 | { 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /contracts/mocks/SafeERC20Helper.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/ERC20.sol"; 4 | import "../token/ERC20/SafeERC20.sol"; 5 | 6 | 7 | contract ERC20FailingMock is ERC20 { 8 | function totalSupply() public view returns (uint256) { 9 | return 0; 10 | } 11 | 12 | function transfer(address, uint256) public returns (bool) { 13 | return false; 14 | } 15 | 16 | function transferFrom(address, address, uint256) public returns (bool) { 17 | return false; 18 | } 19 | 20 | function approve(address, uint256) public returns (bool) { 21 | return false; 22 | } 23 | 24 | function balanceOf(address) public view returns (uint256) { 25 | return 0; 26 | } 27 | 28 | function allowance(address, address) public view returns (uint256) { 29 | return 0; 30 | } 31 | } 32 | 33 | 34 | contract ERC20SucceedingMock is ERC20 { 35 | function totalSupply() public view returns (uint256) { 36 | return 0; 37 | } 38 | 39 | function transfer(address, uint256) public returns (bool) { 40 | return true; 41 | } 42 | 43 | function transferFrom(address, address, uint256) public returns (bool) { 44 | return true; 45 | } 46 | 47 | function approve(address, uint256) public returns (bool) { 48 | return true; 49 | } 50 | 51 | function balanceOf(address) public view returns (uint256) { 52 | return 0; 53 | } 54 | 55 | function allowance(address, address) public view returns (uint256) { 56 | return 0; 57 | } 58 | } 59 | 60 | 61 | contract SafeERC20Helper { 62 | using SafeERC20 for ERC20; 63 | 64 | ERC20 failing; 65 | ERC20 succeeding; 66 | 67 | constructor() public { 68 | failing = new ERC20FailingMock(); 69 | succeeding = new ERC20SucceedingMock(); 70 | } 71 | 72 | function doFailingTransfer() public { 73 | failing.safeTransfer(0, 0); 74 | } 75 | 76 | function doFailingTransferFrom() public { 77 | failing.safeTransferFrom(0, 0, 0); 78 | } 79 | 80 | function doFailingApprove() public { 81 | failing.safeApprove(0, 0); 82 | } 83 | 84 | function doSucceedingTransfer() public { 85 | succeeding.safeTransfer(0, 0); 86 | } 87 | 88 | function doSucceedingTransferFrom() public { 89 | succeeding.safeTransferFrom(0, 0, 0); 90 | } 91 | 92 | function doSucceedingApprove() public { 93 | succeeding.safeApprove(0, 0); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /contracts/mocks/SafeMathMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | import "../math/SafeMath.sol"; 5 | 6 | 7 | contract SafeMathMock { 8 | 9 | function mul(uint256 a, uint256 b) public pure returns (uint256) { 10 | return SafeMath.mul(a, b); 11 | } 12 | 13 | function div(uint256 a, uint256 b) public pure returns (uint256) { 14 | return SafeMath.div(a, b); 15 | } 16 | 17 | function sub(uint256 a, uint256 b) public pure returns (uint256) { 18 | return SafeMath.sub(a, b); 19 | } 20 | 21 | function add(uint256 a, uint256 b) public pure returns (uint256) { 22 | return SafeMath.add(a, b); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/mocks/SecureTargetBounty.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import {Bounty, Target} from "../../contracts/Bounty.sol"; 4 | 5 | 6 | contract SecureTargetMock is Target { 7 | function checkInvariant() public returns(bool) { 8 | return true; 9 | } 10 | } 11 | 12 | 13 | contract SecureTargetBounty is Bounty { 14 | function deployContract() internal returns (address) { 15 | return new SecureTargetMock(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contracts/mocks/StandardBurnableTokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/StandardBurnableToken.sol"; 4 | 5 | 6 | contract StandardBurnableTokenMock is StandardBurnableToken { 7 | 8 | constructor(address initialAccount, uint initialBalance) public { 9 | balances[initialAccount] = initialBalance; 10 | totalSupply_ = initialBalance; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /contracts/mocks/StandardTokenMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/StandardToken.sol"; 4 | 5 | 6 | // mock class using StandardToken 7 | contract StandardTokenMock is StandardToken { 8 | 9 | constructor(address initialAccount, uint256 initialBalance) public { 10 | balances[initialAccount] = initialBalance; 11 | totalSupply_ = initialBalance; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /contracts/mocks/TimedCrowdsaleImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/ERC20.sol"; 4 | import "../crowdsale/validation/TimedCrowdsale.sol"; 5 | 6 | 7 | contract TimedCrowdsaleImpl is TimedCrowdsale { 8 | 9 | constructor ( 10 | uint256 _openingTime, 11 | uint256 _closingTime, 12 | uint256 _rate, 13 | address _wallet, 14 | ERC20 _token 15 | ) 16 | public 17 | Crowdsale(_rate, _wallet, _token) 18 | TimedCrowdsale(_openingTime, _closingTime) 19 | { 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /contracts/mocks/WhitelistMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../ownership/Whitelist.sol"; 4 | 5 | 6 | contract WhitelistMock is Whitelist { 7 | 8 | function onlyWhitelistedCanDoThis() 9 | onlyWhitelisted 10 | view 11 | external 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /contracts/mocks/WhitelistedCrowdsaleImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../token/ERC20/ERC20.sol"; 4 | import "../crowdsale/validation/WhitelistedCrowdsale.sol"; 5 | 6 | 7 | contract WhitelistedCrowdsaleImpl is WhitelistedCrowdsale { 8 | 9 | constructor ( 10 | uint256 _rate, 11 | address _wallet, 12 | ERC20 _token 13 | ) 14 | public 15 | Crowdsale(_rate, _wallet, _token) 16 | { 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /contracts/ownership/CanReclaimToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./Ownable.sol"; 4 | import "../token/ERC20/ERC20Basic.sol"; 5 | import "../token/ERC20/SafeERC20.sol"; 6 | 7 | 8 | /** 9 | * @title Contracts that should be able to recover tokens 10 | * @author SylTi 11 | * @dev This allow a contract to recover any ERC20 token received in a contract by transferring the balance to the contract owner. 12 | * This will prevent any accidental loss of tokens. 13 | */ 14 | contract CanReclaimToken is Ownable { 15 | using SafeERC20 for ERC20Basic; 16 | 17 | /** 18 | * @dev Reclaim all ERC20Basic compatible tokens 19 | * @param token ERC20Basic The address of the token contract 20 | */ 21 | function reclaimToken(ERC20Basic token) external onlyOwner { 22 | uint256 balance = token.balanceOf(this); 23 | token.safeTransfer(owner, balance); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /contracts/ownership/Claimable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 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 | emit OwnershipTransferred(owner, pendingOwner); 36 | owner = pendingOwner; 37 | pendingOwner = address(0); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /contracts/ownership/Contactable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./Ownable.sol"; 4 | 5 | 6 | /** 7 | * @title Contactable token 8 | * @dev Basic version of a contactable contract, allowing the owner to provide a string with their 9 | * contact information. 10 | */ 11 | contract Contactable is Ownable { 12 | 13 | string public contactInformation; 14 | 15 | /** 16 | * @dev Allows the owner to set a string with their contact information. 17 | * @param info The contact information to attach to the contract. 18 | */ 19 | function setContactInformation(string info) onlyOwner public { 20 | contactInformation = info; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contracts/ownership/DelayedClaimable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./Claimable.sol"; 4 | 5 | 6 | /** 7 | * @title DelayedClaimable 8 | * @dev Extension for the Claimable contract, where the ownership needs to be claimed before/after 9 | * a certain block number. 10 | */ 11 | contract DelayedClaimable is Claimable { 12 | 13 | uint256 public end; 14 | uint256 public start; 15 | 16 | /** 17 | * @dev Used to specify the time period during which a pending 18 | * owner can claim ownership. 19 | * @param _start The earliest time ownership can be claimed. 20 | * @param _end The latest time ownership can be claimed. 21 | */ 22 | function setLimits(uint256 _start, uint256 _end) onlyOwner public { 23 | require(_start <= _end); 24 | end = _end; 25 | start = _start; 26 | } 27 | 28 | /** 29 | * @dev Allows the pendingOwner address to finalize the transfer, as long as it is called within 30 | * the specified start and end time. 31 | */ 32 | function claimOwnership() onlyPendingOwner public { 33 | require((block.number <= end) && (block.number >= start)); 34 | emit OwnershipTransferred(owner, pendingOwner); 35 | owner = pendingOwner; 36 | pendingOwner = address(0); 37 | end = 0; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /contracts/ownership/HasNoContracts.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./Ownable.sol"; 4 | 5 | 6 | /** 7 | * @title Contracts that should not own Contracts 8 | * @author Remco Bloemen 9 | * @dev Should contracts (anything Ownable) end up being owned by this contract, it allows the owner 10 | * of this contract to reclaim ownership of the contracts. 11 | */ 12 | contract HasNoContracts is Ownable { 13 | 14 | /** 15 | * @dev Reclaim ownership of Ownable contracts 16 | * @param contractAddr The address of the Ownable to be reclaimed. 17 | */ 18 | function reclaimContract(address contractAddr) external onlyOwner { 19 | Ownable contractInst = Ownable(contractAddr); 20 | contractInst.transferOwnership(owner); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contracts/ownership/HasNoEther.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./Ownable.sol"; 4 | 5 | 6 | /** 7 | * @title Contracts that should not own Ether 8 | * @author Remco Bloemen 9 | * @dev This tries to block incoming ether to prevent accidental loss of Ether. Should Ether end up 10 | * in the contract, it will allow the owner to reclaim this ether. 11 | * @notice Ether can still be sent to this contract by: 12 | * calling functions labeled `payable` 13 | * `selfdestruct(contract_address)` 14 | * mining directly to the contract address 15 | */ 16 | contract HasNoEther is Ownable { 17 | 18 | /** 19 | * @dev Constructor that rejects incoming Ether 20 | * @dev The `payable` flag is added so we can access `msg.value` without compiler warning. If we 21 | * leave out payable, then Solidity will allow inheriting contracts to implement a payable 22 | * constructor. By doing it this way we prevent a payable constructor from working. Alternatively 23 | * we could use assembly to access msg.value. 24 | */ 25 | constructor() public payable { 26 | require(msg.value == 0); 27 | } 28 | 29 | /** 30 | * @dev Disallows direct send by settings a default function without the `payable` flag. 31 | */ 32 | function() external { 33 | } 34 | 35 | /** 36 | * @dev Transfer all Ether held by the contract to the owner. 37 | */ 38 | function reclaimEther() external onlyOwner { 39 | owner.transfer(this.balance); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /contracts/ownership/HasNoTokens.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./CanReclaimToken.sol"; 4 | 5 | 6 | /** 7 | * @title Contracts that should not own Tokens 8 | * @author Remco Bloemen 9 | * @dev This blocks incoming ERC223 tokens to prevent accidental loss of tokens. 10 | * Should tokens (any ERC20Basic compatible) end up in the contract, it allows the 11 | * owner to reclaim the tokens. 12 | */ 13 | contract HasNoTokens is CanReclaimToken { 14 | 15 | /** 16 | * @dev Reject all ERC223 compatible tokens 17 | * @param from_ address The address that is transferring the tokens 18 | * @param value_ uint256 the amount of the specified token 19 | * @param data_ Bytes The data passed from the caller. 20 | */ 21 | function tokenFallback(address from_, uint256 value_, bytes data_) external { 22 | from_; 23 | value_; 24 | data_; 25 | revert(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /contracts/ownership/NoOwner.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./HasNoEther.sol"; 4 | import "./HasNoTokens.sol"; 5 | import "./HasNoContracts.sol"; 6 | 7 | 8 | /** 9 | * @title Base contract for contracts that should not own things. 10 | * @author Remco Bloemen 11 | * @dev Solves a class of errors where a contract accidentally becomes owner of Ether, Tokens or 12 | * Owned contracts. See respective base contracts for details. 13 | */ 14 | contract NoOwner is HasNoEther, HasNoTokens, HasNoContracts { 15 | } 16 | -------------------------------------------------------------------------------- /contracts/ownership/Ownable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 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 OwnershipRenounced(address indexed previousOwner); 14 | event OwnershipTransferred( 15 | address indexed previousOwner, 16 | address indexed newOwner 17 | ); 18 | 19 | 20 | /** 21 | * @dev The Ownable constructor sets the original `owner` of the contract to the sender 22 | * account. 23 | */ 24 | constructor() public { 25 | owner = msg.sender; 26 | } 27 | 28 | /** 29 | * @dev Throws if called by any account other than the owner. 30 | */ 31 | modifier onlyOwner() { 32 | require(msg.sender == owner); 33 | _; 34 | } 35 | 36 | /** 37 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 38 | * @param newOwner The address to transfer ownership to. 39 | */ 40 | function transferOwnership(address newOwner) public onlyOwner { 41 | require(newOwner != address(0)); 42 | emit OwnershipTransferred(owner, newOwner); 43 | owner = newOwner; 44 | } 45 | 46 | /** 47 | * @dev Allows the current owner to relinquish control of the contract. 48 | */ 49 | function renounceOwnership() public onlyOwner { 50 | emit OwnershipRenounced(owner); 51 | owner = address(0); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /contracts/ownership/Whitelist.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | import "./Ownable.sol"; 5 | import "./rbac/RBAC.sol"; 6 | 7 | 8 | /** 9 | * @title Whitelist 10 | * @dev The Whitelist contract has a whitelist of addresses, and provides basic authorization control functions. 11 | * @dev This simplifies the implementation of "user permissions". 12 | */ 13 | contract Whitelist is Ownable, RBAC { 14 | event WhitelistedAddressAdded(address addr); 15 | event WhitelistedAddressRemoved(address addr); 16 | 17 | string public constant ROLE_WHITELISTED = "whitelist"; 18 | 19 | /** 20 | * @dev Throws if called by any account that's not whitelisted. 21 | */ 22 | modifier onlyWhitelisted() { 23 | checkRole(msg.sender, ROLE_WHITELISTED); 24 | _; 25 | } 26 | 27 | /** 28 | * @dev add an address to the whitelist 29 | * @param addr address 30 | * @return true if the address was added to the whitelist, false if the address was already in the whitelist 31 | */ 32 | function addAddressToWhitelist(address addr) 33 | onlyOwner 34 | public 35 | { 36 | addRole(addr, ROLE_WHITELISTED); 37 | emit WhitelistedAddressAdded(addr); 38 | } 39 | 40 | /** 41 | * @dev getter to determine if address is in whitelist 42 | */ 43 | function whitelist(address addr) 44 | public 45 | view 46 | returns (bool) 47 | { 48 | return hasRole(addr, ROLE_WHITELISTED); 49 | } 50 | 51 | /** 52 | * @dev add addresses to the whitelist 53 | * @param addrs addresses 54 | * @return true if at least one address was added to the whitelist, 55 | * false if all addresses were already in the whitelist 56 | */ 57 | function addAddressesToWhitelist(address[] addrs) 58 | onlyOwner 59 | public 60 | { 61 | for (uint256 i = 0; i < addrs.length; i++) { 62 | addAddressToWhitelist(addrs[i]); 63 | } 64 | } 65 | 66 | /** 67 | * @dev remove an address from the whitelist 68 | * @param addr address 69 | * @return true if the address was removed from the whitelist, 70 | * false if the address wasn't in the whitelist in the first place 71 | */ 72 | function removeAddressFromWhitelist(address addr) 73 | onlyOwner 74 | public 75 | { 76 | removeRole(addr, ROLE_WHITELISTED); 77 | emit WhitelistedAddressRemoved(addr); 78 | } 79 | 80 | /** 81 | * @dev remove addresses from the whitelist 82 | * @param addrs addresses 83 | * @return true if at least one address was removed from the whitelist, 84 | * false if all addresses weren't in the whitelist in the first place 85 | */ 86 | function removeAddressesFromWhitelist(address[] addrs) 87 | onlyOwner 88 | public 89 | { 90 | for (uint256 i = 0; i < addrs.length; i++) { 91 | removeAddressFromWhitelist(addrs[i]); 92 | } 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /contracts/ownership/rbac/RBACWithAdmin.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./RBAC.sol"; 4 | 5 | 6 | /** 7 | * @title RBACWithAdmin 8 | * @author Matt Condon (@Shrugs) 9 | * @dev It's recommended that you define constants in the contract, 10 | * @dev like ROLE_ADMIN below, to avoid typos. 11 | */ 12 | contract RBACWithAdmin is RBAC { 13 | /** 14 | * A constant role name for indicating admins. 15 | */ 16 | string public constant ROLE_ADMIN = "admin"; 17 | 18 | /** 19 | * @dev modifier to scope access to admins 20 | * // reverts 21 | */ 22 | modifier onlyAdmin() 23 | { 24 | checkRole(msg.sender, ROLE_ADMIN); 25 | _; 26 | } 27 | 28 | /** 29 | * @dev constructor. Sets msg.sender as admin by default 30 | */ 31 | constructor() 32 | public 33 | { 34 | addRole(msg.sender, ROLE_ADMIN); 35 | } 36 | 37 | /** 38 | * @dev add a role to an address 39 | * @param addr address 40 | * @param roleName the name of the role 41 | */ 42 | function adminAddRole(address addr, string roleName) 43 | onlyAdmin 44 | public 45 | { 46 | addRole(addr, roleName); 47 | } 48 | 49 | /** 50 | * @dev remove a role from an address 51 | * @param addr address 52 | * @param roleName the name of the role 53 | */ 54 | function adminRemoveRole(address addr, string roleName) 55 | onlyAdmin 56 | public 57 | { 58 | removeRole(addr, roleName); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /contracts/ownership/rbac/Roles.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | /** 5 | * @title Roles 6 | * @author Francisco Giordano (@frangio) 7 | * @dev Library for managing addresses assigned to a Role. 8 | * See RBAC.sol for example usage. 9 | */ 10 | library Roles { 11 | struct Role { 12 | mapping (address => bool) bearer; 13 | } 14 | 15 | /** 16 | * @dev give an address access to this role 17 | */ 18 | function add(Role storage role, address addr) 19 | internal 20 | { 21 | role.bearer[addr] = true; 22 | } 23 | 24 | /** 25 | * @dev remove an address' access to this role 26 | */ 27 | function remove(Role storage role, address addr) 28 | internal 29 | { 30 | role.bearer[addr] = false; 31 | } 32 | 33 | /** 34 | * @dev check if an address has this role 35 | * // reverts 36 | */ 37 | function check(Role storage role, address addr) 38 | view 39 | internal 40 | { 41 | require(has(role, addr)); 42 | } 43 | 44 | /** 45 | * @dev check if an address has this role 46 | * @return bool 47 | */ 48 | function has(Role storage role, address addr) 49 | view 50 | internal 51 | returns (bool) 52 | { 53 | return role.bearer[addr]; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /contracts/payment/PullPayment.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 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 or transfer. 11 | */ 12 | contract PullPayment { 13 | using SafeMath for uint256; 14 | 15 | mapping(address => uint256) public payments; 16 | uint256 public totalPayments; 17 | 18 | /** 19 | * @dev Withdraw accumulated balance, called by payee. 20 | */ 21 | function withdrawPayments() public { 22 | address payee = msg.sender; 23 | uint256 payment = payments[payee]; 24 | 25 | require(payment != 0); 26 | require(address(this).balance >= payment); 27 | 28 | totalPayments = totalPayments.sub(payment); 29 | payments[payee] = 0; 30 | 31 | payee.transfer(payment); 32 | } 33 | 34 | /** 35 | * @dev Called by the payer to store the sent amount as credit to be pulled. 36 | * @param dest The destination address of the funds. 37 | * @param amount The amount to transfer. 38 | */ 39 | function asyncSend(address dest, uint256 amount) internal { 40 | payments[dest] = payments[dest].add(amount); 41 | totalPayments = totalPayments.add(amount); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/payment/SplitPayment.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "../math/SafeMath.sol"; 4 | 5 | 6 | /** 7 | * @title SplitPayment 8 | * @dev Base contract that supports multiple payees claiming funds sent to this contract 9 | * according to the proportion they own. 10 | */ 11 | contract SplitPayment { 12 | using SafeMath for uint256; 13 | 14 | uint256 public totalShares = 0; 15 | uint256 public totalReleased = 0; 16 | 17 | mapping(address => uint256) public shares; 18 | mapping(address => uint256) public released; 19 | address[] public payees; 20 | 21 | /** 22 | * @dev Constructor 23 | */ 24 | constructor(address[] _payees, uint256[] _shares) public payable { 25 | require(_payees.length == _shares.length); 26 | 27 | for (uint256 i = 0; i < _payees.length; i++) { 28 | addPayee(_payees[i], _shares[i]); 29 | } 30 | } 31 | 32 | /** 33 | * @dev payable fallback 34 | */ 35 | function () public payable {} 36 | 37 | /** 38 | * @dev Claim your share of the balance. 39 | */ 40 | function claim() public { 41 | address payee = msg.sender; 42 | 43 | require(shares[payee] > 0); 44 | 45 | uint256 totalReceived = address(this).balance.add(totalReleased); 46 | uint256 payment = totalReceived.mul( 47 | shares[payee]).div( 48 | totalShares).sub( 49 | released[payee] 50 | ); 51 | 52 | require(payment != 0); 53 | require(address(this).balance >= payment); 54 | 55 | released[payee] = released[payee].add(payment); 56 | totalReleased = totalReleased.add(payment); 57 | 58 | payee.transfer(payment); 59 | } 60 | 61 | /** 62 | * @dev Add a new payee to the contract. 63 | * @param _payee The address of the payee to add. 64 | * @param _shares The number of shares owned by the payee. 65 | */ 66 | function addPayee(address _payee, uint256 _shares) internal { 67 | require(_payee != address(0)); 68 | require(_shares > 0); 69 | require(shares[_payee] == 0); 70 | 71 | payees.push(_payee); 72 | shares[_payee] = _shares; 73 | totalShares = totalShares.add(_shares); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /contracts/token/ERC20/BasicToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 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 | uint256 totalSupply_; 18 | 19 | /** 20 | * @dev total number of tokens in existence 21 | */ 22 | function totalSupply() public view returns (uint256) { 23 | return totalSupply_; 24 | } 25 | 26 | /** 27 | * @dev transfer token for a specified address 28 | * @param _to The address to transfer to. 29 | * @param _value The amount to be transferred. 30 | */ 31 | function transfer(address _to, uint256 _value) public returns (bool) { 32 | require(_to != address(0)); 33 | require(_value <= balances[msg.sender]); 34 | 35 | balances[msg.sender] = balances[msg.sender].sub(_value); 36 | balances[_to] = balances[_to].add(_value); 37 | emit Transfer(msg.sender, _to, _value); 38 | return true; 39 | } 40 | 41 | /** 42 | * @dev Gets the balance of the specified address. 43 | * @param _owner The address to query the the balance of. 44 | * @return An uint256 representing the amount owned by the passed address. 45 | */ 46 | function balanceOf(address _owner) public view returns (uint256) { 47 | return balances[_owner]; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /contracts/token/ERC20/BurnableToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./BasicToken.sol"; 4 | 5 | 6 | /** 7 | * @title Burnable Token 8 | * @dev Token that can be irreversibly burned (destroyed). 9 | */ 10 | contract BurnableToken is BasicToken { 11 | 12 | event Burn(address indexed burner, uint256 value); 13 | 14 | /** 15 | * @dev Burns a specific amount of tokens. 16 | * @param _value The amount of token to be burned. 17 | */ 18 | function burn(uint256 _value) public { 19 | _burn(msg.sender, _value); 20 | } 21 | 22 | function _burn(address _who, uint256 _value) internal { 23 | require(_value <= balances[_who]); 24 | // no need to require value <= totalSupply, since that would imply the 25 | // sender's balance is greater than the totalSupply, which *should* be an assertion failure 26 | 27 | balances[_who] = balances[_who].sub(_value); 28 | totalSupply_ = totalSupply_.sub(_value); 29 | emit Burn(_who, _value); 30 | emit Transfer(_who, address(0), _value); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /contracts/token/ERC20/CappedToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./MintableToken.sol"; 4 | 5 | 6 | /** 7 | * @title Capped token 8 | * @dev Mintable token with a token cap. 9 | */ 10 | contract CappedToken is MintableToken { 11 | 12 | uint256 public cap; 13 | 14 | constructor(uint256 _cap) public { 15 | require(_cap > 0); 16 | cap = _cap; 17 | } 18 | 19 | /** 20 | * @dev Function to mint tokens 21 | * @param _to The address that will receive the minted tokens. 22 | * @param _amount The amount of tokens to mint. 23 | * @return A boolean that indicates if the operation was successful. 24 | */ 25 | function mint( 26 | address _to, 27 | uint256 _amount 28 | ) 29 | onlyOwner 30 | canMint 31 | public 32 | returns (bool) 33 | { 34 | require(totalSupply_.add(_amount) <= cap); 35 | 36 | return super.mint(_to, _amount); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /contracts/token/ERC20/DetailedERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./ERC20.sol"; 4 | 5 | 6 | contract DetailedERC20 is ERC20 { 7 | string public name; 8 | string public symbol; 9 | uint8 public decimals; 10 | 11 | constructor(string _name, string _symbol, uint8 _decimals) public { 12 | name = _name; 13 | symbol = _symbol; 14 | decimals = _decimals; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /contracts/token/ERC20/ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./ERC20Basic.sol"; 4 | 5 | 6 | /** 7 | * @title ERC20 interface 8 | * @dev see https://github.com/ethereum/EIPs/issues/20 9 | */ 10 | contract ERC20 is ERC20Basic { 11 | function allowance(address owner, address spender) 12 | public view returns (uint256); 13 | 14 | function transferFrom(address from, address to, uint256 value) 15 | public returns (bool); 16 | 17 | function approve(address spender, uint256 value) public returns (bool); 18 | event Approval( 19 | address indexed owner, 20 | address indexed spender, 21 | uint256 value 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /contracts/token/ERC20/ERC20Basic.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 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 | function totalSupply() public view returns (uint256); 11 | function balanceOf(address who) public view 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/ERC20/MintableToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./StandardToken.sol"; 4 | import "../../ownership/Ownable.sol"; 5 | 6 | 7 | /** 8 | * @title Mintable token 9 | * @dev Simple ERC20 Token example, with mintable token creation 10 | * @dev Issue: * https://github.com/OpenZeppelin/openzeppelin-solidity/issues/120 11 | * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol 12 | */ 13 | contract MintableToken is StandardToken, Ownable { 14 | event Mint(address indexed to, uint256 amount); 15 | event MintFinished(); 16 | 17 | bool public mintingFinished = false; 18 | 19 | 20 | modifier canMint() { 21 | require(!mintingFinished); 22 | _; 23 | } 24 | 25 | modifier hasMintPermission() { 26 | require(msg.sender == owner); 27 | _; 28 | } 29 | 30 | /** 31 | * @dev Function to mint tokens 32 | * @param _to The address that will receive the minted tokens. 33 | * @param _amount The amount of tokens to mint. 34 | * @return A boolean that indicates if the operation was successful. 35 | */ 36 | function mint( 37 | address _to, 38 | uint256 _amount 39 | ) 40 | hasMintPermission 41 | canMint 42 | public 43 | returns (bool) 44 | { 45 | totalSupply_ = totalSupply_.add(_amount); 46 | balances[_to] = balances[_to].add(_amount); 47 | emit Mint(_to, _amount); 48 | emit Transfer(address(0), _to, _amount); 49 | return true; 50 | } 51 | 52 | /** 53 | * @dev Function to stop minting new tokens. 54 | * @return True if the operation was successful. 55 | */ 56 | function finishMinting() onlyOwner canMint public returns (bool) { 57 | mintingFinished = true; 58 | emit MintFinished(); 59 | return true; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /contracts/token/ERC20/PausableToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./StandardToken.sol"; 4 | import "../../lifecycle/Pausable.sol"; 5 | 6 | 7 | /** 8 | * @title Pausable token 9 | * @dev StandardToken modified with pausable transfers. 10 | **/ 11 | contract PausableToken is StandardToken, Pausable { 12 | 13 | function transfer( 14 | address _to, 15 | uint256 _value 16 | ) 17 | public 18 | whenNotPaused 19 | returns (bool) 20 | { 21 | return super.transfer(_to, _value); 22 | } 23 | 24 | function transferFrom( 25 | address _from, 26 | address _to, 27 | uint256 _value 28 | ) 29 | public 30 | whenNotPaused 31 | returns (bool) 32 | { 33 | return super.transferFrom(_from, _to, _value); 34 | } 35 | 36 | function approve( 37 | address _spender, 38 | uint256 _value 39 | ) 40 | public 41 | whenNotPaused 42 | returns (bool) 43 | { 44 | return super.approve(_spender, _value); 45 | } 46 | 47 | function increaseApproval( 48 | address _spender, 49 | uint _addedValue 50 | ) 51 | public 52 | whenNotPaused 53 | returns (bool success) 54 | { 55 | return super.increaseApproval(_spender, _addedValue); 56 | } 57 | 58 | function decreaseApproval( 59 | address _spender, 60 | uint _subtractedValue 61 | ) 62 | public 63 | whenNotPaused 64 | returns (bool success) 65 | { 66 | return super.decreaseApproval(_spender, _subtractedValue); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /contracts/token/ERC20/RBACMintableToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./MintableToken.sol"; 4 | import "../../ownership/rbac/RBAC.sol"; 5 | 6 | 7 | /** 8 | * @title RBACMintableToken 9 | * @author Vittorio Minacori (@vittominacori) 10 | * @dev Mintable Token, with RBAC minter permissions 11 | */ 12 | contract RBACMintableToken is MintableToken, RBAC { 13 | /** 14 | * A constant role name for indicating minters. 15 | */ 16 | string public constant ROLE_MINTER = "minter"; 17 | 18 | /** 19 | * @dev override the Mintable token modifier to add role based logic 20 | */ 21 | modifier hasMintPermission() { 22 | checkRole(msg.sender, ROLE_MINTER); 23 | _; 24 | } 25 | 26 | /** 27 | * @dev add a minter role to an address 28 | * @param minter address 29 | */ 30 | function addMinter(address minter) onlyOwner public { 31 | addRole(minter, ROLE_MINTER); 32 | } 33 | 34 | /** 35 | * @dev remove a minter role from an address 36 | * @param minter address 37 | */ 38 | function removeMinter(address minter) onlyOwner public { 39 | removeRole(minter, ROLE_MINTER); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /contracts/token/ERC20/SafeERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./ERC20Basic.sol"; 4 | import "./ERC20.sol"; 5 | 6 | 7 | /** 8 | * @title SafeERC20 9 | * @dev Wrappers around ERC20 operations that throw on failure. 10 | * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, 11 | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. 12 | */ 13 | library SafeERC20 { 14 | function safeTransfer(ERC20Basic token, address to, uint256 value) internal { 15 | require(token.transfer(to, value)); 16 | } 17 | 18 | function safeTransferFrom( 19 | ERC20 token, 20 | address from, 21 | address to, 22 | uint256 value 23 | ) 24 | internal 25 | { 26 | require(token.transferFrom(from, to, value)); 27 | } 28 | 29 | function safeApprove(ERC20 token, address spender, uint256 value) internal { 30 | require(token.approve(spender, value)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /contracts/token/ERC20/StandardBurnableToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./BurnableToken.sol"; 4 | import "./StandardToken.sol"; 5 | 6 | 7 | /** 8 | * @title Standard Burnable Token 9 | * @dev Adds burnFrom method to ERC20 implementations 10 | */ 11 | contract StandardBurnableToken is BurnableToken, StandardToken { 12 | 13 | /** 14 | * @dev Burns a specific amount of tokens from the target address and decrements allowance 15 | * @param _from address The address which you want to send tokens from 16 | * @param _value uint256 The amount of token to be burned 17 | */ 18 | function burnFrom(address _from, uint256 _value) public { 19 | require(_value <= allowed[_from][msg.sender]); 20 | // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted, 21 | // this function needs to emit an event with the updated approval. 22 | allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); 23 | _burn(_from, _value); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /contracts/token/ERC20/TokenTimelock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./SafeERC20.sol"; 4 | 5 | 6 | /** 7 | * @title TokenTimelock 8 | * @dev TokenTimelock is a token holder contract that will allow a 9 | * beneficiary to extract the tokens after a given release time 10 | */ 11 | contract TokenTimelock { 12 | using SafeERC20 for ERC20Basic; 13 | 14 | // ERC20 basic token contract being held 15 | ERC20Basic public token; 16 | 17 | // beneficiary of tokens after they are released 18 | address public beneficiary; 19 | 20 | // timestamp when token release is enabled 21 | uint256 public releaseTime; 22 | 23 | constructor( 24 | ERC20Basic _token, 25 | address _beneficiary, 26 | uint256 _releaseTime 27 | ) 28 | public 29 | { 30 | // solium-disable-next-line security/no-block-members 31 | require(_releaseTime > block.timestamp); 32 | token = _token; 33 | beneficiary = _beneficiary; 34 | releaseTime = _releaseTime; 35 | } 36 | 37 | /** 38 | * @notice Transfers tokens held by timelock to beneficiary. 39 | */ 40 | function release() public { 41 | // solium-disable-next-line security/no-block-members 42 | require(block.timestamp >= releaseTime); 43 | 44 | uint256 amount = token.balanceOf(this); 45 | require(amount > 0); 46 | 47 | token.safeTransfer(beneficiary, amount); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contracts/token/ERC721/DeprecatedERC721.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./ERC721.sol"; 4 | 5 | 6 | /** 7 | * @title ERC-721 methods shipped in OpenZeppelin v1.7.0, removed in the latest version of the standard 8 | * @dev Only use this interface for compatibility with previously deployed contracts 9 | * @dev Use ERC721 for interacting with new contracts which are standard-compliant 10 | */ 11 | contract DeprecatedERC721 is ERC721 { 12 | function takeOwnership(uint256 _tokenId) public; 13 | function transfer(address _to, uint256 _tokenId) public; 14 | function tokensOf(address _owner) public view returns (uint256[]); 15 | } 16 | -------------------------------------------------------------------------------- /contracts/token/ERC721/ERC721.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./ERC721Basic.sol"; 4 | 5 | 6 | /** 7 | * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension 8 | * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 9 | */ 10 | contract ERC721Enumerable is ERC721Basic { 11 | function totalSupply() public view returns (uint256); 12 | function tokenOfOwnerByIndex( 13 | address _owner, 14 | uint256 _index 15 | ) 16 | public 17 | view 18 | returns (uint256 _tokenId); 19 | 20 | function tokenByIndex(uint256 _index) public view returns (uint256); 21 | } 22 | 23 | 24 | /** 25 | * @title ERC-721 Non-Fungible Token Standard, optional metadata extension 26 | * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 27 | */ 28 | contract ERC721Metadata is ERC721Basic { 29 | function name() public view returns (string _name); 30 | function symbol() public view returns (string _symbol); 31 | function tokenURI(uint256 _tokenId) public view returns (string); 32 | } 33 | 34 | 35 | /** 36 | * @title ERC-721 Non-Fungible Token Standard, full implementation interface 37 | * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 38 | */ 39 | contract ERC721 is ERC721Basic, ERC721Enumerable, ERC721Metadata { 40 | } 41 | -------------------------------------------------------------------------------- /contracts/token/ERC721/ERC721Basic.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | /** 5 | * @title ERC721 Non-Fungible Token Standard basic interface 6 | * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 7 | */ 8 | contract ERC721Basic { 9 | event Transfer( 10 | address indexed _from, 11 | address indexed _to, 12 | uint256 _tokenId 13 | ); 14 | event Approval( 15 | address indexed _owner, 16 | address indexed _approved, 17 | uint256 _tokenId 18 | ); 19 | event ApprovalForAll( 20 | address indexed _owner, 21 | address indexed _operator, 22 | bool _approved 23 | ); 24 | 25 | function balanceOf(address _owner) public view returns (uint256 _balance); 26 | function ownerOf(uint256 _tokenId) public view returns (address _owner); 27 | function exists(uint256 _tokenId) public view returns (bool _exists); 28 | 29 | function approve(address _to, uint256 _tokenId) public; 30 | function getApproved(uint256 _tokenId) 31 | public view returns (address _operator); 32 | 33 | function setApprovalForAll(address _operator, bool _approved) public; 34 | function isApprovedForAll(address _owner, address _operator) 35 | public view returns (bool); 36 | 37 | function transferFrom(address _from, address _to, uint256 _tokenId) public; 38 | function safeTransferFrom(address _from, address _to, uint256 _tokenId) 39 | public; 40 | 41 | function safeTransferFrom( 42 | address _from, 43 | address _to, 44 | uint256 _tokenId, 45 | bytes _data 46 | ) 47 | public; 48 | } 49 | -------------------------------------------------------------------------------- /contracts/token/ERC721/ERC721Holder.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./ERC721Receiver.sol"; 4 | 5 | 6 | contract ERC721Holder is ERC721Receiver { 7 | function onERC721Received(address, uint256, bytes) public returns(bytes4) { 8 | return ERC721_RECEIVED; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /contracts/token/ERC721/ERC721Receiver.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | /** 5 | * @title ERC721 token receiver interface 6 | * @dev Interface for any contract that wants to support safeTransfers 7 | * from ERC721 asset contracts. 8 | */ 9 | contract ERC721Receiver { 10 | /** 11 | * @dev Magic value to be returned upon successful reception of an NFT 12 | * Equals to `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`, 13 | * which can be also obtained as `ERC721Receiver(0).onERC721Received.selector` 14 | */ 15 | bytes4 constant ERC721_RECEIVED = 0xf0b9e5ba; 16 | 17 | /** 18 | * @notice Handle the receipt of an NFT 19 | * @dev The ERC721 smart contract calls this function on the recipient 20 | * after a `safetransfer`. This function MAY throw to revert and reject the 21 | * transfer. This function MUST use 50,000 gas or less. Return of other 22 | * than the magic value MUST result in the transaction being reverted. 23 | * Note: the contract address is always the message sender. 24 | * @param _from The sending address 25 | * @param _tokenId The NFT identifier which is being transfered 26 | * @param _data Additional data with no specified format 27 | * @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))` 28 | */ 29 | function onERC721Received( 30 | address _from, 31 | uint256 _tokenId, 32 | bytes _data 33 | ) 34 | public 35 | returns(bytes4); 36 | } 37 | -------------------------------------------------------------------------------- /contracts/token/ERC827/ERC827.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | import "../ERC20/ERC20.sol"; 5 | 6 | 7 | /** 8 | * @title ERC827 interface, an extension of ERC20 token standard 9 | * 10 | * @dev Interface of a ERC827 token, following the ERC20 standard with extra 11 | * @dev methods to transfer value and data and execute calls in transfers and 12 | * @dev approvals. 13 | */ 14 | contract ERC827 is ERC20 { 15 | function approveAndCall( 16 | address _spender, 17 | uint256 _value, 18 | bytes _data 19 | ) 20 | public 21 | payable 22 | returns (bool); 23 | 24 | function transferAndCall( 25 | address _to, 26 | uint256 _value, 27 | bytes _data 28 | ) 29 | public 30 | payable 31 | returns (bool); 32 | 33 | function transferFromAndCall( 34 | address _from, 35 | address _to, 36 | uint256 _value, 37 | bytes _data 38 | ) 39 | public 40 | payable 41 | returns (bool); 42 | } 43 | -------------------------------------------------------------------------------- /ethpm.json: -------------------------------------------------------------------------------- 1 | { 2 | "package_name": "zeppelin", 3 | "version": "1.9.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/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConsenSysMesh/openzeppelin-solidity/d5f06ab32ff40bf447fa34bcdb997b54e2499ee0/migrations/.gitkeep -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openzeppelin-solidity", 3 | "version": "1.9.0", 4 | "description": "Secure Smart Contract library for Solidity", 5 | "files": [ 6 | "contracts", 7 | "test" 8 | ], 9 | "scripts": { 10 | "test": "scripts/test.sh", 11 | "lint": "eslint .", 12 | "lint:fix": "eslint . --fix", 13 | "lint:sol": "solium -d .", 14 | "lint:sol:fix": "solium -d . --fix", 15 | "lint:all": "npm run lint && npm run lint:sol", 16 | "lint:all:fix": "npm run lint:fix && npm run lint:sol:fix", 17 | "console": "truffle console", 18 | "coverage": "scripts/coverage.sh", 19 | "version": "scripts/version.js" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/OpenZeppelin/zeppelin-solidity.git" 24 | }, 25 | "keywords": [ 26 | "solidity", 27 | "ethereum", 28 | "smart", 29 | "contracts", 30 | "security", 31 | "zeppelin" 32 | ], 33 | "author": "Manuel Araoz ", 34 | "license": "MIT", 35 | "bugs": { 36 | "url": "https://github.com/OpenZeppelin/zeppelin-solidity/issues" 37 | }, 38 | "homepage": "https://github.com/OpenZeppelin/zeppelin-solidity", 39 | "devDependencies": { 40 | "babel-polyfill": "^6.23.0", 41 | "babel-preset-es2015": "^6.18.0", 42 | "babel-preset-stage-2": "^6.18.0", 43 | "babel-preset-stage-3": "^6.17.0", 44 | "babel-register": "^6.23.0", 45 | "chai": "^4.0.2", 46 | "chai-as-promised": "^7.0.0", 47 | "chai-bignumber": "^2.0.0", 48 | "coveralls": "^2.13.1", 49 | "dotenv": "^4.0.0", 50 | "eslint": "^4.11.0", 51 | "eslint-config-standard": "^10.2.1", 52 | "eslint-plugin-import": "^2.8.0", 53 | "eslint-plugin-node": "^5.2.1", 54 | "eslint-plugin-promise": "^3.6.0", 55 | "eslint-plugin-standard": "^3.0.1", 56 | "ethereumjs-util": "^5.1.2", 57 | "ethjs-abi": "^0.2.1", 58 | "ganache-cli": "6.1.0", 59 | "solidity-coverage": "^0.5.0", 60 | "solium": "^1.1.7", 61 | "truffle": "^4.1.8", 62 | "truffle-hdwallet-provider": "0.0.3" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /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 ganache instance that we started (if we started one and if it's still running). 11 | if [ -n "$ganache_pid" ] && ps -p $ganache_pid > /dev/null; then 12 | kill -9 $ganache_pid 13 | fi 14 | } 15 | 16 | if [ "$SOLIDITY_COVERAGE" = true ]; then 17 | ganache_port=8555 18 | else 19 | ganache_port=8545 20 | fi 21 | 22 | ganache_running() { 23 | nc -z localhost "$ganache_port" 24 | } 25 | 26 | start_ganache() { 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 "$ganache_port" "${accounts[@]}" > /dev/null & 43 | else 44 | node_modules/.bin/ganache-cli --gasLimit 0xfffffffffff "${accounts[@]}" > /dev/null & 45 | fi 46 | 47 | ganache_pid=$! 48 | } 49 | 50 | if ganache_running; then 51 | echo "Using existing ganache instance" 52 | else 53 | echo "Starting our own ganache instance" 54 | start_ganache 55 | fi 56 | 57 | if [ "$SOLC_NIGHTLY" = true ]; then 58 | echo "Downloading solc nightly" 59 | wget -q https://raw.githubusercontent.com/ethereum/solc-bin/gh-pages/bin/soljson-nightly.js -O /tmp/soljson.js && find . -name soljson.js -exec cp /tmp/soljson.js {} \; 60 | fi 61 | 62 | if [ "$SOLIDITY_COVERAGE" = true ]; then 63 | node_modules/.bin/solidity-coverage 64 | 65 | if [ "$CONTINUOUS_INTEGRATION" = true ]; then 66 | cat coverage/lcov.info | node_modules/.bin/coveralls 67 | fi 68 | else 69 | node_modules/.bin/truffle test "$@" 70 | fi 71 | -------------------------------------------------------------------------------- /scripts/version.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // Synchronizes ethpm.json version number with package.json. 4 | // Useful to run as an npm script alogn with `npm version`. 5 | 6 | const fs = require('fs'); 7 | const cp = require('child_process'); 8 | 9 | const pkg = require('../package.json'); 10 | const ethpm = require('../ethpm.json'); 11 | 12 | ethpm.version = pkg.version; 13 | 14 | fs.writeFileSync('ethpm.json', JSON.stringify(ethpm, null, 2) + '\n'); 15 | 16 | cp.execSync('git add ethpm.json'); 17 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-unused-expressions": 0 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/DayLimit.test.js: -------------------------------------------------------------------------------- 1 | 2 | import latestTime from './helpers/latestTime'; 3 | import { increaseTimeTo, duration } from './helpers/increaseTime'; 4 | 5 | import assertRevert from './helpers/assertRevert'; 6 | 7 | const DayLimitMock = artifacts.require('DayLimitMock'); 8 | 9 | contract('DayLimit', function (accounts) { 10 | let dayLimit; 11 | let initLimit = 10; 12 | 13 | beforeEach(async function () { 14 | this.startTime = latestTime(); 15 | dayLimit = await DayLimitMock.new(initLimit); 16 | }); 17 | 18 | it('should construct with the passed daily limit', async function () { 19 | let dailyLimit = await dayLimit.dailyLimit(); 20 | assert.equal(initLimit, dailyLimit); 21 | }); 22 | 23 | it('should be able to spend if daily limit is not reached', async function () { 24 | await dayLimit.attemptSpend(8); 25 | let spentToday = await dayLimit.spentToday(); 26 | assert.equal(spentToday, 8); 27 | 28 | await dayLimit.attemptSpend(2); 29 | spentToday = await dayLimit.spentToday(); 30 | assert.equal(spentToday, 10); 31 | }); 32 | 33 | it('should prevent spending if daily limit is reached', async function () { 34 | await dayLimit.attemptSpend(8); 35 | let spentToday = await dayLimit.spentToday(); 36 | assert.equal(spentToday, 8); 37 | await assertRevert(dayLimit.attemptSpend(3)); 38 | }); 39 | 40 | it('should allow spending if daily limit is reached and then set higher', async function () { 41 | await dayLimit.attemptSpend(8); 42 | let spentToday = await dayLimit.spentToday(); 43 | assert.equal(spentToday, 8); 44 | 45 | await assertRevert(dayLimit.attemptSpend(3)); 46 | spentToday = await dayLimit.spentToday(); 47 | assert.equal(spentToday, 8); 48 | 49 | await dayLimit.setDailyLimit(15); 50 | await dayLimit.attemptSpend(3); 51 | spentToday = await dayLimit.spentToday(); 52 | assert.equal(spentToday, 11); 53 | }); 54 | 55 | it('should allow spending if daily limit is reached and then amount spent is reset', async function () { 56 | await dayLimit.attemptSpend(8); 57 | let spentToday = await dayLimit.spentToday(); 58 | assert.equal(spentToday, 8); 59 | 60 | await assertRevert(dayLimit.attemptSpend(3)); 61 | spentToday = await dayLimit.spentToday(); 62 | assert.equal(spentToday, 8); 63 | 64 | await dayLimit.resetSpentToday(); 65 | await dayLimit.attemptSpend(3); 66 | spentToday = await dayLimit.spentToday(); 67 | assert.equal(spentToday, 3); 68 | }); 69 | 70 | it('should allow spending if daily limit is reached and then the next has come', async function () { 71 | let limit = 10; 72 | let dayLimit = await DayLimitMock.new(limit); 73 | 74 | await dayLimit.attemptSpend(8); 75 | let spentToday = await dayLimit.spentToday(); 76 | assert.equal(spentToday, 8); 77 | 78 | await assertRevert(dayLimit.attemptSpend(3)); 79 | spentToday = await dayLimit.spentToday(); 80 | assert.equal(spentToday, 8); 81 | 82 | await increaseTimeTo(this.startTime + duration.days(1)); 83 | 84 | await dayLimit.attemptSpend(3); 85 | spentToday = await dayLimit.spentToday(); 86 | assert.equal(spentToday, 3); 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /test/LimitBalance.test.js: -------------------------------------------------------------------------------- 1 | import assertRevert from './helpers/assertRevert'; 2 | var LimitBalanceMock = artifacts.require('LimitBalanceMock'); 3 | 4 | contract('LimitBalance', function (accounts) { 5 | let lb; 6 | 7 | beforeEach(async function () { 8 | lb = await LimitBalanceMock.new(); 9 | }); 10 | 11 | let LIMIT = 1000; 12 | 13 | it('should expose limit', async function () { 14 | let limit = await lb.limit(); 15 | assert.equal(limit, LIMIT); 16 | }); 17 | 18 | it('should allow sending below limit', async function () { 19 | let amount = 1; 20 | await lb.limitedDeposit({ value: amount }); 21 | 22 | assert.equal(web3.eth.getBalance(lb.address), amount); 23 | }); 24 | 25 | it('shouldnt allow sending above limit', async function () { 26 | let amount = 1110; 27 | await assertRevert(lb.limitedDeposit({ value: amount })); 28 | }); 29 | 30 | it('should allow multiple sends below limit', async function () { 31 | let amount = 500; 32 | await lb.limitedDeposit({ value: amount }); 33 | 34 | assert.equal(web3.eth.getBalance(lb.address), amount); 35 | 36 | await lb.limitedDeposit({ value: amount }); 37 | assert.equal(web3.eth.getBalance(lb.address), amount * 2); 38 | }); 39 | 40 | it('shouldnt allow multiple sends above limit', async function () { 41 | let amount = 500; 42 | await lb.limitedDeposit({ value: amount }); 43 | 44 | assert.equal(web3.eth.getBalance(lb.address), amount); 45 | await assertRevert(lb.limitedDeposit({ value: amount + 1 })); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /test/ReentrancyGuard.test.js: -------------------------------------------------------------------------------- 1 | 2 | import expectThrow from './helpers/expectThrow'; 3 | const ReentrancyMock = artifacts.require('ReentrancyMock'); 4 | const ReentrancyAttack = artifacts.require('ReentrancyAttack'); 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 than 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/SimpleSavingsWallet.test.js: -------------------------------------------------------------------------------- 1 | 2 | import expectThrow from './helpers/expectThrow'; 3 | 4 | const SimpleSavingsWallet = artifacts.require('SimpleSavingsWallet'); 5 | 6 | contract('SimpleSavingsWallet', function (accounts) { 7 | let savingsWallet; 8 | let owner; 9 | 10 | const paymentAmount = 4242; 11 | 12 | beforeEach(async function () { 13 | savingsWallet = await SimpleSavingsWallet.new(4141); 14 | owner = await savingsWallet.owner(); 15 | }); 16 | 17 | it('should receive funds', async function () { 18 | await web3.eth.sendTransaction({ from: owner, to: savingsWallet.address, value: paymentAmount }); 19 | assert.isTrue((new web3.BigNumber(paymentAmount)).equals(web3.eth.getBalance(savingsWallet.address))); 20 | }); 21 | 22 | it('owner can send funds', async function () { 23 | // Receive payment so we have some money to spend. 24 | await web3.eth.sendTransaction({ from: accounts[9], to: savingsWallet.address, value: 1000000 }); 25 | await expectThrow(savingsWallet.sendTo(0, paymentAmount, { from: owner })); 26 | await expectThrow(savingsWallet.sendTo(savingsWallet.address, paymentAmount, { from: owner })); 27 | await expectThrow(savingsWallet.sendTo(accounts[1], 0, { from: owner })); 28 | 29 | const balance = web3.eth.getBalance(accounts[1]); 30 | await savingsWallet.sendTo(accounts[1], paymentAmount, { from: owner }); 31 | assert.isTrue(balance.plus(paymentAmount).equals(web3.eth.getBalance(accounts[1]))); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/crowdsale/CappedCrowdsale.test.js: -------------------------------------------------------------------------------- 1 | import ether from '../helpers/ether'; 2 | import EVMRevert from '../helpers/EVMRevert'; 3 | 4 | const BigNumber = web3.BigNumber; 5 | 6 | require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should(); 10 | 11 | const CappedCrowdsale = artifacts.require('CappedCrowdsaleImpl'); 12 | const SimpleToken = artifacts.require('SimpleToken'); 13 | 14 | contract('CappedCrowdsale', function ([_, wallet]) { 15 | const rate = new BigNumber(1); 16 | const cap = ether(100); 17 | const lessThanCap = ether(60); 18 | const tokenSupply = new BigNumber('1e22'); 19 | 20 | beforeEach(async function () { 21 | this.token = await SimpleToken.new(); 22 | this.crowdsale = await CappedCrowdsale.new(rate, wallet, this.token.address, cap); 23 | await this.token.transfer(this.crowdsale.address, tokenSupply); 24 | }); 25 | 26 | describe('creating a valid crowdsale', function () { 27 | it('should fail with zero cap', async function () { 28 | await CappedCrowdsale.new(rate, wallet, 0, this.token.address).should.be.rejectedWith(EVMRevert); 29 | }); 30 | }); 31 | 32 | describe('accepting payments', function () { 33 | it('should accept payments within cap', async function () { 34 | await this.crowdsale.send(cap.minus(lessThanCap)).should.be.fulfilled; 35 | await this.crowdsale.send(lessThanCap).should.be.fulfilled; 36 | }); 37 | 38 | it('should reject payments outside cap', async function () { 39 | await this.crowdsale.send(cap); 40 | await this.crowdsale.send(1).should.be.rejectedWith(EVMRevert); 41 | }); 42 | 43 | it('should reject payments that exceed cap', async function () { 44 | await this.crowdsale.send(cap.plus(1)).should.be.rejectedWith(EVMRevert); 45 | }); 46 | }); 47 | 48 | describe('ending', function () { 49 | it('should not reach cap if sent under cap', async function () { 50 | let capReached = await this.crowdsale.capReached(); 51 | capReached.should.equal(false); 52 | await this.crowdsale.send(lessThanCap); 53 | capReached = await this.crowdsale.capReached(); 54 | capReached.should.equal(false); 55 | }); 56 | 57 | it('should not reach cap if sent just under cap', async function () { 58 | await this.crowdsale.send(cap.minus(1)); 59 | let capReached = await this.crowdsale.capReached(); 60 | capReached.should.equal(false); 61 | }); 62 | 63 | it('should reach cap if cap sent', async function () { 64 | await this.crowdsale.send(cap); 65 | let capReached = await this.crowdsale.capReached(); 66 | capReached.should.equal(true); 67 | }); 68 | }); 69 | }); 70 | -------------------------------------------------------------------------------- /test/crowdsale/FinalizableCrowdsale.test.js: -------------------------------------------------------------------------------- 1 | import { advanceBlock } from '../helpers/advanceToBlock'; 2 | import { increaseTimeTo, duration } from '../helpers/increaseTime'; 3 | import latestTime from '../helpers/latestTime'; 4 | import EVMRevert from '../helpers/EVMRevert'; 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('FinalizableCrowdsaleImpl'); 14 | const MintableToken = artifacts.require('MintableToken'); 15 | 16 | contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) { 17 | const rate = new BigNumber(1000); 18 | 19 | before(async function () { 20 | // Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache 21 | await advanceBlock(); 22 | }); 23 | 24 | beforeEach(async function () { 25 | this.openingTime = latestTime() + duration.weeks(1); 26 | this.closingTime = this.openingTime + duration.weeks(1); 27 | this.afterClosingTime = this.closingTime + duration.seconds(1); 28 | 29 | this.token = await MintableToken.new(); 30 | this.crowdsale = await FinalizableCrowdsale.new( 31 | this.openingTime, this.closingTime, rate, wallet, this.token.address, { from: owner } 32 | ); 33 | await this.token.transferOwnership(this.crowdsale.address); 34 | }); 35 | 36 | it('cannot be finalized before ending', async function () { 37 | await this.crowdsale.finalize({ from: owner }).should.be.rejectedWith(EVMRevert); 38 | }); 39 | 40 | it('cannot be finalized by third party after ending', async function () { 41 | await increaseTimeTo(this.afterClosingTime); 42 | await this.crowdsale.finalize({ from: thirdparty }).should.be.rejectedWith(EVMRevert); 43 | }); 44 | 45 | it('can be finalized by owner after ending', async function () { 46 | await increaseTimeTo(this.afterClosingTime); 47 | await this.crowdsale.finalize({ from: owner }).should.be.fulfilled; 48 | }); 49 | 50 | it('cannot be finalized twice', async function () { 51 | await increaseTimeTo(this.afterClosingTime); 52 | await this.crowdsale.finalize({ from: owner }); 53 | await this.crowdsale.finalize({ from: owner }).should.be.rejectedWith(EVMRevert); 54 | }); 55 | 56 | it('logs finalized', async function () { 57 | await increaseTimeTo(this.afterClosingTime); 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 | -------------------------------------------------------------------------------- /test/crowdsale/MintedCrowdsale.behaviour.js: -------------------------------------------------------------------------------- 1 | const BigNumber = web3.BigNumber; 2 | 3 | const should = require('chai') 4 | .use(require('chai-as-promised')) 5 | .use(require('chai-bignumber')(BigNumber)) 6 | .should(); 7 | 8 | export default function ([_, investor, wallet, purchaser], rate, value) { 9 | const expectedTokenAmount = rate.mul(value); 10 | 11 | describe('as a minted crowdsale', function () { 12 | describe('accepting payments', function () { 13 | it('should accept payments', async function () { 14 | await this.crowdsale.send(value).should.be.fulfilled; 15 | await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }).should.be.fulfilled; 16 | }); 17 | }); 18 | 19 | describe('high-level purchase', function () { 20 | it('should log purchase', async function () { 21 | const { logs } = await this.crowdsale.sendTransaction({ value: value, from: investor }); 22 | const event = logs.find(e => e.event === 'TokenPurchase'); 23 | should.exist(event); 24 | event.args.purchaser.should.equal(investor); 25 | event.args.beneficiary.should.equal(investor); 26 | event.args.value.should.be.bignumber.equal(value); 27 | event.args.amount.should.be.bignumber.equal(expectedTokenAmount); 28 | }); 29 | 30 | it('should assign tokens to sender', async function () { 31 | await this.crowdsale.sendTransaction({ value: value, from: investor }); 32 | let balance = await this.token.balanceOf(investor); 33 | balance.should.be.bignumber.equal(expectedTokenAmount); 34 | }); 35 | 36 | it('should forward funds to wallet', async function () { 37 | const pre = web3.eth.getBalance(wallet); 38 | await this.crowdsale.sendTransaction({ value, from: investor }); 39 | const post = web3.eth.getBalance(wallet); 40 | post.minus(pre).should.be.bignumber.equal(value); 41 | }); 42 | }); 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /test/crowdsale/MintedCrowdsale.test.js: -------------------------------------------------------------------------------- 1 | import shouldBehaveLikeMintedCrowdsale from './MintedCrowdsale.behaviour'; 2 | import ether from '../helpers/ether'; 3 | 4 | const BigNumber = web3.BigNumber; 5 | 6 | const MintedCrowdsale = artifacts.require('MintedCrowdsaleImpl'); 7 | const MintableToken = artifacts.require('MintableToken'); 8 | const RBACMintableToken = artifacts.require('RBACMintableToken'); 9 | 10 | contract('MintedCrowdsale', function ([_, investor, wallet, purchaser]) { 11 | const rate = new BigNumber(1000); 12 | const value = ether(5); 13 | 14 | describe('using MintableToken', function () { 15 | beforeEach(async function () { 16 | this.token = await MintableToken.new(); 17 | this.crowdsale = await MintedCrowdsale.new(rate, wallet, this.token.address); 18 | await this.token.transferOwnership(this.crowdsale.address); 19 | }); 20 | 21 | it('should be token owner', async function () { 22 | const owner = await this.token.owner(); 23 | owner.should.equal(this.crowdsale.address); 24 | }); 25 | 26 | shouldBehaveLikeMintedCrowdsale([_, investor, wallet, purchaser], rate, value); 27 | }); 28 | 29 | describe('using RBACMintableToken', function () { 30 | const ROLE_MINTER = 'minter'; 31 | 32 | beforeEach(async function () { 33 | this.token = await RBACMintableToken.new(); 34 | this.crowdsale = await MintedCrowdsale.new(rate, wallet, this.token.address); 35 | await this.token.addMinter(this.crowdsale.address); 36 | }); 37 | 38 | it('should have minter role on token', async function () { 39 | const isMinter = await this.token.hasRole(this.crowdsale.address, ROLE_MINTER); 40 | isMinter.should.equal(true); 41 | }); 42 | 43 | shouldBehaveLikeMintedCrowdsale([_, investor, wallet, purchaser], rate, value); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /test/crowdsale/PostDeliveryCrowdsale.test.js: -------------------------------------------------------------------------------- 1 | import { advanceBlock } from '../helpers/advanceToBlock'; 2 | import { increaseTimeTo, duration } from '../helpers/increaseTime'; 3 | import latestTime from '../helpers/latestTime'; 4 | import EVMRevert from '../helpers/EVMRevert'; 5 | import ether from '../helpers/ether'; 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 PostDeliveryCrowdsale = artifacts.require('PostDeliveryCrowdsaleImpl'); 15 | const SimpleToken = artifacts.require('SimpleToken'); 16 | 17 | contract('PostDeliveryCrowdsale', function ([_, investor, wallet, purchaser]) { 18 | const rate = new BigNumber(1); 19 | const value = ether(42); 20 | const tokenSupply = new BigNumber('1e22'); 21 | 22 | before(async function () { 23 | // Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache 24 | await advanceBlock(); 25 | }); 26 | 27 | beforeEach(async function () { 28 | this.openingTime = latestTime() + duration.weeks(1); 29 | this.closingTime = this.openingTime + duration.weeks(1); 30 | this.beforeEndTime = this.closingTime - duration.hours(1); 31 | this.afterClosingTime = this.closingTime + duration.seconds(1); 32 | this.token = await SimpleToken.new(); 33 | this.crowdsale = await PostDeliveryCrowdsale.new( 34 | this.openingTime, this.closingTime, rate, wallet, this.token.address 35 | ); 36 | await this.token.transfer(this.crowdsale.address, tokenSupply); 37 | }); 38 | 39 | it('should not immediately assign tokens to beneficiary', async function () { 40 | await increaseTimeTo(this.openingTime); 41 | await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); 42 | const balance = await this.token.balanceOf(investor); 43 | balance.should.be.bignumber.equal(0); 44 | }); 45 | 46 | it('should not allow beneficiaries to withdraw tokens before crowdsale ends', async function () { 47 | await increaseTimeTo(this.beforeEndTime); 48 | await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); 49 | await this.crowdsale.withdrawTokens({ from: investor }).should.be.rejectedWith(EVMRevert); 50 | }); 51 | 52 | it('should allow beneficiaries to withdraw tokens after crowdsale ends', async function () { 53 | await increaseTimeTo(this.openingTime); 54 | await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); 55 | await increaseTimeTo(this.afterClosingTime); 56 | await this.crowdsale.withdrawTokens({ from: investor }).should.be.fulfilled; 57 | }); 58 | 59 | it('should return the amount of tokens bought', async function () { 60 | await increaseTimeTo(this.openingTime); 61 | await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); 62 | await increaseTimeTo(this.afterClosingTime); 63 | await this.crowdsale.withdrawTokens({ from: investor }); 64 | const balance = await this.token.balanceOf(investor); 65 | balance.should.be.bignumber.equal(value); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /test/crowdsale/RefundVault.test.js: -------------------------------------------------------------------------------- 1 | import ether from '../helpers/ether'; 2 | import EVMRevert from '../helpers/EVMRevert'; 3 | 4 | const BigNumber = web3.BigNumber; 5 | 6 | require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should(); 10 | 11 | const RefundVault = artifacts.require('RefundVault'); 12 | 13 | contract('RefundVault', function ([_, owner, wallet, investor]) { 14 | const value = ether(42); 15 | 16 | beforeEach(async function () { 17 | this.vault = await RefundVault.new(wallet, { from: owner }); 18 | }); 19 | 20 | it('should accept contributions', async function () { 21 | await this.vault.deposit(investor, { value, from: owner }).should.be.fulfilled; 22 | }); 23 | 24 | it('should not refund contribution during active state', async function () { 25 | await this.vault.deposit(investor, { value, from: owner }); 26 | await this.vault.refund(investor).should.be.rejectedWith(EVMRevert); 27 | }); 28 | 29 | it('only owner can enter refund mode', async function () { 30 | await this.vault.enableRefunds({ from: _ }).should.be.rejectedWith(EVMRevert); 31 | await this.vault.enableRefunds({ from: owner }).should.be.fulfilled; 32 | }); 33 | 34 | it('should refund contribution after entering refund mode', async function () { 35 | await this.vault.deposit(investor, { value, from: owner }); 36 | await this.vault.enableRefunds({ from: owner }); 37 | 38 | const pre = web3.eth.getBalance(investor); 39 | await this.vault.refund(investor); 40 | const post = web3.eth.getBalance(investor); 41 | 42 | post.minus(pre).should.be.bignumber.equal(value); 43 | }); 44 | 45 | it('only owner can close', async function () { 46 | await this.vault.close({ from: _ }).should.be.rejectedWith(EVMRevert); 47 | await this.vault.close({ from: owner }).should.be.fulfilled; 48 | }); 49 | 50 | it('should forward funds to wallet after closing', async function () { 51 | await this.vault.deposit(investor, { value, from: owner }); 52 | 53 | const pre = web3.eth.getBalance(wallet); 54 | await this.vault.close({ from: owner }); 55 | const post = web3.eth.getBalance(wallet); 56 | 57 | post.minus(pre).should.be.bignumber.equal(value); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /test/crowdsale/TimedCrowdsale.test.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 EVMRevert from '../helpers/EVMRevert'; 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 TimedCrowdsale = artifacts.require('TimedCrowdsaleImpl'); 15 | const SimpleToken = artifacts.require('SimpleToken'); 16 | 17 | contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) { 18 | const rate = new BigNumber(1); 19 | const value = ether(42); 20 | const tokenSupply = new BigNumber('1e22'); 21 | 22 | before(async function () { 23 | // Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache 24 | await advanceBlock(); 25 | }); 26 | 27 | beforeEach(async function () { 28 | this.openingTime = latestTime() + duration.weeks(1); 29 | this.closingTime = this.openingTime + duration.weeks(1); 30 | this.afterClosingTime = this.closingTime + duration.seconds(1); 31 | this.token = await SimpleToken.new(); 32 | this.crowdsale = await TimedCrowdsale.new(this.openingTime, this.closingTime, rate, wallet, this.token.address); 33 | await this.token.transfer(this.crowdsale.address, tokenSupply); 34 | }); 35 | 36 | it('should be ended only after end', async function () { 37 | let ended = await this.crowdsale.hasClosed(); 38 | ended.should.equal(false); 39 | await increaseTimeTo(this.afterClosingTime); 40 | ended = await this.crowdsale.hasClosed(); 41 | ended.should.equal(true); 42 | }); 43 | 44 | describe('accepting payments', function () { 45 | it('should reject payments before start', async function () { 46 | await this.crowdsale.send(value).should.be.rejectedWith(EVMRevert); 47 | await this.crowdsale.buyTokens(investor, { from: purchaser, value: value }).should.be.rejectedWith(EVMRevert); 48 | }); 49 | 50 | it('should accept payments after start', async function () { 51 | await increaseTimeTo(this.openingTime); 52 | await this.crowdsale.send(value).should.be.fulfilled; 53 | await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }).should.be.fulfilled; 54 | }); 55 | 56 | it('should reject payments after end', async function () { 57 | await increaseTimeTo(this.afterClosingTime); 58 | await this.crowdsale.send(value).should.be.rejectedWith(EVMRevert); 59 | await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }).should.be.rejectedWith(EVMRevert); 60 | }); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /test/examples/SimpleToken.test.js: -------------------------------------------------------------------------------- 1 | import decodeLogs from '../helpers/decodeLogs'; 2 | const SimpleToken = artifacts.require('SimpleToken'); 3 | 4 | contract('SimpleToken', accounts => { 5 | let token; 6 | const creator = accounts[0]; 7 | 8 | beforeEach(async function () { 9 | token = await SimpleToken.new({ from: creator }); 10 | }); 11 | 12 | it('has a name', async function () { 13 | const name = await token.name(); 14 | assert.equal(name, 'SimpleToken'); 15 | }); 16 | 17 | it('has a symbol', async function () { 18 | const symbol = await token.symbol(); 19 | assert.equal(symbol, 'SIM'); 20 | }); 21 | 22 | it('has 18 decimals', async function () { 23 | const decimals = await token.decimals(); 24 | assert(decimals.eq(18)); 25 | }); 26 | 27 | it('assigns the initial total supply to the creator', async function () { 28 | const totalSupply = await token.totalSupply(); 29 | const creatorBalance = await token.balanceOf(creator); 30 | 31 | assert(creatorBalance.eq(totalSupply)); 32 | 33 | const receipt = web3.eth.getTransactionReceipt(token.transactionHash); 34 | const logs = decodeLogs(receipt.logs, SimpleToken, token.address); 35 | assert.equal(logs.length, 1); 36 | assert.equal(logs[0].event, 'Transfer'); 37 | assert.equal(logs[0].args.from.valueOf(), 0x0); 38 | assert.equal(logs[0].args.to.valueOf(), creator); 39 | assert(logs[0].args.value.eq(totalSupply)); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test/helpers/EVMRevert.js: -------------------------------------------------------------------------------- 1 | export default 'revert'; 2 | -------------------------------------------------------------------------------- /test/helpers/EVMThrow.js: -------------------------------------------------------------------------------- 1 | export default 'invalid opcode'; 2 | -------------------------------------------------------------------------------- /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 | export default async promise => { 2 | try { 3 | await promise; 4 | assert.fail('Expected invalid opcode not received'); 5 | } catch (error) { 6 | const invalidOpcodeReceived = error.message.search('invalid opcode') >= 0; 7 | assert(invalidOpcodeReceived, `Expected "invalid opcode", got ${error} instead`); 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /test/helpers/assertRevert.js: -------------------------------------------------------------------------------- 1 | export default async promise => { 2 | try { 3 | await promise; 4 | assert.fail('Expected revert not received'); 5 | } catch (error) { 6 | const revertFound = error.message.search('revert') >= 0; 7 | assert(revertFound, `Expected "revert", got ${error} instead`); 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /test/helpers/decodeLogs.js: -------------------------------------------------------------------------------- 1 | const SolidityEvent = require('web3/lib/web3/event.js'); 2 | 3 | export default function decodeLogs (logs, contract, address) { 4 | return logs.map(log => { 5 | const event = new SolidityEvent(null, contract.events[log.topics[0]], address); 6 | return event.decode(log); 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /test/helpers/ether.js: -------------------------------------------------------------------------------- 1 | export default function ether (n) { 2 | return new web3.BigNumber(web3.toWei(n, 'ether')); 3 | } 4 | -------------------------------------------------------------------------------- /test/helpers/expectEvent.js: -------------------------------------------------------------------------------- 1 | const assert = require('chai').assert; 2 | 3 | const inLogs = async (logs, eventName) => { 4 | const event = logs.find(e => e.event === eventName); 5 | assert.exists(event); 6 | return event; 7 | }; 8 | 9 | const inTransaction = async (tx, eventName) => { 10 | const { logs } = await tx; 11 | return inLogs(logs, eventName); 12 | }; 13 | 14 | module.exports = { 15 | inLogs, 16 | inTransaction, 17 | }; 18 | -------------------------------------------------------------------------------- /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 | // ganache log actually show an 'invalid jump' event.) 12 | const outOfGas = error.message.search('out of gas') >= 0; 13 | const revert = error.message.search('revert') >= 0; 14 | assert( 15 | invalidOpcode || outOfGas || revert, 16 | 'Expected throw, got \'' + error + '\' instead', 17 | ); 18 | return; 19 | } 20 | assert.fail('Expected throw not received'); 21 | }; 22 | -------------------------------------------------------------------------------- /test/helpers/increaseTime.js: -------------------------------------------------------------------------------- 1 | import latestTime from './latestTime'; 2 | 3 | // Increases ganache 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 ganache 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/sendTransaction.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const ethjsABI = require('ethjs-abi'); 3 | 4 | export function findMethod (abi, name, args) { 5 | for (var i = 0; i < abi.length; i++) { 6 | const methodArgs = _.map(abi[i].inputs, 'type').join(','); 7 | if ((abi[i].name === name) && (methodArgs === args)) { 8 | return abi[i]; 9 | } 10 | } 11 | } 12 | 13 | export default function sendTransaction (target, name, argsTypes, argsValues, opts) { 14 | const abiMethod = findMethod(target.abi, name, argsTypes); 15 | const encodedData = ethjsABI.encodeMethod(abiMethod, argsValues); 16 | return target.sendTransaction(Object.assign({ data: encodedData }, opts)); 17 | } 18 | -------------------------------------------------------------------------------- /test/helpers/sign.js: -------------------------------------------------------------------------------- 1 | import utils from 'ethereumjs-util'; 2 | 3 | /** 4 | * Hash and add same prefix to the hash that ganache use. 5 | * @param {string} message the plaintext/ascii/original message 6 | * @return {string} the hash of the message, prefixed, and then hashed again 7 | */ 8 | export const hashMessage = (message) => { 9 | const messageHex = Buffer.from(utils.sha3(message).toString('hex'), 'hex'); 10 | const prefix = utils.toBuffer('\u0019Ethereum Signed Message:\n' + messageHex.length.toString()); 11 | return utils.bufferToHex(utils.sha3(Buffer.concat([prefix, messageHex]))); 12 | }; 13 | 14 | // signs message using web3 (auto-applies prefix) 15 | export const signMessage = (signer, message = '', options = {}) => { 16 | return web3.eth.sign(signer, web3.sha3(message, options)); 17 | }; 18 | 19 | // signs hex string using web3 (auto-applies prefix) 20 | export const signHex = (signer, message = '') => { 21 | return signMessage(signer, message, { encoding: 'hex' }); 22 | }; 23 | -------------------------------------------------------------------------------- /test/helpers/toPromise.js: -------------------------------------------------------------------------------- 1 | export default func => 2 | (...args) => 3 | new Promise((resolve, reject) => 4 | func(...args, (error, data) => error ? reject(error) : resolve(data))); 5 | -------------------------------------------------------------------------------- /test/helpers/transactionMined.js: -------------------------------------------------------------------------------- 1 | 2 | // from https://gist.github.com/xavierlepretre/88682e871f4ad07be4534ae560692ee6 3 | module.export = web3.eth.transactionMined = function (txnHash, interval) { 4 | var transactionReceiptAsync; 5 | interval = interval || 500; 6 | transactionReceiptAsync = function (txnHash, resolve, reject) { 7 | try { 8 | var receipt = web3.eth.getTransactionReceipt(txnHash); 9 | if (receipt === null) { 10 | setTimeout(function () { 11 | transactionReceiptAsync(txnHash, resolve, reject); 12 | }, interval); 13 | } else { 14 | resolve(receipt); 15 | } 16 | } catch (e) { 17 | reject(e); 18 | } 19 | }; 20 | 21 | if (Array.isArray(txnHash)) { 22 | var promises = []; 23 | txnHash.forEach(function (oneTxHash) { 24 | promises.push( 25 | web3.eth.getTransactionReceiptMined(oneTxHash, interval)); 26 | }); 27 | return Promise.all(promises); 28 | } else { 29 | return new Promise(function (resolve, reject) { 30 | transactionReceiptAsync(txnHash, resolve, reject); 31 | }); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /test/library/Math.test.js: -------------------------------------------------------------------------------- 1 | var MathMock = artifacts.require('MathMock'); 2 | 3 | contract('Math', function (accounts) { 4 | let math; 5 | 6 | before(async function () { 7 | math = await MathMock.new(); 8 | }); 9 | 10 | it('returns max64 correctly', async function () { 11 | let a = 5678; 12 | let b = 1234; 13 | await math.max64(a, b); 14 | let result = await math.result64(); 15 | assert.equal(result, a); 16 | }); 17 | 18 | it('returns min64 correctly', async function () { 19 | let a = 5678; 20 | let b = 1234; 21 | await math.min64(a, b); 22 | let result = await math.result64(); 23 | 24 | assert.equal(result, b); 25 | }); 26 | 27 | it('returns max256 correctly', async function () { 28 | let a = 5678; 29 | let b = 1234; 30 | await math.max256(a, b); 31 | let result = await math.result256(); 32 | assert.equal(result, a); 33 | }); 34 | 35 | it('returns min256 correctly', async function () { 36 | let a = 5678; 37 | let b = 1234; 38 | await math.min256(a, b); 39 | let result = await math.result256(); 40 | 41 | assert.equal(result, b); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /test/library/MerkleProof.test.js: -------------------------------------------------------------------------------- 1 | 2 | import MerkleTree from '../helpers/merkleTree.js'; 3 | import { sha3, bufferToHex } from 'ethereumjs-util'; 4 | 5 | var MerkleProofWrapper = artifacts.require('MerkleProofWrapper'); 6 | 7 | contract('MerkleProof', function (accounts) { 8 | let merkleProof; 9 | 10 | before(async function () { 11 | merkleProof = await MerkleProofWrapper.new(); 12 | }); 13 | 14 | describe('verifyProof', function () { 15 | it('should return true for a valid Merkle proof', async function () { 16 | const elements = ['a', 'b', 'c', 'd']; 17 | const merkleTree = new MerkleTree(elements); 18 | 19 | const root = merkleTree.getHexRoot(); 20 | 21 | const proof = merkleTree.getHexProof(elements[0]); 22 | 23 | const leaf = bufferToHex(sha3(elements[0])); 24 | 25 | const result = await merkleProof.verifyProof(proof, root, leaf); 26 | assert.isOk(result, 'verifyProof did not return true for a valid proof'); 27 | }); 28 | 29 | it('should return false for an invalid Merkle proof', async function () { 30 | const correctElements = ['a', 'b', 'c']; 31 | const correctMerkleTree = new MerkleTree(correctElements); 32 | 33 | const correctRoot = correctMerkleTree.getHexRoot(); 34 | 35 | const correctLeaf = bufferToHex(sha3(correctElements[0])); 36 | 37 | const badElements = ['d', 'e', 'f']; 38 | const badMerkleTree = new MerkleTree(badElements); 39 | 40 | const badProof = badMerkleTree.getHexProof(badElements[0]); 41 | 42 | const result = await merkleProof.verifyProof(badProof, correctRoot, correctLeaf); 43 | assert.isNotOk(result, 'verifyProof did not return false for an invalid proof'); 44 | }); 45 | 46 | it('should return false for a Merkle proof of invalid length', async function () { 47 | const elements = ['a', 'b', 'c']; 48 | const merkleTree = new MerkleTree(elements); 49 | 50 | const root = merkleTree.getHexRoot(); 51 | 52 | const proof = merkleTree.getHexProof(elements[0]); 53 | const badProof = proof.slice(0, proof.length - 5); 54 | 55 | const leaf = bufferToHex(sha3(elements[0])); 56 | 57 | const result = await merkleProof.verifyProof(badProof, root, leaf); 58 | assert.isNotOk(result, 'verifyProof did not return false for proof of invalid length'); 59 | }); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /test/lifecycle/Destructible.test.js: -------------------------------------------------------------------------------- 1 | 2 | var Destructible = artifacts.require('Destructible'); 3 | require('../helpers/transactionMined.js'); 4 | 5 | contract('Destructible', function (accounts) { 6 | it('should send balance to owner after destruction', async function () { 7 | let destructible = await Destructible.new({ from: accounts[0], value: web3.toWei('10', 'ether') }); 8 | let owner = await destructible.owner(); 9 | let initBalance = web3.eth.getBalance(owner); 10 | await destructible.destroy({ from: owner }); 11 | let newBalance = web3.eth.getBalance(owner); 12 | assert.isTrue(newBalance > initBalance); 13 | }); 14 | 15 | it('should send balance to recepient after destruction', async function () { 16 | let destructible = await Destructible.new({ from: accounts[0], value: web3.toWei('10', 'ether') }); 17 | let owner = await destructible.owner(); 18 | let initBalance = web3.eth.getBalance(accounts[1]); 19 | await destructible.destroyAndSend(accounts[1], { from: owner }); 20 | let newBalance = web3.eth.getBalance(accounts[1]); 21 | assert.isTrue(newBalance.greaterThan(initBalance)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/lifecycle/Pausable.test.js: -------------------------------------------------------------------------------- 1 | 2 | import assertRevert from '../helpers/assertRevert'; 3 | const PausableMock = artifacts.require('PausableMock'); 4 | 5 | contract('Pausable', function (accounts) { 6 | it('can perform normal process in non-pause', async function () { 7 | let Pausable = await PausableMock.new(); 8 | let count0 = await Pausable.count(); 9 | assert.equal(count0, 0); 10 | 11 | await Pausable.normalProcess(); 12 | let count1 = await Pausable.count(); 13 | assert.equal(count1, 1); 14 | }); 15 | 16 | it('can not perform normal process in pause', async function () { 17 | let Pausable = await PausableMock.new(); 18 | await Pausable.pause(); 19 | let count0 = await Pausable.count(); 20 | assert.equal(count0, 0); 21 | 22 | await assertRevert(Pausable.normalProcess()); 23 | let count1 = await Pausable.count(); 24 | assert.equal(count1, 0); 25 | }); 26 | 27 | it('can not take drastic measure in non-pause', async function () { 28 | let Pausable = await PausableMock.new(); 29 | await assertRevert(Pausable.drasticMeasure()); 30 | const drasticMeasureTaken = await Pausable.drasticMeasureTaken(); 31 | assert.isFalse(drasticMeasureTaken); 32 | }); 33 | 34 | it('can take a drastic measure in a pause', async function () { 35 | let Pausable = await PausableMock.new(); 36 | await Pausable.pause(); 37 | await Pausable.drasticMeasure(); 38 | let drasticMeasureTaken = await Pausable.drasticMeasureTaken(); 39 | 40 | assert.isTrue(drasticMeasureTaken); 41 | }); 42 | 43 | it('should resume allowing normal process after pause is over', async function () { 44 | let Pausable = await PausableMock.new(); 45 | await Pausable.pause(); 46 | await Pausable.unpause(); 47 | await Pausable.normalProcess(); 48 | let count0 = await Pausable.count(); 49 | 50 | assert.equal(count0, 1); 51 | }); 52 | 53 | it('should prevent drastic measure after pause is over', async function () { 54 | let Pausable = await PausableMock.new(); 55 | await Pausable.pause(); 56 | await Pausable.unpause(); 57 | 58 | await assertRevert(Pausable.drasticMeasure()); 59 | 60 | const drasticMeasureTaken = await Pausable.drasticMeasureTaken(); 61 | assert.isFalse(drasticMeasureTaken); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/lifecycle/TokenDestructible.test.js: -------------------------------------------------------------------------------- 1 | 2 | var TokenDestructible = artifacts.require('TokenDestructible'); 3 | var StandardTokenMock = artifacts.require('StandardTokenMock'); 4 | require('../helpers/transactionMined.js'); 5 | 6 | contract('TokenDestructible', function (accounts) { 7 | let destructible; 8 | 9 | beforeEach(async function () { 10 | destructible = await TokenDestructible.new({ 11 | from: accounts[0], 12 | value: web3.toWei('10', 'ether'), 13 | }); 14 | }); 15 | 16 | it('should send balance to owner after destruction', async function () { 17 | let owner = await destructible.owner(); 18 | let initBalance = web3.eth.getBalance(owner); 19 | await destructible.destroy([], { from: owner }); 20 | let newBalance = web3.eth.getBalance(owner); 21 | assert.isTrue(newBalance > initBalance); 22 | }); 23 | 24 | it('should send tokens to owner after destruction', async function () { 25 | let owner = await destructible.owner(); 26 | let token = await StandardTokenMock.new(destructible.address, 100); 27 | let initContractBalance = await token.balanceOf(destructible.address); 28 | let initOwnerBalance = await token.balanceOf(owner); 29 | assert.equal(initContractBalance, 100); 30 | assert.equal(initOwnerBalance, 0); 31 | await destructible.destroy([token.address], { from: owner }); 32 | let newContractBalance = await token.balanceOf(destructible.address); 33 | let newOwnerBalance = await token.balanceOf(owner); 34 | assert.equal(newContractBalance, 0); 35 | assert.equal(newOwnerBalance, 100); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/math/SafeMath.test.js: -------------------------------------------------------------------------------- 1 | import assertJump from '../helpers/assertJump'; 2 | const BigNumber = web3.BigNumber; 3 | const SafeMathMock = artifacts.require('SafeMathMock'); 4 | 5 | require('chai') 6 | .use(require('chai-bignumber')(BigNumber)) 7 | .should(); 8 | 9 | contract('SafeMath', () => { 10 | const MAX_UINT = new BigNumber('115792089237316195423570985008687907853269984665640564039457584007913129639935'); 11 | 12 | before(async function () { 13 | this.safeMath = await SafeMathMock.new(); 14 | }); 15 | 16 | describe('add', function () { 17 | it('adds correctly', async function () { 18 | const a = new BigNumber(5678); 19 | const b = new BigNumber(1234); 20 | 21 | const result = await this.safeMath.add(a, b); 22 | result.should.be.bignumber.equal(a.plus(b)); 23 | }); 24 | 25 | it('throws an error on addition overflow', async function () { 26 | const a = MAX_UINT; 27 | const b = new BigNumber(1); 28 | 29 | await assertJump(this.safeMath.add(a, b)); 30 | }); 31 | }); 32 | 33 | describe('sub', function () { 34 | it('subtracts correctly', async function () { 35 | const a = new BigNumber(5678); 36 | const b = new BigNumber(1234); 37 | 38 | const result = await this.safeMath.sub(a, b); 39 | result.should.be.bignumber.equal(a.minus(b)); 40 | }); 41 | 42 | it('throws an error if subtraction result would be negative', async function () { 43 | const a = new BigNumber(1234); 44 | const b = new BigNumber(5678); 45 | 46 | await assertJump(this.safeMath.sub(a, b)); 47 | }); 48 | }); 49 | 50 | describe('mul', function () { 51 | it('multiplies correctly', async function () { 52 | const a = new BigNumber(1234); 53 | const b = new BigNumber(5678); 54 | 55 | const result = await this.safeMath.mul(a, b); 56 | result.should.be.bignumber.equal(a.times(b)); 57 | }); 58 | 59 | it('handles a zero product correctly', async function () { 60 | const a = new BigNumber(0); 61 | const b = new BigNumber(5678); 62 | 63 | const result = await this.safeMath.mul(a, b); 64 | result.should.be.bignumber.equal(a.times(b)); 65 | }); 66 | 67 | it('throws an error on multiplication overflow', async function () { 68 | const a = MAX_UINT; 69 | const b = new BigNumber(2); 70 | 71 | await assertJump(this.safeMath.mul(a, b)); 72 | }); 73 | }); 74 | 75 | describe('div', function () { 76 | it('divides correctly', async function () { 77 | const a = new BigNumber(5678); 78 | const b = new BigNumber(5678); 79 | 80 | const result = await this.safeMath.div(a, b); 81 | result.should.be.bignumber.equal(a.div(b)); 82 | }); 83 | 84 | it('throws an error on zero division', async function () { 85 | const a = new BigNumber(5678); 86 | const b = new BigNumber(0); 87 | 88 | await assertJump(this.safeMath.div(a, b)); 89 | }); 90 | }); 91 | }); 92 | -------------------------------------------------------------------------------- /test/ownership/CanReclaimToken.test.js: -------------------------------------------------------------------------------- 1 | 2 | import expectThrow from '../helpers/expectThrow'; 3 | 4 | const CanReclaimToken = artifacts.require('CanReclaimToken'); 5 | const BasicTokenMock = artifacts.require('BasicTokenMock'); 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/ownership/Claimable.test.js: -------------------------------------------------------------------------------- 1 | 2 | import assertRevert from '../helpers/assertRevert'; 3 | 4 | var Claimable = artifacts.require('Claimable'); 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 | await assertRevert(claimable.claimOwnership({ from: accounts[2] })); 28 | }); 29 | 30 | it('should prevent non-owners from transfering', async function () { 31 | const other = accounts[2]; 32 | const owner = await claimable.owner.call(); 33 | 34 | assert.isTrue(owner !== other); 35 | await assertRevert(claimable.transferOwnership(other, { from: other })); 36 | }); 37 | 38 | describe('after initiating a transfer', function () { 39 | let newOwner; 40 | 41 | beforeEach(async function () { 42 | newOwner = accounts[1]; 43 | await claimable.transferOwnership(newOwner); 44 | }); 45 | 46 | it('changes allow pending owner to claim ownership', async function () { 47 | await claimable.claimOwnership({ from: newOwner }); 48 | let owner = await claimable.owner(); 49 | 50 | assert.isTrue(owner === newOwner); 51 | }); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /test/ownership/Contactable.test.js: -------------------------------------------------------------------------------- 1 | 2 | var Contactable = artifacts.require('Contactable'); 3 | 4 | contract('Contactable', function (accounts) { 5 | let contactable; 6 | 7 | beforeEach(async function () { 8 | contactable = await Contactable.new(); 9 | }); 10 | 11 | it('should have an empty contact info', async function () { 12 | let info = await contactable.contactInformation(); 13 | assert.isTrue(info === ''); 14 | }); 15 | 16 | describe('after setting the contact information', function () { 17 | let contactInfo = 'contact information'; 18 | 19 | beforeEach(async function () { 20 | await contactable.setContactInformation(contactInfo); 21 | }); 22 | 23 | it('should return the setted contact information', async function () { 24 | let info = await contactable.contactInformation(); 25 | assert.isTrue(info === contactInfo); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/ownership/DelayedClaimable.test.js: -------------------------------------------------------------------------------- 1 | import assertRevert from '../helpers/assertRevert'; 2 | 3 | var DelayedClaimable = artifacts.require('DelayedClaimable'); 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 | await assertRevert(delayedClaimable.claimOwnership({ from: accounts[1] })); 47 | let owner = await delayedClaimable.owner(); 48 | assert.isTrue(owner !== accounts[1]); 49 | }); 50 | 51 | it('set end and start invalid values fail', async function () { 52 | await delayedClaimable.transferOwnership(accounts[1]); 53 | await assertRevert(delayedClaimable.setLimits(1001, 1000)); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /test/ownership/HasNoContracts.test.js: -------------------------------------------------------------------------------- 1 | 2 | import expectThrow from '../helpers/expectThrow'; 3 | 4 | const Ownable = artifacts.require('Ownable'); 5 | const HasNoContracts = artifacts.require('HasNoContracts'); 6 | 7 | contract('HasNoContracts', function (accounts) { 8 | let hasNoContracts = null; 9 | let ownable = null; 10 | 11 | beforeEach(async () => { 12 | // Create contract and token 13 | hasNoContracts = await HasNoContracts.new(); 14 | ownable = await Ownable.new(); 15 | 16 | // Force ownership into contract 17 | await ownable.transferOwnership(hasNoContracts.address); 18 | const owner = await ownable.owner(); 19 | assert.equal(owner, hasNoContracts.address); 20 | }); 21 | 22 | it('should allow owner to reclaim contracts', async function () { 23 | await hasNoContracts.reclaimContract(ownable.address); 24 | const owner = await ownable.owner(); 25 | assert.equal(owner, accounts[0]); 26 | }); 27 | 28 | it('should allow only owner to reclaim contracts', async function () { 29 | await expectThrow( 30 | hasNoContracts.reclaimContract(ownable.address, { from: accounts[1] }), 31 | ); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/ownership/HasNoEther.test.js: -------------------------------------------------------------------------------- 1 | 2 | import expectThrow from '../helpers/expectThrow'; 3 | import toPromise from '../helpers/toPromise'; 4 | const HasNoEtherTest = artifacts.require('HasNoEtherTest'); 5 | const ForceEther = artifacts.require('ForceEther'); 6 | 7 | contract('HasNoEther', function (accounts) { 8 | const amount = web3.toWei('1', 'ether'); 9 | 10 | it('should be constructorable', async function () { 11 | await HasNoEtherTest.new(); 12 | }); 13 | 14 | it('should not accept ether in constructor', async function () { 15 | await expectThrow(HasNoEtherTest.new({ value: amount })); 16 | }); 17 | 18 | it('should not accept ether', async function () { 19 | let hasNoEther = await HasNoEtherTest.new(); 20 | 21 | await expectThrow( 22 | toPromise(web3.eth.sendTransaction)({ 23 | from: accounts[1], 24 | to: hasNoEther.address, 25 | value: amount, 26 | }), 27 | ); 28 | }); 29 | 30 | it('should allow owner to reclaim ether', async function () { 31 | // Create contract 32 | let hasNoEther = await HasNoEtherTest.new(); 33 | const startBalance = await web3.eth.getBalance(hasNoEther.address); 34 | assert.equal(startBalance, 0); 35 | 36 | // Force ether into it 37 | let forceEther = await ForceEther.new({ value: amount }); 38 | await forceEther.destroyAndSend(hasNoEther.address); 39 | const forcedBalance = await web3.eth.getBalance(hasNoEther.address); 40 | assert.equal(forcedBalance, amount); 41 | 42 | // Reclaim 43 | const ownerStartBalance = await web3.eth.getBalance(accounts[0]); 44 | await hasNoEther.reclaimEther(); 45 | const ownerFinalBalance = await web3.eth.getBalance(accounts[0]); 46 | const finalBalance = await web3.eth.getBalance(hasNoEther.address); 47 | assert.equal(finalBalance, 0); 48 | assert.isAbove(ownerFinalBalance, ownerStartBalance); 49 | }); 50 | 51 | it('should allow only owner to reclaim ether', async function () { 52 | // Create contract 53 | let hasNoEther = await HasNoEtherTest.new({ from: accounts[0] }); 54 | 55 | // Force ether into it 56 | let forceEther = await ForceEther.new({ value: amount }); 57 | await forceEther.destroyAndSend(hasNoEther.address); 58 | const forcedBalance = await web3.eth.getBalance(hasNoEther.address); 59 | assert.equal(forcedBalance, amount); 60 | 61 | // Reclaim 62 | await expectThrow(hasNoEther.reclaimEther({ from: accounts[1] })); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /test/ownership/HasNoTokens.test.js: -------------------------------------------------------------------------------- 1 | 2 | import expectThrow from '../helpers/expectThrow'; 3 | 4 | const HasNoTokens = artifacts.require('HasNoTokens'); 5 | const ERC223TokenMock = artifacts.require('ERC223TokenMock'); 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 ERC223TokenMock.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 ERC223 tokens', async function () { 23 | await expectThrow(token.transferERC223(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/ownership/Ownable.behaviour.js: -------------------------------------------------------------------------------- 1 | import EVMRevert from '../helpers/EVMRevert'; 2 | 3 | const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; 4 | 5 | require('chai') 6 | .use(require('chai-as-promised')) 7 | .should(); 8 | 9 | export default function (accounts) { 10 | describe('as an ownable', function () { 11 | it('should have an owner', async function () { 12 | let owner = await this.ownable.owner(); 13 | owner.should.not.eq(ZERO_ADDRESS); 14 | }); 15 | 16 | it('changes owner after transfer', async function () { 17 | let other = accounts[1]; 18 | await this.ownable.transferOwnership(other); 19 | let owner = await this.ownable.owner(); 20 | 21 | owner.should.eq(other); 22 | }); 23 | 24 | it('should prevent non-owners from transfering', async function () { 25 | const other = accounts[2]; 26 | const owner = await this.ownable.owner.call(); 27 | owner.should.not.eq(other); 28 | await this.ownable.transferOwnership(other, { from: other }).should.be.rejectedWith(EVMRevert); 29 | }); 30 | 31 | it('should guard ownership against stuck state', async function () { 32 | let originalOwner = await this.ownable.owner(); 33 | await this.ownable.transferOwnership(null, { from: originalOwner }).should.be.rejectedWith(EVMRevert); 34 | }); 35 | 36 | it('loses owner after renouncement', async function () { 37 | await this.ownable.renounceOwnership(); 38 | let owner = await this.ownable.owner(); 39 | 40 | owner.should.eq(ZERO_ADDRESS); 41 | }); 42 | 43 | it('should prevent non-owners from renouncement', async function () { 44 | const other = accounts[2]; 45 | const owner = await this.ownable.owner.call(); 46 | owner.should.not.eq(other); 47 | await this.ownable.renounceOwnership({ from: other }).should.be.rejectedWith(EVMRevert); 48 | }); 49 | }); 50 | }; 51 | -------------------------------------------------------------------------------- /test/ownership/Ownable.test.js: -------------------------------------------------------------------------------- 1 | import shouldBehaveLikeOwnable from './Ownable.behaviour'; 2 | 3 | const Ownable = artifacts.require('Ownable'); 4 | 5 | contract('Ownable', function (accounts) { 6 | beforeEach(async function () { 7 | this.ownable = await Ownable.new(); 8 | }); 9 | 10 | shouldBehaveLikeOwnable(accounts); 11 | }); 12 | -------------------------------------------------------------------------------- /test/payment/PullPayment.test.js: -------------------------------------------------------------------------------- 1 | var PullPaymentMock = artifacts.require('PullPaymentMock'); 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 | 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 | await ppce.callSend(accounts[0], 200); 27 | 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 | await ppce.callSend(accounts[0], 200); 37 | 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 | 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 | 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 | -------------------------------------------------------------------------------- /test/payment/SplitPayment.test.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 | const EVMThrow = require('../helpers/EVMThrow.js'); 9 | const SplitPayment = artifacts.require('SplitPayment'); 10 | 11 | contract('SplitPayment', function ([owner, payee1, payee2, payee3, nonpayee1, payer1]) { 12 | const amount = web3.toWei(1.0, 'ether'); 13 | 14 | beforeEach(async function () { 15 | this.payees = [payee1, payee2, payee3]; 16 | this.shares = [20, 10, 70]; 17 | 18 | this.contract = await SplitPayment.new(this.payees, this.shares); 19 | }); 20 | 21 | it('should accept payments', async function () { 22 | await web3.eth.sendTransaction({ from: owner, to: this.contract.address, value: amount }); 23 | 24 | const balance = web3.eth.getBalance(this.contract.address); 25 | balance.should.be.bignumber.equal(amount); 26 | }); 27 | 28 | it('should store shares if address is payee', async function () { 29 | const shares = await this.contract.shares.call(payee1); 30 | shares.should.be.bignumber.not.equal(0); 31 | }); 32 | 33 | it('should not store shares if address is not payee', async function () { 34 | const shares = await this.contract.shares.call(nonpayee1); 35 | shares.should.be.bignumber.equal(0); 36 | }); 37 | 38 | it('should throw if no funds to claim', async function () { 39 | await this.contract.claim({ from: payee1 }).should.be.rejectedWith(EVMThrow); 40 | }); 41 | 42 | it('should throw if non-payee want to claim', async function () { 43 | await web3.eth.sendTransaction({ from: payer1, to: this.contract.address, value: amount }); 44 | await this.contract.claim({ from: nonpayee1 }).should.be.rejectedWith(EVMThrow); 45 | }); 46 | 47 | it('should distribute funds to payees', async function () { 48 | await web3.eth.sendTransaction({ from: payer1, to: this.contract.address, value: amount }); 49 | 50 | // receive funds 51 | const initBalance = web3.eth.getBalance(this.contract.address); 52 | initBalance.should.be.bignumber.equal(amount); 53 | 54 | // distribute to payees 55 | const initAmount1 = web3.eth.getBalance(payee1); 56 | await this.contract.claim({ from: payee1 }); 57 | const profit1 = web3.eth.getBalance(payee1) - initAmount1; 58 | assert(Math.abs(profit1 - web3.toWei(0.20, 'ether')) < 1e16); 59 | 60 | const initAmount2 = web3.eth.getBalance(payee2); 61 | await this.contract.claim({ from: payee2 }); 62 | const profit2 = web3.eth.getBalance(payee2) - initAmount2; 63 | assert(Math.abs(profit2 - web3.toWei(0.10, 'ether')) < 1e16); 64 | 65 | const initAmount3 = web3.eth.getBalance(payee3); 66 | await this.contract.claim({ from: payee3 }); 67 | const profit3 = web3.eth.getBalance(payee3) - initAmount3; 68 | assert(Math.abs(profit3 - web3.toWei(0.70, 'ether')) < 1e16); 69 | 70 | // end balance should be zero 71 | const endBalance = web3.eth.getBalance(this.contract.address); 72 | endBalance.should.be.bignumber.equal(0); 73 | 74 | // check correct funds released accounting 75 | const totalReleased = await this.contract.totalReleased.call(); 76 | totalReleased.should.be.bignumber.equal(initBalance); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /test/token/ERC20/BasicToken.test.js: -------------------------------------------------------------------------------- 1 | import assertRevert from '../../helpers/assertRevert'; 2 | const BasicToken = artifacts.require('BasicTokenMock'); 3 | 4 | contract('StandardToken', function ([_, owner, recipient, anotherAccount]) { 5 | const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; 6 | 7 | beforeEach(async function () { 8 | this.token = await BasicToken.new(owner, 100); 9 | }); 10 | 11 | describe('total supply', function () { 12 | it('returns the total amount of tokens', async function () { 13 | const totalSupply = await this.token.totalSupply(); 14 | 15 | assert.equal(totalSupply, 100); 16 | }); 17 | }); 18 | 19 | describe('balanceOf', function () { 20 | describe('when the requested account has no tokens', function () { 21 | it('returns zero', async function () { 22 | const balance = await this.token.balanceOf(anotherAccount); 23 | 24 | assert.equal(balance, 0); 25 | }); 26 | }); 27 | 28 | describe('when the requested account has some tokens', function () { 29 | it('returns the total amount of tokens', async function () { 30 | const balance = await this.token.balanceOf(owner); 31 | 32 | assert.equal(balance, 100); 33 | }); 34 | }); 35 | }); 36 | 37 | describe('transfer', function () { 38 | describe('when the recipient is not the zero address', function () { 39 | const to = recipient; 40 | 41 | describe('when the sender does not have enough balance', function () { 42 | const amount = 101; 43 | 44 | it('reverts', async function () { 45 | await assertRevert(this.token.transfer(to, amount, { from: owner })); 46 | }); 47 | }); 48 | 49 | describe('when the sender has enough balance', function () { 50 | const amount = 100; 51 | 52 | it('transfers the requested amount', async function () { 53 | await this.token.transfer(to, amount, { from: owner }); 54 | 55 | const senderBalance = await this.token.balanceOf(owner); 56 | assert.equal(senderBalance, 0); 57 | 58 | const recipientBalance = await this.token.balanceOf(to); 59 | assert.equal(recipientBalance, amount); 60 | }); 61 | 62 | it('emits a transfer event', async function () { 63 | const { logs } = await this.token.transfer(to, amount, { from: owner }); 64 | 65 | assert.equal(logs.length, 1); 66 | assert.equal(logs[0].event, 'Transfer'); 67 | assert.equal(logs[0].args.from, owner); 68 | assert.equal(logs[0].args.to, to); 69 | assert(logs[0].args.value.eq(amount)); 70 | }); 71 | }); 72 | }); 73 | 74 | describe('when the recipient is the zero address', function () { 75 | const to = ZERO_ADDRESS; 76 | 77 | it('reverts', async function () { 78 | await assertRevert(this.token.transfer(to, 100, { from: owner })); 79 | }); 80 | }); 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /test/token/ERC20/BurnableToken.behaviour.js: -------------------------------------------------------------------------------- 1 | import assertRevert from '../../helpers/assertRevert'; 2 | import { inLogs } from '../../helpers/expectEvent'; 3 | 4 | const BigNumber = web3.BigNumber; 5 | const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should(); 11 | 12 | export default function ([owner], initialBalance) { 13 | describe('as a basic burnable token', function () { 14 | const from = owner; 15 | 16 | describe('when the given amount is not greater than balance of the sender', function () { 17 | const amount = 100; 18 | 19 | beforeEach(async function () { 20 | ({ logs: this.logs } = await this.token.burn(amount, { from })); 21 | }); 22 | 23 | it('burns the requested amount', async function () { 24 | const balance = await this.token.balanceOf(from); 25 | balance.should.be.bignumber.equal(initialBalance - amount); 26 | }); 27 | 28 | it('emits a burn event', async function () { 29 | const event = await inLogs(this.logs, 'Burn'); 30 | event.args.burner.should.eq(owner); 31 | event.args.value.should.be.bignumber.equal(amount); 32 | }); 33 | 34 | it('emits a transfer event', async function () { 35 | const event = await inLogs(this.logs, 'Transfer'); 36 | event.args.from.should.eq(owner); 37 | event.args.to.should.eq(ZERO_ADDRESS); 38 | event.args.value.should.be.bignumber.equal(amount); 39 | }); 40 | }); 41 | 42 | describe('when the given amount is greater than the balance of the sender', function () { 43 | const amount = initialBalance + 1; 44 | 45 | it('reverts', async function () { 46 | await assertRevert(this.token.burn(amount, { from })); 47 | }); 48 | }); 49 | }); 50 | }; 51 | -------------------------------------------------------------------------------- /test/token/ERC20/BurnableToken.test.js: -------------------------------------------------------------------------------- 1 | import shouldBehaveLikeBurnableToken from './BurnableToken.behaviour'; 2 | const BurnableTokenMock = artifacts.require('BurnableTokenMock'); 3 | 4 | contract('BurnableToken', function ([owner]) { 5 | const initialBalance = 1000; 6 | 7 | beforeEach(async function () { 8 | this.token = await BurnableTokenMock.new(owner, initialBalance); 9 | }); 10 | 11 | shouldBehaveLikeBurnableToken([owner], initialBalance); 12 | }); 13 | -------------------------------------------------------------------------------- /test/token/ERC20/CappedToken.test.js: -------------------------------------------------------------------------------- 1 | 2 | import expectThrow from '../../helpers/expectThrow'; 3 | import ether from '../../helpers/ether'; 4 | 5 | var CappedToken = artifacts.require('CappedToken'); 6 | 7 | contract('Capped', function (accounts) { 8 | const cap = ether(1000); 9 | 10 | let token; 11 | 12 | beforeEach(async function () { 13 | token = await CappedToken.new(cap); 14 | }); 15 | 16 | it('should start with the correct cap', async function () { 17 | let _cap = await token.cap(); 18 | 19 | assert(cap.eq(_cap)); 20 | }); 21 | 22 | it('should mint when amount is less than cap', async function () { 23 | const result = await token.mint(accounts[0], 100); 24 | assert.equal(result.logs[0].event, 'Mint'); 25 | }); 26 | 27 | it('should fail to mint if the ammount exceeds the cap', async function () { 28 | await token.mint(accounts[0], cap.sub(1)); 29 | await expectThrow(token.mint(accounts[0], 100)); 30 | }); 31 | 32 | it('should fail to mint after cap is reached', async function () { 33 | await token.mint(accounts[0], cap); 34 | await expectThrow(token.mint(accounts[0], 1)); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /test/token/ERC20/DetailedERC20.test.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 | const DetailedERC20Mock = artifacts.require('DetailedERC20Mock'); 9 | 10 | contract('DetailedERC20', accounts => { 11 | let detailedERC20 = null; 12 | 13 | const _name = 'My Detailed ERC20'; 14 | const _symbol = 'MDT'; 15 | const _decimals = 18; 16 | 17 | beforeEach(async function () { 18 | detailedERC20 = await DetailedERC20Mock.new(_name, _symbol, _decimals); 19 | }); 20 | 21 | it('has a name', async function () { 22 | const name = await detailedERC20.name(); 23 | name.should.be.equal(_name); 24 | }); 25 | 26 | it('has a symbol', async function () { 27 | const symbol = await detailedERC20.symbol(); 28 | symbol.should.be.equal(_symbol); 29 | }); 30 | 31 | it('has an amount of decimals', async function () { 32 | const decimals = await detailedERC20.decimals(); 33 | decimals.should.be.bignumber.equal(_decimals); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/token/ERC20/MintableToken.test.js: -------------------------------------------------------------------------------- 1 | import shouldBehaveLikeMintableToken from './MintableToken.behaviour'; 2 | const MintableToken = artifacts.require('MintableToken'); 3 | 4 | contract('MintableToken', function ([owner, anotherAccount]) { 5 | const minter = owner; 6 | 7 | beforeEach(async function () { 8 | this.token = await MintableToken.new({ from: owner }); 9 | }); 10 | 11 | shouldBehaveLikeMintableToken([owner, anotherAccount, minter]); 12 | }); 13 | -------------------------------------------------------------------------------- /test/token/ERC20/RBACMintableToken.test.js: -------------------------------------------------------------------------------- 1 | import expectThrow from '../../helpers/expectThrow'; 2 | import shouldBehaveLikeMintableToken from './MintableToken.behaviour'; 3 | const RBACMintableToken = artifacts.require('RBACMintableToken'); 4 | 5 | const ROLE_MINTER = 'minter'; 6 | 7 | contract('RBACMintableToken', function ([owner, anotherAccount, minter]) { 8 | beforeEach(async function () { 9 | this.token = await RBACMintableToken.new({ from: owner }); 10 | await this.token.addMinter(minter, { from: owner }); 11 | }); 12 | 13 | describe('handle roles', function () { 14 | it('owner can add and remove a minter role', async function () { 15 | await this.token.addMinter(anotherAccount, { from: owner }); 16 | let hasRole = await this.token.hasRole(anotherAccount, ROLE_MINTER); 17 | assert.equal(hasRole, true); 18 | 19 | await this.token.removeMinter(anotherAccount, { from: owner }); 20 | hasRole = await this.token.hasRole(anotherAccount, ROLE_MINTER); 21 | assert.equal(hasRole, false); 22 | }); 23 | 24 | it('another account can\'t add or remove a minter role', async function () { 25 | await expectThrow( 26 | this.token.addMinter(anotherAccount, { from: anotherAccount }) 27 | ); 28 | 29 | await this.token.addMinter(anotherAccount, { from: owner }); 30 | await expectThrow( 31 | this.token.removeMinter(anotherAccount, { from: anotherAccount }) 32 | ); 33 | }); 34 | }); 35 | 36 | shouldBehaveLikeMintableToken([owner, anotherAccount, minter]); 37 | }); 38 | -------------------------------------------------------------------------------- /test/token/ERC20/SafeERC20.test.js: -------------------------------------------------------------------------------- 1 | import EVMRevert from '../../helpers/EVMRevert'; 2 | 3 | require('chai') 4 | .use(require('chai-as-promised')) 5 | .should(); 6 | 7 | const SafeERC20Helper = artifacts.require('SafeERC20Helper'); 8 | 9 | contract('SafeERC20', function () { 10 | beforeEach(async function () { 11 | this.helper = await SafeERC20Helper.new(); 12 | }); 13 | 14 | it('should throw on failed transfer', async function () { 15 | await this.helper.doFailingTransfer().should.be.rejectedWith(EVMRevert); 16 | }); 17 | 18 | it('should throw on failed transferFrom', async function () { 19 | await this.helper.doFailingTransferFrom().should.be.rejectedWith(EVMRevert); 20 | }); 21 | 22 | it('should throw on failed approve', async function () { 23 | await this.helper.doFailingApprove().should.be.rejectedWith(EVMRevert); 24 | }); 25 | 26 | it('should not throw on succeeding transfer', async function () { 27 | await this.helper.doSucceedingTransfer().should.be.fulfilled; 28 | }); 29 | 30 | it('should not throw on succeeding transferFrom', async function () { 31 | await this.helper.doSucceedingTransferFrom().should.be.fulfilled; 32 | }); 33 | 34 | it('should not throw on succeeding approve', async function () { 35 | await this.helper.doSucceedingApprove().should.be.fulfilled; 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/token/ERC20/StandardBurnableToken.test.js: -------------------------------------------------------------------------------- 1 | import assertRevert from '../../helpers/assertRevert'; 2 | import { inLogs } from '../../helpers/expectEvent'; 3 | import shouldBehaveLikeBurnableToken from './BurnableToken.behaviour'; 4 | 5 | const StandardBurnableTokenMock = artifacts.require('StandardBurnableTokenMock'); 6 | const BigNumber = web3.BigNumber; 7 | const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; 8 | 9 | require('chai') 10 | .use(require('chai-as-promised')) 11 | .use(require('chai-bignumber')(BigNumber)) 12 | .should(); 13 | 14 | contract('StandardBurnableToken', function ([owner, burner]) { 15 | const initialBalance = 1000; 16 | 17 | beforeEach(async function () { 18 | this.token = await StandardBurnableTokenMock.new(owner, initialBalance); 19 | }); 20 | 21 | shouldBehaveLikeBurnableToken([owner], initialBalance); 22 | 23 | describe('burnFrom', function () { 24 | describe('on success', function () { 25 | const amount = 100; 26 | 27 | beforeEach(async function () { 28 | await this.token.approve(burner, 300, { from: owner }); 29 | const { logs } = await this.token.burnFrom(owner, amount, { from: burner }); 30 | this.logs = logs; 31 | }); 32 | 33 | it('burns the requested amount', async function () { 34 | const balance = await this.token.balanceOf(owner); 35 | balance.should.be.bignumber.equal(initialBalance - amount); 36 | }); 37 | 38 | it('decrements allowance', async function () { 39 | const allowance = await this.token.allowance(owner, burner); 40 | allowance.should.be.bignumber.equal(200); 41 | }); 42 | 43 | it('emits a burn event', async function () { 44 | const event = await inLogs(this.logs, 'Burn'); 45 | event.args.burner.should.eq(owner); 46 | event.args.value.should.be.bignumber.equal(amount); 47 | }); 48 | 49 | it('emits a transfer event', async function () { 50 | const event = await inLogs(this.logs, 'Transfer'); 51 | event.args.from.should.eq(owner); 52 | event.args.to.should.eq(ZERO_ADDRESS); 53 | event.args.value.should.be.bignumber.equal(amount); 54 | }); 55 | }); 56 | 57 | describe('when the given amount is greater than the balance of the sender', function () { 58 | const amount = initialBalance + 1; 59 | it('reverts', async function () { 60 | await this.token.approve(burner, amount, { from: owner }); 61 | await assertRevert(this.token.burnFrom(owner, amount, { from: burner })); 62 | }); 63 | }); 64 | 65 | describe('when the given amount is greater than the allowance', function () { 66 | const amount = 100; 67 | it('reverts', async function () { 68 | await this.token.approve(burner, amount - 1, { from: owner }); 69 | await assertRevert(this.token.burnFrom(owner, amount, { from: burner })); 70 | }); 71 | }); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /test/token/ERC20/TokenTimelock.test.js: -------------------------------------------------------------------------------- 1 | import latestTime from '../../helpers/latestTime'; 2 | import { increaseTimeTo, duration } from '../../helpers/increaseTime'; 3 | 4 | const BigNumber = web3.BigNumber; 5 | 6 | require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should(); 10 | 11 | const MintableToken = artifacts.require('MintableToken'); 12 | const TokenTimelock = artifacts.require('TokenTimelock'); 13 | 14 | contract('TokenTimelock', function ([_, owner, beneficiary]) { 15 | const amount = new BigNumber(100); 16 | 17 | beforeEach(async function () { 18 | this.token = await MintableToken.new({ from: owner }); 19 | this.releaseTime = latestTime() + duration.years(1); 20 | this.timelock = await TokenTimelock.new(this.token.address, beneficiary, this.releaseTime); 21 | await this.token.mint(this.timelock.address, amount, { from: owner }); 22 | }); 23 | 24 | it('cannot be released before time limit', async function () { 25 | await this.timelock.release().should.be.rejected; 26 | }); 27 | 28 | it('cannot be released just before time limit', async function () { 29 | await increaseTimeTo(this.releaseTime - duration.seconds(3)); 30 | await this.timelock.release().should.be.rejected; 31 | }); 32 | 33 | it('can be released just after limit', async function () { 34 | await increaseTimeTo(this.releaseTime + duration.seconds(1)); 35 | await this.timelock.release().should.be.fulfilled; 36 | const balance = await this.token.balanceOf(beneficiary); 37 | balance.should.be.bignumber.equal(amount); 38 | }); 39 | 40 | it('can be released after time limit', async function () { 41 | await increaseTimeTo(this.releaseTime + duration.years(1)); 42 | await this.timelock.release().should.be.fulfilled; 43 | const balance = await this.token.balanceOf(beneficiary); 44 | balance.should.be.bignumber.equal(amount); 45 | }); 46 | 47 | it('cannot be released twice', async function () { 48 | await increaseTimeTo(this.releaseTime + duration.years(1)); 49 | await this.timelock.release().should.be.fulfilled; 50 | await this.timelock.release().should.be.rejected; 51 | const balance = await this.token.balanceOf(beneficiary); 52 | balance.should.be.bignumber.equal(amount); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /test/token/ERC721/ERC721BasicToken.test.js: -------------------------------------------------------------------------------- 1 | import shouldBehaveLikeERC721BasicToken from './ERC721BasicToken.behaviour'; 2 | import shouldMintAndBurnERC721Token from './ERC721MintBurn.behaviour'; 3 | 4 | const BigNumber = web3.BigNumber; 5 | const ERC721BasicToken = artifacts.require('ERC721BasicTokenMock.sol'); 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should(); 11 | 12 | contract('ERC721BasicToken', function (accounts) { 13 | beforeEach(async function () { 14 | this.token = await ERC721BasicToken.new({ from: accounts[0] }); 15 | }); 16 | 17 | shouldBehaveLikeERC721BasicToken(accounts); 18 | shouldMintAndBurnERC721Token(accounts); 19 | }); 20 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | require('babel-register'); 3 | require('babel-polyfill'); 4 | 5 | const HDWalletProvider = require('truffle-hdwallet-provider'); 6 | 7 | const providerWithMnemonic = (mnemonic, rpcEndpoint) => 8 | new HDWalletProvider(mnemonic, rpcEndpoint); 9 | 10 | const infuraProvider = network => providerWithMnemonic( 11 | process.env.MNEMONIC || '', 12 | `https://${network}.infura.io/${process.env.INFURA_API_KEY}` 13 | ); 14 | 15 | const ropstenProvider = process.env.SOLIDITY_COVERAGE 16 | ? undefined 17 | : infuraProvider('ropsten'); 18 | 19 | module.exports = { 20 | networks: { 21 | development: { 22 | host: 'localhost', 23 | port: 8545, 24 | network_id: '*', // eslint-disable-line camelcase 25 | }, 26 | ropsten: { 27 | provider: ropstenProvider, 28 | network_id: 3, // eslint-disable-line camelcase 29 | }, 30 | coverage: { 31 | host: 'localhost', 32 | network_id: '*', // eslint-disable-line camelcase 33 | port: 8555, 34 | gas: 0xfffffffffff, 35 | gasPrice: 0x01, 36 | }, 37 | ganache: { 38 | host: 'localhost', 39 | port: 8545, 40 | network_id: '*', // eslint-disable-line camelcase 41 | }, 42 | }, 43 | }; 44 | --------------------------------------------------------------------------------