Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4073cf6585 | |||
| 4ce0e211c5 | |||
| 9af6ad5ddf | |||
| 2f336f7aaf | |||
| 5751eac444 | |||
| cda518d353 | |||
| f446f5c5cd | |||
| 1455a5a942 | |||
| 207b92f63c | |||
| b217ef6314 | |||
| 687dc19a4a | |||
| 161f25fc12 | |||
| 4bb26c32b6 | |||
| d91f4d4bc1 | |||
| ddcae6254e | |||
| 8375b6085f | |||
| 83b941c76c | |||
| 63c8751e06 | |||
| 306132f823 | |||
| 677d05743c | |||
| aef0f63aee | |||
| 5e55569db6 | |||
| 9bb2c958ec | |||
| e931c1cbfc | |||
| dd1fd0002a | |||
| ac3808885a | |||
| 258c001f7f | |||
| d07bdccc0c | |||
| 227a335399 | |||
| 58abd66969 | |||
| 8662846838 | |||
| 6ea0577bfe | |||
| b9b26e1d8a | |||
| 887c1bb925 | |||
| cc5e898250 | |||
| 1cef36b5c0 | |||
| c95be493c3 | |||
| bddc8755c1 | |||
| 3ad555bb01 | |||
| 846b0714ad | |||
| f79f7b00e3 | |||
| 47585b1117 |
5
.env.example
Normal file
5
.env.example
Normal file
@ -0,0 +1,5 @@
|
||||
# configure your infura api key (not technically required)
|
||||
INFURA_API_KEY=
|
||||
|
||||
# change the mnemonic that your hd wallet is seeded with
|
||||
MNEMONIC=
|
||||
51
.eslintrc
Normal file
51
.eslintrc
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"extends" : [
|
||||
"standard",
|
||||
"plugin:promise/recommended"
|
||||
],
|
||||
"plugins": [
|
||||
"promise"
|
||||
],
|
||||
"env": {
|
||||
"browser" : true,
|
||||
"node" : true,
|
||||
"mocha" : true,
|
||||
"jest" : true
|
||||
},
|
||||
"globals" : {
|
||||
"artifacts": false,
|
||||
"contract": false,
|
||||
"assert": false,
|
||||
"web3": false
|
||||
},
|
||||
"rules": {
|
||||
|
||||
// Strict mode
|
||||
"strict": [2, "global"],
|
||||
|
||||
// Code style
|
||||
"indent": [2, 2],
|
||||
"quotes": [2, "single"],
|
||||
"semi": ["error", "always"],
|
||||
"space-before-function-paren": ["error", "always"],
|
||||
"no-use-before-define": 0,
|
||||
"eqeqeq": [2, "smart"],
|
||||
"dot-notation": [2, {"allowKeywords": true, "allowPattern": ""}],
|
||||
"no-redeclare": [2, {"builtinGlobals": true}],
|
||||
"no-trailing-spaces": [2, { "skipBlankLines": true }],
|
||||
"eol-last": 1,
|
||||
"comma-spacing": [2, {"before": false, "after": true}],
|
||||
"camelcase": [2, {"properties": "always"}],
|
||||
"no-mixed-spaces-and-tabs": [2, "smart-tabs"],
|
||||
"comma-dangle": [1, "always-multiline"],
|
||||
"no-dupe-args": 2,
|
||||
"no-dupe-keys": 2,
|
||||
"no-debugger": 0,
|
||||
"no-undef": 2,
|
||||
"object-curly-spacing": [2, "always"],
|
||||
"max-len": [2, 120, 2],
|
||||
"generator-star-spacing": ["error", "before"],
|
||||
"promise/avoid-new": 0,
|
||||
"promise/always-return": 0
|
||||
}
|
||||
}
|
||||
37
.gitignore
vendored
37
.gitignore
vendored
@ -1,9 +1,36 @@
|
||||
*.swp
|
||||
*.swo
|
||||
node_modules/
|
||||
build/
|
||||
.DS_Store/
|
||||
/coverage
|
||||
coverage.json
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
allFiredEvents
|
||||
scTopics
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
coverage.json
|
||||
coverageEnv
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Dependency directory
|
||||
node_modules
|
||||
|
||||
# Debug log from npm
|
||||
npm-debug.log
|
||||
|
||||
# local env variables
|
||||
.env
|
||||
|
||||
# truffle build directory
|
||||
build/
|
||||
|
||||
# lol macs
|
||||
.DS_Store/
|
||||
|
||||
1
.node-version
Normal file
1
.node-version
Normal file
@ -0,0 +1 @@
|
||||
v8.9.1
|
||||
@ -1,5 +1,9 @@
|
||||
module.exports = {
|
||||
norpc: true,
|
||||
testCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle test --network coverage',
|
||||
skipFiles: ['lifecycle/Migrations.sol']
|
||||
compileCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle compile --network coverage',
|
||||
skipFiles: [
|
||||
'lifecycle/Migrations.sol',
|
||||
'mocks'
|
||||
]
|
||||
}
|
||||
|
||||
16
.travis.yml
16
.travis.yml
@ -3,14 +3,22 @@ sudo: required
|
||||
group: beta
|
||||
language: node_js
|
||||
node_js:
|
||||
- "6"
|
||||
- "8"
|
||||
cache:
|
||||
yarn: true
|
||||
directories:
|
||||
- node_modules
|
||||
env:
|
||||
-
|
||||
- SOLIDITY_COVERAGE=true
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- env: SOLIDITY_COVERAGE=true
|
||||
before_script:
|
||||
- truffle version
|
||||
- yarn list
|
||||
script:
|
||||
- yarn test
|
||||
- npm run lint
|
||||
- npm run test
|
||||
notifications:
|
||||
slack:
|
||||
rooms:
|
||||
|
||||
@ -38,7 +38,7 @@ The design guidelines have quite a high abstraction level. These style guideline
|
||||
|
||||
#### G0 - Default to Solidity's official style guide.
|
||||
|
||||
Follow the official Solidity style guide: http://solidity.readthedocs.io/en/latest/style-guide.html
|
||||
Follow the official Solidity style guide: https://solidity.readthedocs.io/en/latest/style-guide.html
|
||||
|
||||
#### G1 - No Magic Constants
|
||||
|
||||
|
||||
13
README.md
13
README.md
@ -7,7 +7,7 @@ OpenZeppelin is a library for writing secure [Smart Contracts](https://en.wikipe
|
||||
|
||||
With OpenZeppelin, you can build distributed applications, protocols and organizations:
|
||||
- using common contract security patterns (See [Onward with Ethereum Smart Contract Security](https://medium.com/bitcorps-blog/onward-with-ethereum-smart-contract-security-97a827e47702#.y3kvdetbz))
|
||||
- in the [Solidity language](http://solidity.readthedocs.io/en/develop/).
|
||||
- in the [Solidity language](https://solidity.readthedocs.io/en/develop/).
|
||||
|
||||
> NOTE: New to smart contract development? Check our [introductory guide](https://medium.com/zeppelin-blog/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05#.cox40d2ut).
|
||||
|
||||
@ -25,9 +25,6 @@ To install the OpenZeppelin library, run:
|
||||
```sh
|
||||
npm init
|
||||
npm install zeppelin-solidity
|
||||
|
||||
# If you are using yarn, add dependency like this -
|
||||
yarn add zeppelin-solidity
|
||||
```
|
||||
|
||||
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:
|
||||
@ -50,7 +47,7 @@ If you find a security issue, please email [security@openzeppelin.org](mailto:se
|
||||
|
||||
Building a distributed application, protocol or organization with OpenZeppelin?
|
||||
|
||||
- Read documentation: http://zeppelin-solidity.readthedocs.io/en/latest/
|
||||
- Read documentation: https://zeppelin-solidity.readthedocs.io/en/latest/
|
||||
|
||||
- Ask for help and follow progress at: https://slack.openzeppelin.org/
|
||||
|
||||
@ -64,12 +61,12 @@ Interested in contributing to OpenZeppelin?
|
||||
- [Golem](https://golem.network/)
|
||||
- [Mediachain](http://www.mediachain.io/)
|
||||
- [Truffle](http://truffleframework.com/)
|
||||
- [Firstblood](http://firstblood.io/)
|
||||
- [Rootstock](http://www.rsk.co/)
|
||||
- [Firstblood](https://firstblood.io/)
|
||||
- [Rootstock](https://www.rsk.co/)
|
||||
- [Consensys](https://consensys.net/)
|
||||
- [DigixGlobal](https://www.dgx.io/)
|
||||
- [Coinfund](https://coinfund.io/)
|
||||
- [DemocracyEarth](http://democracy.earth/)
|
||||
- [DemocracyEarth](https://democracy.earth/)
|
||||
- [Signatura](https://signatura.co/)
|
||||
- [Ether.camp](http://www.ether.camp/)
|
||||
- [Aragon](https://aragon.one/)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
/**
|
||||
* @title Helps contracts guard agains rentrancy attacks.
|
||||
* @title Helps contracts guard agains reentrancy attacks.
|
||||
* @author Remco Bloemen <remco@2π.com>
|
||||
* @notice If you mark a function `nonReentrant`, you should also
|
||||
* mark it `external`.
|
||||
@ -11,7 +11,7 @@ contract ReentrancyGuard {
|
||||
/**
|
||||
* @dev We use a single lock for the whole contract.
|
||||
*/
|
||||
bool private rentrancy_lock = false;
|
||||
bool private reentrancy_lock = false;
|
||||
|
||||
/**
|
||||
* @dev Prevents a contract from calling itself, directly or indirectly.
|
||||
@ -22,10 +22,10 @@ contract ReentrancyGuard {
|
||||
* wrapper marked as `nonReentrant`.
|
||||
*/
|
||||
modifier nonReentrant() {
|
||||
require(!rentrancy_lock);
|
||||
rentrancy_lock = true;
|
||||
require(!reentrancy_lock);
|
||||
reentrancy_lock = true;
|
||||
_;
|
||||
rentrancy_lock = false;
|
||||
reentrancy_lock = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
|
||||
import '../../contracts/token/BasicToken.sol';
|
||||
import '../token/BasicToken.sol';
|
||||
|
||||
|
||||
// mock class using BasicToken
|
||||
@ -1,6 +1,6 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import '../../contracts/token/BurnableToken.sol';
|
||||
import '../token/BurnableToken.sol';
|
||||
|
||||
contract BurnableTokenMock is BurnableToken {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
|
||||
import '../../contracts/crowdsale/CappedCrowdsale.sol';
|
||||
import '../crowdsale/CappedCrowdsale.sol';
|
||||
|
||||
|
||||
contract CappedCrowdsaleImpl is CappedCrowdsale {
|
||||
@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import '../../contracts/token/StandardToken.sol';
|
||||
import '../../contracts/token/DetailedERC20.sol';
|
||||
import '../token/StandardToken.sol';
|
||||
import '../token/DetailedERC20.sol';
|
||||
|
||||
contract DetailedERC20Mock is StandardToken, DetailedERC20 {
|
||||
function DetailedERC20Mock(string _name, string _symbol, uint8 _decimals) DetailedERC20(_name, _symbol, _decimals) public {}
|
||||
@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
|
||||
import '../../contracts/token/BasicToken.sol';
|
||||
import '../token/BasicToken.sol';
|
||||
|
||||
|
||||
contract ERC23ContractInterface {
|
||||
@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
|
||||
import '../../contracts/crowdsale/FinalizableCrowdsale.sol';
|
||||
import '../crowdsale/FinalizableCrowdsale.sol';
|
||||
|
||||
|
||||
contract FinalizableCrowdsaleImpl is FinalizableCrowdsale {
|
||||
@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
|
||||
import '../../contracts/LimitBalance.sol';
|
||||
import '../LimitBalance.sol';
|
||||
|
||||
|
||||
// mock class using LimitBalance
|
||||
@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
|
||||
import '../../contracts/lifecycle/Pausable.sol';
|
||||
import '../lifecycle/Pausable.sol';
|
||||
|
||||
|
||||
// mock class using Pausable
|
||||
@ -1,6 +1,6 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import '../../contracts/token/PausableToken.sol';
|
||||
import '../token/PausableToken.sol';
|
||||
|
||||
// mock class using PausableToken
|
||||
contract PausableTokenMock is PausableToken {
|
||||
@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
|
||||
import '../../contracts/payment/PullPayment.sol';
|
||||
import '../payment/PullPayment.sol';
|
||||
|
||||
|
||||
// mock class using PullPayment
|
||||
69
contracts/mocks/RBACMock.sol
Normal file
69
contracts/mocks/RBACMock.sol
Normal file
@ -0,0 +1,69 @@
|
||||
pragma solidity ^0.4.8;
|
||||
|
||||
import '../ownership/rbac/RBAC.sol';
|
||||
|
||||
|
||||
contract RBACMock is RBAC {
|
||||
|
||||
string constant ROLE_ADVISOR = "advisor";
|
||||
|
||||
modifier onlyAdminOrAdvisor()
|
||||
{
|
||||
require(
|
||||
hasRole(msg.sender, ROLE_ADMIN) ||
|
||||
hasRole(msg.sender, ROLE_ADVISOR)
|
||||
);
|
||||
_;
|
||||
}
|
||||
|
||||
function RBACMock(address[] _advisors)
|
||||
public
|
||||
{
|
||||
addRole(msg.sender, ROLE_ADVISOR);
|
||||
|
||||
for (uint256 i = 0; i < _advisors.length; i++) {
|
||||
addRole(_advisors[i], ROLE_ADVISOR);
|
||||
}
|
||||
}
|
||||
|
||||
function onlyAdminsCanDoThis()
|
||||
onlyAdmin
|
||||
view
|
||||
external
|
||||
{
|
||||
}
|
||||
|
||||
function onlyAdvisorsCanDoThis()
|
||||
onlyRole(ROLE_ADVISOR)
|
||||
view
|
||||
external
|
||||
{
|
||||
}
|
||||
|
||||
function eitherAdminOrAdvisorCanDoThis()
|
||||
onlyAdminOrAdvisor
|
||||
view
|
||||
external
|
||||
{
|
||||
}
|
||||
|
||||
function nobodyCanDoThis()
|
||||
onlyRole("unknown")
|
||||
view
|
||||
external
|
||||
{
|
||||
}
|
||||
|
||||
// admins can remove advisor's role
|
||||
function removeAdvisor(address _addr)
|
||||
onlyAdmin
|
||||
public
|
||||
{
|
||||
// revert if the user isn't an advisor
|
||||
// (perhaps you want to soft-fail here instead?)
|
||||
checkRole(_addr, ROLE_ADVISOR);
|
||||
|
||||
// remove the advisor's role
|
||||
removeRole(_addr, ROLE_ADVISOR);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import '../../contracts/ReentrancyGuard.sol';
|
||||
import '../ReentrancyGuard.sol';
|
||||
import './ReentrancyAttack.sol';
|
||||
|
||||
contract ReentrancyMock is ReentrancyGuard {
|
||||
@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
|
||||
import '../../contracts/crowdsale/RefundableCrowdsale.sol';
|
||||
import '../crowdsale/RefundableCrowdsale.sol';
|
||||
|
||||
|
||||
contract RefundableCrowdsaleImpl is RefundableCrowdsale {
|
||||
@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import '../../contracts/token/ERC20.sol';
|
||||
import '../../contracts/token/SafeERC20.sol';
|
||||
import '../token/ERC20.sol';
|
||||
import '../token/SafeERC20.sol';
|
||||
|
||||
contract ERC20FailingMock is ERC20 {
|
||||
function transfer(address, uint256) public returns (bool) {
|
||||
@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
|
||||
import '../../contracts/math/SafeMath.sol';
|
||||
import '../math/SafeMath.sol';
|
||||
|
||||
|
||||
contract SafeMathMock {
|
||||
@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
|
||||
import '../../contracts/token/StandardToken.sol';
|
||||
import '../token/StandardToken.sol';
|
||||
|
||||
|
||||
// mock class using StandardToken
|
||||
157
contracts/ownership/rbac/RBAC.sol
Normal file
157
contracts/ownership/rbac/RBAC.sol
Normal file
@ -0,0 +1,157 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import './Roles.sol';
|
||||
|
||||
|
||||
/**
|
||||
* @title RBAC (Role-Based Access Control)
|
||||
* @author Matt Condon (@Shrugs)
|
||||
* @dev Stores and provides setters and getters for roles and addresses.
|
||||
* Supports unlimited numbers of roles and addresses.
|
||||
* See //contracts/examples/RBACExample.sol for an example of usage.
|
||||
* This RBAC method uses strings to key roles. It may be beneficial
|
||||
* for you to write your own implementation of this interface using Enums or similar.
|
||||
* It's also recommended that you define constants in the contract, like ROLE_ADMIN below,
|
||||
* to avoid typos.
|
||||
*/
|
||||
contract RBAC {
|
||||
using Roles for Roles.Role;
|
||||
|
||||
mapping (string => Roles.Role) private roles;
|
||||
|
||||
event RoleAdded(address addr, string roleName);
|
||||
event RoleRemoved(address addr, string roleName);
|
||||
|
||||
/**
|
||||
* A constant role name for indicating admins.
|
||||
*/
|
||||
string public constant ROLE_ADMIN = "admin";
|
||||
|
||||
/**
|
||||
* @dev constructor. Sets msg.sender as admin by default
|
||||
*/
|
||||
function RBAC()
|
||||
public
|
||||
{
|
||||
addRole(msg.sender, ROLE_ADMIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev add a role to an address
|
||||
* @param addr address
|
||||
* @param roleName the name of the role
|
||||
*/
|
||||
function addRole(address addr, string roleName)
|
||||
internal
|
||||
{
|
||||
roles[roleName].add(addr);
|
||||
RoleAdded(addr, roleName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev remove a role from an address
|
||||
* @param addr address
|
||||
* @param roleName the name of the role
|
||||
*/
|
||||
function removeRole(address addr, string roleName)
|
||||
internal
|
||||
{
|
||||
roles[roleName].remove(addr);
|
||||
RoleRemoved(addr, roleName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev reverts if addr does not have role
|
||||
* @param addr address
|
||||
* @param roleName the name of the role
|
||||
* // reverts
|
||||
*/
|
||||
function checkRole(address addr, string roleName)
|
||||
view
|
||||
public
|
||||
{
|
||||
roles[roleName].check(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev determine if addr has role
|
||||
* @param addr address
|
||||
* @param roleName the name of the role
|
||||
* @return bool
|
||||
*/
|
||||
function hasRole(address addr, string roleName)
|
||||
view
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
return roles[roleName].has(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev add a role to an address
|
||||
* @param addr address
|
||||
* @param roleName the name of the role
|
||||
*/
|
||||
function adminAddRole(address addr, string roleName)
|
||||
onlyAdmin
|
||||
public
|
||||
{
|
||||
addRole(addr, roleName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev remove a role from an address
|
||||
* @param addr address
|
||||
* @param roleName the name of the role
|
||||
*/
|
||||
function adminRemoveRole(address addr, string roleName)
|
||||
onlyAdmin
|
||||
public
|
||||
{
|
||||
removeRole(addr, roleName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dev modifier to scope access to a single role (uses msg.sender as addr)
|
||||
* @param roleName the name of the role
|
||||
* // reverts
|
||||
*/
|
||||
modifier onlyRole(string roleName)
|
||||
{
|
||||
checkRole(msg.sender, roleName);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev modifier to scope access to admins
|
||||
* // reverts
|
||||
*/
|
||||
modifier onlyAdmin()
|
||||
{
|
||||
checkRole(msg.sender, ROLE_ADMIN);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev modifier to scope access to a set of roles (uses msg.sender as addr)
|
||||
* @param roleNames the names of the roles to scope access to
|
||||
* // reverts
|
||||
*
|
||||
* @TODO - when solidity supports dynamic arrays as arguments to modifiers, provide this
|
||||
* see: https://github.com/ethereum/solidity/issues/2467
|
||||
*/
|
||||
// modifier onlyRoles(string[] roleNames) {
|
||||
// bool hasAnyRole = false;
|
||||
// for (uint8 i = 0; i < roleNames.length; i++) {
|
||||
// if (hasRole(msg.sender, roleNames[i])) {
|
||||
// hasAnyRole = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// require(hasAnyRole);
|
||||
|
||||
// _;
|
||||
// }
|
||||
}
|
||||
55
contracts/ownership/rbac/Roles.sol
Normal file
55
contracts/ownership/rbac/Roles.sol
Normal file
@ -0,0 +1,55 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
|
||||
/**
|
||||
* @title Roles
|
||||
* @author Francisco Giordano (@frangio)
|
||||
* @dev Library for managing addresses assigned to a Role.
|
||||
* See RBAC.sol for example usage.
|
||||
*/
|
||||
library Roles {
|
||||
struct Role {
|
||||
mapping (address => bool) bearer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev give an address access to this role
|
||||
*/
|
||||
function add(Role storage role, address addr)
|
||||
internal
|
||||
{
|
||||
role.bearer[addr] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev remove an address' access to this role
|
||||
*/
|
||||
function remove(Role storage role, address addr)
|
||||
internal
|
||||
{
|
||||
role.bearer[addr] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev check if an address has this role
|
||||
* // reverts
|
||||
*/
|
||||
function check(Role storage role, address addr)
|
||||
view
|
||||
internal
|
||||
{
|
||||
require(has(role, addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev check if an address has this role
|
||||
* @return bool
|
||||
*/
|
||||
function has(Role storage role, address addr)
|
||||
view
|
||||
internal
|
||||
returns (bool)
|
||||
{
|
||||
return role.bearer[addr];
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,7 @@ import '../math/SafeMath.sol';
|
||||
|
||||
/**
|
||||
* @title SplitPayment
|
||||
* @dev Base contract that supports multiple payees claiming funds sent to this contract
|
||||
* @dev Base contract that supports multiple payees claiming funds sent to this contract
|
||||
* according to the proportion they own.
|
||||
*/
|
||||
contract SplitPayment {
|
||||
@ -20,7 +20,7 @@ contract SplitPayment {
|
||||
/**
|
||||
* @dev Constructor
|
||||
*/
|
||||
function SplitPayment(address[] _payees, uint256[] _shares) public {
|
||||
function SplitPayment(address[] _payees, uint256[] _shares) public payable {
|
||||
require(_payees.length == _shares.length);
|
||||
|
||||
for (uint256 i = 0; i < _payees.length; i++) {
|
||||
@ -62,4 +62,9 @@ contract SplitPayment {
|
||||
|
||||
payee.transfer(payment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev payable fallback
|
||||
*/
|
||||
function () public payable {}
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import './StandardToken.sol';
|
||||
import './BasicToken.sol';
|
||||
|
||||
/**
|
||||
* @title Burnable Token
|
||||
* @dev Token that can be irreversibly burned (destroyed).
|
||||
*/
|
||||
contract BurnableToken is StandardToken {
|
||||
contract BurnableToken is BasicToken {
|
||||
|
||||
event Burn(address indexed burner, uint256 value);
|
||||
|
||||
@ -15,7 +15,6 @@ contract BurnableToken is StandardToken {
|
||||
* @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
|
||||
|
||||
@ -62,10 +62,14 @@ contract StandardToken is ERC20, BasicToken {
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Increase the amount of tokens that an owner allowed to a 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
|
||||
* @param _spender The address which will spend the funds.
|
||||
* @param _addedValue The amount of tokens to increase the allowance by.
|
||||
*/
|
||||
function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
|
||||
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
|
||||
@ -73,6 +77,16 @@ contract StandardToken is ERC20, BasicToken {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Decrease the amount of tokens that an owner allowed to a spender.
|
||||
*
|
||||
* approve should be called when allowed[_spender] == 0. To decrement
|
||||
* allowed value is better to use this function to avoid 2 calls (and wait until
|
||||
* the first transaction is mined)
|
||||
* From MonolithDAO Token.sol
|
||||
* @param _spender The address which will spend the funds.
|
||||
* @param _subtractedValue The amount of tokens to decrease the allowance by.
|
||||
*/
|
||||
function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
|
||||
uint oldValue = allowed[msg.sender][_spender];
|
||||
if (_subtractedValue > oldValue) {
|
||||
|
||||
@ -19,9 +19,9 @@ contract TokenTimelock {
|
||||
address public beneficiary;
|
||||
|
||||
// timestamp when token release is enabled
|
||||
uint64 public releaseTime;
|
||||
uint256 public releaseTime;
|
||||
|
||||
function TokenTimelock(ERC20Basic _token, address _beneficiary, uint64 _releaseTime) public {
|
||||
function TokenTimelock(ERC20Basic _token, address _beneficiary, uint256 _releaseTime) public {
|
||||
require(_releaseTime > now);
|
||||
token = _token;
|
||||
beneficiary = _beneficiary;
|
||||
|
||||
13
docs/source/delayedclaimable.rst
Normal file
13
docs/source/delayedclaimable.rst
Normal file
@ -0,0 +1,13 @@
|
||||
DelayedClaimable
|
||||
=============================================
|
||||
Extension for the Claimable contract, where the ownership needs to be claimed before/after a certain block number.
|
||||
|
||||
setLimits(uint256 _start, uint256 _end) onlyOwner
|
||||
""""""""""""""""""""""""""""""""""""""
|
||||
Specifies the time period during which a pending owner can claim ownership.
|
||||
|
||||
|
||||
claimOwnership( ) onlyPendingOwner
|
||||
""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Completes transfer of ownership by setting pending owner as the new owner.
|
||||
@ -12,10 +12,6 @@ To install the OpenZeppelin library, run::
|
||||
npm init # follow instructions
|
||||
npm install zeppelin-solidity
|
||||
|
||||
# If you are using yarn, add dependency like this -
|
||||
yarn add zeppelin-solidity
|
||||
|
||||
|
||||
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";
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"package_name": "zeppelin",
|
||||
"version": "1.4.0",
|
||||
"version": "1.5.0",
|
||||
"description": "Secure Smart Contract library for Solidity",
|
||||
"authors": [
|
||||
"Manuel Araoz <manuelaraoz@gmail.com>"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
var Migrations = artifacts.require("./Migrations.sol");
|
||||
var Migrations = artifacts.require('./Migrations.sol');
|
||||
|
||||
module.exports = function(deployer) {
|
||||
module.exports = function (deployer) {
|
||||
deployer.deploy(Migrations);
|
||||
};
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
//var Ownable = artifacts.require("ownership/Ownable.sol");
|
||||
// var Ownable = artifacts.require("ownership/Ownable.sol");
|
||||
|
||||
module.exports = function(deployer) {
|
||||
//deployer.deploy(Ownable);
|
||||
// NOTE: Use this file to easily deploy the contracts you're writing.
|
||||
// (but make sure to reset this file before committing
|
||||
// with `git checkout HEAD -- migrations/2_deploy_contracts.js`)
|
||||
|
||||
module.exports = function (deployer) {
|
||||
// deployer.deploy(Ownable);
|
||||
};
|
||||
|
||||
1071
package-lock.json
generated
1071
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@ -1,9 +1,10 @@
|
||||
{
|
||||
"name": "zeppelin-solidity",
|
||||
"version": "1.4.0",
|
||||
"version": "1.5.0",
|
||||
"description": "Secure Smart Contract library for Solidity",
|
||||
"scripts": {
|
||||
"test": "scripts/test.sh",
|
||||
"lint": "eslint .",
|
||||
"console": "truffle console",
|
||||
"coverage": "scripts/coverage.sh"
|
||||
},
|
||||
@ -35,11 +36,20 @@
|
||||
"chai-as-promised": "^7.0.0",
|
||||
"chai-bignumber": "^2.0.0",
|
||||
"coveralls": "^2.13.1",
|
||||
"ethereumjs-util": "^5.1.2",
|
||||
"eslint": "^4.11.0",
|
||||
"eslint-config-standard": "^10.2.1",
|
||||
"eslint-plugin-import": "^2.8.0",
|
||||
"eslint-plugin-node": "^5.2.1",
|
||||
"eslint-plugin-promise": "^3.6.0",
|
||||
"eslint-plugin-standard": "^3.0.1",
|
||||
"ethereumjs-testrpc": "^6.0.1",
|
||||
"ethereumjs-util": "^5.1.2",
|
||||
"mocha-lcov-reporter": "^1.3.0",
|
||||
"solidity-coverage": "^0.2.2",
|
||||
"solidity-coverage": "^0.4.3",
|
||||
"truffle": "^4.0.0",
|
||||
"truffle-hdwallet-provider": "0.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^4.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
5
test/.eslintrc
Normal file
5
test/.eslintrc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-unused-expressions": 0
|
||||
}
|
||||
}
|
||||
@ -1,19 +1,18 @@
|
||||
const assertRevert = require('./helpers/assertRevert');
|
||||
|
||||
var BasicTokenMock = artifacts.require("./helpers/BasicTokenMock.sol");
|
||||
var BasicTokenMock = artifacts.require('mocks/BasicTokenMock.sol');
|
||||
|
||||
contract('BasicToken', function(accounts) {
|
||||
|
||||
it("should return the correct totalSupply after construction", async function() {
|
||||
contract('BasicToken', function (accounts) {
|
||||
it('should return the correct totalSupply after construction', async function () {
|
||||
let token = await BasicTokenMock.new(accounts[0], 100);
|
||||
let totalSupply = await token.totalSupply();
|
||||
|
||||
assert.equal(totalSupply, 100);
|
||||
})
|
||||
});
|
||||
|
||||
it("should return correct balances after transfer", async function(){
|
||||
it('should return correct balances after transfer', async function () {
|
||||
let token = await BasicTokenMock.new(accounts[0], 100);
|
||||
let transfer = await token.transfer(accounts[1], 100);
|
||||
await token.transfer(accounts[1], 100);
|
||||
|
||||
let firstAccountBalance = await token.balanceOf(accounts[0]);
|
||||
assert.equal(firstAccountBalance, 0);
|
||||
@ -22,24 +21,23 @@ 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);
|
||||
await token.transfer(accounts[1], 101);
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw an error when trying to transfer to 0x0', async function() {
|
||||
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);
|
||||
await token.transfer(0x0, 100);
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@ -1,18 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
let sendReward = function(sender, receiver, value){
|
||||
let sendReward = function (sender, receiver, value) {
|
||||
web3.eth.sendTransaction({
|
||||
from:sender,
|
||||
to:receiver,
|
||||
value: value
|
||||
from: sender,
|
||||
to: receiver,
|
||||
value: value,
|
||||
});
|
||||
};
|
||||
var SecureTargetBounty = artifacts.require('helpers/SecureTargetBounty.sol');
|
||||
var InsecureTargetBounty = artifacts.require('helpers/InsecureTargetBounty.sol');
|
||||
var SecureTargetBounty = artifacts.require('mocks/SecureTargetBounty.sol');
|
||||
var InsecureTargetBounty = artifacts.require('mocks/InsecureTargetBounty.sol');
|
||||
|
||||
function awaitEvent(event, handler) {
|
||||
function awaitEvent (event, handler) {
|
||||
return new Promise((resolve, reject) => {
|
||||
function wrappedHandler(...args) {
|
||||
function wrappedHandler (...args) {
|
||||
Promise.resolve(handler(...args)).then(resolve).catch(reject);
|
||||
}
|
||||
|
||||
@ -20,9 +19,8 @@ function awaitEvent(event, handler) {
|
||||
});
|
||||
}
|
||||
|
||||
contract('Bounty', function(accounts) {
|
||||
|
||||
it('sets reward', async function() {
|
||||
contract('Bounty', function (accounts) {
|
||||
it('sets reward', async function () {
|
||||
let owner = accounts[0];
|
||||
let reward = web3.toWei(1, 'ether');
|
||||
let bounty = await SecureTargetBounty.new();
|
||||
@ -31,7 +29,7 @@ contract('Bounty', function(accounts) {
|
||||
assert.equal(reward, web3.eth.getBalance(bounty.address).toNumber());
|
||||
});
|
||||
|
||||
it('empties itself when destroyed', async function(){
|
||||
it('empties itself when destroyed', async function () {
|
||||
let owner = accounts[0];
|
||||
let reward = web3.toWei(1, 'ether');
|
||||
let bounty = await SecureTargetBounty.new();
|
||||
@ -43,16 +41,15 @@ contract('Bounty', function(accounts) {
|
||||
assert.equal(0, web3.eth.getBalance(bounty.address).toNumber());
|
||||
});
|
||||
|
||||
describe('Against secure contract', function(){
|
||||
|
||||
it('cannot claim reward', async function(){
|
||||
describe('Against secure contract', function () {
|
||||
it('cannot claim reward', async function () {
|
||||
let owner = accounts[0];
|
||||
let researcher = accounts[1];
|
||||
let reward = web3.toWei(1, 'ether');
|
||||
let bounty = await SecureTargetBounty.new();
|
||||
let event = bounty.TargetCreated({});
|
||||
|
||||
let watcher = async function(err, result) {
|
||||
let watcher = async function (err, result) {
|
||||
event.stopWatching();
|
||||
if (err) { throw err; }
|
||||
|
||||
@ -63,35 +60,34 @@ contract('Bounty', function(accounts) {
|
||||
web3.eth.getBalance(bounty.address).toNumber());
|
||||
|
||||
try {
|
||||
await bounty.claim(targetAddress, {from:researcher});
|
||||
await bounty.claim(targetAddress, { from: researcher });
|
||||
assert.isTrue(false); // should never reach here
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
let reClaimedBounty = await bounty.claimed.call();
|
||||
assert.isFalse(reClaimedBounty);
|
||||
|
||||
}
|
||||
try {
|
||||
await bounty.withdrawPayments({from:researcher});
|
||||
await bounty.withdrawPayments({ from: researcher });
|
||||
assert.isTrue(false); // should never reach here
|
||||
} catch (err) {
|
||||
assert.equal(reward,
|
||||
web3.eth.getBalance(bounty.address).toNumber());
|
||||
}
|
||||
};
|
||||
bounty.createTarget({from:researcher});
|
||||
bounty.createTarget({ from: researcher });
|
||||
await awaitEvent(event, watcher);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Against broken contract', function(){
|
||||
it('claims reward', async function() {
|
||||
describe('Against broken contract', function () {
|
||||
it('claims reward', async function () {
|
||||
let owner = accounts[0];
|
||||
let researcher = accounts[1];
|
||||
let reward = web3.toWei(1, 'ether');
|
||||
let bounty = await InsecureTargetBounty.new();
|
||||
let event = bounty.TargetCreated({});
|
||||
|
||||
let watcher = async function(err, result) {
|
||||
let watcher = async function (err, result) {
|
||||
event.stopWatching();
|
||||
if (err) { throw err; }
|
||||
let targetAddress = result.args.createdAddress;
|
||||
@ -99,16 +95,16 @@ contract('Bounty', function(accounts) {
|
||||
|
||||
assert.equal(reward, web3.eth.getBalance(bounty.address).toNumber());
|
||||
|
||||
await bounty.claim(targetAddress, {from:researcher});
|
||||
await bounty.claim(targetAddress, { from: researcher });
|
||||
let claim = await bounty.claimed.call();
|
||||
|
||||
assert.isTrue(claim);
|
||||
|
||||
await bounty.withdrawPayments({from:researcher});
|
||||
await bounty.withdrawPayments({ from: researcher });
|
||||
|
||||
assert.equal(0, web3.eth.getBalance(bounty.address).toNumber());
|
||||
};
|
||||
bounty.createTarget({from:researcher});
|
||||
bounty.createTarget({ from: researcher });
|
||||
await awaitEvent(event, watcher);
|
||||
});
|
||||
});
|
||||
@ -1,39 +0,0 @@
|
||||
'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)
|
||||
})
|
||||
})
|
||||
38
test/BurnableToken.test.js
Normal file
38
test/BurnableToken.test.js
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
const EVMRevert = require('./helpers/EVMRevert.js');
|
||||
const BurnableTokenMock = artifacts.require('mocks/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);
|
||||
});
|
||||
});
|
||||
@ -1,14 +1,14 @@
|
||||
'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) {
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
|
||||
const CanReclaimToken = artifacts.require('../contracts/ownership/CanReclaimToken.sol');
|
||||
const BasicTokenMock = artifacts.require('mocks/BasicTokenMock.sol');
|
||||
|
||||
contract('CanReclaimToken', function (accounts) {
|
||||
let token = null;
|
||||
let canReclaimToken = null;
|
||||
|
||||
beforeEach(async function() {
|
||||
beforeEach(async function () {
|
||||
// Create contract and token
|
||||
token = await BasicTokenMock.new(accounts[0], 100);
|
||||
canReclaimToken = await CanReclaimToken.new();
|
||||
@ -18,7 +18,7 @@ contract('CanReclaimToken', function(accounts) {
|
||||
assert.equal(startBalance, 10);
|
||||
});
|
||||
|
||||
it('should allow owner to reclaim tokens', async function() {
|
||||
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]);
|
||||
@ -27,9 +27,9 @@ contract('CanReclaimToken', function(accounts) {
|
||||
assert.equal(ownerFinalBalance - ownerStartBalance, 10);
|
||||
});
|
||||
|
||||
it('should allow only owner to reclaim tokens', async function() {
|
||||
it('should allow only owner to reclaim tokens', async function () {
|
||||
await expectThrow(
|
||||
canReclaimToken.reclaimToken(token.address, {from: accounts[1]}),
|
||||
canReclaimToken.reclaimToken(token.address, { from: accounts[1] }),
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -1,96 +0,0 @@
|
||||
import ether from './helpers/ether'
|
||||
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
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should()
|
||||
|
||||
const CappedCrowdsale = artifacts.require('./helpers/CappedCrowdsaleImpl.sol')
|
||||
const MintableToken = artifacts.require('MintableToken')
|
||||
|
||||
contract('CappedCrowdsale', function ([_, wallet]) {
|
||||
|
||||
const rate = new BigNumber(1000)
|
||||
|
||||
const cap = ether(300)
|
||||
const lessThanCap = ether(60)
|
||||
|
||||
before(async function() {
|
||||
//Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
|
||||
await advanceBlock()
|
||||
})
|
||||
|
||||
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 increaseTimeTo(this.startTime)
|
||||
})
|
||||
|
||||
it('should accept payments within cap', async function () {
|
||||
await this.crowdsale.send(cap.minus(lessThanCap)).should.be.fulfilled
|
||||
await this.crowdsale.send(lessThanCap).should.be.fulfilled
|
||||
})
|
||||
|
||||
it('should reject payments outside cap', async function () {
|
||||
await this.crowdsale.send(cap)
|
||||
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(EVMRevert)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('ending', function () {
|
||||
|
||||
beforeEach(async function () {
|
||||
await increaseTimeTo(this.startTime)
|
||||
})
|
||||
|
||||
it('should not be ended if under cap', async function () {
|
||||
let hasEnded = await this.crowdsale.hasEnded()
|
||||
hasEnded.should.equal(false)
|
||||
await this.crowdsale.send(lessThanCap)
|
||||
hasEnded = await this.crowdsale.hasEnded()
|
||||
hasEnded.should.equal(false)
|
||||
})
|
||||
|
||||
it('should not be ended if just under cap', async function () {
|
||||
await this.crowdsale.send(cap.minus(1))
|
||||
let hasEnded = await this.crowdsale.hasEnded()
|
||||
hasEnded.should.equal(false)
|
||||
})
|
||||
|
||||
it('should be ended if cap reached', async function () {
|
||||
await this.crowdsale.send(cap)
|
||||
let hasEnded = await this.crowdsale.hasEnded()
|
||||
hasEnded.should.equal(true)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
88
test/CappedCrowdsale.test.js
Normal file
88
test/CappedCrowdsale.test.js
Normal file
@ -0,0 +1,88 @@
|
||||
import ether from './helpers/ether';
|
||||
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;
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const CappedCrowdsale = artifacts.require('mocks/CappedCrowdsaleImpl.sol');
|
||||
const MintableToken = artifacts.require('MintableToken');
|
||||
|
||||
contract('CappedCrowdsale', function ([_, wallet]) {
|
||||
const rate = new BigNumber(1000);
|
||||
|
||||
const cap = ether(300);
|
||||
const lessThanCap = ether(60);
|
||||
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
|
||||
await advanceBlock();
|
||||
});
|
||||
|
||||
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 increaseTimeTo(this.startTime);
|
||||
});
|
||||
|
||||
it('should accept payments within cap', async function () {
|
||||
await this.crowdsale.send(cap.minus(lessThanCap)).should.be.fulfilled;
|
||||
await this.crowdsale.send(lessThanCap).should.be.fulfilled;
|
||||
});
|
||||
|
||||
it('should reject payments outside cap', async function () {
|
||||
await this.crowdsale.send(cap);
|
||||
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(EVMRevert);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ending', function () {
|
||||
beforeEach(async function () {
|
||||
await increaseTimeTo(this.startTime);
|
||||
});
|
||||
|
||||
it('should not be ended if under cap', async function () {
|
||||
let hasEnded = await this.crowdsale.hasEnded();
|
||||
hasEnded.should.equal(false);
|
||||
await this.crowdsale.send(lessThanCap);
|
||||
hasEnded = await this.crowdsale.hasEnded();
|
||||
hasEnded.should.equal(false);
|
||||
});
|
||||
|
||||
it('should not be ended if just under cap', async function () {
|
||||
await this.crowdsale.send(cap.minus(1));
|
||||
let hasEnded = await this.crowdsale.hasEnded();
|
||||
hasEnded.should.equal(false);
|
||||
});
|
||||
|
||||
it('should be ended if cap reached', async function () {
|
||||
await this.crowdsale.send(cap);
|
||||
let hasEnded = await this.crowdsale.hasEnded();
|
||||
hasEnded.should.equal(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,39 +1,36 @@
|
||||
'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) {
|
||||
contract('Capped', function (accounts) {
|
||||
const cap = ether(1000);
|
||||
|
||||
let token;
|
||||
|
||||
beforeEach(async function() {
|
||||
beforeEach(async function () {
|
||||
token = await CappedToken.new(cap);
|
||||
})
|
||||
});
|
||||
|
||||
it('should start with the correct cap', async function() {
|
||||
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() {
|
||||
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() {
|
||||
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() {
|
||||
it('should fail to mint after cap is reached', async function () {
|
||||
await token.mint(accounts[0], cap);
|
||||
await expectThrow(token.mint(accounts[0], 1));
|
||||
})
|
||||
|
||||
});
|
||||
});
|
||||
@ -1,21 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
const assertRevert = require('./helpers/assertRevert');
|
||||
|
||||
var Claimable = artifacts.require('../contracts/ownership/Claimable.sol');
|
||||
|
||||
contract('Claimable', function(accounts) {
|
||||
contract('Claimable', function (accounts) {
|
||||
let claimable;
|
||||
|
||||
beforeEach(async function() {
|
||||
beforeEach(async function () {
|
||||
claimable = await Claimable.new();
|
||||
});
|
||||
|
||||
it('should have an owner', async function() {
|
||||
it('should have an owner', async function () {
|
||||
let owner = await claimable.owner();
|
||||
assert.isTrue(owner !== 0);
|
||||
});
|
||||
|
||||
it('changes pendingOwner after transfer', async function() {
|
||||
it('changes pendingOwner after transfer', async function () {
|
||||
let newOwner = accounts[1];
|
||||
await claimable.transferOwnership(newOwner);
|
||||
let pendingOwner = await claimable.pendingOwner();
|
||||
@ -23,23 +23,23 @@ contract('Claimable', function(accounts) {
|
||||
assert.isTrue(pendingOwner === newOwner);
|
||||
});
|
||||
|
||||
it('should prevent to claimOwnership from no pendingOwner', async function() {
|
||||
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) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
it('should prevent non-owners from transfering', async function() {
|
||||
it('should prevent non-owners from transfering', async function () {
|
||||
const other = accounts[2];
|
||||
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) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
@ -52,8 +52,8 @@ contract('Claimable', function(accounts) {
|
||||
await claimable.transferOwnership(newOwner);
|
||||
});
|
||||
|
||||
it('changes allow pending owner to claim ownership', async function() {
|
||||
await claimable.claimOwnership({from: newOwner});
|
||||
it('changes allow pending owner to claim ownership', async function () {
|
||||
await claimable.claimOwnership({ from: newOwner });
|
||||
let owner = await claimable.owner();
|
||||
|
||||
assert.isTrue(owner === newOwner);
|
||||
@ -1,30 +1,28 @@
|
||||
'use strict';
|
||||
const assertRevert = require('./helpers/assertRevert');
|
||||
|
||||
var Contactable = artifacts.require('../contracts/ownership/Contactable.sol');
|
||||
|
||||
contract('Contactable', function(accounts) {
|
||||
contract('Contactable', function (accounts) {
|
||||
let contactable;
|
||||
|
||||
beforeEach(async function() {
|
||||
beforeEach(async function () {
|
||||
contactable = await Contactable.new();
|
||||
});
|
||||
|
||||
it('should have an empty contact info', async function() {
|
||||
it('should have an empty contact info', async function () {
|
||||
let info = await contactable.contactInformation();
|
||||
assert.isTrue(info == "");
|
||||
assert.isTrue(info === '');
|
||||
});
|
||||
|
||||
describe('after setting the contact information', function () {
|
||||
let contactInfo = "contact information"
|
||||
let contactInfo = 'contact information';
|
||||
|
||||
beforeEach(async function () {
|
||||
await contactable.setContactInformation(contactInfo);
|
||||
});
|
||||
|
||||
it('should return the setted contact information', async function() {
|
||||
it('should return the setted contact information', async function () {
|
||||
let info = await contactable.contactInformation();
|
||||
assert.isTrue(info === contactInfo);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,152 +0,0 @@
|
||||
import ether from './helpers/ether'
|
||||
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
|
||||
|
||||
const should = require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should()
|
||||
|
||||
const Crowdsale = artifacts.require('Crowdsale')
|
||||
const MintableToken = artifacts.require('MintableToken')
|
||||
|
||||
contract('Crowdsale', function ([_, investor, wallet, purchaser]) {
|
||||
|
||||
const rate = new BigNumber(1000)
|
||||
const value = ether(42)
|
||||
|
||||
const expectedTokenAmount = rate.mul(value)
|
||||
|
||||
before(async function() {
|
||||
//Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
|
||||
await advanceBlock()
|
||||
})
|
||||
|
||||
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())
|
||||
})
|
||||
|
||||
it('should be token owner', async function () {
|
||||
const owner = await this.token.owner()
|
||||
owner.should.equal(this.crowdsale.address)
|
||||
})
|
||||
|
||||
it('should be ended only after end', async function () {
|
||||
let ended = await this.crowdsale.hasEnded()
|
||||
ended.should.equal(false)
|
||||
await increaseTimeTo(this.afterEndTime)
|
||||
ended = await this.crowdsale.hasEnded()
|
||||
ended.should.equal(true)
|
||||
})
|
||||
|
||||
describe('accepting payments', function () {
|
||||
|
||||
it('should reject payments before start', async function () {
|
||||
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 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 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)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('high-level purchase', function () {
|
||||
|
||||
beforeEach(async function() {
|
||||
await increaseTimeTo(this.startTime)
|
||||
})
|
||||
|
||||
it('should log purchase', async function () {
|
||||
const {logs} = await this.crowdsale.sendTransaction({value: value, from: investor})
|
||||
|
||||
const event = logs.find(e => e.event === 'TokenPurchase')
|
||||
|
||||
should.exist(event)
|
||||
event.args.purchaser.should.equal(investor)
|
||||
event.args.beneficiary.should.equal(investor)
|
||||
event.args.value.should.be.bignumber.equal(value)
|
||||
event.args.amount.should.be.bignumber.equal(expectedTokenAmount)
|
||||
})
|
||||
|
||||
it('should increase totalSupply', async function () {
|
||||
await this.crowdsale.send(value)
|
||||
const totalSupply = await this.token.totalSupply()
|
||||
totalSupply.should.be.bignumber.equal(expectedTokenAmount)
|
||||
})
|
||||
|
||||
it('should assign tokens to sender', async function () {
|
||||
await this.crowdsale.sendTransaction({value: value, from: investor})
|
||||
let balance = await this.token.balanceOf(investor);
|
||||
balance.should.be.bignumber.equal(expectedTokenAmount)
|
||||
})
|
||||
|
||||
it('should forward funds to wallet', async function () {
|
||||
const pre = web3.eth.getBalance(wallet)
|
||||
await this.crowdsale.sendTransaction({value, from: investor})
|
||||
const post = web3.eth.getBalance(wallet)
|
||||
post.minus(pre).should.be.bignumber.equal(value)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('low-level purchase', function () {
|
||||
|
||||
beforeEach(async function() {
|
||||
await increaseTimeTo(this.startTime)
|
||||
})
|
||||
|
||||
it('should log purchase', async function () {
|
||||
const {logs} = await this.crowdsale.buyTokens(investor, {value: value, from: purchaser})
|
||||
|
||||
const event = logs.find(e => e.event === 'TokenPurchase')
|
||||
|
||||
should.exist(event)
|
||||
event.args.purchaser.should.equal(purchaser)
|
||||
event.args.beneficiary.should.equal(investor)
|
||||
event.args.value.should.be.bignumber.equal(value)
|
||||
event.args.amount.should.be.bignumber.equal(expectedTokenAmount)
|
||||
})
|
||||
|
||||
it('should increase totalSupply', async function () {
|
||||
await this.crowdsale.buyTokens(investor, {value, from: purchaser})
|
||||
const totalSupply = await this.token.totalSupply()
|
||||
totalSupply.should.be.bignumber.equal(expectedTokenAmount)
|
||||
})
|
||||
|
||||
it('should assign tokens to beneficiary', async function () {
|
||||
await this.crowdsale.buyTokens(investor, {value, from: purchaser})
|
||||
const balance = await this.token.balanceOf(investor)
|
||||
balance.should.be.bignumber.equal(expectedTokenAmount)
|
||||
})
|
||||
|
||||
it('should forward funds to wallet', async function () {
|
||||
const pre = web3.eth.getBalance(wallet)
|
||||
await this.crowdsale.buyTokens(investor, {value, from: purchaser})
|
||||
const post = web3.eth.getBalance(wallet)
|
||||
post.minus(pre).should.be.bignumber.equal(value)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
143
test/Crowdsale.test.js
Normal file
143
test/Crowdsale.test.js
Normal file
@ -0,0 +1,143 @@
|
||||
import ether from './helpers/ether';
|
||||
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;
|
||||
|
||||
const should = require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const Crowdsale = artifacts.require('Crowdsale');
|
||||
const MintableToken = artifacts.require('MintableToken');
|
||||
|
||||
contract('Crowdsale', function ([_, investor, wallet, purchaser]) {
|
||||
const rate = new BigNumber(1000);
|
||||
const value = ether(42);
|
||||
|
||||
const expectedTokenAmount = rate.mul(value);
|
||||
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
|
||||
await advanceBlock();
|
||||
});
|
||||
|
||||
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());
|
||||
});
|
||||
|
||||
it('should be token owner', async function () {
|
||||
const owner = await this.token.owner();
|
||||
owner.should.equal(this.crowdsale.address);
|
||||
});
|
||||
|
||||
it('should be ended only after end', async function () {
|
||||
let ended = await this.crowdsale.hasEnded();
|
||||
ended.should.equal(false);
|
||||
await increaseTimeTo(this.afterEndTime);
|
||||
ended = await this.crowdsale.hasEnded();
|
||||
ended.should.equal(true);
|
||||
});
|
||||
|
||||
describe('accepting payments', function () {
|
||||
it('should reject payments before start', async function () {
|
||||
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 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 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);
|
||||
});
|
||||
});
|
||||
|
||||
describe('high-level purchase', function () {
|
||||
beforeEach(async function () {
|
||||
await increaseTimeTo(this.startTime);
|
||||
});
|
||||
|
||||
it('should log purchase', async function () {
|
||||
const { logs } = await this.crowdsale.sendTransaction({ value: value, from: investor });
|
||||
|
||||
const event = logs.find(e => e.event === 'TokenPurchase');
|
||||
|
||||
should.exist(event);
|
||||
event.args.purchaser.should.equal(investor);
|
||||
event.args.beneficiary.should.equal(investor);
|
||||
event.args.value.should.be.bignumber.equal(value);
|
||||
event.args.amount.should.be.bignumber.equal(expectedTokenAmount);
|
||||
});
|
||||
|
||||
it('should increase totalSupply', async function () {
|
||||
await this.crowdsale.send(value);
|
||||
const totalSupply = await this.token.totalSupply();
|
||||
totalSupply.should.be.bignumber.equal(expectedTokenAmount);
|
||||
});
|
||||
|
||||
it('should assign tokens to sender', async function () {
|
||||
await this.crowdsale.sendTransaction({ value: value, from: investor });
|
||||
let balance = await this.token.balanceOf(investor);
|
||||
balance.should.be.bignumber.equal(expectedTokenAmount);
|
||||
});
|
||||
|
||||
it('should forward funds to wallet', async function () {
|
||||
const pre = web3.eth.getBalance(wallet);
|
||||
await this.crowdsale.sendTransaction({ value, from: investor });
|
||||
const post = web3.eth.getBalance(wallet);
|
||||
post.minus(pre).should.be.bignumber.equal(value);
|
||||
});
|
||||
});
|
||||
|
||||
describe('low-level purchase', function () {
|
||||
beforeEach(async function () {
|
||||
await increaseTimeTo(this.startTime);
|
||||
});
|
||||
|
||||
it('should log purchase', async function () {
|
||||
const { logs } = await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
|
||||
const event = logs.find(e => e.event === 'TokenPurchase');
|
||||
|
||||
should.exist(event);
|
||||
event.args.purchaser.should.equal(purchaser);
|
||||
event.args.beneficiary.should.equal(investor);
|
||||
event.args.value.should.be.bignumber.equal(value);
|
||||
event.args.amount.should.be.bignumber.equal(expectedTokenAmount);
|
||||
});
|
||||
|
||||
it('should increase totalSupply', async function () {
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
const totalSupply = await this.token.totalSupply();
|
||||
totalSupply.should.be.bignumber.equal(expectedTokenAmount);
|
||||
});
|
||||
|
||||
it('should assign tokens to beneficiary', async function () {
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
const balance = await this.token.balanceOf(investor);
|
||||
balance.should.be.bignumber.equal(expectedTokenAmount);
|
||||
});
|
||||
|
||||
it('should forward funds to wallet', async function () {
|
||||
const pre = web3.eth.getBalance(wallet);
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
const post = web3.eth.getBalance(wallet);
|
||||
post.minus(pre).should.be.bignumber.equal(value);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,26 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
import latestTime from './helpers/latestTime';
|
||||
import { increaseTimeTo, duration } from './helpers/increaseTime';
|
||||
|
||||
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 DayLimitMock = artifacts.require('mocks/DayLimitMock.sol');
|
||||
|
||||
contract('DayLimit', function (accounts) {
|
||||
let dayLimit;
|
||||
let initLimit = 10;
|
||||
|
||||
beforeEach( async function() {
|
||||
beforeEach(async function () {
|
||||
this.startTime = latestTime();
|
||||
dayLimit = await DayLimitMock.new(initLimit);
|
||||
});
|
||||
|
||||
it('should construct with the passed daily limit', async function() {
|
||||
it('should construct with the passed daily limit', async function () {
|
||||
let dailyLimit = await dayLimit.dailyLimit();
|
||||
assert.equal(initLimit, dailyLimit);
|
||||
});
|
||||
|
||||
it('should be able to spend if daily limit is not reached', async function() {
|
||||
it('should be able to spend if daily limit is not reached', async function () {
|
||||
await dayLimit.attemptSpend(8);
|
||||
let spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 8);
|
||||
@ -30,7 +30,7 @@ contract('DayLimit', function(accounts) {
|
||||
assert.equal(spentToday, 10);
|
||||
});
|
||||
|
||||
it('should prevent spending if daily limit is reached', async function() {
|
||||
it('should prevent spending if daily limit is reached', async function () {
|
||||
await dayLimit.attemptSpend(8);
|
||||
let spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 8);
|
||||
@ -38,12 +38,12 @@ contract('DayLimit', function(accounts) {
|
||||
try {
|
||||
await dayLimit.attemptSpend(3);
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
it('should allow spending if daily limit is reached and then set higher', async function() {
|
||||
it('should allow spending if daily limit is reached and then set higher', async function () {
|
||||
await dayLimit.attemptSpend(8);
|
||||
let spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 8);
|
||||
@ -51,7 +51,7 @@ contract('DayLimit', function(accounts) {
|
||||
try {
|
||||
await dayLimit.attemptSpend(3);
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
spentToday = await dayLimit.spentToday();
|
||||
@ -63,7 +63,7 @@ contract('DayLimit', function(accounts) {
|
||||
assert.equal(spentToday, 11);
|
||||
});
|
||||
|
||||
it('should allow spending if daily limit is reached and then amount spent is reset', async function() {
|
||||
it('should allow spending if daily limit is reached and then amount spent is reset', async function () {
|
||||
await dayLimit.attemptSpend(8);
|
||||
let spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 8);
|
||||
@ -71,7 +71,7 @@ contract('DayLimit', function(accounts) {
|
||||
try {
|
||||
await dayLimit.attemptSpend(3);
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
spentToday = await dayLimit.spentToday();
|
||||
@ -83,7 +83,7 @@ contract('DayLimit', function(accounts) {
|
||||
assert.equal(spentToday, 3);
|
||||
});
|
||||
|
||||
it('should allow spending if daily limit is reached and then the next has come', async function() {
|
||||
it('should allow spending if daily limit is reached and then the next has come', async function () {
|
||||
let limit = 10;
|
||||
let dayLimit = await DayLimitMock.new(limit);
|
||||
|
||||
@ -94,7 +94,7 @@ contract('DayLimit', function(accounts) {
|
||||
try {
|
||||
await dayLimit.attemptSpend(3);
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
spentToday = await dayLimit.spentToday();
|
||||
@ -106,5 +106,4 @@ contract('DayLimit', function(accounts) {
|
||||
spentToday = await dayLimit.spentToday();
|
||||
assert.equal(spentToday, 3);
|
||||
});
|
||||
|
||||
});
|
||||
@ -1,17 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
var DelayedClaimable = artifacts.require('../contracts/ownership/DelayedClaimable.sol');
|
||||
|
||||
contract('DelayedClaimable', function(accounts) {
|
||||
contract('DelayedClaimable', function (accounts) {
|
||||
var delayedClaimable;
|
||||
|
||||
beforeEach(function() {
|
||||
return DelayedClaimable.new().then(function(deployed) {
|
||||
beforeEach(function () {
|
||||
return DelayedClaimable.new().then(function (deployed) {
|
||||
delayedClaimable = deployed;
|
||||
});
|
||||
});
|
||||
|
||||
it('can set claim blocks', async function() {
|
||||
it('can set claim blocks', async function () {
|
||||
await delayedClaimable.transferOwnership(accounts[2]);
|
||||
await delayedClaimable.setLimits(0, 1000);
|
||||
let end = await delayedClaimable.end();
|
||||
@ -20,7 +19,7 @@ contract('DelayedClaimable', function(accounts) {
|
||||
assert.equal(start, 0);
|
||||
});
|
||||
|
||||
it('changes pendingOwner after transfer successful', async function() {
|
||||
it('changes pendingOwner after transfer successful', async function () {
|
||||
await delayedClaimable.transferOwnership(accounts[2]);
|
||||
await delayedClaimable.setLimits(0, 1000);
|
||||
let end = await delayedClaimable.end();
|
||||
@ -29,12 +28,12 @@ contract('DelayedClaimable', function(accounts) {
|
||||
assert.equal(start, 0);
|
||||
let pendingOwner = await delayedClaimable.pendingOwner();
|
||||
assert.equal(pendingOwner, accounts[2]);
|
||||
await delayedClaimable.claimOwnership({from: accounts[2]});
|
||||
await delayedClaimable.claimOwnership({ from: accounts[2] });
|
||||
let owner = await delayedClaimable.owner();
|
||||
assert.equal(owner, accounts[2]);
|
||||
});
|
||||
|
||||
it('changes pendingOwner after transfer fails', async function() {
|
||||
it('changes pendingOwner after transfer fails', async function () {
|
||||
await delayedClaimable.transferOwnership(accounts[1]);
|
||||
await delayedClaimable.setLimits(100, 110);
|
||||
let end = await delayedClaimable.end();
|
||||
@ -45,7 +44,7 @@ contract('DelayedClaimable', function(accounts) {
|
||||
assert.equal(pendingOwner, accounts[1]);
|
||||
var err = null;
|
||||
try {
|
||||
await delayedClaimable.claimOwnership({from: accounts[1]});
|
||||
await delayedClaimable.claimOwnership({ from: accounts[1] });
|
||||
} catch (error) {
|
||||
err = error;
|
||||
}
|
||||
@ -54,7 +53,7 @@ contract('DelayedClaimable', function(accounts) {
|
||||
assert.isTrue(owner !== accounts[1]);
|
||||
});
|
||||
|
||||
it('set end and start invalid values fail', async function() {
|
||||
it('set end and start invalid values fail', async function () {
|
||||
await delayedClaimable.transferOwnership(accounts[1]);
|
||||
var err = null;
|
||||
try {
|
||||
@ -64,5 +63,4 @@ contract('DelayedClaimable', function(accounts) {
|
||||
}
|
||||
assert.isFalse(err.message.search('revert') === -1);
|
||||
});
|
||||
|
||||
});
|
||||
@ -1,26 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
var Destructible = artifacts.require('../contracts/lifecycle/Destructible.sol');
|
||||
require('./helpers/transactionMined.js');
|
||||
|
||||
contract('Destructible', function(accounts) {
|
||||
|
||||
it('should send balance to owner after destruction', async function() {
|
||||
let destructible = await Destructible.new({from: accounts[0], value: web3.toWei('10','ether')});
|
||||
contract('Destructible', function (accounts) {
|
||||
it('should send balance to owner after destruction', async function () {
|
||||
let destructible = await Destructible.new({ from: accounts[0], value: web3.toWei('10', 'ether') });
|
||||
let owner = await destructible.owner();
|
||||
let initBalance = web3.eth.getBalance(owner);
|
||||
await destructible.destroy({from: owner});
|
||||
await destructible.destroy({ from: owner });
|
||||
let newBalance = web3.eth.getBalance(owner);
|
||||
assert.isTrue(newBalance > initBalance);
|
||||
});
|
||||
|
||||
it('should send balance to recepient after destruction', async function() {
|
||||
let destructible = await Destructible.new({from: accounts[0], value: web3.toWei('10','ether')});
|
||||
it('should send balance to recepient after destruction', async function () {
|
||||
let destructible = await Destructible.new({ from: accounts[0], value: web3.toWei('10', 'ether') });
|
||||
let owner = await destructible.owner();
|
||||
let initBalance = web3.eth.getBalance(accounts[1]);
|
||||
await destructible.destroyAndSend(accounts[1], {from: owner} );
|
||||
await destructible.destroyAndSend(accounts[1], { from: owner });
|
||||
let newBalance = web3.eth.getBalance(accounts[1]);
|
||||
assert.isTrue(newBalance.greaterThan(initBalance));
|
||||
});
|
||||
|
||||
});
|
||||
@ -5,16 +5,16 @@ require('chai')
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const DetailedERC20Mock = artifacts.require('./helpers/DetailedERC20Mock.sol');
|
||||
const DetailedERC20Mock = artifacts.require('mocks/DetailedERC20Mock.sol');
|
||||
|
||||
contract('DetailedERC20', accounts => {
|
||||
let detailedERC20 = null;
|
||||
|
||||
const _name = "My Detailed ERC20";
|
||||
const _symbol = "MDT";
|
||||
const _name = 'My Detailed ERC20';
|
||||
const _symbol = 'MDT';
|
||||
const _decimals = 18;
|
||||
|
||||
beforeEach(async function() {
|
||||
beforeEach(async function () {
|
||||
detailedERC20 = await DetailedERC20Mock.new(_name, _symbol, _decimals);
|
||||
});
|
||||
|
||||
@ -30,6 +30,6 @@ contract('DetailedERC20', accounts => {
|
||||
|
||||
it('has an amount of decimals', async function () {
|
||||
const decimals = await detailedERC20.decimals();
|
||||
decimals.should.be.bignumber.equal(_decimals)
|
||||
decimals.should.be.bignumber.equal(_decimals);
|
||||
});
|
||||
});
|
||||
@ -1,32 +1,32 @@
|
||||
var ECRecovery = artifacts.require("../contracts/ECRecovery.sol");
|
||||
var utils = require('ethereumjs-util');
|
||||
var ECRecovery = artifacts.require('../contracts/ECRecovery.sol');
|
||||
var hashMessage = require('./helpers/hashMessage.js');
|
||||
|
||||
contract('ECRecovery', function(accounts) {
|
||||
|
||||
contract('ECRecovery', function (accounts) {
|
||||
let ecrecovery;
|
||||
|
||||
before(async function() {
|
||||
before(async function () {
|
||||
ecrecovery = await ECRecovery.new();
|
||||
});
|
||||
|
||||
it("recover v0", async function() {
|
||||
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')
|
||||
// eslint-disable-next-line max-len
|
||||
let signature = '0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be89200';
|
||||
assert.equal(signer, await ecrecovery.recover(message, signature));
|
||||
});
|
||||
|
||||
it("recover v1", async function() {
|
||||
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')
|
||||
// eslint-disable-next-line max-len
|
||||
let signature = '0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e001';
|
||||
assert.equal(signer, await ecrecovery.recover(message, signature));
|
||||
});
|
||||
|
||||
it("recover using web3.eth.sign()", async function() {
|
||||
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'));
|
||||
|
||||
@ -34,7 +34,7 @@ contract('ECRecovery', function(accounts) {
|
||||
assert.equal(web3.eth.accounts[0], await ecrecovery.recover(hashMessage('OpenZeppelin'), signature));
|
||||
});
|
||||
|
||||
it("recover using web3.eth.sign() should return wrong signer", async function() {
|
||||
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'));
|
||||
|
||||
@ -42,7 +42,7 @@ contract('ECRecovery', function(accounts) {
|
||||
assert.notEqual(web3.eth.accounts[0], await ecrecovery.recover(hashMessage('Test'), signature));
|
||||
});
|
||||
|
||||
it("recover should fail when a wrong hash is sent", async function() {
|
||||
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'));
|
||||
|
||||
@ -51,5 +51,4 @@ contract('ECRecovery', function(accounts) {
|
||||
await ecrecovery.recover(hashMessage('OpenZeppelin').substring(2), signature)
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
@ -1,63 +0,0 @@
|
||||
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
|
||||
|
||||
const should = require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should()
|
||||
|
||||
const FinalizableCrowdsale = artifacts.require('./helpers/FinalizableCrowdsaleImpl.sol')
|
||||
const MintableToken = artifacts.require('MintableToken')
|
||||
|
||||
contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) {
|
||||
|
||||
const rate = new BigNumber(1000)
|
||||
|
||||
before(async function() {
|
||||
//Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
|
||||
await advanceBlock()
|
||||
})
|
||||
|
||||
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(EVMRevert)
|
||||
})
|
||||
|
||||
it('cannot be finalized by third party after ending', async function () {
|
||||
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 increaseTimeTo(this.afterEndTime)
|
||||
await this.crowdsale.finalize({from: owner}).should.be.fulfilled
|
||||
})
|
||||
|
||||
it('cannot be finalized twice', async function () {
|
||||
await increaseTimeTo(this.afterEndTime)
|
||||
await this.crowdsale.finalize({from: owner})
|
||||
await this.crowdsale.finalize({from: owner}).should.be.rejectedWith(EVMRevert)
|
||||
})
|
||||
|
||||
it('logs finalized', async function () {
|
||||
await increaseTimeTo(this.afterEndTime)
|
||||
const {logs} = await this.crowdsale.finalize({from: owner})
|
||||
const event = logs.find(e => e.event === 'Finalized')
|
||||
should.exist(event)
|
||||
})
|
||||
|
||||
})
|
||||
60
test/FinalizableCrowdsale.test.js
Normal file
60
test/FinalizableCrowdsale.test.js
Normal file
@ -0,0 +1,60 @@
|
||||
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;
|
||||
|
||||
const should = require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const FinalizableCrowdsale = artifacts.require('mocks/FinalizableCrowdsaleImpl.sol');
|
||||
const MintableToken = artifacts.require('MintableToken');
|
||||
|
||||
contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) {
|
||||
const rate = new BigNumber(1000);
|
||||
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
|
||||
await advanceBlock();
|
||||
});
|
||||
|
||||
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(EVMRevert);
|
||||
});
|
||||
|
||||
it('cannot be finalized by third party after ending', async function () {
|
||||
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 increaseTimeTo(this.afterEndTime);
|
||||
await this.crowdsale.finalize({ from: owner }).should.be.fulfilled;
|
||||
});
|
||||
|
||||
it('cannot be finalized twice', async function () {
|
||||
await increaseTimeTo(this.afterEndTime);
|
||||
await this.crowdsale.finalize({ from: owner });
|
||||
await this.crowdsale.finalize({ from: owner }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('logs finalized', async function () {
|
||||
await increaseTimeTo(this.afterEndTime);
|
||||
const { logs } = await this.crowdsale.finalize({ from: owner });
|
||||
const event = logs.find(e => e.event === 'Finalized');
|
||||
should.exist(event);
|
||||
});
|
||||
});
|
||||
@ -1,12 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
import toPromise from './helpers/toPromise';
|
||||
|
||||
const Ownable = artifacts.require('../contracts/ownership/Ownable.sol');
|
||||
const HasNoContracts = artifacts.require(
|
||||
'../contracts/ownership/HasNoContracts.sol',
|
||||
);
|
||||
|
||||
contract('HasNoContracts', function(accounts) {
|
||||
contract('HasNoContracts', function (accounts) {
|
||||
let hasNoContracts = null;
|
||||
let ownable = null;
|
||||
|
||||
@ -21,15 +21,15 @@ contract('HasNoContracts', function(accounts) {
|
||||
assert.equal(owner, hasNoContracts.address);
|
||||
});
|
||||
|
||||
it('should allow owner to reclaim contracts', async function() {
|
||||
it('should allow owner to reclaim contracts', async function () {
|
||||
await hasNoContracts.reclaimContract(ownable.address);
|
||||
const owner = await ownable.owner();
|
||||
assert.equal(owner, accounts[0]);
|
||||
});
|
||||
|
||||
it('should allow only owner to reclaim contracts', async function() {
|
||||
it('should allow only owner to reclaim contracts', async function () {
|
||||
await expectThrow(
|
||||
hasNoContracts.reclaimContract(ownable.address, {from: accounts[1]}),
|
||||
hasNoContracts.reclaimContract(ownable.address, { from: accounts[1] }),
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -1,22 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
import toPromise from './helpers/toPromise';
|
||||
const HasNoEther = artifacts.require('../contracts/lifecycle/HasNoEther.sol');
|
||||
const HasNoEtherTest = artifacts.require('../helpers/HasNoEtherTest.sol');
|
||||
const ForceEther = artifacts.require('../helpers/ForceEther.sol');
|
||||
const HasNoEtherTest = artifacts.require('../mocks/HasNoEtherTest.sol');
|
||||
const ForceEther = artifacts.require('../mocks/ForceEther.sol');
|
||||
|
||||
contract('HasNoEther', function(accounts) {
|
||||
contract('HasNoEther', function (accounts) {
|
||||
const amount = web3.toWei('1', 'ether');
|
||||
|
||||
it('should be constructorable', async function() {
|
||||
let hasNoEther = await HasNoEtherTest.new();
|
||||
it('should be constructorable', async function () {
|
||||
await HasNoEtherTest.new();
|
||||
});
|
||||
|
||||
it('should not accept ether in constructor', async function() {
|
||||
await expectThrow(HasNoEtherTest.new({value: amount}));
|
||||
it('should not accept ether in constructor', async function () {
|
||||
await expectThrow(HasNoEtherTest.new({ value: amount }));
|
||||
});
|
||||
|
||||
it('should not accept ether', async function() {
|
||||
it('should not accept ether', async function () {
|
||||
let hasNoEther = await HasNoEtherTest.new();
|
||||
|
||||
await expectThrow(
|
||||
@ -28,14 +27,14 @@ contract('HasNoEther', function(accounts) {
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow owner to reclaim ether', async function() {
|
||||
it('should allow owner to reclaim ether', async function () {
|
||||
// Create contract
|
||||
let hasNoEther = await HasNoEtherTest.new();
|
||||
const startBalance = await web3.eth.getBalance(hasNoEther.address);
|
||||
assert.equal(startBalance, 0);
|
||||
|
||||
// Force ether into it
|
||||
let forceEther = await ForceEther.new({value: amount});
|
||||
let forceEther = await ForceEther.new({ value: amount });
|
||||
await forceEther.destroyAndSend(hasNoEther.address);
|
||||
const forcedBalance = await web3.eth.getBalance(hasNoEther.address);
|
||||
assert.equal(forcedBalance, amount);
|
||||
@ -49,17 +48,17 @@ contract('HasNoEther', function(accounts) {
|
||||
assert.isAbove(ownerFinalBalance, ownerStartBalance);
|
||||
});
|
||||
|
||||
it('should allow only owner to reclaim ether', async function() {
|
||||
it('should allow only owner to reclaim ether', async function () {
|
||||
// Create contract
|
||||
let hasNoEther = await HasNoEtherTest.new({from: accounts[0]});
|
||||
let hasNoEther = await HasNoEtherTest.new({ from: accounts[0] });
|
||||
|
||||
// Force ether into it
|
||||
let forceEther = await ForceEther.new({value: amount});
|
||||
let forceEther = await ForceEther.new({ value: amount });
|
||||
await forceEther.destroyAndSend(hasNoEther.address);
|
||||
const forcedBalance = await web3.eth.getBalance(hasNoEther.address);
|
||||
assert.equal(forcedBalance, amount);
|
||||
|
||||
// Reclaim
|
||||
await expectThrow(hasNoEther.reclaimEther({from: accounts[1]}));
|
||||
await expectThrow(hasNoEther.reclaimEther({ from: accounts[1] }));
|
||||
});
|
||||
});
|
||||
@ -1,10 +1,10 @@
|
||||
'use strict';
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
import toPromise from './helpers/toPromise';
|
||||
const HasNoTokens = artifacts.require('../contracts/lifecycle/HasNoTokens.sol');
|
||||
const ERC23TokenMock = artifacts.require('./helpers/ERC23TokenMock.sol');
|
||||
|
||||
contract('HasNoTokens', function(accounts) {
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
|
||||
const HasNoTokens = artifacts.require('../contracts/lifecycle/HasNoTokens.sol');
|
||||
const ERC23TokenMock = artifacts.require('mocks/ERC23TokenMock.sol');
|
||||
|
||||
contract('HasNoTokens', function (accounts) {
|
||||
let hasNoTokens = null;
|
||||
let token = null;
|
||||
|
||||
@ -19,11 +19,11 @@ contract('HasNoTokens', function(accounts) {
|
||||
assert.equal(startBalance, 10);
|
||||
});
|
||||
|
||||
it('should not accept ERC23 tokens', async function() {
|
||||
it('should not accept ERC23 tokens', async function () {
|
||||
await expectThrow(token.transferERC23(hasNoTokens.address, 10, ''));
|
||||
});
|
||||
|
||||
it('should allow owner to reclaim tokens', async function() {
|
||||
it('should allow owner to reclaim tokens', async function () {
|
||||
const ownerStartBalance = await token.balanceOf(accounts[0]);
|
||||
await hasNoTokens.reclaimToken(token.address);
|
||||
const ownerFinalBalance = await token.balanceOf(accounts[0]);
|
||||
@ -32,9 +32,9 @@ contract('HasNoTokens', function(accounts) {
|
||||
assert.equal(ownerFinalBalance - ownerStartBalance, 10);
|
||||
});
|
||||
|
||||
it('should allow only owner to reclaim tokens', async function() {
|
||||
it('should allow only owner to reclaim tokens', async function () {
|
||||
await expectThrow(
|
||||
hasNoTokens.reclaimToken(token.address, {from: accounts[1]}),
|
||||
hasNoTokens.reclaimToken(token.address, { from: accounts[1] }),
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -1,61 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var LimitBalanceMock = artifacts.require('helpers/LimitBalanceMock.sol');
|
||||
const assertRevert = require('./helpers/assertRevert');
|
||||
|
||||
contract('LimitBalance', function(accounts) {
|
||||
let lb;
|
||||
|
||||
beforeEach(async function() {
|
||||
lb = await LimitBalanceMock.new();
|
||||
});
|
||||
|
||||
let LIMIT = 1000;
|
||||
|
||||
it('should expose limit', async function() {
|
||||
let limit = await lb.limit();
|
||||
assert.equal(limit, LIMIT);
|
||||
});
|
||||
|
||||
it('should allow sending below limit', async function() {
|
||||
let amount = 1;
|
||||
await lb.limitedDeposit({value: amount});
|
||||
|
||||
assert.equal(web3.eth.getBalance(lb.address), amount);
|
||||
});
|
||||
|
||||
it('shouldnt allow sending above limit', async function() {
|
||||
let amount = 1110;
|
||||
try {
|
||||
await lb.limitedDeposit({value: amount});
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
it('should allow multiple sends below limit', async function() {
|
||||
let amount = 500;
|
||||
await lb.limitedDeposit({value: amount});
|
||||
|
||||
assert.equal(web3.eth.getBalance(lb.address), amount);
|
||||
|
||||
await lb.limitedDeposit({value: amount});
|
||||
assert.equal(web3.eth.getBalance(lb.address), amount*2);
|
||||
});
|
||||
|
||||
it('shouldnt allow multiple sends above limit', async function() {
|
||||
let amount = 500;
|
||||
await lb.limitedDeposit({value: amount});
|
||||
|
||||
assert.equal(web3.eth.getBalance(lb.address), amount);
|
||||
|
||||
try {
|
||||
await lb.limitedDeposit({value: amount+1});
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
59
test/LimitBalance.test.js
Normal file
59
test/LimitBalance.test.js
Normal file
@ -0,0 +1,59 @@
|
||||
|
||||
var LimitBalanceMock = artifacts.require('mocks/LimitBalanceMock.sol');
|
||||
const assertRevert = require('./helpers/assertRevert');
|
||||
|
||||
contract('LimitBalance', function (accounts) {
|
||||
let lb;
|
||||
|
||||
beforeEach(async function () {
|
||||
lb = await LimitBalanceMock.new();
|
||||
});
|
||||
|
||||
let LIMIT = 1000;
|
||||
|
||||
it('should expose limit', async function () {
|
||||
let limit = await lb.limit();
|
||||
assert.equal(limit, LIMIT);
|
||||
});
|
||||
|
||||
it('should allow sending below limit', async function () {
|
||||
let amount = 1;
|
||||
await lb.limitedDeposit({ value: amount });
|
||||
|
||||
assert.equal(web3.eth.getBalance(lb.address), amount);
|
||||
});
|
||||
|
||||
it('shouldnt allow sending above limit', async function () {
|
||||
let amount = 1110;
|
||||
try {
|
||||
await lb.limitedDeposit({ value: amount });
|
||||
assert.fail('should have thrown before');
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
it('should allow multiple sends below limit', async function () {
|
||||
let amount = 500;
|
||||
await lb.limitedDeposit({ value: amount });
|
||||
|
||||
assert.equal(web3.eth.getBalance(lb.address), amount);
|
||||
|
||||
await lb.limitedDeposit({ value: amount });
|
||||
assert.equal(web3.eth.getBalance(lb.address), amount * 2);
|
||||
});
|
||||
|
||||
it('shouldnt allow multiple sends above limit', async function () {
|
||||
let amount = 500;
|
||||
await lb.limitedDeposit({ value: amount });
|
||||
|
||||
assert.equal(web3.eth.getBalance(lb.address), amount);
|
||||
|
||||
try {
|
||||
await lb.limitedDeposit({ value: amount + 1 });
|
||||
assert.fail('should have thrown before');
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -1,18 +1,19 @@
|
||||
var MerkleProof = artifacts.require("./MerkleProof.sol");
|
||||
|
||||
import MerkleTree from "./helpers/merkleTree.js";
|
||||
import { sha3, bufferToHex } from "ethereumjs-util";
|
||||
import MerkleTree from './helpers/merkleTree.js';
|
||||
import { sha3, bufferToHex } from 'ethereumjs-util';
|
||||
|
||||
contract('MerkleProof', function(accounts) {
|
||||
var MerkleProof = artifacts.require('./MerkleProof.sol');
|
||||
|
||||
contract('MerkleProof', function (accounts) {
|
||||
let merkleProof;
|
||||
|
||||
before(async function() {
|
||||
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"];
|
||||
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();
|
||||
@ -22,28 +23,28 @@ contract('MerkleProof', function(accounts) {
|
||||
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");
|
||||
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"]
|
||||
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 badElements = ['d', 'e', 'f'];
|
||||
const badMerkleTree = new MerkleTree(badElements);
|
||||
|
||||
const badProof = badMerkleTree.getHexProof(badElements[0])
|
||||
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");
|
||||
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"]
|
||||
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();
|
||||
@ -54,7 +55,7 @@ contract('MerkleProof', function(accounts) {
|
||||
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");
|
||||
})
|
||||
assert.isNotOk(result, 'verifyProof did not return false for proof of invalid length');
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,28 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
var MintableToken = artifacts.require('../contracts/Tokens/MintableToken.sol');
|
||||
|
||||
contract('Mintable', function(accounts) {
|
||||
contract('Mintable', function (accounts) {
|
||||
let token;
|
||||
|
||||
beforeEach(async function() {
|
||||
beforeEach(async function () {
|
||||
token = await MintableToken.new();
|
||||
});
|
||||
|
||||
it('should start with a totalSupply of 0', async function() {
|
||||
it('should start with a totalSupply of 0', async function () {
|
||||
let totalSupply = await token.totalSupply();
|
||||
|
||||
assert.equal(totalSupply, 0);
|
||||
});
|
||||
|
||||
it('should return mintingFinished false after construction', async function() {
|
||||
it('should return mintingFinished false after construction', async function () {
|
||||
let mintingFinished = await token.mintingFinished();
|
||||
|
||||
assert.equal(mintingFinished, false);
|
||||
});
|
||||
|
||||
it('should mint a given amount of tokens to a given address', async function() {
|
||||
it('should mint a given amount of tokens to a given address', async function () {
|
||||
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]);
|
||||
@ -35,12 +34,11 @@ contract('Mintable', function(accounts) {
|
||||
|
||||
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));
|
||||
})
|
||||
|
||||
});
|
||||
});
|
||||
@ -1,21 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
const assertRevert = require('./helpers/assertRevert');
|
||||
|
||||
var Ownable = artifacts.require('../contracts/ownership/Ownable.sol');
|
||||
|
||||
contract('Ownable', function(accounts) {
|
||||
contract('Ownable', function (accounts) {
|
||||
let ownable;
|
||||
|
||||
beforeEach(async function() {
|
||||
beforeEach(async function () {
|
||||
ownable = await Ownable.new();
|
||||
});
|
||||
|
||||
it('should have an owner', async function() {
|
||||
it('should have an owner', async function () {
|
||||
let owner = await ownable.owner();
|
||||
assert.isTrue(owner !== 0);
|
||||
});
|
||||
|
||||
it('changes owner after transfer', async function() {
|
||||
it('changes owner after transfer', async function () {
|
||||
let other = accounts[1];
|
||||
await ownable.transferOwnership(other);
|
||||
let owner = await ownable.owner();
|
||||
@ -23,26 +23,25 @@ contract('Ownable', function(accounts) {
|
||||
assert.isTrue(owner === other);
|
||||
});
|
||||
|
||||
it('should prevent non-owners from transfering', async function() {
|
||||
it('should prevent non-owners from transfering', async function () {
|
||||
const other = accounts[2];
|
||||
const owner = await ownable.owner.call();
|
||||
assert.isTrue(owner !== other);
|
||||
try {
|
||||
await ownable.transferOwnership(other, {from: other});
|
||||
await ownable.transferOwnership(other, { from: other });
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
it('should guard ownership against stuck state', async function() {
|
||||
it('should guard ownership against stuck state', async function () {
|
||||
let originalOwner = await ownable.owner();
|
||||
try {
|
||||
await ownable.transferOwnership(null, {from: originalOwner});
|
||||
await ownable.transferOwnership(null, { from: originalOwner });
|
||||
assert.fail();
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@ -1,11 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
const assertRevert = require('./helpers/assertRevert');
|
||||
const PausableMock = artifacts.require('helpers/PausableMock.sol');
|
||||
const PausableMock = artifacts.require('mocks/PausableMock.sol');
|
||||
|
||||
contract('Pausable', function(accounts) {
|
||||
|
||||
it('can perform normal process in non-pause', async function() {
|
||||
contract('Pausable', function (accounts) {
|
||||
it('can perform normal process in non-pause', async function () {
|
||||
let Pausable = await PausableMock.new();
|
||||
let count0 = await Pausable.count();
|
||||
assert.equal(count0, 0);
|
||||
@ -15,7 +13,7 @@ contract('Pausable', function(accounts) {
|
||||
assert.equal(count1, 1);
|
||||
});
|
||||
|
||||
it('can not perform normal process in pause', async function() {
|
||||
it('can not perform normal process in pause', async function () {
|
||||
let Pausable = await PausableMock.new();
|
||||
await Pausable.pause();
|
||||
let count0 = await Pausable.count();
|
||||
@ -24,27 +22,26 @@ contract('Pausable', function(accounts) {
|
||||
try {
|
||||
await Pausable.normalProcess();
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
let count1 = await Pausable.count();
|
||||
assert.equal(count1, 0);
|
||||
});
|
||||
|
||||
|
||||
it('can not take drastic measure in non-pause', async function() {
|
||||
it('can not take drastic measure in non-pause', async function () {
|
||||
let Pausable = await PausableMock.new();
|
||||
try {
|
||||
await Pausable.drasticMeasure();
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
const drasticMeasureTaken = await Pausable.drasticMeasureTaken();
|
||||
assert.isFalse(drasticMeasureTaken);
|
||||
});
|
||||
|
||||
it('can take a drastic measure in a pause', async function() {
|
||||
it('can take a drastic measure in a pause', async function () {
|
||||
let Pausable = await PausableMock.new();
|
||||
await Pausable.pause();
|
||||
await Pausable.drasticMeasure();
|
||||
@ -53,7 +50,7 @@ contract('Pausable', function(accounts) {
|
||||
assert.isTrue(drasticMeasureTaken);
|
||||
});
|
||||
|
||||
it('should resume allowing normal process after pause is over', async function() {
|
||||
it('should resume allowing normal process after pause is over', async function () {
|
||||
let Pausable = await PausableMock.new();
|
||||
await Pausable.pause();
|
||||
await Pausable.unpause();
|
||||
@ -63,19 +60,18 @@ contract('Pausable', function(accounts) {
|
||||
assert.equal(count0, 1);
|
||||
});
|
||||
|
||||
it('should prevent drastic measure after pause is over', async function() {
|
||||
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) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
|
||||
const drasticMeasureTaken = await Pausable.drasticMeasureTaken();
|
||||
assert.isFalse(drasticMeasureTaken);
|
||||
});
|
||||
|
||||
});
|
||||
@ -1,29 +1,29 @@
|
||||
'user strict';
|
||||
|
||||
const assertRevert = require('./helpers/assertRevert');
|
||||
var PausableTokenMock = artifacts.require('./helpers/PausableTokenMock.sol');
|
||||
var PausableTokenMock = artifacts.require('mocks/PausableTokenMock.sol');
|
||||
|
||||
contract('PausableToken', function(accounts) {
|
||||
contract('PausableToken', function (accounts) {
|
||||
let token;
|
||||
|
||||
beforeEach(async function() {
|
||||
beforeEach(async function () {
|
||||
token = await PausableTokenMock.new(accounts[0], 100);
|
||||
});
|
||||
|
||||
it('should return paused false after construction', async function() {
|
||||
it('should return paused false after construction', async function () {
|
||||
let paused = await token.paused();
|
||||
|
||||
assert.equal(paused, false);
|
||||
});
|
||||
|
||||
it('should return paused true after pause', async function() {
|
||||
it('should return paused true after pause', async function () {
|
||||
await token.pause();
|
||||
let paused = await token.paused();
|
||||
|
||||
assert.equal(paused, true);
|
||||
});
|
||||
|
||||
it('should return paused false after pause and unpause', async function() {
|
||||
it('should return paused false after pause and unpause', async function () {
|
||||
await token.pause();
|
||||
await token.unpause();
|
||||
let paused = await token.paused();
|
||||
@ -31,7 +31,7 @@ contract('PausableToken', function(accounts) {
|
||||
assert.equal(paused, false);
|
||||
});
|
||||
|
||||
it('should be able to transfer if transfers are unpaused', async function() {
|
||||
it('should be able to transfer if transfers are unpaused', async function () {
|
||||
await token.transfer(accounts[1], 100);
|
||||
let balance0 = await token.balanceOf(accounts[0]);
|
||||
assert.equal(balance0, 0);
|
||||
@ -40,7 +40,7 @@ contract('PausableToken', function(accounts) {
|
||||
assert.equal(balance1, 100);
|
||||
});
|
||||
|
||||
it('should be able to transfer after transfers are paused and unpaused', async function() {
|
||||
it('should be able to transfer after transfers are paused and unpaused', async function () {
|
||||
await token.pause();
|
||||
await token.unpause();
|
||||
await token.transfer(accounts[1], 100);
|
||||
@ -51,7 +51,7 @@ contract('PausableToken', function(accounts) {
|
||||
assert.equal(balance1, 100);
|
||||
});
|
||||
|
||||
it('should throw an error trying to transfer while transactions are paused', async function() {
|
||||
it('should throw an error trying to transfer while transactions are paused', async function () {
|
||||
await token.pause();
|
||||
try {
|
||||
await token.transfer(accounts[1], 100);
|
||||
@ -61,7 +61,7 @@ contract('PausableToken', function(accounts) {
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw an error trying to transfer from another account while transactions are paused', async function() {
|
||||
it('should throw an error trying to transfer from another account while transactions are paused', async function () {
|
||||
await token.pause();
|
||||
try {
|
||||
await token.transferFrom(accounts[0], accounts[1], 100);
|
||||
@ -70,4 +70,4 @@ contract('PausableToken', function(accounts) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
@ -1,20 +1,20 @@
|
||||
var PullPaymentMock = artifacts.require("./helpers/PullPaymentMock.sol");
|
||||
var PullPaymentMock = artifacts.require('mocks/PullPaymentMock.sol');
|
||||
|
||||
contract('PullPayment', function(accounts) {
|
||||
contract('PullPayment', function (accounts) {
|
||||
let ppce;
|
||||
let amount = 17*1e18;
|
||||
let amount = 17 * 1e18;
|
||||
|
||||
beforeEach(async function() {
|
||||
ppce = await PullPaymentMock.new({value: amount});
|
||||
beforeEach(async function () {
|
||||
ppce = await PullPaymentMock.new({ value: amount });
|
||||
});
|
||||
|
||||
it("can't call asyncSend externally", async function() {
|
||||
it('can\'t call asyncSend externally', async function () {
|
||||
assert.isUndefined(ppce.asyncSend);
|
||||
});
|
||||
|
||||
it("can record an async payment correctly", async function() {
|
||||
it('can record an async payment correctly', async function () {
|
||||
let AMOUNT = 100;
|
||||
let callSend = await ppce.callSend(accounts[0], AMOUNT);
|
||||
await ppce.callSend(accounts[0], AMOUNT);
|
||||
let paymentsToAccount0 = await ppce.payments(accounts[0]);
|
||||
let totalPayments = await ppce.totalPayments();
|
||||
|
||||
@ -22,9 +22,9 @@ contract('PullPayment', function(accounts) {
|
||||
assert.equal(paymentsToAccount0, AMOUNT);
|
||||
});
|
||||
|
||||
it("can add multiple balances on one account", async function() {
|
||||
let call1 = await ppce.callSend(accounts[0], 200);
|
||||
let call2 = await ppce.callSend(accounts[0], 300);
|
||||
it('can add multiple balances on one account', async function () {
|
||||
await ppce.callSend(accounts[0], 200);
|
||||
await ppce.callSend(accounts[0], 300);
|
||||
let paymentsToAccount0 = await ppce.payments(accounts[0]);
|
||||
let totalPayments = await ppce.totalPayments();
|
||||
|
||||
@ -32,9 +32,9 @@ contract('PullPayment', function(accounts) {
|
||||
assert.equal(paymentsToAccount0, 500);
|
||||
});
|
||||
|
||||
it("can add balances on multiple accounts", async function() {
|
||||
let call1 = await ppce.callSend(accounts[0], 200);
|
||||
let call2 = await ppce.callSend(accounts[1], 300);
|
||||
it('can add balances on multiple accounts', async function () {
|
||||
await ppce.callSend(accounts[0], 200);
|
||||
await ppce.callSend(accounts[1], 300);
|
||||
|
||||
let paymentsToAccount0 = await ppce.payments(accounts[0]);
|
||||
assert.equal(paymentsToAccount0, 200);
|
||||
@ -46,11 +46,11 @@ contract('PullPayment', function(accounts) {
|
||||
assert.equal(totalPayments, 500);
|
||||
});
|
||||
|
||||
it("can withdraw payment", async function() {
|
||||
it('can withdraw payment', async function () {
|
||||
let payee = accounts[1];
|
||||
let initialBalance = web3.eth.getBalance(payee);
|
||||
|
||||
let call1 = await ppce.callSend(payee, amount);
|
||||
await ppce.callSend(payee, amount);
|
||||
|
||||
let payment1 = await ppce.payments(payee);
|
||||
assert.equal(payment1, amount);
|
||||
@ -58,7 +58,7 @@ contract('PullPayment', function(accounts) {
|
||||
let totalPayments = await ppce.totalPayments();
|
||||
assert.equal(totalPayments, amount);
|
||||
|
||||
let withdraw = await ppce.withdrawPayments({from: payee});
|
||||
await ppce.withdrawPayments({ from: payee });
|
||||
let payment2 = await ppce.payments(payee);
|
||||
assert.equal(payment2, 0);
|
||||
|
||||
@ -66,7 +66,6 @@ contract('PullPayment', function(accounts) {
|
||||
assert.equal(totalPayments, 0);
|
||||
|
||||
let balance = web3.eth.getBalance(payee);
|
||||
assert(Math.abs(balance-initialBalance-amount) < 1e16);
|
||||
assert(Math.abs(balance - initialBalance - amount) < 1e16);
|
||||
});
|
||||
|
||||
});
|
||||
98
test/RBAC.test.js
Normal file
98
test/RBAC.test.js
Normal file
@ -0,0 +1,98 @@
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
import expectEvent from './helpers/expectEvent';
|
||||
|
||||
const RBACMock = artifacts.require('mocks/RBACMock.sol');
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.should();
|
||||
|
||||
const ROLE_ADVISOR = 'advisor';
|
||||
|
||||
contract('RBAC', function (accounts) {
|
||||
let mock;
|
||||
|
||||
const [
|
||||
admin,
|
||||
anyone,
|
||||
futureAdvisor,
|
||||
...advisors
|
||||
] = accounts;
|
||||
|
||||
before(async () => {
|
||||
mock = await RBACMock.new(advisors, { from: admin });
|
||||
});
|
||||
|
||||
context('in normal conditions', () => {
|
||||
it('allows admin to call #onlyAdminsCanDoThis', async () => {
|
||||
await mock.onlyAdminsCanDoThis({ from: admin })
|
||||
.should.be.fulfilled;
|
||||
});
|
||||
it('allows admin to call #onlyAdvisorsCanDoThis', async () => {
|
||||
await mock.onlyAdvisorsCanDoThis({ from: admin })
|
||||
.should.be.fulfilled;
|
||||
});
|
||||
it('allows advisors to call #onlyAdvisorsCanDoThis', async () => {
|
||||
await mock.onlyAdvisorsCanDoThis({ from: advisors[0] })
|
||||
.should.be.fulfilled;
|
||||
});
|
||||
it('allows admin to call #eitherAdminOrAdvisorCanDoThis', async () => {
|
||||
await mock.eitherAdminOrAdvisorCanDoThis({ from: admin })
|
||||
.should.be.fulfilled;
|
||||
});
|
||||
it('allows advisors to call #eitherAdminOrAdvisorCanDoThis', async () => {
|
||||
await mock.eitherAdminOrAdvisorCanDoThis({ from: advisors[0] })
|
||||
.should.be.fulfilled;
|
||||
});
|
||||
it('does not allow admins to call #nobodyCanDoThis', async () => {
|
||||
expectThrow(
|
||||
mock.nobodyCanDoThis({ from: admin })
|
||||
);
|
||||
});
|
||||
it('does not allow advisors to call #nobodyCanDoThis', async () => {
|
||||
expectThrow(
|
||||
mock.nobodyCanDoThis({ from: advisors[0] })
|
||||
);
|
||||
});
|
||||
it('does not allow anyone to call #nobodyCanDoThis', async () => {
|
||||
expectThrow(
|
||||
mock.nobodyCanDoThis({ from: anyone })
|
||||
);
|
||||
});
|
||||
it('allows an admin to remove an advisor\'s role', async () => {
|
||||
await mock.removeAdvisor(advisors[0], { from: admin })
|
||||
.should.be.fulfilled;
|
||||
});
|
||||
it('allows admins to #adminRemoveRole', async () => {
|
||||
await mock.adminRemoveRole(advisors[3], ROLE_ADVISOR, { from: admin })
|
||||
.should.be.fulfilled;
|
||||
});
|
||||
|
||||
it('announces a RoleAdded event on addRole', async () => {
|
||||
expectEvent.inTransaction(
|
||||
mock.adminAddRole(futureAdvisor, ROLE_ADVISOR, { from: admin }),
|
||||
'RoleAdded'
|
||||
);
|
||||
});
|
||||
|
||||
it('announces a RoleRemoved event on removeRole', async () => {
|
||||
expectEvent.inTransaction(
|
||||
mock.adminRemoveRole(futureAdvisor, ROLE_ADVISOR, { from: admin }),
|
||||
'RoleRemoved'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('in adversarial conditions', () => {
|
||||
it('does not allow an advisor to remove another advisor', async () => {
|
||||
expectThrow(
|
||||
mock.removeAdvisor(advisors[1], { from: advisors[0] })
|
||||
);
|
||||
});
|
||||
it('does not allow "anyone" to remove an advisor', async () => {
|
||||
expectThrow(
|
||||
mock.removeAdvisor(advisors[0], { from: anyone })
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,18 +1,18 @@
|
||||
'use strict';
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
const ReentrancyMock = artifacts.require('./helper/ReentrancyMock.sol');
|
||||
const ReentrancyAttack = artifacts.require('./helper/ReentrancyAttack.sol');
|
||||
|
||||
contract('ReentrancyGuard', function(accounts) {
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
const ReentrancyMock = artifacts.require('./mocks/ReentrancyMock.sol');
|
||||
const ReentrancyAttack = artifacts.require('./mocks/ReentrancyAttack.sol');
|
||||
|
||||
contract('ReentrancyGuard', function (accounts) {
|
||||
let reentrancyMock;
|
||||
|
||||
beforeEach(async function() {
|
||||
beforeEach(async function () {
|
||||
reentrancyMock = await ReentrancyMock.new();
|
||||
let initialCounter = await reentrancyMock.counter();
|
||||
assert.equal(initialCounter, 0);
|
||||
});
|
||||
|
||||
it('should not allow remote callback', async function() {
|
||||
it('should not allow remote callback', async function () {
|
||||
let attacker = await ReentrancyAttack.new();
|
||||
await expectThrow(reentrancyMock.countAndCall(attacker.address));
|
||||
});
|
||||
@ -21,11 +21,11 @@ contract('ReentrancyGuard', function(accounts) {
|
||||
// I put them here as documentation, and to monitor any changes
|
||||
// in the side-effects.
|
||||
|
||||
it('should not allow local recursion', async function() {
|
||||
it('should not allow local recursion', async function () {
|
||||
await expectThrow(reentrancyMock.countLocalRecursive(10));
|
||||
});
|
||||
|
||||
it('should not allow indirect local recursion', async function() {
|
||||
it('should not allow indirect local recursion', async function () {
|
||||
await expectThrow(reentrancyMock.countThisRecursive(10));
|
||||
});
|
||||
});
|
||||
@ -1,61 +0,0 @@
|
||||
const BigNumber = web3.BigNumber
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should()
|
||||
|
||||
import ether from './helpers/ether'
|
||||
import EVMRevert from './helpers/EVMRevert'
|
||||
|
||||
const RefundVault = artifacts.require('RefundVault')
|
||||
|
||||
contract('RefundVault', function ([_, owner, wallet, investor]) {
|
||||
|
||||
const value = ether(42)
|
||||
|
||||
beforeEach(async function () {
|
||||
this.vault = await RefundVault.new(wallet, {from: owner})
|
||||
})
|
||||
|
||||
it('should accept contributions', async function () {
|
||||
await this.vault.deposit(investor, {value, from: owner}).should.be.fulfilled
|
||||
})
|
||||
|
||||
it('should not refund contribution during active state', async function () {
|
||||
await this.vault.deposit(investor, {value, from: owner})
|
||||
await this.vault.refund(investor).should.be.rejectedWith(EVMRevert)
|
||||
})
|
||||
|
||||
it('only owner can enter refund mode', async function () {
|
||||
await this.vault.enableRefunds({from: _}).should.be.rejectedWith(EVMRevert)
|
||||
await this.vault.enableRefunds({from: owner}).should.be.fulfilled
|
||||
})
|
||||
|
||||
it('should refund contribution after entering refund mode', async function () {
|
||||
await this.vault.deposit(investor, {value, from: owner})
|
||||
await this.vault.enableRefunds({from: owner})
|
||||
|
||||
const pre = web3.eth.getBalance(investor)
|
||||
await this.vault.refund(investor)
|
||||
const post = web3.eth.getBalance(investor)
|
||||
|
||||
post.minus(pre).should.be.bignumber.equal(value)
|
||||
})
|
||||
|
||||
it('only owner can close', async function () {
|
||||
await this.vault.close({from: _}).should.be.rejectedWith(EVMRevert)
|
||||
await this.vault.close({from: owner}).should.be.fulfilled
|
||||
})
|
||||
|
||||
it('should forward funds to wallet after closing', async function () {
|
||||
await this.vault.deposit(investor, {value, from: owner})
|
||||
|
||||
const pre = web3.eth.getBalance(wallet)
|
||||
await this.vault.close({from: owner})
|
||||
const post = web3.eth.getBalance(wallet)
|
||||
|
||||
post.minus(pre).should.be.bignumber.equal(value)
|
||||
})
|
||||
|
||||
})
|
||||
59
test/RefundVault.test.js
Normal file
59
test/RefundVault.test.js
Normal file
@ -0,0 +1,59 @@
|
||||
import ether from './helpers/ether';
|
||||
import EVMRevert from './helpers/EVMRevert';
|
||||
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const RefundVault = artifacts.require('RefundVault');
|
||||
|
||||
contract('RefundVault', function ([_, owner, wallet, investor]) {
|
||||
const value = ether(42);
|
||||
|
||||
beforeEach(async function () {
|
||||
this.vault = await RefundVault.new(wallet, { from: owner });
|
||||
});
|
||||
|
||||
it('should accept contributions', async function () {
|
||||
await this.vault.deposit(investor, { value, from: owner }).should.be.fulfilled;
|
||||
});
|
||||
|
||||
it('should not refund contribution during active state', async function () {
|
||||
await this.vault.deposit(investor, { value, from: owner });
|
||||
await this.vault.refund(investor).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('only owner can enter refund mode', async function () {
|
||||
await this.vault.enableRefunds({ from: _ }).should.be.rejectedWith(EVMRevert);
|
||||
await this.vault.enableRefunds({ from: owner }).should.be.fulfilled;
|
||||
});
|
||||
|
||||
it('should refund contribution after entering refund mode', async function () {
|
||||
await this.vault.deposit(investor, { value, from: owner });
|
||||
await this.vault.enableRefunds({ from: owner });
|
||||
|
||||
const pre = web3.eth.getBalance(investor);
|
||||
await this.vault.refund(investor);
|
||||
const post = web3.eth.getBalance(investor);
|
||||
|
||||
post.minus(pre).should.be.bignumber.equal(value);
|
||||
});
|
||||
|
||||
it('only owner can close', async function () {
|
||||
await this.vault.close({ from: _ }).should.be.rejectedWith(EVMRevert);
|
||||
await this.vault.close({ from: owner }).should.be.fulfilled;
|
||||
});
|
||||
|
||||
it('should forward funds to wallet after closing', async function () {
|
||||
await this.vault.deposit(investor, { value, from: owner });
|
||||
|
||||
const pre = web3.eth.getBalance(wallet);
|
||||
await this.vault.close({ from: owner });
|
||||
const post = web3.eth.getBalance(wallet);
|
||||
|
||||
post.minus(pre).should.be.bignumber.equal(value);
|
||||
});
|
||||
});
|
||||
@ -1,83 +0,0 @@
|
||||
import ether from './helpers/ether'
|
||||
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
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should()
|
||||
|
||||
const RefundableCrowdsale = artifacts.require('./helpers/RefundableCrowdsaleImpl.sol')
|
||||
|
||||
contract('RefundableCrowdsale', function ([_, owner, wallet, investor]) {
|
||||
|
||||
const rate = new BigNumber(1000)
|
||||
const goal = ether(800)
|
||||
const lessThanGoal = ether(750)
|
||||
|
||||
before(async function() {
|
||||
//Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
|
||||
await advanceBlock()
|
||||
})
|
||||
|
||||
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 RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, goal, {from: owner})
|
||||
})
|
||||
|
||||
describe('creating a valid crowdsale', function () {
|
||||
|
||||
it('should fail with zero goal', async function () {
|
||||
await RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0, {from: owner}).should.be.rejectedWith(EVMRevert);
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
it('should deny refunds before end', async function () {
|
||||
await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMRevert)
|
||||
await increaseTimeTo(this.startTime)
|
||||
await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMRevert)
|
||||
})
|
||||
|
||||
it('should deny refunds after end if goal was reached', async function () {
|
||||
await increaseTimeTo(this.startTime)
|
||||
await this.crowdsale.sendTransaction({value: goal, from: investor})
|
||||
await increaseTimeTo(this.afterEndTime)
|
||||
await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMRevert)
|
||||
})
|
||||
|
||||
it('should allow refunds after end if goal was not reached', async function () {
|
||||
await increaseTimeTo(this.startTime)
|
||||
await this.crowdsale.sendTransaction({value: lessThanGoal, from: investor})
|
||||
await increaseTimeTo(this.afterEndTime)
|
||||
|
||||
await this.crowdsale.finalize({from: owner})
|
||||
|
||||
const pre = web3.eth.getBalance(investor)
|
||||
await this.crowdsale.claimRefund({from: investor, gasPrice: 0})
|
||||
.should.be.fulfilled
|
||||
const post = web3.eth.getBalance(investor)
|
||||
|
||||
post.minus(pre).should.be.bignumber.equal(lessThanGoal)
|
||||
})
|
||||
|
||||
it('should forward funds to wallet after end if goal was reached', async function () {
|
||||
await increaseTimeTo(this.startTime)
|
||||
await this.crowdsale.sendTransaction({value: goal, from: investor})
|
||||
await increaseTimeTo(this.afterEndTime)
|
||||
|
||||
const pre = web3.eth.getBalance(wallet)
|
||||
await this.crowdsale.finalize({from: owner})
|
||||
const post = web3.eth.getBalance(wallet)
|
||||
|
||||
post.minus(pre).should.be.bignumber.equal(goal)
|
||||
})
|
||||
|
||||
})
|
||||
80
test/RefundableCrowdsale.test.js
Normal file
80
test/RefundableCrowdsale.test.js
Normal file
@ -0,0 +1,80 @@
|
||||
import ether from './helpers/ether';
|
||||
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;
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const RefundableCrowdsale = artifacts.require('mocks/RefundableCrowdsaleImpl.sol');
|
||||
|
||||
contract('RefundableCrowdsale', function ([_, owner, wallet, investor]) {
|
||||
const rate = new BigNumber(1000);
|
||||
const goal = ether(800);
|
||||
const lessThanGoal = ether(750);
|
||||
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
|
||||
await advanceBlock();
|
||||
});
|
||||
|
||||
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 RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, goal, { from: owner });
|
||||
});
|
||||
|
||||
describe('creating a valid crowdsale', function () {
|
||||
it('should fail with zero goal', async function () {
|
||||
await RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0, { from: owner })
|
||||
.should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
});
|
||||
|
||||
it('should deny refunds before end', async function () {
|
||||
await this.crowdsale.claimRefund({ from: investor }).should.be.rejectedWith(EVMRevert);
|
||||
await increaseTimeTo(this.startTime);
|
||||
await this.crowdsale.claimRefund({ from: investor }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('should deny refunds after end if goal was reached', async function () {
|
||||
await increaseTimeTo(this.startTime);
|
||||
await this.crowdsale.sendTransaction({ value: goal, from: investor });
|
||||
await increaseTimeTo(this.afterEndTime);
|
||||
await this.crowdsale.claimRefund({ from: investor }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('should allow refunds after end if goal was not reached', async function () {
|
||||
await increaseTimeTo(this.startTime);
|
||||
await this.crowdsale.sendTransaction({ value: lessThanGoal, from: investor });
|
||||
await increaseTimeTo(this.afterEndTime);
|
||||
|
||||
await this.crowdsale.finalize({ from: owner });
|
||||
|
||||
const pre = web3.eth.getBalance(investor);
|
||||
await this.crowdsale.claimRefund({ from: investor, gasPrice: 0 })
|
||||
.should.be.fulfilled;
|
||||
const post = web3.eth.getBalance(investor);
|
||||
|
||||
post.minus(pre).should.be.bignumber.equal(lessThanGoal);
|
||||
});
|
||||
|
||||
it('should forward funds to wallet after end if goal was reached', async function () {
|
||||
await increaseTimeTo(this.startTime);
|
||||
await this.crowdsale.sendTransaction({ value: goal, from: investor });
|
||||
await increaseTimeTo(this.afterEndTime);
|
||||
|
||||
const pre = web3.eth.getBalance(wallet);
|
||||
await this.crowdsale.finalize({ from: owner });
|
||||
const post = web3.eth.getBalance(wallet);
|
||||
|
||||
post.minus(pre).should.be.bignumber.equal(goal);
|
||||
});
|
||||
});
|
||||
@ -4,10 +4,9 @@ require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.should();
|
||||
|
||||
const SafeERC20Helper = artifacts.require('./helpers/SafeERC20Helper.sol');
|
||||
const SafeERC20Helper = artifacts.require('mocks/SafeERC20Helper.sol');
|
||||
|
||||
contract('SafeERC20', function () {
|
||||
|
||||
beforeEach(async function () {
|
||||
this.helper = await SafeERC20Helper.new();
|
||||
});
|
||||
@ -1,72 +1,70 @@
|
||||
const assertRevert = require('./helpers/assertRevert');
|
||||
const assertJump = require('./helpers/assertJump');
|
||||
var SafeMathMock = artifacts.require("./helpers/SafeMathMock.sol");
|
||||
|
||||
contract('SafeMath', function(accounts) {
|
||||
var SafeMathMock = artifacts.require('mocks/SafeMathMock.sol');
|
||||
|
||||
contract('SafeMath', function (accounts) {
|
||||
let safeMath;
|
||||
|
||||
before(async function() {
|
||||
before(async function () {
|
||||
safeMath = await SafeMathMock.new();
|
||||
});
|
||||
|
||||
it("multiplies correctly", async function() {
|
||||
it('multiplies correctly', async function () {
|
||||
let a = 5678;
|
||||
let b = 1234;
|
||||
let mult = await safeMath.multiply(a, b);
|
||||
await safeMath.multiply(a, b);
|
||||
let result = await safeMath.result();
|
||||
assert.equal(result, a*b);
|
||||
assert.equal(result, a * b);
|
||||
});
|
||||
|
||||
it("adds correctly", async function() {
|
||||
it('adds correctly', async function () {
|
||||
let a = 5678;
|
||||
let b = 1234;
|
||||
let add = await safeMath.add(a, b);
|
||||
await safeMath.add(a, b);
|
||||
let result = await safeMath.result();
|
||||
|
||||
assert.equal(result, a+b);
|
||||
assert.equal(result, a + b);
|
||||
});
|
||||
|
||||
it("subtracts correctly", async function() {
|
||||
it('subtracts correctly', async function () {
|
||||
let a = 5678;
|
||||
let b = 1234;
|
||||
let subtract = await safeMath.subtract(a, b);
|
||||
await safeMath.subtract(a, b);
|
||||
let result = await safeMath.result();
|
||||
|
||||
assert.equal(result, a-b);
|
||||
assert.equal(result, a - b);
|
||||
});
|
||||
|
||||
it("should throw an error if subtraction result would be negative", async function () {
|
||||
it('should throw an error if subtraction result would be negative', async function () {
|
||||
let a = 1234;
|
||||
let b = 5678;
|
||||
try {
|
||||
let subtract = await safeMath.subtract(a, b);
|
||||
await safeMath.subtract(a, b);
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertJump(error);
|
||||
}
|
||||
});
|
||||
|
||||
it("should throw an error on addition overflow", async function() {
|
||||
it('should throw an error on addition overflow', async function () {
|
||||
let a = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
|
||||
let b = 1;
|
||||
try {
|
||||
let add = await safeMath.add(a, b);
|
||||
await safeMath.add(a, b);
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
it("should throw an error on multiplication overflow", async function() {
|
||||
it('should throw an error on multiplication overflow', async function () {
|
||||
let a = 115792089237316195423570985008687907853269984665640564039457584007913129639933;
|
||||
let b = 2;
|
||||
try {
|
||||
let multiply = await safeMath.multiply(a, b);
|
||||
await safeMath.multiply(a, b);
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@ -1,12 +1,12 @@
|
||||
import ether from './helpers/ether'
|
||||
import {advanceBlock} from './helpers/advanceToBlock'
|
||||
import {increaseTimeTo, duration} from './helpers/increaseTime'
|
||||
import latestTime from './helpers/latestTime'
|
||||
import EVMRevert from './helpers/EVMRevert'
|
||||
import ether from './helpers/ether';
|
||||
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;
|
||||
|
||||
const should = require('chai')
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
@ -14,42 +14,47 @@ const should = require('chai')
|
||||
const SampleCrowdsale = artifacts.require('SampleCrowdsale');
|
||||
const SampleCrowdsaleToken = artifacts.require('SampleCrowdsaleToken');
|
||||
|
||||
contract('Crowdsale', function ([owner, wallet, investor]) {
|
||||
|
||||
contract('SampleCrowdsale', function ([owner, wallet, investor]) {
|
||||
const RATE = new BigNumber(10);
|
||||
const GOAL = ether(10);
|
||||
const CAP = ether(20);
|
||||
const CAP = ether(20);
|
||||
|
||||
before(async function() {
|
||||
//Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
|
||||
await advanceBlock()
|
||||
})
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
|
||||
await advanceBlock();
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
this.startTime = latestTime() + duration.weeks(1);
|
||||
this.endTime = this.startTime + duration.weeks(1);
|
||||
this.endTime = this.startTime + duration.weeks(1);
|
||||
this.afterEndTime = this.endTime + duration.seconds(1);
|
||||
|
||||
this.crowdsale = await SampleCrowdsale.new(this.startTime, this.endTime, RATE, GOAL, CAP, wallet);
|
||||
this.token = SampleCrowdsaleToken.at(await this.crowdsale.token());
|
||||
});
|
||||
|
||||
|
||||
it('should create crowdsale with correct parameters', async function () {
|
||||
this.crowdsale.should.exist;
|
||||
this.token.should.exist;
|
||||
|
||||
(await this.crowdsale.startTime()).should.be.bignumber.equal(this.startTime);
|
||||
(await this.crowdsale.endTime()).should.be.bignumber.equal(this.endTime);
|
||||
(await this.crowdsale.rate()).should.be.bignumber.equal(RATE);
|
||||
(await this.crowdsale.wallet()).should.be.equal(wallet);
|
||||
(await this.crowdsale.goal()).should.be.bignumber.equal(GOAL);
|
||||
(await this.crowdsale.cap()).should.be.bignumber.equal(CAP);
|
||||
const startTime = await this.crowdsale.startTime();
|
||||
const endTime = await this.crowdsale.endTime();
|
||||
const rate = await this.crowdsale.rate();
|
||||
const walletAddress = await this.crowdsale.wallet();
|
||||
const goal = await this.crowdsale.goal();
|
||||
const cap = await this.crowdsale.cap();
|
||||
|
||||
startTime.should.be.bignumber.equal(this.startTime);
|
||||
endTime.should.be.bignumber.equal(this.endTime);
|
||||
rate.should.be.bignumber.equal(RATE);
|
||||
walletAddress.should.be.equal(wallet);
|
||||
goal.should.be.bignumber.equal(GOAL);
|
||||
cap.should.be.bignumber.equal(CAP);
|
||||
});
|
||||
|
||||
it('should not accept payments before start', async function () {
|
||||
await this.crowdsale.send(ether(1)).should.be.rejectedWith(EVMRevert);
|
||||
await this.crowdsale.buyTokens(investor, {from: investor, value: ether(1)}).should.be.rejectedWith(EVMRevert);
|
||||
await this.crowdsale.buyTokens(investor, { from: investor, value: ether(1) }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('should accept payments during the sale', async function () {
|
||||
@ -57,7 +62,7 @@ contract('Crowdsale', function ([owner, wallet, investor]) {
|
||||
const expectedTokenAmount = RATE.mul(investmentAmount);
|
||||
|
||||
await increaseTimeTo(this.startTime);
|
||||
await this.crowdsale.buyTokens(investor, {value: investmentAmount, from: investor}).should.be.fulfilled;
|
||||
await this.crowdsale.buyTokens(investor, { value: investmentAmount, from: investor }).should.be.fulfilled;
|
||||
|
||||
(await this.token.balanceOf(investor)).should.be.bignumber.equal(expectedTokenAmount);
|
||||
(await this.token.totalSupply()).should.be.bignumber.equal(expectedTokenAmount);
|
||||
@ -66,7 +71,7 @@ contract('Crowdsale', function ([owner, wallet, investor]) {
|
||||
it('should reject payments after end', async function () {
|
||||
await increaseTimeTo(this.afterEnd);
|
||||
await this.crowdsale.send(ether(1)).should.be.rejectedWith(EVMRevert);
|
||||
await this.crowdsale.buyTokens(investor, {value: ether(1), from: investor}).should.be.rejectedWith(EVMRevert);
|
||||
await this.crowdsale.buyTokens(investor, { value: ether(1), from: investor }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
it('should reject payments over cap', async function () {
|
||||
@ -81,7 +86,7 @@ contract('Crowdsale', function ([owner, wallet, investor]) {
|
||||
|
||||
const beforeFinalization = web3.eth.getBalance(wallet);
|
||||
await increaseTimeTo(this.afterEndTime);
|
||||
await this.crowdsale.finalize({from: owner});
|
||||
await this.crowdsale.finalize({ from: owner });
|
||||
const afterFinalization = web3.eth.getBalance(wallet);
|
||||
|
||||
afterFinalization.minus(beforeFinalization).should.be.bignumber.equal(GOAL);
|
||||
@ -91,14 +96,13 @@ contract('Crowdsale', function ([owner, wallet, investor]) {
|
||||
const balanceBeforeInvestment = web3.eth.getBalance(investor);
|
||||
|
||||
await increaseTimeTo(this.startTime);
|
||||
await this.crowdsale.sendTransaction({value: ether(1), from: investor, gasPrice: 0});
|
||||
await this.crowdsale.sendTransaction({ value: ether(1), from: investor, gasPrice: 0 });
|
||||
await increaseTimeTo(this.afterEndTime);
|
||||
|
||||
await this.crowdsale.finalize({from: owner});
|
||||
await this.crowdsale.claimRefund({from: investor, gasPrice: 0}).should.be.fulfilled;
|
||||
await this.crowdsale.finalize({ from: owner });
|
||||
await this.crowdsale.claimRefund({ from: investor, gasPrice: 0 }).should.be.fulfilled;
|
||||
|
||||
const balanceAfterRefund = web3.eth.getBalance(investor);
|
||||
balanceBeforeInvestment.should.be.bignumber.equal(balanceAfterRefund);
|
||||
});
|
||||
|
||||
});
|
||||
@ -1,78 +0,0 @@
|
||||
const BigNumber = web3.BigNumber
|
||||
|
||||
const should = require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should()
|
||||
|
||||
const EVMThrow = require('./helpers/EVMThrow.js')
|
||||
const SplitPaymentMock = artifacts.require('./helpers/SplitPaymentMock.sol')
|
||||
|
||||
contract('SplitPayment', function ([owner, payee1, payee2, payee3, nonpayee1, payer1]) {
|
||||
const amount = web3.toWei(1.0, 'ether')
|
||||
|
||||
beforeEach(async function () {
|
||||
this.payees = [payee1, payee2, payee3]
|
||||
this.shares = [20, 10, 70]
|
||||
|
||||
this.contract = await SplitPaymentMock.new(this.payees, this.shares)
|
||||
})
|
||||
|
||||
it('should accept payments', async function () {
|
||||
await web3.eth.sendTransaction({ from: owner, to: this.contract.address, value: amount })
|
||||
|
||||
const balance = web3.eth.getBalance(this.contract.address)
|
||||
balance.should.be.bignumber.equal(amount)
|
||||
})
|
||||
|
||||
it('should store shares if address is payee', async function () {
|
||||
const shares = await this.contract.shares.call(payee1)
|
||||
shares.should.be.bignumber.not.equal(0)
|
||||
})
|
||||
|
||||
it('should not store shares if address is not payee', async function () {
|
||||
const shares = await this.contract.shares.call(nonpayee1)
|
||||
shares.should.be.bignumber.equal(0)
|
||||
})
|
||||
|
||||
it('should throw if no funds to claim', async function () {
|
||||
await this.contract.claim({from: payee1}).should.be.rejectedWith(EVMThrow)
|
||||
})
|
||||
|
||||
it('should throw if non-payee want to claim', async function () {
|
||||
await web3.eth.sendTransaction({from: payer1, to: this.contract.address, value: amount})
|
||||
await this.contract.claim({from: nonpayee1}).should.be.rejectedWith(EVMThrow)
|
||||
})
|
||||
|
||||
it('should distribute funds to payees', async function () {
|
||||
await web3.eth.sendTransaction({from: payer1, to: this.contract.address, value: amount})
|
||||
|
||||
// receive funds
|
||||
const initBalance = web3.eth.getBalance(this.contract.address)
|
||||
initBalance.should.be.bignumber.equal(amount)
|
||||
|
||||
// distribute to payees
|
||||
const initAmount1 = web3.eth.getBalance(payee1)
|
||||
await this.contract.claim({from: payee1})
|
||||
const profit1 = web3.eth.getBalance(payee1) - initAmount1
|
||||
assert(Math.abs(profit1 - web3.toWei(0.20, 'ether')) < 1e16)
|
||||
|
||||
const initAmount2 = web3.eth.getBalance(payee2)
|
||||
await this.contract.claim({from: payee2})
|
||||
const profit2 = web3.eth.getBalance(payee2) - initAmount2
|
||||
assert(Math.abs(profit2 - web3.toWei(0.10, 'ether')) < 1e16)
|
||||
|
||||
const initAmount3 = web3.eth.getBalance(payee3)
|
||||
await this.contract.claim({from: payee3})
|
||||
const profit3 = web3.eth.getBalance(payee3) - initAmount3
|
||||
assert(Math.abs(profit3 - web3.toWei(0.70, 'ether')) < 1e16)
|
||||
|
||||
// end balance should be zero
|
||||
const endBalance = web3.eth.getBalance(this.contract.address)
|
||||
endBalance.should.be.bignumber.equal(0)
|
||||
|
||||
// check correct funds released accounting
|
||||
const totalReleased = await this.contract.totalReleased.call()
|
||||
totalReleased.should.be.bignumber.equal(initBalance)
|
||||
})
|
||||
})
|
||||
78
test/SplitPayment.test.js
Normal file
78
test/SplitPayment.test.js
Normal file
@ -0,0 +1,78 @@
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const EVMThrow = require('./helpers/EVMThrow.js');
|
||||
const SplitPayment = artifacts.require('../contracts/payment/SplitPayment.sol');
|
||||
|
||||
contract('SplitPayment', function ([owner, payee1, payee2, payee3, nonpayee1, payer1]) {
|
||||
const amount = web3.toWei(1.0, 'ether');
|
||||
|
||||
beforeEach(async function () {
|
||||
this.payees = [payee1, payee2, payee3];
|
||||
this.shares = [20, 10, 70];
|
||||
|
||||
this.contract = await SplitPayment.new(this.payees, this.shares);
|
||||
});
|
||||
|
||||
it('should accept payments', async function () {
|
||||
await web3.eth.sendTransaction({ from: owner, to: this.contract.address, value: amount });
|
||||
|
||||
const balance = web3.eth.getBalance(this.contract.address);
|
||||
balance.should.be.bignumber.equal(amount);
|
||||
});
|
||||
|
||||
it('should store shares if address is payee', async function () {
|
||||
const shares = await this.contract.shares.call(payee1);
|
||||
shares.should.be.bignumber.not.equal(0);
|
||||
});
|
||||
|
||||
it('should not store shares if address is not payee', async function () {
|
||||
const shares = await this.contract.shares.call(nonpayee1);
|
||||
shares.should.be.bignumber.equal(0);
|
||||
});
|
||||
|
||||
it('should throw if no funds to claim', async function () {
|
||||
await this.contract.claim({ from: payee1 }).should.be.rejectedWith(EVMThrow);
|
||||
});
|
||||
|
||||
it('should throw if non-payee want to claim', async function () {
|
||||
await web3.eth.sendTransaction({ from: payer1, to: this.contract.address, value: amount });
|
||||
await this.contract.claim({ from: nonpayee1 }).should.be.rejectedWith(EVMThrow);
|
||||
});
|
||||
|
||||
it('should distribute funds to payees', async function () {
|
||||
await web3.eth.sendTransaction({ from: payer1, to: this.contract.address, value: amount });
|
||||
|
||||
// receive funds
|
||||
const initBalance = web3.eth.getBalance(this.contract.address);
|
||||
initBalance.should.be.bignumber.equal(amount);
|
||||
|
||||
// distribute to payees
|
||||
const initAmount1 = web3.eth.getBalance(payee1);
|
||||
await this.contract.claim({ from: payee1 });
|
||||
const profit1 = web3.eth.getBalance(payee1) - initAmount1;
|
||||
assert(Math.abs(profit1 - web3.toWei(0.20, 'ether')) < 1e16);
|
||||
|
||||
const initAmount2 = web3.eth.getBalance(payee2);
|
||||
await this.contract.claim({ from: payee2 });
|
||||
const profit2 = web3.eth.getBalance(payee2) - initAmount2;
|
||||
assert(Math.abs(profit2 - web3.toWei(0.10, 'ether')) < 1e16);
|
||||
|
||||
const initAmount3 = web3.eth.getBalance(payee3);
|
||||
await this.contract.claim({ from: payee3 });
|
||||
const profit3 = web3.eth.getBalance(payee3) - initAmount3;
|
||||
assert(Math.abs(profit3 - web3.toWei(0.70, 'ether')) < 1e16);
|
||||
|
||||
// end balance should be zero
|
||||
const endBalance = web3.eth.getBalance(this.contract.address);
|
||||
endBalance.should.be.bignumber.equal(0);
|
||||
|
||||
// check correct funds released accounting
|
||||
const totalReleased = await this.contract.totalReleased.call();
|
||||
totalReleased.should.be.bignumber.equal(initBalance);
|
||||
});
|
||||
});
|
||||
@ -1,24 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
const assertRevert = require('./helpers/assertRevert');
|
||||
const expectThrow = require('./helpers/expectThrow');
|
||||
var StandardTokenMock = artifacts.require('./helpers/StandardTokenMock.sol');
|
||||
|
||||
contract('StandardToken', function(accounts) {
|
||||
var StandardTokenMock = artifacts.require('mocks/StandardTokenMock.sol');
|
||||
|
||||
contract('StandardToken', function (accounts) {
|
||||
let token;
|
||||
|
||||
beforeEach(async function() {
|
||||
beforeEach(async function () {
|
||||
token = await StandardTokenMock.new(accounts[0], 100);
|
||||
});
|
||||
|
||||
it('should return the correct totalSupply after construction', async function() {
|
||||
it('should return the correct totalSupply after construction', async function () {
|
||||
let totalSupply = await token.totalSupply();
|
||||
|
||||
assert.equal(totalSupply, 100);
|
||||
});
|
||||
|
||||
it('should return the correct allowance amount after approval', async function() {
|
||||
it('should return the correct allowance amount after approval', async function () {
|
||||
let token = await StandardTokenMock.new();
|
||||
await token.approve(accounts[1], 100);
|
||||
let allowance = await token.allowance(accounts[0], accounts[1]);
|
||||
@ -26,7 +24,7 @@ contract('StandardToken', function(accounts) {
|
||||
assert.equal(allowance, 100);
|
||||
});
|
||||
|
||||
it('should return correct balances after transfer', async function() {
|
||||
it('should return correct balances after transfer', async function () {
|
||||
let token = await StandardTokenMock.new(accounts[0], 100);
|
||||
await token.transfer(accounts[1], 100);
|
||||
let balance0 = await token.balanceOf(accounts[0]);
|
||||
@ -36,20 +34,20 @@ contract('StandardToken', function(accounts) {
|
||||
assert.equal(balance1, 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 StandardTokenMock.new(accounts[0], 100);
|
||||
try {
|
||||
await token.transfer(accounts[1], 101);
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
it('should return correct balances after transfering from another account', async function() {
|
||||
it('should return correct balances after transfering from another account', async function () {
|
||||
let token = await StandardTokenMock.new(accounts[0], 100);
|
||||
await token.approve(accounts[1], 100);
|
||||
await token.transferFrom(accounts[0], accounts[2], 100, {from: accounts[1]});
|
||||
await token.transferFrom(accounts[0], accounts[2], 100, { from: accounts[1] });
|
||||
|
||||
let balance0 = await token.balanceOf(accounts[0]);
|
||||
assert.equal(balance0, 0);
|
||||
@ -61,71 +59,70 @@ contract('StandardToken', function(accounts) {
|
||||
assert.equal(balance2, 0);
|
||||
});
|
||||
|
||||
it('should throw an error when trying to transfer more than allowed', async function() {
|
||||
it('should throw an error when trying to transfer more than allowed', async function () {
|
||||
await token.approve(accounts[1], 99);
|
||||
try {
|
||||
await token.transferFrom(accounts[0], accounts[2], 100, {from: accounts[1]});
|
||||
await token.transferFrom(accounts[0], accounts[2], 100, { from: accounts[1] });
|
||||
assert.fail('should have thrown before');
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw an error when trying to transferFrom more than _from has', async function() {
|
||||
it('should throw an error when trying to transferFrom more than _from has', async function () {
|
||||
let balance0 = await token.balanceOf(accounts[0]);
|
||||
await token.approve(accounts[1], 99);
|
||||
try {
|
||||
await token.transferFrom(accounts[0], accounts[2], balance0+1, {from: accounts[1]});
|
||||
await token.transferFrom(accounts[0], accounts[2], balance0 + 1, { from: accounts[1] });
|
||||
assert.fail('should have thrown before');
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
describe('validating allowance updates to spender', function() {
|
||||
describe('validating allowance updates to spender', function () {
|
||||
let preApproved;
|
||||
|
||||
it('should start with zero', async function() {
|
||||
it('should start with zero', async function () {
|
||||
preApproved = await token.allowance(accounts[0], accounts[1]);
|
||||
assert.equal(preApproved, 0);
|
||||
})
|
||||
});
|
||||
|
||||
it('should increase by 50 then decrease by 10', async function() {
|
||||
it('should increase by 50 then decrease by 10', async function () {
|
||||
await token.increaseApproval(accounts[1], 50);
|
||||
let postIncrease = await token.allowance(accounts[0], accounts[1]);
|
||||
preApproved.plus(50).should.be.bignumber.equal(postIncrease);
|
||||
await token.decreaseApproval(accounts[1], 10);
|
||||
let postDecrease = await token.allowance(accounts[0], accounts[1]);
|
||||
postIncrease.minus(10).should.be.bignumber.equal(postDecrease);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it('should increase by 50 then set to 0 when decreasing by more than 50', async function() {
|
||||
it('should increase by 50 then set to 0 when decreasing by more than 50', async function () {
|
||||
await token.approve(accounts[1], 50);
|
||||
await token.decreaseApproval(accounts[1], 60);
|
||||
let postDecrease = await token.allowance(accounts[0], accounts[1]);
|
||||
postDecrease.should.be.bignumber.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error when trying to transfer to 0x0', async function() {
|
||||
it('should throw an error when trying to transfer to 0x0', async function () {
|
||||
let token = await StandardTokenMock.new(accounts[0], 100);
|
||||
try {
|
||||
let transfer = await token.transfer(0x0, 100);
|
||||
await token.transfer(0x0, 100);
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw an error when trying to transferFrom to 0x0', async function() {
|
||||
it('should throw an error when trying to transferFrom to 0x0', async function () {
|
||||
let token = await StandardTokenMock.new(accounts[0], 100);
|
||||
await token.approve(accounts[1], 100);
|
||||
try {
|
||||
let transfer = await token.transferFrom(accounts[0], 0x0, 100, {from: accounts[1]});
|
||||
await token.transferFrom(accounts[0], 0x0, 100, { from: accounts[1] });
|
||||
assert.fail('should have thrown before');
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
assertRevert(error);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@ -1,32 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
var TokenDestructible = artifacts.require('../contracts/lifecycle/TokenDestructible.sol');
|
||||
var StandardTokenMock = artifacts.require("./helpers/StandardTokenMock.sol");
|
||||
var StandardTokenMock = artifacts.require('mocks/StandardTokenMock.sol');
|
||||
require('./helpers/transactionMined.js');
|
||||
|
||||
contract('TokenDestructible', function(accounts) {
|
||||
contract('TokenDestructible', function (accounts) {
|
||||
let destructible;
|
||||
|
||||
beforeEach(async function() {
|
||||
destructible = await TokenDestructible.new({fron: accounts[0], value: web3.toWei('10', 'ether')});
|
||||
beforeEach(async function () {
|
||||
destructible = await TokenDestructible.new({ fron: accounts[0], value: web3.toWei('10', 'ether') });
|
||||
});
|
||||
|
||||
it('should send balance to owner after destruction', async function() {
|
||||
it('should send balance to owner after destruction', async function () {
|
||||
let owner = await destructible.owner();
|
||||
let initBalance = web3.eth.getBalance(owner);
|
||||
await destructible.destroy([], {from: owner});
|
||||
await destructible.destroy([], { from: owner });
|
||||
let newBalance = web3.eth.getBalance(owner);
|
||||
assert.isTrue(newBalance > initBalance);
|
||||
});
|
||||
|
||||
it('should send tokens to owner after destruction', async function() {
|
||||
it('should send tokens to owner after destruction', async function () {
|
||||
let owner = await destructible.owner();
|
||||
let token = await StandardTokenMock.new(destructible.address, 100);
|
||||
let initContractBalance = await token.balanceOf(destructible.address);
|
||||
let initOwnerBalance = await token.balanceOf(owner);
|
||||
assert.equal(initContractBalance, 100);
|
||||
assert.equal(initOwnerBalance, 0);
|
||||
await destructible.destroy([token.address], {from: owner});
|
||||
await destructible.destroy([token.address], { from: owner });
|
||||
let newContractBalance = await token.balanceOf(destructible.address);
|
||||
let newOwnerBalance = await token.balanceOf(owner);
|
||||
assert.equal(newContractBalance, 0);
|
||||
@ -1,57 +0,0 @@
|
||||
const BigNumber = web3.BigNumber
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should()
|
||||
|
||||
|
||||
import latestTime from './helpers/latestTime'
|
||||
import {increaseTimeTo, duration} from './helpers/increaseTime'
|
||||
|
||||
const MintableToken = artifacts.require('MintableToken')
|
||||
const TokenTimelock = artifacts.require('TokenTimelock')
|
||||
|
||||
contract('TokenTimelock', function ([_, owner, beneficiary]) {
|
||||
|
||||
const amount = new BigNumber(100)
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await MintableToken.new({from: owner})
|
||||
this.releaseTime = latestTime() + duration.years(1)
|
||||
this.timelock = await TokenTimelock.new(this.token.address, beneficiary, this.releaseTime)
|
||||
await this.token.mint(this.timelock.address, amount, {from: owner})
|
||||
})
|
||||
|
||||
it('cannot be released before time limit', async function () {
|
||||
await this.timelock.release().should.be.rejected
|
||||
})
|
||||
|
||||
it('cannot be released just before time limit', async function () {
|
||||
await increaseTimeTo(this.releaseTime - duration.seconds(3))
|
||||
await this.timelock.release().should.be.rejected
|
||||
})
|
||||
|
||||
it('can be released just after limit', async function () {
|
||||
await increaseTimeTo(this.releaseTime + duration.seconds(1))
|
||||
await this.timelock.release().should.be.fulfilled
|
||||
const balance = await this.token.balanceOf(beneficiary)
|
||||
balance.should.be.bignumber.equal(amount)
|
||||
})
|
||||
|
||||
it('can be released after time limit', async function () {
|
||||
await increaseTimeTo(this.releaseTime + duration.years(1))
|
||||
await this.timelock.release().should.be.fulfilled
|
||||
const balance = await this.token.balanceOf(beneficiary)
|
||||
balance.should.be.bignumber.equal(amount)
|
||||
})
|
||||
|
||||
it('cannot be released twice', async function () {
|
||||
await increaseTimeTo(this.releaseTime + duration.years(1))
|
||||
await this.timelock.release().should.be.fulfilled
|
||||
await this.timelock.release().should.be.rejected
|
||||
const balance = await this.token.balanceOf(beneficiary)
|
||||
balance.should.be.bignumber.equal(amount)
|
||||
})
|
||||
|
||||
})
|
||||
54
test/TokenTimelock.test.js
Normal file
54
test/TokenTimelock.test.js
Normal file
@ -0,0 +1,54 @@
|
||||
import latestTime from './helpers/latestTime';
|
||||
import { increaseTimeTo, duration } from './helpers/increaseTime';
|
||||
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
const MintableToken = artifacts.require('MintableToken');
|
||||
const TokenTimelock = artifacts.require('TokenTimelock');
|
||||
|
||||
contract('TokenTimelock', function ([_, owner, beneficiary]) {
|
||||
const amount = new BigNumber(100);
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await MintableToken.new({ from: owner });
|
||||
this.releaseTime = latestTime() + duration.years(1);
|
||||
this.timelock = await TokenTimelock.new(this.token.address, beneficiary, this.releaseTime);
|
||||
await this.token.mint(this.timelock.address, amount, { from: owner });
|
||||
});
|
||||
|
||||
it('cannot be released before time limit', async function () {
|
||||
await this.timelock.release().should.be.rejected;
|
||||
});
|
||||
|
||||
it('cannot be released just before time limit', async function () {
|
||||
await increaseTimeTo(this.releaseTime - duration.seconds(3));
|
||||
await this.timelock.release().should.be.rejected;
|
||||
});
|
||||
|
||||
it('can be released just after limit', async function () {
|
||||
await increaseTimeTo(this.releaseTime + duration.seconds(1));
|
||||
await this.timelock.release().should.be.fulfilled;
|
||||
const balance = await this.token.balanceOf(beneficiary);
|
||||
balance.should.be.bignumber.equal(amount);
|
||||
});
|
||||
|
||||
it('can be released after time limit', async function () {
|
||||
await increaseTimeTo(this.releaseTime + duration.years(1));
|
||||
await this.timelock.release().should.be.fulfilled;
|
||||
const balance = await this.token.balanceOf(beneficiary);
|
||||
balance.should.be.bignumber.equal(amount);
|
||||
});
|
||||
|
||||
it('cannot be released twice', async function () {
|
||||
await increaseTimeTo(this.releaseTime + duration.years(1));
|
||||
await this.timelock.release().should.be.fulfilled;
|
||||
await this.timelock.release().should.be.rejected;
|
||||
const balance = await this.token.balanceOf(beneficiary);
|
||||
balance.should.be.bignumber.equal(amount);
|
||||
});
|
||||
});
|
||||
@ -1,19 +1,18 @@
|
||||
const BigNumber = web3.BigNumber
|
||||
import EVMRevert from './helpers/EVMRevert';
|
||||
import latestTime from './helpers/latestTime';
|
||||
import { increaseTimeTo, duration } from './helpers/increaseTime';
|
||||
|
||||
const BigNumber = web3.BigNumber;
|
||||
|
||||
require('chai')
|
||||
.use(require('chai-as-promised'))
|
||||
.use(require('chai-bignumber')(BigNumber))
|
||||
.should();
|
||||
|
||||
import EVMRevert from './helpers/EVMRevert'
|
||||
import latestTime from './helpers/latestTime';
|
||||
import {increaseTimeTo, duration} from './helpers/increaseTime';
|
||||
|
||||
const MintableToken = artifacts.require('MintableToken');
|
||||
const TokenVesting = artifacts.require('TokenVesting');
|
||||
|
||||
contract('TokenVesting', function ([_, owner, beneficiary]) {
|
||||
|
||||
const amount = new BigNumber(1000);
|
||||
|
||||
beforeEach(async function () {
|
||||
@ -75,7 +74,7 @@ contract('TokenVesting', function ([_, owner, beneficiary]) {
|
||||
});
|
||||
|
||||
it('should fail to be revoked by owner if revocable not set', async function () {
|
||||
const vesting = await TokenVesting.new(beneficiary, this.start, this.cliff, this.duration, false, { from: owner } );
|
||||
const vesting = await TokenVesting.new(beneficiary, this.start, this.cliff, this.duration, false, { from: owner });
|
||||
await vesting.revoke(this.token.address, { from: owner }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
@ -105,11 +104,10 @@ contract('TokenVesting', function ([_, owner, beneficiary]) {
|
||||
it('should fail to be revoked a second time', async function () {
|
||||
await increaseTimeTo(this.start + this.cliff + duration.weeks(12));
|
||||
|
||||
const vested = await this.vesting.vestedAmount(this.token.address);
|
||||
await this.vesting.vestedAmount(this.token.address);
|
||||
|
||||
await this.vesting.revoke(this.token.address, { from: owner });
|
||||
|
||||
await this.vesting.revoke(this.token.address, { from: owner }).should.be.rejectedWith(EVMRevert);
|
||||
});
|
||||
|
||||
});
|
||||
@ -1 +1 @@
|
||||
export default 'revert'
|
||||
export default 'revert';
|
||||
|
||||
@ -1 +1 @@
|
||||
export default 'invalid opcode'
|
||||
export default 'invalid opcode';
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import '../../contracts/payment/SplitPayment.sol';
|
||||
|
||||
// mock class using SplitPayment
|
||||
contract SplitPaymentMock is SplitPayment {
|
||||
function SplitPaymentMock(address[] _payees, uint256[] _shares) public
|
||||
SplitPayment(_payees, _shares) payable {}
|
||||
function () external payable {}
|
||||
}
|
||||
@ -1,22 +1,22 @@
|
||||
export function advanceBlock() {
|
||||
export function advanceBlock () {
|
||||
return new Promise((resolve, reject) => {
|
||||
web3.currentProvider.sendAsync({
|
||||
jsonrpc: '2.0',
|
||||
method: 'evm_mine',
|
||||
id: Date.now(),
|
||||
}, (err, res) => {
|
||||
return err ? reject(err) : resolve(res)
|
||||
})
|
||||
})
|
||||
return err ? reject(err) : resolve(res);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Advances the block number so that the last mined block is `number`.
|
||||
export default async function advanceToBlock(number) {
|
||||
export default async function advanceToBlock (number) {
|
||||
if (web3.eth.blockNumber > number) {
|
||||
throw Error(`block number ${number} is in the past (current is ${web3.eth.blockNumber})`)
|
||||
throw Error(`block number ${number} is in the past (current is ${web3.eth.blockNumber})`);
|
||||
}
|
||||
|
||||
while (web3.eth.blockNumber < number) {
|
||||
await advanceBlock()
|
||||
await advanceBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
module.exports = function(error) {
|
||||
module.exports = function (error) {
|
||||
assert.isAbove(error.message.search('invalid opcode'), -1, 'Invalid opcode error must be returned');
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
module.exports = function(error) {
|
||||
module.exports = function (error) {
|
||||
assert.isAbove(error.message.search('revert'), -1, 'Error containing "revert" must be returned');
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
export default function ether(n) {
|
||||
return new web3.BigNumber(web3.toWei(n, 'ether'))
|
||||
export default function ether (n) {
|
||||
return new web3.BigNumber(web3.toWei(n, 'ether'));
|
||||
}
|
||||
|
||||
16
test/helpers/expectEvent.js
Normal file
16
test/helpers/expectEvent.js
Normal file
@ -0,0 +1,16 @@
|
||||
const assert = require('chai').assert;
|
||||
|
||||
const inLogs = async (logs, eventName) => {
|
||||
const event = logs.find(e => e.event === eventName);
|
||||
assert.exists(event);
|
||||
};
|
||||
|
||||
const inTransaction = async (tx, eventName) => {
|
||||
const { logs } = await tx;
|
||||
return inLogs(logs, eventName);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
inLogs,
|
||||
inTransaction,
|
||||
};
|
||||
@ -13,7 +13,7 @@ export default async promise => {
|
||||
const revert = error.message.search('revert') >= 0;
|
||||
assert(
|
||||
invalidOpcode || outOfGas || revert,
|
||||
"Expected throw, got '" + error + "' instead",
|
||||
'Expected throw, got \'' + error + '\' instead',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user