Compare commits

...

327 Commits

Author SHA1 Message Date
b7e7c765e0 v1.4.0 2017-11-23 13:30:54 -03:00
9e1da49f23 sync yarn.lock with package-lock.json 2017-11-23 13:21:05 -03:00
c29dd086d3 Update to testrpc 6.0.1 and test fixes for revert opcode. 2017-11-23 13:06:05 -03:00
b9cbea1c9c Merge pull request #576 from ajsantander/master
Address new compiler warnings
2017-11-23 12:54:44 -03:00
b254b74b87 Merge pull request #577 from redsquirrel/patch-1
Minor formatting change
2017-11-23 12:47:51 -03:00
bb1736e376 Change visibility of fallbacks to external 2017-11-23 12:28:46 -03:00
11349835e9 Minor formatting change 2017-11-23 08:22:59 -06:00
c6e0edb268 Remove solidity warnings in tests 2017-11-23 10:57:36 -03:00
b50391862c Changes to remove warnings 2017-11-23 10:41:18 -03:00
0bcf0a2001 Merge pull request #573 from ajsantander/master
Update to truffle 4.0.0 and solc 0.4.18
2017-11-22 19:26:38 -03:00
0eaa5f50ac Disable solidity-coverage
This is required to update to truffle 4 and solc 0.4.18, see PR #573
2017-11-22 19:08:31 -03:00
ce86029f6a Update solidity version on test helpers 2017-11-22 19:00:13 -03:00
815d9e1f45 Replace constant with view/pure 2017-11-22 18:59:54 -03:00
e6213767fa Update all solidity versions to 0.4.18 2017-11-22 18:52:52 -03:00
f28c245a3c Update to truffle 4.0.0
had to up the gasLimit in test.sh to avoid an out of gas error when deploying the scripts
2017-11-22 18:52:52 -03:00
12303ceaf5 fix treatment of bignumber in CappedToken test 2017-11-22 15:27:52 -03:00
9001ce9d3a Merge pull request #515 from cwhinfrey/master
Create CappedToken, a capped MintableToken
2017-11-22 15:25:12 -03:00
492ef4a419 Merge pull request #571 from quantum13/patch-1
Small code style change
2017-11-22 14:33:01 -03:00
5f67dd7868 Merge pull request #574 from gakonst/master
Fix unused variable warning in `Standard Token.sol`
2017-11-22 14:32:19 -03:00
3c5a268da4 fixes #572 2017-11-22 12:55:11 +00:00
db5a12cfdd Merge pull request #506 from TalAter/fix/deprecated-throw-in-tests
Replace deprecated throw with assert in Solidity tests
2017-11-21 14:41:31 -03:00
03ad0efd29 Small code style change
http://solidity.readthedocs.io/en/develop/style-guide.html#other-recommendations
The visibility modifiers for a function should come before any custom modifiers.
2017-11-20 23:13:32 +03:00
5fc53b6f2f Replaced assert with require 2017-11-19 01:34:24 +02:00
99f3e26f83 Merge pull request #568 from frangio/readme-npm-init
Add npm init in README
2017-11-17 17:50:55 -03:00
151371cc86 add npm init in README 2017-11-17 17:34:36 -03:00
376208bd96 Merge pull request #566 from onbjerg/patch-1
Make coverage badge flat
2017-11-17 16:59:15 -03:00
11b63d4fc1 Revert alt text for coverage badge 2017-11-17 20:49:41 +01:00
39ae5b4cca Make coverage badge flat 2017-11-17 13:16:00 +01:00
670b843b63 Merge pull request #553 from limexp/fix/534-ci-versions-info
added versions output to Travis CI log #534
2017-11-16 15:16:09 -03:00
070d25dc9e Merge pull request #564 from spalladino/fix/travis-no-prs-notifications
Do not notify via Slack about PR build failures
2017-11-16 12:29:38 -03:00
9684ce76c5 Do not notify via Slack on PRs 2017-11-16 10:20:34 -03:00
d919f0dde2 Merge pull request #487 from limexp/fix/docs
fix docs issue #459 and align with README.md
2017-11-15 18:27:10 -03:00
689e18aab5 Merge branch 'master' into fix/docs 2017-11-15 18:19:12 -03:00
8765e2a53f Use instead of directly calling on 2017-11-15 16:14:28 -05:00
7a19bcf6d9 Merge pull request #505 from ZumZoom/patch-1
Finish minting should be called only once
2017-11-15 11:59:05 -03:00
088897150e Merge pull request #526 from amazingandyyy/patch-1
Update RefundVault.sol
2017-11-15 11:56:03 -03:00
34be16d939 Merge pull request #522 from emn178/feature/improve_mul
improve mul performance and reduce gas cost
2017-11-14 17:49:09 -03:00
14ae881e26 Merge pull request #544 from maraoz/timer-improvement
remove timer test helper
2017-11-14 17:24:42 -03:00
666a3a73e0 remove unused 'day' test variable 2017-11-14 12:50:43 -05:00
84bffb854a Merge pull request #477 from facuspagnuolo/feaure/create_detailed_erc20_interface
Create detailed ERC20 interface
2017-11-13 15:42:09 -03:00
365c875ced Create detailed ERC20 interface 2017-11-13 15:36:02 -03:00
7dd0ee6212 remove timer 2017-11-12 15:10:46 -05:00
7123faff9f added versions output to Travis CI log #534 2017-11-11 16:32:38 +03:00
61b5921ab2 Fix typo 2017-11-10 20:20:44 -05:00
e72c7ce91b Merge pull request #417 from abarmat/feature-splitpayment-contract
Feature SplitPayment contract
2017-11-10 18:45:56 -03:00
c4ca7f03e3 improve timer test helper 2017-11-10 13:29:58 -08:00
9be77ddd54 Merge pull request #469 from nedodn/patch-2
Update TokenTimelock.sol: Issue #464
2017-11-10 17:44:20 -03:00
70a17d0b96 Merge pull request #475 from et/patch-2
Add `npm init`
2017-11-10 17:31:58 -03:00
ad2282456e Merge pull request #478 from rudygodoy/patch-2
Fixes typos in documentation
2017-11-10 17:26:00 -03:00
fe3e360483 Merge pull request #482 from sohkai/patch-1
Small typo fixes for bounty docs
2017-11-10 17:24:26 -03:00
5a857fc1a7 Merge pull request #490 from Nedudi/master
Update SimpleToken.sol
2017-11-10 17:15:52 -03:00
c5cd35b2ea Merge pull request #504 from FloorLamp/patch-1
Update ecrecovery.rst
2017-11-10 17:07:16 -03:00
a808b0b03f Merge pull request #523 from thesved/patch-1
Math.sol is not used, not needed
2017-11-10 16:19:01 -03:00
4e8f422a81 Merge pull request #542 from spalladino/feature/travis-notifications
Add Slack notifications
2017-11-10 15:27:03 -03:00
070226d624 Add Slack notifications 2017-11-10 13:18:20 -03:00
2413f83504 Include 'revert' in expectThrow() helper 2017-11-10 11:41:17 -03:00
be692e59eb Update RefundVault.sol 2017-10-31 00:13:27 -07:00
e74652415f Math.sol is not used, not needed
Small thing, but the Math.sol is not really needed, since it is not used.
2017-10-30 11:07:26 +01:00
5ad07e1892 improve mum performance and reduce gas cost 2017-10-30 09:58:52 +08:00
575372f660 Add Capped Token tests 2017-10-25 23:58:36 -04:00
7a26a0ecf1 Add capped token contract 2017-10-25 23:57:21 -04:00
8e01dd14f9 Merge pull request #510 from doraemondrian/master
Use address(0) instead of 0x0
2017-10-24 16:46:05 -03:00
5088c64140 Merge pull request #503 from martriay/fix-missing-safemath
[TokenVesting] Add missing safemath ops
2017-10-23 12:53:25 -03:00
ac4a19dd7d Use address type 2017-10-23 03:11:14 -07:00
09b1926c41 Use address type 2017-10-23 03:10:40 -07:00
d7b67eca52 Use address type 2017-10-23 03:10:00 -07:00
e4427befbb Use address type 2017-10-23 03:08:30 -07:00
ca1babe1f7 Use address type 2017-10-23 03:06:51 -07:00
1d54b86a7c Replace deprecated throw with assert in Solidity tests 2017-10-17 21:02:47 +03:00
2d83c557b1 Finish minting should me called only once
Multiple calls to `finishMinting` will emit multiple `MintFinished` events which may be surprising if one rely on `MintFinished` event.
2017-10-17 16:24:16 +03:00
dfb9ebd647 Update ecrecovery.rst
Fix typo
2017-10-16 17:50:25 -04:00
b60e434e0b [TokenVesting] Add missing safemath ops 2017-10-16 03:48:32 -03:00
39d6c92069 Merge pull request #497 from martriay/token-vesting-fix
[TokenVesting] vestedAmount should return the historical vested amount
2017-10-13 16:46:37 -03:00
eb9f88bafc [TokenVesting] Remove unused variable 2017-10-13 16:20:24 -03:00
aa431dfb20 [TokenVesting] Increase released amount before transfer 2017-10-13 16:13:54 -03:00
fff8e040b7 [TokenVesting] vestedAmount returns the historical vested amount 2017-10-13 15:32:44 -03:00
74636b7333 [TokenVesting] Use SafeMath 2017-10-12 00:34:03 -03:00
647fc13963 Merge pull request #492 from frangio/fix-vesting-revoke
TokenVesting bugfix
2017-10-11 16:58:21 -03:00
d5e0714faf use safeTransfer 2017-10-11 16:31:31 -03:00
a184013d1e explicitly mark functions public 2017-10-09 19:08:32 -03:00
7d08c4da7f make TokenVesting variables public 2017-10-09 19:02:57 -03:00
01b92d1d56 fix a problem when revoke is called twice 2017-10-09 19:01:04 -03:00
790833e5d4 Update SimpleToken.sol 2017-10-08 04:26:21 +03:00
2cb2799a51 align docs developer-resources.rst with README.md 2017-10-07 23:44:43 +03:00
9dcf37dd19 align docs getting-started.rst with README.md 2017-10-07 23:37:37 +03:00
0d89e99ceb Fix contracts path issue 2017-10-07 23:24:23 +03:00
a5a1be7219 Fixing docs issue #459 2017-10-07 23:21:58 +03:00
5aba967db9 Merge pull request #476 from martriay/add-token-vesting
Add token vesting
2017-10-05 18:44:39 -03:00
ffd1090718 [TokenVesting] Remove VestedTokenMock 2017-10-04 18:08:36 -03:00
22b9263674 [TokenVesting] Remove VestedToken and LimitedTranferToken 2017-10-04 14:52:55 -03:00
d21d35ca6f [TokenVesting] Fix test. 2017-10-04 14:52:31 -03:00
4e39f50aec [TokenVesting] Remove unnecessary instatiation on test. 2017-10-04 14:52:31 -03:00
9e0e80e820 [TokenVesting] Allow instantiation of already started vesting contracts. Improve comments' wording. 2017-10-04 14:52:31 -03:00
562fb6945f [TokenVesting] Rename events according to convention 2017-10-04 14:52:31 -03:00
822de45bfc [TokenVesting] Add a start parameter to constructor to defer vesting 2017-10-04 14:52:30 -03:00
bd56163900 [TokenVesting] Fix vestedAmount calculation. Linearity test watches beneficiary balance over vestedAmount 2017-10-04 14:52:30 -03:00
696615d392 [TokenVesting] Add linear release test 2017-10-04 14:52:30 -03:00
645edfc936 [TokenVesting] Fix should-revoke test 2017-10-04 14:52:30 -03:00
a227b212f5 [TokenVesting] Add tests 2017-10-04 14:52:30 -03:00
c11265e694 [TokenVesting] Add events 2017-10-04 14:52:30 -03:00
6344a76f83 add pending tests 2017-10-04 14:52:30 -03:00
3da7c31484 add revocable flag 2017-10-04 14:52:30 -03:00
998c72ab5b add preconditions to constructor 2017-10-04 14:52:30 -03:00
00f323d132 add shortcut for vestedAmount after vesting end 2017-10-04 14:52:30 -03:00
80e591f487 add TokenVesting contract 2017-10-04 14:52:30 -03:00
1333f45cdc Add missing code blocks to bounty docs 2017-10-01 22:34:58 -04:00
2ad88b59f6 Small indenting fix for bounty docs 2017-10-01 22:27:42 -04:00
a9055f5ce2 Fixes typos 2017-09-29 14:55:18 -05:00
9b0e89c4bf Add npm init
If you don't do this, you'll receive this error:

```
❯ zeppelin npm install zeppelin-solidity
npm WARN saveError ENOENT: no such file or directory, open '/Users/et/package.json'
npm WARN enoent ENOENT: no such file or directory, open '/Users/et/package.json'
npm WARN et No description
npm WARN et No repository field.
npm WARN et No README data
npm WARN et No license field.

+ zeppelin-solidity@1.3.0
updated 1 package in 0.677s
```
2017-09-28 17:18:47 -06:00
27f8609ac9 Update TokenTimelock.sol: Issue #464
Removed deprecated function claim() as per Issue #464.
2017-09-27 14:07:08 -05:00
5cf503673f Merge pull request #466 from phiferd/master
Using require for Token preconditions
2017-09-25 11:53:50 -03:00
3837319141 Adding some additional tests 2017-09-23 17:06:14 +08:00
e70dd18734 Moving business logic preconditions to the beginning of the function. 2017-09-23 11:57:29 +08:00
158a7a881d Merge pull request #460 from dmx374/patch-3
Add explicit visibility
2017-09-22 17:32:39 +02:00
725ed40a57 v1.3.0 2017-09-21 14:18:08 -03:00
3733c069c9 Add explicit visibility 2017-09-19 08:29:03 +02:00
1df75a951f Merge pull request #446 from jakub-wojciechowski/master
Make approve method compliant with ERC20
2017-09-18 18:38:37 -03:00
adfd8fb6a9 Warning in approve method documentation. 2017-09-18 18:38:05 -03:00
98f672b534 Make approve method compliant with ERC20 2017-09-18 18:38:05 -03:00
e9068859b6 Merge pull request #448 from SylTi/fix/small-fixes
A bunch of small fixes
2017-09-18 18:18:55 -03:00
1203a2473d add whenNotPaused modifier to all of PausableToken functions that modify it's state. Fix #401 2017-09-18 22:49:22 +02:00
4a1ff913ab replace var by uint256 in StandardToken. Fix #432 2017-09-18 22:46:52 +02:00
83918cad4b change approve() to conform to ERC20. Fix #438 2017-09-18 22:46:52 +02:00
d3c5ce268f Merge pull request #260 from yondonfu/feature/merkleproof
Merkle proof library with tests and docs
2017-09-18 16:47:17 -03:00
f60c5ad88a Merge pull request #445 from frangio/fix-leftover-testrpc
Properly kill background testrpc instance
2017-09-18 15:54:42 -03:00
bcda5bfe9b Merge branch 'master' into feature/merkleproof 2017-09-18 14:01:10 -04:00
33eb8b1da5 Merge pull request #457 from sot528/fix-typo
Just fix typo.
2017-09-18 14:26:21 -03:00
b069827bad fix typo. 2017-09-19 01:57:50 +09:00
74e416f04f Merge pull request #450 from dmx374/master
Explicit public visibility on methods
2017-09-18 12:58:34 -03:00
b395b06b65 Explicit public visibility on methods 2017-09-18 12:57:46 -03:00
bd84db735d Merge pull request #450 from aupiff/master
removing trailing whitespace
2017-09-18 12:01:22 -03:00
bd99b207c9 Merge pull request #454 from economicnetwork/master
comments on vesting
2017-09-18 11:46:48 -03:00
2438557255 explain cliff 2017-09-18 12:41:54 +07:00
9f1826d83e vesting: more corrections on comments 2017-09-18 12:22:23 +07:00
676f5f6931 comments on vesting 2017-09-18 12:18:10 +07:00
6d8bb497c8 removing trailing whitespace 2017-09-16 10:20:06 -04:00
5fd8684a5a properly kill background testrpc instance 2017-09-14 15:40:14 -03:00
1737555b0d Merge pull request #439 from frangio/fix-436
Remove indexed declaration of value in Burn event
2017-09-11 12:28:30 -03:00
eda63c75c4 Merge pull request #440 from spalladino/fix/simple_token_initial_supply
Fix INITIAL_SUPPLY in SimpleToken example
2017-09-11 12:27:35 -03:00
61f62eb3c7 Fix INITIAL_SUPPLY in SimpleToken example
Use token decimals
2017-09-11 12:13:19 -03:00
f96ebfca31 cosmetic changes to BurnableToken 2017-09-11 12:11:00 -03:00
fac580d1a9 remove indexed declaration of uint event parameter 2017-09-11 12:08:23 -03:00
dc1017c929 Simplify implementation using similar interface as PullPayment contract 2017-09-09 12:04:31 -03:00
07b688a0e6 Merge pull request #430 from frangio/fix-unchecked-transfer
Use SafeERC20 to transfer tokens safely
2017-09-07 20:33:43 -03:00
20187f2970 use SafeERC20#safeTransfer 2017-09-07 20:04:48 -03:00
84be318ca9 Merge pull request #424 from eugene-babichenko/transfer-ownership-event
Add OwnershipTransferred event to Ownable contract and its derivatives
2017-09-07 11:59:29 -03:00
5035718e4b fixed wrong call order in Ownable.transferOwnership 2017-09-07 11:59:36 +03:00
fdc8fbaa45 Merge pull request #428 from frangio/fix-425-pausable-docs
Fix Pausable documentation
2017-09-06 16:25:37 -03:00
99887da49a fix Pausable documentation 2017-09-06 15:07:12 -03:00
7a36a6c92a fix calls to OwnershipTransferred 2017-09-06 10:31:23 +03:00
6beac0f215 add previousOwner field to OwnershipTransferred event 2017-09-06 10:29:25 +03:00
b59469c151 fire OwnershipTransferred event when the owner of an Ownable contract instance actually changed 2017-09-05 18:32:07 +03:00
b07466a477 Merge pull request #420 from sh4ka/patch-1
Fix docblock syntax
2017-09-01 11:25:50 -03:00
0bd22e78d3 Fix docblock syntax 2017-09-01 14:03:31 +01:00
69e83e5086 Add a SplitPullPayment contract that combines distribution of funds and delayed withdrawal from each party 2017-08-29 12:06:24 -03:00
8336785a9b Add a SplitPayment contract to distribute funds among multiple beneficiaries 2017-08-29 12:06:23 -03:00
f073352632 Merge pull request #416 from frangio/add-comment-basictoken-throw
Add comment making explicit that transfer throws without enough balance
2017-08-29 12:05:14 -03:00
aad25205cd add comment making explicit that SafeMath.sub can throw 2017-08-29 11:51:41 -03:00
dcdc453a55 Merge pull request #413 from frangio/add-safe-erc20
Add SafeERC20 helpers
2017-08-28 19:43:32 -03:00
5636575327 Merge pull request #415 from frangio/merge-411-manually
Check that destination of token transfers is not 0x0
2017-08-28 19:41:29 -03:00
00f80c726a fix reference to mock contract 2017-08-28 19:31:19 -03:00
74db6c2b3b add missing test for error when doing transferFrom to 0x0 2017-08-28 19:31:19 -03:00
d095ba84bf Add tests to check transfers to 0x0 fail 2017-08-28 19:31:19 -03:00
209e2de93b Fix for #400: Check that destination of token transfers is not 0x 2017-08-28 19:31:07 -03:00
c37c233d22 add SafeERC20 tests for succeeding operations 2017-08-28 19:27:56 -03:00
7b463769a5 explain how to use SafeERC20 2017-08-28 17:34:25 -03:00
c7636bdc4c add safe ERC20 helpers 2017-08-28 17:32:18 -03:00
307d34e05a Merge pull request #407 from frangio/rename-truffle-config
Rename Truffle config file
2017-08-25 20:47:43 -03:00
69e21dacb8 rename truffle.js to truffle-config.js 2017-08-25 20:08:54 -03:00
f27a1ac040 update solidity-coverage to 0.2.2 2017-08-25 20:08:54 -03:00
af6fdae3dd Merge pull request #348 from SylTi/refactor/HasNoToken
refactor HasNoTokens.sol to extract reclaimToken
2017-08-24 20:24:34 -03:00
6ae22e084a Merge pull request #406 from frangio/update-testrpc-4.1.1
Update testrpc to 4.1.1
2017-08-24 19:41:31 -03:00
d463b26709 bump testrpc to 4.1.1 2017-08-24 18:36:03 -03:00
271e6192e8 remove moment.js from package-lock 2017-08-24 18:36:03 -03:00
51906bae6c refactor 2017-08-24 21:42:31 +02:00
406004a99a refactor HasNoTokens.sol 2017-08-24 21:42:31 +02:00
b50894aabe Merge pull request #405 from androolloyd/fix/396-make-decimals-uint8-in-token-example
changed decimal to be uint8 so that it matches the ERC20 specification.
2017-08-24 11:12:29 -03:00
d6f07267ee Merge pull request #403 from rstormsf/patch-2
Remove confusing comment left from FinalizableCrowdsale
2017-08-24 11:07:51 -03:00
1827cbfd2a changed decimal to be uint8 so that it matches the ERC20 specification. 2017-08-24 10:41:41 -03:00
a0c0cb66c5 Remove confusing comment left from FinalizableCrowdsale
AFter this PR 
https://github.com/OpenZeppelin/zeppelin-solidity/pull/364
the comment was left.
2017-08-23 18:57:22 -07:00
47aa4bbf8f Merge pull request #394 from sot528/fix/remove-coverall-script
Removed coveralls script from package.json
2017-08-22 20:48:37 -03:00
33de70158c remove coveralls script from package.json 2017-08-22 10:15:21 +09:00
f45a4e8243 Merge pull request #392 from OpenZeppelin/revert-376-bugfix/windowsIncompatibilty
Revert Truffle config renaming
2017-08-21 16:30:02 -03:00
ac75f4e2ed Revert "[bugfix] windows incompatibilty" 2017-08-21 16:04:30 -03:00
631748480e Merge pull request #391 from rudygodoy/pr-224-tests
Added tests for PR #224
2017-08-21 15:47:02 -03:00
3d5c759d62 Merge pull request #388 from duckranger/patch-1
Update limitbalance.rst
2017-08-21 15:36:51 -03:00
2e0440e549 Merge pull request #389 from duckranger/patch-2
Update pullpayment.rst
2017-08-21 15:36:31 -03:00
86beb5b730 Merge pull request #376 from SylTi/bugfix/windowsIncompatibilty
[bugfix] windows incompatibilty
2017-08-21 15:34:40 -03:00
289fd87ef8 Tests increase and decrease allowance for spender
- Spender starts with 0 tokens allowed to spend
- Spender is granted 50, then decreased it's allowance by 10

