├── .npmrc ├── solidity ├── .gitignore ├── contracts │ ├── build │ │ ├── IOwned.bin │ │ ├── IERC20Token.bin │ │ ├── Utils.abi │ │ ├── SafeMath.abi │ │ ├── SafeMath.bin │ │ ├── Utils.bin │ │ ├── IOwned.abi │ │ ├── Owned.abi │ │ ├── Owned.bin │ │ ├── IERC20Token.abi │ │ ├── ERC20Token.abi │ │ └── ERC20Token.bin │ ├── interfaces │ │ ├── ITokenHolder.sol │ │ ├── IOwned.sol │ │ └── IERC20Token.sol │ ├── helpers │ │ ├── TestERC20Token.sol │ │ └── TestUtils.sol │ ├── Migrations.sol │ ├── ENJAllocation.sol │ ├── TokenHolder.sol │ ├── Owned.sol │ ├── Utils.sol │ ├── ERC20Token.sol │ ├── ENJCrowdfund.sol │ └── ENJToken.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── test │ ├── helpers │ │ ├── latestTime.js │ │ ├── Utils.js │ │ ├── increaseTime.js │ │ └── FormulaConstants.js │ ├── SafeMath.js │ ├── Owned.js │ ├── TokenHolder.js │ ├── ERC20Token.js │ ├── ENJCrowdfund.js │ └── ENJToken.js ├── truffle-config.js └── build │ └── contracts │ ├── Utils.json │ ├── IOwned.json │ ├── TestUtils.json │ ├── Migrations.json │ ├── Owned.json │ ├── IERC20Token.json │ ├── ERC20Token.json │ ├── TestERC20Token.json │ ├── ENJCrowdfund.json │ └── ENJToken.json ├── .babelrc ├── .gitignore ├── .gitmodules ├── README.md ├── package.json └── LICENSE.md /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /solidity/.gitignore: -------------------------------------------------------------------------------- 1 | .hypothesis 2 | -------------------------------------------------------------------------------- /solidity/contracts/build/IOwned.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /solidity/contracts/build/IERC20Token.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2", "stage-3"] 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_STORE 2 | .vscode 3 | node_modules 4 | npm-debug.log 5 | *.pyc 6 | bin -------------------------------------------------------------------------------- /solidity/contracts/build/Utils.abi: -------------------------------------------------------------------------------- 1 | [{"inputs":[],"payable":false,"type":"constructor"}] -------------------------------------------------------------------------------- /solidity/contracts/build/SafeMath.abi: -------------------------------------------------------------------------------- 1 | [{"inputs":[],"payable":false,"type":"constructor"}] -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "BancorContracts"] 2 | path = BancorContracts 3 | url = git@github.com:bancorprotocol/contracts.git 4 | branch = master 5 | -------------------------------------------------------------------------------- /solidity/contracts/build/SafeMath.bin: -------------------------------------------------------------------------------- 1 | 60606040523415600b57fe5b5b5b5b603380601b6000396000f30060606040525bfe00a165627a7a723058206174375844076856929d806177da8791346da99f87a78d235e73145aaf167cbd0029 -------------------------------------------------------------------------------- /solidity/contracts/build/Utils.bin: -------------------------------------------------------------------------------- 1 | 60606040523415600b57fe5b5b5b5b603380601b6000396000f30060606040525bfe00a165627a7a7230582001f9930667cddde8740fc2335229eabbf00f9b52209ab11220f74ccb235c6f9a0029 -------------------------------------------------------------------------------- /solidity/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | /* global artifacts */ 2 | 3 | const Migrations = artifacts.require('Migrations.sol'); 4 | 5 | module.exports = (deployer) => { 6 | deployer.deploy(Migrations); 7 | }; 8 | -------------------------------------------------------------------------------- /solidity/test/helpers/latestTime.js: -------------------------------------------------------------------------------- 1 | // From https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/test/helpers/latestTime.js 2 | 3 | // Returns the time of the last mined block in seconds 4 | export default function latestTime() { 5 | return web3.eth.getBlock('latest').timestamp; 6 | } 7 | -------------------------------------------------------------------------------- /solidity/contracts/interfaces/ITokenHolder.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | import './IOwned.sol'; 3 | import './IERC20Token.sol'; 4 | 5 | /* 6 | Token Holder interface 7 | */ 8 | contract ITokenHolder is IOwned { 9 | function withdrawTokens(IERC20Token _token, address _to, uint256 _amount) public; 10 | } -------------------------------------------------------------------------------- /solidity/truffle-config.js: -------------------------------------------------------------------------------- 1 | require('babel-register'); 2 | require('babel-polyfill'); 3 | module.exports = { 4 | networks: { 5 | development: { 6 | host: "localhost", 7 | port: 8545, 8 | network_id: "*", // Match any network id 9 | gasPrice: 24000000000 10 | } 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /solidity/contracts/build/IOwned.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"owner","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"type":"function"}] -------------------------------------------------------------------------------- /solidity/contracts/helpers/TestERC20Token.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | import '../ERC20Token.sol'; 3 | 4 | /* 5 | Test token with predefined supply 6 | */ 7 | contract TestERC20Token is ERC20Token { 8 | function TestERC20Token(string _name, string _symbol, uint256 _supply) 9 | ERC20Token(_name, _symbol, 0) 10 | { 11 | totalSupply = _supply; 12 | balanceOf[msg.sender] = _supply; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /solidity/contracts/interfaces/IOwned.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | 3 | /* 4 | Owned contract interface 5 | */ 6 | contract IOwned { 7 | // this function isn't abstract since the compiler emits automatically generated getter functions as external 8 | function owner() public constant returns (address) { owner; } 9 | 10 | function transferOwnership(address _newOwner) public; 11 | function acceptOwnership() public; 12 | } -------------------------------------------------------------------------------- /solidity/build/contracts/Utils.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "Utils", 3 | "abi": [ 4 | { 5 | "inputs": [], 6 | "payable": false, 7 | "type": "constructor" 8 | } 9 | ], 10 | "unlinked_binary": "0x60606040523415600e57600080fd5b5b5b5b603680601e6000396000f30060606040525b600080fd00a165627a7a72305820db33078cbf034db3284b9e72d41ffe6c0adaa66beb8222ad97faf70bc7f99ea10029", 11 | "networks": {}, 12 | "schema_version": "0.0.5", 13 | "updated_at": 1505761384009 14 | } -------------------------------------------------------------------------------- /solidity/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | /* global artifacts */ 2 | /* eslint-disable prefer-reflect */ 3 | const bigNumber = require('bignumber.js'); 4 | const ENJCrowdfund = artifacts.require('ENJCrowdfund.sol'); 5 | const ENJToken = artifacts.require('ENJToken.sol'); 6 | 7 | module.exports = async (deployer) => { 8 | deployer.deploy(ENJCrowdfund, new bigNumber(4).times(new bigNumber(10).pow(26)), this.web3.eth.accounts[1]).then(() => { 9 | deployer.deploy(ENJToken, ENJCrowdfund.address, this.web3.eth.accounts[2]); 10 | }) 11 | }; 12 | -------------------------------------------------------------------------------- /solidity/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | modifier restricted() { 8 | if (msg.sender == owner) _; 9 | } 10 | 11 | function Migrations() { 12 | owner = msg.sender; 13 | } 14 | 15 | function setCompleted(uint completed) restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/contracts/helpers/TestUtils.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | import '../Utils.sol'; 3 | 4 | /* 5 | Utils test helper that exposes the safe math functions 6 | */ 7 | contract TestUtils is Utils { 8 | function TestUtils() { 9 | } 10 | 11 | function testSafeAdd(uint256 _x, uint256 _y) public constant returns (uint256) { 12 | return super.safeAdd(_x, _y); 13 | } 14 | 15 | function testSafeSub(uint256 _x, uint256 _y) public constant returns (uint256) { 16 | return super.safeSub(_x, _y); 17 | } 18 | 19 | function testSafeMul(uint256 _x, uint256 _y) public constant returns (uint256) { 20 | return super.safeMul(_x, _y); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /solidity/test/helpers/Utils.js: -------------------------------------------------------------------------------- 1 | /* global assert */ 2 | 3 | function isException(error) { 4 | let strError = error.toString(); 5 | return strError.includes('invalid opcode') || strError.includes('invalid JUMP'); 6 | } 7 | 8 | function ensureException(error) { 9 | assert(isException(error), error.toString()); 10 | } 11 | 12 | async function timeDifference(timestamp1,timestamp2) { 13 | var difference = timestamp1 - timestamp2; 14 | return difference; 15 | } 16 | 17 | module.exports = { 18 | zeroAddress: '0x0000000000000000000000000000000000000000', 19 | isException: isException, 20 | ensureException: ensureException, 21 | timeDifference:timeDifference 22 | }; 23 | 24 | 25 | -------------------------------------------------------------------------------- /solidity/contracts/build/Owned.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"newOwner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_prevOwner","type":"address"},{"indexed":false,"name":"_newOwner","type":"address"}],"name":"OwnerUpdate","type":"event"}] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Enjin Token And Crowdfund Contract 2 | 3 | ## Testing 4 | Tests are included and can be run using truffle. 5 | 6 | ### Prerequisites 7 | * Node.js v7.6.0+ 8 | * truffle v3.2.2+ 9 | * testrpc v3.0.5+ 10 | 11 | To run the test, execute the following commands from the project's `/solidity` folder - 12 | 13 | Please run `yarn` first 14 | 15 | Then run these commands: 16 | 17 | * `npm run testrpc` 18 | * `truffle test test/ENJToken.js` 19 | 20 | As the dates of the crowdfund are hardcoded in the contract and we are increasing 21 | the blockchain time artificially, you will need to reset testrpc before running 22 | the second round of tests: 23 | 24 | * `npm run testrpc` 25 | * `truffle test test/ENJCrowdfund.js` 26 | 27 | 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "enjinContracts", 3 | "version": "0.2.1", 4 | "author": "Vanbex", 5 | "engines": { 6 | "npm": "^3.0.0" 7 | }, 8 | "scripts": { 9 | "testrpc": "testrpc -a 10", 10 | "test": "cd solidity && truffle test", 11 | "compile": "cd solidity && truffle compile" 12 | }, 13 | "devDependencies": { 14 | "babel-preset-es2015": "^6.18.0", 15 | "babel-preset-stage-2": "^6.24.1", 16 | "babel-preset-stage-3": "^6.17.0", 17 | "babel-register": "^6.23.0" 18 | }, 19 | "dependencies": { 20 | "babel-polyfill": "^6.26.0", 21 | "babel-preset-env": "^1.6.0", 22 | "bignumber.js": "^4.0.4", 23 | "chai": "^4.1.2", 24 | "chai-as-promised": "^7.1.1", 25 | "chai-bignumber": "^2.0.1", 26 | "web3_extended": "^1.0.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /solidity/contracts/ENJAllocation.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | 3 | import './IERC20Token.sol'; 4 | 5 | contract IENJToken is IERC20Token { 6 | function crowdfundAddress() public constant returns (address); 7 | function incentivisationFundAddress() public constant returns (address); 8 | function totalAllocated() public constant returns (uint256); 9 | } 10 | 11 | contract ENJAllocation { 12 | address public tokenAddress; 13 | IENJToken token; 14 | 15 | function ENJAllocation(address _tokenAddress){ 16 | tokenAddress = _tokenAddress; 17 | token = IENJToken(tokenAddress); 18 | } 19 | 20 | function circulation() constant returns (uint256) { 21 | return token.totalAllocated() - token.balanceOf(token.incentivisationFundAddress()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solidity/build/contracts/IOwned.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "IOwned", 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "inputs": [], 7 | "name": "acceptOwnership", 8 | "outputs": [], 9 | "payable": false, 10 | "type": "function" 11 | }, 12 | { 13 | "constant": true, 14 | "inputs": [], 15 | "name": "owner", 16 | "outputs": [ 17 | { 18 | "name": "owner", 19 | "type": "address" 20 | } 21 | ], 22 | "payable": false, 23 | "type": "function" 24 | }, 25 | { 26 | "constant": false, 27 | "inputs": [ 28 | { 29 | "name": "_newOwner", 30 | "type": "address" 31 | } 32 | ], 33 | "name": "transferOwnership", 34 | "outputs": [], 35 | "payable": false, 36 | "type": "function" 37 | } 38 | ], 39 | "unlinked_binary": "0x", 40 | "networks": {}, 41 | "schema_version": "0.0.5", 42 | "updated_at": 1505761384009 43 | } -------------------------------------------------------------------------------- /solidity/contracts/interfaces/IERC20Token.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | 3 | /* 4 | ERC20 Standard Token interface 5 | */ 6 | contract IERC20Token { 7 | // these functions aren't abstract since the compiler emits automatically generated getter functions as external 8 | function name() public constant returns (string) { name; } 9 | function symbol() public constant returns (string) { symbol; } 10 | function decimals() public constant returns (uint8) { decimals; } 11 | function totalSupply() public constant returns (uint256) { totalSupply; } 12 | function balanceOf(address _owner) public constant returns (uint256 balance) { _owner; balance; } 13 | function allowance(address _owner, address _spender) public constant returns (uint256 remaining) { _owner; _spender; remaining; } 14 | 15 | function transfer(address _to, uint256 _value) public returns (bool success); 16 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); 17 | function approve(address _spender, uint256 _value) public returns (bool success); 18 | } 19 | -------------------------------------------------------------------------------- /solidity/contracts/build/Owned.bin: -------------------------------------------------------------------------------- 1 | 6060604052341561000c57fe5b5b60008054600160a060020a03191633600160a060020a03161790555b5b61022b806100396000396000f300606060405263ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166379ba5097811461005b5780638da5cb5b1461006d578063d4ee1d9014610099578063f2fde38b146100c5575bfe5b341561006357fe5b61006b6100e3565b005b341561007557fe5b61007d610180565b60408051600160a060020a039092168252519081900360200190f35b34156100a157fe5b61007d61018f565b60408051600160a060020a039092168252519081900360200190f35b34156100cd57fe5b61006b600160a060020a036004351661019e565b005b60015433600160a060020a039081169116146100ff5760006000fd5b60005460015460408051600160a060020a03938416815292909116602083015280517f343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a9281900390910190a1600180546000805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a038416179091551690555b565b600054600160a060020a031681565b600154600160a060020a031681565b60005433600160a060020a039081169116146101b657fe5b600054600160a060020a03828116911614156101d25760006000fd5b6001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b505600a165627a7a72305820b92f8e8c588495b7416773244e36621d30441b884d7bf7d645422430ab74e0a80029 -------------------------------------------------------------------------------- /solidity/contracts/TokenHolder.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | import './Owned.sol'; 3 | import './Utils.sol'; 4 | import './interfaces/IERC20Token.sol'; 5 | import './interfaces/ITokenHolder.sol'; 6 | 7 | /* 8 | We consider every contract to be a 'token holder' since it's currently not possible 9 | for a contract to deny receiving tokens. 10 | 11 | The TokenHolder's contract sole purpose is to provide a safety mechanism that allows 12 | the owner to send tokens that were sent to the contract by mistake back to their sender. 13 | */ 14 | contract TokenHolder is ITokenHolder, Owned, Utils { 15 | /** 16 | @dev constructor 17 | */ 18 | function TokenHolder() { 19 | } 20 | 21 | /** 22 | @dev withdraws tokens held by the contract and sends them to an account 23 | can only be called by the owner 24 | 25 | @param _token ERC20 token contract address 26 | @param _to account to receive the new amount 27 | @param _amount amount to withdraw 28 | */ 29 | function withdrawTokens(IERC20Token _token, address _to, uint256 _amount) 30 | public 31 | ownerOnly 32 | validAddress(_token) 33 | validAddress(_to) 34 | notThis(_to) 35 | { 36 | assert(_token.transfer(_to, _amount)); 37 | } 38 | } -------------------------------------------------------------------------------- /solidity/contracts/Owned.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | import './interfaces/IOwned.sol'; 3 | 4 | /* 5 | Provides support and utilities for contract ownership 6 | */ 7 | contract Owned is IOwned { 8 | address public owner; 9 | address public newOwner; 10 | 11 | event OwnerUpdate(address _prevOwner, address _newOwner); 12 | 13 | /** 14 | @dev constructor 15 | */ 16 | function Owned() { 17 | owner = msg.sender; 18 | } 19 | 20 | // allows execution by the owner only 21 | modifier ownerOnly { 22 | assert(msg.sender == owner); 23 | _; 24 | } 25 | 26 | /** 27 | @dev allows transferring the contract ownership 28 | the new owner still needs to accept the transfer 29 | can only be called by the contract owner 30 | 31 | @param _newOwner new contract owner 32 | */ 33 | function transferOwnership(address _newOwner) public ownerOnly { 34 | require(_newOwner != owner); 35 | newOwner = _newOwner; 36 | } 37 | 38 | /** 39 | @dev used by a new owner to accept an ownership transfer 40 | */ 41 | function acceptOwnership() public { 42 | require(msg.sender == newOwner); 43 | OwnerUpdate(owner, newOwner); 44 | owner = newOwner; 45 | newOwner = 0x0; 46 | } 47 | } -------------------------------------------------------------------------------- /solidity/contracts/build/IERC20Token.abi: -------------------------------------------------------------------------------- 1 | [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"name","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"totalSupply","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"decimals","type":"uint8"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"symbol","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"type":"function"}] -------------------------------------------------------------------------------- /solidity/test/helpers/increaseTime.js: -------------------------------------------------------------------------------- 1 | // From https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/test/helpers/increaseTime.js 2 | 3 | import latestTime from './latestTime' 4 | 5 | // Increases testrpc time by the passed duration in seconds 6 | export default function increaseTime(duration) { 7 | const id = Date.now(); 8 | 9 | return new Promise((resolve, reject) => { 10 | web3.currentProvider.sendAsync({ 11 | jsonrpc: '2.0', 12 | method: 'evm_increaseTime', 13 | params: [duration], 14 | id: id, 15 | }, err1 => { 16 | if (err1) return reject(err1) 17 | 18 | web3.currentProvider.sendAsync({ 19 | jsonrpc: '2.0', 20 | method: 'evm_mine', 21 | id: id+1, 22 | }, (err2, res) => { 23 | return err2 ? reject(err2) : resolve(res) 24 | }) 25 | }) 26 | }) 27 | } 28 | 29 | /** 30 | * Beware that due to the need of calling two separate testrpc methods and rpc calls overhead 31 | * it's hard to increase time precisely to a target point so design your test to tolerate 32 | * small fluctuations from time to time. 33 | * 34 | * @param target time in seconds 35 | */ 36 | export function increaseTimeTo(target) { 37 | let now = latestTime(); 38 | now = Math.floor(now/10); 39 | if (target < now) throw Error(`Cannot increase current time(${now}) to a moment in the past(${target})`); 40 | let diff = target - now; 41 | return increaseTime(diff); 42 | } 43 | 44 | export const duration = { 45 | seconds: function(val) { return val}, 46 | minutes: function(val) { return val * this.seconds(60) }, 47 | hours: function(val) { return val * this.minutes(60) }, 48 | days: function(val) { return val * this.hours(24) }, 49 | weeks: function(val) { return val * this.days(7) }, 50 | years: function(val) { return val * this.days(365)} 51 | }; 52 | -------------------------------------------------------------------------------- /solidity/contracts/Utils.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | 3 | /* 4 | Utilities & Common Modifiers 5 | */ 6 | contract Utils { 7 | /** 8 | constructor 9 | */ 10 | function Utils() { 11 | } 12 | 13 | // validates an address - currently only checks that it isn't null 14 | modifier validAddress(address _address) { 15 | require(_address != 0x0); 16 | _; 17 | } 18 | 19 | // verifies that the address is different than this contract address 20 | modifier notThis(address _address) { 21 | require(_address != address(this)); 22 | _; 23 | } 24 | 25 | // Overflow protected math functions 26 | 27 | /** 28 | @dev returns the sum of _x and _y, asserts if the calculation overflows 29 | 30 | @param _x value 1 31 | @param _y value 2 32 | 33 | @return sum 34 | */ 35 | function safeAdd(uint256 _x, uint256 _y) internal returns (uint256) { 36 | uint256 z = _x + _y; 37 | assert(z >= _x); 38 | return z; 39 | } 40 | 41 | /** 42 | @dev returns the difference of _x minus _y, asserts if the subtraction results in a negative number 43 | 44 | @param _x minuend 45 | @param _y subtrahend 46 | 47 | @return difference 48 | */ 49 | function safeSub(uint256 _x, uint256 _y) internal returns (uint256) { 50 | assert(_x >= _y); 51 | return _x - _y; 52 | } 53 | 54 | /** 55 | @dev returns the product of multiplying _x by _y, asserts if the calculation overflows 56 | 57 | @param _x factor 1 58 | @param _y factor 2 59 | 60 | @return product 61 | */ 62 | function safeMul(uint256 _x, uint256 _y) internal returns (uint256) { 63 | uint256 z = _x * _y; 64 | assert(_x == 0 || z / _x == _y); 65 | return z; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /solidity/contracts/build/ERC20Token.abi: -------------------------------------------------------------------------------- 1 | [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"standard","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_decimals","type":"uint8"}],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}] -------------------------------------------------------------------------------- /solidity/test/SafeMath.js: -------------------------------------------------------------------------------- 1 | /* global artifacts, contract, it, assert, web3 */ 2 | /* eslint-disable prefer-reflect */ 3 | 4 | const TestUtils = artifacts.require('TestUtils.sol'); 5 | const utils = require('./helpers/Utils'); 6 | 7 | contract('Utils', () => { 8 | it('verifies successful addition', async () => { 9 | let math = await TestUtils.new(); 10 | let x = 2957; 11 | let y = 1740; 12 | let z = await math.testSafeAdd.call(x, y); 13 | assert.equal(z, x + y); 14 | }); 15 | 16 | it('should throw on addition overflow', async () => { 17 | let math = await TestUtils.new(); 18 | let x = web3.toBigNumber('115792089237316195423570985008687907853269984665640564039457584007913129639935'); 19 | let y = 1; 20 | 21 | try { 22 | await math.testSafeAdd.call(x, y); 23 | assert(false, "didn't throw"); 24 | } 25 | catch (error) { 26 | return utils.ensureException(error); 27 | } 28 | }); 29 | 30 | it('verifies successful subtraction', async () => { 31 | let math = await TestUtils.new(); 32 | let x = 2957; 33 | let y = 1740; 34 | let z = await math.testSafeSub.call(x, y); 35 | assert.equal(z, x - y); 36 | }); 37 | 38 | it('should throw on subtraction with negative result', async () => { 39 | let math = await TestUtils.new(); 40 | let x = 10; 41 | let y = 11; 42 | 43 | try { 44 | await math.testSafeSub.call(x, y); 45 | assert(false, "didn't throw"); 46 | } 47 | catch (error) { 48 | return utils.ensureException(error); 49 | } 50 | }); 51 | 52 | it('verifies successful multiplication', async () => { 53 | let math = await TestUtils.new(); 54 | let x = 2957; 55 | let y = 1740; 56 | let z = await math.testSafeMul.call(x, y); 57 | assert.equal(z, x * y); 58 | }); 59 | 60 | it('should throw on multiplication overflow', async () => { 61 | let math = await TestUtils.new(); 62 | let x = web3.toBigNumber('15792089237316195423570985008687907853269984665640564039457584007913129639935'); 63 | let y = 2000; 64 | 65 | try { 66 | await math.testSafeMul.call(x, y); 67 | assert(false, "didn't throw"); 68 | } 69 | catch (error) { 70 | return utils.ensureException(error); 71 | } 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /solidity/build/contracts/TestUtils.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "TestUtils", 3 | "abi": [ 4 | { 5 | "constant": true, 6 | "inputs": [ 7 | { 8 | "name": "_x", 9 | "type": "uint256" 10 | }, 11 | { 12 | "name": "_y", 13 | "type": "uint256" 14 | } 15 | ], 16 | "name": "testSafeMul", 17 | "outputs": [ 18 | { 19 | "name": "", 20 | "type": "uint256" 21 | } 22 | ], 23 | "payable": false, 24 | "type": "function" 25 | }, 26 | { 27 | "constant": true, 28 | "inputs": [ 29 | { 30 | "name": "_x", 31 | "type": "uint256" 32 | }, 33 | { 34 | "name": "_y", 35 | "type": "uint256" 36 | } 37 | ], 38 | "name": "testSafeAdd", 39 | "outputs": [ 40 | { 41 | "name": "", 42 | "type": "uint256" 43 | } 44 | ], 45 | "payable": false, 46 | "type": "function" 47 | }, 48 | { 49 | "constant": true, 50 | "inputs": [ 51 | { 52 | "name": "_x", 53 | "type": "uint256" 54 | }, 55 | { 56 | "name": "_y", 57 | "type": "uint256" 58 | } 59 | ], 60 | "name": "testSafeSub", 61 | "outputs": [ 62 | { 63 | "name": "", 64 | "type": "uint256" 65 | } 66 | ], 67 | "payable": false, 68 | "type": "function" 69 | }, 70 | { 71 | "inputs": [], 72 | "payable": false, 73 | "type": "constructor" 74 | } 75 | ], 76 | "unlinked_binary": "0x6060604052341561000f57600080fd5b5b5b5b5b5b61019f806100236000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416639ee6ff708114610053578063de47864c1461007e578063ec0da330146100a9575b600080fd5b341561005e57600080fd5b61006c6004356024356100d4565b60405190815260200160405180910390f35b341561008957600080fd5b61006c6004356024356100e9565b60405190815260200160405180910390f35b34156100b457600080fd5b61006c6004356024356100fe565b60405190815260200160405180910390f35b60006100e08383610113565b90505b92915050565b60006100e08383610142565b90505b92915050565b60006100e0838361015c565b90505b92915050565b600082820283158061012f575082848281151561012c57fe5b04145b151561013757fe5b8091505b5092915050565b60008282018381101561013757fe5b8091505b5092915050565b60008183101561016857fe5b508082035b929150505600a165627a7a723058208ab441fa93c19ac758ee0a1710a88904f48008c08364113fcdc54f1a130c0a970029", 77 | "networks": {}, 78 | "schema_version": "0.0.5", 79 | "updated_at": 1505761384009 80 | } -------------------------------------------------------------------------------- /solidity/build/contracts/Migrations.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "Migrations", 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "inputs": [ 7 | { 8 | "name": "new_address", 9 | "type": "address" 10 | } 11 | ], 12 | "name": "upgrade", 13 | "outputs": [], 14 | "payable": false, 15 | "type": "function" 16 | }, 17 | { 18 | "constant": true, 19 | "inputs": [], 20 | "name": "last_completed_migration", 21 | "outputs": [ 22 | { 23 | "name": "", 24 | "type": "uint256" 25 | } 26 | ], 27 | "payable": false, 28 | "type": "function" 29 | }, 30 | { 31 | "constant": true, 32 | "inputs": [], 33 | "name": "owner", 34 | "outputs": [ 35 | { 36 | "name": "", 37 | "type": "address" 38 | } 39 | ], 40 | "payable": false, 41 | "type": "function" 42 | }, 43 | { 44 | "constant": false, 45 | "inputs": [ 46 | { 47 | "name": "completed", 48 | "type": "uint256" 49 | } 50 | ], 51 | "name": "setCompleted", 52 | "outputs": [], 53 | "payable": false, 54 | "type": "function" 55 | }, 56 | { 57 | "inputs": [], 58 | "payable": false, 59 | "type": "constructor" 60 | } 61 | ], 62 | "unlinked_binary": "0x6060604052341561000f57600080fd5b5b60008054600160a060020a03191633600160a060020a03161790555b5b6101e58061003c6000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630900f010811461005e578063445df0ac1461007f5780638da5cb5b146100a4578063fdacd576146100d3575b600080fd5b341561006957600080fd5b61007d600160a060020a03600435166100eb565b005b341561008a57600080fd5b610092610182565b60405190815260200160405180910390f35b34156100af57600080fd5b6100b7610188565b604051600160a060020a03909116815260200160405180910390f35b34156100de57600080fd5b61007d600435610197565b005b6000805433600160a060020a039081169116141561017c5781905080600160a060020a031663fdacd5766001546040517c010000000000000000000000000000000000000000000000000000000063ffffffff84160281526004810191909152602401600060405180830381600087803b151561016757600080fd5b6102c65a03f1151561017857600080fd5b5050505b5b5b5050565b60015481565b600054600160a060020a031681565b60005433600160a060020a03908116911614156101b45760018190555b5b5b505600a165627a7a7230582095d6f576cfead9e1012b68ae5480107857fb669430c339d5a5d4c023c3cfcbf90029", 63 | "networks": { 64 | "1505761635724": { 65 | "links": {}, 66 | "events": {}, 67 | "updated_at": 1505761682898 68 | } 69 | }, 70 | "schema_version": "0.0.5", 71 | "updated_at": 1505761682898 72 | } -------------------------------------------------------------------------------- /solidity/test/Owned.js: -------------------------------------------------------------------------------- 1 | /* global artifacts, contract, it, assert */ 2 | /* eslint-disable prefer-reflect */ 3 | 4 | const Owned = artifacts.require('Owned.sol'); 5 | const utils = require('./helpers/Utils'); 6 | 7 | contract('Owned', (accounts) => { 8 | it('verifies the owner after construction', async () => { 9 | let contract = await Owned.new(); 10 | let owner = await contract.owner.call(); 11 | assert.equal(owner, accounts[0]); 12 | }); 13 | 14 | it('verifies the new owner after ownership transfer', async () => { 15 | let contract = await Owned.new(); 16 | await contract.transferOwnership(accounts[1]); 17 | await contract.acceptOwnership({ from: accounts[1] }); 18 | let owner = await contract.owner.call(); 19 | assert.equal(owner, accounts[1]); 20 | }); 21 | 22 | it('verifies that ownership transfer fires an OwnerUpdate event', async () => { 23 | let contract = await Owned.new(); 24 | await contract.transferOwnership(accounts[1]); 25 | let res = await contract.acceptOwnership({ from: accounts[1] }); 26 | assert(res.logs.length > 0 && res.logs[0].event == 'OwnerUpdate'); 27 | }); 28 | 29 | it('verifies that newOwner is cleared after ownership transfer', async () => { 30 | let contract = await Owned.new(); 31 | await contract.transferOwnership(accounts[1]); 32 | await contract.acceptOwnership({ from: accounts[1] }); 33 | let newOwner = await contract.newOwner.call(); 34 | assert.equal(newOwner, utils.zeroAddress); 35 | }); 36 | 37 | it('verifies that no ownership transfer takes places before the new owner accepted it', async () => { 38 | let contract = await Owned.new(); 39 | await contract.transferOwnership(accounts[1]); 40 | let owner = await contract.owner.call(); 41 | assert.equal(owner, accounts[0]); 42 | }); 43 | 44 | it('verifies that only the owner can initiate ownership transfer', async () => { 45 | let contract = await Owned.new(); 46 | 47 | try { 48 | await contract.transferOwnership(accounts[1], { from: accounts[2] }); 49 | assert(false, "didn't throw"); 50 | } 51 | catch (error) { 52 | return utils.ensureException(error); 53 | } 54 | }); 55 | 56 | it('verifies that the owner can cancel ownership transfer before the new owner accepted it', async () => { 57 | let contract = await Owned.new(); 58 | await contract.transferOwnership(accounts[1]); 59 | await contract.transferOwnership('0x0'); 60 | let newOwner = await contract.newOwner.call(); 61 | assert.equal(newOwner, utils.zeroAddress); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /solidity/build/contracts/Owned.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "Owned", 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "inputs": [], 7 | "name": "acceptOwnership", 8 | "outputs": [], 9 | "payable": false, 10 | "type": "function" 11 | }, 12 | { 13 | "constant": true, 14 | "inputs": [], 15 | "name": "owner", 16 | "outputs": [ 17 | { 18 | "name": "", 19 | "type": "address" 20 | } 21 | ], 22 | "payable": false, 23 | "type": "function" 24 | }, 25 | { 26 | "constant": true, 27 | "inputs": [], 28 | "name": "newOwner", 29 | "outputs": [ 30 | { 31 | "name": "", 32 | "type": "address" 33 | } 34 | ], 35 | "payable": false, 36 | "type": "function" 37 | }, 38 | { 39 | "constant": false, 40 | "inputs": [ 41 | { 42 | "name": "_newOwner", 43 | "type": "address" 44 | } 45 | ], 46 | "name": "transferOwnership", 47 | "outputs": [], 48 | "payable": false, 49 | "type": "function" 50 | }, 51 | { 52 | "inputs": [], 53 | "payable": false, 54 | "type": "constructor" 55 | }, 56 | { 57 | "anonymous": false, 58 | "inputs": [ 59 | { 60 | "indexed": false, 61 | "name": "_prevOwner", 62 | "type": "address" 63 | }, 64 | { 65 | "indexed": false, 66 | "name": "_newOwner", 67 | "type": "address" 68 | } 69 | ], 70 | "name": "OwnerUpdate", 71 | "type": "event" 72 | } 73 | ], 74 | "unlinked_binary": "0x6060604052341561000f57600080fd5b5b60008054600160a060020a03191633600160a060020a03161790555b5b6102448061003c6000396000f300606060405263ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166379ba5097811461005e5780638da5cb5b14610073578063d4ee1d90146100a2578063f2fde38b146100d1575b600080fd5b341561006957600080fd5b6100716100f2565b005b341561007e57600080fd5b61008661019a565b604051600160a060020a03909116815260200160405180910390f35b34156100ad57600080fd5b6100866101a9565b604051600160a060020a03909116815260200160405180910390f35b34156100dc57600080fd5b610071600160a060020a03600435166101b8565b005b60015433600160a060020a0390811691161461010d57600080fd5b6000546001547f343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a91600160a060020a039081169116604051600160a060020a039283168152911660208201526040908101905180910390a1600180546000805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a038416179091551690555b565b600054600160a060020a031681565b600154600160a060020a031681565b60005433600160a060020a039081169116146101d057fe5b600054600160a060020a03828116911614156101eb57600080fd5b6001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b505600a165627a7a72305820be2fe4c0da0296b081e49c3d7779afb26a10ad948c374ba41d543d6f265b33750029", 75 | "networks": {}, 76 | "schema_version": "0.0.5", 77 | "updated_at": 1505761384009 78 | } -------------------------------------------------------------------------------- /solidity/test/TokenHolder.js: -------------------------------------------------------------------------------- 1 | /* global artifacts, contract, it, assert */ 2 | /* eslint-disable prefer-reflect */ 3 | 4 | const TokenHolder = artifacts.require('TokenHolder.sol'); 5 | const TestERC20Token = artifacts.require('TestERC20Token.sol'); 6 | const utils = require('./helpers/Utils'); 7 | 8 | let holderAddress; 9 | let erc20Token; 10 | let erc20TokenAddress; 11 | 12 | // initializes the holder with some ERC20 token balance 13 | async function initHolder() { 14 | let holder = await TokenHolder.new(); 15 | holderAddress = holder.address; 16 | erc20Token = await TestERC20Token.new('ERC Token 1', 'ERC1', 100000); 17 | erc20TokenAddress = erc20Token.address; 18 | await erc20Token.transfer(holderAddress, 1000); 19 | return holder; 20 | } 21 | 22 | contract('TokenHolder', (accounts) => { 23 | it('verifies that the owner can withdraw tokens', async () => { 24 | let holder = await initHolder(); 25 | let prevBalance = await erc20Token.balanceOf.call(accounts[2]); 26 | await holder.withdrawTokens(erc20TokenAddress, accounts[2], 100); 27 | let balance = await erc20Token.balanceOf.call(accounts[2]); 28 | assert.equal(balance.toNumber(), prevBalance.plus(100).toNumber()); 29 | }); 30 | 31 | it('should throw when a non owner attempts to withdraw tokens', async () => { 32 | let holder = await initHolder(); 33 | 34 | try { 35 | await holder.withdrawTokens(erc20TokenAddress, accounts[2], 100, { from: accounts[3] }); 36 | assert(false, "didn't throw"); 37 | } 38 | catch (error) { 39 | return utils.ensureException(error); 40 | } 41 | }); 42 | 43 | it('should throw when attempting to withdraw tokens from an invalid ERC20 token address', async () => { 44 | let holder = await initHolder(); 45 | 46 | try { 47 | await holder.withdrawTokens('0x0', accounts[2], 100); 48 | assert(false, "didn't throw"); 49 | } 50 | catch (error) { 51 | return utils.ensureException(error); 52 | } 53 | }); 54 | 55 | it('should throw when attempting to withdraw tokens to an invalid account address', async () => { 56 | let holder = await initHolder(); 57 | 58 | try { 59 | await holder.withdrawTokens(erc20TokenAddress, '0x0', 100); 60 | assert(false, "didn't throw"); 61 | } 62 | catch (error) { 63 | return utils.ensureException(error); 64 | } 65 | }); 66 | 67 | it('should throw when attempting to withdraw tokens to the holder address', async () => { 68 | let holder = await initHolder(); 69 | 70 | try { 71 | await holder.withdrawTokens(erc20TokenAddress, holderAddress, 100); 72 | assert(false, "didn't throw"); 73 | } 74 | catch (error) { 75 | return utils.ensureException(error); 76 | } 77 | }); 78 | 79 | it('should throw when attempting to withdraw an amount greater than the holder balance', async () => { 80 | let holder = await initHolder(); 81 | 82 | try { 83 | await holder.withdrawTokens(erc20TokenAddress, accounts[2], 5000); 84 | assert(false, "didn't throw"); 85 | } 86 | catch (error) { 87 | return utils.ensureException(error); 88 | } 89 | }); 90 | }); -------------------------------------------------------------------------------- /solidity/build/contracts/IERC20Token.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "IERC20Token", 3 | "abi": [ 4 | { 5 | "constant": true, 6 | "inputs": [], 7 | "name": "name", 8 | "outputs": [ 9 | { 10 | "name": "name", 11 | "type": "string" 12 | } 13 | ], 14 | "payable": false, 15 | "type": "function" 16 | }, 17 | { 18 | "constant": false, 19 | "inputs": [ 20 | { 21 | "name": "_spender", 22 | "type": "address" 23 | }, 24 | { 25 | "name": "_value", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "approve", 30 | "outputs": [ 31 | { 32 | "name": "success", 33 | "type": "bool" 34 | } 35 | ], 36 | "payable": false, 37 | "type": "function" 38 | }, 39 | { 40 | "constant": true, 41 | "inputs": [], 42 | "name": "totalSupply", 43 | "outputs": [ 44 | { 45 | "name": "totalSupply", 46 | "type": "uint256" 47 | } 48 | ], 49 | "payable": false, 50 | "type": "function" 51 | }, 52 | { 53 | "constant": false, 54 | "inputs": [ 55 | { 56 | "name": "_from", 57 | "type": "address" 58 | }, 59 | { 60 | "name": "_to", 61 | "type": "address" 62 | }, 63 | { 64 | "name": "_value", 65 | "type": "uint256" 66 | } 67 | ], 68 | "name": "transferFrom", 69 | "outputs": [ 70 | { 71 | "name": "success", 72 | "type": "bool" 73 | } 74 | ], 75 | "payable": false, 76 | "type": "function" 77 | }, 78 | { 79 | "constant": true, 80 | "inputs": [], 81 | "name": "decimals", 82 | "outputs": [ 83 | { 84 | "name": "decimals", 85 | "type": "uint8" 86 | } 87 | ], 88 | "payable": false, 89 | "type": "function" 90 | }, 91 | { 92 | "constant": true, 93 | "inputs": [ 94 | { 95 | "name": "_owner", 96 | "type": "address" 97 | } 98 | ], 99 | "name": "balanceOf", 100 | "outputs": [ 101 | { 102 | "name": "balance", 103 | "type": "uint256" 104 | } 105 | ], 106 | "payable": false, 107 | "type": "function" 108 | }, 109 | { 110 | "constant": true, 111 | "inputs": [], 112 | "name": "symbol", 113 | "outputs": [ 114 | { 115 | "name": "symbol", 116 | "type": "string" 117 | } 118 | ], 119 | "payable": false, 120 | "type": "function" 121 | }, 122 | { 123 | "constant": false, 124 | "inputs": [ 125 | { 126 | "name": "_to", 127 | "type": "address" 128 | }, 129 | { 130 | "name": "_value", 131 | "type": "uint256" 132 | } 133 | ], 134 | "name": "transfer", 135 | "outputs": [ 136 | { 137 | "name": "success", 138 | "type": "bool" 139 | } 140 | ], 141 | "payable": false, 142 | "type": "function" 143 | }, 144 | { 145 | "constant": true, 146 | "inputs": [ 147 | { 148 | "name": "_owner", 149 | "type": "address" 150 | }, 151 | { 152 | "name": "_spender", 153 | "type": "address" 154 | } 155 | ], 156 | "name": "allowance", 157 | "outputs": [ 158 | { 159 | "name": "remaining", 160 | "type": "uint256" 161 | } 162 | ], 163 | "payable": false, 164 | "type": "function" 165 | } 166 | ], 167 | "unlinked_binary": "0x", 168 | "networks": {}, 169 | "schema_version": "0.0.5", 170 | "updated_at": 1505761384009 171 | } -------------------------------------------------------------------------------- /solidity/contracts/ERC20Token.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | import './Utils.sol'; 3 | import './interfaces/IERC20Token.sol'; 4 | 5 | /** 6 | ERC20 Standard Token implementation 7 | */ 8 | contract ERC20Token is IERC20Token, Utils { 9 | string public standard = "Token 0.1"; 10 | string public name = ""; 11 | string public symbol = ""; 12 | uint8 public decimals = 0; 13 | uint256 public totalSupply = 0; 14 | mapping (address => uint256) public balanceOf; 15 | mapping (address => mapping (address => uint256)) public allowance; 16 | 17 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 18 | event Approval(address indexed _owner, address indexed _spender, uint256 _value); 19 | 20 | /** 21 | @dev constructor 22 | 23 | @param _name token name 24 | @param _symbol token symbol 25 | @param _decimals decimal points, for display purposes 26 | */ 27 | function ERC20Token(string _name, string _symbol, uint8 _decimals) { 28 | require(bytes(_name).length > 0 && bytes(_symbol).length > 0); // validate input 29 | 30 | name = _name; 31 | symbol = _symbol; 32 | decimals = _decimals; 33 | } 34 | 35 | /** 36 | @dev send coins 37 | throws on any error rather then return a false flag to minimize user errors 38 | 39 | @param _to target address 40 | @param _value transfer amount 41 | 42 | @return true if the transfer was successful, false if it wasn't 43 | */ 44 | function transfer(address _to, uint256 _value) 45 | public 46 | validAddress(_to) 47 | returns (bool success) 48 | { 49 | balanceOf[msg.sender] = safeSub(balanceOf[msg.sender], _value); 50 | balanceOf[_to] = safeAdd(balanceOf[_to], _value); 51 | Transfer(msg.sender, _to, _value); 52 | return true; 53 | } 54 | 55 | /** 56 | @dev an account/contract attempts to get the coins 57 | throws on any error rather then return a false flag to minimize user errors 58 | 59 | @param _from source address 60 | @param _to target address 61 | @param _value transfer amount 62 | 63 | @return true if the transfer was successful, false if it wasn't 64 | */ 65 | function transferFrom(address _from, address _to, uint256 _value) 66 | public 67 | validAddress(_from) 68 | validAddress(_to) 69 | returns (bool success) 70 | { 71 | allowance[_from][msg.sender] = safeSub(allowance[_from][msg.sender], _value); 72 | balanceOf[_from] = safeSub(balanceOf[_from], _value); 73 | balanceOf[_to] = safeAdd(balanceOf[_to], _value); 74 | Transfer(_from, _to, _value); 75 | return true; 76 | } 77 | 78 | /** 79 | @dev allow another account/contract to spend some tokens on your behalf 80 | throws on any error rather then return a false flag to minimize user errors 81 | 82 | also, to minimize the risk of the approve/transferFrom attack vector 83 | (see https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/), approve has to be called twice 84 | in 2 separate transactions - once to change the allowance to 0 and secondly to change it to the new allowance value 85 | 86 | @param _spender approved address 87 | @param _value allowance amount 88 | 89 | @return true if the approval was successful, false if it wasn't 90 | */ 91 | function approve(address _spender, uint256 _value) 92 | public 93 | validAddress(_spender) 94 | returns (bool success) 95 | { 96 | // if the allowance isn't 0, it can only be updated to 0 to prevent an allowance change immediately after withdrawal 97 | require(_value == 0 || allowance[msg.sender][_spender] == 0); 98 | 99 | allowance[msg.sender][_spender] = _value; 100 | Approval(msg.sender, _spender, _value); 101 | return true; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /solidity/contracts/build/ERC20Token.bin: -------------------------------------------------------------------------------- 1 | 60a0604052600960608190527f546f6b656e20302e310000000000000000000000000000000000000000000000608090815261003e916000919061011e565b5060408051602081019182905260009081905261005d9160019161011e565b5060408051602081019182905260009081905261007c9160029161011e565b506003805460ff191690556000600455341561009457fe5b604051610a71380380610a7183398101604090815281516020830151918301519083019291909101905b5b5b600083511180156100d2575060008251115b15156100de5760006000fd5b82516100f190600190602086019061011e565b50815161010590600290602085019061011e565b506003805460ff191660ff83161790555b5050506101be565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061015f57805160ff191683800117855561018c565b8280016001018555821561018c579182015b8281111561018c578251825591602001919060010190610171565b5b5061019992915061019d565b5090565b6101bb91905b8082111561019957600081556001016101a3565b5090565b90565b6108a4806101cd6000396000f300606060405236156100a15763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde0381146100a3578063095ea7b31461013357806318160ddd1461016657806323b872dd14610188578063313ce567146101c15780635a3b7e42146101e757806370a082311461027757806395d89b41146102a5578063a9059cbb14610335578063dd62ed3e14610368575bfe5b34156100ab57fe5b6100b361039c565b6040805160208082528351818301528351919283929083019185019080838382156100f9575b8051825260208311156100f957601f1990920191602091820191016100d9565b505050905090810190601f1680156101255780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561013b57fe5b610152600160a060020a0360043516602435610429565b604080519115158252519081900360200190f35b341561016e57fe5b6101766104e8565b60408051918252519081900360200190f35b341561019057fe5b610152600160a060020a03600435811690602435166044356104ee565b604080519115158252519081900360200190f35b34156101c957fe5b6101d1610626565b6040805160ff9092168252519081900360200190f35b34156101ef57fe5b6100b361062f565b6040805160208082528351818301528351919283929083019185019080838382156100f9575b8051825260208311156100f957601f1990920191602091820191016100d9565b505050905090810190601f1680156101255780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561027f57fe5b610176600160a060020a03600435166106bd565b60408051918252519081900360200190f35b34156102ad57fe5b6100b36106cf565b6040805160208082528351818301528351919283929083019185019080838382156100f9575b8051825260208311156100f957601f1990920191602091820191016100d9565b505050905090810190601f1680156101255780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561033d57fe5b610152600160a060020a036004351660243561075a565b604080519115158252519081900360200190f35b341561037057fe5b610176600160a060020a036004358116906024351661082a565b60408051918252519081900360200190f35b60018054604080516020600284861615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156104215780601f106103f657610100808354040283529160200191610421565b820191906000526020600020905b81548152906001019060200180831161040457829003601f168201915b505050505081565b600082600160a060020a03811615156104425760006000fd5b8215806104725750600160a060020a03338116600090815260066020908152604080832093881683529290522054155b151561047e5760006000fd5b600160a060020a03338116600081815260066020908152604080832094891680845294825291829020879055815187815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3600191505b5b5092915050565b60045481565b600083600160a060020a03811615156105075760006000fd5b83600160a060020a038116151561051e5760006000fd5b600160a060020a038087166000908152600660209081526040808320339094168352929052205461054f9085610847565b600160a060020a0380881660008181526006602090815260408083203390951683529381528382209490945590815260059092529020546105909085610847565b600160a060020a0380881660009081526005602052604080822093909355908716815220546105bf908561085e565b600160a060020a0380871660008181526005602090815260409182902094909455805188815290519193928a16927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3600192505b5b505b509392505050565b60035460ff1681565b6000805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156104215780601f106103f657610100808354040283529160200191610421565b820191906000526020600020905b81548152906001019060200180831161040457829003601f168201915b505050505081565b60056020526000908152604090205481565b6002805460408051602060018416156101000260001901909316849004601f810184900484028201840190925281815292918301828280156104215780601f106103f657610100808354040283529160200191610421565b820191906000526020600020905b81548152906001019060200180831161040457829003601f168201915b505050505081565b600082600160a060020a03811615156107735760006000fd5b600160a060020a0333166000908152600560205260409020546107969084610847565b600160a060020a0333811660009081526005602052604080822093909355908616815220546107c5908461085e565b600160a060020a038086166000818152600560209081526040918290209490945580518781529051919333909316927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3600191505b5b5092915050565b600660209081526000928352604080842090915290825290205481565b60008183101561085357fe5b508082035b92915050565b60008282018381101561086d57fe5b8091505b50929150505600a165627a7a72305820df77b620a05f424c1c1ec6f70bb2b951f9727cac057ab4183f6da5db3493b46c0029 -------------------------------------------------------------------------------- /solidity/test/ERC20Token.js: -------------------------------------------------------------------------------- 1 | /* global artifacts, contract, it, assert */ 2 | /* eslint-disable prefer-reflect */ 3 | 4 | const TestERC20Token = artifacts.require('TestERC20Token.sol'); 5 | const utils = require('./helpers/Utils'); 6 | 7 | const invalidAccount = '0x0'; 8 | 9 | contract('ERC20Token', (accounts) => { 10 | it('verifies the token name after construction', async () => { 11 | let token = await TestERC20Token.new('Token1', 'TKN1', 0); 12 | let name = await token.name.call(); 13 | assert.equal(name, 'Token1'); 14 | }); 15 | 16 | it('verifies the token symbol after construction', async () => { 17 | let token = await TestERC20Token.new('Token1', 'TKN1', 0); 18 | let symbol = await token.symbol.call(); 19 | assert.equal(symbol, 'TKN1'); 20 | }); 21 | 22 | it('verifies the balances after a transfer', async () => { 23 | let token = await TestERC20Token.new('Token1', 'TKN1', 10000); 24 | await token.transfer(accounts[1], 500); 25 | let balance; 26 | balance = await token.balanceOf.call(accounts[0]); 27 | assert.equal(balance, 9500); 28 | balance = await token.balanceOf.call(accounts[1]); 29 | assert.equal(balance, 500); 30 | }); 31 | 32 | it('verifies that a transfer fires a Transfer event', async () => { 33 | let token = await TestERC20Token.new('Token1', 'TKN1', 10000); 34 | let res = await token.transfer(accounts[1], 500); 35 | assert(res.logs.length > 0 && res.logs[0].event == 'Transfer'); 36 | }); 37 | 38 | it('should throw when attempting to transfer more than the balance', async () => { 39 | let token = await TestERC20Token.new('Token1', 'TKN1', 100); 40 | 41 | try { 42 | await token.transfer(accounts[1], 500); 43 | assert(false, "didn't throw"); 44 | } 45 | catch (error) { 46 | return utils.ensureException(error); 47 | } 48 | }); 49 | 50 | it('should throw when attempting to transfer to an invalid address', async () => { 51 | let token = await TestERC20Token.new('Token1', 'TKN1', 100); 52 | 53 | try { 54 | await token.transfer(invalidAccount, 10); 55 | assert(false, "didn't throw"); 56 | } 57 | catch (error) { 58 | return utils.ensureException(error); 59 | } 60 | }); 61 | 62 | it('verifies the allowance after an approval', async () => { 63 | let token = await TestERC20Token.new('Token1', 'TKN1', 10000); 64 | await token.approve(accounts[1], 500); 65 | let allowance = await token.allowance.call(accounts[0], accounts[1]); 66 | assert.equal(allowance, 500); 67 | }); 68 | 69 | it('verifies that an approval fires an Approval event', async () => { 70 | let token = await TestERC20Token.new('Token1', 'TKN1', 10000); 71 | let res = await token.approve(accounts[1], 500); 72 | assert(res.logs.length > 0 && res.logs[0].event == 'Approval'); 73 | }); 74 | 75 | it('should throw when attempting to define allowance for an invalid address', async () => { 76 | let token = await TestERC20Token.new('Token1', 'TKN1', 100); 77 | 78 | try { 79 | await token.approve(invalidAccount, 10); 80 | assert(false, "didn't throw"); 81 | } 82 | catch (error) { 83 | return utils.ensureException(error); 84 | } 85 | }); 86 | 87 | it('verifies the balances after transferring from another account', async () => { 88 | let token = await TestERC20Token.new('Token1', 'TKN1', 1000); 89 | await token.approve(accounts[1], 500); 90 | await token.transferFrom(accounts[0], accounts[2], 50, { from: accounts[1] }); 91 | let balance; 92 | balance = await token.balanceOf.call(accounts[0]); 93 | assert.equal(balance, 950); 94 | balance = await token.balanceOf.call(accounts[1]); 95 | assert.equal(balance, 0); 96 | balance = await token.balanceOf.call(accounts[2]); 97 | assert.equal(balance, 50); 98 | }); 99 | 100 | it('verifies that transferring from another account fires a Transfer event', async () => { 101 | let token = await TestERC20Token.new('Token1', 'TKN1', 1000); 102 | await token.approve(accounts[1], 500); 103 | let res = await token.transferFrom(accounts[0], accounts[2], 50, { from: accounts[1] }); 104 | assert(res.logs.length > 0 && res.logs[0].event == 'Transfer'); 105 | }); 106 | 107 | it('verifies the new allowance after transferring from another account', async () => { 108 | let token = await TestERC20Token.new('Token1', 'TKN1', 1000); 109 | await token.approve(accounts[1], 500); 110 | await token.transferFrom(accounts[0], accounts[2], 50, { from: accounts[1] }); 111 | let allowance = await token.allowance.call(accounts[0], accounts[1]); 112 | assert.equal(allowance, 450); 113 | }); 114 | 115 | it('should throw when attempting to transfer from another account more than the allowance', async () => { 116 | let token = await TestERC20Token.new('Token1', 'TKN1', 1000); 117 | await token.approve(accounts[1], 100); 118 | 119 | try { 120 | await token.transferFrom(accounts[0], accounts[2], 200, { from: accounts[1] }); 121 | assert(false, "didn't throw"); 122 | } 123 | catch (error) { 124 | return utils.ensureException(error); 125 | } 126 | }); 127 | 128 | it('should throw when attempting to transfer from an invalid account', async () => { 129 | let token = await TestERC20Token.new('Token1', 'TKN1', 1000); 130 | await token.approve(accounts[1], 100); 131 | 132 | try { 133 | await token.transferFrom(invalidAccount, accounts[2], 50, { from: accounts[1] }); 134 | assert(false, "didn't throw"); 135 | } 136 | catch (error) { 137 | return utils.ensureException(error); 138 | } 139 | }); 140 | 141 | it('should throw when attempting to transfer from to an invalid account', async () => { 142 | let token = await TestERC20Token.new('Token1', 'TKN1', 1000); 143 | await token.approve(accounts[1], 100); 144 | 145 | try { 146 | await token.transferFrom(accounts[0], invalidAccount, 50, { from: accounts[1] }); 147 | assert(false, "didn't throw"); 148 | } 149 | catch (error) { 150 | return utils.ensureException(error); 151 | } 152 | }); 153 | }); 154 | -------------------------------------------------------------------------------- /solidity/contracts/ENJCrowdfund.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | import './TokenHolder.sol'; 3 | import './ENJToken.sol'; 4 | 5 | 6 | contract ENJCrowdfund is TokenHolder { 7 | 8 | ///////////////////////////////////////// VARIABLE INITIALIZATION ///////////////////////////////////////// 9 | 10 | uint256 constant public startTime = 1507032000; // 10/03/2017 @ 12:00pm (UTC) crowdsale start time (in seconds) 11 | uint256 constant public endTime = 1509494340; // 10/31/2017 @ 11:59pm (UTC) crowdsale end time (in seconds) 12 | uint256 constant internal week2Start = startTime + (7 days); // 10/10/2017 @ 12:00pm (UTC) week 2 price begins 13 | uint256 constant internal week3Start = week2Start + (7 days); // 10/17/2017 @ 12:00pm (UTC) week 3 price begins 14 | uint256 constant internal week4Start = week3Start + (7 days); // 10/25/2017 @ 12:00pm (UTC) week 4 price begins 15 | 16 | uint256 public totalPresaleTokensYetToAllocate; // Counter that keeps track of presale tokens yet to allocate 17 | address public beneficiary = 0x0; // address to receive all ether contributions 18 | address public tokenAddress = 0x0; // address of the token itself 19 | 20 | ENJToken token; // ENJ Token interface 21 | 22 | ///////////////////////////////////////// EVENTS ///////////////////////////////////////// 23 | 24 | event CrowdsaleContribution(address indexed _contributor, uint256 _amount, uint256 _return); 25 | event PresaleContribution(address indexed _contributor, uint256 _amountOfTokens); 26 | 27 | ///////////////////////////////////////// CONSTRUCTOR ///////////////////////////////////////// 28 | 29 | /** 30 | @dev constructor 31 | @param _totalPresaleTokensYetToAllocate Total amount of presale tokens sold 32 | @param _beneficiary Address that will be receiving the ETH contributed 33 | */ 34 | function ENJCrowdfund(uint256 _totalPresaleTokensYetToAllocate, address _beneficiary) 35 | validAddress(_beneficiary) 36 | { 37 | totalPresaleTokensYetToAllocate = _totalPresaleTokensYetToAllocate; 38 | beneficiary = _beneficiary; 39 | } 40 | 41 | ///////////////////////////////////////// MODIFIERS ///////////////////////////////////////// 42 | 43 | // Ensures that the current time is between startTime (inclusive) and endTime (exclusive) 44 | modifier between() { 45 | assert(now >= startTime && now < endTime); 46 | _; 47 | } 48 | 49 | // Ensures the Token address is set 50 | modifier tokenIsSet() { 51 | require(tokenAddress != 0x0); 52 | _; 53 | } 54 | 55 | ///////////////////////////////////////// OWNER FUNCTIONS ///////////////////////////////////////// 56 | 57 | /** 58 | @dev Sets the ENJ Token address 59 | Can only be called once by the owner 60 | @param _tokenAddress ENJ Token Address 61 | */ 62 | function setToken(address _tokenAddress) validAddress(_tokenAddress) ownerOnly { 63 | require(tokenAddress == 0x0); 64 | tokenAddress = _tokenAddress; 65 | token = ENJToken(_tokenAddress); 66 | } 67 | 68 | /** 69 | @dev Sets a new Beneficiary address 70 | Can only be called by the owner 71 | @param _newBeneficiary Beneficiary Address 72 | */ 73 | function changeBeneficiary(address _newBeneficiary) validAddress(_newBeneficiary) ownerOnly { 74 | beneficiary = _newBeneficiary; 75 | } 76 | 77 | /** 78 | @dev Function to send ENJ to presale investors 79 | Can only be called while the presale is not over. 80 | @param _batchOfAddresses list of addresses 81 | @param _amountofENJ matching list of address balances 82 | */ 83 | function deliverPresaleTokens(address[] _batchOfAddresses, uint256[] _amountofENJ) external tokenIsSet ownerOnly returns (bool success) { 84 | require(now < startTime); 85 | for (uint256 i = 0; i < _batchOfAddresses.length; i++) { 86 | deliverPresaleTokenToClient(_batchOfAddresses[i], _amountofENJ[i]); 87 | } 88 | return true; 89 | } 90 | 91 | /** 92 | @dev Logic to transfer presale tokens 93 | Can only be called while the there are leftover presale tokens to allocate. Any multiple contribution from 94 | the same address will be aggregated. 95 | @param _accountHolder user address 96 | @param _amountofENJ balance to send out 97 | */ 98 | function deliverPresaleTokenToClient(address _accountHolder, uint256 _amountofENJ) internal ownerOnly { 99 | require(totalPresaleTokensYetToAllocate > 0); 100 | token.transfer(_accountHolder, _amountofENJ); 101 | token.addToAllocation(_amountofENJ); 102 | totalPresaleTokensYetToAllocate = safeSub(totalPresaleTokensYetToAllocate, _amountofENJ); 103 | PresaleContribution(_accountHolder, _amountofENJ); 104 | } 105 | 106 | ///////////////////////////////////////// PUBLIC FUNCTIONS ///////////////////////////////////////// 107 | /** 108 | @dev ETH contribution function 109 | Can only be called during the crowdsale. Also allows a person to buy tokens for another address 110 | 111 | @return tokens issued in return 112 | */ 113 | function contributeETH(address _to) public validAddress(_to) between tokenIsSet payable returns (uint256 amount) { 114 | return processContribution(_to); 115 | } 116 | 117 | /** 118 | @dev handles contribution logic 119 | note that the Contribution event is triggered using the sender as the contributor, regardless of the actual contributor 120 | 121 | @return tokens issued in return 122 | */ 123 | function processContribution(address _to) private returns (uint256 amount) { 124 | 125 | uint256 tokenAmount = getTotalAmountOfTokens(msg.value); 126 | beneficiary.transfer(msg.value); 127 | token.transfer(_to, tokenAmount); 128 | token.addToAllocation(tokenAmount); 129 | CrowdsaleContribution(_to, msg.value, tokenAmount); 130 | return tokenAmount; 131 | } 132 | 133 | 134 | 135 | ///////////////////////////////////////// CONSTANT FUNCTIONS ///////////////////////////////////////// 136 | 137 | /** 138 | @dev Returns total tokens allocated so far 139 | Constant function that simply returns a number 140 | 141 | @return total tokens allocated so far 142 | */ 143 | function totalEnjSold() public constant returns(uint256 total) { 144 | return token.totalAllocated(); 145 | } 146 | 147 | /** 148 | @dev computes the number of tokens that should be issued for a given contribution 149 | @param _contribution contribution amount 150 | @return computed number of tokens 151 | */ 152 | function getTotalAmountOfTokens(uint256 _contribution) public constant returns (uint256 amountOfTokens) { 153 | uint256 currentTokenRate = 0; 154 | if (now < week2Start) { 155 | return currentTokenRate = safeMul(_contribution, 6000); 156 | } else if (now < week3Start) { 157 | return currentTokenRate = safeMul(_contribution, 5000); 158 | } else if (now < week4Start) { 159 | return currentTokenRate = safeMul(_contribution, 4000); 160 | } else { 161 | return currentTokenRate = safeMul(_contribution, 3000); 162 | } 163 | 164 | } 165 | 166 | /** 167 | @dev Fallback function 168 | Main entry to buy into the crowdfund, all you need to do is send a value transaction 169 | to this contract address. Please include at least 100 000 gas in the transaction. 170 | */ 171 | function() payable { 172 | contributeETH(msg.sender); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /solidity/contracts/ENJToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | import './ERC20Token.sol'; 3 | import './TokenHolder.sol'; 4 | 5 | 6 | contract ENJToken is ERC20Token, TokenHolder { 7 | 8 | ///////////////////////////////////////// VARIABLE INITIALIZATION ///////////////////////////////////////// 9 | 10 | uint256 constant public ENJ_UNIT = 10 ** 18; 11 | uint256 public totalSupply = 1 * (10**9) * ENJ_UNIT; 12 | 13 | // Constants 14 | uint256 constant public maxPresaleSupply = 600 * 10**6 * ENJ_UNIT; // Total presale supply at max bonus 15 | uint256 constant public minCrowdsaleAllocation = 200 * 10**6 * ENJ_UNIT; // Min amount for crowdsale 16 | uint256 constant public incentivisationAllocation = 100 * 10**6 * ENJ_UNIT; // Incentivisation Allocation 17 | uint256 constant public advisorsAllocation = 26 * 10**6 * ENJ_UNIT; // Advisors Allocation 18 | uint256 constant public enjinTeamAllocation = 74 * 10**6 * ENJ_UNIT; // Enjin Team allocation 19 | 20 | address public crowdFundAddress; // Address of the crowdfund 21 | address public advisorAddress; // Enjin advisor's address 22 | address public incentivisationFundAddress; // Address that holds the incentivization funds 23 | address public enjinTeamAddress; // Enjin Team address 24 | 25 | // Variables 26 | 27 | uint256 public totalAllocatedToAdvisors = 0; // Counter to keep track of advisor token allocation 28 | uint256 public totalAllocatedToTeam = 0; // Counter to keep track of team token allocation 29 | uint256 public totalAllocated = 0; // Counter to keep track of overall token allocation 30 | uint256 constant public endTime = 1509494340; // 10/31/2017 @ 11:59pm (UTC) crowdsale end time (in seconds) 31 | 32 | bool internal isReleasedToPublic = false; // Flag to allow transfer/transferFrom before the end of the crowdfund 33 | 34 | uint256 internal teamTranchesReleased = 0; // Track how many tranches (allocations of 12.5% team tokens) have been released 35 | uint256 internal maxTeamTranches = 8; // The number of tranches allowed to the team until depleted 36 | 37 | ///////////////////////////////////////// MODIFIERS ///////////////////////////////////////// 38 | 39 | // Enjin Team timelock 40 | modifier safeTimelock() { 41 | require(now >= endTime + 6 * 4 weeks); 42 | _; 43 | } 44 | 45 | // Advisor Team timelock 46 | modifier advisorTimelock() { 47 | require(now >= endTime + 2 * 4 weeks); 48 | _; 49 | } 50 | 51 | // Function only accessible by the Crowdfund contract 52 | modifier crowdfundOnly() { 53 | require(msg.sender == crowdFundAddress); 54 | _; 55 | } 56 | 57 | ///////////////////////////////////////// CONSTRUCTOR ///////////////////////////////////////// 58 | 59 | /** 60 | @dev constructor 61 | @param _crowdFundAddress Crowdfund address 62 | @param _advisorAddress Advisor address 63 | */ 64 | function ENJToken(address _crowdFundAddress, address _advisorAddress, address _incentivisationFundAddress, address _enjinTeamAddress) 65 | ERC20Token("Enjin Coin", "ENJ", 18) 66 | { 67 | crowdFundAddress = _crowdFundAddress; 68 | advisorAddress = _advisorAddress; 69 | enjinTeamAddress = _enjinTeamAddress; 70 | incentivisationFundAddress = _incentivisationFundAddress; 71 | balanceOf[_crowdFundAddress] = minCrowdsaleAllocation + maxPresaleSupply; // Total presale + crowdfund tokens 72 | balanceOf[_incentivisationFundAddress] = incentivisationAllocation; // 10% Allocated for Marketing and Incentivisation 73 | totalAllocated += incentivisationAllocation; // Add to total Allocated funds 74 | } 75 | 76 | ///////////////////////////////////////// ERC20 OVERRIDE ///////////////////////////////////////// 77 | 78 | /** 79 | @dev send coins 80 | throws on any error rather then return a false flag to minimize user errors 81 | in addition to the standard checks, the function throws if transfers are disabled 82 | 83 | @param _to target address 84 | @param _value transfer amount 85 | 86 | @return true if the transfer was successful, throws if it wasn't 87 | */ 88 | function transfer(address _to, uint256 _value) public returns (bool success) { 89 | if (isTransferAllowed() == true || msg.sender == crowdFundAddress || msg.sender == incentivisationFundAddress) { 90 | assert(super.transfer(_to, _value)); 91 | return true; 92 | } 93 | revert(); 94 | } 95 | 96 | /** 97 | @dev an account/contract attempts to get the coins 98 | throws on any error rather then return a false flag to minimize user errors 99 | in addition to the standard checks, the function throws if transfers are disabled 100 | 101 | @param _from source address 102 | @param _to target address 103 | @param _value transfer amount 104 | 105 | @return true if the transfer was successful, throws if it wasn't 106 | */ 107 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { 108 | if (isTransferAllowed() == true || msg.sender == crowdFundAddress || msg.sender == incentivisationFundAddress) { 109 | assert(super.transferFrom(_from, _to, _value)); 110 | return true; 111 | } 112 | revert(); 113 | } 114 | 115 | ///////////////////////////////////////// ALLOCATION FUNCTIONS ///////////////////////////////////////// 116 | 117 | /** 118 | @dev Release one single tranche of the Enjin Team Token allocation 119 | throws if before timelock (6 months) ends and if not initiated by the owner of the contract 120 | returns true if valid 121 | Schedule goes as follows: 122 | 3 months: 12.5% (this tranche can only be released after the initial 6 months has passed) 123 | 6 months: 12.5% 124 | 9 months: 12.5% 125 | 12 months: 12.5% 126 | 15 months: 12.5% 127 | 18 months: 12.5% 128 | 21 months: 12.5% 129 | 24 months: 12.5% 130 | @return true if successful, throws if not 131 | */ 132 | function releaseEnjinTeamTokens() safeTimelock ownerOnly returns(bool success) { 133 | require(totalAllocatedToTeam < enjinTeamAllocation); 134 | 135 | uint256 enjinTeamAlloc = enjinTeamAllocation / 1000; 136 | uint256 currentTranche = uint256(now - endTime) / 12 weeks; // "months" after crowdsale end time (division floored) 137 | 138 | if(teamTranchesReleased < maxTeamTranches && currentTranche > teamTranchesReleased) { 139 | teamTranchesReleased++; 140 | 141 | uint256 amount = safeMul(enjinTeamAlloc, 125); 142 | balanceOf[enjinTeamAddress] = safeAdd(balanceOf[enjinTeamAddress], amount); 143 | Transfer(0x0, enjinTeamAddress, amount); 144 | totalAllocated = safeAdd(totalAllocated, amount); 145 | totalAllocatedToTeam = safeAdd(totalAllocatedToTeam, amount); 146 | return true; 147 | } 148 | revert(); 149 | } 150 | 151 | /** 152 | @dev release Advisors Token allocation 153 | throws if before timelock (2 months) ends or if no initiated by the advisors address 154 | or if there is no more allocation to give out 155 | returns true if valid 156 | 157 | @return true if successful, throws if not 158 | */ 159 | function releaseAdvisorTokens() advisorTimelock ownerOnly returns(bool success) { 160 | require(totalAllocatedToAdvisors == 0); 161 | balanceOf[advisorAddress] = safeAdd(balanceOf[advisorAddress], advisorsAllocation); 162 | totalAllocated = safeAdd(totalAllocated, advisorsAllocation); 163 | totalAllocatedToAdvisors = advisorsAllocation; 164 | Transfer(0x0, advisorAddress, advisorsAllocation); 165 | return true; 166 | } 167 | 168 | /** 169 | @dev Retrieve unsold tokens from the crowdfund 170 | throws if before timelock (6 months from end of Crowdfund) ends and if no initiated by the owner of the contract 171 | returns true if valid 172 | 173 | @return true if successful, throws if not 174 | */ 175 | function retrieveUnsoldTokens() safeTimelock ownerOnly returns(bool success) { 176 | uint256 amountOfTokens = balanceOf[crowdFundAddress]; 177 | balanceOf[crowdFundAddress] = 0; 178 | balanceOf[incentivisationFundAddress] = safeAdd(balanceOf[incentivisationFundAddress], amountOfTokens); 179 | totalAllocated = safeAdd(totalAllocated, amountOfTokens); 180 | Transfer(crowdFundAddress, incentivisationFundAddress, amountOfTokens); 181 | return true; 182 | } 183 | 184 | /** 185 | @dev Keep track of token allocations 186 | can only be called by the crowdfund contract 187 | */ 188 | function addToAllocation(uint256 _amount) crowdfundOnly { 189 | totalAllocated = safeAdd(totalAllocated, _amount); 190 | } 191 | 192 | /** 193 | @dev Function to allow transfers 194 | can only be called by the owner of the contract 195 | Transfers will be allowed regardless after the crowdfund end time. 196 | */ 197 | function allowTransfers() ownerOnly { 198 | isReleasedToPublic = true; 199 | } 200 | 201 | /** 202 | @dev User transfers are allowed/rejected 203 | Transfers are forbidden before the end of the crowdfund 204 | */ 205 | function isTransferAllowed() internal constant returns(bool) { 206 | if (now > endTime || isReleasedToPublic == true) { 207 | return true; 208 | } 209 | return false; 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /solidity/build/contracts/ERC20Token.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "ERC20Token", 3 | "abi": [ 4 | { 5 | "constant": true, 6 | "inputs": [], 7 | "name": "name", 8 | "outputs": [ 9 | { 10 | "name": "", 11 | "type": "string" 12 | } 13 | ], 14 | "payable": false, 15 | "type": "function" 16 | }, 17 | { 18 | "constant": false, 19 | "inputs": [ 20 | { 21 | "name": "_spender", 22 | "type": "address" 23 | }, 24 | { 25 | "name": "_value", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "approve", 30 | "outputs": [ 31 | { 32 | "name": "success", 33 | "type": "bool" 34 | } 35 | ], 36 | "payable": false, 37 | "type": "function" 38 | }, 39 | { 40 | "constant": true, 41 | "inputs": [], 42 | "name": "totalSupply", 43 | "outputs": [ 44 | { 45 | "name": "", 46 | "type": "uint256" 47 | } 48 | ], 49 | "payable": false, 50 | "type": "function" 51 | }, 52 | { 53 | "constant": false, 54 | "inputs": [ 55 | { 56 | "name": "_from", 57 | "type": "address" 58 | }, 59 | { 60 | "name": "_to", 61 | "type": "address" 62 | }, 63 | { 64 | "name": "_value", 65 | "type": "uint256" 66 | } 67 | ], 68 | "name": "transferFrom", 69 | "outputs": [ 70 | { 71 | "name": "success", 72 | "type": "bool" 73 | } 74 | ], 75 | "payable": false, 76 | "type": "function" 77 | }, 78 | { 79 | "constant": true, 80 | "inputs": [], 81 | "name": "decimals", 82 | "outputs": [ 83 | { 84 | "name": "", 85 | "type": "uint8" 86 | } 87 | ], 88 | "payable": false, 89 | "type": "function" 90 | }, 91 | { 92 | "constant": true, 93 | "inputs": [], 94 | "name": "standard", 95 | "outputs": [ 96 | { 97 | "name": "", 98 | "type": "string" 99 | } 100 | ], 101 | "payable": false, 102 | "type": "function" 103 | }, 104 | { 105 | "constant": true, 106 | "inputs": [ 107 | { 108 | "name": "", 109 | "type": "address" 110 | } 111 | ], 112 | "name": "balanceOf", 113 | "outputs": [ 114 | { 115 | "name": "", 116 | "type": "uint256" 117 | } 118 | ], 119 | "payable": false, 120 | "type": "function" 121 | }, 122 | { 123 | "constant": true, 124 | "inputs": [], 125 | "name": "symbol", 126 | "outputs": [ 127 | { 128 | "name": "", 129 | "type": "string" 130 | } 131 | ], 132 | "payable": false, 133 | "type": "function" 134 | }, 135 | { 136 | "constant": false, 137 | "inputs": [ 138 | { 139 | "name": "_to", 140 | "type": "address" 141 | }, 142 | { 143 | "name": "_value", 144 | "type": "uint256" 145 | } 146 | ], 147 | "name": "transfer", 148 | "outputs": [ 149 | { 150 | "name": "success", 151 | "type": "bool" 152 | } 153 | ], 154 | "payable": false, 155 | "type": "function" 156 | }, 157 | { 158 | "constant": true, 159 | "inputs": [ 160 | { 161 | "name": "", 162 | "type": "address" 163 | }, 164 | { 165 | "name": "", 166 | "type": "address" 167 | } 168 | ], 169 | "name": "allowance", 170 | "outputs": [ 171 | { 172 | "name": "", 173 | "type": "uint256" 174 | } 175 | ], 176 | "payable": false, 177 | "type": "function" 178 | }, 179 | { 180 | "inputs": [ 181 | { 182 | "name": "_name", 183 | "type": "string" 184 | }, 185 | { 186 | "name": "_symbol", 187 | "type": "string" 188 | }, 189 | { 190 | "name": "_decimals", 191 | "type": "uint8" 192 | } 193 | ], 194 | "payable": false, 195 | "type": "constructor" 196 | }, 197 | { 198 | "anonymous": false, 199 | "inputs": [ 200 | { 201 | "indexed": true, 202 | "name": "_from", 203 | "type": "address" 204 | }, 205 | { 206 | "indexed": true, 207 | "name": "_to", 208 | "type": "address" 209 | }, 210 | { 211 | "indexed": false, 212 | "name": "_value", 213 | "type": "uint256" 214 | } 215 | ], 216 | "name": "Transfer", 217 | "type": "event" 218 | }, 219 | { 220 | "anonymous": false, 221 | "inputs": [ 222 | { 223 | "indexed": true, 224 | "name": "_owner", 225 | "type": "address" 226 | }, 227 | { 228 | "indexed": true, 229 | "name": "_spender", 230 | "type": "address" 231 | }, 232 | { 233 | "indexed": false, 234 | "name": "_value", 235 | "type": "uint256" 236 | } 237 | ], 238 | "name": "Approval", 239 | "type": "event" 240 | } 241 | ], 242 | "unlinked_binary": "0x606060405260408051908101604052600981527f546f6b656e20302e3100000000000000000000000000000000000000000000006020820152600090805161004b929160200190610137565b50602060405190810160405260008152600190805161006e929160200190610137565b506020604051908101604052600081526002908051610091929160200190610137565b506003805460ff19169055600060045534156100ac57600080fd5b604051610ac5380380610ac5833981016040528080518201919060200180518201919060200180519150505b5b5b600083511180156100ec575060008251115b15156100f757600080fd5b600183805161010a929160200190610137565b50600282805161011e929160200190610137565b506003805460ff191660ff83161790555b5050506101d7565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061017857805160ff19168380011785556101a5565b828001600101855582156101a5579182015b828111156101a557825182559160200191906001019061018a565b5b506101b29291506101b6565b5090565b6101d491905b808211156101b257600081556001016101bc565b5090565b90565b6108df806101e66000396000f300606060405236156100a15763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde0381146100a6578063095ea7b31461013157806318160ddd1461016757806323b872dd1461018c578063313ce567146101c85780635a3b7e42146101f157806370a082311461027c57806395d89b41146102ad578063a9059cbb14610338578063dd62ed3e1461036e575b600080fd5b34156100b157600080fd5b6100b96103a5565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156100f65780820151818401525b6020016100dd565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561013c57600080fd5b610153600160a060020a0360043516602435610443565b604051901515815260200160405180910390f35b341561017257600080fd5b61017a610503565b60405190815260200160405180910390f35b341561019757600080fd5b610153600160a060020a0360043581169060243516604435610509565b604051901515815260200160405180910390f35b34156101d357600080fd5b6101db61063f565b60405160ff909116815260200160405180910390f35b34156101fc57600080fd5b6100b9610648565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156100f65780820151818401525b6020016100dd565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561028757600080fd5b61017a600160a060020a03600435166106e6565b60405190815260200160405180910390f35b34156102b857600080fd5b6100b96106f8565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156100f65780820151818401525b6020016100dd565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561034357600080fd5b610153600160a060020a0360043516602435610796565b604051901515815260200160405180910390f35b341561037957600080fd5b61017a600160a060020a0360043581169060243516610865565b60405190815260200160405180910390f35b60018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561043b5780601f106104105761010080835404028352916020019161043b565b820191906000526020600020905b81548152906001019060200180831161041e57829003601f168201915b505050505081565b600082600160a060020a038116151561045b57600080fd5b82158061048b5750600160a060020a03338116600090815260066020908152604080832093881683529290522054155b151561049657600080fd5b600160a060020a03338116600081815260066020908152604080832094891680845294909152908190208690557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259086905190815260200160405180910390a3600191505b5b5092915050565b60045481565b600083600160a060020a038116151561052157600080fd5b83600160a060020a038116151561053757600080fd5b600160a060020a03808716600090815260066020908152604080832033909416835292905220546105689085610882565b600160a060020a0380881660008181526006602090815260408083203390951683529381528382209490945590815260059092529020546105a99085610882565b600160a060020a0380881660009081526005602052604080822093909355908716815220546105d89085610899565b600160a060020a03808716600081815260056020526040908190209390935591908816907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9087905190815260200160405180910390a3600192505b5b505b509392505050565b60035460ff1681565b60008054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561043b5780601f106104105761010080835404028352916020019161043b565b820191906000526020600020905b81548152906001019060200180831161041e57829003601f168201915b505050505081565b60056020526000908152604090205481565b60028054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561043b5780601f106104105761010080835404028352916020019161043b565b820191906000526020600020905b81548152906001019060200180831161041e57829003601f168201915b505050505081565b600082600160a060020a03811615156107ae57600080fd5b600160a060020a0333166000908152600560205260409020546107d19084610882565b600160a060020a0333811660009081526005602052604080822093909355908616815220546108009084610899565b600160a060020a0380861660008181526005602052604090819020939093559133909116907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9086905190815260200160405180910390a3600191505b5b5092915050565b600660209081526000928352604080842090915290825290205481565b60008183101561088e57fe5b508082035b92915050565b6000828201838110156108a857fe5b8091505b50929150505600a165627a7a72305820ac19f77e4e3a92e2d789c59090f8be1b397faf36274aa6be20a82250816deb520029", 243 | "networks": {}, 244 | "schema_version": "0.0.5", 245 | "updated_at": 1505761384009 246 | } -------------------------------------------------------------------------------- /solidity/build/contracts/TestERC20Token.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "TestERC20Token", 3 | "abi": [ 4 | { 5 | "constant": true, 6 | "inputs": [], 7 | "name": "name", 8 | "outputs": [ 9 | { 10 | "name": "", 11 | "type": "string" 12 | } 13 | ], 14 | "payable": false, 15 | "type": "function" 16 | }, 17 | { 18 | "constant": false, 19 | "inputs": [ 20 | { 21 | "name": "_spender", 22 | "type": "address" 23 | }, 24 | { 25 | "name": "_value", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "approve", 30 | "outputs": [ 31 | { 32 | "name": "success", 33 | "type": "bool" 34 | } 35 | ], 36 | "payable": false, 37 | "type": "function" 38 | }, 39 | { 40 | "constant": true, 41 | "inputs": [], 42 | "name": "totalSupply", 43 | "outputs": [ 44 | { 45 | "name": "", 46 | "type": "uint256" 47 | } 48 | ], 49 | "payable": false, 50 | "type": "function" 51 | }, 52 | { 53 | "constant": false, 54 | "inputs": [ 55 | { 56 | "name": "_from", 57 | "type": "address" 58 | }, 59 | { 60 | "name": "_to", 61 | "type": "address" 62 | }, 63 | { 64 | "name": "_value", 65 | "type": "uint256" 66 | } 67 | ], 68 | "name": "transferFrom", 69 | "outputs": [ 70 | { 71 | "name": "success", 72 | "type": "bool" 73 | } 74 | ], 75 | "payable": false, 76 | "type": "function" 77 | }, 78 | { 79 | "constant": true, 80 | "inputs": [], 81 | "name": "decimals", 82 | "outputs": [ 83 | { 84 | "name": "", 85 | "type": "uint8" 86 | } 87 | ], 88 | "payable": false, 89 | "type": "function" 90 | }, 91 | { 92 | "constant": true, 93 | "inputs": [], 94 | "name": "standard", 95 | "outputs": [ 96 | { 97 | "name": "", 98 | "type": "string" 99 | } 100 | ], 101 | "payable": false, 102 | "type": "function" 103 | }, 104 | { 105 | "constant": true, 106 | "inputs": [ 107 | { 108 | "name": "", 109 | "type": "address" 110 | } 111 | ], 112 | "name": "balanceOf", 113 | "outputs": [ 114 | { 115 | "name": "", 116 | "type": "uint256" 117 | } 118 | ], 119 | "payable": false, 120 | "type": "function" 121 | }, 122 | { 123 | "constant": true, 124 | "inputs": [], 125 | "name": "symbol", 126 | "outputs": [ 127 | { 128 | "name": "", 129 | "type": "string" 130 | } 131 | ], 132 | "payable": false, 133 | "type": "function" 134 | }, 135 | { 136 | "constant": false, 137 | "inputs": [ 138 | { 139 | "name": "_to", 140 | "type": "address" 141 | }, 142 | { 143 | "name": "_value", 144 | "type": "uint256" 145 | } 146 | ], 147 | "name": "transfer", 148 | "outputs": [ 149 | { 150 | "name": "success", 151 | "type": "bool" 152 | } 153 | ], 154 | "payable": false, 155 | "type": "function" 156 | }, 157 | { 158 | "constant": true, 159 | "inputs": [ 160 | { 161 | "name": "", 162 | "type": "address" 163 | }, 164 | { 165 | "name": "", 166 | "type": "address" 167 | } 168 | ], 169 | "name": "allowance", 170 | "outputs": [ 171 | { 172 | "name": "", 173 | "type": "uint256" 174 | } 175 | ], 176 | "payable": false, 177 | "type": "function" 178 | }, 179 | { 180 | "inputs": [ 181 | { 182 | "name": "_name", 183 | "type": "string" 184 | }, 185 | { 186 | "name": "_symbol", 187 | "type": "string" 188 | }, 189 | { 190 | "name": "_supply", 191 | "type": "uint256" 192 | } 193 | ], 194 | "payable": false, 195 | "type": "constructor" 196 | }, 197 | { 198 | "anonymous": false, 199 | "inputs": [ 200 | { 201 | "indexed": true, 202 | "name": "_from", 203 | "type": "address" 204 | }, 205 | { 206 | "indexed": true, 207 | "name": "_to", 208 | "type": "address" 209 | }, 210 | { 211 | "indexed": false, 212 | "name": "_value", 213 | "type": "uint256" 214 | } 215 | ], 216 | "name": "Transfer", 217 | "type": "event" 218 | }, 219 | { 220 | "anonymous": false, 221 | "inputs": [ 222 | { 223 | "indexed": true, 224 | "name": "_owner", 225 | "type": "address" 226 | }, 227 | { 228 | "indexed": true, 229 | "name": "_spender", 230 | "type": "address" 231 | }, 232 | { 233 | "indexed": false, 234 | "name": "_value", 235 | "type": "uint256" 236 | } 237 | ], 238 | "name": "Approval", 239 | "type": "event" 240 | } 241 | ], 242 | "unlinked_binary": "0x606060405260408051908101604052600981527f546f6b656e20302e3100000000000000000000000000000000000000000000006020820152600090805161004b929160200190610160565b50602060405190810160405260008152600190805161006e929160200190610160565b506020604051908101604052600081526002908051610091929160200190610160565b506003805460ff19169055600060045534156100ac57600080fd5b604051610aee380380610aee833981016040528080518201919060200180518201919060200180519150505b828260005b5b5b600083511180156100f1575060008251115b15156100fc57600080fd5b600183805161010f929160200190610160565b506002828051610123929160200190610160565b506003805460ff191660ff83161790555b5050506004819055600160a060020a03331660009081526005602052604090208190555b505050610200565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106101a157805160ff19168380011785556101ce565b828001600101855582156101ce579182015b828111156101ce5782518255916020019190600101906101b3565b5b506101db9291506101df565b5090565b6101fd91905b808211156101db57600081556001016101e5565b5090565b90565b6108df8061020f6000396000f300606060405236156100a15763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde0381146100a6578063095ea7b31461013157806318160ddd1461016757806323b872dd1461018c578063313ce567146101c85780635a3b7e42146101f157806370a082311461027c57806395d89b41146102ad578063a9059cbb14610338578063dd62ed3e1461036e575b600080fd5b34156100b157600080fd5b6100b96103a5565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156100f65780820151818401525b6020016100dd565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561013c57600080fd5b610153600160a060020a0360043516602435610443565b604051901515815260200160405180910390f35b341561017257600080fd5b61017a610503565b60405190815260200160405180910390f35b341561019757600080fd5b610153600160a060020a0360043581169060243516604435610509565b604051901515815260200160405180910390f35b34156101d357600080fd5b6101db61063f565b60405160ff909116815260200160405180910390f35b34156101fc57600080fd5b6100b9610648565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156100f65780820151818401525b6020016100dd565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561028757600080fd5b61017a600160a060020a03600435166106e6565b60405190815260200160405180910390f35b34156102b857600080fd5b6100b96106f8565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156100f65780820151818401525b6020016100dd565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561034357600080fd5b610153600160a060020a0360043516602435610796565b604051901515815260200160405180910390f35b341561037957600080fd5b61017a600160a060020a0360043581169060243516610865565b60405190815260200160405180910390f35b60018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561043b5780601f106104105761010080835404028352916020019161043b565b820191906000526020600020905b81548152906001019060200180831161041e57829003601f168201915b505050505081565b600082600160a060020a038116151561045b57600080fd5b82158061048b5750600160a060020a03338116600090815260066020908152604080832093881683529290522054155b151561049657600080fd5b600160a060020a03338116600081815260066020908152604080832094891680845294909152908190208690557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259086905190815260200160405180910390a3600191505b5b5092915050565b60045481565b600083600160a060020a038116151561052157600080fd5b83600160a060020a038116151561053757600080fd5b600160a060020a03808716600090815260066020908152604080832033909416835292905220546105689085610882565b600160a060020a0380881660008181526006602090815260408083203390951683529381528382209490945590815260059092529020546105a99085610882565b600160a060020a0380881660009081526005602052604080822093909355908716815220546105d89085610899565b600160a060020a03808716600081815260056020526040908190209390935591908816907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9087905190815260200160405180910390a3600192505b5b505b509392505050565b60035460ff1681565b60008054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561043b5780601f106104105761010080835404028352916020019161043b565b820191906000526020600020905b81548152906001019060200180831161041e57829003601f168201915b505050505081565b60056020526000908152604090205481565b60028054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561043b5780601f106104105761010080835404028352916020019161043b565b820191906000526020600020905b81548152906001019060200180831161041e57829003601f168201915b505050505081565b600082600160a060020a03811615156107ae57600080fd5b600160a060020a0333166000908152600560205260409020546107d19084610882565b600160a060020a0333811660009081526005602052604080822093909355908616815220546108009084610899565b600160a060020a0380861660008181526005602052604090819020939093559133909116907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9086905190815260200160405180910390a3600191505b5b5092915050565b600660209081526000928352604080842090915290825290205481565b60008183101561088e57fe5b508082035b92915050565b6000828201838110156108a857fe5b8091505b50929150505600a165627a7a72305820ddaf3bc809ec6a909e25a587535013cf52a54ebf8c234578c642448c499722910029", 243 | "networks": {}, 244 | "schema_version": "0.0.5", 245 | "updated_at": 1505761384009 246 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /solidity/test/helpers/FormulaConstants.js: -------------------------------------------------------------------------------- 1 | module.exports.MIN_PRECISION = 32; 2 | module.exports.MAX_PRECISION = 127; 3 | module.exports.maxExpArray = [ 4 | /* 0 */ '0xc1', 5 | /* 1 */ '0x17a', 6 | /* 2 */ '0x2e5', 7 | /* 3 */ '0x5ab', 8 | /* 4 */ '0xb1b', 9 | /* 5 */ '0x15bf', 10 | /* 6 */ '0x2a0c', 11 | /* 7 */ '0x50a2', 12 | /* 8 */ '0x9aa2', 13 | /* 9 */ '0x1288c', 14 | /* 10 */ '0x238b2', 15 | /* 11 */ '0x4429a', 16 | /* 12 */ '0x82b78', 17 | /* 13 */ '0xfaadc', 18 | /* 14 */ '0x1e0bb8', 19 | /* 15 */ '0x399e96', 20 | /* 16 */ '0x6e7f88', 21 | /* 17 */ '0xd3e7a3', 22 | /* 18 */ '0x1965fea', 23 | /* 19 */ '0x30b5057', 24 | /* 20 */ '0x5d681f3', 25 | /* 21 */ '0xb320d03', 26 | /* 22 */ '0x15784a40', 27 | /* 23 */ '0x292c5bdd', 28 | /* 24 */ '0x4ef57b9b', 29 | /* 25 */ '0x976bd995', 30 | /* 26 */ '0x122624e32', 31 | /* 27 */ '0x22ce03cd5', 32 | /* 28 */ '0x42beef808', 33 | /* 29 */ '0x7ffffffff', 34 | /* 30 */ '0xf577eded5', 35 | /* 31 */ '0x1d6bd8b2eb', 36 | /* 32 */ '0x386bfdba29', 37 | /* 33 */ '0x6c3390ecc8', 38 | /* 34 */ '0xcf8014760f', 39 | /* 35 */ '0x18ded91f0e7', 40 | /* 36 */ '0x2fb1d8fe082', 41 | /* 37 */ '0x5b771955b36', 42 | /* 38 */ '0xaf67a93bb50', 43 | /* 39 */ '0x15060c256cb2', 44 | /* 40 */ '0x285145f31ae5', 45 | /* 41 */ '0x4d5156639708', 46 | /* 42 */ '0x944620b0e70e', 47 | /* 43 */ '0x11c592761c666', 48 | /* 44 */ '0x2214d10d014ea', 49 | /* 45 */ '0x415bc6d6fb7dd', 50 | /* 46 */ '0x7d56e76777fc5', 51 | /* 47 */ '0xf05dc6b27edad', 52 | /* 48 */ '0x1ccf4b44bb4820', 53 | /* 49 */ '0x373fc456c53bb7', 54 | /* 50 */ '0x69f3d1c921891c', 55 | /* 51 */ '0xcb2ff529eb71e4', 56 | /* 52 */ '0x185a82b87b72e95', 57 | /* 53 */ '0x2eb40f9f620fda6', 58 | /* 54 */ '0x5990681d961a1ea', 59 | /* 55 */ '0xabc25204e02828d', 60 | /* 56 */ '0x14962dee9dc97640', 61 | /* 57 */ '0x277abdcdab07d5a7', 62 | /* 58 */ '0x4bb5ecca963d54ab', 63 | /* 59 */ '0x9131271922eaa606', 64 | /* 60 */ '0x116701e6ab0cd188d', 65 | /* 61 */ '0x215f77c045fbe8856', 66 | /* 62 */ '0x3ffffffffffffffff', 67 | /* 63 */ '0x7abbf6f6abb9d087f', 68 | /* 64 */ '0xeb5ec597592befbf4', 69 | /* 65 */ '0x1c35fedd14b861eb04', 70 | /* 66 */ '0x3619c87664579bc94a', 71 | /* 67 */ '0x67c00a3b07ffc01fd6', 72 | /* 68 */ '0xc6f6c8f8739773a7a4', 73 | /* 69 */ '0x17d8ec7f04136f4e561', 74 | /* 70 */ '0x2dbb8caad9b7097b91a', 75 | /* 71 */ '0x57b3d49dda84556d6f6', 76 | /* 72 */ '0xa830612b6591d9d9e61', 77 | /* 73 */ '0x1428a2f98d728ae223dd', 78 | /* 74 */ '0x26a8ab31cb8464ed99e1', 79 | /* 75 */ '0x4a23105873875bd52dfd', 80 | /* 76 */ '0x8e2c93b0e33355320ead', 81 | /* 77 */ '0x110a688680a7530515f3e', 82 | /* 78 */ '0x20ade36b7dbeeb8d79659', 83 | /* 79 */ '0x3eab73b3bbfe282243ce1', 84 | /* 80 */ '0x782ee3593f6d69831c453', 85 | /* 81 */ '0xe67a5a25da41063de1495', 86 | /* 82 */ '0x1b9fe22b629ddbbcdf8754', 87 | /* 83 */ '0x34f9e8e490c48e67e6ab8b', 88 | /* 84 */ '0x6597fa94f5b8f20ac16666', 89 | /* 85 */ '0xc2d415c3db974ab32a5184', 90 | /* 86 */ '0x175a07cfb107ed35ab61430', 91 | /* 87 */ '0x2cc8340ecb0d0f520a6af58', 92 | /* 88 */ '0x55e129027014146b9e37405', 93 | /* 89 */ '0xa4b16f74ee4bb2040a1ec6c', 94 | /* 90 */ '0x13bd5ee6d583ead3bd636b5c', 95 | /* 91 */ '0x25daf6654b1eaa55fd64df5e', 96 | /* 92 */ '0x4898938c9175530325b9d116', 97 | /* 93 */ '0x8b380f3558668c46c91c49a2', 98 | /* 94 */ '0x10afbbe022fdf442b2a522507', 99 | /* 95 */ '0x1ffffffffffffffffffffffff', 100 | /* 96 */ '0x3d5dfb7b55dce843f89a7dbcb', 101 | /* 97 */ '0x75af62cbac95f7dfa3295ec26', 102 | /* 98 */ '0xe1aff6e8a5c30f58221fbf899', 103 | /* 99 */ '0x1b0ce43b322bcde4a56e8ada5a', 104 | /* 100 */ '0x33e0051d83ffe00feb432b473b', 105 | /* 101 */ '0x637b647c39cbb9d3d26c56e949', 106 | /* 102 */ '0xbec763f8209b7a72b0afea0d31', 107 | /* 103 */ '0x16ddc6556cdb84bdc8d12d22e6f', 108 | /* 104 */ '0x2bd9ea4eed422ab6b7b072b029e', 109 | /* 105 */ '0x54183095b2c8ececf30dd533d03', 110 | /* 106 */ '0xa14517cc6b9457111eed5b8adf1', 111 | /* 107 */ '0x13545598e5c23276ccf0ede68034', 112 | /* 108 */ '0x2511882c39c3adea96fec2102329', 113 | /* 109 */ '0x471649d87199aa990756806903c5', 114 | /* 110 */ '0x88534434053a9828af9f37367ee6', 115 | /* 111 */ '0x1056f1b5bedf75c6bcb2ce8aed428', 116 | /* 112 */ '0x1f55b9d9ddff141121e70ebe0104e', 117 | /* 113 */ '0x3c1771ac9fb6b4c18e229803dae82', 118 | /* 114 */ '0x733d2d12ed20831ef0a4aead8c66d', 119 | /* 115 */ '0xdcff115b14eedde6fc3aa5353f2e4', 120 | /* 116 */ '0x1a7cf47248624733f355c5c1f0d1f1', 121 | /* 117 */ '0x32cbfd4a7adc790560b3335687b89b', 122 | /* 118 */ '0x616a0ae1edcba5599528c20605b3f6', 123 | /* 119 */ '0xbad03e7d883f69ad5b0a186184e06b', 124 | /* 120 */ '0x16641a07658687a905357ac0ebe198b', 125 | /* 121 */ '0x2af09481380a0a35cf1ba02f36c6a56', 126 | /* 122 */ '0x5258b7ba7725d902050f6360afddf96', 127 | /* 123 */ '0x9deaf736ac1f569deb1b5ae3f36c130', 128 | /* 124 */ '0x12ed7b32a58f552afeb26faf21deca06', 129 | /* 125 */ '0x244c49c648baa98192dce88b42f53caf', 130 | /* 126 */ '0x459c079aac334623648e24d17c74b3dc', 131 | /* 127 */ '0x6ae67b5f2f528d5f3189036ee0f27453', 132 | ]; 133 | module.exports.maxValArray = [ 134 | /* 0 */ '0x114b06b554307756ca04f4cba9a73491a', 135 | /* 1 */ '0x116725662328c918cc52a23d39760e5b9', 136 | /* 2 */ '0x120a92c8c432654ba21dcdb328faecff8', 137 | /* 3 */ '0x120b168bc2dcf50ec6a41c4c207124358', 138 | /* 4 */ '0x1267c5d67acef5c18aba51d228f9f502f', 139 | /* 5 */ '0x1267ae3becb1b8844eb792511b7bb538f', 140 | /* 6 */ '0xc29d4a7745ae89ef20a05db656441649', 141 | /* 7 */ '0x6242dea9277cf2d473468985313625bb', 142 | /* 8 */ '0x31aef9b37fbc57d1ca51c53eb472c345', 143 | /* 9 */ '0x1923b23c38638957faeb8b4fe57b5ead', 144 | /* 10 */ '0xcb919ec79bf364210433b9b9680eadd', 145 | /* 11 */ '0x67186c63186761709a96a91d44ff2bf', 146 | /* 12 */ '0x343e6242f854acd626b78022c4a8002', 147 | /* 13 */ '0x1a7efb7b1b687ccb2bb413b92d5e413', 148 | /* 14 */ '0xd72d0627fadb6aa6e0f3c994a5592a', 149 | /* 15 */ '0x6d4f32a7dcd0924c122312b7522049', 150 | /* 16 */ '0x37947990f145344d736c1e7e5cff2f', 151 | /* 17 */ '0x1c49d8ceb31e3ef3e98703e0e656cc', 152 | /* 18 */ '0xe69cb6255a180e2ead170f676fa3c', 153 | /* 19 */ '0x75a24620898b4a19aafdfa67d23e8', 154 | /* 20 */ '0x3c1419351dd33d49e1ce203728e25', 155 | /* 21 */ '0x1eb97e709f819575e656eefb8bd98', 156 | /* 22 */ '0xfbc4a1f867f03d4c057d522b6523', 157 | /* 23 */ '0x812507c14867d2237468ba955def', 158 | /* 24 */ '0x425b9d8ca5a58142d5172c3eb2b5', 159 | /* 25 */ '0x2228e76a368b75ea80882c9f6010', 160 | /* 26 */ '0x119ed9f43c52cdd38348ee8d7b23', 161 | /* 27 */ '0x91bfcff5e91c7f115393af54bad', 162 | /* 28 */ '0x4b8845f19f7b4a93653588ce846', 163 | /* 29 */ '0x273fa600431f30b0f21b619c797', 164 | /* 30 */ '0x1474840ba4069691110ff1bb823', 165 | /* 31 */ '0xab212322b671a11d3647e3ecaf', 166 | /* 32 */ '0x59ce8876bf3a3b1b396ae19c95', 167 | /* 33 */ '0x2f523e50d3b0d68a3e39f2f06e', 168 | /* 34 */ '0x190c4f51698c5ee5c3b34928a0', 169 | /* 35 */ '0xd537c5d5647f2a79965d56f94', 170 | /* 36 */ '0x72169649d403b5b512b40d5c2', 171 | /* 37 */ '0x3d713a141a21a93a218c980c1', 172 | /* 38 */ '0x215544c77538e6de9275431a6', 173 | /* 39 */ '0x123c0edc8bf784d147024b7df', 174 | /* 40 */ '0xa11eada236d9ccb5d9a46757', 175 | /* 41 */ '0x59f185464ae514ade263ef14', 176 | /* 42 */ '0x32d507935c586248656e95cb', 177 | /* 43 */ '0x1d2270a4f18efd8eab5a27d7', 178 | /* 44 */ '0x10f7bfaf758e3c1010bead08', 179 | /* 45 */ '0xa101f6bc5df6cc4cf4cb56d', 180 | /* 46 */ '0x61773c45cb6403833991e6e', 181 | /* 47 */ '0x3c5f563f3abca8034b91c7d', 182 | /* 48 */ '0x265cd2a70d374397f75a844', 183 | /* 49 */ '0x1911bbf62c34780ee22ce8e', 184 | /* 50 */ '0x10e3053085e97a7710c2e6d', 185 | /* 51 */ '0xbbfc0e61443560740fa601', 186 | /* 52 */ '0x874f16aa407949aebced14', 187 | /* 53 */ '0x64df208d66f55c59261f5d', 188 | /* 54 */ '0x4dee90487e19a58fbf52e9', 189 | /* 55 */ '0x3e679f9e3b2f65e9d9b0db', 190 | /* 56 */ '0x33c719b34c57f9f7a922f6', 191 | /* 57 */ '0x2c7c090c36927c216fe17c', 192 | /* 58 */ '0x2789fc1ccdbd02af70650f', 193 | /* 59 */ '0x2451aae7a1741e150c6ae0', 194 | /* 60 */ '0x22700f74722225e8c308e6', 195 | /* 61 */ '0x21aae2600cf1170129eb92', 196 | /* 62 */ '0x21e552192ec12eccaa1d44', 197 | /* 63 */ '0x231a0b6c2a250a15897b8a', 198 | /* 64 */ '0x255901ff2640b9b00fef5e', 199 | /* 65 */ '0x28c842993fe2877ca68b09', 200 | /* 66 */ '0x2da7b7138200abf065bc12', 201 | /* 67 */ '0x34584e19c1677771772dbf', 202 | /* 68 */ '0x3d678fd12af3f51aa5828a', 203 | /* 69 */ '0x49a16c994ca36bb50c32c9', 204 | /* 70 */ '0x5a2b2d67887520aacedab6', 205 | /* 71 */ '0x70ac191abaee2a72987db6', 206 | /* 72 */ '0x8f8afbb1a74e96379df7b1', 207 | /* 73 */ '0xba4bd6d86b43467101fd6c', 208 | /* 74 */ '0xf61f8e0679ef553e95c271', 209 | /* 75 */ '0x14ac1e3b06c9771ad8f351c', 210 | /* 76 */ '0x1c3d320c47b0e10030f080e', 211 | /* 77 */ '0x272f678a02b5bd5dcc145a7', 212 | /* 78 */ '0x3732bb25f4914992758a3aa', 213 | /* 79 */ '0x4ee25a85a30b4e758af15a0', 214 | /* 80 */ '0x724dbc7344a886ed20dbae2', 215 | /* 81 */ '0xa7d64de739a14a222daf692', 216 | /* 82 */ '0xf99876906cf6526b6b82ecc', 217 | /* 83 */ '0x177bbaca105a36b48757a319', 218 | /* 84 */ '0x23c442370233418f33964a65', 219 | /* 85 */ '0x3716c05776b217ecbb587d11', 220 | /* 86 */ '0x55c42bb597ed985a9d69778e', 221 | /* 87 */ '0x86e8f9efa6efeba9e16b0a90', 222 | /* 88 */ '0xd651f2e547d194ee8b6d9a69', 223 | /* 89 */ '0x157b681e454d31a35819b1989', 224 | /* 90 */ '0x22c414309a2b397b4f8e0eb28', 225 | /* 91 */ '0x38c1a2330fcf634a5db1378a0', 226 | /* 92 */ '0x5d6efaaf8133556840468bbbb', 227 | /* 93 */ '0x9b0c82dee2e1f20d0a157a7ae', 228 | /* 94 */ '0x10347bdd997b95a7905d850436', 229 | /* 95 */ '0x1b4c902e273a586783055cede8', 230 | /* 96 */ '0x2e50642e85a0b7c589bac2651b', 231 | /* 97 */ '0x4f1b7f75028232ad3258b8b742', 232 | /* 98 */ '0x880028111c381b5279db2271c3', 233 | /* 99 */ '0xeb454460fe475acef6b927865e', 234 | /* 100 */ '0x1996fab0c95ac4a2b5cfa8f555d', 235 | /* 101 */ '0x2cc9f3994685c8d3224acb9fea1', 236 | /* 102 */ '0x4ed2e079d693966878c7149351a', 237 | /* 103 */ '0x8b740d663b523dad8b67451d8fc', 238 | /* 104 */ '0xf7f73c5d826e196ff66a259204c', 239 | /* 105 */ '0x1bb0d7eb2857065dcad087986fa6', 240 | /* 106 */ '0x31b4dfa1eedd2bd17d3504820344', 241 | /* 107 */ '0x599fae8ac47c48cf034887f489bb', 242 | /* 108 */ '0xa249948898a0e444bffa21361f42', 243 | /* 109 */ '0x12711786051c98ca2acc4adf7ba6a', 244 | /* 110 */ '0x21a98821bf01e72cc3f724b65a121', 245 | /* 111 */ '0x3dad0dd7c71f7b443dddd56fede23', 246 | /* 112 */ '0x716933ca69ac1b439f976665fafdf', 247 | /* 113 */ '0xd143a4beebca9707458aad7b22dcd', 248 | /* 114 */ '0x18369cb4cd8522c1b28abc22a3e805', 249 | /* 115 */ '0x2cf816f46d1971ec18f0ffb6922e86', 250 | /* 116 */ '0x53c58e5a59ee4d9fd7f747f67a3aac', 251 | /* 117 */ '0x9c833e3c0364561037250933eab9a9', 252 | /* 118 */ '0x1253c9d983f03e6a0955355049411cb', 253 | /* 119 */ '0x226e05852615979ea99f6ef68dbab51', 254 | /* 120 */ '0x40d8c81134ee9e16db1e0108defbb9f', 255 | /* 121 */ '0x7a70173a27075f4b9482d36deadc951', 256 | /* 122 */ '0xe7b966d76665f99c3fb1791404f62c6', 257 | /* 123 */ '0x1b78e22c38ae6aa69d36b8ccfade23fd', 258 | /* 124 */ '0x3439aeef615a970c9678397b6ad71179', 259 | /* 125 */ '0x637d37d6cb204d7419ac094d7e89f0dd', 260 | /* 126 */ '0xbde80a98943810876a7852209de22be2', 261 | /* 127 */ '0x12710231c0fd7a13f8a2b4af9d6b70c87', 262 | ]; 263 | -------------------------------------------------------------------------------- /solidity/test/ENJCrowdfund.js: -------------------------------------------------------------------------------- 1 | const ENJToken = artifacts.require('ENJToken.sol'); 2 | const Utils = require('./helpers/Utils'); 3 | const BigNumber = require('bignumber.js'); 4 | const ENJCrowdfund = artifacts.require('ENJCrowdfund.sol'); 5 | 6 | let tokenAddress; 7 | let crowdfundAddress; 8 | let advisorAddress; 9 | let incentiveAddress; 10 | let teamAddress; 11 | let owner; 12 | let beneficiary; 13 | let totalPresaleTokensYetToAllocate = new BigNumber(100000000).times(new BigNumber(10).pow(18)); 14 | let batchOfAddress = []; 15 | let batchOfENJ = []; 16 | let longBatchOfAddress = []; 17 | let longBatchOfENJ = []; 18 | let incentiveAllocation = 100000000; 19 | 20 | async function timeJump(timeToInc) { 21 | return new Promise((resolve, reject) => { 22 | web3 23 | .currentProvider 24 | .sendAsync({ 25 | jsonrpc: '2.0', 26 | method: 'evm_increaseTime', 27 | params: [(timeToInc)] // timeToInc is the time in seconds to increase 28 | }, function (err, result) { 29 | if (err) { 30 | reject(err); 31 | } 32 | resolve(result); 33 | }); 34 | }); 35 | } 36 | 37 | contract('ENJCrowdfund', (accounts) => { 38 | before(async() => { 39 | advisorAddress = accounts[1]; 40 | owner = accounts[2]; 41 | beneficiary = accounts[3]; 42 | incentiveAddress = accounts[4]; 43 | teamAddress = accounts[4]; 44 | batchOfAddress = [accounts[8], accounts[7], accounts[6], accounts[5]]; 45 | batchOfENJ = [ 46 | new BigNumber(100).times(new BigNumber(10).pow(18)), 47 | new BigNumber(200).times(new BigNumber(10).pow(18)), 48 | new BigNumber(300).times(new BigNumber(10).pow(18)), 49 | new BigNumber(400).times(new BigNumber(10).pow(18)) 50 | ] 51 | let crowdfund = await ENJCrowdfund.new(totalPresaleTokensYetToAllocate, beneficiary, {from: owner}); 52 | crowdfundAddress = crowdfund.address; 53 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 54 | tokenAddress = token.address; 55 | }); 56 | 57 | it('verifies parameters', async() => { 58 | let crowdfund = await ENJCrowdfund.new(totalPresaleTokensYetToAllocate, beneficiary, {from: owner}); 59 | let _beney = await crowdfund 60 | .beneficiary 61 | .call(); 62 | assert.equal(_beney, accounts[3]); 63 | let presaleTokens = await crowdfund 64 | .totalPresaleTokensYetToAllocate 65 | .call(); 66 | assert.equal(presaleTokens.dividedBy(new BigNumber(10).pow(18)).toNumber(), 100000000); 67 | }); 68 | 69 | it('changeBeneficiary: should change the beneficiary', async() => { 70 | let crowdfund = await ENJCrowdfund.new(totalPresaleTokensYetToAllocate, beneficiary, {from: owner}); 71 | await crowdfund.changeBeneficiary(accounts[6], {from: owner}); 72 | let _beney = await crowdfund 73 | .beneficiary 74 | .call(); 75 | assert.equal(_beney, accounts[6]); 76 | }); 77 | 78 | it('changeBeneficiary: should change the beneficiary -- fail', 79 | async() => { 80 | let crowdfund = await ENJCrowdfund.new(totalPresaleTokensYetToAllocate, beneficiary, {from: owner}); 81 | try { 82 | await crowdfund.changeBeneficiary(accounts[6], {from: accounts[8]}); 83 | } catch (error) { 84 | return Utils.ensureException(error); 85 | } 86 | }); 87 | 88 | it('setToken:should set the token', async() => { 89 | let crowdfund = await ENJCrowdfund.new(totalPresaleTokensYetToAllocate, beneficiary, {from: owner}); 90 | let token = await ENJToken.new(crowdfund.address, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 91 | await crowdfund.setToken(token.address, {from: owner}); 92 | let _tokenAddress = await crowdfund 93 | .tokenAddress 94 | .call(); 95 | assert.equal(_tokenAddress, token.address); 96 | }); 97 | 98 | it('setToken:should set the token -- fails called other than owner', 99 | async() => { 100 | let crowdfund = await ENJCrowdfund.new(totalPresaleTokensYetToAllocate, beneficiary, {from: owner}); 101 | let token = await ENJToken.new(crowdfund.address, advisorAddress, incentiveAddress, teamAddress); 102 | 103 | try { 104 | await crowdfund.setToken(token.address, {from: accounts[8]}); 105 | } catch (error) { 106 | return Utils.ensureException(error); 107 | } 108 | }); 109 | 110 | it('setToken:should fail when token is already set', async() => { 111 | let crowdfund = await ENJCrowdfund.new(totalPresaleTokensYetToAllocate, beneficiary, {from: owner}); 112 | let token = await ENJToken.new(crowdfund.address, advisorAddress, incentiveAddress, teamAddress); 113 | await crowdfund.setToken(token.address, {from: owner}); 114 | let _tokenAddress = await crowdfund 115 | .tokenAddress 116 | .call(); 117 | assert.equal(_tokenAddress, token.address); 118 | try { 119 | await crowdfund.setToken(token.address, {from: owner}); 120 | } catch (error) { 121 | return Utils.ensureException(error); 122 | } 123 | }) 124 | 125 | it('deliverPresaleTokens: should deliver the tokens to the presale contributors', async() => { 126 | let crowdfund = await ENJCrowdfund.new(totalPresaleTokensYetToAllocate, beneficiary, {from: owner}); 127 | let token = await ENJToken.new(crowdfund.address, advisorAddress, incentiveAddress, teamAddress); 128 | await crowdfund.setToken(token.address, {from: owner}); 129 | let tokenAddress = await crowdfund 130 | .tokenAddress 131 | .call(); 132 | assert.strictEqual(tokenAddress, token.address); 133 | await crowdfund.deliverPresaleTokens(batchOfAddress, batchOfENJ, { 134 | from: owner, 135 | gas: 3000000 136 | }); 137 | let presaleTokens = await crowdfund 138 | .totalPresaleTokensYetToAllocate 139 | .call(); 140 | assert.strictEqual(presaleTokens.dividedBy(new BigNumber(10).pow(18)).toNumber(), 99999000); 141 | let _balance1 = await token 142 | .balanceOf 143 | .call(accounts[8]); 144 | assert.strictEqual(_balance1.dividedBy(new BigNumber(10).pow(18)).toNumber(), 100); 145 | let _balance2 = await token 146 | .balanceOf 147 | .call(accounts[7]); 148 | assert.strictEqual(_balance2.dividedBy(new BigNumber(10).pow(18)).toNumber(), 200); 149 | let _balance3 = await token 150 | .balanceOf 151 | .call(accounts[6]); 152 | assert.strictEqual(_balance3.dividedBy(new BigNumber(10).pow(18)).toNumber(), 300); 153 | let _balance4 = await token 154 | .balanceOf 155 | .call(accounts[5]); 156 | assert.strictEqual(_balance4.dividedBy(new BigNumber(10).pow(18)).toNumber(), 400); 157 | }); 158 | 159 | it('deliverPresaleTokens: should deliver the tokens to the presale contributors --fails called by other than owner', 160 | async() => { 161 | let crowdfund = await ENJCrowdfund.new(totalPresaleTokensYetToAllocate, beneficiary, {from: owner}); 162 | let token = await ENJToken.new(crowdfund.address, advisorAddress, incentiveAddress, teamAddress); 163 | await crowdfund.setToken(token.address, {from: owner}); 164 | let tokenAddress = await crowdfund 165 | .tokenAddress 166 | .call(); 167 | assert.strictEqual(tokenAddress, token.address); 168 | try { 169 | await crowdfund.deliverPresaleTokens(batchOfAddress, batchOfENJ, { 170 | from: accounts[4], 171 | gas: 3000000 172 | }); 173 | } catch (error) { 174 | return Utils.ensureException(error); 175 | } 176 | }); 177 | 178 | it('deliverPresaleTokens: should deliver the tokens to the presale contributors --fails when token is not set', 179 | async() => { 180 | let crowdfund = await ENJCrowdfund.new(totalPresaleTokensYetToAllocate, beneficiary, {from: owner}); 181 | let token = await ENJToken.new(crowdfund.address, advisorAddress, incentiveAddress, teamAddress); 182 | try { 183 | await crowdfund.deliverPresaleTokens(batchOfAddress, batchOfENJ, { 184 | from: accounts[4], 185 | gas: 3000000 186 | }); 187 | } catch (error) { 188 | return Utils.ensureException(error); 189 | } 190 | }); 191 | 192 | it('Jump into the first week of the crowdsale', async() => { 193 | let crowdfund = await ENJCrowdfund.new(totalPresaleTokensYetToAllocate, beneficiary, {from: owner}); 194 | let token = await ENJToken.new(crowdfund.address, advisorAddress, incentiveAddress, teamAddress); 195 | let currentTime = Math.floor(Date.now() / 1000); 196 | let startTime = await crowdfund 197 | .startTime 198 | .call(); 199 | let durationDiff = await Utils.timeDifference(startTime.toNumber(), currentTime); 200 | let durationToInc = Math.floor(durationDiff + 2000); 201 | await timeJump(durationToInc); 202 | }); 203 | 204 | it('contributeETH: user cannot contribute -- first week -- fails when token is not set', 205 | async() => { 206 | let crowdfund = await ENJCrowdfund.new(totalPresaleTokensYetToAllocate, beneficiary, {from: owner}); 207 | let token = await ENJToken.new(crowdfund.address, advisorAddress, incentiveAddress, teamAddress); 208 | try { 209 | await crowdfund.contributeETH(accounts[8], { 210 | from: accounts[8], 211 | gas: 2000000, 212 | value: new BigNumber(11).times(new BigNumber(10).pow(18)) 213 | }); 214 | } catch (error) { 215 | return Utils.ensureException(error); 216 | } 217 | }); 218 | 219 | it('contributeETH: user can contribute', async() => { 220 | let crowdfund = await ENJCrowdfund.new(totalPresaleTokensYetToAllocate, beneficiary, {from: owner}); 221 | let token = await ENJToken.new(crowdfund.address, advisorAddress, incentiveAddress, teamAddress); 222 | await crowdfund.setToken(token.address, {from: owner}); 223 | let balanceSoFar = 0; 224 | let tokenAddress = await crowdfund 225 | .tokenAddress 226 | .call(); 227 | assert.strictEqual(tokenAddress, token.address); 228 | await crowdfund.contributeETH(accounts[8], { 229 | from: accounts[8], 230 | gas: 2000000, 231 | value: new BigNumber(1).times(new BigNumber(10).pow(18)) 232 | }); 233 | let _balance = await token 234 | .balanceOf 235 | .call(accounts[8]); 236 | balanceSoFar = _balance.dividedBy(new BigNumber(10).pow(18)).toNumber() + incentiveAllocation; 237 | assert.strictEqual(_balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), 6000); 238 | let ENJSold = await crowdfund 239 | .totalEnjSold 240 | .call(); 241 | assert.strictEqual(ENJSold.dividedBy(new BigNumber(10).pow(18)).toNumber(), 6000 + incentiveAllocation); 242 | 243 | // Second week 244 | await timeJump(7 * 24 * 60 * 60 + 2000); 245 | await crowdfund.contributeETH(accounts[8], { 246 | from: accounts[8], 247 | gas: 2000000, 248 | value: new BigNumber(1).times(new BigNumber(10).pow(18)) 249 | }); 250 | _balance = await token 251 | .balanceOf 252 | .call(accounts[8]); 253 | 254 | balanceSoFar += 5000 255 | assert.strictEqual(_balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), balanceSoFar - incentiveAllocation); 256 | ENJSold = await crowdfund 257 | .totalEnjSold 258 | .call(); 259 | assert.strictEqual(ENJSold.dividedBy(new BigNumber(10).pow(18)).toNumber(), balanceSoFar); 260 | 261 | // Third week 262 | await timeJump(7 * 24 * 60 * 60 + 2000); 263 | await crowdfund.contributeETH(accounts[8], { 264 | from: accounts[8], 265 | gas: 2000000, 266 | value: new BigNumber(1).times(new BigNumber(10).pow(18)) 267 | }); 268 | _balance = await token 269 | .balanceOf 270 | .call(accounts[8]); 271 | 272 | balanceSoFar += 4000 273 | assert.strictEqual(_balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), balanceSoFar - incentiveAllocation); 274 | ENJSold = await crowdfund 275 | .totalEnjSold 276 | .call(); 277 | assert.strictEqual(ENJSold.dividedBy(new BigNumber(10).pow(18)).toNumber(), balanceSoFar); 278 | 279 | // Fourth week 280 | await timeJump(7 * 24 * 60 * 60 + 2000); 281 | await crowdfund.contributeETH(accounts[8], { 282 | from: accounts[8], 283 | gas: 2000000, 284 | value: new BigNumber(1).times(new BigNumber(10).pow(18)) 285 | }); 286 | _balance = await token 287 | .balanceOf 288 | .call(accounts[8]); 289 | 290 | balanceSoFar += 3000 291 | assert.strictEqual(_balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), balanceSoFar - incentiveAllocation); 292 | ENJSold = await crowdfund 293 | .totalEnjSold 294 | .call(); 295 | assert.strictEqual(ENJSold.dividedBy(new BigNumber(10).pow(18)).toNumber(), balanceSoFar); 296 | 297 | // Fifth week -- Failure 298 | await timeJump(7 * 24 * 60 * 60 + 2000); 299 | try { 300 | await crowdfund.contributeETH(accounts[8], { 301 | from: accounts[8], 302 | gas: 2000000, 303 | value: new BigNumber(1).times(new BigNumber(10).pow(18)) 304 | }); 305 | } catch (error) { 306 | return utils.ensureException(error); 307 | } 308 | }); 309 | 310 | }); -------------------------------------------------------------------------------- /solidity/build/contracts/ENJCrowdfund.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "ENJCrowdfund", 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "inputs": [ 7 | { 8 | "name": "_tokenAddress", 9 | "type": "address" 10 | } 11 | ], 12 | "name": "setToken", 13 | "outputs": [], 14 | "payable": false, 15 | "type": "function" 16 | }, 17 | { 18 | "constant": false, 19 | "inputs": [ 20 | { 21 | "name": "_batchOfAddresses", 22 | "type": "address[]" 23 | }, 24 | { 25 | "name": "_amountofENJ", 26 | "type": "uint256[]" 27 | } 28 | ], 29 | "name": "deliverPresaleTokens", 30 | "outputs": [ 31 | { 32 | "name": "success", 33 | "type": "bool" 34 | } 35 | ], 36 | "payable": false, 37 | "type": "function" 38 | }, 39 | { 40 | "constant": true, 41 | "inputs": [], 42 | "name": "totalPresaleTokensYetToAllocate", 43 | "outputs": [ 44 | { 45 | "name": "", 46 | "type": "uint256" 47 | } 48 | ], 49 | "payable": false, 50 | "type": "function" 51 | }, 52 | { 53 | "constant": true, 54 | "inputs": [], 55 | "name": "endTime", 56 | "outputs": [ 57 | { 58 | "name": "", 59 | "type": "uint256" 60 | } 61 | ], 62 | "payable": false, 63 | "type": "function" 64 | }, 65 | { 66 | "constant": true, 67 | "inputs": [], 68 | "name": "beneficiary", 69 | "outputs": [ 70 | { 71 | "name": "", 72 | "type": "address" 73 | } 74 | ], 75 | "payable": false, 76 | "type": "function" 77 | }, 78 | { 79 | "constant": true, 80 | "inputs": [], 81 | "name": "totalEnjSold", 82 | "outputs": [ 83 | { 84 | "name": "total", 85 | "type": "uint256" 86 | } 87 | ], 88 | "payable": false, 89 | "type": "function" 90 | }, 91 | { 92 | "constant": true, 93 | "inputs": [], 94 | "name": "startTime", 95 | "outputs": [ 96 | { 97 | "name": "", 98 | "type": "uint256" 99 | } 100 | ], 101 | "payable": false, 102 | "type": "function" 103 | }, 104 | { 105 | "constant": false, 106 | "inputs": [], 107 | "name": "acceptOwnership", 108 | "outputs": [], 109 | "payable": false, 110 | "type": "function" 111 | }, 112 | { 113 | "constant": true, 114 | "inputs": [], 115 | "name": "owner", 116 | "outputs": [ 117 | { 118 | "name": "", 119 | "type": "address" 120 | } 121 | ], 122 | "payable": false, 123 | "type": "function" 124 | }, 125 | { 126 | "constant": true, 127 | "inputs": [], 128 | "name": "tokenAddress", 129 | "outputs": [ 130 | { 131 | "name": "", 132 | "type": "address" 133 | } 134 | ], 135 | "payable": false, 136 | "type": "function" 137 | }, 138 | { 139 | "constant": true, 140 | "inputs": [ 141 | { 142 | "name": "_contribution", 143 | "type": "uint256" 144 | } 145 | ], 146 | "name": "getTotalAmountOfTokens", 147 | "outputs": [ 148 | { 149 | "name": "amountOfTokens", 150 | "type": "uint256" 151 | } 152 | ], 153 | "payable": false, 154 | "type": "function" 155 | }, 156 | { 157 | "constant": true, 158 | "inputs": [], 159 | "name": "newOwner", 160 | "outputs": [ 161 | { 162 | "name": "", 163 | "type": "address" 164 | } 165 | ], 166 | "payable": false, 167 | "type": "function" 168 | }, 169 | { 170 | "constant": false, 171 | "inputs": [ 172 | { 173 | "name": "_newBeneficiary", 174 | "type": "address" 175 | } 176 | ], 177 | "name": "changeBeneficiary", 178 | "outputs": [], 179 | "payable": false, 180 | "type": "function" 181 | }, 182 | { 183 | "constant": false, 184 | "inputs": [ 185 | { 186 | "name": "_newOwner", 187 | "type": "address" 188 | } 189 | ], 190 | "name": "transferOwnership", 191 | "outputs": [], 192 | "payable": false, 193 | "type": "function" 194 | }, 195 | { 196 | "constant": false, 197 | "inputs": [ 198 | { 199 | "name": "_to", 200 | "type": "address" 201 | } 202 | ], 203 | "name": "contributeETH", 204 | "outputs": [ 205 | { 206 | "name": "amount", 207 | "type": "uint256" 208 | } 209 | ], 210 | "payable": true, 211 | "type": "function" 212 | }, 213 | { 214 | "inputs": [ 215 | { 216 | "name": "_totalPresaleTokensYetToAllocate", 217 | "type": "uint256" 218 | }, 219 | { 220 | "name": "_beneficiary", 221 | "type": "address" 222 | } 223 | ], 224 | "payable": false, 225 | "type": "constructor" 226 | }, 227 | { 228 | "payable": true, 229 | "type": "fallback" 230 | }, 231 | { 232 | "anonymous": false, 233 | "inputs": [ 234 | { 235 | "indexed": true, 236 | "name": "_contributor", 237 | "type": "address" 238 | }, 239 | { 240 | "indexed": false, 241 | "name": "_amount", 242 | "type": "uint256" 243 | }, 244 | { 245 | "indexed": false, 246 | "name": "_return", 247 | "type": "uint256" 248 | } 249 | ], 250 | "name": "CrowdsaleContribution", 251 | "type": "event" 252 | }, 253 | { 254 | "anonymous": false, 255 | "inputs": [ 256 | { 257 | "indexed": true, 258 | "name": "_contributor", 259 | "type": "address" 260 | }, 261 | { 262 | "indexed": false, 263 | "name": "_amountOfTokens", 264 | "type": "uint256" 265 | } 266 | ], 267 | "name": "PresaleContribution", 268 | "type": "event" 269 | }, 270 | { 271 | "anonymous": false, 272 | "inputs": [ 273 | { 274 | "indexed": false, 275 | "name": "_prevOwner", 276 | "type": "address" 277 | }, 278 | { 279 | "indexed": false, 280 | "name": "_newOwner", 281 | "type": "address" 282 | } 283 | ], 284 | "name": "OwnerUpdate", 285 | "type": "event" 286 | } 287 | ], 288 | "unlinked_binary": "0x60606040526359d37bc06002556359f90e446003556359dcb6406004556359e5f0c06005556359ef2b4060065560088054600160a060020a0319908116909155600980549091169055341561005357600080fd5b604051604080610bb883398101604052808051919060200180519150505b5b5b5b60008054600160a060020a03191633600160a060020a03161790555b80600160a060020a03811615156100a657600080fd5b600783905560088054600160a060020a031916600160a060020a0384161790555b5b5050505b610add806100db6000396000f300606060405236156100bf5763ffffffff60e060020a600035041663144fa6d781146100cd57806318b7fed8146100ee5780632eee5a3e1461012c5780633197cbb61461015157806338af3eed146101765780634bce2e9b146101a557806378e97925146101ca57806379ba5097146101ef5780638da5cb5b146102045780639d76ea5814610233578063a5ddfef114610262578063d4ee1d901461028a578063dc070657146102b9578063f2fde38b146102da578063ff36cf59146102fb575b5b6100c933610321565b505b005b34156100d857600080fd5b6100cb600160a060020a0360043516610380565b005b34156100f957600080fd5b6101186024600480358281019290820135918135918201910135610403565b604051901515815260200160405180910390f35b341561013757600080fd5b61013f610495565b60405190815260200160405180910390f35b341561015c57600080fd5b61013f61049b565b60405190815260200160405180910390f35b341561018157600080fd5b6101896104a1565b604051600160a060020a03909116815260200160405180910390f35b34156101b057600080fd5b61013f6104b0565b60405190815260200160405180910390f35b34156101d557600080fd5b61013f61051a565b60405190815260200160405180910390f35b34156101fa57600080fd5b6100cb610520565b005b341561020f57600080fd5b6101896105c8565b604051600160a060020a03909116815260200160405180910390f35b341561023e57600080fd5b6101896105d7565b604051600160a060020a03909116815260200160405180910390f35b341561026d57600080fd5b61013f6004356105e6565b60405190815260200160405180910390f35b341561029557600080fd5b61018961066a565b604051600160a060020a03909116815260200160405180910390f35b34156102c457600080fd5b6100cb600160a060020a0360043516610679565b005b34156102e557600080fd5b6100cb600160a060020a03600435166106d6565b005b61013f600160a060020a0360043516610321565b60405190815260200160405180910390f35b600081600160a060020a038116151561033957600080fd5b600254421015801561034c575060035442105b151561035457fe5b600954600160a060020a0316151561036b57600080fd5b61037483610736565b91505b5b5b5b50919050565b80600160a060020a038116151561039657600080fd5b60005433600160a060020a039081169116146103ae57fe5b600954600160a060020a0316156103c457600080fd5b60098054600160a060020a03841673ffffffffffffffffffffffffffffffffffffffff199182168117909255600a805490911690911790555b5b5b5050565b6009546000908190600160a060020a0316151561041f57600080fd5b60005433600160a060020a0390811691161461043757fe5b5060005b848110156104855761047c86868381811061045257fe5b90506020020135600160a060020a0316858584818110151561047057fe5b9050602002013561089d565b5b60010161043b565b600191505b5b5b50949350505050565b60075481565b60035481565b600854600160a060020a031681565b600a54600090600160a060020a03166345f7f24982604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b15156104fa57600080fd5b6102c65a03f1151561050b57600080fd5b50505060405180519150505b90565b60025481565b60015433600160a060020a0390811691161461053b57600080fd5b6000546001547f343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a91600160a060020a039081169116604051600160a060020a039283168152911660208201526040908101905180910390a1600180546000805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a038416179091551690555b565b600054600160a060020a031681565b600954600160a060020a031681565b600454600090819042101561060b5761060183611770610a6b565b9050809150610377565b60055442101561062b5761060183611388610a6b565b9050809150610377565b60065442101561064b5761060183610fa0610a6b565b9050809150610377565b61060183610bb8610a6b565b9050809150610377565b5b5b5b50919050565b600154600160a060020a031681565b80600160a060020a038116151561068f57600080fd5b60005433600160a060020a039081169116146106a757fe5b6008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0384161790555b5b5b5050565b60005433600160a060020a039081169116146106ee57fe5b600054600160a060020a038281169116141561070957600080fd5b6001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b600080610742346105e6565b600854909150600160a060020a03163480156108fc0290604051600060405180830381858888f19350505050151561077957600080fd5b600a54600160a060020a031663a9059cbb848360006040516020015260405160e060020a63ffffffff8516028152600160a060020a0390921660048301526024820152604401602060405180830381600087803b15156107d857600080fd5b6102c65a03f115156107e957600080fd5b50505060405180515050600a54600160a060020a03166398c20c008260405160e060020a63ffffffff84160281526004810191909152602401600060405180830381600087803b151561083b57600080fd5b6102c65a03f1151561084c57600080fd5b50505082600160a060020a03167f59c2edee20e1156b2d5d0d006ac843ed49ca044ce77be4aa26cba19c64f220be348360405191825260208201526040908101905180910390a28091505b50919050565b60005433600160a060020a039081169116146108b557fe5b600a54600160a060020a03166370a082318360006040516020015260405160e060020a63ffffffff8416028152600160a060020a039091166004820152602401602060405180830381600087803b151561090e57600080fd5b6102c65a03f1151561091f57600080fd5b5050506040518051159050801561093857506000600754115b151561094357600080fd5b600a54600160a060020a031663a9059cbb838360006040516020015260405160e060020a63ffffffff8516028152600160a060020a0390921660048301526024820152604401602060405180830381600087803b15156109a257600080fd5b6102c65a03f115156109b357600080fd5b50505060405180515050600a54600160a060020a03166398c20c008260405160e060020a63ffffffff84160281526004810191909152602401600060405180830381600087803b1515610a0557600080fd5b6102c65a03f11515610a1657600080fd5b505050610a2560075482610a9a565b600755600160a060020a0382167f3d0ab7e8209f975ae8d4c319005ac3a64cf3b4ee6503d416abb001d442eb1abc8260405190815260200160405180910390a25b5b5050565b6000828202831580610a875750828482811515610a8457fe5b04145b1515610a8f57fe5b8091505b5092915050565b600081831015610aa657fe5b508082035b929150505600a165627a7a72305820ad1d2f0085cfb693d1cb64cb400a0276ecef8e6df11c05e72db98d6178b958e30029", 289 | "networks": { 290 | "1505761635724": { 291 | "links": {}, 292 | "events": { 293 | "0x59c2edee20e1156b2d5d0d006ac843ed49ca044ce77be4aa26cba19c64f220be": { 294 | "anonymous": false, 295 | "inputs": [ 296 | { 297 | "indexed": true, 298 | "name": "_contributor", 299 | "type": "address" 300 | }, 301 | { 302 | "indexed": false, 303 | "name": "_amount", 304 | "type": "uint256" 305 | }, 306 | { 307 | "indexed": false, 308 | "name": "_return", 309 | "type": "uint256" 310 | } 311 | ], 312 | "name": "CrowdsaleContribution", 313 | "type": "event" 314 | }, 315 | "0x3d0ab7e8209f975ae8d4c319005ac3a64cf3b4ee6503d416abb001d442eb1abc": { 316 | "anonymous": false, 317 | "inputs": [ 318 | { 319 | "indexed": true, 320 | "name": "_contributor", 321 | "type": "address" 322 | }, 323 | { 324 | "indexed": false, 325 | "name": "_amountOfTokens", 326 | "type": "uint256" 327 | } 328 | ], 329 | "name": "PresaleContribution", 330 | "type": "event" 331 | }, 332 | "0x343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a": { 333 | "anonymous": false, 334 | "inputs": [ 335 | { 336 | "indexed": false, 337 | "name": "_prevOwner", 338 | "type": "address" 339 | }, 340 | { 341 | "indexed": false, 342 | "name": "_newOwner", 343 | "type": "address" 344 | } 345 | ], 346 | "name": "OwnerUpdate", 347 | "type": "event" 348 | } 349 | }, 350 | "updated_at": 1505761682890 351 | } 352 | }, 353 | "schema_version": "0.0.5", 354 | "updated_at": 1505761682890 355 | } -------------------------------------------------------------------------------- /solidity/build/contracts/ENJToken.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "ENJToken", 3 | "abi": [ 4 | { 5 | "constant": true, 6 | "inputs": [], 7 | "name": "name", 8 | "outputs": [ 9 | { 10 | "name": "", 11 | "type": "string" 12 | } 13 | ], 14 | "payable": false, 15 | "type": "function" 16 | }, 17 | { 18 | "constant": false, 19 | "inputs": [ 20 | { 21 | "name": "_spender", 22 | "type": "address" 23 | }, 24 | { 25 | "name": "_value", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "approve", 30 | "outputs": [ 31 | { 32 | "name": "success", 33 | "type": "bool" 34 | } 35 | ], 36 | "payable": false, 37 | "type": "function" 38 | }, 39 | { 40 | "constant": false, 41 | "inputs": [], 42 | "name": "releaseAdvisorTokens", 43 | "outputs": [ 44 | { 45 | "name": "success", 46 | "type": "bool" 47 | } 48 | ], 49 | "payable": false, 50 | "type": "function" 51 | }, 52 | { 53 | "constant": true, 54 | "inputs": [], 55 | "name": "totalSupply", 56 | "outputs": [ 57 | { 58 | "name": "", 59 | "type": "uint256" 60 | } 61 | ], 62 | "payable": false, 63 | "type": "function" 64 | }, 65 | { 66 | "constant": false, 67 | "inputs": [], 68 | "name": "allowTransfers", 69 | "outputs": [], 70 | "payable": false, 71 | "type": "function" 72 | }, 73 | { 74 | "constant": true, 75 | "inputs": [], 76 | "name": "maxPresaleSupply", 77 | "outputs": [ 78 | { 79 | "name": "", 80 | "type": "uint256" 81 | } 82 | ], 83 | "payable": false, 84 | "type": "function" 85 | }, 86 | { 87 | "constant": false, 88 | "inputs": [ 89 | { 90 | "name": "_from", 91 | "type": "address" 92 | }, 93 | { 94 | "name": "_to", 95 | "type": "address" 96 | }, 97 | { 98 | "name": "_value", 99 | "type": "uint256" 100 | } 101 | ], 102 | "name": "transferFrom", 103 | "outputs": [ 104 | { 105 | "name": "success", 106 | "type": "bool" 107 | } 108 | ], 109 | "payable": false, 110 | "type": "function" 111 | }, 112 | { 113 | "constant": true, 114 | "inputs": [], 115 | "name": "decimals", 116 | "outputs": [ 117 | { 118 | "name": "", 119 | "type": "uint8" 120 | } 121 | ], 122 | "payable": false, 123 | "type": "function" 124 | }, 125 | { 126 | "constant": true, 127 | "inputs": [], 128 | "name": "endTime", 129 | "outputs": [ 130 | { 131 | "name": "", 132 | "type": "uint256" 133 | } 134 | ], 135 | "payable": false, 136 | "type": "function" 137 | }, 138 | { 139 | "constant": true, 140 | "inputs": [], 141 | "name": "totalAllocated", 142 | "outputs": [ 143 | { 144 | "name": "", 145 | "type": "uint256" 146 | } 147 | ], 148 | "payable": false, 149 | "type": "function" 150 | }, 151 | { 152 | "constant": true, 153 | "inputs": [], 154 | "name": "crowdFundAddress", 155 | "outputs": [ 156 | { 157 | "name": "", 158 | "type": "address" 159 | } 160 | ], 161 | "payable": false, 162 | "type": "function" 163 | }, 164 | { 165 | "constant": true, 166 | "inputs": [], 167 | "name": "standard", 168 | "outputs": [ 169 | { 170 | "name": "", 171 | "type": "string" 172 | } 173 | ], 174 | "payable": false, 175 | "type": "function" 176 | }, 177 | { 178 | "constant": true, 179 | "inputs": [], 180 | "name": "minCrowdsaleAllocation", 181 | "outputs": [ 182 | { 183 | "name": "", 184 | "type": "uint256" 185 | } 186 | ], 187 | "payable": false, 188 | "type": "function" 189 | }, 190 | { 191 | "constant": true, 192 | "inputs": [], 193 | "name": "enjinTeamAllocation", 194 | "outputs": [ 195 | { 196 | "name": "", 197 | "type": "uint256" 198 | } 199 | ], 200 | "payable": false, 201 | "type": "function" 202 | }, 203 | { 204 | "constant": true, 205 | "inputs": [ 206 | { 207 | "name": "", 208 | "type": "address" 209 | } 210 | ], 211 | "name": "balanceOf", 212 | "outputs": [ 213 | { 214 | "name": "", 215 | "type": "uint256" 216 | } 217 | ], 218 | "payable": false, 219 | "type": "function" 220 | }, 221 | { 222 | "constant": false, 223 | "inputs": [], 224 | "name": "retrieveUnsoldTokens", 225 | "outputs": [ 226 | { 227 | "name": "success", 228 | "type": "bool" 229 | } 230 | ], 231 | "payable": false, 232 | "type": "function" 233 | }, 234 | { 235 | "constant": true, 236 | "inputs": [], 237 | "name": "startTime", 238 | "outputs": [ 239 | { 240 | "name": "", 241 | "type": "uint256" 242 | } 243 | ], 244 | "payable": false, 245 | "type": "function" 246 | }, 247 | { 248 | "constant": false, 249 | "inputs": [], 250 | "name": "acceptOwnership", 251 | "outputs": [], 252 | "payable": false, 253 | "type": "function" 254 | }, 255 | { 256 | "constant": true, 257 | "inputs": [], 258 | "name": "owner", 259 | "outputs": [ 260 | { 261 | "name": "", 262 | "type": "address" 263 | } 264 | ], 265 | "payable": false, 266 | "type": "function" 267 | }, 268 | { 269 | "constant": true, 270 | "inputs": [], 271 | "name": "symbol", 272 | "outputs": [ 273 | { 274 | "name": "", 275 | "type": "string" 276 | } 277 | ], 278 | "payable": false, 279 | "type": "function" 280 | }, 281 | { 282 | "constant": true, 283 | "inputs": [], 284 | "name": "advisorAddress", 285 | "outputs": [ 286 | { 287 | "name": "", 288 | "type": "address" 289 | } 290 | ], 291 | "payable": false, 292 | "type": "function" 293 | }, 294 | { 295 | "constant": false, 296 | "inputs": [ 297 | { 298 | "name": "_amount", 299 | "type": "uint256" 300 | } 301 | ], 302 | "name": "addToAllocation", 303 | "outputs": [], 304 | "payable": false, 305 | "type": "function" 306 | }, 307 | { 308 | "constant": true, 309 | "inputs": [], 310 | "name": "totalAllocatedToIncentives", 311 | "outputs": [ 312 | { 313 | "name": "", 314 | "type": "uint256" 315 | } 316 | ], 317 | "payable": false, 318 | "type": "function" 319 | }, 320 | { 321 | "constant": true, 322 | "inputs": [], 323 | "name": "incentivisationAllocation", 324 | "outputs": [ 325 | { 326 | "name": "", 327 | "type": "uint256" 328 | } 329 | ], 330 | "payable": false, 331 | "type": "function" 332 | }, 333 | { 334 | "constant": false, 335 | "inputs": [ 336 | { 337 | "name": "_to", 338 | "type": "address" 339 | }, 340 | { 341 | "name": "_value", 342 | "type": "uint256" 343 | } 344 | ], 345 | "name": "transfer", 346 | "outputs": [ 347 | { 348 | "name": "success", 349 | "type": "bool" 350 | } 351 | ], 352 | "payable": false, 353 | "type": "function" 354 | }, 355 | { 356 | "constant": true, 357 | "inputs": [], 358 | "name": "incentivisationFundAddress", 359 | "outputs": [ 360 | { 361 | "name": "", 362 | "type": "address" 363 | } 364 | ], 365 | "payable": false, 366 | "type": "function" 367 | }, 368 | { 369 | "constant": false, 370 | "inputs": [], 371 | "name": "releaseEnjinTeamTokens", 372 | "outputs": [ 373 | { 374 | "name": "success", 375 | "type": "bool" 376 | } 377 | ], 378 | "payable": false, 379 | "type": "function" 380 | }, 381 | { 382 | "constant": true, 383 | "inputs": [], 384 | "name": "newOwner", 385 | "outputs": [ 386 | { 387 | "name": "", 388 | "type": "address" 389 | } 390 | ], 391 | "payable": false, 392 | "type": "function" 393 | }, 394 | { 395 | "constant": true, 396 | "inputs": [], 397 | "name": "totalAllocatedToAdvisors", 398 | "outputs": [ 399 | { 400 | "name": "", 401 | "type": "uint256" 402 | } 403 | ], 404 | "payable": false, 405 | "type": "function" 406 | }, 407 | { 408 | "constant": true, 409 | "inputs": [ 410 | { 411 | "name": "", 412 | "type": "address" 413 | }, 414 | { 415 | "name": "", 416 | "type": "address" 417 | } 418 | ], 419 | "name": "allowance", 420 | "outputs": [ 421 | { 422 | "name": "", 423 | "type": "uint256" 424 | } 425 | ], 426 | "payable": false, 427 | "type": "function" 428 | }, 429 | { 430 | "constant": true, 431 | "inputs": [], 432 | "name": "totalAllocatedToTeam", 433 | "outputs": [ 434 | { 435 | "name": "", 436 | "type": "uint256" 437 | } 438 | ], 439 | "payable": false, 440 | "type": "function" 441 | }, 442 | { 443 | "constant": false, 444 | "inputs": [ 445 | { 446 | "name": "_newOwner", 447 | "type": "address" 448 | } 449 | ], 450 | "name": "transferOwnership", 451 | "outputs": [], 452 | "payable": false, 453 | "type": "function" 454 | }, 455 | { 456 | "constant": true, 457 | "inputs": [], 458 | "name": "advisorsAllocation", 459 | "outputs": [ 460 | { 461 | "name": "", 462 | "type": "uint256" 463 | } 464 | ], 465 | "payable": false, 466 | "type": "function" 467 | }, 468 | { 469 | "inputs": [ 470 | { 471 | "name": "_crowdFundAddress", 472 | "type": "address" 473 | }, 474 | { 475 | "name": "_advisorAddress", 476 | "type": "address" 477 | }, 478 | { 479 | "name": "_incentivisationFundAddress", 480 | "type": "address" 481 | } 482 | ], 483 | "payable": false, 484 | "type": "constructor" 485 | }, 486 | { 487 | "payable": false, 488 | "type": "fallback" 489 | }, 490 | { 491 | "anonymous": false, 492 | "inputs": [ 493 | { 494 | "indexed": false, 495 | "name": "_prevOwner", 496 | "type": "address" 497 | }, 498 | { 499 | "indexed": false, 500 | "name": "_newOwner", 501 | "type": "address" 502 | } 503 | ], 504 | "name": "OwnerUpdate", 505 | "type": "event" 506 | }, 507 | { 508 | "anonymous": false, 509 | "inputs": [ 510 | { 511 | "indexed": true, 512 | "name": "_from", 513 | "type": "address" 514 | }, 515 | { 516 | "indexed": true, 517 | "name": "_to", 518 | "type": "address" 519 | }, 520 | { 521 | "indexed": false, 522 | "name": "_value", 523 | "type": "uint256" 524 | } 525 | ], 526 | "name": "Transfer", 527 | "type": "event" 528 | }, 529 | { 530 | "anonymous": false, 531 | "inputs": [ 532 | { 533 | "indexed": true, 534 | "name": "_owner", 535 | "type": "address" 536 | }, 537 | { 538 | "indexed": true, 539 | "name": "_spender", 540 | "type": "address" 541 | }, 542 | { 543 | "indexed": false, 544 | "name": "_value", 545 | "type": "uint256" 546 | } 547 | ], 548 | "name": "Approval", 549 | "type": "event" 550 | } 551 | ], 552 | "unlinked_binary": "0x606060405260408051908101604052600981527f546f6b656e20302e310000000000000000000000000000000000000000000000602082015260009080516200004d929160200190620002b9565b50602060405190810160405260008152600190805162000072929160200190620002b9565b50602060405190810160405260008152600290805162000097929160200190620002b9565b506003805460ff19169055600060048190556b033b2e3c9fd0803ce80000006009556b01f04ef12cb04cf158000000600a556aa56fa5b99019a5c8000000600b556a52b7d2dcc80cd2e4000000600c556a295be96e64066972000000600d819055600e55601281905560138190556014556359d37bc06015556359f90e446016556017805467ffffffffffffffff1916905534156200013557600080fd5b604051606080620018fc8339810160405280805191906020018051919060200180519150505b5b604080519081016040908152600882527f454e4a20436f696e00000000000000000000000000000000000000000000000060208301528051908101604052600381527f454e4a0000000000000000000000000000000000000000000000000000000000602082015260125b5b5b60008351118015620001dc575060008251115b1515620001e857600080fd5b6001838051620001fd929160200190620002b9565b50600282805162000213929160200190620002b9565b506003805460ff191660ff83161790555b505060078054600160a060020a03191633600160a060020a0316179055505b600f8054600160a060020a0319908116600160a060020a0386811691821790935560108054831686851617905560118054909216928416928317909155600a54600b54600092835260056020526040808420919092019055600c5492825290208190556014805490910190555b50505062000363565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620002fc57805160ff19168380011785556200032c565b828001600101855582156200032c579182015b828111156200032c5782518255916020019190600101906200030f565b5b506200033b9291506200033f565b5090565b6200036091905b808211156200033b576000815560010162000346565b5090565b90565b61158980620003736000396000f3006060604052361561019e5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde0381146101b1578063095ea7b31461023c5780631367641e1461027257806318160ddd146102995780632185810b146102be57806321bdb26e146102d357806323b872dd146102f8578063313ce567146103345780633197cbb61461035d57806345f7f249146103825780635154865a146103a75780635a3b7e42146103d6578063606baff8146104615780636a06bf921461048657806370a08231146104ab57806374151a2a146104dc57806378e979251461050357806379ba5097146105285780638da5cb5b1461053d57806395d89b411461056c57806396d4d091146105f757806398c20c0014610626578063a39e1ea91461063e578063a833c7ab14610663578063a9059cbb14610688578063b384e9b4146106be578063ccdd95d6146106ed578063d4ee1d9014610714578063d966cfc314610743578063dd62ed3e14610768578063e783bfb11461079f578063f2fde38b146107c4578063fb064161146107e5575b34156101a957600080fd5b5b600080fd5b005b34156101bc57600080fd5b6101c461080a565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156102015780820151818401525b6020016101e8565b50505050905090810190601f16801561022e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561024757600080fd5b61025e600160a060020a03600435166024356108a8565b604051901515815260200160405180910390f35b341561027d57600080fd5b61025e610968565b604051901515815260200160405180910390f35b34156102a457600080fd5b6102ac610a4d565b60405190815260200160405180910390f35b34156102c957600080fd5b6101af610a53565b005b34156102de57600080fd5b6102ac610a7c565b60405190815260200160405180910390f35b341561030357600080fd5b61025e600160a060020a0360043581169060243516604435610a82565b604051901515815260200160405180910390f35b341561033f57600080fd5b610347610aff565b60405160ff909116815260200160405180910390f35b341561036857600080fd5b6102ac610b08565b60405190815260200160405180910390f35b341561038d57600080fd5b6102ac610b0e565b60405190815260200160405180910390f35b34156103b257600080fd5b6103ba610b14565b604051600160a060020a03909116815260200160405180910390f35b34156103e157600080fd5b6101c4610b23565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156102015780820151818401525b6020016101e8565b50505050905090810190601f16801561022e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561046c57600080fd5b6102ac610bc1565b60405190815260200160405180910390f35b341561049157600080fd5b6102ac610bc7565b60405190815260200160405180910390f35b34156104b657600080fd5b6102ac600160a060020a0360043516610bcd565b60405190815260200160405180910390f35b34156104e757600080fd5b61025e610bdf565b604051901515815260200160405180910390f35b341561050e57600080fd5b6102ac610c91565b60405190815260200160405180910390f35b341561053357600080fd5b6101af610c97565b005b341561054857600080fd5b6103ba610d3f565b604051600160a060020a03909116815260200160405180910390f35b341561057757600080fd5b6101c4610d4e565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156102015780820151818401525b6020016101e8565b50505050905090810190601f16801561022e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561060257600080fd5b6103ba610dec565b604051600160a060020a03909116815260200160405180910390f35b341561063157600080fd5b6101af600435610dfb565b005b341561064957600080fd5b6102ac610e2a565b60405190815260200160405180910390f35b341561066e57600080fd5b6102ac610e4d565b60405190815260200160405180910390f35b341561069357600080fd5b61025e600160a060020a0360043516602435610e53565b604051901515815260200160405180910390f35b34156106c957600080fd5b6103ba610ece565b604051600160a060020a03909116815260200160405180910390f35b34156106f857600080fd5b61025e610edd565b604051901515815260200160405180910390f35b341561071f57600080fd5b6103ba61118c565b604051600160a060020a03909116815260200160405180910390f35b341561074e57600080fd5b6102ac61119b565b60405190815260200160405180910390f35b341561077357600080fd5b6102ac600160a060020a03600435811690602435166111a1565b60405190815260200160405180910390f35b34156107aa57600080fd5b6102ac6111be565b60405190815260200160405180910390f35b34156107cf57600080fd5b6101af600160a060020a03600435166111c4565b005b34156107f057600080fd5b6102ac611224565b60405190815260200160405180910390f35b60018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108a05780601f10610875576101008083540402835291602001916108a0565b820191906000526020600020905b81548152906001019060200180831161088357829003601f168201915b505050505081565b600082600160a060020a03811615156108c057600080fd5b8215806108f05750600160a060020a03338116600090815260066020908152604080832093881683529290522054155b15156108fb57600080fd5b600160a060020a03338116600081815260066020908152604080832094891680845294909152908190208690557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259086905190815260200160405180910390a3600191505b5b5092915050565b6016546000906249d4000142101561097f57600080fd5b60105433600160a060020a0390811691161461099a57600080fd5b601254156109a757600080fd5b600160a060020a033316600090815260056020526040902054600d546109cd919061122a565b6005600033600160a060020a0316600160a060020a031681526020019081526020016000208190555033600160a060020a031630600160a060020a031660008051602061153e833981519152600d5460405190815260200160405180910390a3610a3b601454600d5461122a565b60145550600d5460125560015b5b5b90565b60095481565b60075433600160a060020a03908116911614610a6b57fe5b6017805460ff191660011790555b5b565b600a5481565b600081818111610a9157600080fd5b610a99611244565b151560011480610ab75750600f5433600160a060020a039081169116145b80610ad0575060115433600160a060020a039081169116145b156101a957610ae0858585611271565b1515610ae857fe5b60019150610af6565b600080fd5b5b509392505050565b60035460ff1681565b60165481565b60145481565b600f54600160a060020a031681565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108a05780601f10610875576101008083540402835291602001916108a0565b820191906000526020600020905b81548152906001019060200180831161088357829003601f168201915b505050505081565b600b5481565b600e5481565b60056020526000908152604090205481565b60008060165462dd7c00014210151515610bf857600080fd5b60075433600160a060020a03908116911614610c1057fe5b50600f54600160a060020a0390811660009081526005602052604080822054339093168252902054610c42908261122a565b600160a060020a033316600090815260056020526040902055601454610c68908261122a565b601455600f54600160a060020a0316600090815260056020526040812055600191505b5b5b5090565b60155481565b60085433600160a060020a03908116911614610cb257600080fd5b6007546008547f343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a91600160a060020a039081169116604051600160a060020a039283168152911660208201526040908101905180910390a1600880546007805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a038416179091551690555b565b600754600160a060020a031681565b60028054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108a05780601f10610875576101008083540402835291602001916108a0565b820191906000526020600020905b81548152906001019060200180831161088357829003601f168201915b505050505081565b601054600160a060020a031681565b600f5433600160a060020a03908116911614610e1657600080fd5b610e226014548261122a565b6014555b5b50565b601154600160a060020a0316600090815260056020526040902054600c54035b90565b600c5481565b600081818111610e6257600080fd5b610e6a611244565b151560011480610e885750600f5433600160a060020a039081169116145b80610ea1575060115433600160a060020a039081169116145b156101a957610eb08484611395565b1515610eb857fe5b60019150610960565b600080fd5b5b5092915050565b601154600160a060020a031681565b600754600090819033600160a060020a03908116911614610efa57fe5b600e5460135410610f0a57600080fd5b600e546103e8905b04905060165462dd7c000142118015610f335750601754610100900460ff16155b15610f63576017805461ff001916610100179055610f5a610f558260fa611452565b611481565b60019150610c8b565b60165463014c3a000142118015610f83575060175462010000900460ff16155b15610fb5576017805462ff0000191662010000179055610f5a610f5582607d611452565b611481565b60019150610c8b565b6016546301baf8000142118015610fd657506017546301000000900460ff16155b1561100a576017805463ff00000019166301000000179055610f5a610f5582607d611452565b611481565b60019150610c8b565b601654630229b600014211801561102c5750601754640100000000900460ff16155b15611062576017805464ff000000001916640100000000179055610f5a610f5582607d611452565b611481565b60019150610c8b565b60165463029874000142118015611085575060175465010000000000900460ff16155b156110bd576017805465ff0000000000191665010000000000179055610f5a610f5582607d611452565b611481565b60019150610c8b565b601654630307320001421180156110e157506017546601000000000000900460ff16155b1561111b576017805466ff00000000000019166601000000000000179055610f5a610f5582607d611452565b611481565b60019150610c8b565b601654630375f00001421180156111405750601754670100000000000000900460ff16155b156101a9576017805467ff000000000000001916670100000000000000179055610f5a610f5582607d611452565b611481565b60019150610c8b565b5b5b5b5b5b5b600080fd5b5b5090565b600854600160a060020a031681565b60125481565b600660209081526000928352604080842090915290825290205481565b60135481565b60075433600160a060020a039081169116146111dc57fe5b600754600160a060020a03828116911614156111f757600080fd5b6008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b600d5481565b60008282018381101561123957fe5b8091505b5092915050565b600060165442118061125d575060175460ff1615156001145b1561126a57506001610a48565b5060005b90565b600083600160a060020a038116151561128957600080fd5b83600160a060020a038116151561129f57600080fd5b600160a060020a03808716600090815260066020908152604080832033909416835292905220546112d09085611526565b600160a060020a0380881660008181526006602090815260408083203390951683529381528382209490945590815260059092529020546113119085611526565b600160a060020a038088166000908152600560205260408082209390935590871681522054611340908561122a565b600160a060020a038087166000818152600560205260409081902093909355919088169060008051602061153e8339815191529087905190815260200160405180910390a3600192505b5b505b509392505050565b600082600160a060020a03811615156113ad57600080fd5b600160a060020a0333166000908152600560205260409020546113d09084611526565b600160a060020a0333811660009081526005602052604080822093909355908616815220546113ff908461122a565b600160a060020a03808616600081815260056020526040908190209390935591339091169060008051602061153e8339815191529086905190815260200160405180910390a3600191505b5b5092915050565b600082820283158061146e575082848281151561146b57fe5b04145b151561123957fe5b8091505b5092915050565b60075433600160a060020a0390811691161461149957fe5b600160a060020a0333166000908152600560205260409020546114bc908261122a565b600160a060020a03338116600081815260056020526040908190209390935591309091169060008051602061153e8339815191529084905190815260200160405180910390a361150e6014548261122a565b60145560135461151e908261122a565b6013555b5b50565b60008183101561153257fe5b508082035b929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a723058204161c74651bc878a18266a9c34c2d377323791c72bedad1be15d417475f31fc90029", 553 | "networks": { 554 | "1505761635724": { 555 | "links": {}, 556 | "events": { 557 | "0x343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a": { 558 | "anonymous": false, 559 | "inputs": [ 560 | { 561 | "indexed": false, 562 | "name": "_prevOwner", 563 | "type": "address" 564 | }, 565 | { 566 | "indexed": false, 567 | "name": "_newOwner", 568 | "type": "address" 569 | } 570 | ], 571 | "name": "OwnerUpdate", 572 | "type": "event" 573 | }, 574 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": { 575 | "anonymous": false, 576 | "inputs": [ 577 | { 578 | "indexed": true, 579 | "name": "_from", 580 | "type": "address" 581 | }, 582 | { 583 | "indexed": true, 584 | "name": "_to", 585 | "type": "address" 586 | }, 587 | { 588 | "indexed": false, 589 | "name": "_value", 590 | "type": "uint256" 591 | } 592 | ], 593 | "name": "Transfer", 594 | "type": "event" 595 | }, 596 | "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": { 597 | "anonymous": false, 598 | "inputs": [ 599 | { 600 | "indexed": true, 601 | "name": "_owner", 602 | "type": "address" 603 | }, 604 | { 605 | "indexed": true, 606 | "name": "_spender", 607 | "type": "address" 608 | }, 609 | { 610 | "indexed": false, 611 | "name": "_value", 612 | "type": "uint256" 613 | } 614 | ], 615 | "name": "Approval", 616 | "type": "event" 617 | } 618 | }, 619 | "updated_at": 1505761682894 620 | } 621 | }, 622 | "schema_version": "0.0.5", 623 | "updated_at": 1505761682894 624 | } -------------------------------------------------------------------------------- /solidity/test/ENJToken.js: -------------------------------------------------------------------------------- 1 | const ENJToken = artifacts.require('ENJToken.sol'); 2 | const Utils = require('./helpers/Utils'); 3 | const BigNumber = require('bignumber.js'); 4 | const ENJCrowdfund = artifacts.require('ENJCrowdfund.sol'); 5 | 6 | let tokenAddress; 7 | let crowdfundAddress; 8 | let advisorAddress; 9 | let owner; 10 | let beneficiary; 11 | let incentiveAddress; 12 | let teamAddress; 13 | let incentiveAllocation = 100000000; 14 | 15 | async function timeJump(timeToInc) { 16 | return new Promise((resolve, reject) => { 17 | web3 18 | .currentProvider 19 | .sendAsync({ 20 | jsonrpc: '2.0', 21 | method: 'evm_increaseTime', 22 | params: [(timeToInc)] // timeToInc is the time in seconds to increase 23 | }, function (err, result) { 24 | if (err) { 25 | reject(err); 26 | } 27 | resolve(result); 28 | }); 29 | }) 30 | } 31 | 32 | contract('ENJToken', (accounts) => { 33 | before(async() => { 34 | crowdfundAddress = accounts[0]; 35 | advisorAddress = accounts[1]; 36 | owner = accounts[2]; 37 | beneficiary = accounts[3]; 38 | incentiveAddress = accounts[4]; 39 | teamAddress = accounts[5]; 40 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 41 | tokenAddress = token.address; 42 | }); 43 | 44 | it('verify parameters', async() => { 45 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 46 | let balance = await token 47 | .balanceOf 48 | .call(crowdfundAddress); 49 | assert.strictEqual(balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), 800000000); 50 | let incentiveBalance = await token 51 | .balanceOf 52 | .call(incentiveAddress); 53 | assert.strictEqual(incentiveBalance.dividedBy(new BigNumber(10).pow(18)).toNumber(), 100000000); 54 | }); 55 | 56 | it('verify the allocation variables', async() => { 57 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 58 | let _totalSupply = await token 59 | .totalSupply 60 | .call(); 61 | assert.strictEqual(_totalSupply.dividedBy(new BigNumber(10).pow(18)).toNumber(), 1000000000); 62 | let _maxPresaleSupply = await token 63 | .maxPresaleSupply 64 | .call(); 65 | assert.strictEqual(_maxPresaleSupply.dividedBy(new BigNumber(10).pow(18)).toNumber(), 600000000); 66 | let _minCrowdsaleAllocation = await token 67 | .minCrowdsaleAllocation 68 | .call(); 69 | assert.strictEqual(_minCrowdsaleAllocation.dividedBy(new BigNumber(10).pow(18)).toNumber(), 200000000); 70 | let _incentivisationAllocation = await token 71 | .incentivisationAllocation 72 | .call(); 73 | assert.strictEqual(_incentivisationAllocation.dividedBy(new BigNumber(10).pow(18)).toNumber(), 100000000); 74 | let _advisorsAllocation = await token 75 | .advisorsAllocation 76 | .call(); 77 | assert.strictEqual(_advisorsAllocation.dividedBy(new BigNumber(10).pow(18)).toNumber(), 26000000); 78 | let _enjinTeamAllocation = await token 79 | .enjinTeamAllocation 80 | .call(); 81 | assert.strictEqual(_enjinTeamAllocation.dividedBy(new BigNumber(10).pow(18)).toNumber(), 74000000); 82 | }) 83 | 84 | // ///////////////////////////////////////// Transfer // /////////////////////////////////////// 85 | 86 | it('transfer: ether directly to the token contract -- it will throw', async() => { 87 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 88 | try { 89 | await web3 90 | .eth 91 | .sendTransaction({ 92 | from: accounts[8], 93 | to: token.address, 94 | value: web3.toWei('10', 'Ether') 95 | }); 96 | } catch (error) { 97 | return Utils.ensureException(error); 98 | } 99 | }); 100 | 101 | it('transfer: should transfer 10000 to accounts[8] from crowdsale', async() => { 102 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 103 | await token.transfer(accounts[8], new BigNumber(10000).times(new BigNumber(10).pow(18)), {from: crowdfundAddress}); 104 | let balance = await token 105 | .balanceOf 106 | .call(accounts[8]); 107 | assert.strictEqual(balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), 10000); 108 | }); 109 | 110 | it('transfer: first should transfer 10000 to accounts[8] from crowdsale then accounts[8] transfers 1000 to accounts[7]', 111 | async() => { 112 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 113 | let currentTime = Math.floor(Date.now() / 1000); 114 | await token.transfer(accounts[8], new BigNumber(10000).times(new BigNumber(10).pow(18)), {from: crowdfundAddress}); 115 | let balance = await token 116 | .balanceOf 117 | .call(accounts[8]); 118 | assert.strictEqual(balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), 10000); 119 | await token.allowTransfers({from: owner}); 120 | await token.transfer(accounts[7], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: accounts[8]}); 121 | let accBalance = await token 122 | .balanceOf 123 | .call(accounts[7]); 124 | assert.strictEqual(accBalance.dividedBy(new BigNumber(10).pow(18)).toNumber(), 1000); 125 | }); 126 | 127 | it('transfer: should fail when trying to transfer zero', async() => { 128 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 129 | try { 130 | await token.transfer(accounts[8], new BigNumber(0).times(new BigNumber(10).pow(18)), {from: crowdfundAddress}); 131 | } catch (error) { 132 | return Utils.ensureException(error); 133 | } 134 | }); 135 | 136 | it('approve: msg.sender should approve 1000 to accounts[8]', async() => { 137 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 138 | await token.approve(accounts[8], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: crowdfundAddress}); 139 | let _allowance = await token 140 | .allowance 141 | .call(crowdfundAddress, accounts[8]); 142 | assert.strictEqual(_allowance.dividedBy(new BigNumber(10).pow(18)).toNumber(),1000); 143 | }); 144 | 145 | it('approve: msg.sender should approve 1000 to accounts[7] & withdraws 200 once', async() => { 146 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 147 | await token.transfer(accounts[8], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: crowdfundAddress}); 148 | await token.approve(accounts[7], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: accounts[8]}); 149 | let _allowance1 = await token 150 | .allowance 151 | .call(accounts[8], accounts[7]); 152 | assert.strictEqual(_allowance1.dividedBy(new BigNumber(10).pow(18)).toNumber(), 1000); 153 | await token.allowTransfers({from: owner}); 154 | await token.transferFrom(accounts[8], accounts[6], new BigNumber(200).times(new BigNumber(10).pow(18)), {from: accounts[7]}); 155 | let balance = await token 156 | .balanceOf 157 | .call(accounts[6]); 158 | assert.strictEqual(balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), 200); 159 | let _allowance2 = await token 160 | .allowance 161 | .call(accounts[8], accounts[7]); 162 | assert.strictEqual(_allowance2.dividedBy(new BigNumber(10).pow(18)).toNumber(), 800); 163 | let _balance = await token 164 | .balanceOf 165 | .call(accounts[8]); 166 | assert.strictEqual(_balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), 800); 167 | 168 | }); 169 | 170 | it('approve: msg.sender should approve 1000 to accounts[7] & withdraws 200 twice', async() => { 171 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 172 | await token.transfer(accounts[8], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: crowdfundAddress}); 173 | await token.approve(accounts[7], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: accounts[8]}); 174 | let _allowance1 = await token 175 | .allowance 176 | .call(accounts[8], accounts[7]); 177 | assert.strictEqual(_allowance1.dividedBy(new BigNumber(10).pow(18)).toNumber(), 1000); 178 | await token.allowTransfers({from: owner}); 179 | await token.transferFrom(accounts[8], accounts[6], new BigNumber(200).times(new BigNumber(10).pow(18)), {from: accounts[7]}); 180 | let _balance1 = await token 181 | .balanceOf 182 | .call(accounts[6]); 183 | assert.strictEqual(_balance1.dividedBy(new BigNumber(10).pow(18)).toNumber(), 200); 184 | let _allowance2 = await token 185 | .allowance 186 | .call(accounts[8], accounts[7]); 187 | assert.strictEqual(_allowance2.dividedBy(new BigNumber(10).pow(18)).toNumber(), 800); 188 | let _balance2 = await token 189 | .balanceOf 190 | .call(accounts[8]); 191 | assert.strictEqual(_balance2.dividedBy(new BigNumber(10).pow(18)).toNumber(), 800); 192 | await token.transferFrom(accounts[8], accounts[5], new BigNumber(200).times(new BigNumber(10).pow(18)), {from: accounts[7]}); 193 | let _balance3 = await token 194 | .balanceOf 195 | .call(accounts[5]); 196 | assert.strictEqual(_balance3.dividedBy(new BigNumber(10).pow(18)).toNumber(), 200); 197 | let _allowance3 = await token 198 | .allowance 199 | .call(accounts[8], accounts[7]); 200 | assert.strictEqual(_allowance3.dividedBy(new BigNumber(10).pow(18)).toNumber(), 600); 201 | let _balance4 = await token 202 | .balanceOf 203 | .call(accounts[8]); 204 | assert.strictEqual(_balance4.dividedBy(new BigNumber(10).pow(18)).toNumber(), 600); 205 | }); 206 | 207 | it('Approve max (2^256 - 1)', async() => { 208 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 209 | await token.approve(accounts[8], '115792089237316195423570985008687907853269984665640564039457584007913129639935', {from: accounts[7]}); 210 | let _allowance = await token.allowance(accounts[7], accounts[8]); 211 | let result = _allowance.equals('1.15792089237316195423570985008687907853269984665640564039457584007913129639935e' + 212 | '+77'); 213 | assert.isTrue(result); 214 | }); 215 | 216 | it('approves: msg.sender approves accounts[7] of 1000 & withdraws 800 & 500 (2nd tx should fail)', 217 | async() => { 218 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 219 | await token.transfer(accounts[8], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: crowdfundAddress}); 220 | await token.approve(accounts[7], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: accounts[8]}); 221 | let _allowance1 = await token 222 | .allowance 223 | .call(accounts[8], accounts[7]); 224 | assert.strictEqual(_allowance1.dividedBy(new BigNumber(10).pow(18)).toNumber(), 1000); 225 | await token.allowTransfers({from: owner}); 226 | await token.transferFrom(accounts[8], accounts[6], new BigNumber(800).times(new BigNumber(10).pow(18)), {from: accounts[7]}); 227 | let _balance1 = await token 228 | .balanceOf 229 | .call(accounts[6]); 230 | assert.strictEqual(_balance1.dividedBy(new BigNumber(10).pow(18)).toNumber(), 800); 231 | let _allowance2 = await token 232 | .allowance 233 | .call(accounts[8], accounts[7]); 234 | assert.strictEqual(_allowance2.dividedBy(new BigNumber(10).pow(18)).toNumber(), 200); 235 | let _balance2 = await token 236 | .balanceOf 237 | .call(accounts[8]); 238 | assert.strictEqual(_balance2.dividedBy(new BigNumber(10).pow(18)).toNumber(), 200); 239 | try { 240 | await token.transferFrom(accounts[8], accounts[6], new BigNumber(500).times(new BigNumber(10).pow(18)), {from: accounts[7]}); 241 | } catch (error) { 242 | return Utils.ensureException(error); 243 | } 244 | }); 245 | 246 | it('transferFrom: user attempt to transfer 100 tokens with 1000 allowance before the crowdsale ends -- fails ', 247 | async() => { 248 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 249 | await token.transfer(accounts[8], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: crowdfundAddress}); 250 | await token.approve(accounts[7], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: accounts[8]}); 251 | let _allowance1 = await token 252 | .allowance 253 | .call(accounts[8], accounts[7]); 254 | assert.strictEqual(_allowance1.dividedBy(new BigNumber(10).pow(18)).toNumber(), 1000); 255 | try { 256 | await token.transferFrom(accounts[8], accounts[6], new BigNumber(100).times(new BigNumber(10).pow(18)), {from: accounts[7]}); 257 | } catch (error) { 258 | return Utils.ensureException(error); 259 | } 260 | 261 | }); 262 | 263 | it('transferFrom: Attempt to withdraw from account with no allowance -- fail', async() => { 264 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 265 | await token.transfer(accounts[8], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: crowdfundAddress}); 266 | await token.allowTransfers({from: owner}); 267 | try { 268 | await token 269 | .transferFrom 270 | .call(accounts[8], accounts[6], new BigNumber(100).times(new BigNumber(10).pow(18)), {from: accounts[7]}); 271 | } catch (error) { 272 | return Utils.ensureException(error); 273 | } 274 | }); 275 | 276 | it('transferFrom: Allow accounts[7] 1000 to withdraw from accounts[8]. Withdraw 800 and then approve 0 & attempt transfer', 277 | async() => { 278 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 279 | await token.transfer(accounts[8], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: crowdfundAddress}); 280 | await token.approve(accounts[7], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: accounts[8]}); 281 | let _allowance1 = await token 282 | .allowance 283 | .call(accounts[8], accounts[7]); 284 | assert.strictEqual(_allowance1.dividedBy(new BigNumber(10).pow(18)).toNumber(), 1000); 285 | await token.allowTransfers({from: owner}); 286 | await token.transferFrom(accounts[8], accounts[6], new BigNumber(200).times(new BigNumber(10).pow(18)), {from: accounts[7]}); 287 | let _balance1 = await token 288 | .balanceOf 289 | .call(accounts[6]); 290 | assert.strictEqual(_balance1.dividedBy(new BigNumber(10).pow(18)).toNumber(), 200); 291 | let _allowance2 = await token 292 | .allowance 293 | .call(accounts[8], accounts[7]); 294 | assert.strictEqual(_allowance2.dividedBy(new BigNumber(10).pow(18)).toNumber(), 800); 295 | let _balance2 = await token 296 | .balanceOf 297 | .call(accounts[8]); 298 | assert.strictEqual(_balance2.dividedBy(new BigNumber(10).pow(18)).toNumber(), 800); 299 | await token.approve(accounts[7], 0, {from: accounts[8]}); 300 | try { 301 | await token.transferFrom(accounts[8], accounts[6], new BigNumber(200).times(new BigNumber(10).pow(18)), {from: accounts[7]}); 302 | } catch (error) { 303 | return Utils.ensureException(error); 304 | } 305 | }); 306 | 307 | it('addToAllocation: verifies the functionality of updating the variable totalAllocated', 308 | async() => { 309 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 310 | await token.addToAllocation(new BigNumber(10).times(new BigNumber(10).pow(18)), {from: crowdfundAddress}); 311 | let allocation = await token 312 | .totalAllocated 313 | .call(); 314 | assert.strictEqual(allocation.dividedBy(new BigNumber(10).pow(18)).toNumber(), incentiveAllocation + 10); 315 | }); 316 | 317 | it('addToAllocation:verifies the functionality of updating the variable totalAllocated -- fails called by other than crowdfund', 318 | async() => { 319 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 320 | try { 321 | await token.addToAllocation(new BigNumber(10).times(new BigNumber(10).pow(18)), {from: accounts[8]}); 322 | } catch (error) { 323 | return Utils.ensureException(error); 324 | } 325 | }); 326 | 327 | it('allowTransfers: allow transfer of tokens called by owner only --fails called by accounts[8]', 328 | async() => { 329 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 330 | try { 331 | await token.allowTransfers({from: accounts[8]}); 332 | } catch (error) { 333 | return Utils.ensureException(error); 334 | } 335 | }); 336 | 337 | it('Jumps into the crowdsale', async() => { 338 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 339 | let currentTime = Math.floor(Date.now() / 1000); 340 | let endTime = await token 341 | .endTime 342 | .call(); 343 | let durationToInc = Math.floor(endTime - currentTime + 20000); 344 | await timeJump(durationToInc); 345 | assert.strictEqual(true, true); 346 | }); 347 | 348 | it('transfer: first should transfer 10000 to accounts[8] from crowdsale then accounts[8] transfer 1000 to accounts[7] when endTime completes', 349 | async() => { 350 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 351 | await token.transfer(accounts[8], new BigNumber(10000).times(new BigNumber(10).pow(18)), {from: crowdfundAddress}); 352 | let balance = await token 353 | .balanceOf 354 | .call(accounts[8]); 355 | assert.strictEqual(balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), 10000); 356 | await token.transfer(accounts[7], new BigNumber(1000).times(new BigNumber(10).pow(18)), {from: accounts[8]}); 357 | let accBalance = await token 358 | .balanceOf 359 | .call(accounts[7]); 360 | assert.strictEqual(accBalance.dividedBy(new BigNumber(10).pow(18)).toNumber(), 1000); 361 | }); 362 | 363 | // //////////////////////////// Allocation functions //// ////////////////////////////////////////// 364 | 365 | it('releaseEnjinTeamTokens: verifies the enjin team allocation after six months -- fails called before 6 months', 366 | async() => { 367 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 368 | try { 369 | await token.releaseEnjinTeamTokens({from: owner}); 370 | } catch (err) { 371 | return Utils.ensureException(err); 372 | } 373 | }); 374 | 375 | it('releaseAdvisorTokens: verifies the enjin advisor allocation after two months -- fails called before 2 months', 376 | async() => { 377 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 378 | try { 379 | await token.releaseAdvisorTokens({from: owner}); 380 | } catch (err) { 381 | return Utils.ensureException(err); 382 | } 383 | }); 384 | 385 | it('retrieveUnsoldTokens: verifies the retrieval of the unsold tokens after six months -- fails called before the 6 months', 386 | async() => { 387 | let crowdsale = await ENJCrowdfund.new(1000000, beneficiary) 388 | let token = await ENJToken.new(crowdsale.address, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 389 | try { 390 | await token.retrieveUnsoldTokens({from: owner}); 391 | } catch (error) { 392 | return Utils.ensureException(error); 393 | } 394 | }); 395 | 396 | it('Jumps 6 months forward', async() => { 397 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 398 | let currentTime = Math.floor(Date.now() / 1000); 399 | let endTime = await token 400 | .endTime 401 | .call(); 402 | let durationToInc = Math.floor(15552000 + 20000); 403 | await timeJump(durationToInc); 404 | assert.strictEqual(true, true); 405 | }); 406 | 407 | 408 | it('releaseEnjinTeamTokens: verifies the enjin team allocation after six months', async() => { 409 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 410 | let enjinTeamAllocation = (await token.enjinTeamAllocation.call()) 411 | .dividedBy(new BigNumber(10).pow(18)) 412 | .times(0.125) 413 | .toNumber(); 414 | await token.releaseEnjinTeamTokens({from: owner}); 415 | let balance = await token 416 | .balanceOf 417 | .call(teamAddress); 418 | assert.strictEqual(balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), enjinTeamAllocation); 419 | let allocation = await token 420 | .totalAllocated 421 | .call(); 422 | assert.strictEqual(allocation.dividedBy(new BigNumber(10).pow(18)).toNumber(), enjinTeamAllocation + incentiveAllocation); 423 | let totalAllocatedToTeam = await token 424 | .totalAllocatedToTeam 425 | .call(); 426 | assert.strictEqual(totalAllocatedToTeam.dividedBy(new BigNumber(10).pow(18)).toNumber(), enjinTeamAllocation); 427 | }); 428 | 429 | 430 | it('releaseEnjinTeamTokens: verifies the enjin team allocation after six months -- fail, double dip', 431 | async() => { 432 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 433 | let enjinTeamAllocation = (await token.enjinTeamAllocation.call()) 434 | .dividedBy(new BigNumber(10).pow(18)) 435 | .times(0.25) 436 | .toNumber(); 437 | try { 438 | await token.releaseEnjinTeamTokens({from: owner}); 439 | 440 | } catch (err) { 441 | return Utils.ensureException(err); 442 | } 443 | }); 444 | 445 | it('releaseEnjinTeamTokens: verifies the enjin team allocation after six months -- fails called by other than user', 446 | async() => { 447 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 448 | try { 449 | await token.releaseEnjinTeamTokens({from: accounts[8]}); 450 | } catch (err) { 451 | return Utils.ensureException(err); 452 | } 453 | }); 454 | 455 | it('releaseAdvisorTokens: verifies the advisor token allocation after six month', async() => { 456 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 457 | await token.releaseAdvisorTokens({from: owner}); 458 | let balance = await token 459 | .balanceOf 460 | .call(advisorAddress); 461 | assert.strictEqual(balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), 26000000); 462 | let allocation = await token 463 | .totalAllocated 464 | .call(); 465 | assert.strictEqual(allocation.dividedBy(new BigNumber(10).pow(18)).toNumber(), 26000000 + incentiveAllocation); 466 | let _advisorsAllocation = await token 467 | .totalAllocatedToAdvisors 468 | .call(); 469 | assert.strictEqual(_advisorsAllocation.dividedBy(new BigNumber(10).pow(18)).toNumber(), 26000000); 470 | }); 471 | 472 | it('releaseAdvisorTokens: verifies the enjin team allocation after six months -- fails called by other than user', 473 | async() => { 474 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 475 | try { 476 | await token.releaseAdvisorTokens({from: accounts[8]}); 477 | } catch (err) { 478 | return Utils.ensureException(err); 479 | } 480 | }); 481 | 482 | 483 | it('retrieveUnsoldTokens: verifies the retrieval of the unsold tokens after six months', 484 | async() => { 485 | let crowdsale = await ENJCrowdfund.new(1000000, beneficiary) 486 | let token = await ENJToken.new(crowdsale.address, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 487 | await token.retrieveUnsoldTokens({from: owner}); 488 | let balance = await token 489 | .balanceOf 490 | .call(incentiveAddress); 491 | assert.strictEqual(balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), 800000000 + 100000000); 492 | let crowdBalance = await token 493 | .balanceOf 494 | .call(crowdsale.address); 495 | assert.strictEqual(crowdBalance.dividedBy(new BigNumber(10).pow(18)).toNumber(), 0); 496 | }); 497 | 498 | it('retrieveUnsoldTokens: verifies the retrieval of the unsold tokens after six months -- fails when msg.sender not equals to owner', 499 | async() => { 500 | let crowdsale = await ENJCrowdfund.new(1000000, beneficiary) 501 | let token = await ENJToken.new(crowdsale.address, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 502 | try { 503 | await token.retrieveUnsoldTokens({from: accounts[8]}); 504 | } catch (error) { 505 | return Utils.ensureException(error); 506 | } 507 | }); 508 | 509 | 510 | it('releaseEnjinTeamTokens: verifies all of the enjin team allocation', async() => { 511 | let token = await ENJToken.new(crowdfundAddress, advisorAddress, incentiveAddress, teamAddress, {from: owner}); 512 | let balanceSoFar = 0; 513 | let enjinTeamAllocationOtherTranche = (await token.enjinTeamAllocation.call()) 514 | .dividedBy(new BigNumber(10).pow(18)) 515 | .times(0.125) 516 | .toNumber(); 517 | // We are 6 months in, this should work 518 | await token.releaseEnjinTeamTokens({from: owner}); 519 | let balance = await token 520 | .balanceOf 521 | .call(teamAddress); 522 | balanceSoFar = enjinTeamAllocationOtherTranche; 523 | assert.strictEqual(balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), balanceSoFar); 524 | let allocation = await token 525 | .totalAllocated 526 | .call(); 527 | assert.strictEqual(allocation.dividedBy(new BigNumber(10).pow(18)).toNumber(), enjinTeamAllocationOtherTranche + incentiveAllocation); 528 | let totalAllocatedToTeam = await token 529 | .totalAllocatedToTeam 530 | .call(); 531 | assert.strictEqual(totalAllocatedToTeam.dividedBy(new BigNumber(10).pow(18)).toNumber(), balanceSoFar); 532 | 533 | // Add 3 months 534 | for (let i = 0 ; i < 7; i++) { 535 | await timeJump(7776000 + 20000); 536 | await token.releaseEnjinTeamTokens({from: owner}); 537 | balance = await token 538 | .balanceOf 539 | .call(teamAddress); 540 | balanceSoFar += enjinTeamAllocationOtherTranche; 541 | assert.strictEqual(balance.dividedBy(new BigNumber(10).pow(18)).toNumber(), balanceSoFar); 542 | allocation = await token 543 | .totalAllocated 544 | .call(); 545 | assert.strictEqual(allocation.dividedBy(new BigNumber(10).pow(18)).toNumber(), balanceSoFar + incentiveAllocation); 546 | totalAllocatedToTeam = await token 547 | .totalAllocatedToTeam 548 | .call(); 549 | assert.strictEqual(totalAllocatedToTeam.dividedBy(new BigNumber(10).pow(18)).toNumber(), balanceSoFar); 550 | 551 | } 552 | assert.strictEqual(totalAllocatedToTeam.dividedBy(new BigNumber(10).pow(18)).toNumber(), (await token.enjinTeamAllocation.call()).dividedBy(new BigNumber(10).pow(18)).toNumber()) 553 | await timeJump(7776000 + 20000); 554 | try { 555 | await token.retrieveUnsoldTokens({from: accounts[8]}); 556 | } catch (error) { 557 | Utils.ensureException(error); 558 | } 559 | await timeJump(77760000); 560 | try { 561 | await token.retrieveUnsoldTokens({from: accounts[8]}); 562 | } catch (error) { 563 | Utils.ensureException(error); 564 | } 565 | }); 566 | }); --------------------------------------------------------------------------------