Refs PR #224
2017-08-20 23:20:09 -05:00
8b11035b39 Indentation refactoring. 2017-08-20 23:13:39 -05:00
21f251eafb Removed onlyPayloadSize modifier 2017-08-20 23:11:23 -05:00
e7b1c33955 Update StandardToken.sol
Added increaseApproval and decreaseApproval to increase / decrease the approval in 1 transaction.
2017-08-20 23:10:28 -05:00
1da0467820 Update pullpayment.rst
Fixed typo
2017-08-20 22:00:42 +12:00
05609de044 Update limitbalance.rst
Fixed typo
2017-08-20 21:58:27 +12:00
02fb43ff52 Merge pull request #386 from frangio/remove-packagejson-main
Remove main field from package.json
2017-08-19 18:35:14 -03:00
1626c0095f Merge pull request #369 from frangio/parallelize-travis
Make Travis run tests and coverage in parallel
2017-08-19 18:34:09 -03:00
341ce621a9 remove main field from package.json 2017-08-19 18:22:42 -03:00
52efe2412c Merge pull request #384 from frangio/fix-pausabletoken-documentation
Fix PausableToken documentation
2017-08-19 16:40:13 -03:00
84e3e76bb8 fix PausableToken documentation 2017-08-19 16:35:46 -03:00
1d162e95c5 Merge pull request #377 from yaronvel/master
fix for issue 375: transferFrom allows sending to self more than self balance
2017-08-19 16:26:46 -03:00
060843d912 Merge pull request #380 from skywinder/typo-fix
Fixed typos in documentation
2017-08-19 16:24:31 -03:00
d3bc0a4ef7 Merge pull request #379 from skywinder/patch-1
Fixed typo in documentation
2017-08-19 16:22:58 -03:00
d1a82dde63 Merge pull request #373 from Neurone/patch-1
Fix mispelled words (#371)
2017-08-19 16:06:57 -03:00
99efe80c61 fixed typos in standart token doc 2017-08-18 15:35:13 +03:00
b12db57f34 Fixed typo
recieve -> receive
2017-08-18 15:25:15 +03:00
9333fec5f1 fix to issue 375 2017-08-17 21:56:11 +03:00
6f94af9264 fix windows incompatibilty 2017-08-17 12:34:43 +02:00
0ed98ea9b9 Merge pull request #368 from jakub-wojciechowski/master
Remove moment.js dependencies
2017-08-16 10:17:53 -03:00
0b66144942 Merge pull request #374 from rstormsf/patch-1
Remove beta tag from truffle
2017-08-16 01:12:51 -03:00
b91a3eded3 Remove beta tag from truffle
truffle@beta uses old solc 0.4.11
truffle main branch uses most up to date 0.4.15
2017-08-15 14:55:37 -07:00
7c9c0f6538 Fix for mispelled words (#371) 2017-08-15 23:08:41 +02:00
0d6846a882 Remove moment.js dependencies - updates after review 2017-08-15 12:31:49 +02:00
84a68e0c25 Merge pull request #364 from frangio/remove-crowdsale-finish-minting
Remove token.finishMinting() from default finalization
2017-08-14 14:57:22 -03:00
e82fa4eae0 parallelize tests and coverage in travis 2017-08-14 13:37:53 -03:00
c79c6d76d8 unify test and coverage scripts 2017-08-14 13:37:11 -03:00
36452136f1 add test for finishMinting 2017-08-13 22:41:25 -03:00
17cfb0fc78 Remove moment.js from package dependencies 2017-08-14 00:36:01 +02:00
e86ac90853 Refactor and remove moment.js usages 2017-08-14 00:27:09 +02:00
99e0f5b5cb Refactor time manipulation in TokenTimelock tests 2017-08-14 00:21:57 +02:00
4fc6bb7977 remove token.finishMinting() from default finalization 2017-08-12 22:02:44 -03:00
6e66ba321e Merge pull request #363 from frangio/sync-yarn-npm-locks
Sync yarn.lock file with package-lock.json
2017-08-12 19:26:58 -03:00
2c2067ecc1 sync yarn.lock file with package-lock.json
1. deleted node_modules
2. ran `npm install`
3. deleted yarn.lock
4. ran `yarn import`
2017-08-12 18:57:32 -03:00
e6a7a978d1 Merge pull request #362 from cgewecke/bump-solidity-coverage
Upgrade solidity coverage to ^0.2.1
2017-08-12 18:42:55 -03:00
3e02f45f67 Upgrade solidity coverage to ^0.2.1 2017-08-12 14:20:14 -07:00
b972f43513 Merge pull request #345 from SylTi/master
Add Transfer event when token is minted
2017-08-11 14:47:43 -03:00
30d02b1c78 Merge pull request #357 from frangio/fix-hdwallet-dependency
Move truffle-hdwallet-provider to devDependencies
2017-08-11 13:13:11 -03:00
479d01101d move truffle-hdwallet-provider to devDependencies 2017-08-11 11:30:44 -03:00
2b079136fb Merge pull request #353 from jakub-wojciechowski/master
Change crowdsales to use timestamps instead of block numbers #350
2017-08-10 12:42:55 -03:00
46c5759b88 Introduce increaseTimeTo helper method. 2017-08-10 16:23:52 +02:00
7c883b6368 Duration helper and eliminated hardcoded periods 2017-08-10 13:13:49 +02:00
69daed7746 Merge pull request #341 from lsaether/master
Added contracts/token/BurnableToken.sol
2017-08-09 17:22:58 -03:00
0b9afefa93 Merge pull request #339 from abarmat/typo-1
Fix typo in SafeMath doc
2017-08-07 17:25:36 -03:00
52490b92bf Merge pull request #340 from abarmat/style-1
Add missing parentheses in modifier
2017-08-07 17:25:01 -03:00
2261039d52 Simplify advanceBlock in tests 2017-08-07 18:29:09 +02:00
24323d3ce3 MerkleTree util class hashes elements 2017-08-07 11:23:52 -04:00
c6e055689b Change crowdsales to use timestamps instead of block numbers #350 update example 2017-08-06 16:42:16 +02:00
2b5192b9ce Change crowdsales to use timestamps instead of block numbers #350 update derived crowdsales 2017-08-06 16:41:43 +02:00
77dfcb6e23 Change crowdsales to use timestamps instead of block numbers #350 2017-08-06 16:40:19 +02:00
4fe837704b Add Transfer event when token is minted to be fully ERC20 compliant &
tests
2017-08-05 00:14:01 +02:00
cf58330936 added tests for BurnableToken 2017-07-31 17:23:23 -07:00
287b873add Merge pull request #338 from jeremygrenier/master
Remove return values of pause() and unpause() of Pausable
2017-07-31 11:58:56 -03:00
115e7afe0b Merge pull request #342 from jakub-wojciechowski/master
Add complex crowdsale example #331
2017-07-31 11:42:38 -03:00
a9e1fcd623 Add complex crowdsale example #331 requested changes 2017-07-29 09:00:54 +01:00
04e0b2e5c2 Add complex crowdsale example #331 tests 2017-07-29 00:29:59 +01:00
2403508e1b Add complex crowdsale example #331 2017-07-29 00:29:17 +01:00
b414545b6e fixed typos XP 2017-07-28 16:11:27 -07:00
3296471bda Added contracts/token/BurnableToken.sol 2017-07-28 16:07:04 -07:00
eb5b6252bc Add missing parentheses in modifier 2017-07-28 20:59:11 +02:00
e5da857d4f Fix typos in SafeMath doc 2017-07-28 20:53:55 +02:00
09a8da5d6a Remove return values of pause() and unpause() of Pausable 2017-07-28 17:35:27 +02:00
863ad48a81 Check proof length multiple of 32. Use keccak256 instead of sha3 2017-07-28 10:38:32 -04:00
de0e6ba222 Merge pull request #333 from frangio/examples
Move examples to separate directory
2017-07-26 20:22:20 -03:00
91e5a925d9 Merge pull request #334 from OpenZeppelin/upgrade/truffle-3.4.6
Upgrade truffle to 3.4.6
2017-07-26 19:33:01 -03:00
5e7c168b25 Fix missing storage keyword warnings 2017-07-26 17:23:20 -03:00
6fccd202fe Fix invalid number of args for solidity function errors in tests 2017-07-26 17:20:28 -03:00
18e98fbba8 Upgrade version of Truffle to 3.4.6 2017-07-26 16:36:13 -03:00
a799d218fd add constant qualifier 2017-07-26 16:12:05 -03:00
9f0cbd3303 move example contract 2017-07-26 16:12:05 -03:00
93fb8f35a8 Merge pull request #328 from frangio/remove-multisig
Remove MultisigWallet in favor of ConsenSys/MultiSigWallet
2017-07-24 19:13:23 -03:00
2303fd51a3 Merge pull request #329 from frangio/fix-test-script-cleanup
Fix test script cleanup and portability
2017-07-24 19:06:08 -03:00
910fc4915e Merge pull request #330 from frangio/coveralls-notification
Remove coveralls token
2017-07-24 18:00:27 -03:00
002acb984e remove coveralls token from repository 2017-07-24 17:23:24 -03:00
bebe704688 use portable shebang line 2017-07-24 13:57:42 -03:00
9a006f3a68 add check to see if process is running
because when we interrupt the tests via ^C, the signal also kills the
background process
2017-07-24 13:57:34 -03:00
58e2e4d742 remove MultisigWallet in favor of ConsenSys/MultiSigWallet 2017-07-24 13:26:48 -03:00
60bc6a6da5 Merge pull request #327 from jakub-wojciechowski/master
fix testing error throwing
2017-07-22 22:17:32 -03:00
b3f60b9320 refactor testing error throwing 2017-07-22 21:40:01 +01:00
e9cf6dfb60 Merge pull request #323 from pooleja/fix/ownable_error
Fix/ownable error - Silent transferOwnership Failure
2017-07-22 15:57:45 -03:00
5e7847537a fix testing error throwing 2017-07-22 11:46:49 +01:00
64787b1ac5 Add semicolon to match coding standards 2017-07-21 23:07:50 -07:00
58fdb956b5 Add assert to prevent regression 2017-07-21 23:04:50 -07:00
4d91118dd9 Merge pull request #320 from cgewecke/coverage-badge
Minor coverage maintenance
2017-07-21 16:06:23 -03:00
ed872ca0a1 Minor coverage maintenance 2017-07-21 11:25:53 -07:00
1bb1d41beb Merge pull request #281 from rudygodoy/master
Tests refactoring and typo fixes
2017-07-21 11:57:13 -03:00
1db46aa5d5 Merge pull request #292 from jakub-wojciechowski/test/pausable
Test if unpause prevents events allowed in paused state
2017-07-21 11:39:42 -03:00
c991eaf916 Merge pull request #325 from frangio/refactor/test-script
Refactor test script
2017-07-21 11:13:40 -03:00
86a69fd6d6 refactor test script
- fix status code (script exited with success even with failing tests)
- clean up and explain things
2017-07-20 18:58:31 -03:00
6735a3ccd6 Renamed tAMOUNT to much friendly amount 2017-07-20 16:01:41 -05:00
6d565ef841 Fix auto-formatting 2017-07-20 10:58:16 -07:00
b2e36314cb Add requirement for address to not be 0 and throw error 2017-07-20 10:51:57 -07:00
6904f12032 Merge with upstream/master 2017-07-20 07:01:58 -05:00
c3a30e9be3 Merge pull request #318 from BrianGuo/master
changed instances of uint to uint256
2017-07-19 15:54:53 -03:00
93b953fb48 changed instances of uint to uint256; fixes issue #226 2017-07-19 09:59:46 -04:00
e2fdf09e9b v1.2.0 2017-07-18 15:07:10 -03:00
4f44427966 Added function helper, few changes on ECRecover lib 2017-07-18 11:31:30 -03:00
f8c0fab5d8 Fixed tests and few changes on contract comments 2017-07-18 11:31:30 -03:00
478d1b1a93 Removed safeRecover, using ecrecover method instead, recovering signature from entire hash 2017-07-18 11:31:30 -03:00
a68eaa4e2d Added NatSpec documentation on ECRecovery contract 2017-07-18 11:31:30 -03:00
68c2bcb9dd Removed .only on ECRecovery tests 2017-07-18 11:31:30 -03:00
635c04378d Removed ECRecovery mock contract, ECRecovery funcions are public constants 2017-07-18 11:31:30 -03:00
227c7aae0f added check to ret boolean on ECRecovery 2017-07-18 11:31:30 -03:00
641b751385 Fix ECRecovery contract indentation
Fix ident on github

Fix ident github

Fix ident on github
2017-07-18 11:31:30 -03:00
4201d50dcf ECRecovery library added with test and docs 2017-07-18 11:31:30 -03:00
b05fb9c200 Update ownable.rst
Change the name of the function in the docs to the actual name in the contract source To prevent misunderstandings.
2017-07-17 21:37:59 -03:00
4f34d41523 Fixing typo. 2017-07-17 21:37:32 -03:00
91fc295a42 Updated reference to Ownable contract. 2017-07-17 21:37:32 -03:00
67d3a759a7 leave weiAmount after PR comments 2017-07-17 21:36:09 -03:00
950b6a5e56 sanity check for RefundableCrowdsale: goal > 0 2017-07-17 21:36:09 -03:00
db40fd314a sanity check for CappedCrowdsale: cap > 0 2017-07-17 21:36:09 -03:00
6035bd522b simplify crowdsale weiRaised update 2017-07-17 21:36:09 -03:00
b8884687df fix off by one error in VestedToken 2017-07-17 21:34:38 -03:00
18581f138f converted if() throw convention to require()/assert()/revert() 2017-07-17 15:35:09 -03:00
f3867f8477 Merge pull request #315 from joeykrug/patch-1
Added Constant to SafeMath functions as they don't modify storage
2017-07-15 15:52:36 -03:00
353285e5d9 Added Constant to SafeMath functions as they don't modify storage 2017-07-15 11:37:35 -07:00
a56bcbf8fd Correctly call super.transferableTokens
Fix #307
2017-07-14 18:17:09 -03:00
81297fac88 Merge pull request #308 from frangio/fix/erc20
Make ERC20 and token contracts conform to standard
2017-07-13 17:28:50 -03:00
6331dd125d fix ERC20 to conform to standard 2017-07-13 12:05:45 -03:00
f8790c1ed7 Merge pull request #304 from cgewecke/fix-coveralls
Fix coverage
2017-07-10 23:24:45 -03:00
5afbdf00db Fix coverage 2017-07-10 15:45:12 -07:00
322a9598ab Merge pull request #289 from ezynda3/master
update according to changes in #288
2017-07-06 11:07:13 -03:00
ba86e8e095 Merge pull request #296 from frangio/fix/293-tokentimelock-claim
Add TokenTimelock#release function that anyone can call
2017-07-05 11:47:15 -03:00
5e423bc353 add release function, deprecate claim 2017-07-05 11:24:59 -03:00
6eac859781 Test if unpause prevents events allowed in paused state 2017-07-03 17:06:47 +01:00
f2c2c01f8e Merge branch 'master' of github.com:OpenZeppelin/zeppelin-solidity 2017-07-02 15:50:40 -07:00
c254d8703d update according to changes in #288 2017-07-02 14:33:15 -07:00
981ec2dbdc v1.1.0 2017-07-02 18:27:18 -03:00
3c9638b62e Refactoring to not DRY.
The latest test case is not affected since the aproval is for
accounts[1], which does the transaction, and it is independent of
the amount of tokens that accounts[0] might have.
2017-06-29 13:18:54 -05:00
60ef284a9a Typo in variable, using global tAMOUNT for the latest test case. 2017-06-29 13:13:53 -05:00
b40a01e97b Small refactoring to not DRY 2017-06-29 13:12:58 -05:00
34e3ce4ab4 Typo fix: avaible -> available 2017-06-29 12:44:14 -05:00
4d6b48f39e Typo fix. standart -> standard 2017-06-29 12:40:26 -05:00
de99e7bf34 Prevent DRY 2017-06-29 12:31:32 -05:00
549590d105 Refactored to prevent DRY with beforeEach().
Refs# 259
2017-06-26 17:32:34 -05:00
bc3db5d4c1 Fix weird indent issue for inline assembly 2017-06-15 11:13:37 -04:00
30e202313d Fix indentation in MerkleProof.sol and remove mock contract 2017-06-15 11:10:37 -04:00
2e0bd06da2 Add tests, docs and MerkleTree helper 2017-06-15 11:07:22 -04:00
3c4d0d0a77 MerkleProof library and initial stubbed out tests 2017-06-14 16:34:46 -04:00
149 changed files with 9404 additions and 5397 deletions

View File

@ -1 +0,0 @@
repo_token: AelGMv47LJ85e3KF1PhYBsjyduSjDmP0h

4
.gitignore vendored
View File

@ -4,4 +4,6 @@ node_modules/
build/
.DS_Store/
/coverage
coverage.json
coverage.json
allFiredEvents
scTopics

5
.solcover.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = {
norpc: true,
testCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle test --network coverage',
skipFiles: ['lifecycle/Migrations.sol']
}

View File

@ -1 +1 @@
node_modules
node_modules

View File

@ -1,12 +1,20 @@
dist: trusty
sudo: false
sudo: required
group: beta
language: node_js
node_js:
- "6"
cache:
yarn: true
before_script:
- truffle version
- yarn list
script:
- yarn test
after_script:
- yarn run coveralls
notifications:
slack:
rooms:
- secure: uEhwUkuwJp5pBNh+VTEytPHz3FDKsnPrKO+8MTAKv5hKi4PCRoVhLv6pklr82HUpL6pvSvJbUPA0HVebOXA+MMSxdny/BHZTh2mtw5Y78l2Ad0svDTWuV2Lus2pmhYigRhT0Wo00/SRX9+pxm0kg4EIFJSTS+uR9G76x0l9NljpEGXrqxlDxjxoHBgk8Ciru2LHaLzX/utE3jlABts4Sb1F3wc2BwFkjd6BDCRTGAPhVJwwFk41ZfnmLVbgSNUyk46Cb38oG5oXHb0FI3d3jV/k1OUhRyFfmA2fLXRk0wavibW8TG1gGJJWZ7xTCKzw/Cvup6mpehSAeQef8eekMdjpWEhF9hYRq1BvOs0384UU8NQ0O+BtdXU+X3Nyr84TMJN/iIfgN7gYX7AsvXH3jC0JfNUcIkWlJvyXdE6l2GV1hMmhL09GFEBbSpuSXRIWlOXTcYBlp5NbvE8xO8PUW+T6N5RG2XXjv1g8wCpr6Wwk1+LmRkX5trv8MFBZ2pM8p4H5da5++Ov8egLonNGK2jbx6aBLBX3tPf+g70LZEkiQ4eBfZw8VIgXIvKreisicppNuCD27gNmSEPNt0NkwiEBcTCJ9GSVAO0CU2g4ggvHDX2A+RW5XPET9bGkBXKLfFyV7Qe+MSQjXkCnW3bIRh7Wo1V31XiUiYOLuZPIiH3EQ=
on_success: change
on_failure: always
on_pull_requests: false

16
LICENSE
View File

@ -5,18 +5,18 @@ Copyright (c) 2016 Smart Contract Solutions, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,7 +1,7 @@
# Zeppelin Solidity
[![NPM Package](https://img.shields.io/npm/v/zeppelin-solidity.svg?style=flat-square)](https://www.npmjs.org/package/zeppelin-solidity)
[![Build Status](https://img.shields.io/travis/OpenZeppelin/zeppelin-solidity.svg?branch=master&style=flat-square)](https://travis-ci.org/OpenZeppelin/zeppelin-solidity)
[![Coverage Status](https://coveralls.io/repos/github/OpenZeppelin/zeppelin-solidity/badge.svg?branch=coveralls)](https://coveralls.io/github/OpenZeppelin/zeppelin-solidity?branch=coveralls)
[![Coverage Status](https://img.shields.io/coveralls/github/OpenZeppelin/zeppelin-solidity/master.svg?style=flat-square)](https://coveralls.io/github/OpenZeppelin/zeppelin-solidity?branch=master)
OpenZeppelin is a library for writing secure [Smart Contracts](https://en.wikipedia.org/wiki/Smart_contract) on Ethereum.
@ -16,13 +16,14 @@ With OpenZeppelin, you can build distributed applications, protocols and organiz
OpenZeppelin integrates with [Truffle](https://github.com/ConsenSys/truffle), an Ethereum development environment. Please install Truffle and initialize your project with `truffle init`.
```sh
npm install -g truffle@beta
npm install -g truffle
mkdir myproject && cd myproject
truffle init
```
To install the OpenZeppelin library, run:
```sh
npm init
npm install zeppelin-solidity
# If you are using yarn, add dependency like this -

View File

@ -5,7 +5,7 @@ Authored by Dennis Peterson and Peter Vessenes
# Introduction
Zeppelin requested that New Alchemy perform an audit of the contracts in their OpenZeppelin library. The OpenZeppelin contracts are a set of contracts intended to be a safe building block for a variety of uses by parties that may not be as sophisticated as the OpenZeppelin team. It is a design goal that the contracts be deployable safely and "as-is".
Zeppelin requested that New Alchemy perform an audit of the contracts in their OpenZeppelin library. The OpenZeppelin contracts are a set of contracts intended to be a safe building block for a variety of uses by parties that may not be as sophisticated as the OpenZeppelin team. It is a design goal that the contracts be deployable safely and "as-is".
The contracts are hosted at:
@ -22,9 +22,9 @@ The audit makes no statements or warrantees about utility of the code, safety of
# Executive Summary
Overall the OpenZeppelin codebase is of reasonably high quality -- it is clean, modular and follows best practices throughout.
Overall the OpenZeppelin codebase is of reasonably high quality -- it is clean, modular and follows best practices throughout.
It is still in flux as a codebase, and needs better documentation per file as to expected behavior and future plans. It probably needs more comprehensive and aggressive tests written by people less nice than the current OpenZeppelin team.
It is still in flux as a codebase, and needs better documentation per file as to expected behavior and future plans. It probably needs more comprehensive and aggressive tests written by people less nice than the current OpenZeppelin team.
We identified two critical errors and one moderate issue, and would not recommend this commit hash for public use until these bugs are remedied.
@ -34,12 +34,12 @@ The repository includes a set of Truffle unit tests, a requirement and best prac
## Big Picture: Is This A Worthwhile Project?
As soon as a developer touches OpenZeppelin contracts, they will modify something, leaving them in an un-audited state. We do not recommend developers deploy any unaudited code to the Blockchain if it will handle money, information or other things of value.
As soon as a developer touches OpenZeppelin contracts, they will modify something, leaving them in an un-audited state. We do not recommend developers deploy any unaudited code to the Blockchain if it will handle money, information or other things of value.
> "In accordance with Unix philosophy, Perl gives you enough rope to hang yourself"
> --Larry Wall
We think this is an incredibly worthwhile project -- aided by the high code quality. Creating a framework that can be easily extended helps increase the average code quality on the Blockchain by charting a course for developers and encouraging containment of modifications to certain sections.
We think this is an incredibly worthwhile project -- aided by the high code quality. Creating a framework that can be easily extended helps increase the average code quality on the Blockchain by charting a course for developers and encouraging containment of modifications to certain sections.
> "Rust: The language that makes you take the safety off before shooting yourself in the foot"
> -- (@mbrubeck)
@ -65,7 +65,7 @@ In general we prefer `throw` in our code audits, because it is simpler -- it's l
In the OpenZeppelin contracts, both styles are used in different parts of the codebase. `SimpleToken` transfers throw upon failure, while the full ERC20 token returns `false`. Some modifiers `throw`, others just wrap the function body in a conditional, effectively allowing the function to return false if the condition is not met.
We don't love this, and would usually recommend you stick with one style or the other throughout the codebase.
We don't love this, and would usually recommend you stick with one style or the other throughout the codebase.
In at least one case, these different techniques are combined cleverly (see the Multisig comments, line 65). As a set of contracts intended for general use, we recommend you either strive for more consistency or document explicit design criteria that govern which techniques are used where.
@ -77,19 +77,19 @@ Note that it may be impossible to use either one in all situations. For example,
CrowdsaleToken.sol has no provision for withdrawing the raised ether. We *strongly* recommend a standard `withdraw` function be added. There is no scenario in which someone should deploy this contract as is, whether for testing or live.
## Recursive Call in MultisigWallet
Line 45 of `MultisigWallet.sol` checks if the amount being sent by `execute` is under a daily limit.
Line 45 of `MultisigWallet.sol` checks if the amount being sent by `execute` is under a daily limit.
This function can only be called by the "Owner". As a first angle of attack, it's worth asking what will happen if the multisig wallet owners reset the daily limit by approving a call to `resetSpentToday`.
This function can only be called by the "Owner". As a first angle of attack, it's worth asking what will happen if the multisig wallet owners reset the daily limit by approving a call to `resetSpentToday`.
If a chain of calls can be constructed in which the owner confirms the `resetSpentToday` function and then withdraws through `execute` in a recursive call, the contract can be drained. In fact, this could be done without a recursive call, just through repeated `execute` calls alternating with the `confirm` calls.
We are still working through the confirmation protocol in `Shareable.sol`, but we are not convinced that this is impossible, in fact it looks possible. The flexibility any shared owner has in being able to revoke confirmation later is another worrisome angle of approach even if some simple patches are included.
We are still working through the confirmation protocol in `Shareable.sol`, but we are not convinced that this is impossible, in fact it looks possible. The flexibility any shared owner has in being able to revoke confirmation later is another worrisome angle of approach even if some simple patches are included.
This bug has a number of causes that need to be addressed:
1. `resetSpentToday` and `confirm` together do not limit the days on which the function can be called or (it appears) the number of times it can be called.
1. Once a call has been confirmed and `execute`d it appears that it can be re-executed. This is not good.
3. `confirmandCheck` doesn't seem to have logic about whether or not the function in question has been called.
1. `resetSpentToday` and `confirm` together do not limit the days on which the function can be called or (it appears) the number of times it can be called.
1. Once a call has been confirmed and `execute`d it appears that it can be re-executed. This is not good.
3. `confirmandCheck` doesn't seem to have logic about whether or not the function in question has been called.
4. Even if it did, `revoke` would need updates and logic to deal with revocation requests after a function call had been completed.
We do not recommend using the MultisigWallet until these issues are fixed.
@ -97,9 +97,9 @@ We do not recommend using the MultisigWallet until these issues are fixed.
# Moderate to Minor Issues
## PullPayment
PullPayment.sol needs some work. It has no explicit provision for cancelling a payment. This would be desirable in a number of scenarios; consider a payee losing their wallet, or giving a griefing address, or just an address that requires more than the default gas offered by `send`.
PullPayment.sol needs some work. It has no explicit provision for cancelling a payment. This would be desirable in a number of scenarios; consider a payee losing their wallet, or giving a griefing address, or just an address that requires more than the default gas offered by `send`.
`asyncSend` has no overflow checking. This is a bad plan. We recommend overflow and underflow checking at the layer closest to the data manipulation.
`asyncSend` has no overflow checking. This is a bad plan. We recommend overflow and underflow checking at the layer closest to the data manipulation.
`asyncSend` allows more balance to be queued up for sending than the contract holds. This is probably a bad idea, or at the very least should be called something different. If the intent is to allow this, it should have provisions for dealing with race conditions between competing `withdrawPayments` calls.
@ -107,7 +107,7 @@ It would be nice to see how many payments are pending. This would imply a bit of
## Shareable Contract
We do not believe the `Shareable.sol` contract is ready for primetime. It is missing functions, and as written may be vulnerable to a reordering attack -- an attack in which a miner or other party "racing" with a smart contract participant inserts their own information into a list or mapping.
We do not believe the `Shareable.sol` contract is ready for primetime. It is missing functions, and as written may be vulnerable to a reordering attack -- an attack in which a miner or other party "racing" with a smart contract participant inserts their own information into a list or mapping.
The confirmation and revocation code needs to be looked over with a very careful eye imagining extraordinarily bad behavior by shared owners before this contract can be called safe.
@ -129,7 +129,7 @@ I presume that the goal of this contract is to allow and annotate a migration to
### Pausable
We like these pauses! Note that these allow significant griefing potential by owners, and that this might not be obvious to participants in smart contracts using the OpenZeppelin framework. We would recommend that additional sample logic be added to for instance the TokenContract showing safer use of the pause and resume functions. In particular, we would recommend a timelock after which anyone could unpause the contract.
We like these pauses! Note that these allow significant griefing potential by owners, and that this might not be obvious to participants in smart contracts using the OpenZeppelin framework. We would recommend that additional sample logic be added to for instance the TokenContract showing safer use of the pause and resume functions. In particular, we would recommend a timelock after which anyone could unpause the contract.
The modifers use the pattern `if(bool){_;}`. This is fine for functions that return false upon failure, but could be problematic for functions expected to throw upon failure. See our comments above on standardizing on `throw` or `return(false)`.
@ -163,7 +163,7 @@ Line 34: "this contract only has six types of events"...actually only two.
Line 61: Why is `ownerIndex` keyed by addresses hashed to `uint`s? Why not use the addresses directly, so `ownerIndex` is less obscure, and so there's stronger typing?
Line 62: Do not love `++i) ... owners[2+ i]`. Makes me do math, which is not what I want to do. I want to not have to do math.
Line 62: Do not love `++i) ... owners[2+ i]`. Makes me do math, which is not what I want to do. I want to not have to do math.
There should probably be a function for adding a new operation, so the developer doesn't have to work directly with the internal data. (This would make the multisig contract even shorter.)
@ -171,7 +171,7 @@ There's a `revoke` function but not a `propose` function that we can see.
Beware reordering. If `propose` allows the user to choose a bytes string for their proposal, bad things(TM) will happen as currently written.
### Multisig
Just an interface. Note it allows changing an owner address, but not changing the number of owners. This is somewhat limiting but also simplifies implementation.
@ -184,9 +184,9 @@ Safe from reentrance attack since ether send is at the end, plus it uses `.send(
There's an argument to be made that `.call.value()` is a better option *if* you're sure that it will be done after all state updates, since `.send` will fail if the recipient has an expensive fallback function. However, in the context of a function meant to be embedded in other contracts, it's probably better to use `.send`. One possible compromise is to add a function which allows only the owner to send ether via `.call.value`.
If you don't use `call.value` you should implement a `cancel` function in case some value is pending here.
If you don't use `call.value` you should implement a `cancel` function in case some value is pending here.
Line 14:
Line 14:
Doesn't use safeAdd. Although it appears that payout amounts can only be increased, in fact the payer could lower the payout as much as desired via overflow. Also, the payer could add a large non-overflowing amount, causing the payment to exceed the contract balance and therefore fail when withdraw is attempted.
Recommendation: track the sum of non-withdrawn asyncSends, and don't allow a new one which exceeds the leftover balance. If it's ever desirable to make payments revocable, it should be done explicitly.
@ -195,7 +195,7 @@ Recommendation: track the sum of non-withdrawn asyncSends, and don't allow a new
### ERC20
Standard ERC20 interface only.
Standard ERC20 interface only.
There's a security hole in the standard, reported at Edcon: `approve` does not protect against race conditions and simply replaces the current value. An approved spender could wait for the owner to call `approve` again, then attempt to spend the old limit before the new limit is applied. If successful, this attacker could successfully spend the sum of both limits.
@ -208,11 +208,11 @@ https://drive.google.com/file/d/0ByMtMw2hul0EN3NCaVFHSFdxRzA/view
### ERC20Basic
Simpler interface skipping the Approve function. Note this departs from ERC20 in another way: transfer throws instead of returning false.
Simpler interface skipping the Approve function. Note this departs from ERC20 in another way: transfer throws instead of returning false.
### BasicToken
Uses `SafeSub` and `SafeMath`, so transfer `throw`s instead of returning false. This complies with ERC20Basic but not the actual ERC20 standard.
Uses `SafeSub` and `SafeMath`, so transfer `throw`s instead of returning false. This complies with ERC20Basic but not the actual ERC20 standard.
### StandardToken
@ -234,10 +234,10 @@ Note: an alternative pattern is a mint() function which is only callable from a
### VestedToken
Lines 23, 27:
Functions `transfer()` and `transferFrom()` have a modifier canTransfer which throws if not enough tokens are available. However, transfer() returns a boolean success. Inconsistent treatment of failure conditions may cause problems for other contracts using the token. (Note that transferableTokens() relies on safeSub(), so will also throw if there's insufficient balance.)
Lines 23, 27:
Functions `transfer()` and `transferFrom()` have a modifier canTransfer which throws if not enough tokens are available. However, transfer() returns a boolean success. Inconsistent treatment of failure conditions may cause problems for other contracts using the token. (Note that transferableTokens() relies on safeSub(), so will also throw if there's insufficient balance.)
Line 64:
Line 64:
Delete not actually necessary since the value is overwritten in the next line anyway.
## Root level
@ -255,7 +255,7 @@ The modifier `limitedDaily` calls `underLimit`, which both checks that the spend
Lines 4, 11:
Comment claims that `DayLimit` is multiowned, and Shareable is imported, but DayLimit does not actually inherit from Shareable. The intent may be for child contracts to inherit from Shareable (as Multisig does); in this case the import should be removed and the comment altered.
Line 46:
Line 46:
Manual overflow check instead of using safeAdd. Since this is called from a function that throws upon failure anyway, there's no real downside to using safeAdd.
### LimitBalance
@ -264,19 +264,19 @@ No issues.
### MultisigWallet
Lines 28, 76, 80:
Lines 28, 76, 80:
`kill`, `setDailyLimit`, and `resetSpentToday` only happen with multisig approval, and hashes for these actions are logged by Shareable. However, they should probably post their own events for easy reading.
Line 45:
Line 45:
This call to underLimit will reduce the daily limit, and then either throw or return 0. So in this case there's no danger that the limit will be reduced without the operation going through.
Line 65:
Line 65:
Shareable's onlyManyOwners will take the user's confirmation, and execute the function body if and only if enough users have confirmed. Whole thing throws if the send fails, which will roll back the confirmation. Confirm returns false if not enough have confirmed yet, true if the whole thing succeeds, and throws only in the exceptional circumstance that the designated transaction unexpectedly fails. Elegant design.
Line 68:
Line 68:
Throw here is good but note this function can fail either by returning false or by throwing.
Line 92:
Line 92:
A bit odd to split `clearPending()` between this contract and Shareable. However this does allow contracts inheriting from Shareable to use custom structs for pending transactions.

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import './payment/PullPayment.sol';
@ -16,20 +16,18 @@ contract Bounty is PullPayment, Destructible {
event TargetCreated(address createdAddress);
/**
* @dev Fallback function allowing the contract to recieve funds, if they haven't already been claimed.
* @dev Fallback function allowing the contract to receive funds, if they haven't already been claimed.
*/
function() payable {
if (claimed) {
throw;
}
function() external payable {
require(!claimed);
}
/**
* @dev Create and deploy the target contract (extension of Target contract), and sets the
* @dev Create and deploy the target contract (extension of Target contract), and sets the
* msg.sender as a researcher
* @return A target contract
*/
function createTarget() returns(Target) {
function createTarget() public returns(Target) {
Target target = Target(deployContract());
researchers[target] = msg.sender;
TargetCreated(target);
@ -46,15 +44,11 @@ contract Bounty is PullPayment, Destructible {
* @dev Sends the contract funds to the researcher that proved the contract is broken.
* @param target contract
*/
function claim(Target target) {
function claim(Target target) public {
address researcher = researchers[target];
if (researcher == 0) {
throw;
}
require(researcher != 0);
// Check Target contract invariants
if (target.checkInvariant()) {
throw;
}
require(!target.checkInvariant());
asyncSend(researcher, this.balance);
claimed = true;
}
@ -69,10 +63,10 @@ contract Bounty is PullPayment, Destructible {
contract Target {
/**
* @dev Checks all values a contract assumes to be true all the time. If this function returns
* false, the contract is broken in some way and is in an inconsistent state.
* In order to win the bounty, security researchers will try to cause this broken state.
* @return True if all invariant values are correct, false otherwise.
* @dev Checks all values a contract assumes to be true all the time. If this function returns
* false, the contract is broken in some way and is in an inconsistent state.
* In order to win the bounty, security researchers will try to cause this broken state.
* @return True if all invariant values are correct, false otherwise.
*/
function checkInvariant() returns(bool);
function checkInvariant() public returns(bool);
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
/**
* @title DayLimit
@ -15,7 +15,7 @@ contract DayLimit {
* @dev Constructor that sets the passed value as a dailyLimit.
* @param _limit uint256 to represent the daily limit.
*/
function DayLimit(uint256 _limit) {
function DayLimit(uint256 _limit) public {
dailyLimit = _limit;
lastDay = today();
}
@ -38,7 +38,7 @@ contract DayLimit {
/**
* @dev Checks to see if there is enough resource to spend today. If true, the resource may be expended.
* @param _value uint256 representing the amount of resource to spend.
* @return A boolean that is True if the resource was spended and false otherwise.
* @return A boolean that is True if the resource was spent and false otherwise.
*/
function underLimit(uint256 _value) internal returns (bool) {
// reset the spend limit if we're on a different day to last time.
@ -59,7 +59,7 @@ contract DayLimit {
* @dev Private function to determine today's index
* @return uint256 of today's index.
*/
function today() private constant returns (uint256) {
function today() private view returns (uint256) {
return now / 1 days;
}
@ -67,9 +67,7 @@ contract DayLimit {
* @dev Simple modifier for daily limit.
*/
modifier limitedDaily(uint256 _value) {
if (!underLimit(_value)) {
throw;
}
require(underLimit(_value));
_;
}
}

47
contracts/ECRecovery.sol Normal file
View File

@ -0,0 +1,47 @@
pragma solidity ^0.4.18;
/**
* @title Eliptic curve signature operations
*
* @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d
*/
library ECRecovery {
/**
* @dev Recover signer address from a message by using his signature
* @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address.
* @param sig bytes signature, the signature is generated using web3.eth.sign()
*/
function recover(bytes32 hash, bytes sig) public pure returns (address) {
bytes32 r;
bytes32 s;
uint8 v;
//Check the signature length
if (sig.length != 65) {
return (address(0));
}
// Divide the signature in r, s and v variables
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := byte(0, mload(add(sig, 96)))
}
// Version of signature should be 27 or 28, but 0 and 1 are also possible versions
if (v < 27) {
v += 27;
}
// If the version is correct return the signer address
if (v != 27 && v != 28) {
return (address(0));
} else {
return ecrecover(hash, v, r, s);
}
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
/**
@ -12,10 +12,10 @@ contract LimitBalance {
uint256 public limit;
/**
* @dev Constructor that sets the passed value as a limit.
* @dev Constructor that sets the passed value as a limit.
* @param _limit uint256 to represent the limit.
*/
function LimitBalance(uint256 _limit) {
function LimitBalance(uint256 _limit) public {
limit = _limit;
}
@ -23,9 +23,7 @@ contract LimitBalance {
* @dev Checks if limit was reached. Case true, it throws.
*/
modifier limitedPayable() {
if (this.balance > limit) {
throw;
}
require(this.balance <= limit);
_;
}

41
contracts/MerkleProof.sol Normal file
View File

@ -0,0 +1,41 @@
pragma solidity ^0.4.18;
/*
* @title MerkleProof
* @dev Merkle proof verification
* @note Based on https://github.com/ameensol/merkle-tree-solidity/blob/master/src/MerkleProof.sol
*/
library MerkleProof {
/*
* @dev Verifies a Merkle proof proving the existence of a leaf in a Merkle tree. Assumes that each pair of leaves
* and each pair of pre-images is sorted.
* @param _proof Merkle proof containing sibling hashes on the branch from the leaf to the root of the Merkle tree
* @param _root Merkle root
* @param _leaf Leaf of Merkle tree
*/
function verifyProof(bytes _proof, bytes32 _root, bytes32 _leaf) public pure returns (bool) {
// Check if proof length is a multiple of 32
if (_proof.length % 32 != 0) return false;
bytes32 proofElement;
bytes32 computedHash = _leaf;
for (uint256 i = 32; i <= _proof.length; i += 32) {
assembly {
// Load the current element of the proof
proofElement := mload(add(_proof, i))
}
if (computedHash < proofElement) {
// Hash(current computed hash + current element of the proof)
computedHash = keccak256(computedHash, proofElement);
} else {
// Hash(current element of the proof + current computed hash)
computedHash = keccak256(proofElement, computedHash);
}
}
// Check if the computed hash (root) is equal to the provided root
return computedHash == _root;
}
}

View File

@ -1,127 +0,0 @@
pragma solidity ^0.4.11;
import "./ownership/Multisig.sol";
import "./ownership/Shareable.sol";
import "./DayLimit.sol";
/**
* MultisigWallet
* Usage:
* bytes32 h = Wallet(w).from(oneOwner).execute(to, value, data);
* Wallet(w).from(anotherOwner).confirm(h);
*/
contract MultisigWallet is Multisig, Shareable, DayLimit {
struct Transaction {
address to;
uint256 value;
bytes data;
}
/**
* Constructor, sets the owners addresses, number of approvals required, and daily spending limit
* @param _owners A list of owners.
* @param _required The amount required for a transaction to be approved.
*/
function MultisigWallet(address[] _owners, uint256 _required, uint256 _daylimit)
Shareable(_owners, _required)
DayLimit(_daylimit) { }
/**
* @dev destroys the contract sending everything to `_to`.
*/
function destroy(address _to) onlymanyowners(keccak256(msg.data)) external {
selfdestruct(_to);
}
/**
* @dev Fallback function, receives value and emits a deposit event.
*/
function() payable {
// just being sent some cash?
if (msg.value > 0)
Deposit(msg.sender, msg.value);
}
/**
* @dev Outside-visible transaction entry point. Executes transaction immediately if below daily
* spending limit. If not, goes into multisig process. We provide a hash on return to allow the
* sender to provide shortcuts for the other confirmations (allowing them to avoid replicating
* the _to, _value, and _data arguments). They still get the option of using them if they want,
* anyways.
* @param _to The receiver address
* @param _value The value to send
* @param _data The data part of the transaction
*/
function execute(address _to, uint256 _value, bytes _data) external onlyOwner returns (bytes32 _r) {
// first, take the opportunity to check that we're under the daily limit.
if (underLimit(_value)) {
SingleTransact(msg.sender, _value, _to, _data);
// yes - just execute the call.
if (!_to.call.value(_value)(_data)) {
throw;
}
return 0;
}
// determine our operation hash.
_r = keccak256(msg.data, block.number);
if (!confirm(_r) && txs[_r].to == 0) {
txs[_r].to = _to;
txs[_r].value = _value;
txs[_r].data = _data;
ConfirmationNeeded(_r, msg.sender, _value, _to, _data);
}
}
/**
* @dev Confirm a transaction by providing just the hash. We use the previous transactions map,
* txs, in order to determine the body of the transaction from the hash provided.
* @param _h The transaction hash to approve.
*/
function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) {
if (txs[_h].to != 0) {
if (!txs[_h].to.call.value(txs[_h].value)(txs[_h].data)) {
throw;
}
MultiTransact(msg.sender, _h, txs[_h].value, txs[_h].to, txs[_h].data);
delete txs[_h];
return true;
}
}
/**
* @dev Updates the daily limit value.
* @param _newLimit uint256 to represent the new limit.
*/
function setDailyLimit(uint256 _newLimit) onlymanyowners(keccak256(msg.data)) external {
_setDailyLimit(_newLimit);
}
/**
* @dev Resets the value spent to enable more spending
*/
function resetSpentToday() onlymanyowners(keccak256(msg.data)) external {
_resetSpentToday();
}
// INTERNAL METHODS
/**
* @dev Clears the list of transactions pending approval.
*/
function clearPending() internal {
uint256 length = pendingsIndex.length;
for (uint256 i = 0; i < length; ++i) {
delete txs[pendingsIndex[i]];
}
super.clearPending();
}
// FIELDS
// pending transactions we have at present.
mapping (bytes32 => Transaction) txs;
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
/**
* @title Helps contracts guard agains rentrancy attacks.
@ -9,7 +9,7 @@ pragma solidity ^0.4.11;
contract ReentrancyGuard {
/**
* @dev We use a single lock for the whole contract.
* @dev We use a single lock for the whole contract.
*/
bool private rentrancy_lock = false;
@ -22,13 +22,10 @@ contract ReentrancyGuard {
* wrapper marked as `nonReentrant`.
*/
modifier nonReentrant() {
if(rentrancy_lock == false) {
rentrancy_lock = true;
_;
rentrancy_lock = false;
} else {
throw;
}
require(!rentrancy_lock);
rentrancy_lock = true;
_;
rentrancy_lock = false;
}
}

View File

@ -1,31 +1,32 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import '../math/SafeMath.sol';
import './Crowdsale.sol';
/**
* @title CappedCrowdsale
* @dev Extension of Crowsdale with a max amount of funds raised
* @dev Extension of Crowdsale with a max amount of funds raised
*/
contract CappedCrowdsale is Crowdsale {
using SafeMath for uint256;
uint256 public cap;
function CappedCrowdsale(uint256 _cap) {
function CappedCrowdsale(uint256 _cap) public {
require(_cap > 0);
cap = _cap;
}
// overriding Crowdsale#validPurchase to add extra cap logic
// @return true if investors can buy at the moment
function validPurchase() internal constant returns (bool) {
function validPurchase() internal view returns (bool) {
bool withinCap = weiRaised.add(msg.value) <= cap;
return super.validPurchase() && withinCap;
}
// overriding Crowdsale#hasEnded to add cap logic
// @return true if crowdsale event has ended
function hasEnded() public constant returns (bool) {
function hasEnded() public view returns (bool) {
bool capReached = weiRaised >= cap;
return super.hasEnded() || capReached;
}

View File

@ -1,14 +1,14 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import '../token/MintableToken.sol';
import '../math/SafeMath.sol';
/**
* @title Crowdsale
* @title Crowdsale
* @dev Crowdsale is a base contract for managing a token crowdsale.
* Crowdsales have a start and end block, where investors can make
* Crowdsales have a start and end timestamps, where investors can make
* token purchases and the crowdsale will assign them tokens based
* on a token per ETH rate. Funds collected are forwarded to a wallet
* on a token per ETH rate. Funds collected are forwarded to a wallet
* as they arrive.
*/
contract Crowdsale {
@ -17,9 +17,9 @@ contract Crowdsale {
// The token being sold
MintableToken public token;
// start and end block where investments are allowed (both inclusive)
uint256 public startBlock;
uint256 public endBlock;
// start and end timestamps where investments are allowed (both inclusive)
uint256 public startTime;
uint256 public endTime;
// address where funds are collected
address public wallet;
@ -36,24 +36,24 @@ contract Crowdsale {
* @param beneficiary who got the tokens
* @param value weis paid for purchase
* @param amount amount of tokens purchased
*/
*/
event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
function Crowdsale(uint256 _startBlock, uint256 _endBlock, uint256 _rate, address _wallet) {
require(_startBlock >= block.number);
require(_endBlock >= _startBlock);
function Crowdsale(uint256 _startTime, uint256 _endTime, uint256 _rate, address _wallet) public {
require(_startTime >= now);
require(_endTime >= _startTime);
require(_rate > 0);
require(_wallet != 0x0);
require(_wallet != address(0));
token = createTokenContract();
startBlock = _startBlock;
endBlock = _endBlock;
startTime = _startTime;
endTime = _endTime;
rate = _rate;
wallet = _wallet;
}
// creates the token to be sold.
// creates the token to be sold.
// override this method to have crowdsale of a specific mintable token.
function createTokenContract() internal returns (MintableToken) {
return new MintableToken();
@ -61,23 +61,22 @@ contract Crowdsale {
// fallback function can be used to buy tokens
function () payable {
function () external payable {
buyTokens(msg.sender);
}
// low level token purchase function
function buyTokens(address beneficiary) payable {
require(beneficiary != 0x0);
function buyTokens(address beneficiary) public payable {
require(beneficiary != address(0));
require(validPurchase());
uint256 weiAmount = msg.value;
uint256 updatedWeiRaised = weiRaised.add(weiAmount);
// calculate token amount to be created
uint256 tokens = weiAmount.mul(rate);
// update state
weiRaised = updatedWeiRaised;
weiRaised = weiRaised.add(weiAmount);
token.mint(beneficiary, tokens);
TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);
@ -92,16 +91,15 @@ contract Crowdsale {
}
// @return true if the transaction can buy tokens
function validPurchase() internal constant returns (bool) {
uint256 current = block.number;
bool withinPeriod = current >= startBlock && current <= endBlock;
function validPurchase() internal view returns (bool) {
bool withinPeriod = now >= startTime && now <= endTime;
bool nonZeroPurchase = msg.value != 0;
return withinPeriod && nonZeroPurchase;
}
// @return true if crowdsale event has ended
function hasEnded() public constant returns (bool) {
return block.number > endBlock;
function hasEnded() public view returns (bool) {
return now > endTime;
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import '../math/SafeMath.sol';
import '../ownership/Ownable.sol';
@ -6,8 +6,8 @@ import './Crowdsale.sol';
/**
* @title FinalizableCrowdsale
* @dev Extension of Crowsdale where an owner can do extra work
* after finishing. By default, it will end token minting.
* @dev Extension of Crowdsale where an owner can do extra work
* after finishing.
*/
contract FinalizableCrowdsale is Crowdsale, Ownable {
using SafeMath for uint256;
@ -16,24 +16,25 @@ contract FinalizableCrowdsale is Crowdsale, Ownable {
event Finalized();
// should be called after crowdsale ends, to do
// some extra finalization work
function finalize() onlyOwner {
/**
* @dev Must be called after crowdsale ends, to do some extra finalization
* work. Calls the contract's finalization function.
*/
function finalize() onlyOwner public {
require(!isFinalized);
require(hasEnded());
finalization();
Finalized();
isFinalized = true;
}
// end token minting on finalization
// override this with custom logic if needed
/**
* @dev Can be overridden to add finalization logic. The overriding function
* should call super.finalization() to ensure the chain of finalization is
* executed entirely.
*/
function finalization() internal {
token.finishMinting();
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import '../math/SafeMath.sol';
import '../ownership/Ownable.sol';
@ -22,31 +22,31 @@ contract RefundVault is Ownable {
event RefundsEnabled();
event Refunded(address indexed beneficiary, uint256 weiAmount);
function RefundVault(address _wallet) {
require(_wallet != 0x0);
function RefundVault(address _wallet) public {
require(_wallet != address(0));
wallet = _wallet;
state = State.Active;
}
function deposit(address investor) onlyOwner payable {
function deposit(address investor) onlyOwner public payable {
require(state == State.Active);
deposited[investor] = deposited[investor].add(msg.value);
}
function close() onlyOwner {
function close() onlyOwner public {
require(state == State.Active);
state = State.Closed;
Closed();
wallet.transfer(this.balance);
}
function enableRefunds() onlyOwner {
function enableRefunds() onlyOwner public {
require(state == State.Active);
state = State.Refunding;
RefundsEnabled();
}
function refund(address investor) {
function refund(address investor) public {
require(state == State.Refunding);
uint256 depositedValue = deposited[investor];
deposited[investor] = 0;

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import '../math/SafeMath.sol';
@ -21,7 +21,8 @@ contract RefundableCrowdsale is FinalizableCrowdsale {
// refund vault used to hold funds while crowdsale is running
RefundVault public vault;
function RefundableCrowdsale(uint256 _goal) {
function RefundableCrowdsale(uint256 _goal) public {
require(_goal > 0);
vault = new RefundVault(wallet);
goal = _goal;
}
@ -34,7 +35,7 @@ contract RefundableCrowdsale is FinalizableCrowdsale {
}
// if crowdsale is unsuccessful, investors can claim refunds here
function claimRefund() {
function claimRefund() public {
require(isFinalized);
require(!goalReached());
@ -52,7 +53,7 @@ contract RefundableCrowdsale is FinalizableCrowdsale {
super.finalization();
}
function goalReached() public constant returns (bool) {
function goalReached() public view returns (bool) {
return weiRaised >= goal;
}

View File

@ -0,0 +1,48 @@
pragma solidity ^0.4.18;
import "../crowdsale/CappedCrowdsale.sol";
import "../crowdsale/RefundableCrowdsale.sol";
import "../token/MintableToken.sol";
/**
* @title SampleCrowdsaleToken
* @dev Very simple ERC20 Token that can be minted.
* It is meant to be used in a crowdsale contract.
*/
contract SampleCrowdsaleToken is MintableToken {
string public constant name = "Sample Crowdsale Token";
string public constant symbol = "SCT";
uint8 public constant decimals = 18;
}
/**
* @title SampleCrowdsale
* @dev This is an example of a fully fledged crowdsale.
* The way to add new features to a base crowdsale is by multiple inheritance.
* In this example we are providing following extensions:
* CappedCrowdsale - sets a max boundary for raised funds
* RefundableCrowdsale - set a min goal to be reached and returns funds if it's not met
*
* After adding multiple features it's good practice to run integration tests
* to ensure that subcontracts works together as intended.
*/
contract SampleCrowdsale is CappedCrowdsale, RefundableCrowdsale {
function SampleCrowdsale(uint256 _startTime, uint256 _endTime, uint256 _rate, uint256 _goal, uint256 _cap, address _wallet) public
CappedCrowdsale(_cap)
FinalizableCrowdsale()
RefundableCrowdsale(_goal)
Crowdsale(_startTime, _endTime, _rate, _wallet)
{
//As goal needs to be met for a successful crowdsale
//the value needs to less or equal than a cap which is limit for accepted funds
require(_goal <= _cap);
}
function createTokenContract() internal returns (MintableToken) {
return new SampleCrowdsaleToken();
}
}

View File

@ -0,0 +1,29 @@
pragma solidity ^0.4.18;
import "../token/StandardToken.sol";
/**
* @title SimpleToken
* @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
* Note they can later distribute these tokens as they wish using `transfer` and other
* `StandardToken` functions.
*/
contract SimpleToken is StandardToken {
string public constant name = "SimpleToken";
string public constant symbol = "SIM";
uint8 public constant decimals = 18;
uint256 public constant INITIAL_SUPPLY = 10000 * (10 ** uint256(decimals));
/**
* @dev Constructor that gives msg.sender all of existing tokens.
*/
function SimpleToken() public {
totalSupply = INITIAL_SUPPLY;
balances[msg.sender] = INITIAL_SUPPLY;
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import "../ownership/Ownable.sol";
@ -10,16 +10,16 @@ import "../ownership/Ownable.sol";
*/
contract Destructible is Ownable {
function Destructible() payable { }
function Destructible() public payable { }
/**
* @dev Transfers the current balance to the owner and terminates the contract.
* @dev Transfers the current balance to the owner and terminates the contract.
*/
function destroy() onlyOwner {
function destroy() onlyOwner public {
selfdestruct(owner);
}
function destroyAndSend(address _recipient) onlyOwner {
function destroyAndSend(address _recipient) onlyOwner public {
selfdestruct(_recipient);
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import '../ownership/Ownable.sol';
@ -10,11 +10,11 @@ import '../ownership/Ownable.sol';
contract Migrations is Ownable {
uint256 public lastCompletedMigration;
function setCompleted(uint256 completed) onlyOwner {
function setCompleted(uint256 completed) onlyOwner public {
lastCompletedMigration = completed;
}
function upgrade(address newAddress) onlyOwner {
function upgrade(address newAddress) onlyOwner public {
Migrations upgraded = Migrations(newAddress);
upgraded.setCompleted(lastCompletedMigration);
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import "../ownership/Ownable.sol";
@ -16,36 +16,34 @@ contract Pausable is Ownable {
/**
* @dev modifier to allow actions only when the contract IS paused
* @dev Modifier to make a function callable only when the contract is not paused.
*/
modifier whenNotPaused() {
if (paused) throw;
require(!paused);
_;
}
/**
* @dev modifier to allow actions only when the contract IS NOT paused
* @dev Modifier to make a function callable only when the contract is paused.
*/
modifier whenPaused {
if (!paused) throw;
modifier whenPaused() {
require(paused);
_;
}
/**
* @dev called by the owner to pause, triggers stopped state
*/
function pause() onlyOwner whenNotPaused returns (bool) {
function pause() onlyOwner whenNotPaused public {
paused = true;
Pause();
return true;
}
/**
* @dev called by the owner to unpause, returns to normal state
*/
function unpause() onlyOwner whenPaused returns (bool) {
function unpause() onlyOwner whenPaused public {
paused = false;
Unpause();
return true;
}
}

View File

@ -1,10 +1,10 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import "../ownership/Ownable.sol";
import "../token/ERC20Basic.sol";
/**
/**
* @title TokenDestructible:
* @author Remco Bloemen <remco@2π.com>
* @dev Base contract that can be destroyed by owner. All funds in contract including
@ -12,16 +12,16 @@ import "../token/ERC20Basic.sol";
*/
contract TokenDestructible is Ownable {
function TokenDestructible() payable { }
function TokenDestructible() public payable { }
/**
/**
* @notice Terminate contract and refund to owner
* @param tokens List of addresses of ERC20 or ERC20Basic token contracts to
refund.
* @notice The called token contracts could try to re-enter this contract. Only
supply token contracts you trust.
*/
function destroy(address[] tokens) onlyOwner {
function destroy(address[] tokens) onlyOwner public {
// Transfer tokens to owner
for(uint256 i = 0; i < tokens.length; i++) {

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
/**
* @title Math
@ -6,19 +6,19 @@ pragma solidity ^0.4.11;
*/
library Math {
function max64(uint64 a, uint64 b) internal constant returns (uint64) {
function max64(uint64 a, uint64 b) internal pure returns (uint64) {
return a >= b ? a : b;
}
function min64(uint64 a, uint64 b) internal constant returns (uint64) {
function min64(uint64 a, uint64 b) internal pure returns (uint64) {
return a < b ? a : b;
}
function max256(uint256 a, uint256 b) internal constant returns (uint256) {
function max256(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min256(uint256 a, uint256 b) internal constant returns (uint256) {
function min256(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
/**
@ -6,25 +6,28 @@ pragma solidity ^0.4.11;
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
function mul(uint256 a, uint256 b) internal returns (uint256) {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(a == 0 || c / a == b);
assert(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal returns (uint256) {
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal returns (uint256) {
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal returns (uint256) {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;

View File

@ -0,0 +1,25 @@
pragma solidity ^0.4.18;
import "./Ownable.sol";
import "../token/ERC20Basic.sol";
import "../token/SafeERC20.sol";
/**
* @title Contracts that should be able to recover tokens
* @author SylTi
* @dev This allow a contract to recover any ERC20 token received in a contract by transferring the balance to the contract owner.
* This will prevent any accidental loss of tokens.
*/
contract CanReclaimToken is Ownable {
using SafeERC20 for ERC20Basic;
/**
* @dev Reclaim all ERC20Basic compatible tokens
* @param token ERC20Basic The address of the token contract
*/
function reclaimToken(ERC20Basic token) external onlyOwner {
uint256 balance = token.balanceOf(this);
token.safeTransfer(owner, balance);
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import './Ownable.sol';
@ -6,35 +6,34 @@ import './Ownable.sol';
/**
* @title Claimable
* @dev Extension for the Ownable contract, where the ownership needs to be claimed.
* @dev Extension for the Ownable contract, where the ownership needs to be claimed.
* This allows the new owner to accept the transfer.
*/
contract Claimable is Ownable {
address public pendingOwner;
/**
* @dev Modifier throws if called by any account other than the pendingOwner.
* @dev Modifier throws if called by any account other than the pendingOwner.
*/
modifier onlyPendingOwner() {
if (msg.sender != pendingOwner) {
throw;
}
require(msg.sender == pendingOwner);
_;
}
/**
* @dev Allows the current owner to set the pendingOwner address.
* @param newOwner The address to transfer ownership to.
* @dev Allows the current owner to set the pendingOwner address.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) onlyOwner {
function transferOwnership(address newOwner) onlyOwner public {
pendingOwner = newOwner;
}
/**
* @dev Allows the pendingOwner address to finalize the transfer.
*/
function claimOwnership() onlyPendingOwner {
function claimOwnership() onlyPendingOwner public {
OwnershipTransferred(owner, pendingOwner);
owner = pendingOwner;
pendingOwner = 0x0;
pendingOwner = address(0);
}
}

View File

@ -1,10 +1,10 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import './Ownable.sol';
/**
* @title Contactable token
* @dev Basic version of a contactable contract, allowing the owner to provide a string with their
* @dev Basic version of a contactable contract, allowing the owner to provide a string with their
* contact information.
*/
contract Contactable is Ownable{
@ -15,7 +15,7 @@ contract Contactable is Ownable{
* @dev Allows the owner to set a string with their contact information.
* @param info The contact information to attach to the contract.
*/
function setContactInformation(string info) onlyOwner{
function setContactInformation(string info) onlyOwner public {
contactInformation = info;
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import './Claimable.sol';
@ -15,28 +15,27 @@ contract DelayedClaimable is Claimable {
uint256 public start;
/**
* @dev Used to specify the time period during which a pending
* owner can claim ownership.
* @dev Used to specify the time period during which a pending
* owner can claim ownership.
* @param _start The earliest time ownership can be claimed.
* @param _end The latest time ownership can be claimed.
* @param _end The latest time ownership can be claimed.
*/
function setLimits(uint256 _start, uint256 _end) onlyOwner {
if (_start > _end)
throw;
function setLimits(uint256 _start, uint256 _end) onlyOwner public {
require(_start <= _end);
end = _end;
start = _start;
}
/**
* @dev Allows the pendingOwner address to finalize the transfer, as long as it is called within
* the specified start and end time.
* @dev Allows the pendingOwner address to finalize the transfer, as long as it is called within
* the specified start and end time.
*/
function claimOwnership() onlyPendingOwner {
if ((block.number > end) || (block.number < start))
throw;
function claimOwnership() onlyPendingOwner public {
require((block.number <= end) && (block.number >= start));
OwnershipTransferred(owner, pendingOwner);
owner = pendingOwner;
pendingOwner = 0x0;
pendingOwner = address(0);
end = 0;
}

View File

@ -1,8 +1,8 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import "./Ownable.sol";
/**
/**
* @title Contracts that should not own Contracts
* @author Remco Bloemen <remco@2π.com>
* @dev Should contracts (anything Ownable) end up being owned by this contract, it allows the owner

View File

@ -1,8 +1,8 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import "./Ownable.sol";
/**
/**
* @title Contracts that should not own Ether
* @author Remco Bloemen <remco@2π.com>
* @dev This tries to block incoming ether to prevent accidental loss of Ether. Should Ether end up
@ -16,15 +16,13 @@ contract HasNoEther is Ownable {
/**
* @dev Constructor that rejects incoming Ether
* @dev The `payable` flag is added so we can access `msg.value` without compiler warning. If we
* leave out payable, then Solidity will allow inheriting contracts to implement a payable
* constructor. By doing it this way we prevent a payable constructor from working. Alternatively
* @dev The `payable` flag is added so we can access `msg.value` without compiler warning. If we
* leave out payable, then Solidity will allow inheriting contracts to implement a payable
* constructor. By doing it this way we prevent a payable constructor from working. Alternatively
* we could use assembly to access msg.value.
*/
function HasNoEther() payable {
if(msg.value > 0) {
throw;
}
function HasNoEther() public payable {
require(msg.value == 0);
}
/**
@ -37,8 +35,6 @@ contract HasNoEther is Ownable {
* @dev Transfer all Ether held by the contract to the owner.
*/
function reclaimEther() external onlyOwner {
if(!owner.send(this.balance)) {
throw;
}
assert(owner.send(this.balance));
}
}

View File

@ -1,34 +1,27 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import "./Ownable.sol";
import "../token/ERC20Basic.sol";
import "./CanReclaimToken.sol";
/**
/**
* @title Contracts that should not own Tokens
* @author Remco Bloemen <remco@2π.com>
* @dev This blocks incoming ERC23 tokens to prevent accidental loss of tokens.
* Should tokens (any ERC20Basic compatible) end up in the contract, it allows the
* owner to reclaim the tokens.
*/
contract HasNoTokens is Ownable {
contract HasNoTokens is CanReclaimToken {
/**
/**
* @dev Reject all ERC23 compatible tokens
* @param from_ address The address that is transferring the tokens
* @param value_ uint256 the amount of the specified token
* @param data_ Bytes The data passed from the caller.
*/
function tokenFallback(address from_, uint256 value_, bytes data_) external {
throw;
from_;
value_;
data_;
revert();
}
/**
* @dev Reclaim all ERC20Basic compatible tokens
* @param tokenAddr address The address of the token contract
*/
function reclaimToken(address tokenAddr) external onlyOwner {
ERC20Basic tokenInst = ERC20Basic(tokenAddr);
uint256 balance = tokenInst.balanceOf(this);
tokenInst.transfer(owner, balance);
}
}

View File

@ -1,28 +0,0 @@
pragma solidity ^0.4.11;
/**
* @title Multisig
* @dev Interface contract for multisig proxy contracts; see below for docs.
*/
contract Multisig {
// EVENTS
// logged events:
// Funds has arrived into the wallet (record how much).
event Deposit(address _from, uint256 value);
// Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going).
event SingleTransact(address owner, uint256 value, address to, bytes data);
// Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going).
event MultiTransact(address owner, bytes32 operation, uint256 value, address to, bytes data);
// Confirmation still needed for a transaction.
event ConfirmationNeeded(bytes32 operation, address initiator, uint256 value, address to, bytes data);
// FUNCTIONS
// TODO: document
function changeOwner(address _from, address _to) external;
function execute(address _to, uint256 _value, bytes _data) external returns (bytes32);
function confirm(bytes32 _h) returns (bool);
}

View File

@ -1,13 +1,13 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import "./HasNoEther.sol";
import "./HasNoTokens.sol";
import "./HasNoContracts.sol";
/**
/**
* @title Base contract for contracts that should not own things.
* @author Remco Bloemen <remco@2π.com>
* @dev Solves a class of errors where a contract accidentally becomes owner of Ether, Tokens or
* @dev Solves a class of errors where a contract accidentally becomes owner of Ether, Tokens or
* Owned contracts. See respective base contracts for details.
*/
contract NoOwner is HasNoEther, HasNoTokens, HasNoContracts {

View File

@ -1,43 +1,44 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
/**
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function Ownable() {
function Ownable() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
if (msg.sender != owner) {
throw;
}
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) onlyOwner {
if (newOwner != address(0)) {
owner = newOwner;
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}

View File

@ -1,189 +0,0 @@
pragma solidity ^0.4.11;
/**
* @title Shareable
* @dev inheritable "property" contract that enables methods to be protected by requiring the
* acquiescence of either a single, or, crucially, each of a number of, designated owners.
* @dev Usage: use modifiers onlyowner (just own owned) or onlymanyowners(hash), whereby the same hash must be provided by some number (specified in constructor) of the set of owners (specified in the constructor) before the interior is executed.
*/
contract Shareable {
// struct for the status of a pending operation.
struct PendingState {
uint256 yetNeeded;
uint256 ownersDone;
uint256 index;
}
// the number of owners that must confirm the same operation before it is run.
uint256 public required;
// list of owners
address[256] owners;
// index on the list of owners to allow reverse lookup
mapping(address => uint256) ownerIndex;
// the ongoing operations.
mapping(bytes32 => PendingState) pendings;
bytes32[] pendingsIndex;
// this contract only has six types of events: it can accept a confirmation, in which case
// we record owner and operation (hash) alongside it.
event Confirmation(address owner, bytes32 operation);
event Revoke(address owner, bytes32 operation);
// simple single-sig function modifier.
modifier onlyOwner {
if (!isOwner(msg.sender)) {
throw;
}
_;
}
/**
* @dev Modifier for multisig functions.
* @param _operation The operation must have an intrinsic hash in order that later attempts can be
* realised as the same underlying operation and thus count as confirmations.
*/
modifier onlymanyowners(bytes32 _operation) {
if (confirmAndCheck(_operation)) {
_;
}
}
/**
* @dev Constructor is given the number of sigs required to do protected "onlymanyowners"
* transactions as well as the selection of addresses capable of confirming them.
* @param _owners A list of owners.
* @param _required The amount required for a transaction to be approved.
*/
function Shareable(address[] _owners, uint256 _required) {
owners[1] = msg.sender;
ownerIndex[msg.sender] = 1;
for (uint256 i = 0; i < _owners.length; ++i) {
owners[2 + i] = _owners[i];
ownerIndex[_owners[i]] = 2 + i;
}
required = _required;
if (required > owners.length) {
throw;
}
}
/**
* @dev Revokes a prior confirmation of the given operation.
* @param _operation A string identifying the operation.
*/
function revoke(bytes32 _operation) external {
uint256 index = ownerIndex[msg.sender];
// make sure they're an owner
if (index == 0) {
return;
}
uint256 ownerIndexBit = 2**index;
var pending = pendings[_operation];
if (pending.ownersDone & ownerIndexBit > 0) {
pending.yetNeeded++;
pending.ownersDone -= ownerIndexBit;
Revoke(msg.sender, _operation);
}
}
/**
* @dev Gets an owner by 0-indexed position (using numOwners as the count)
* @param ownerIndex uint256 The index of the owner
* @return The address of the owner
*/
function getOwner(uint256 ownerIndex) external constant returns (address) {
return address(owners[ownerIndex + 1]);
}
/**
* @dev Checks if given address is an owner.
* @param _addr address The address which you want to check.
* @return True if the address is an owner and fase otherwise.
*/
function isOwner(address _addr) constant returns (bool) {
return ownerIndex[_addr] > 0;
}
/**
* @dev Function to check is specific owner has already confirme the operation.
* @param _operation The operation identifier.
* @param _owner The owner address.
* @return True if the owner has confirmed and false otherwise.
*/
function hasConfirmed(bytes32 _operation, address _owner) constant returns (bool) {
var pending = pendings[_operation];
uint256 index = ownerIndex[_owner];
// make sure they're an owner
if (index == 0) {
return false;
}
// determine the bit to set for this owner.
uint256 ownerIndexBit = 2**index;
return !(pending.ownersDone & ownerIndexBit == 0);
}
/**
* @dev Confirm and operation and checks if it's already executable.
* @param _operation The operation identifier.
* @return Returns true when operation can be executed.
*/
function confirmAndCheck(bytes32 _operation) internal returns (bool) {
// determine what index the present sender is:
uint256 index = ownerIndex[msg.sender];
// make sure they're an owner
if (index == 0) {
throw;
}
var pending = pendings[_operation];
// if we're not yet working on this operation, switch over and reset the confirmation status.
if (pending.yetNeeded == 0) {
// reset count of confirmations needed.
pending.yetNeeded = required;
// reset which owners have confirmed (none) - set our bitmap to 0.
pending.ownersDone = 0;
pending.index = pendingsIndex.length++;
pendingsIndex[pending.index] = _operation;
}
// determine the bit to set for this owner.
uint256 ownerIndexBit = 2**index;
// make sure we (the message sender) haven't confirmed this operation previously.
if (pending.ownersDone & ownerIndexBit == 0) {
Confirmation(msg.sender, _operation);
// ok - check if count is enough to go ahead.
if (pending.yetNeeded <= 1) {
// enough confirmations: reset and run interior.
delete pendingsIndex[pendings[_operation].index];
delete pendings[_operation];
return true;
} else {
// not enough: record that this owner in particular confirmed.
pending.yetNeeded--;
pending.ownersDone |= ownerIndexBit;
}
}
return false;
}
/**
* @dev Clear the pending list.
*/
function clearPending() internal {
uint256 length = pendingsIndex.length;
for (uint256 i = 0; i < length; ++i) {
if (pendingsIndex[i] != 0) {
delete pendings[pendingsIndex[i]];
}
}
delete pendingsIndex;
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import '../math/SafeMath.sol';
@ -28,23 +28,16 @@ contract PullPayment {
/**
* @dev withdraw accumulated balance, called by payee.
*/
function withdrawPayments() {
function withdrawPayments() public {
address payee = msg.sender;
uint256 payment = payments[payee];
if (payment == 0) {
throw;
}
if (this.balance < payment) {
throw;
}
require(payment != 0);
require(this.balance >= payment);
totalPayments = totalPayments.sub(payment);
payments[payee] = 0;
if (!payee.send(payment)) {
throw;
}
assert(payee.send(payment));
}
}

View File

@ -0,0 +1,65 @@
pragma solidity ^0.4.18;
import '../math/SafeMath.sol';
/**
* @title SplitPayment
* @dev Base contract that supports multiple payees claiming funds sent to this contract
* according to the proportion they own.
*/
contract SplitPayment {
using SafeMath for uint256;
uint256 public totalShares = 0;
uint256 public totalReleased = 0;
mapping(address => uint256) public shares;
mapping(address => uint256) public released;
address[] public payees;
/**
* @dev Constructor
*/
function SplitPayment(address[] _payees, uint256[] _shares) public {
require(_payees.length == _shares.length);
for (uint256 i = 0; i < _payees.length; i++) {
addPayee(_payees[i], _shares[i]);
}
}
/**
* @dev Add a new payee to the contract.
* @param _payee The address of the payee to add.
* @param _shares The number of shares owned by the payee.
*/
function addPayee(address _payee, uint256 _shares) internal {
require(_payee != address(0));
require(_shares > 0);
require(shares[_payee] == 0);
payees.push(_payee);
shares[_payee] = _shares;
totalShares = totalShares.add(_shares);
}
/**
* @dev Claim your share of the balance.
*/
function claim() public {
address payee = msg.sender;
require(shares[payee] > 0);
uint256 totalReceived = this.balance.add(totalReleased);
uint256 payment = totalReceived.mul(shares[payee]).div(totalShares).sub(released[payee]);
require(payment != 0);
require(this.balance >= payment);
released[payee] = released[payee].add(payment);
totalReleased = totalReleased.add(payment);
payee.transfer(payment);
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import './ERC20Basic.sol';
@ -7,7 +7,7 @@ import '../math/SafeMath.sol';
/**
* @title Basic token
* @dev Basic version of StandardToken, with no allowances.
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
@ -19,18 +19,23 @@ contract BasicToken is ERC20Basic {
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) {
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) constant returns (uint256 balance) {
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}

View File

@ -0,0 +1,28 @@
pragma solidity ^0.4.18;
import './StandardToken.sol';
/**
* @title Burnable Token
* @dev Token that can be irreversibly burned (destroyed).
*/
contract BurnableToken is StandardToken {
event Burn(address indexed burner, uint256 value);
/**
* @dev Burns a specific amount of tokens.
* @param _value The amount of token to be burned.
*/
function burn(uint256 _value) public {
require(_value > 0);
require(_value <= balances[msg.sender]);
// no need to require value <= totalSupply, since that would imply the
// sender's balance is greater than the totalSupply, which *should* be an assertion failure
address burner = msg.sender;
balances[burner] = balances[burner].sub(_value);
totalSupply = totalSupply.sub(_value);
Burn(burner, _value);
}
}

View File

@ -0,0 +1,31 @@
pragma solidity ^0.4.11;
import './MintableToken.sol';
/**
* @title Capped token
* @dev Mintable token with a token cap.
*/
contract CappedToken is MintableToken {
uint256 public cap;
function CappedToken(uint256 _cap) public {
require(_cap > 0);
cap = _cap;
}
/**
* @dev Function to mint tokens
* @param _to The address that will receive the minted tokens.
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
require(totalSupply.add(_amount) <= cap);
return super.mint(_to, _amount);
}
}

View File

@ -0,0 +1,15 @@
pragma solidity ^0.4.18;
import './ERC20.sol';
contract DetailedERC20 is ERC20 {
string public name;
string public symbol;
uint8 public decimals;
function DetailedERC20(string _name, string _symbol, uint8 _decimals) public {
name = _name;
symbol = _symbol;
decimals = _decimals;
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import './ERC20Basic.sol';
@ -9,8 +9,8 @@ import './ERC20Basic.sol';
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender) constant returns (uint256);
function transferFrom(address from, address to, uint256 value);
function approve(address spender, uint256 value);
function allowance(address owner, address spender) public view returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
}

View File

@ -1,14 +1,14 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
uint256 public totalSupply;
function balanceOf(address who) constant returns (uint256);
function transfer(address to, uint256 value);
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}

View File

@ -1,57 +0,0 @@
pragma solidity ^0.4.11;
import "./ERC20.sol";
/**
* @title LimitedTransferToken
* @dev LimitedTransferToken defines the generic interface and the implementation to limit token
* transferability for different events. It is intended to be used as a base class for other token
* contracts.
* LimitedTransferToken has been designed to allow for different limiting factors,
* this can be achieved by recursively calling super.transferableTokens() until the base class is
* hit. For example:
* function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
* return min256(unlockedTokens, super.transferableTokens(holder, time));
* }
* A working example is VestedToken.sol:
* https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/VestedToken.sol
*/
contract LimitedTransferToken is ERC20 {
/**
* @dev Checks whether it can transfer or otherwise throws.
*/
modifier canTransfer(address _sender, uint256 _value) {
if (_value > transferableTokens(_sender, uint64(now))) throw;
_;
}
/**
* @dev Checks modifier and allows transfer if tokens are not locked.
* @param _to The address that will recieve the tokens.
* @param _value The amount of tokens to be transferred.
*/
function transfer(address _to, uint256 _value) canTransfer(msg.sender, _value) {
super.transfer(_to, _value);
}
/**
* @dev Checks modifier and allows transfer if tokens are not locked.
* @param _from The address that will send the tokens.
* @param _to The address that will recieve the tokens.
* @param _value The amount of tokens to be transferred.
*/
function transferFrom(address _from, address _to, uint256 _value) canTransfer(_from, _value) {
super.transferFrom(_from, _to, _value);
}
/**
* @dev Default transferable tokens function returns all tokens for a holder (no limit).
* @dev Overwriting transferableTokens(address holder, uint64 time) is the way to provide the
* specific logic for limiting token transferability for a holder over time.
*/
function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
return balanceOf(holder);
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import './StandardToken.sol';
@ -21,20 +21,21 @@ contract MintableToken is StandardToken, Ownable {
modifier canMint() {
if(mintingFinished) throw;
require(!mintingFinished);
_;
}
/**
* @dev Function to mint tokens
* @param _to The address that will recieve the minted tokens.
* @param _to The address that will receive the minted tokens.
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(address _to, uint256 _amount) onlyOwner canMint returns (bool) {
function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
totalSupply = totalSupply.add(_amount);
balances[_to] = balances[_to].add(_amount);
Mint(_to, _amount);
Transfer(address(0), _to, _amount);
return true;
}
@ -42,7 +43,7 @@ contract MintableToken is StandardToken, Ownable {
* @dev Function to stop minting new tokens.
* @return True if the operation was successful.
*/
function finishMinting() onlyOwner returns (bool) {
function finishMinting() onlyOwner canMint public returns (bool) {
mintingFinished = true;
MintFinished();
return true;

View File

@ -1,21 +1,33 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import './StandardToken.sol';
import '../lifecycle/Pausable.sol';
/**
* Pausable token
* @title Pausable token
*
* Simple ERC20 Token example, with pausable token creation
* @dev StandardToken modified with pausable transfers.
**/
contract PausableToken is StandardToken, Pausable {
function transfer(address _to, uint _value) whenNotPaused {
super.transfer(_to, _value);
function transfer(address _to, uint256 _value) public whenNotPaused returns (bool) {
return super.transfer(_to, _value);
}
function transferFrom(address _from, address _to, uint _value) whenNotPaused {
super.transferFrom(_from, _to, _value);
function transferFrom(address _from, address _to, uint256 _value) public whenNotPaused returns (bool) {
return super.transferFrom(_from, _to, _value);
}
function approve(address _spender, uint256 _value) public whenNotPaused returns (bool) {
return super.approve(_spender, _value);
}
function increaseApproval(address _spender, uint _addedValue) public whenNotPaused returns (bool success) {
return super.increaseApproval(_spender, _addedValue);
}
function decreaseApproval(address _spender, uint _subtractedValue) public whenNotPaused returns (bool success) {
return super.decreaseApproval(_spender, _subtractedValue);
}
}

View File

@ -0,0 +1,24 @@
pragma solidity ^0.4.18;
import './ERC20Basic.sol';
import './ERC20.sol';
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
function safeTransfer(ERC20Basic token, address to, uint256 value) internal {
assert(token.transfer(to, value));
}
function safeTransferFrom(ERC20 token, address from, address to, uint256 value) internal {
assert(token.transferFrom(from, to, value));
}
function safeApprove(ERC20 token, address spender, uint256 value) internal {
assert(token.approve(spender, value));
}
}

View File

@ -1,28 +0,0 @@
pragma solidity ^0.4.11;
import "./StandardToken.sol";
/**
* @title SimpleToken
* @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
* Note they can later distribute these tokens as they wish using `transfer` and other
* `StandardToken` functions.
*/
contract SimpleToken is StandardToken {
string public name = "SimpleToken";
string public symbol = "SIM";
uint256 public decimals = 18;
uint256 public INITIAL_SUPPLY = 10000;
/**
* @dev Contructor that gives msg.sender all of existing tokens.
*/
function SimpleToken() {
totalSupply = INITIAL_SUPPLY;
balances[msg.sender] = INITIAL_SUPPLY;
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import './BasicToken.sol';
@ -14,52 +14,74 @@ import './ERC20.sol';
*/
contract StandardToken is ERC20, BasicToken {
mapping (address => mapping (address => uint256)) allowed;
mapping (address => mapping (address => uint256)) internal allowed;
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amout of tokens to be transfered
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(address _from, address _to, uint256 _value) {
var _allowance = allowed[_from][msg.sender];
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
// Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
// if (_value > _allowance) throw;
balances[_to] = balances[_to].add(_value);
balances[_from] = balances[_from].sub(_value);
allowed[_from][msg.sender] = _allowance.sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
Transfer(_from, _to, _value);
return true;
}
/**
* @dev Aprove the passed address to spend the specified amount of tokens on behalf of msg.sender.
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
*
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value) {
// To change the approve amount you first have to reduce the addresses`
// allowance to zero by calling `approve(_spender, 0)` if it is not
// already 0 to mitigate the race condition described here:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
if ((_value != 0) && (allowed[msg.sender][_spender] != 0)) throw;
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint256 specifing the amount of tokens still avaible for the spender.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
function allowance(address _owner, address _spender) public view returns (uint256) {
return allowed[_owner][_spender];
}
/**
* approve should be called when allowed[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
*/
function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
uint oldValue = allowed[msg.sender][_spender];
if (_subtractedValue > oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}

View File

@ -1,25 +1,27 @@
pragma solidity ^0.4.11;
pragma solidity ^0.4.18;
import './ERC20Basic.sol';
import "../token/SafeERC20.sol";
/**
* @title TokenTimelock
* @dev TokenTimelock is a token holder contract that will allow a
* @dev TokenTimelock is a token holder contract that will allow a
* beneficiary to extract the tokens after a given release time
*/
contract TokenTimelock {
using SafeERC20 for ERC20Basic;
// ERC20 basic token contract being held
ERC20Basic token;
ERC20Basic public token;
// beneficiary of tokens after they are released
address beneficiary;
address public beneficiary;
// timestamp when token release is enabled
uint releaseTime;
uint64 public releaseTime;
function TokenTimelock(ERC20Basic _token, address _beneficiary, uint _releaseTime) {
function TokenTimelock(ERC20Basic _token, address _beneficiary, uint64 _releaseTime) public {
require(_releaseTime > now);
token = _token;
beneficiary = _beneficiary;
@ -27,15 +29,14 @@ contract TokenTimelock {
}
/**
* @dev beneficiary claims tokens held by time lock
* @notice Transfers tokens held by timelock to beneficiary.
*/
function claim() {
require(msg.sender == beneficiary);
function release() public {
require(now >= releaseTime);
uint amount = token.balanceOf(this);
uint256 amount = token.balanceOf(this);
require(amount > 0);
token.transfer(beneficiary, amount);
token.safeTransfer(beneficiary, amount);
}
}

View File

@ -0,0 +1,114 @@
pragma solidity ^0.4.18;
import './ERC20Basic.sol';
import './SafeERC20.sol';
import '../ownership/Ownable.sol';
import '../math/SafeMath.sol';
/**
* @title TokenVesting
* @dev A token holder contract that can release its token balance gradually like a
* typical vesting scheme, with a cliff and vesting period. Optionally revocable by the
* owner.
*/
contract TokenVesting is Ownable {
using SafeMath for uint256;
using SafeERC20 for ERC20Basic;
event Released(uint256 amount);
event Revoked();
// beneficiary of tokens after they are released
address public beneficiary;
uint256 public cliff;
uint256 public start;
uint256 public duration;
bool public revocable;
mapping (address => uint256) public released;
mapping (address => bool) public revoked;
/**
* @dev Creates a vesting contract that vests its balance of any ERC20 token to the
* _beneficiary, gradually in a linear fashion until _start + _duration. By then all
* of the balance will have vested.
* @param _beneficiary address of the beneficiary to whom vested tokens are transferred
* @param _cliff duration in seconds of the cliff in which tokens will begin to vest
* @param _duration duration in seconds of the period in which the tokens will vest
* @param _revocable whether the vesting is revocable or not
*/
function TokenVesting(address _beneficiary, uint256 _start, uint256 _cliff, uint256 _duration, bool _revocable) public {
require(_beneficiary != address(0));
require(_cliff <= _duration);
beneficiary = _beneficiary;
revocable = _revocable;
duration = _duration;
cliff = _start.add(_cliff);
start = _start;
}
/**
* @notice Transfers vested tokens to beneficiary.
* @param token ERC20 token which is being vested
*/
function release(ERC20Basic token) public {
uint256 unreleased = releasableAmount(token);
require(unreleased > 0);
released[token] = released[token].add(unreleased);
token.safeTransfer(beneficiary, unreleased);
Released(unreleased);
}
/**
* @notice Allows the owner to revoke the vesting. Tokens already vested
* remain in the contract, the rest are returned to the owner.
* @param token ERC20 token which is being vested
*/
function revoke(ERC20Basic token) public onlyOwner {
require(revocable);
require(!revoked[token]);
uint256 balance = token.balanceOf(this);
uint256 unreleased = releasableAmount(token);
uint256 refund = balance.sub(unreleased);
revoked[token] = true;
token.safeTransfer(owner, refund);
Revoked();
}
/**
* @dev Calculates the amount that has already vested but hasn't been released yet.
* @param token ERC20 token which is being vested
*/
function releasableAmount(ERC20Basic token) public view returns (uint256) {
return vestedAmount(token).sub(released[token]);
}
/**
* @dev Calculates the amount that has already vested.
* @param token ERC20 token which is being vested
*/
function vestedAmount(ERC20Basic token) public view returns (uint256) {
uint256 currentBalance = token.balanceOf(this);
uint256 totalBalance = currentBalance.add(released[token]);
if (now < cliff) {
return 0;
} else if (now >= start.add(duration) || revoked[token]) {
return totalBalance;
} else {
return totalBalance.mul(now.sub(start)).div(duration);
}
}
}

View File

@ -1,248 +0,0 @@
pragma solidity ^0.4.11;
import "../math/Math.sol";
import "./StandardToken.sol";
import "./LimitedTransferToken.sol";
/**
* @title Vested token
* @dev Tokens that can be vested for a group of addresses.
*/
contract VestedToken is StandardToken, LimitedTransferToken {
uint256 MAX_GRANTS_PER_ADDRESS = 20;
struct TokenGrant {
address granter; // 20 bytes
uint256 value; // 32 bytes
uint64 cliff;
uint64 vesting;
uint64 start; // 3 * 8 = 24 bytes
bool revokable;
bool burnsOnRevoke; // 2 * 1 = 2 bits? or 2 bytes?
} // total 78 bytes = 3 sstore per operation (32 per sstore)
mapping (address => TokenGrant[]) public grants;
event NewTokenGrant(address indexed from, address indexed to, uint256 value, uint256 grantId);
/**
* @dev Grant tokens to a specified address
* @param _to address The address which the tokens will be granted to.
* @param _value uint256 The amount of tokens to be granted.
* @param _start uint64 Time of the beginning of the grant.
* @param _cliff uint64 Time of the cliff period.
* @param _vesting uint64 The vesting period.
*/
function grantVestedTokens(
address _to,
uint256 _value,
uint64 _start,
uint64 _cliff,
uint64 _vesting,
bool _revokable,
bool _burnsOnRevoke
) public {
// Check for date inconsistencies that may cause unexpected behavior
if (_cliff < _start || _vesting < _cliff) {
throw;
}
if (tokenGrantsCount(_to) > MAX_GRANTS_PER_ADDRESS) throw; // To prevent a user being spammed and have his balance locked (out of gas attack when calculating vesting).
uint256 count = grants[_to].push(
TokenGrant(
_revokable ? msg.sender : 0, // avoid storing an extra 20 bytes when it is non-revokable
_value,
_cliff,
_vesting,
_start,
_revokable,
_burnsOnRevoke
)
);
transfer(_to, _value);
NewTokenGrant(msg.sender, _to, _value, count - 1);
}
/**
* @dev Revoke the grant of tokens of a specifed address.
* @param _holder The address which will have its tokens revoked.
* @param _grantId The id of the token grant.
*/
function revokeTokenGrant(address _holder, uint256 _grantId) public {
TokenGrant grant = grants[_holder][_grantId];
if (!grant.revokable) { // Check if grant was revokable
throw;
}
if (grant.granter != msg.sender) { // Only granter can revoke it
throw;
}
address receiver = grant.burnsOnRevoke ? 0xdead : msg.sender;
uint256 nonVested = nonVestedTokens(grant, uint64(now));
// remove grant from array
delete grants[_holder][_grantId];
grants[_holder][_grantId] = grants[_holder][grants[_holder].length.sub(1)];
grants[_holder].length -= 1;
balances[receiver] = balances[receiver].add(nonVested);
balances[_holder] = balances[_holder].sub(nonVested);
Transfer(_holder, receiver, nonVested);
}
/**
* @dev Calculate the total amount of transferable tokens of a holder at a given time
* @param holder address The address of the holder
* @param time uint64 The specific time.
* @return An uint256 representing a holder's total amount of transferable tokens.
*/
function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
uint256 grantIndex = tokenGrantsCount(holder);
if (grantIndex == 0) return balanceOf(holder); // shortcut for holder without grants
// Iterate through all the grants the holder has, and add all non-vested tokens
uint256 nonVested = 0;
for (uint256 i = 0; i < grantIndex; i++) {
nonVested = SafeMath.add(nonVested, nonVestedTokens(grants[holder][i], time));
}
// Balance - totalNonVested is the amount of tokens a holder can transfer at any given time
uint256 vestedTransferable = SafeMath.sub(balanceOf(holder), nonVested);
// Return the minimum of how many vested can transfer and other value
// in case there are other limiting transferability factors (default is balanceOf)
return Math.min256(vestedTransferable, super.transferableTokens(holder, time));
}
/**
* @dev Check the amount of grants that an address has.
* @param _holder The holder of the grants.
* @return A uint256 representing the total amount of grants.
*/
function tokenGrantsCount(address _holder) constant returns (uint256 index) {
return grants[_holder].length;
}
/**
* @dev Calculate amount of vested tokens at a specifc time.
* @param tokens uint256 The amount of tokens grantted.
* @param time uint64 The time to be checked
* @param start uint64 A time representing the begining of the grant
* @param cliff uint64 The cliff period.
* @param vesting uint64 The vesting period.
* @return An uint256 representing the amount of vested tokensof a specif grant.
* transferableTokens
* | _/-------- vestedTokens rect
* | _/
* | _/
* | _/
* | _/
* | /
* | .|
* | . |
* | . |
* | . |
* | . |
* | . |
* +===+===========+---------+----------> time
* Start Clift Vesting
*/
function calculateVestedTokens(
uint256 tokens,
uint256 time,
uint256 start,
uint256 cliff,
uint256 vesting) constant returns (uint256)
{
// Shortcuts for before cliff and after vesting cases.
if (time < cliff) return 0;
if (time >= vesting) return tokens;
// Interpolate all vested tokens.
// As before cliff the shortcut returns 0, we can use just calculate a value
// in the vesting rect (as shown in above's figure)
// vestedTokens = tokens * (time - start) / (vesting - start)
uint256 vestedTokens = SafeMath.div(
SafeMath.mul(
tokens,
SafeMath.sub(time, start)
),
SafeMath.sub(vesting, start)
);
return vestedTokens;
}
/**
* @dev Get all information about a specifc grant.
* @param _holder The address which will have its tokens revoked.
* @param _grantId The id of the token grant.
* @return Returns all the values that represent a TokenGrant(address, value, start, cliff,
* revokability, burnsOnRevoke, and vesting) plus the vested value at the current time.
*/
function tokenGrant(address _holder, uint256 _grantId) constant returns (address granter, uint256 value, uint256 vested, uint64 start, uint64 cliff, uint64 vesting, bool revokable, bool burnsOnRevoke) {
TokenGrant grant = grants[_holder][_grantId];
granter = grant.granter;
value = grant.value;
start = grant.start;
cliff = grant.cliff;
vesting = grant.vesting;
revokable = grant.revokable;
burnsOnRevoke = grant.burnsOnRevoke;
vested = vestedTokens(grant, uint64(now));
}
/**
* @dev Get the amount of vested tokens at a specific time.
* @param grant TokenGrant The grant to be checked.
* @param time The time to be checked
* @return An uint256 representing the amount of vested tokens of a specific grant at a specific time.
*/
function vestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
return calculateVestedTokens(
grant.value,
uint256(time),
uint256(grant.start),
uint256(grant.cliff),
uint256(grant.vesting)
);
}
/**
* @dev Calculate the amount of non vested tokens at a specific time.
* @param grant TokenGrant The grant to be checked.
* @param time uint64 The time to be checked
* @return An uint256 representing the amount of non vested tokens of a specifc grant on the
* passed time frame.
*/
function nonVestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
return grant.value.sub(vestedTokens(grant, time));
}
/**
* @dev Calculate the date when the holder can trasfer all its tokens
* @param holder address The address of the holder
* @return An uint256 representing the date of the last transferable tokens.
*/
function lastTokenIsTransferableDate(address holder) constant public returns (uint64 date) {
date = uint64(now);
uint256 grantIndex = grants[holder].length;
for (uint256 i = 0; i < grantIndex; i++) {
date = Math.max64(grants[holder][i].vesting, date);
}
}
}

View File

@ -17,4 +17,4 @@ help:
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@ -9,4 +9,4 @@ Returns the token balance of the passed address.
function transfer(address _to, uint _value) returns (bool success)
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Transfers tokens from sender's account. Amount must not be greater than sender's balance.
Transfers tokens from sender's account. Amount must not be greater than sender's balance.

View File

@ -7,14 +7,14 @@ To create a bounty for your contract, inherit from the base `Bounty` contract an
import "./YourContract.sol";
contract YourBounty is Bounty {
function deployContract() internal returns(address) {
return new YourContract()
function deployContract() internal returns(address) {
return new YourContract()
}
}
Next, implement invariant logic into your smart contract.
Your main contract should inherit from the Target class and implement the checkInvariant method. This is a function that should check everything your contract assumes to be true all the time. If this function returns false, it means your contract was broken in some way and is in an inconsistent state. This is what security researchers will try to acomplish when trying to get the bounty.
Your main contract should inherit from the `Target` class and implement the ```checkInvariant()``` method. This is a function that should check everything your contract assumes to be true all the time. If this function returns false, it means your contract was broken in some way and is in an inconsistent state. This is what security researchers will try to acomplish when trying to get the bounty.
At contracts/YourContract.sol::
@ -35,7 +35,7 @@ At ```migrations/2_deploy_contracts.js```::
deployer.deploy(YourBounty);
};
Next, add a reward to the bounty contract
Next, add a reward to the bounty contract.
After deploying the contract, send reward funds into the bounty contract.

View File

@ -1,12 +1,12 @@
Developer Resources
=============================================
Building a distributed application, protocol or organization with Zeppelin?
Building a distributed application, protocol or organization with OpenZeppelin?
Ask for help and follow progress at: https://zeppelin-slackin.herokuapp.com/
Ask for help and follow progress at: https://slack.openzeppelin.org/
Interested in contributing to Zeppelin?
Interested in contributing to OpenZeppelin?
* Framework proposal and roadmap: https://medium.com/zeppelin-blog/zeppelin-framework-proposal-and-development-roadmap-fdfa9a3a32ab#.iain47pak
* Issue tracker: https://github.com/OpenZeppelin/zeppelin-solidity/issues
* Contribution guidelines: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/CONTRIBUTING.md
* Contribution guidelines: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/CONTRIBUTING.md

View File

@ -0,0 +1,9 @@
ECRecovery
=============================================
Returns the signer of the hash using the signature divided in v, r, and s values.
recover(bytes32 hash, bytes sig) internal returns (address)
"""""""""""""""""""""""""""""""""""""""""""""""""
Returns the signer of the the hash using the signature that provides the web3.eth.sign() method.

View File

@ -1,36 +1,25 @@
Getting Started
=============================================
Zeppelin integrates with `Truffle <https://github.com/ConsenSys/truffle/>`_, an Ethereum development environment. Please install Truffle and initialize your project with ``truffle init``::
OpenZeppelin integrates with `Truffle <https://github.com/ConsenSys/truffle/>`_, an Ethereum development environment. Please install Truffle and initialize your project with ``truffle init``::
npm install -g truffle
mkdir myproject && cd myproject
truffle init
To install the Zeppelin library, run::
To install the OpenZeppelin library, run::
npm i zeppelin-solidity
npm init # follow instructions
npm install zeppelin-solidity
After that, you'll get all the library's contracts in the contracts/zeppelin folder. You can use the contracts in the library like so::
# If you are using yarn, add dependency like this -
yarn add zeppelin-solidity
import "./zeppelin/Ownable.sol";
After that, you'll get all the library's contracts in the `node_modules/zeppelin-solidity/contracts` folder. You can use the contracts in the library like so::
import "zeppelin-solidity/contracts/ownership/Ownable.sol";
contract MyContract is Ownable {
...
}
.. epigraph::
NOTE: The current distribution channel is npm, which is not ideal. `We're looking into providing a better tool for code distribution <https://github.com/OpenZeppelin/zeppelin-solidity/issues/13/>`_ , and ideas are welcome.
Truffle Beta Support
""""""""""""""""""""""""
We also support Truffle Beta npm integration. If you're using Truffle Beta, the contracts in ``node_modules`` will be enough, so feel free to delete the copies at your ``contracts`` folder. If you're using Truffle Beta, you can use Zeppelin contracts like so::
import "zeppelin-solidity/contracts/Ownable.sol";
contract MyContract is Ownable {
...
}
For more info see the `Truffle Beta package management tutorial <http://truffleframework.com/tutorials/package-management/>`_.

View File

@ -6,14 +6,14 @@
Welcome to Zeppelin-Solidity
=============================================
Zeppelin is a library for writing secure Smart Contracts on Ethereum.
Zeppelin is a library for writing secure Smart Contracts on Ethereum.
With Zeppelin, you can build distributed applications, protocols and organizations:
* using :doc:`contract-security-patterns`
* in the `Solidity language <https://solidity.readthedocs.io/en/develop/>`_.
The code is open-source, and `available on github <https://github.com/OpenZeppelin/zeppelin-solidity>`_.
The code is open-source, and `available on github <https://github.com/OpenZeppelin/zeppelin-solidity>`_.
.. toctree::
:maxdepth: 2
@ -24,7 +24,7 @@ The code is open-source, and `available on github <https://github.com/OpenZeppel
.. toctree::
:maxdepth: 2
:caption: Smart Contracts
ownable
Pausable
destructible
@ -41,7 +41,7 @@ The code is open-source, and `available on github <https://github.com/OpenZeppel
.. toctree::
:maxdepth: 2
:caption: Developer Resources
contract-security-patterns
developer-resources
license
license

View File

@ -13,4 +13,4 @@ Destroys the contract and sends funds back to the owner.
destroyAndSend(address _recipient) onlyOwner
"""""""""""""""""""
Destroys the contract and sends funds back to the _recepient.
Destroys the contract and sends funds back to the _recepient.

View File

@ -6,18 +6,18 @@ Copyright (c) 2016 Smart Contract Solutions, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -5,8 +5,8 @@ Base contract that provides mechanism for limiting the amount of funds a contrac
LimitBalance(unit _limit)
""""""""""""""""""""""""""""
Constructor takes an unisgned integer and sets it as the limit of funds this contract can hold.
Constructor takes an unsigned integer and sets it as the limit of funds this contract can hold.
modifier limitedPayable()
""""""""""""""""""""""""""""
Throws an error if this contract's balance is already above the limit.
Throws an error if this contract's balance is already above the limit.

24
docs/source/math.rst Normal file
View File

@ -0,0 +1,24 @@
Math
=============================================
Provides assorted low-level math operations.
max64(uint64 a, uint64 b) internal constant returns (uint64)
"""""""""""""""""""""""""""""""""""""""""""""""""
Returns the largest of two uint64 numbers.
min64(uint64 a, uint64 b) internal constant returns (uint64)
"""""""""""""""""""""""""""""""""""""""""""""""""
Returns the smallest of two uint64 numbers.
max64(uint256 a, uint256 b) internal constant returns (uint256)
"""""""""""""""""""""""""""""""""""""""""""""""""
Returns the largest of two uint256 numbers.
min64(uint256 a, uint256 b) internal constant returns (uint256)
"""""""""""""""""""""""""""""""""""""""""""""""""
Returns the smallest of two uint256 numbers.

View File

@ -0,0 +1,9 @@
MerkleProof
=============================================
Merkle proof verification for leaves of a Merkle tree.
verifyProof(bytes _proof, bytes32 _root, bytes32 _leaf) internal constant returns (bool)
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Verifies a Merkle proof proving the existence of a leaf in a Merkle tree. Assumes that each pair of leaves and each pair of pre-images is sorted.

View File

@ -13,4 +13,4 @@ Creates a new instance of the contract at the passed address.
setCompleted(uint completed) onlyOwner**
""""""""""""""""""""""""""""""""""""""""
Sets the last time that a migration was completed.
Sets the last time that a migration was completed.

View File

@ -11,6 +11,6 @@ modifier onlyOwner( )
""""""""""""""""""""""""""""""""""""""
Prevents function from running if it is called by anyone other than the owner.
transfer(address newOwner) onlyOwner
transferOwnership(address newOwner) onlyOwner
""""""""""""""""""""""""""""""""""""""
Transfers ownership of the contract to the passed address.
Transfers ownership of the contract to the passed address.

View File

@ -24,4 +24,4 @@ Only runs if pause mechanism is activated.
unpause() onlyOwner whenPaused returns (bool)
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Deactivates the pause mechanism.
Deactivates the pause mechanism.

View File

@ -9,4 +9,4 @@ Adds sent amount to available balance that payee can pull from this contract, ca
withdrawPayments( )
"""""""""""""""""""""""""""""""""""""""""""""""
Sends designated balance to payee calling the contract. Throws error if designated balance is 0, if contract does not hold enough funds ot pay the payee, or if the send transaction is not successful.
Sends designated balance to payee calling the contract. Throws error if designated balance is 0, if contract does not hold enough funds to pay the payee, or if the send transaction is not successful.

View File

@ -8,17 +8,17 @@ assert(bool assertion) internal
Throws an error if the passed result is false. Used in this contract by checking mathematical expressions.
safeMul(uint a, uint b) internal returns (uint)
mul(uint256 a, uint256 b) internal returns (uint256)
"""""""""""""""""""""""""""""""""""""""""""""""""
Multiplies two unisgned integers. Asserts that dividing the product by the non-zero multiplicand results in the multiplier.
Multiplies two unsigned integers. Asserts that dividing the product by the non-zero multiplicand results in the multiplier.
safeSub(uint a, uint b) internal returns (uint)
sub(uint256 a, uint256 b) internal returns (uint256)
"""""""""""""""""""""""""""""""""""""""""""""""""
Checks that b is not greater than a before subtracting.
safeAdd(uint a, uint b) internal returns (uint)
add(uint256 a, uint256 b) internal returns (uint256)
"""""""""""""""""""""""""""""""""""""""""""""""""
Checks that the result is greater than both a and b.

View File

@ -23,4 +23,4 @@ Transfers tokens from an account that the sender is approved to transfer from. A
function transfer(address _to, uint _value) returns (bool success)
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Transfers tokens from sender's account. Amount must not be greater than sender's balance.
Transfers tokens from sender's account. Amount must not be greater than sender's balance.

View File

@ -1,6 +1,6 @@
{
"package_name": "zeppelin",
"version": "1.1.0",
"version": "1.4.0",
"description": "Secure Smart Contract library for Solidity",
"authors": [
"Manuel Araoz <manuelaraoz@gmail.com>"

6040
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,11 @@
{
"name": "zeppelin-solidity",
"version": "1.1.0",
"version": "1.4.0",
"description": "Secure Smart Contract library for Solidity",
"main": "truffle.js",
"scripts": {
"test": "scripts/test.sh",
"console": "truffle console",
"coverage": "scripts/coverage.sh",
"coveralls": "scripts/coveralls.sh"
"coverage": "scripts/coverage.sh"
},
"repository": {
"type": "git",
@ -27,10 +25,8 @@
"url": "https://github.com/OpenZeppelin/zeppelin-solidity/issues"
},
"homepage": "https://github.com/OpenZeppelin/zeppelin-solidity",
"dependencies": {
"truffle-hdwallet-provider": "0.0.3"
},
"devDependencies": {
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.18.0",
"babel-preset-stage-2": "^6.18.0",
"babel-preset-stage-3": "^6.17.0",
@ -39,10 +35,11 @@
"chai-as-promised": "^7.0.0",
"chai-bignumber": "^2.0.0",
"coveralls": "^2.13.1",
"ethereumjs-testrpc": "^3.0.2",
"ethereumjs-util": "^5.1.2",
"ethereumjs-testrpc": "^6.0.1",
"mocha-lcov-reporter": "^1.3.0",
"moment": "^2.18.1",
"solidity-coverage": "^0.1.0",
"truffle": "3.2.2"
"solidity-coverage": "^0.2.2",
"truffle": "^4.0.0",
"truffle-hdwallet-provider": "0.0.3"
}
}

View File

@ -1,3 +1,3 @@
#! /bin/bash
#!/usr/bin/env bash
SOLIDITY_COVERAGE=true ./node_modules/.bin/solidity-coverage
SOLIDITY_COVERAGE=true scripts/test.sh

View File

@ -1,4 +0,0 @@
#! /bin/bash
yarn run coverage && cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js

View File

@ -1,25 +1,65 @@
#! /bin/bash
#!/usr/bin/env bash
output=$(nc -z localhost 8545; echo $?)
[ $output -eq "0" ] && trpc_running=true
if [ ! $trpc_running ]; then
echo "Starting our own testrpc node instance"
# we give each account 1M ether, needed for high-value tests
testrpc \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501200,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501201,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501202,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501203,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501204,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501205,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501206,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501207,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501208,1000000000000000000000000" \
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501209,1000000000000000000000000" \
> /dev/null &
trpc_pid=$!
# Exit script as soon as a command fails.
set -o errexit
# Executes cleanup function at script exit.
trap cleanup EXIT
cleanup() {
# Kill the testrpc instance that we started (if we started one and if it's still running).
if [ -n "$testrpc_pid" ] && ps -p $testrpc_pid > /dev/null; then
kill -9 $testrpc_pid
fi
}
if [ "$SOLIDITY_COVERAGE" = true ]; then
testrpc_port=8555
else
testrpc_port=8545
fi
./node_modules/truffle/cli.js test "$@"
if [ ! $trpc_running ]; then
kill -9 $trpc_pid
testrpc_running() {
nc -z localhost "$testrpc_port"
}
start_testrpc() {
# We define 10 accounts with balance 1M ether, needed for high-value tests.
local accounts=(
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501200,1000000000000000000000000"
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501201,1000000000000000000000000"
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501202,1000000000000000000000000"
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501203,1000000000000000000000000"
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501204,1000000000000000000000000"
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501205,1000000000000000000000000"
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501206,1000000000000000000000000"
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501207,1000000000000000000000000"
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501208,1000000000000000000000000"
--account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501209,1000000000000000000000000"
)
if [ "$SOLIDITY_COVERAGE" = true ]; then
node_modules/.bin/testrpc-sc --gasLimit 0xfffffffffff --port "$testrpc_port" "${accounts[@]}" > /dev/null &
else
node_modules/.bin/testrpc --gasLimit 0xfffffffffff "${accounts[@]}" > /dev/null &
fi
testrpc_pid=$!
}
if testrpc_running; then
echo "Using existing testrpc instance"
else
echo "Starting our own testrpc instance"
start_testrpc
fi
if [ "$SOLIDITY_COVERAGE" = true ]; then
node_modules/.bin/solidity-coverage
if [ "$CONTINUOUS_INTEGRATION" = true ]; then
cat coverage/lcov.info | node_modules/.bin/coveralls
fi
else
node_modules/.bin/truffle test "$@"
fi

View File

@ -1,4 +1,4 @@
const assertJump = require('./helpers/assertJump');
const assertRevert = require('./helpers/assertRevert');
var BasicTokenMock = artifacts.require("./helpers/BasicTokenMock.sol");
@ -22,14 +22,24 @@ contract('BasicToken', function(accounts) {
assert.equal(secondAccountBalance, 100);
});
it("should throw an error when trying to transfer more than balance", async function() {
it('should throw an error when trying to transfer more than balance', async function() {
let token = await BasicTokenMock.new(accounts[0], 100);
try {
let transfer = await token.transfer(accounts[1], 101);
assert.fail('should have thrown before');
} catch(error) {
return assertJump(error);
assertRevert(error);
}
});
it('should throw an error when trying to transfer to 0x0', async function() {
let token = await BasicTokenMock.new(accounts[0], 100);
try {
let transfer = await token.transfer(0x0, 100);
assert.fail('should have thrown before');
} catch(error) {
assertRevert(error);
}
assert.fail('should have thrown before');
});
});

View File

@ -15,7 +15,7 @@ function awaitEvent(event, handler) {
function wrappedHandler(...args) {
Promise.resolve(handler(...args)).then(resolve).catch(reject);
}
event.watch(wrappedHandler);
});
}
@ -90,7 +90,7 @@ contract('Bounty', function(accounts) {
let reward = web3.toWei(1, 'ether');
let bounty = await InsecureTargetBounty.new();
let event = bounty.TargetCreated({});
let watcher = async function(err, result) {
event.stopWatching();
if (err) { throw err; }

39
test/BurnableToken.js Normal file
View File

@ -0,0 +1,39 @@
'use strict'
const EVMRevert = require('./helpers/EVMRevert.js')
const BurnableTokenMock = artifacts.require("./helpers/BurnableTokenMock.sol")
const BigNumber = web3.BigNumber
require('chai')
.use(require('chai-as-promised'))
.use(require('chai-bignumber')(BigNumber))
.should()
const expect = require('chai').expect
contract('BurnableToken', function (accounts) {
let token
let expectedTokenSupply = new BigNumber(999)
beforeEach(async function () {
token = await BurnableTokenMock.new(accounts[0], 1000)
})
it('owner should be able to burn tokens', async function () {
const { logs } = await token.burn(1, { from: accounts[0] })
const balance = await token.balanceOf(accounts[0])
balance.should.be.bignumber.equal(expectedTokenSupply)
const totalSupply = await token.totalSupply()
totalSupply.should.be.bignumber.equal(expectedTokenSupply)
const event = logs.find(e => e.event === 'Burn')
expect(event).to.exist
})
it('cannot burn more tokens than your balance', async function () {
await token.burn(2000, { from: accounts[0] })
.should.be.rejectedWith(EVMRevert)
})
})

35
test/CanReclaimToken.js Normal file
View File

@ -0,0 +1,35 @@
'use strict';
import expectThrow from './helpers/expectThrow';
import toPromise from './helpers/toPromise';
const CanReclaimToken = artifacts.require('../contracts/ownership/CanReclaimToken.sol');
const BasicTokenMock = artifacts.require("./helpers/BasicTokenMock.sol");
contract('CanReclaimToken', function(accounts) {
let token = null;
let canReclaimToken = null;
beforeEach(async function() {
// Create contract and token
token = await BasicTokenMock.new(accounts[0], 100);
canReclaimToken = await CanReclaimToken.new();
// Force token into contract
await token.transfer(canReclaimToken.address, 10);
const startBalance = await token.balanceOf(canReclaimToken.address);
assert.equal(startBalance, 10);
});
it('should allow owner to reclaim tokens', async function() {
const ownerStartBalance = await token.balanceOf(accounts[0]);
await canReclaimToken.reclaimToken(token.address);
const ownerFinalBalance = await token.balanceOf(accounts[0]);
const finalBalance = await token.balanceOf(canReclaimToken.address);
assert.equal(finalBalance, 0);
assert.equal(ownerFinalBalance - ownerStartBalance, 10);
});
it('should allow only owner to reclaim tokens', async function() {
await expectThrow(
canReclaimToken.reclaimToken(token.address, {from: accounts[1]}),
);
});
});

View File

@ -1,6 +1,8 @@
import ether from './helpers/ether'
import advanceToBlock from './helpers/advanceToBlock'
import EVMThrow from './helpers/EVMThrow'
import {advanceBlock} from './helpers/advanceToBlock'
import {increaseTimeTo, duration} from './helpers/increaseTime'
import latestTime from './helpers/latestTime'
import EVMRevert from './helpers/EVMRevert'
const BigNumber = web3.BigNumber
@ -19,19 +21,32 @@ contract('CappedCrowdsale', function ([_, wallet]) {
const cap = ether(300)
const lessThanCap = ether(60)
beforeEach(async function () {
this.startBlock = web3.eth.blockNumber + 10
this.endBlock = web3.eth.blockNumber + 20
before(async function() {
//Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
await advanceBlock()
})
this.crowdsale = await CappedCrowdsale.new(this.startBlock, this.endBlock, rate, wallet, cap)
beforeEach(async function () {
this.startTime = latestTime() + duration.weeks(1);
this.endTime = this.startTime + duration.weeks(1);
this.crowdsale = await CappedCrowdsale.new(this.startTime, this.endTime, rate, wallet, cap)
this.token = MintableToken.at(await this.crowdsale.token())
})
describe('creating a valid crowdsale', function () {
it('should fail with zero cap', async function () {
await CappedCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0).should.be.rejectedWith(EVMRevert);
})
});
describe('accepting payments', function () {
beforeEach(async function () {
await advanceToBlock(this.startBlock - 1)
await increaseTimeTo(this.startTime)
})
it('should accept payments within cap', async function () {
@ -41,11 +56,11 @@ contract('CappedCrowdsale', function ([_, wallet]) {
it('should reject payments outside cap', async function () {
await this.crowdsale.send(cap)
await this.crowdsale.send(1).should.be.rejectedWith(EVMThrow)
await this.crowdsale.send(1).should.be.rejectedWith(EVMRevert)
})
it('should reject payments that exceed cap', async function () {
await this.crowdsale.send(cap.plus(1)).should.be.rejectedWith(EVMThrow)
await this.crowdsale.send(cap.plus(1)).should.be.rejectedWith(EVMRevert)
})
})
@ -53,7 +68,7 @@ contract('CappedCrowdsale', function ([_, wallet]) {
describe('ending', function () {
beforeEach(async function () {
await advanceToBlock(this.startBlock - 1)
await increaseTimeTo(this.startTime)
})
it('should not be ended if under cap', async function () {

39
test/CappedToken.js Normal file
View File

@ -0,0 +1,39 @@
'use strict';
import expectThrow from './helpers/expectThrow';
import ether from './helpers/ether';
var CappedToken = artifacts.require('../contracts/Tokens/CappedToken.sol');
const BigNumber = web3.BigNumber
contract('Capped', function(accounts) {
const cap = ether(1000);
let token;
beforeEach(async function() {
token = await CappedToken.new(cap);
})
it('should start with the correct cap', async function() {
let _cap = await token.cap();
assert(cap.eq(_cap));
})
it('should mint when amount is less than cap', async function() {
const result = await token.mint(accounts[0], 100);
assert.equal(result.logs[0].event, 'Mint');
})
it('should fail to mint if the ammount exceeds the cap', async function() {
await token.mint(accounts[0], cap.sub(1));
await expectThrow(token.mint(accounts[0], 100));
})
it('should fail to mint after cap is reached', async function() {
await token.mint(accounts[0], cap);
await expectThrow(token.mint(accounts[0], 1));
})
});

View File

@ -1,5 +1,5 @@
'use strict';
const assertJump = require('./helpers/assertJump');
const assertRevert = require('./helpers/assertRevert');
var Claimable = artifacts.require('../contracts/ownership/Claimable.sol');
@ -25,9 +25,10 @@ contract('Claimable', function(accounts) {
it('should prevent to claimOwnership from no pendingOwner', async function() {
try {
await claimable.claimOwnership({from: accounts[2]});
await claimable.claimOwnership({from: accounts[2]});
assert.fail('should have thrown before');
} catch(error) {
assertJump(error);
assertRevert(error);
}
});
@ -36,9 +37,10 @@ contract('Claimable', function(accounts) {
const owner = await claimable.owner.call();
assert.isTrue(owner !== other);
try {
await claimable.transferOwnership(other, {from: other});
await claimable.transferOwnership(other, {from: other});
assert.fail('should have thrown before');
} catch(error) {
assertJump(error);
assertRevert(error);
}
});

View File

@ -1,5 +1,5 @@
'use strict';
const assertJump = require('./helpers/assertJump');
const assertRevert = require('./helpers/assertRevert');
var Contactable = artifacts.require('../contracts/ownership/Contactable.sol');

View File

@ -1,6 +1,8 @@
import ether from './helpers/ether'
import advanceToBlock from './helpers/advanceToBlock'
import EVMThrow from './helpers/EVMThrow'
import {advanceBlock} from './helpers/advanceToBlock'
import {increaseTimeTo, duration} from './helpers/increaseTime'
import latestTime from './helpers/latestTime'
import EVMRevert from './helpers/EVMRevert'
const BigNumber = web3.BigNumber
@ -19,11 +21,18 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) {
const expectedTokenAmount = rate.mul(value)
beforeEach(async function () {
this.startBlock = web3.eth.blockNumber + 10
this.endBlock = web3.eth.blockNumber + 20
before(async function() {
//Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
await advanceBlock()
})
this.crowdsale = await Crowdsale.new(this.startBlock, this.endBlock, rate, wallet)
beforeEach(async function () {
this.startTime = latestTime() + duration.weeks(1);
this.endTime = this.startTime + duration.weeks(1);
this.afterEndTime = this.endTime + duration.seconds(1)
this.crowdsale = await Crowdsale.new(this.startTime, this.endTime, rate, wallet)
this.token = MintableToken.at(await this.crowdsale.token())
})
@ -36,7 +45,7 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) {
it('should be ended only after end', async function () {
let ended = await this.crowdsale.hasEnded()
ended.should.equal(false)
await advanceToBlock(this.endBlock + 1)
await increaseTimeTo(this.afterEndTime)
ended = await this.crowdsale.hasEnded()
ended.should.equal(true)
})
@ -44,20 +53,20 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) {
describe('accepting payments', function () {
it('should reject payments before start', async function () {
await this.crowdsale.send(value).should.be.rejectedWith(EVMThrow)
await this.crowdsale.buyTokens(investor, value, {from: purchaser}).should.be.rejectedWith(EVMThrow)
await this.crowdsale.send(value).should.be.rejectedWith(EVMRevert)
await this.crowdsale.buyTokens(investor, {from: purchaser, value: value}).should.be.rejectedWith(EVMRevert)
})
it('should accept payments after start', async function () {
await advanceToBlock(this.startBlock - 1)
await increaseTimeTo(this.startTime)
await this.crowdsale.send(value).should.be.fulfilled
await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}).should.be.fulfilled
})
it('should reject payments after end', async function () {
await advanceToBlock(this.endBlock)
await this.crowdsale.send(value).should.be.rejectedWith(EVMThrow)
await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}).should.be.rejectedWith(EVMThrow)
await increaseTimeTo(this.afterEndTime)
await this.crowdsale.send(value).should.be.rejectedWith(EVMRevert)
await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}).should.be.rejectedWith(EVMRevert)
})
})
@ -65,7 +74,7 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) {
describe('high-level purchase', function () {
beforeEach(async function() {
await advanceToBlock(this.startBlock)
await increaseTimeTo(this.startTime)
})
it('should log purchase', async function () {
@ -104,7 +113,7 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) {
describe('low-level purchase', function () {
beforeEach(async function() {
await advanceToBlock(this.startBlock)
await increaseTimeTo(this.startTime)
})
it('should log purchase', async function () {

View File

@ -1,23 +1,26 @@
'use strict';
const assertJump = require('./helpers/assertJump');
const timer = require('./helpers/timer');
const assertRevert = require('./helpers/assertRevert');
import latestTime from './helpers/latestTime'
import {increaseTimeTo, duration} from './helpers/increaseTime'
var DayLimitMock = artifacts.require('./helpers/DayLimitMock.sol');
contract('DayLimit', function(accounts) {
const day = 60 * 60 * 24;
let dayLimit;
let initLimit = 10;
beforeEach( async function() {
this.startTime = latestTime();
dayLimit = await DayLimitMock.new(initLimit);
});
it('should construct with the passed daily limit', async function() {
let initLimit = 10;
let dayLimit = await DayLimitMock.new(initLimit);
let dailyLimit = await dayLimit.dailyLimit();
assert.equal(initLimit, dailyLimit);
});
it('should be able to spend if daily limit is not reached', async function() {
let limit = 10;
let dayLimit = await DayLimitMock.new(limit);
await dayLimit.attemptSpend(8);
let spentToday = await dayLimit.spentToday();
assert.equal(spentToday, 8);
@ -28,32 +31,28 @@ contract('DayLimit', function(accounts) {
});
it('should prevent spending if daily limit is reached', async function() {
let limit = 10;
let dayLimit = await DayLimitMock.new(limit);
await dayLimit.attemptSpend(8);
let spentToday = await dayLimit.spentToday();
assert.equal(spentToday, 8);
try {
await dayLimit.attemptSpend(3);
await dayLimit.attemptSpend(3);
assert.fail('should have thrown before');
} catch(error) {
assertJump(error);
assertRevert(error);
}
});
it('should allow spending if daily limit is reached and then set higher', async function() {
let limit = 10;
let dayLimit = await DayLimitMock.new(limit);
await dayLimit.attemptSpend(8);
let spentToday = await dayLimit.spentToday();
assert.equal(spentToday, 8);
try {
await dayLimit.attemptSpend(3);
await dayLimit.attemptSpend(3);
assert.fail('should have thrown before');
} catch(error) {
assertJump(error);
assertRevert(error);
}
spentToday = await dayLimit.spentToday();
assert.equal(spentToday, 8);
@ -65,22 +64,20 @@ contract('DayLimit', function(accounts) {
});
it('should allow spending if daily limit is reached and then amount spent is reset', async function() {
let limit = 10;
let dayLimit = await DayLimitMock.new(limit);
await dayLimit.attemptSpend(8);
let spentToday = await dayLimit.spentToday();
assert.equal(spentToday, 8);
try {
await dayLimit.attemptSpend(3);
await dayLimit.attemptSpend(3);
assert.fail('should have thrown before');
} catch(error) {
assertJump(error);
assertRevert(error);
}
spentToday = await dayLimit.spentToday();
assert.equal(spentToday, 8);
await dayLimit.resetSpentToday(15);
await dayLimit.resetSpentToday();
await dayLimit.attemptSpend(3);
spentToday = await dayLimit.spentToday();
assert.equal(spentToday, 3);
@ -96,13 +93,14 @@ contract('DayLimit', function(accounts) {
try {
await dayLimit.attemptSpend(3);
assert.fail('should have thrown before');
} catch(error) {
assertJump(error);
assertRevert(error);
}
spentToday = await dayLimit.spentToday();
assert.equal(spentToday, 8);
await timer(day);
await increaseTimeTo(this.startTime + duration.days(1));
await dayLimit.attemptSpend(3);
spentToday = await dayLimit.spentToday();

View File

@ -49,7 +49,7 @@ contract('DelayedClaimable', function(accounts) {
} catch (error) {
err = error;
}
assert.isFalse(err.message.search('invalid opcode') === -1);
assert.isFalse(err.message.search('revert') === -1);
let owner = await delayedClaimable.owner();
assert.isTrue(owner !== accounts[1]);
});
@ -62,7 +62,7 @@ contract('DelayedClaimable', function(accounts) {
} catch (error) {
err = error;
}
assert.isFalse(err.message.search('invalid opcode') === -1);
assert.isFalse(err.message.search('revert') === -1);
});
});

35
test/DetailedERC20.js Normal file
View File

@ -0,0 +1,35 @@
const BigNumber = web3.BigNumber;
require('chai')
.use(require('chai-as-promised'))
.use(require('chai-bignumber')(BigNumber))
.should();
const DetailedERC20Mock = artifacts.require('./helpers/DetailedERC20Mock.sol');
contract('DetailedERC20', accounts => {
let detailedERC20 = null;
const _name = "My Detailed ERC20";
const _symbol = "MDT";
const _decimals = 18;
beforeEach(async function() {
detailedERC20 = await DetailedERC20Mock.new(_name, _symbol, _decimals);
});
it('has a name', async function () {
const name = await detailedERC20.name();
name.should.be.equal(_name);
});
it('has a symbol', async function () {
const symbol = await detailedERC20.symbol();
symbol.should.be.equal(_symbol);
});
it('has an amount of decimals', async function () {
const decimals = await detailedERC20.decimals();
decimals.should.be.bignumber.equal(_decimals)
});
});

55
test/ECRecovery.js Normal file
View File

@ -0,0 +1,55 @@
var ECRecovery = artifacts.require("../contracts/ECRecovery.sol");
var utils = require('ethereumjs-util');
var hashMessage = require('./helpers/hashMessage.js');
contract('ECRecovery', function(accounts) {
let ecrecovery;
before(async function() {
ecrecovery = await ECRecovery.new();
});
it("recover v0", async function() {
// Signature generated outside testrpc with method web3.eth.sign(signer, message)
let signer = '0x2cc1166f6212628a0deef2b33befb2187d35b86c';
let message = '0x7dbaf558b0a1a5dc7a67202117ab143c1d8605a983e4a743bc06fcc03162dc0d'; // web3.sha3('OpenZeppelin')
let signature = '0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be89200';
assert.equal(signer, await ecrecovery.recover(message, signature));
});
it("recover v1", async function() {
// Signature generated outside testrpc with method web3.eth.sign(signer, message)
let signer = '0x1e318623ab09fe6de3c9b8672098464aeda9100e';
let message = '0x7dbaf558b0a1a5dc7a67202117ab143c1d8605a983e4a743bc06fcc03162dc0d'; // web3.sha3('OpenZeppelin')
let signature = '0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e001';
assert.equal(signer, await ecrecovery.recover(message, signature));
});
it("recover using web3.eth.sign()", async function() {
// Create the signature using account[0]
const signature = web3.eth.sign(web3.eth.accounts[0], web3.sha3('OpenZeppelin'));
// Recover the signer address form the generated message and signature.
assert.equal(web3.eth.accounts[0], await ecrecovery.recover(hashMessage('OpenZeppelin'), signature));
});
it("recover using web3.eth.sign() should return wrong signer", async function() {
// Create the signature using account[0]
const signature = web3.eth.sign(web3.eth.accounts[0], web3.sha3('OpenZeppelin'));
// Recover the signer address form the generated message and wrong signature.
assert.notEqual(web3.eth.accounts[0], await ecrecovery.recover(hashMessage('Test'), signature));
});
it("recover should fail when a wrong hash is sent", async function() {
// Create the signature using account[0]
let signature = web3.eth.sign(web3.eth.accounts[0], web3.sha3('OpenZeppelin'));
// Recover the signer address form the generated message and wrong signature.
assert.equal('0x0000000000000000000000000000000000000000',
await ecrecovery.recover(hashMessage('OpenZeppelin').substring(2), signature)
);
});
});

View File

@ -1,5 +1,7 @@
import advanceToBlock from './helpers/advanceToBlock'
import EVMThrow from './helpers/EVMThrow'
import {advanceBlock} from './helpers/advanceToBlock'
import {increaseTimeTo, duration} from './helpers/increaseTime'
import latestTime from './helpers/latestTime'
import EVMRevert from './helpers/EVMRevert'
const BigNumber = web3.BigNumber
@ -15,47 +17,47 @@ contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) {
const rate = new BigNumber(1000)
beforeEach(async function () {
this.startBlock = web3.eth.blockNumber + 10
this.endBlock = web3.eth.blockNumber + 20
before(async function() {
//Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
await advanceBlock()
})
this.crowdsale = await FinalizableCrowdsale.new(this.startBlock, this.endBlock, rate, wallet, {from: owner})
beforeEach(async function () {
this.startTime = latestTime() + duration.weeks(1)
this.endTime = this.startTime + duration.weeks(1)
this.afterEndTime = this.endTime + duration.seconds(1)
this.crowdsale = await FinalizableCrowdsale.new(this.startTime, this.endTime, rate, wallet, {from: owner})
this.token = MintableToken.at(await this.crowdsale.token())
})
it('cannot be finalized before ending', async function () {
await this.crowdsale.finalize({from: owner}).should.be.rejectedWith(EVMThrow)
await this.crowdsale.finalize({from: owner}).should.be.rejectedWith(EVMRevert)
})
it('cannot be finalized by third party after ending', async function () {
await advanceToBlock(this.endBlock)
await this.crowdsale.finalize({from: thirdparty}).should.be.rejectedWith(EVMThrow)
await increaseTimeTo(this.afterEndTime)
await this.crowdsale.finalize({from: thirdparty}).should.be.rejectedWith(EVMRevert)
})
it('can be finalized by owner after ending', async function () {
await advanceToBlock(this.endBlock)
await increaseTimeTo(this.afterEndTime)
await this.crowdsale.finalize({from: owner}).should.be.fulfilled
})
it('cannot be finalized twice', async function () {
await advanceToBlock(this.endBlock + 1)
await increaseTimeTo(this.afterEndTime)
await this.crowdsale.finalize({from: owner})
await this.crowdsale.finalize({from: owner}).should.be.rejectedWith(EVMThrow)
await this.crowdsale.finalize({from: owner}).should.be.rejectedWith(EVMRevert)
})
it('logs finalized', async function () {
await advanceToBlock(this.endBlock)
await increaseTimeTo(this.afterEndTime)
const {logs} = await this.crowdsale.finalize({from: owner})
const event = logs.find(e => e.event === 'Finalized')
should.exist(event)
})
it('finishes minting of token', async function () {
await advanceToBlock(this.endBlock)
await this.crowdsale.finalize({from: owner})
const finished = await this.token.mintingFinished()
finished.should.equal(true)
})
})

View File

@ -1,7 +1,7 @@
'use strict';
var LimitBalanceMock = artifacts.require('helpers/LimitBalanceMock.sol');
const assertJump = require('./helpers/assertJump');
const assertRevert = require('./helpers/assertRevert');
contract('LimitBalance', function(accounts) {
let lb;
@ -27,11 +27,11 @@ contract('LimitBalance', function(accounts) {
it('shouldnt allow sending above limit', async function() {
let amount = 1110;
try {
await lb.limitedDeposit({value: amount});
await lb.limitedDeposit({value: amount});
assert.fail('should have thrown before');
} catch(error) {
return assertJump(error);
assertRevert(error);
}
assert.fail('should have thrown before');
});
it('should allow multiple sends below limit', async function() {
@ -52,10 +52,10 @@ contract('LimitBalance', function(accounts) {
try {
await lb.limitedDeposit({value: amount+1});
assert.fail('should have thrown before');
} catch(error) {
return assertJump(error);
assertRevert(error);
}
assert.fail('should have thrown before');
});
});

60
test/MerkleProof.js Normal file
View File

@ -0,0 +1,60 @@
var MerkleProof = artifacts.require("./MerkleProof.sol");
import MerkleTree from "./helpers/merkleTree.js";
import { sha3, bufferToHex } from "ethereumjs-util";
contract('MerkleProof', function(accounts) {
let merkleProof;
before(async function() {
merkleProof = await MerkleProof.new();
});
describe("verifyProof", function() {
it("should return true for a valid Merkle proof", async function() {
const elements = ["a", "b", "c", "d"];
const merkleTree = new MerkleTree(elements);
const root = merkleTree.getHexRoot();
const proof = merkleTree.getHexProof(elements[0]);
const leaf = bufferToHex(sha3(elements[0]));
const result = await merkleProof.verifyProof(proof, root, leaf);
assert.isOk(result, "verifyProof did not return true for a valid proof");
});
it("should return false for an invalid Merkle proof", async function() {
const correctElements = ["a", "b", "c"]
const correctMerkleTree = new MerkleTree(correctElements);
const correctRoot = correctMerkleTree.getHexRoot();
const correctLeaf = bufferToHex(sha3(correctElements[0]));
const badElements = ["d", "e", "f"]
const badMerkleTree = new MerkleTree(badElements)
const badProof = badMerkleTree.getHexProof(badElements[0])
const result = await merkleProof.verifyProof(badProof, correctRoot, correctLeaf);
assert.isNotOk(result, "verifyProof did not return false for an invalid proof");
});
it("should return false for a Merkle proof of invalid length", async function() {
const elements = ["a", "b", "c"]
const merkleTree = new MerkleTree(elements);
const root = merkleTree.getHexRoot();
const proof = merkleTree.getHexProof(elements[0]);
const badProof = proof.slice(0, proof.length - 5);
const leaf = bufferToHex(sha3(elements[0]));
const result = await merkleProof.verifyProof(badProof, root, leaf);
assert.isNotOk(result, "verifyProof did not return false for proof of invalid length");
})
});
});

View File

@ -1,6 +1,6 @@
'use strict';
const assertJump = require('./helpers/assertJump');
import expectThrow from './helpers/expectThrow';
var MintableToken = artifacts.require('../contracts/Tokens/MintableToken.sol');
contract('Mintable', function(accounts) {
@ -23,13 +23,24 @@ contract('Mintable', function(accounts) {
});
it('should mint a given amount of tokens to a given address', async function() {
await token.mint(accounts[0], 100);
const result = await token.mint(accounts[0], 100);
assert.equal(result.logs[0].event, 'Mint');
assert.equal(result.logs[0].args.to.valueOf(), accounts[0]);
assert.equal(result.logs[0].args.amount.valueOf(), 100);
assert.equal(result.logs[1].event, 'Transfer');
assert.equal(result.logs[1].args.from.valueOf(), 0x0);
let balance0 = await token.balanceOf(accounts[0]);
assert(balance0, 100);
let totalSupply = await token.totalSupply();
assert(totalSupply, 100);
})
it('should fail to mint after call to finishMinting', async function () {
await token.finishMinting();
assert.equal(await token.mintingFinished(), true);
await expectThrow(token.mint(accounts[0], 100));
})
});

View File

@ -1,119 +0,0 @@
'use strict';
var MultisigWalletMock = artifacts.require('./helpers/MultisigWalletMock.sol');
require('./helpers/transactionMined.js');
contract('MultisigWallet', function(accounts) {
let shouldntFail = function(err) {
assert.isFalse(!!err);
};
it('should send balance to passed address upon death', async function() {
//Give account[0] 20 ether
web3.eth.sendTransaction({from: web3.eth.coinbase, to: accounts[0], value: web3.toWei('20','ether')}, shouldntFail);
let dailyLimit = 10;
let ownersRequired = 2;
//Create MultisigWallet contract with 10 ether
let wallet = await MultisigWalletMock.new(accounts, ownersRequired, dailyLimit, {value: web3.toWei('10', 'ether')});
//Get balances of owner and wallet after wallet creation.
let ownerBalance = web3.eth.getBalance(accounts[0]);
let walletBalance = web3.eth.getBalance(wallet.address);
let hash = 1234;
//Call destroy function from two different owner accounts, satisfying owners required
await wallet.destroy(accounts[0], {data: hash});
let txnHash = await wallet.destroy(accounts[0], {from: accounts[1], data: hash});
//Get balances of owner and wallet after destroy function is complete, compare with previous values
let newOwnerBalance = web3.eth.getBalance(accounts[0]);
let newWalletBalance = web3.eth.getBalance(wallet.address);
assert.isTrue(newOwnerBalance > ownerBalance);
assert.isTrue(newWalletBalance < walletBalance);
});
it('should execute transaction if below daily limit', async function() {
//Give account[0] 20 ether
web3.eth.sendTransaction({from: web3.eth.coinbase, to: accounts[0], value: web3.toWei('20','ether')}, shouldntFail);
let dailyLimit = 10;
let ownersRequired = 2;
//Create MultisigWallet contract with 10 ether
let wallet = await MultisigWalletMock.new(accounts, ownersRequired, dailyLimit, {value: web3.toWei('10', 'ether')});
let accountBalance = web3.eth.getBalance(accounts[2]);
let hash = 1234;
//Owner account0 commands wallet to send 9 wei to account2
let txnHash = await wallet.execute(accounts[2], 9, hash);
//Balance of account2 should have increased
let newAccountBalance = web3.eth.getBalance(accounts[2]);
assert.isTrue(newAccountBalance.greaterThan(accountBalance));
});
it('should prevent execution of transaction if above daily limit', async function() {
//Give account[0] 20 ether
web3.eth.sendTransaction({from: web3.eth.coinbase, to: accounts[0], value: web3.toWei('20','ether')}, shouldntFail);
let dailyLimit = 10;
let ownersRequired = 2;
//Create MultisigWallet contract with 10 ether
let wallet = await MultisigWalletMock.new(accounts, ownersRequired, dailyLimit, {value: web3.toWei('10', 'ether')});
let accountBalance = web3.eth.getBalance(accounts[2]);
let hash = 1234;
//Owner account0 commands wallet to send 9 wei to account2
let txnHash = await wallet.execute(accounts[2], 9, hash);
//Balance of account2 should have increased
let newAccountBalance = web3.eth.getBalance(accounts[2]);
assert.isTrue(newAccountBalance > accountBalance);
accountBalance = newAccountBalance;
hash = 4567;
//Owner account0 commands wallet to send 2 more wei to account2, going over the daily limit of 10
txnHash = await wallet.execute(accounts[2], 2, hash);
//Balance of account2 should not change
newAccountBalance = web3.eth.getBalance(accounts[2]);
assert.equal(newAccountBalance.toString(), accountBalance.toString());
});
it('should execute transaction if above daily limit and enough owners approve', async function() {
//Give account[0] 20 ether
web3.eth.sendTransaction({from: web3.eth.coinbase, to: accounts[0], value: web3.toWei('20','ether')}, shouldntFail);
let dailyLimit = 10;
let ownersRequired = 2;
//Create MultisigWallet contract with 10 ether
let wallet = await MultisigWalletMock.new(accounts, ownersRequired, dailyLimit, {value: web3.toWei('10', 'ether')});
let accountBalance = web3.eth.getBalance(accounts[2]);
let hash = 1234;
//Owner account0 commands wallet to send 11 wei to account2
let txnHash = await wallet.execute(accounts[2], 11, hash);
//Balance of account2 should not change
let newAccountBalance = web3.eth.getBalance(accounts[2]);
assert.equal(newAccountBalance.toString(), accountBalance.toString());
accountBalance = newAccountBalance;
//Owner account1 commands wallet to send 11 wei to account2
txnHash = await wallet.execute(accounts[2], 2, hash);
//Balance of account2 should change
newAccountBalance = web3.eth.getBalance(accounts[2]);
assert.isTrue(newAccountBalance > accountBalance);
});
});

View File

@ -1,5 +1,5 @@
'use strict';
const assertJump = require('./helpers/assertJump');
const assertRevert = require('./helpers/assertRevert');
var Ownable = artifacts.require('../contracts/ownership/Ownable.sol');
@ -29,17 +29,20 @@ contract('Ownable', function(accounts) {
assert.isTrue(owner !== other);
try {
await ownable.transferOwnership(other, {from: other});
assert.fail('should have thrown before');
} catch(error) {
assertJump(error);
assertRevert(error);
}
});
it('should guard ownership against stuck state', async function() {
let originalOwner = await ownable.owner();
await ownable.transferOwnership(null, {from: originalOwner});
let newOwner = await ownable.owner();
assert.equal(originalOwner, newOwner);
try {
await ownable.transferOwnership(null, {from: originalOwner});
assert.fail();
} catch(error) {
assertRevert(error);
}
});
});

View File

@ -1,6 +1,6 @@
'use strict';
const assertJump = require('./helpers/assertJump');
const assertRevert = require('./helpers/assertRevert');
const PausableMock = artifacts.require('helpers/PausableMock.sol');
contract('Pausable', function(accounts) {
@ -23,8 +23,9 @@ contract('Pausable', function(accounts) {
try {
await Pausable.normalProcess();
assert.fail('should have thrown before');
} catch(error) {
assertJump(error);
assertRevert(error);
}
let count1 = await Pausable.count();
assert.equal(count1, 0);
@ -35,10 +36,10 @@ contract('Pausable', function(accounts) {
let Pausable = await PausableMock.new();
try {
await Pausable.drasticMeasure();
assert.fail('should have thrown before');
} catch(error) {
assertJump(error);
assertRevert(error);
}
const drasticMeasureTaken = await Pausable.drasticMeasureTaken();
assert.isFalse(drasticMeasureTaken);
});
@ -62,4 +63,19 @@ contract('Pausable', function(accounts) {
assert.equal(count0, 1);
});
it('should prevent drastic measure after pause is over', async function() {
let Pausable = await PausableMock.new();
await Pausable.pause();
await Pausable.unpause();
try {
await Pausable.drasticMeasure();
assert.fail('should have thrown before');
} catch(error) {
assertRevert(error);
}
const drasticMeasureTaken = await Pausable.drasticMeasureTaken();
assert.isFalse(drasticMeasureTaken);
});
});

Some files were not shown because too many files have changed in this diff Show More