├── coverage ├── sort-arrow-sprite.png ├── lcov-report │ ├── sort-arrow-sprite.png │ ├── prettify.css │ ├── index.html │ ├── contracts │ │ ├── index.html │ │ └── ERC20Basic.sol.html │ ├── sorter.js │ ├── base.css │ └── prettify.js ├── prettify.css ├── index.html ├── contracts │ ├── index.html │ ├── ERC20Basic.sol.html │ └── AirdropCentral.sol.html ├── lcov.info ├── sorter.js ├── base.css └── prettify.js ├── migrations └── 1_initial_migration.js ├── README.md ├── truffle.js ├── truffle-config.js ├── travis.yml ├── contracts ├── Migrations.sol ├── ERC20Basic.sol └── AirdropCentral.sol ├── .gitignore ├── package.json ├── LICENSE ├── test └── TestAirdropCentral.js └── coverage.json /coverage/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pabloruiz55/AirdropCentral/HEAD/coverage/sort-arrow-sprite.png -------------------------------------------------------------------------------- /coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pabloruiz55/AirdropCentral/HEAD/coverage/lcov-report/sort-arrow-sprite.png -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Airdrop Central 2 | An AirdropCentral where anyone can submit tokens to be distributed among users 3 | 4 | Check out this article to learn more about the Airdrop Central: https://medium.freecodecamp.org/building-a-multi-token-airdrop-central-to-distribute-erc20-tokens-cb70b6218b5c 5 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "localhost", 5 | port: 8545, 6 | network_id: "*", // Match any network id 7 | gas: 4500000 8 | } 9 | }, 10 | solc: { 11 | optimizer: { 12 | enabled: true, 13 | runs: 200 14 | } 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "localhost", 5 | port: 8545, 6 | network_id: "*", // Match any network id 7 | gas: 4500000 8 | } 9 | }, 10 | solc: { 11 | optimizer: { 12 | enabled: true, 13 | runs: 200 14 | } 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | language: node_js 4 | node_js: 5 | - '7' 6 | install: 7 | - npm install -g truffle 8 | - npm install -g ethereumjs-testrpc 9 | - npm install 10 | script: 11 | - npm test 12 | before_script: 13 | - testrpc > /dev/null & 14 | - sleep 5 15 | after_script: 16 | - npm run coverage && cat coverage/lcov.info | coveralls 17 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.17; 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() public { 12 | owner = msg.sender; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /coverage/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | # /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | yarn-error.log 36 | 37 | # e2e 38 | /e2e/*.js 39 | /e2e/*.map 40 | 41 | # System Files 42 | .DS_Store 43 | Thumbs.db 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "airdropcentral", 3 | "version": "1.0.0", 4 | "description": "An AirdropCentral where anyone can submit tokens to be distributed among users", 5 | "main": "truffle-config.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "dependencies": { 10 | "solidity-coverage": "^0.3.5", 11 | "web3": "^1.0.0-beta.26" 12 | }, 13 | "devDependencies": {}, 14 | "scripts": { 15 | "test": "mocha" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/pabloruiz55/AirdropCentral.git" 20 | }, 21 | "scripts": { 22 | "test": "truffle test", 23 | "coverage": "./node_modules/.bin/solidity-coverage" 24 | }, 25 | "author": "Pablo Ruiz ", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/pabloruiz55/AirdropCentral/issues" 29 | }, 30 | "homepage": "https://github.com/pabloruiz55/AirdropCentral#readme" 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Pablo Ruiz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /coverage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for All files 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | / 20 |

21 |
22 |
23 | 78.26% 24 | Statements 25 | 90/115 26 |
27 |
28 | 42.11% 29 | Branches 30 | 32/76 31 |
32 |
33 | 70% 34 | Functions 35 | 21/30 36 |
37 |
38 | 77.69% 39 | Lines 40 | 94/121 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
FileStatementsBranchesFunctionsLines
contracts/
78.26%90/11542.11%32/7670%21/3077.69%94/121
76 |
77 |
78 | 82 | 83 | 84 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /coverage/lcov-report/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for All files 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | / 20 |

21 |
22 |
23 | 78.26% 24 | Statements 25 | 90/115 26 |
27 |
28 | 42.11% 29 | Branches 30 | 32/76 31 |
32 |
33 | 70% 34 | Functions 35 | 21/30 36 |
37 |
38 | 77.69% 39 | Lines 40 | 94/121 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
FileStatementsBranchesFunctionsLines
contracts/
78.26%90/11542.11%32/7670%21/3077.69%94/121
76 |
77 |
78 | 82 | 83 | 84 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /contracts/ERC20Basic.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.4.18; 2 | 3 | contract ERC20Basic { 4 | using SafeMath for uint256; 5 | 6 | mapping(address => uint256) balances; 7 | mapping (address => mapping (address => uint256)) internal allowed; 8 | string public name; 9 | string public symbol; 10 | uint8 public decimals = 18; 11 | uint256 public totalSupply; 12 | 13 | event Transfer(address indexed from, address indexed to, uint256 value); 14 | event Approval(address indexed owner, address indexed spender, uint256 value); 15 | 16 | function transfer(address _to, uint256 _value) public returns (bool) { 17 | require(_to != address(0)); 18 | require(_value <= balances[msg.sender]); 19 | 20 | // SafeMath.sub will throw if there is not enough balance. 21 | balances[msg.sender] = balances[msg.sender].sub(_value); 22 | balances[_to] = balances[_to].add(_value); 23 | Transfer(msg.sender, _to, _value); 24 | return true; 25 | } 26 | 27 | /** 28 | * @dev Transfer tokens from one address to another 29 | * @param _from address The address which you want to send tokens from 30 | * @param _to address The address which you want to transfer to 31 | * @param _value uint256 the amount of tokens to be transferred 32 | */ 33 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { 34 | require(_to != address(0)); 35 | require(_value <= balances[_from]); 36 | require(_value <= allowed[_from][msg.sender]); 37 | 38 | balances[_from] = balances[_from].sub(_value); 39 | balances[_to] = balances[_to].add(_value); 40 | allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); 41 | Transfer(_from, _to, _value); 42 | return true; 43 | } 44 | 45 | /** 46 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. 47 | * 48 | * Beware that changing an allowance with this method brings the risk that someone may use both the old 49 | * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this 50 | * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: 51 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 52 | * @param _spender The address which will spend the funds. 53 | * @param _value The amount of tokens to be spent. 54 | */ 55 | function approve(address _spender, uint256 _value) public returns (bool) { 56 | allowed[msg.sender][_spender] = _value; 57 | Approval(msg.sender, _spender, _value); 58 | return true; 59 | } 60 | 61 | /** 62 | * @dev Function to check the amount of tokens that an owner allowed to a spender. 63 | * @param _owner address The address which owns the funds. 64 | * @param _spender address The address which will spend the funds. 65 | * @return A uint256 specifying the amount of tokens still available for the spender. 66 | */ 67 | function allowance(address _owner, address _spender) public view returns (uint256) { 68 | return allowed[_owner][_spender]; 69 | } 70 | 71 | function balanceOf(address _owner) public view returns (uint256 balance) { 72 | return balances[_owner]; 73 | } 74 | 75 | function ERC20Basic(string _name, string _symbol) public { 76 | totalSupply = 100000 * 10 ** uint(decimals); 77 | balances[msg.sender] = totalSupply; 78 | name=_name; 79 | symbol = _symbol; 80 | } 81 | 82 | function getAddress() public view returns (address){ 83 | return address(this); 84 | } 85 | } 86 | 87 | /** 88 | * @title SafeMath 89 | * @dev Math operations with safety checks that throw on error 90 | */ 91 | library SafeMath { 92 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 93 | if (a == 0) { 94 | return 0; 95 | } 96 | uint256 c = a * b; 97 | assert(c / a == b); 98 | return c; 99 | } 100 | 101 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 102 | // assert(b > 0); // Solidity automatically throws when dividing by 0 103 | uint256 c = a / b; 104 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 105 | return c; 106 | } 107 | 108 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 109 | assert(b <= a); 110 | return a - b; 111 | } 112 | 113 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 114 | uint256 c = a + b; 115 | assert(c >= a); 116 | return c; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /coverage/contracts/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for contracts/ 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files contracts/ 20 |

21 |
22 |
23 | 78.26% 24 | Statements 25 | 90/115 26 |
27 |
28 | 42.11% 29 | Branches 30 | 32/76 31 |
32 |
33 | 70% 34 | Functions 35 | 21/30 36 |
37 |
38 | 77.69% 39 | Lines 40 | 94/121 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
FileStatementsBranchesFunctionsLines
AirdropCentral.sol
72.15%57/7939.66%23/5863.16%12/1971.76%61/85
ERC20Basic.sol
91.67%33/3650%9/1881.82%9/1191.67%33/36
89 |
90 |
91 | 95 | 96 | 97 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /coverage/lcov-report/contracts/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for contracts/ 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files contracts/ 20 |

21 |
22 |
23 | 78.26% 24 | Statements 25 | 90/115 26 |
27 |
28 | 42.11% 29 | Branches 30 | 32/76 31 |
32 |
33 | 70% 34 | Functions 35 | 21/30 36 |
37 |
38 | 77.69% 39 | Lines 40 | 94/121 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
FileStatementsBranchesFunctionsLines
AirdropCentral.sol
72.15%57/7939.66%23/5863.16%12/1971.76%61/85
ERC20Basic.sol
91.67%33/3650%9/1881.82%9/1191.67%33/36
89 |
90 |
91 | 95 | 96 | 97 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /coverage/lcov.info: -------------------------------------------------------------------------------- 1 | TN: 2 | SF:/Users/pabloruiz55/DocumentsBackup/dapps/AirdropCentral/contracts/AirdropCentral.sol 3 | FN:83,onlyOwner 4 | FN:88,onlyAdmin 5 | FN:93,ifNotPaused 6 | FN:106,AirdropCentral 7 | FN:117,setPaused 8 | FN:126,setAdmin 9 | FN:136,removeFromBlacklist 10 | FN:150,approveSubmission 11 | FN:165,revokeSubmission 12 | FN:181,signupUsersManually 13 | FN:205,airdropTokens 14 | FN:237,returnTokensToAirdropper 15 | FN:267,signUpForAirdrops 16 | FN:284,quitFromAirdrops 17 | FN:296,getTokensAvailableToMe 18 | FN:334,withdrawTokens 19 | FN:375,airdropsCount 20 | FN:379,getAddress 21 | FN:383,airdropHasExpired 22 | FNF:19 23 | FNH:12 24 | FNDA:1,onlyOwner 25 | FNDA:2,onlyAdmin 26 | FNDA:7,ifNotPaused 27 | FNDA:1,AirdropCentral 28 | FNDA:0,setPaused 29 | FNDA:0,setAdmin 30 | FNDA:1,removeFromBlacklist 31 | FNDA:1,approveSubmission 32 | FNDA:1,revokeSubmission 33 | FNDA:0,signupUsersManually 34 | FNDA:3,airdropTokens 35 | FNDA:1,returnTokensToAirdropper 36 | FNDA:2,signUpForAirdrops 37 | FNDA:0,quitFromAirdrops 38 | FNDA:0,getTokensAvailableToMe 39 | FNDA:1,withdrawTokens 40 | FNDA:0,airdropsCount 41 | FNDA:0,getAddress 42 | FNDA:3,airdropHasExpired 43 | DA:84,1 44 | DA:85,1 45 | DA:89,2 46 | DA:90,2 47 | DA:94,7 48 | DA:95,7 49 | DA:107,1 50 | DA:118,0 51 | DA:127,0 52 | DA:137,1 53 | DA:138,1 54 | DA:140,1 55 | DA:141,1 56 | DA:151,1 57 | DA:152,1 58 | DA:154,1 59 | DA:166,1 60 | DA:167,1 61 | DA:168,1 62 | DA:171,1 63 | DA:172,1 64 | DA:182,0 65 | DA:183,0 66 | DA:184,0 67 | DA:186,0 68 | DA:206,3 69 | DA:207,3 70 | DA:209,3 71 | DA:210,3 72 | DA:213,3 73 | DA:216,3 74 | DA:217,3 75 | DA:220,3 76 | DA:221,3 77 | DA:222,3 78 | DA:223,3 79 | DA:226,3 80 | DA:227,3 81 | DA:229,3 82 | DA:241,1 83 | DA:243,1 84 | DA:245,1 85 | DA:246,3 86 | DA:247,3 87 | DA:250,0 88 | DA:251,0 89 | DA:254,1 90 | DA:255,1 91 | DA:268,2 92 | DA:269,2 93 | DA:270,2 94 | DA:272,2 95 | DA:285,0 96 | DA:286,0 97 | DA:287,0 98 | DA:300,0 99 | DA:301,0 100 | DA:303,0 101 | DA:304,0 102 | DA:305,0 103 | DA:307,0 104 | DA:311,0 105 | DA:316,0 106 | DA:319,0 107 | DA:320,0 108 | DA:325,0 109 | DA:338,1 110 | DA:339,1 111 | DA:341,1 112 | DA:343,1 113 | DA:344,3 114 | DA:346,3 115 | DA:350,3 116 | DA:355,3 117 | DA:358,3 118 | DA:360,3 119 | DA:361,3 120 | DA:362,3 121 | DA:368,1 122 | DA:370,1 123 | DA:372,1 124 | DA:376,0 125 | DA:380,0 126 | DA:384,3 127 | DA:385,3 128 | LF:85 129 | LH:61 130 | BRDA:84,1,0,1 131 | BRDA:84,1,1,0 132 | BRDA:89,2,0,2 133 | BRDA:89,2,1,0 134 | BRDA:94,3,0,7 135 | BRDA:94,3,1,0 136 | BRDA:137,4,0,1 137 | BRDA:137,4,1,0 138 | BRDA:140,5,0,1 139 | BRDA:140,5,1,0 140 | BRDA:151,6,0,1 141 | BRDA:151,6,1,0 142 | BRDA:152,7,0,1 143 | BRDA:152,7,1,0 144 | BRDA:166,8,0,1 145 | BRDA:166,8,1,0 146 | BRDA:171,9,0,1 147 | BRDA:171,9,1,0 148 | BRDA:182,10,0,0 149 | BRDA:182,10,1,0 150 | BRDA:206,11,0,3 151 | BRDA:206,11,1,0 152 | BRDA:207,12,0,3 153 | BRDA:207,12,1,0 154 | BRDA:210,13,0,3 155 | BRDA:210,13,1,0 156 | BRDA:226,14,0,3 157 | BRDA:226,14,1,0 158 | BRDA:227,15,0,3 159 | BRDA:227,15,1,0 160 | BRDA:238,16,0,1 161 | BRDA:238,16,1,0 162 | BRDA:247,17,0,0 163 | BRDA:247,17,1,3 164 | BRDA:254,18,0,1 165 | BRDA:254,18,1,0 166 | BRDA:268,19,0,2 167 | BRDA:268,19,1,0 168 | BRDA:285,20,0,0 169 | BRDA:285,20,1,0 170 | BRDA:297,21,0,0 171 | BRDA:297,21,1,0 172 | BRDA:301,22,0,0 173 | BRDA:301,22,1,0 174 | BRDA:311,23,0,0 175 | BRDA:311,23,1,0 176 | BRDA:319,24,0,0 177 | BRDA:319,24,1,0 178 | BRDA:335,25,0,1 179 | BRDA:335,25,1,0 180 | BRDA:339,26,0,1 181 | BRDA:339,26,1,0 182 | BRDA:350,27,0,3 183 | BRDA:350,27,1,0 184 | BRDA:358,28,0,3 185 | BRDA:358,28,1,0 186 | BRDA:370,29,0,1 187 | BRDA:370,29,1,0 188 | BRF:58 189 | BRH:23 190 | end_of_record 191 | TN: 192 | SF:/Users/pabloruiz55/DocumentsBackup/dapps/AirdropCentral/contracts/ERC20Basic.sol 193 | FN:16,transfer 194 | FN:33,transferFrom 195 | FN:55,approve 196 | FN:67,allowance 197 | FN:71,balanceOf 198 | FN:75,ERC20Basic 199 | FN:82,getAddress 200 | FN:92,mul 201 | FN:101,div 202 | FN:108,sub 203 | FN:113,add 204 | FNF:11 205 | FNH:9 206 | FNDA:2,transfer 207 | FNDA:6,transferFrom 208 | FNDA:1,approve 209 | FNDA:0,allowance 210 | FNDA:6,balanceOf 211 | FNDA:2,ERC20Basic 212 | FNDA:0,getAddress 213 | FNDA:6,mul 214 | FNDA:6,div 215 | FNDA:20,sub 216 | FNDA:11,add 217 | DA:17,2 218 | DA:18,2 219 | DA:21,2 220 | DA:22,2 221 | DA:23,2 222 | DA:24,2 223 | DA:34,6 224 | DA:35,6 225 | DA:36,6 226 | DA:38,6 227 | DA:39,6 228 | DA:40,6 229 | DA:41,6 230 | DA:42,6 231 | DA:56,1 232 | DA:57,1 233 | DA:58,1 234 | DA:68,0 235 | DA:72,6 236 | DA:76,2 237 | DA:77,2 238 | DA:78,2 239 | DA:79,2 240 | DA:83,0 241 | DA:93,6 242 | DA:94,0 243 | DA:96,6 244 | DA:97,6 245 | DA:98,6 246 | DA:103,6 247 | DA:105,6 248 | DA:109,20 249 | DA:110,20 250 | DA:114,11 251 | DA:115,11 252 | DA:116,11 253 | LF:36 254 | LH:33 255 | BRDA:17,1,0,2 256 | BRDA:17,1,1,0 257 | BRDA:18,2,0,2 258 | BRDA:18,2,1,0 259 | BRDA:34,3,0,6 260 | BRDA:34,3,1,0 261 | BRDA:35,4,0,6 262 | BRDA:35,4,1,0 263 | BRDA:36,5,0,6 264 | BRDA:36,5,1,0 265 | BRDA:93,6,0,0 266 | BRDA:93,6,1,6 267 | BRDA:97,7,0,6 268 | BRDA:97,7,1,0 269 | BRDA:109,8,0,20 270 | BRDA:109,8,1,0 271 | BRDA:115,9,0,11 272 | BRDA:115,9,1,0 273 | BRF:18 274 | BRH:9 275 | end_of_record 276 | -------------------------------------------------------------------------------- /coverage/sorter.js: -------------------------------------------------------------------------------- 1 | var addSorting = (function () { 2 | "use strict"; 3 | var cols, 4 | currentSort = { 5 | index: 0, 6 | desc: false 7 | }; 8 | 9 | // returns the summary table element 10 | function getTable() { return document.querySelector('.coverage-summary'); } 11 | // returns the thead element of the summary table 12 | function getTableHeader() { return getTable().querySelector('thead tr'); } 13 | // returns the tbody element of the summary table 14 | function getTableBody() { return getTable().querySelector('tbody'); } 15 | // returns the th element for nth column 16 | function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; } 17 | 18 | // loads all columns 19 | function loadColumns() { 20 | var colNodes = getTableHeader().querySelectorAll('th'), 21 | colNode, 22 | cols = [], 23 | col, 24 | i; 25 | 26 | for (i = 0; i < colNodes.length; i += 1) { 27 | colNode = colNodes[i]; 28 | col = { 29 | key: colNode.getAttribute('data-col'), 30 | sortable: !colNode.getAttribute('data-nosort'), 31 | type: colNode.getAttribute('data-type') || 'string' 32 | }; 33 | cols.push(col); 34 | if (col.sortable) { 35 | col.defaultDescSort = col.type === 'number'; 36 | colNode.innerHTML = colNode.innerHTML + ''; 37 | } 38 | } 39 | return cols; 40 | } 41 | // attaches a data attribute to every tr element with an object 42 | // of data values keyed by column name 43 | function loadRowData(tableRow) { 44 | var tableCols = tableRow.querySelectorAll('td'), 45 | colNode, 46 | col, 47 | data = {}, 48 | i, 49 | val; 50 | for (i = 0; i < tableCols.length; i += 1) { 51 | colNode = tableCols[i]; 52 | col = cols[i]; 53 | val = colNode.getAttribute('data-value'); 54 | if (col.type === 'number') { 55 | val = Number(val); 56 | } 57 | data[col.key] = val; 58 | } 59 | return data; 60 | } 61 | // loads all row data 62 | function loadData() { 63 | var rows = getTableBody().querySelectorAll('tr'), 64 | i; 65 | 66 | for (i = 0; i < rows.length; i += 1) { 67 | rows[i].data = loadRowData(rows[i]); 68 | } 69 | } 70 | // sorts the table using the data for the ith column 71 | function sortByIndex(index, desc) { 72 | var key = cols[index].key, 73 | sorter = function (a, b) { 74 | a = a.data[key]; 75 | b = b.data[key]; 76 | return a < b ? -1 : a > b ? 1 : 0; 77 | }, 78 | finalSorter = sorter, 79 | tableBody = document.querySelector('.coverage-summary tbody'), 80 | rowNodes = tableBody.querySelectorAll('tr'), 81 | rows = [], 82 | i; 83 | 84 | if (desc) { 85 | finalSorter = function (a, b) { 86 | return -1 * sorter(a, b); 87 | }; 88 | } 89 | 90 | for (i = 0; i < rowNodes.length; i += 1) { 91 | rows.push(rowNodes[i]); 92 | tableBody.removeChild(rowNodes[i]); 93 | } 94 | 95 | rows.sort(finalSorter); 96 | 97 | for (i = 0; i < rows.length; i += 1) { 98 | tableBody.appendChild(rows[i]); 99 | } 100 | } 101 | // removes sort indicators for current column being sorted 102 | function removeSortIndicators() { 103 | var col = getNthColumn(currentSort.index), 104 | cls = col.className; 105 | 106 | cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); 107 | col.className = cls; 108 | } 109 | // adds sort indicators for current column being sorted 110 | function addSortIndicators() { 111 | getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted'; 112 | } 113 | // adds event listeners for all sorter widgets 114 | function enableUI() { 115 | var i, 116 | el, 117 | ithSorter = function ithSorter(i) { 118 | var col = cols[i]; 119 | 120 | return function () { 121 | var desc = col.defaultDescSort; 122 | 123 | if (currentSort.index === i) { 124 | desc = !currentSort.desc; 125 | } 126 | sortByIndex(i, desc); 127 | removeSortIndicators(); 128 | currentSort.index = i; 129 | currentSort.desc = desc; 130 | addSortIndicators(); 131 | }; 132 | }; 133 | for (i =0 ; i < cols.length; i += 1) { 134 | if (cols[i].sortable) { 135 | // add the click event handler on the th so users 136 | // dont have to click on those tiny arrows 137 | el = getNthColumn(i).querySelector('.sorter').parentElement; 138 | if (el.addEventListener) { 139 | el.addEventListener('click', ithSorter(i)); 140 | } else { 141 | el.attachEvent('onclick', ithSorter(i)); 142 | } 143 | } 144 | } 145 | } 146 | // adds sorting functionality to the UI 147 | return function () { 148 | if (!getTable()) { 149 | return; 150 | } 151 | cols = loadColumns(); 152 | loadData(cols); 153 | addSortIndicators(); 154 | enableUI(); 155 | }; 156 | })(); 157 | 158 | window.addEventListener('load', addSorting); 159 | -------------------------------------------------------------------------------- /coverage/lcov-report/sorter.js: -------------------------------------------------------------------------------- 1 | var addSorting = (function () { 2 | "use strict"; 3 | var cols, 4 | currentSort = { 5 | index: 0, 6 | desc: false 7 | }; 8 | 9 | // returns the summary table element 10 | function getTable() { return document.querySelector('.coverage-summary'); } 11 | // returns the thead element of the summary table 12 | function getTableHeader() { return getTable().querySelector('thead tr'); } 13 | // returns the tbody element of the summary table 14 | function getTableBody() { return getTable().querySelector('tbody'); } 15 | // returns the th element for nth column 16 | function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; } 17 | 18 | // loads all columns 19 | function loadColumns() { 20 | var colNodes = getTableHeader().querySelectorAll('th'), 21 | colNode, 22 | cols = [], 23 | col, 24 | i; 25 | 26 | for (i = 0; i < colNodes.length; i += 1) { 27 | colNode = colNodes[i]; 28 | col = { 29 | key: colNode.getAttribute('data-col'), 30 | sortable: !colNode.getAttribute('data-nosort'), 31 | type: colNode.getAttribute('data-type') || 'string' 32 | }; 33 | cols.push(col); 34 | if (col.sortable) { 35 | col.defaultDescSort = col.type === 'number'; 36 | colNode.innerHTML = colNode.innerHTML + ''; 37 | } 38 | } 39 | return cols; 40 | } 41 | // attaches a data attribute to every tr element with an object 42 | // of data values keyed by column name 43 | function loadRowData(tableRow) { 44 | var tableCols = tableRow.querySelectorAll('td'), 45 | colNode, 46 | col, 47 | data = {}, 48 | i, 49 | val; 50 | for (i = 0; i < tableCols.length; i += 1) { 51 | colNode = tableCols[i]; 52 | col = cols[i]; 53 | val = colNode.getAttribute('data-value'); 54 | if (col.type === 'number') { 55 | val = Number(val); 56 | } 57 | data[col.key] = val; 58 | } 59 | return data; 60 | } 61 | // loads all row data 62 | function loadData() { 63 | var rows = getTableBody().querySelectorAll('tr'), 64 | i; 65 | 66 | for (i = 0; i < rows.length; i += 1) { 67 | rows[i].data = loadRowData(rows[i]); 68 | } 69 | } 70 | // sorts the table using the data for the ith column 71 | function sortByIndex(index, desc) { 72 | var key = cols[index].key, 73 | sorter = function (a, b) { 74 | a = a.data[key]; 75 | b = b.data[key]; 76 | return a < b ? -1 : a > b ? 1 : 0; 77 | }, 78 | finalSorter = sorter, 79 | tableBody = document.querySelector('.coverage-summary tbody'), 80 | rowNodes = tableBody.querySelectorAll('tr'), 81 | rows = [], 82 | i; 83 | 84 | if (desc) { 85 | finalSorter = function (a, b) { 86 | return -1 * sorter(a, b); 87 | }; 88 | } 89 | 90 | for (i = 0; i < rowNodes.length; i += 1) { 91 | rows.push(rowNodes[i]); 92 | tableBody.removeChild(rowNodes[i]); 93 | } 94 | 95 | rows.sort(finalSorter); 96 | 97 | for (i = 0; i < rows.length; i += 1) { 98 | tableBody.appendChild(rows[i]); 99 | } 100 | } 101 | // removes sort indicators for current column being sorted 102 | function removeSortIndicators() { 103 | var col = getNthColumn(currentSort.index), 104 | cls = col.className; 105 | 106 | cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); 107 | col.className = cls; 108 | } 109 | // adds sort indicators for current column being sorted 110 | function addSortIndicators() { 111 | getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted'; 112 | } 113 | // adds event listeners for all sorter widgets 114 | function enableUI() { 115 | var i, 116 | el, 117 | ithSorter = function ithSorter(i) { 118 | var col = cols[i]; 119 | 120 | return function () { 121 | var desc = col.defaultDescSort; 122 | 123 | if (currentSort.index === i) { 124 | desc = !currentSort.desc; 125 | } 126 | sortByIndex(i, desc); 127 | removeSortIndicators(); 128 | currentSort.index = i; 129 | currentSort.desc = desc; 130 | addSortIndicators(); 131 | }; 132 | }; 133 | for (i =0 ; i < cols.length; i += 1) { 134 | if (cols[i].sortable) { 135 | // add the click event handler on the th so users 136 | // dont have to click on those tiny arrows 137 | el = getNthColumn(i).querySelector('.sorter').parentElement; 138 | if (el.addEventListener) { 139 | el.addEventListener('click', ithSorter(i)); 140 | } else { 141 | el.attachEvent('onclick', ithSorter(i)); 142 | } 143 | } 144 | } 145 | } 146 | // adds sorting functionality to the UI 147 | return function () { 148 | if (!getTable()) { 149 | return; 150 | } 151 | cols = loadColumns(); 152 | loadData(cols); 153 | addSortIndicators(); 154 | enableUI(); 155 | }; 156 | })(); 157 | 158 | window.addEventListener('load', addSorting); 159 | -------------------------------------------------------------------------------- /coverage/base.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | margin:0; padding: 0; 3 | height: 100%; 4 | } 5 | body { 6 | font-family: Helvetica Neue, Helvetica, Arial; 7 | font-size: 14px; 8 | color:#333; 9 | } 10 | .small { font-size: 12px; } 11 | *, *:after, *:before { 12 | -webkit-box-sizing:border-box; 13 | -moz-box-sizing:border-box; 14 | box-sizing:border-box; 15 | } 16 | h1 { font-size: 20px; margin: 0;} 17 | h2 { font-size: 14px; } 18 | pre { 19 | font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; 20 | margin: 0; 21 | padding: 0; 22 | -moz-tab-size: 2; 23 | -o-tab-size: 2; 24 | tab-size: 2; 25 | } 26 | a { color:#0074D9; text-decoration:none; } 27 | a:hover { text-decoration:underline; } 28 | .strong { font-weight: bold; } 29 | .space-top1 { padding: 10px 0 0 0; } 30 | .pad2y { padding: 20px 0; } 31 | .pad1y { padding: 10px 0; } 32 | .pad2x { padding: 0 20px; } 33 | .pad2 { padding: 20px; } 34 | .pad1 { padding: 10px; } 35 | .space-left2 { padding-left:55px; } 36 | .space-right2 { padding-right:20px; } 37 | .center { text-align:center; } 38 | .clearfix { display:block; } 39 | .clearfix:after { 40 | content:''; 41 | display:block; 42 | height:0; 43 | clear:both; 44 | visibility:hidden; 45 | } 46 | .fl { float: left; } 47 | @media only screen and (max-width:640px) { 48 | .col3 { width:100%; max-width:100%; } 49 | .hide-mobile { display:none!important; } 50 | } 51 | 52 | .quiet { 53 | color: #7f7f7f; 54 | color: rgba(0,0,0,0.5); 55 | } 56 | .quiet a { opacity: 0.7; } 57 | 58 | .fraction { 59 | font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; 60 | font-size: 10px; 61 | color: #555; 62 | background: #E8E8E8; 63 | padding: 4px 5px; 64 | border-radius: 3px; 65 | vertical-align: middle; 66 | } 67 | 68 | div.path a:link, div.path a:visited { color: #333; } 69 | table.coverage { 70 | border-collapse: collapse; 71 | margin: 10px 0 0 0; 72 | padding: 0; 73 | } 74 | 75 | table.coverage td { 76 | margin: 0; 77 | padding: 0; 78 | vertical-align: top; 79 | } 80 | table.coverage td.line-count { 81 | text-align: right; 82 | padding: 0 5px 0 20px; 83 | } 84 | table.coverage td.line-coverage { 85 | text-align: right; 86 | padding-right: 10px; 87 | min-width:20px; 88 | } 89 | 90 | table.coverage td span.cline-any { 91 | display: inline-block; 92 | padding: 0 5px; 93 | width: 100%; 94 | } 95 | .missing-if-branch { 96 | display: inline-block; 97 | margin-right: 5px; 98 | border-radius: 3px; 99 | position: relative; 100 | padding: 0 4px; 101 | background: #333; 102 | color: yellow; 103 | } 104 | 105 | .skip-if-branch { 106 | display: none; 107 | margin-right: 10px; 108 | position: relative; 109 | padding: 0 4px; 110 | background: #ccc; 111 | color: white; 112 | } 113 | .missing-if-branch .typ, .skip-if-branch .typ { 114 | color: inherit !important; 115 | } 116 | .coverage-summary { 117 | border-collapse: collapse; 118 | width: 100%; 119 | } 120 | .coverage-summary tr { border-bottom: 1px solid #bbb; } 121 | .keyline-all { border: 1px solid #ddd; } 122 | .coverage-summary td, .coverage-summary th { padding: 10px; } 123 | .coverage-summary tbody { border: 1px solid #bbb; } 124 | .coverage-summary td { border-right: 1px solid #bbb; } 125 | .coverage-summary td:last-child { border-right: none; } 126 | .coverage-summary th { 127 | text-align: left; 128 | font-weight: normal; 129 | white-space: nowrap; 130 | } 131 | .coverage-summary th.file { border-right: none !important; } 132 | .coverage-summary th.pct { } 133 | .coverage-summary th.pic, 134 | .coverage-summary th.abs, 135 | .coverage-summary td.pct, 136 | .coverage-summary td.abs { text-align: right; } 137 | .coverage-summary td.file { white-space: nowrap; } 138 | .coverage-summary td.pic { min-width: 120px !important; } 139 | .coverage-summary tfoot td { } 140 | 141 | .coverage-summary .sorter { 142 | height: 10px; 143 | width: 7px; 144 | display: inline-block; 145 | margin-left: 0.5em; 146 | background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; 147 | } 148 | .coverage-summary .sorted .sorter { 149 | background-position: 0 -20px; 150 | } 151 | .coverage-summary .sorted-desc .sorter { 152 | background-position: 0 -10px; 153 | } 154 | .status-line { height: 10px; } 155 | /* dark red */ 156 | .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } 157 | .low .chart { border:1px solid #C21F39 } 158 | /* medium red */ 159 | .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } 160 | /* light red */ 161 | .low, .cline-no { background:#FCE1E5 } 162 | /* light green */ 163 | .high, .cline-yes { background:rgb(230,245,208) } 164 | /* medium green */ 165 | .cstat-yes { background:rgb(161,215,106) } 166 | /* dark green */ 167 | .status-line.high, .high .cover-fill { background:rgb(77,146,33) } 168 | .high .chart { border:1px solid rgb(77,146,33) } 169 | /* dark yellow (gold) */ 170 | .medium .chart { border:1px solid #f9cd0b; } 171 | .status-line.medium, .medium .cover-fill { background: #f9cd0b; } 172 | /* light yellow */ 173 | .medium { background: #fff4c2; } 174 | /* light gray */ 175 | span.cline-neutral { background: #eaeaea; } 176 | 177 | .cbranch-no { background: yellow !important; color: #111; } 178 | 179 | .cstat-skip { background: #ddd; color: #111; } 180 | .fstat-skip { background: #ddd; color: #111 !important; } 181 | .cbranch-skip { background: #ddd !important; color: #111; } 182 | 183 | 184 | .cover-fill, .cover-empty { 185 | display:inline-block; 186 | height: 12px; 187 | } 188 | .chart { 189 | line-height: 0; 190 | } 191 | .cover-empty { 192 | background: white; 193 | } 194 | .cover-full { 195 | border-right: none !important; 196 | } 197 | pre.prettyprint { 198 | border: none !important; 199 | padding: 0 !important; 200 | margin: 0 !important; 201 | } 202 | .com { color: #999 !important; } 203 | .ignore-none { color: #999; font-weight: normal; } 204 | 205 | .wrapper { 206 | min-height: 100%; 207 | height: auto !important; 208 | height: 100%; 209 | margin: 0 auto -48px; 210 | } 211 | .footer, .push { 212 | height: 48px; 213 | } 214 | -------------------------------------------------------------------------------- /coverage/lcov-report/base.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | margin:0; padding: 0; 3 | height: 100%; 4 | } 5 | body { 6 | font-family: Helvetica Neue, Helvetica, Arial; 7 | font-size: 14px; 8 | color:#333; 9 | } 10 | .small { font-size: 12px; } 11 | *, *:after, *:before { 12 | -webkit-box-sizing:border-box; 13 | -moz-box-sizing:border-box; 14 | box-sizing:border-box; 15 | } 16 | h1 { font-size: 20px; margin: 0;} 17 | h2 { font-size: 14px; } 18 | pre { 19 | font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; 20 | margin: 0; 21 | padding: 0; 22 | -moz-tab-size: 2; 23 | -o-tab-size: 2; 24 | tab-size: 2; 25 | } 26 | a { color:#0074D9; text-decoration:none; } 27 | a:hover { text-decoration:underline; } 28 | .strong { font-weight: bold; } 29 | .space-top1 { padding: 10px 0 0 0; } 30 | .pad2y { padding: 20px 0; } 31 | .pad1y { padding: 10px 0; } 32 | .pad2x { padding: 0 20px; } 33 | .pad2 { padding: 20px; } 34 | .pad1 { padding: 10px; } 35 | .space-left2 { padding-left:55px; } 36 | .space-right2 { padding-right:20px; } 37 | .center { text-align:center; } 38 | .clearfix { display:block; } 39 | .clearfix:after { 40 | content:''; 41 | display:block; 42 | height:0; 43 | clear:both; 44 | visibility:hidden; 45 | } 46 | .fl { float: left; } 47 | @media only screen and (max-width:640px) { 48 | .col3 { width:100%; max-width:100%; } 49 | .hide-mobile { display:none!important; } 50 | } 51 | 52 | .quiet { 53 | color: #7f7f7f; 54 | color: rgba(0,0,0,0.5); 55 | } 56 | .quiet a { opacity: 0.7; } 57 | 58 | .fraction { 59 | font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; 60 | font-size: 10px; 61 | color: #555; 62 | background: #E8E8E8; 63 | padding: 4px 5px; 64 | border-radius: 3px; 65 | vertical-align: middle; 66 | } 67 | 68 | div.path a:link, div.path a:visited { color: #333; } 69 | table.coverage { 70 | border-collapse: collapse; 71 | margin: 10px 0 0 0; 72 | padding: 0; 73 | } 74 | 75 | table.coverage td { 76 | margin: 0; 77 | padding: 0; 78 | vertical-align: top; 79 | } 80 | table.coverage td.line-count { 81 | text-align: right; 82 | padding: 0 5px 0 20px; 83 | } 84 | table.coverage td.line-coverage { 85 | text-align: right; 86 | padding-right: 10px; 87 | min-width:20px; 88 | } 89 | 90 | table.coverage td span.cline-any { 91 | display: inline-block; 92 | padding: 0 5px; 93 | width: 100%; 94 | } 95 | .missing-if-branch { 96 | display: inline-block; 97 | margin-right: 5px; 98 | border-radius: 3px; 99 | position: relative; 100 | padding: 0 4px; 101 | background: #333; 102 | color: yellow; 103 | } 104 | 105 | .skip-if-branch { 106 | display: none; 107 | margin-right: 10px; 108 | position: relative; 109 | padding: 0 4px; 110 | background: #ccc; 111 | color: white; 112 | } 113 | .missing-if-branch .typ, .skip-if-branch .typ { 114 | color: inherit !important; 115 | } 116 | .coverage-summary { 117 | border-collapse: collapse; 118 | width: 100%; 119 | } 120 | .coverage-summary tr { border-bottom: 1px solid #bbb; } 121 | .keyline-all { border: 1px solid #ddd; } 122 | .coverage-summary td, .coverage-summary th { padding: 10px; } 123 | .coverage-summary tbody { border: 1px solid #bbb; } 124 | .coverage-summary td { border-right: 1px solid #bbb; } 125 | .coverage-summary td:last-child { border-right: none; } 126 | .coverage-summary th { 127 | text-align: left; 128 | font-weight: normal; 129 | white-space: nowrap; 130 | } 131 | .coverage-summary th.file { border-right: none !important; } 132 | .coverage-summary th.pct { } 133 | .coverage-summary th.pic, 134 | .coverage-summary th.abs, 135 | .coverage-summary td.pct, 136 | .coverage-summary td.abs { text-align: right; } 137 | .coverage-summary td.file { white-space: nowrap; } 138 | .coverage-summary td.pic { min-width: 120px !important; } 139 | .coverage-summary tfoot td { } 140 | 141 | .coverage-summary .sorter { 142 | height: 10px; 143 | width: 7px; 144 | display: inline-block; 145 | margin-left: 0.5em; 146 | background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; 147 | } 148 | .coverage-summary .sorted .sorter { 149 | background-position: 0 -20px; 150 | } 151 | .coverage-summary .sorted-desc .sorter { 152 | background-position: 0 -10px; 153 | } 154 | .status-line { height: 10px; } 155 | /* dark red */ 156 | .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } 157 | .low .chart { border:1px solid #C21F39 } 158 | /* medium red */ 159 | .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } 160 | /* light red */ 161 | .low, .cline-no { background:#FCE1E5 } 162 | /* light green */ 163 | .high, .cline-yes { background:rgb(230,245,208) } 164 | /* medium green */ 165 | .cstat-yes { background:rgb(161,215,106) } 166 | /* dark green */ 167 | .status-line.high, .high .cover-fill { background:rgb(77,146,33) } 168 | .high .chart { border:1px solid rgb(77,146,33) } 169 | /* dark yellow (gold) */ 170 | .medium .chart { border:1px solid #f9cd0b; } 171 | .status-line.medium, .medium .cover-fill { background: #f9cd0b; } 172 | /* light yellow */ 173 | .medium { background: #fff4c2; } 174 | /* light gray */ 175 | span.cline-neutral { background: #eaeaea; } 176 | 177 | .cbranch-no { background: yellow !important; color: #111; } 178 | 179 | .cstat-skip { background: #ddd; color: #111; } 180 | .fstat-skip { background: #ddd; color: #111 !important; } 181 | .cbranch-skip { background: #ddd !important; color: #111; } 182 | 183 | 184 | .cover-fill, .cover-empty { 185 | display:inline-block; 186 | height: 12px; 187 | } 188 | .chart { 189 | line-height: 0; 190 | } 191 | .cover-empty { 192 | background: white; 193 | } 194 | .cover-full { 195 | border-right: none !important; 196 | } 197 | pre.prettyprint { 198 | border: none !important; 199 | padding: 0 !important; 200 | margin: 0 !important; 201 | } 202 | .com { color: #999 !important; } 203 | .ignore-none { color: #999; font-weight: normal; } 204 | 205 | .wrapper { 206 | min-height: 100%; 207 | height: auto !important; 208 | height: 100%; 209 | margin: 0 auto -48px; 210 | } 211 | .footer, .push { 212 | height: 48px; 213 | } 214 | -------------------------------------------------------------------------------- /test/TestAirdropCentral.js: -------------------------------------------------------------------------------- 1 | const AirdropCentral = artifacts.require("./AirdropCentral.sol"); 2 | const ERC20Basic = artifacts.require("./ERC20Basic.sol"); 3 | const Web3 = require('web3') 4 | 5 | //The following line is required to use timeTravel with web3 v1.x.x 6 | Web3.providers.HttpProvider.prototype.sendAsync = Web3.providers.HttpProvider.prototype.send; 7 | 8 | const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")) // Hardcoded development port 9 | 10 | const timeTravel = function (time) { 11 | return new Promise((resolve, reject) => { 12 | web3.currentProvider.sendAsync({ 13 | jsonrpc: "2.0", 14 | method: "evm_increaseTime", 15 | params: [time], // 86400 is num seconds in day 16 | id: new Date().getTime() 17 | }, (err, result) => { 18 | if(err){ return reject(err) } 19 | return resolve(result) 20 | }); 21 | }) 22 | } 23 | 24 | const mineBlock = function () { 25 | return new Promise((resolve, reject) => { 26 | web3.currentProvider.sendAsync({ 27 | jsonrpc: "2.0", 28 | method: "evm_mine" 29 | }, (err, result) => { 30 | if(err){ return reject(err) } 31 | return resolve(result) 32 | }); 33 | }) 34 | } 35 | 36 | const logTitle = function (title) { 37 | console.log("*****************************************"); 38 | console.log(title); 39 | console.log("*****************************************"); 40 | } 41 | 42 | const logError = function (err) { 43 | console.log("-----------------------------------------"); 44 | console.log(err); 45 | console.log("-----------------------------------------"); 46 | } 47 | 48 | contract('AirdropCentral', function(accounts) { 49 | let airdropcentral; 50 | let token; 51 | let token2; 52 | 53 | // STEP 1: Create Token Central with accounts[0] 54 | it("should create the Airdrop Central", async function () { 55 | airdropcentral = await AirdropCentral.new({from:accounts[0]}); 56 | assert.notEqual(airdropcentral.valueOf(), "0x0000000000000000000000000000000000000000", "Airdrop Central was not initialized"); 57 | }); 58 | 59 | // STEP 2: Create 2 tokens with accounts[1] and [2] 60 | it("should create two token contracts", async function () { 61 | token = await ERC20Basic.new("Token1","TKN",{from:accounts[1]}); 62 | assert.notEqual(token.valueOf(), "0x0000000000000000000000000000000000000000", "Token was not initialized"); 63 | 64 | token2 = await ERC20Basic.new("Other Token","OTH",{from:accounts[2]}); 65 | assert.notEqual(token2.valueOf(), "0x0000000000000000000000000000000000000000", "Token was not initialized"); 66 | 67 | }); 68 | 69 | // STEP 3: Accept submission 70 | it("should accept a token and airdropper", async function () { 71 | await airdropcentral.revokeSubmission(accounts[1],token.address,{from:accounts[0]}); 72 | let airdropperBlacklist = await airdropcentral.airdropperBlacklist(accounts[1]); 73 | //console.log("blacklisted?",airdropperBlacklist); 74 | 75 | await airdropcentral.removeFromBlacklist(accounts[1],token.address,{from:accounts[0]}); 76 | await airdropcentral.approveSubmission(accounts[1],token.address,{from:accounts[0]}); 77 | 78 | let tokenWhitelisted = await airdropcentral.tokenWhitelist(token.address); 79 | assert.isTrue(tokenWhitelisted, "submission was not accepted"); 80 | }); 81 | 82 | // STEP 4: Sign up user accounts[3], [4] 83 | it("should sign user up", async function () { 84 | await airdropcentral.signUpForAirdrops({from:accounts[3]}); 85 | await airdropcentral.signUpForAirdrops({from:accounts[4]}); 86 | let users = await airdropcentral.userSignupCount(); 87 | //console.log("Users:",users.toString()); 88 | let userData3 = await airdropcentral.signups(accounts[3]); 89 | let userData4 = await airdropcentral.signups(accounts[4]); 90 | //console.log("User data:",userData); 91 | assert.equal(userData3[0], accounts[3], "User 3 was not signed up"); 92 | assert.equal(userData4[0], accounts[4], "User 4 was not signed up"); 93 | 94 | }); 95 | 96 | // STEP 5: Airdrop token 1 97 | it("should perform airdrop for token 1", async function () { 98 | await token.approve(airdropcentral.address,10000 * 10 ** 18,{from:accounts[1]}); 99 | await airdropcentral.airdropTokens(token.address, 100, 10000,{from:accounts[1]}); 100 | let airdrop1 = await airdropcentral.airdroppedTokens(token.address,0); 101 | console.log("Airdrop 1a data:",airdrop1); 102 | 103 | await airdropcentral.airdropTokens(token.address, 150, 1000,{from:accounts[1]}); 104 | airdrop1 = await airdropcentral.airdroppedTokens(token.address,1); 105 | console.log("Airdrop 1b data:",airdrop1); 106 | 107 | await airdropcentral.airdropTokens(token.address, 250, 1000,{from:accounts[1]}); 108 | airdrop1 = await airdropcentral.airdroppedTokens(token.address,2); 109 | console.log("Airdrop 1c data:",airdrop1); 110 | 111 | }); 112 | 113 | // STEP 6: Withdraw tokens of airdrop 1 114 | // it("user 3 should withdraw tokens of airdrop 1", async function () { 115 | // await airdropcentral.withdrawTokens(token.address,{from:accounts[3]}); 116 | // let tokenBalance = await token.balanceOf(accounts[3]); 117 | // console.log("User 3 new token balance:",tokenBalance); 118 | // 119 | // }); 120 | 121 | // STEP 7: Withdraw tokens of airdrop 1 after expriation 122 | it("user 4 should not be able to withdraw tokens of airdrop 1 after expriation", async function () { 123 | logTitle("Will move forward in time"); 124 | await timeTravel(1500) // Move forward 6 days in time so the crowdsale has ended 125 | await mineBlock() // workaround for https://github.com/ethereumjs/testrpc/issues/336 126 | 127 | 128 | await airdropcentral.withdrawTokens(token.address,{from:accounts[4]}); 129 | let tokenBalance = await token.balanceOf(accounts[4]); 130 | console.log("User 4 new token balance:",tokenBalance); 131 | 132 | }); 133 | 134 | // STEP 8: Withdraw expired tokens 135 | it("airdropper 1 should be able to get his tokens back", async function () { 136 | let tokenBalance = await token.balanceOf(accounts[1]); 137 | console.log("Airdropper 1 prev token balance:",tokenBalance); 138 | await airdropcentral.returnTokensToAirdropper(token.address,{from:accounts[1]}); 139 | tokenBalance = await token.balanceOf(accounts[1]); 140 | console.log("Airdropper 1 new token balance:",tokenBalance); 141 | 142 | }); 143 | 144 | }); 145 | -------------------------------------------------------------------------------- /coverage/contracts/ERC20Basic.sol.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for contracts/ERC20Basic.sol 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / contracts/ ERC20Basic.sol 20 |

21 |
22 |
23 | 91.67% 24 | Statements 25 | 33/36 26 |
27 |
28 | 50% 29 | Branches 30 | 9/18 31 |
32 |
33 | 81.82% 34 | Functions 35 | 9/11 36 |
37 |
38 | 91.67% 39 | Lines 40 | 33/36 41 |
42 |
43 |
44 |
45 |

 46 | 
401 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 | 39 85 | 40 86 | 41 87 | 42 88 | 43 89 | 44 90 | 45 91 | 46 92 | 47 93 | 48 94 | 49 95 | 50 96 | 51 97 | 52 98 | 53 99 | 54 100 | 55 101 | 56 102 | 57 103 | 58 104 | 59 105 | 60 106 | 61 107 | 62 108 | 63 109 | 64 110 | 65 111 | 66 112 | 67 113 | 68 114 | 69 115 | 70 116 | 71 117 | 72 118 | 73 119 | 74 120 | 75 121 | 76 122 | 77 123 | 78 124 | 79 125 | 80 126 | 81 127 | 82 128 | 83 129 | 84 130 | 85 131 | 86 132 | 87 133 | 88 134 | 89 135 | 90 136 | 91 137 | 92 138 | 93 139 | 94 140 | 95 141 | 96 142 | 97 143 | 98 144 | 99 145 | 100 146 | 101 147 | 102 148 | 103 149 | 104 150 | 105 151 | 106 152 | 107 153 | 108 154 | 109 155 | 110 156 | 111 157 | 112 158 | 113 159 | 114 160 | 115 161 | 116 162 | 117 163 | 118 164 | 119  165 |   166 |   167 |   168 |   169 |   170 |   171 |   172 |   173 |   174 |   175 |   176 |   177 |   178 |   179 |   180 | 181 | 182 |   183 |   184 | 185 | 186 | 187 | 188 |   189 |   190 |   191 |   192 |   193 |   194 |   195 |   196 |   197 | 198 | 199 | 200 |   201 | 202 | 203 | 204 | 205 | 206 |   207 |   208 |   209 |   210 |   211 |   212 |   213 |   214 |   215 |   216 |   217 |   218 |   219 | 220 | 221 | 222 |   223 |   224 |   225 |   226 |   227 |   228 |   229 |   230 |   231 |   232 |   233 |   234 |   235 | 236 |   237 |   238 |   239 | 240 | 241 | 242 | 243 |   244 |   245 |   246 |   247 |   248 |   249 |   250 |   251 |   252 |   253 |   254 |   255 |   256 | 257 |   258 |   259 | 260 | 261 | 262 |   263 |   264 |   265 |   266 | 267 |   268 | 269 |   270 |   271 |   272 | 20× 273 | 20× 274 |   275 |   276 |   277 | 11× 278 | 11× 279 | 11× 280 |   281 |   282 |  
pragma solidity 0.4.18;
283 |  
284 | contract ERC20Basic {
285 |   using SafeMath for uint256;
286 |  
287 |   mapping(address => uint256) balances;
288 |   mapping (address => mapping (address => uint256)) internal allowed;
289 |   string public name;
290 |   string public symbol;
291 |   uint8 public decimals = 18;
292 |   uint256 public totalSupply;
293 |  
294 |   event Transfer(address indexed from, address indexed to, uint256 value);
295 |   event Approval(address indexed owner, address indexed spender, uint256 value);
296 |  
297 |   function transfer(address _to, uint256 _value) public returns (bool) {
298 |     Erequire(_to != address(0));
299 |     Erequire(_value <= balances[msg.sender]);
300 |  
301 |     // SafeMath.sub will throw if there is not enough balance.
302 |     balances[msg.sender] = balances[msg.sender].sub(_value);
303 |     balances[_to] = balances[_to].add(_value);
304 |     Transfer(msg.sender, _to, _value);
305 |     return true;
306 |   }
307 |  
308 |   /**
309 |    * @dev Transfer tokens from one address to another
310 |    * @param _from address The address which you want to send tokens from
311 |    * @param _to address The address which you want to transfer to
312 |    * @param _value uint256 the amount of tokens to be transferred
313 |    */
314 |   function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
315 |     Erequire(_to != address(0));
316 |     Erequire(_value <= balances[_from]);
317 |     Erequire(_value <= allowed[_from][msg.sender]);
318 |  
319 |     balances[_from] = balances[_from].sub(_value);
320 |     balances[_to] = balances[_to].add(_value);
321 |     allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
322 |     Transfer(_from, _to, _value);
323 |     return true;
324 |   }
325 |  
326 |   /**
327 |    * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
328 |    *
329 |    * Beware that changing an allowance with this method brings the risk that someone may use both the old
330 |    * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
331 |    * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
332 |    * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
333 |    * @param _spender The address which will spend the funds.
334 |    * @param _value The amount of tokens to be spent.
335 |    */
336 |   function approve(address _spender, uint256 _value) public returns (bool) {
337 |     allowed[msg.sender][_spender] = _value;
338 |     Approval(msg.sender, _spender, _value);
339 |     return true;
340 |   }
341 |  
342 |   /**
343 |    * @dev Function to check the amount of tokens that an owner allowed to a spender.
344 |    * @param _owner address The address which owns the funds.
345 |    * @param _spender address The address which will spend the funds.
346 |    * @return A uint256 specifying the amount of tokens still available for the spender.
347 |    */
348 |   function allowance(address _owner, address _spender) public view returns (uint256) {
349 |     return allowed[_owner][_spender];
350 |   }
351 |  
352 |   function balanceOf(address _owner) public view returns (uint256 balance) {
353 |     return balances[_owner];
354 |   }
355 |  
356 |   function ERC20Basic(string _name, string _symbol) public {
357 |     totalSupply = 100000 * 10 ** uint(decimals);
358 |     balances[msg.sender] = totalSupply;
359 |     name=_name;
360 |     symbol = _symbol;
361 |   }
362 |  
363 |   function getAddress() public view returns (address){
364 |       return address(this);
365 |   }
366 | }
367 |  
368 | /**
369 |  * @title SafeMath
370 |  * @dev Math operations with safety checks that throw on error
371 |  */
372 | library SafeMath {
373 |   function mul(uint256 a, uint256 b) internal pure returns (uint256) {
374 |     Iif (a == 0) {
375 |       return 0;
376 |     }
377 |     uint256 c = a * b;
378 |     Eassert(c / a == b);
379 |     return c;
380 |   }
381 |  
382 |   function div(uint256 a, uint256 b) internal pure returns (uint256) {
383 |     // assert(b > 0); // Solidity automatically throws when dividing by 0
384 |     uint256 c = a / b;
385 |     // assert(a == b * c + a % b); // There is no case in which this doesn't hold
386 |     return c;
387 |   }
388 |  
389 |   function sub(uint256 a, uint256 b) internal pure returns (uint256) {
390 |     Eassert(b <= a);
391 |     return a - b;
392 |   }
393 |  
394 |   function add(uint256 a, uint256 b) internal pure returns (uint256) {
395 |     uint256 c = a + b;
396 |     Eassert(c >= a);
397 |     return c;
398 |   }
399 | }
400 |  
402 |
403 |
404 | 408 | 409 | 410 | 417 | 418 | 419 | 420 | -------------------------------------------------------------------------------- /coverage/lcov-report/contracts/ERC20Basic.sol.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for contracts/ERC20Basic.sol 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / contracts/ ERC20Basic.sol 20 |

21 |
22 |
23 | 91.67% 24 | Statements 25 | 33/36 26 |
27 |
28 | 50% 29 | Branches 30 | 9/18 31 |
32 |
33 | 81.82% 34 | Functions 35 | 9/11 36 |
37 |
38 | 91.67% 39 | Lines 40 | 33/36 41 |
42 |
43 |
44 |
45 |

 46 | 
401 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 | 39 85 | 40 86 | 41 87 | 42 88 | 43 89 | 44 90 | 45 91 | 46 92 | 47 93 | 48 94 | 49 95 | 50 96 | 51 97 | 52 98 | 53 99 | 54 100 | 55 101 | 56 102 | 57 103 | 58 104 | 59 105 | 60 106 | 61 107 | 62 108 | 63 109 | 64 110 | 65 111 | 66 112 | 67 113 | 68 114 | 69 115 | 70 116 | 71 117 | 72 118 | 73 119 | 74 120 | 75 121 | 76 122 | 77 123 | 78 124 | 79 125 | 80 126 | 81 127 | 82 128 | 83 129 | 84 130 | 85 131 | 86 132 | 87 133 | 88 134 | 89 135 | 90 136 | 91 137 | 92 138 | 93 139 | 94 140 | 95 141 | 96 142 | 97 143 | 98 144 | 99 145 | 100 146 | 101 147 | 102 148 | 103 149 | 104 150 | 105 151 | 106 152 | 107 153 | 108 154 | 109 155 | 110 156 | 111 157 | 112 158 | 113 159 | 114 160 | 115 161 | 116 162 | 117 163 | 118 164 | 119  165 |   166 |   167 |   168 |   169 |   170 |   171 |   172 |   173 |   174 |   175 |   176 |   177 |   178 |   179 |   180 | 181 | 182 |   183 |   184 | 185 | 186 | 187 | 188 |   189 |   190 |   191 |   192 |   193 |   194 |   195 |   196 |   197 | 198 | 199 | 200 |   201 | 202 | 203 | 204 | 205 | 206 |   207 |   208 |   209 |   210 |   211 |   212 |   213 |   214 |   215 |   216 |   217 |   218 |   219 | 220 | 221 | 222 |   223 |   224 |   225 |   226 |   227 |   228 |   229 |   230 |   231 |   232 |   233 |   234 |   235 | 236 |   237 |   238 |   239 | 240 | 241 | 242 | 243 |   244 |   245 |   246 |   247 |   248 |   249 |   250 |   251 |   252 |   253 |   254 |   255 |   256 | 257 |   258 |   259 | 260 | 261 | 262 |   263 |   264 |   265 |   266 | 267 |   268 | 269 |   270 |   271 |   272 | 20× 273 | 20× 274 |   275 |   276 |   277 | 11× 278 | 11× 279 | 11× 280 |   281 |   282 |  
pragma solidity 0.4.18;
283 |  
284 | contract ERC20Basic {
285 |   using SafeMath for uint256;
286 |  
287 |   mapping(address => uint256) balances;
288 |   mapping (address => mapping (address => uint256)) internal allowed;
289 |   string public name;
290 |   string public symbol;
291 |   uint8 public decimals = 18;
292 |   uint256 public totalSupply;
293 |  
294 |   event Transfer(address indexed from, address indexed to, uint256 value);
295 |   event Approval(address indexed owner, address indexed spender, uint256 value);
296 |  
297 |   function transfer(address _to, uint256 _value) public returns (bool) {
298 |     Erequire(_to != address(0));
299 |     Erequire(_value <= balances[msg.sender]);
300 |  
301 |     // SafeMath.sub will throw if there is not enough balance.
302 |     balances[msg.sender] = balances[msg.sender].sub(_value);
303 |     balances[_to] = balances[_to].add(_value);
304 |     Transfer(msg.sender, _to, _value);
305 |     return true;
306 |   }
307 |  
308 |   /**
309 |    * @dev Transfer tokens from one address to another
310 |    * @param _from address The address which you want to send tokens from
311 |    * @param _to address The address which you want to transfer to
312 |    * @param _value uint256 the amount of tokens to be transferred
313 |    */
314 |   function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
315 |     Erequire(_to != address(0));
316 |     Erequire(_value <= balances[_from]);
317 |     Erequire(_value <= allowed[_from][msg.sender]);
318 |  
319 |     balances[_from] = balances[_from].sub(_value);
320 |     balances[_to] = balances[_to].add(_value);
321 |     allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
322 |     Transfer(_from, _to, _value);
323 |     return true;
324 |   }
325 |  
326 |   /**
327 |    * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
328 |    *
329 |    * Beware that changing an allowance with this method brings the risk that someone may use both the old
330 |    * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
331 |    * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
332 |    * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
333 |    * @param _spender The address which will spend the funds.
334 |    * @param _value The amount of tokens to be spent.
335 |    */
336 |   function approve(address _spender, uint256 _value) public returns (bool) {
337 |     allowed[msg.sender][_spender] = _value;
338 |     Approval(msg.sender, _spender, _value);
339 |     return true;
340 |   }
341 |  
342 |   /**
343 |    * @dev Function to check the amount of tokens that an owner allowed to a spender.
344 |    * @param _owner address The address which owns the funds.
345 |    * @param _spender address The address which will spend the funds.
346 |    * @return A uint256 specifying the amount of tokens still available for the spender.
347 |    */
348 |   function allowance(address _owner, address _spender) public view returns (uint256) {
349 |     return allowed[_owner][_spender];
350 |   }
351 |  
352 |   function balanceOf(address _owner) public view returns (uint256 balance) {
353 |     return balances[_owner];
354 |   }
355 |  
356 |   function ERC20Basic(string _name, string _symbol) public {
357 |     totalSupply = 100000 * 10 ** uint(decimals);
358 |     balances[msg.sender] = totalSupply;
359 |     name=_name;
360 |     symbol = _symbol;
361 |   }
362 |  
363 |   function getAddress() public view returns (address){
364 |       return address(this);
365 |   }
366 | }
367 |  
368 | /**
369 |  * @title SafeMath
370 |  * @dev Math operations with safety checks that throw on error
371 |  */
372 | library SafeMath {
373 |   function mul(uint256 a, uint256 b) internal pure returns (uint256) {
374 |     Iif (a == 0) {
375 |       return 0;
376 |     }
377 |     uint256 c = a * b;
378 |     Eassert(c / a == b);
379 |     return c;
380 |   }
381 |  
382 |   function div(uint256 a, uint256 b) internal pure returns (uint256) {
383 |     // assert(b > 0); // Solidity automatically throws when dividing by 0
384 |     uint256 c = a / b;
385 |     // assert(a == b * c + a % b); // There is no case in which this doesn't hold
386 |     return c;
387 |   }
388 |  
389 |   function sub(uint256 a, uint256 b) internal pure returns (uint256) {
390 |     Eassert(b <= a);
391 |     return a - b;
392 |   }
393 |  
394 |   function add(uint256 a, uint256 b) internal pure returns (uint256) {
395 |     uint256 c = a + b;
396 |     Eassert(c >= a);
397 |     return c;
398 |   }
399 | }
400 |  
402 |
403 |
404 | 408 | 409 | 410 | 417 | 418 | 419 | 420 | -------------------------------------------------------------------------------- /coverage/prettify.js: -------------------------------------------------------------------------------- 1 | window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); 2 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.js: -------------------------------------------------------------------------------- 1 | window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); 2 | -------------------------------------------------------------------------------- /contracts/AirdropCentral.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.4.18; 2 | 3 | import './ERC20Basic.sol'; 4 | 5 | /// @author Pablo Ruiz 6 | /// @Title Airdrop Central - To submit your token follow the instructions at: 7 | /// https://github.com/pabloruiz55/AirdropCentral 8 | 9 | ////////////////// 10 | 11 | // 12 | // Permissions 13 | // Admin Airdropper User 14 | // approve/ revoke submissions x 15 | // pause / unpause x 16 | // signupUsersManually x 17 | // airdropTokens x 18 | // returnTokensToAirdropper x 19 | // signUpForAirdrops x 20 | // quitFromAirdrops x 21 | // getTokensAvailableToMe x 22 | // withdrawTokens x 23 | 24 | //////// 25 | 26 | contract AirdropCentral { 27 | using SafeMath for uint256; 28 | 29 | // The owner / admin of the Airdrop Central 30 | // In charge of accepting airdrop submissions 31 | address public owner; 32 | 33 | // How many tokens the owner keeps of each airdrop as transaction fee 34 | uint public ownersCut = 2; // 2% commision in tokens 35 | 36 | // Id of each airdrop (token address + id #) 37 | struct TokenAirdropID { 38 | address tokenAddress; 39 | uint airdropAddressID; // The id of the airdrop within a token address 40 | } 41 | 42 | struct TokenAirdrop { 43 | address tokenAddress; 44 | uint airdropAddressID; // The id of the airdrop within a token address 45 | address tokenOwner; 46 | uint airdropDate; // The airdrop creation date 47 | uint airdropExpirationDate; // When airdrop expires 48 | uint tokenBalance; // Current balance 49 | uint totalDropped; // Total to distribute 50 | uint usersAtDate; // How many users were signed at airdrop date 51 | } 52 | 53 | struct User { 54 | address userAddress; 55 | uint signupDate; // Determines which airdrops the user has access to 56 | // User -> Airdrop id# -> balance 57 | mapping (address => mapping (uint => uint)) withdrawnBalances; 58 | } 59 | 60 | // Maps the tokens available to airdrop central contract. Keyed by token address 61 | mapping (address => TokenAirdrop[]) public airdroppedTokens; 62 | TokenAirdropID[] public airdrops; 63 | 64 | // List of users that signed up 65 | mapping (address => User) public signups; 66 | uint public userSignupCount = 0; 67 | 68 | // Admins with permission to accept submissions 69 | mapping (address => bool) admins; 70 | 71 | // Whether or not the contract is paused (in case of a problem is detected) 72 | bool public paused = false; 73 | 74 | // List of approved/rejected token/sender addresses 75 | mapping (address => bool) public tokenWhitelist; 76 | mapping (address => bool) public tokenBlacklist; 77 | mapping (address => bool) public airdropperBlacklist; 78 | 79 | // 80 | // Modifiers 81 | // 82 | 83 | modifier onlyOwner { 84 | require(msg.sender == owner); 85 | _; 86 | } 87 | 88 | modifier onlyAdmin { 89 | require(msg.sender == owner || admins[msg.sender]); 90 | _; 91 | } 92 | 93 | modifier ifNotPaused { 94 | require(!paused); 95 | _; 96 | } 97 | 98 | // 99 | // Events 100 | // 101 | 102 | event E_AirdropSubmitted(address _tokenAddress, address _airdropper,uint _totalTokensToDistribute,uint creationDate, uint _expirationDate); 103 | event E_Signup(address _userAddress,uint _signupDate); 104 | event E_TokensWithdrawn(address _tokenAddress,address _userAddress, uint _tokensWithdrawn, uint _withdrawalDate); 105 | 106 | function AirdropCentral() public { 107 | owner = msg.sender; 108 | } 109 | 110 | ///////////////////// 111 | // Owner / Admin functions 112 | ///////////////////// 113 | 114 | /** 115 | * @dev pause or unpause the contract in case a problem is detected 116 | */ 117 | function setPaused(bool _isPaused) public onlyOwner{ 118 | paused = _isPaused; 119 | } 120 | 121 | /** 122 | * @dev allows owner to grant/revoke admin privileges to other accounts 123 | * @param _admin is the account to be granted/revoked admin privileges 124 | * @param isAdmin is whether or not to grant or revoke privileges. 125 | */ 126 | function setAdmin(address _admin, bool isAdmin) public onlyOwner{ 127 | admins[_admin] = isAdmin; 128 | } 129 | 130 | /** 131 | * @dev removes a token and/or account from the blacklist to allow 132 | * them to submit a token again. 133 | * @param _airdropper is the account to remove from blacklist 134 | * @param _tokenAddress is the token address to remove from blacklist 135 | */ 136 | function removeFromBlacklist(address _airdropper, address _tokenAddress) public onlyOwner { 137 | if(_airdropper != address(0)) 138 | airdropperBlacklist[_airdropper] = false; 139 | 140 | if(_tokenAddress != address(0)) 141 | tokenBlacklist[_tokenAddress] = false; 142 | } 143 | 144 | /** 145 | * @dev approves a given token and account address to make it available for airdrop 146 | * This is necessary to avoid malicious contracts to be added. 147 | * @param _airdropper is the account to add to the whitelist 148 | * @param _tokenAddress is the token address to add to the whitelist 149 | */ 150 | function approveSubmission(address _airdropper, address _tokenAddress) public onlyAdmin { 151 | require(!airdropperBlacklist[_airdropper]); 152 | require(!tokenBlacklist[_tokenAddress]); 153 | 154 | tokenWhitelist[_tokenAddress] = true; 155 | } 156 | 157 | /** 158 | * @dev removes token and airdropper from whitelist. 159 | * Also adds them to a blacklist to prevent further submissions of any 160 | * To be used in case of an emgency where the owner failed to detect 161 | * a problem with the address submitted. 162 | * @param _airdropper is the account to add to the blacklist and remove from whitelist 163 | * @param _tokenAddress is the token address to add to the blacklist and remove from whitelist 164 | */ 165 | function revokeSubmission(address _airdropper, address _tokenAddress) public onlyAdmin { 166 | if(_tokenAddress != address(0)){ 167 | tokenWhitelist[_tokenAddress] = false; 168 | tokenBlacklist[_tokenAddress] = true; 169 | } 170 | 171 | if(_airdropper != address(0)){ 172 | airdropperBlacklist[_airdropper] = true; 173 | } 174 | 175 | } 176 | 177 | /** 178 | * @dev allows admins to add users to the list manually 179 | * Use to add people who explicitely asked to be added... 180 | */ 181 | function signupUsersManually(address _user) public onlyAdmin { 182 | require(signups[_user].userAddress == address(0)); 183 | signups[_user] = User(_user,now); 184 | userSignupCount++; 185 | 186 | E_Signup(msg.sender,now); 187 | } 188 | 189 | 190 | ///////////////////// 191 | // Airdropper functions 192 | ///////////////////// 193 | 194 | /** 195 | * @dev Transfers tokens to contract and sets the Token Airdrop 196 | * @notice Before calling this function, you must have given the Airdrop Central 197 | * an allowance of the tokens to distribute. 198 | * Call approve([this contract's address],_totalTokensToDistribute); on the ERC20 token cotnract first 199 | * @param _tokenAddress is the address of the token 200 | * @param _totalTokensToDistribute is the tokens that will be evenly distributed among all current users 201 | * Enter the number of tokens (the function multiplies by the token decimals) 202 | * @param _expirationTime is in how many seconds will the airdrop expire from now 203 | * user should first know how many users are signed to know final approximate distribution 204 | */ 205 | function airdropTokens(address _tokenAddress, uint _totalTokensToDistribute, uint _expirationTime) public ifNotPaused { 206 | require(tokenWhitelist[_tokenAddress]); 207 | require(!airdropperBlacklist[msg.sender]); 208 | 209 | ERC20Basic token = ERC20Basic(_tokenAddress); 210 | require(token.balanceOf(msg.sender) >= _totalTokensToDistribute); 211 | 212 | //Multiply number entered by token decimals. 213 | _totalTokensToDistribute = _totalTokensToDistribute.mul(10 ** uint256(token.decimals())); 214 | 215 | // Calculate owner's tokens and tokens to airdrop 216 | uint tokensForOwner = _totalTokensToDistribute.mul(ownersCut).div(100); 217 | _totalTokensToDistribute = _totalTokensToDistribute.sub(tokensForOwner); 218 | 219 | // Store the airdrop unique id in array (token address + id) 220 | TokenAirdropID memory taid = TokenAirdropID(_tokenAddress,airdroppedTokens[_tokenAddress].length); 221 | TokenAirdrop memory ta = TokenAirdrop(_tokenAddress,airdroppedTokens[_tokenAddress].length,msg.sender,now,now+_expirationTime,_totalTokensToDistribute,_totalTokensToDistribute,userSignupCount); 222 | airdroppedTokens[_tokenAddress].push(ta); 223 | airdrops.push(taid); 224 | 225 | // Transfer the tokens 226 | require(token.transferFrom(msg.sender,this,_totalTokensToDistribute)); 227 | require(token.transferFrom(msg.sender,owner,tokensForOwner)); 228 | 229 | E_AirdropSubmitted(_tokenAddress,ta.tokenOwner,ta.totalDropped,ta.airdropDate,ta.airdropExpirationDate); 230 | 231 | } 232 | 233 | /** 234 | * @dev returns unclaimed tokens to the airdropper after the airdrop expires 235 | * @param _tokenAddress is the address of the token 236 | */ 237 | function returnTokensToAirdropper(address _tokenAddress) public ifNotPaused { 238 | require(tokenWhitelist[_tokenAddress]); // Token must be whitelisted first 239 | 240 | // Get the token 241 | ERC20Basic token = ERC20Basic(_tokenAddress); 242 | 243 | uint tokensToReturn = 0; 244 | 245 | for (uint i =0; i= user.signupDate && 312 | now <= ta.airdropExpirationDate){ 313 | 314 | // The user will get a portion of the total tokens airdroped, 315 | // divided by the users at the moment the airdrop was created 316 | uint tokensAvailable = ta.totalDropped.div(ta.usersAtDate); 317 | 318 | // if the user has not alreay withdrawn the tokens, count them 319 | if(_withdrawnBalance < tokensAvailable){ 320 | totalTokensAvailable = totalTokensAvailable.add(tokensAvailable); 321 | 322 | } 323 | } 324 | } 325 | return totalTokensAvailable; 326 | } 327 | 328 | /** 329 | * @dev calculates and withdraws the amount of tokens the user has been awarded by airdrops 330 | * Given a token address, the function checks all airdrops with the same 331 | * address and withdraws the corresponding tokens for the user. 332 | * @param _tokenAddress is the token the user wants to check his balance for 333 | */ 334 | function withdrawTokens(address _tokenAddress) ifNotPaused public { 335 | require(tokenWhitelist[_tokenAddress]); // Token must be whitelisted first 336 | 337 | // Get User instance, given the sender account 338 | User storage user = signups[msg.sender]; 339 | require(user.userAddress != address(0)); 340 | 341 | uint totalTokensToTransfer = 0; 342 | // For each airdrop made for this token (token owner may have done several airdrops at any given point) 343 | for (uint i =0; i= user.signupDate && 351 | now <= ta.airdropExpirationDate){ 352 | 353 | // The user will get a portion of the total tokens airdroped, 354 | // divided by the users at the moment the airdrop was created 355 | uint tokensToTransfer = ta.totalDropped.div(ta.usersAtDate); 356 | 357 | // if the user has not alreay withdrawn the tokens 358 | if(_withdrawnBalance < tokensToTransfer){ 359 | // Register the tokens withdrawn by the user and total tokens withdrawn 360 | user.withdrawnBalances[_tokenAddress][i] = tokensToTransfer; 361 | ta.tokenBalance = ta.tokenBalance.sub(tokensToTransfer); 362 | totalTokensToTransfer = totalTokensToTransfer.add(tokensToTransfer); 363 | 364 | } 365 | } 366 | } 367 | // Get the token 368 | ERC20Basic token = ERC20Basic(_tokenAddress); 369 | // Transfer tokens from all airdrops that correspond to this user 370 | require(token.transfer(msg.sender,totalTokensToTransfer)); 371 | 372 | E_TokensWithdrawn(_tokenAddress,msg.sender,totalTokensToTransfer,now); 373 | } 374 | 375 | function airdropsCount() public view returns (uint){ 376 | return airdrops.length; 377 | } 378 | 379 | function getAddress() public view returns (address){ 380 | return address(this); 381 | } 382 | 383 | function airdropHasExpired(address _tokenAddress, uint _id) public view returns (bool){ 384 | TokenAirdrop storage ta = airdroppedTokens[_tokenAddress][_id]; 385 | return (now > ta.airdropExpirationDate); 386 | } 387 | } 388 | -------------------------------------------------------------------------------- /coverage.json: -------------------------------------------------------------------------------- 1 | {"contracts/AirdropCentral.sol":{"l":{"84":1,"85":1,"89":2,"90":2,"94":7,"95":7,"107":1,"118":0,"127":0,"137":1,"138":1,"140":1,"141":1,"151":1,"152":1,"154":1,"166":1,"167":1,"168":1,"171":1,"172":1,"182":0,"183":0,"184":0,"186":0,"206":3,"207":3,"209":3,"210":3,"213":3,"216":3,"217":3,"220":3,"221":3,"222":3,"223":3,"226":3,"227":3,"229":3,"241":1,"243":1,"245":1,"246":3,"247":3,"250":0,"251":0,"254":1,"255":1,"268":2,"269":2,"270":2,"272":2,"285":0,"286":0,"287":0,"300":0,"301":0,"303":0,"304":0,"305":0,"307":0,"311":0,"316":0,"319":0,"320":0,"325":0,"338":1,"339":1,"341":1,"343":1,"344":3,"346":3,"350":3,"355":3,"358":3,"360":3,"361":3,"362":3,"368":1,"370":1,"372":1,"376":0,"380":0,"384":3,"385":3},"path":"/Users/pabloruiz55/DocumentsBackup/dapps/AirdropCentral/contracts/AirdropCentral.sol","s":{"1":1,"2":2,"3":7,"4":1,"5":0,"6":0,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":1,"18":1,"19":0,"20":0,"21":0,"22":3,"23":3,"24":3,"25":3,"26":3,"27":3,"28":3,"29":3,"30":3,"31":3,"32":3,"33":3,"34":1,"35":1,"36":1,"37":1,"38":3,"39":3,"40":0,"41":0,"42":1,"43":1,"44":2,"45":2,"46":2,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":1,"61":1,"62":1,"63":1,"64":1,"65":3,"66":3,"67":3,"68":3,"69":3,"70":3,"71":3,"72":3,"73":1,"74":1,"75":1,"76":0,"77":0,"78":3,"79":3},"b":{"1":[1,0],"2":[2,0],"3":[7,0],"4":[1,0],"5":[1,0],"6":[1,0],"7":[1,0],"8":[1,0],"9":[1,0],"10":[0,0],"11":[3,0],"12":[3,0],"13":[3,0],"14":[3,0],"15":[3,0],"16":[1,0],"17":[0,3],"18":[1,0],"19":[2,0],"20":[0,0],"21":[0,0],"22":[0,0],"23":[0,0],"24":[0,0],"25":[1,0],"26":[1,0],"27":[3,0],"28":[3,0],"29":[1,0]},"f":{"1":1,"2":2,"3":7,"4":1,"5":0,"6":0,"7":1,"8":1,"9":1,"10":0,"11":3,"12":1,"13":2,"14":0,"15":0,"16":1,"17":0,"18":0,"19":3},"fnMap":{"1":{"name":"onlyOwner","line":83,"loc":{"start":{"line":83,"column":4},"end":{"line":83,"column":20}}},"2":{"name":"onlyAdmin","line":88,"loc":{"start":{"line":88,"column":4},"end":{"line":88,"column":20}}},"3":{"name":"ifNotPaused","line":93,"loc":{"start":{"line":93,"column":4},"end":{"line":93,"column":22}}},"4":{"name":"AirdropCentral","line":106,"loc":{"start":{"line":106,"column":4},"end":{"line":106,"column":34}}},"5":{"name":"setPaused","line":117,"loc":{"start":{"line":117,"column":4},"end":{"line":117,"column":52}}},"6":{"name":"setAdmin","line":126,"loc":{"start":{"line":126,"column":4},"end":{"line":126,"column":65}}},"7":{"name":"removeFromBlacklist","line":136,"loc":{"start":{"line":136,"column":4},"end":{"line":136,"column":91}}},"8":{"name":"approveSubmission","line":150,"loc":{"start":{"line":150,"column":4},"end":{"line":150,"column":89}}},"9":{"name":"revokeSubmission","line":165,"loc":{"start":{"line":165,"column":4},"end":{"line":165,"column":88}}},"10":{"name":"signupUsersManually","line":181,"loc":{"start":{"line":181,"column":4},"end":{"line":181,"column":62}}},"11":{"name":"airdropTokens","line":205,"loc":{"start":{"line":205,"column":4},"end":{"line":205,"column":119}}},"12":{"name":"returnTokensToAirdropper","line":237,"loc":{"start":{"line":237,"column":4},"end":{"line":237,"column":77}}},"13":{"name":"signUpForAirdrops","line":267,"loc":{"start":{"line":267,"column":4},"end":{"line":267,"column":48}}},"14":{"name":"quitFromAirdrops","line":284,"loc":{"start":{"line":284,"column":4},"end":{"line":284,"column":47}}},"15":{"name":"getTokensAvailableToMe","line":296,"loc":{"start":{"line":296,"column":4},"end":{"line":296,"column":82}}},"16":{"name":"withdrawTokens","line":334,"loc":{"start":{"line":334,"column":4},"end":{"line":334,"column":67}}},"17":{"name":"airdropsCount","line":375,"loc":{"start":{"line":375,"column":4},"end":{"line":375,"column":52}}},"18":{"name":"getAddress","line":379,"loc":{"start":{"line":379,"column":4},"end":{"line":379,"column":52}}},"19":{"name":"airdropHasExpired","line":383,"loc":{"start":{"line":383,"column":4},"end":{"line":383,"column":87}}}},"statementMap":{"1":{"start":{"line":84,"column":8},"end":{"line":84,"column":35}},"2":{"start":{"line":89,"column":8},"end":{"line":89,"column":57}},"3":{"start":{"line":94,"column":8},"end":{"line":94,"column":23}},"4":{"start":{"line":107,"column":8},"end":{"line":107,"column":25}},"5":{"start":{"line":118,"column":8},"end":{"line":118,"column":25}},"6":{"start":{"line":127,"column":8},"end":{"line":127,"column":31}},"7":{"start":{"line":137,"column":8},"end":{"line":137,"column":4491}},"8":{"start":{"line":138,"column":12},"end":{"line":138,"column":51}},"9":{"start":{"line":140,"column":8},"end":{"line":140,"column":4581}},"10":{"start":{"line":141,"column":12},"end":{"line":141,"column":48}},"11":{"start":{"line":151,"column":8},"end":{"line":151,"column":49}},"12":{"start":{"line":152,"column":8},"end":{"line":152,"column":46}},"13":{"start":{"line":154,"column":8},"end":{"line":154,"column":43}},"14":{"start":{"line":166,"column":8},"end":{"line":166,"column":5745}},"15":{"start":{"line":167,"column":12},"end":{"line":167,"column":48}},"16":{"start":{"line":168,"column":12},"end":{"line":168,"column":47}},"17":{"start":{"line":171,"column":8},"end":{"line":171,"column":5898}},"18":{"start":{"line":172,"column":12},"end":{"line":172,"column":50}},"19":{"start":{"line":182,"column":8},"end":{"line":182,"column":56}},"20":{"start":{"line":183,"column":8},"end":{"line":183,"column":39}},"21":{"start":{"line":186,"column":8},"end":{"line":186,"column":31}},"22":{"start":{"line":206,"column":8},"end":{"line":206,"column":45}},"23":{"start":{"line":207,"column":8},"end":{"line":207,"column":48}},"24":{"start":{"line":209,"column":8},"end":{"line":209,"column":51}},"25":{"start":{"line":210,"column":8},"end":{"line":210,"column":71}},"26":{"start":{"line":213,"column":8},"end":{"line":213,"column":95}},"27":{"start":{"line":216,"column":8},"end":{"line":216,"column":77}},"28":{"start":{"line":217,"column":8},"end":{"line":217,"column":78}},"29":{"start":{"line":220,"column":8},"end":{"line":220,"column":104}},"30":{"start":{"line":221,"column":8},"end":{"line":221,"column":199}},"31":{"start":{"line":226,"column":8},"end":{"line":226,"column":76}},"32":{"start":{"line":227,"column":8},"end":{"line":227,"column":67}},"33":{"start":{"line":229,"column":8},"end":{"line":229,"column":110}},"34":{"start":{"line":238,"column":8},"end":{"line":238,"column":45}},"35":{"start":{"line":241,"column":8},"end":{"line":241,"column":51}},"36":{"start":{"line":243,"column":8},"end":{"line":243,"column":30}},"37":{"start":{"line":245,"column":8},"end":{"line":245,"column":9136}},"38":{"start":{"line":246,"column":12},"end":{"line":246,"column":71}},"39":{"start":{"line":247,"column":12},"end":{"line":247,"column":9290}},"40":{"start":{"line":250,"column":16},"end":{"line":250,"column":67}},"41":{"start":{"line":251,"column":16},"end":{"line":251,"column":34}},"42":{"start":{"line":254,"column":8},"end":{"line":254,"column":57}},"43":{"start":{"line":255,"column":8},"end":{"line":255,"column":69}},"44":{"start":{"line":268,"column":8},"end":{"line":268,"column":61}},"45":{"start":{"line":269,"column":8},"end":{"line":269,"column":49}},"46":{"start":{"line":272,"column":8},"end":{"line":272,"column":31}},"47":{"start":{"line":285,"column":8},"end":{"line":285,"column":61}},"48":{"start":{"line":297,"column":8},"end":{"line":297,"column":45}},"49":{"start":{"line":300,"column":8},"end":{"line":300,"column":46}},"50":{"start":{"line":301,"column":8},"end":{"line":301,"column":46}},"51":{"start":{"line":303,"column":8},"end":{"line":303,"column":35}},"52":{"start":{"line":304,"column":8},"end":{"line":304,"column":11550}},"53":{"start":{"line":305,"column":12},"end":{"line":305,"column":71}},"54":{"start":{"line":307,"column":12},"end":{"line":307,"column":76}},"55":{"start":{"line":311,"column":12},"end":{"line":311,"column":11942}},"56":{"start":{"line":316,"column":16},"end":{"line":316,"column":73}},"57":{"start":{"line":319,"column":16},"end":{"line":319,"column":12365}},"58":{"start":{"line":320,"column":20},"end":{"line":320,"column":83}},"59":{"start":{"line":325,"column":8},"end":{"line":325,"column":35}},"60":{"start":{"line":335,"column":8},"end":{"line":335,"column":45}},"61":{"start":{"line":338,"column":8},"end":{"line":338,"column":46}},"62":{"start":{"line":339,"column":8},"end":{"line":339,"column":46}},"63":{"start":{"line":341,"column":8},"end":{"line":341,"column":37}},"64":{"start":{"line":343,"column":8},"end":{"line":343,"column":13379}},"65":{"start":{"line":344,"column":12},"end":{"line":344,"column":71}},"66":{"start":{"line":346,"column":12},"end":{"line":346,"column":76}},"67":{"start":{"line":350,"column":12},"end":{"line":350,"column":13771}},"68":{"start":{"line":355,"column":16},"end":{"line":355,"column":74}},"69":{"start":{"line":358,"column":16},"end":{"line":358,"column":14183}},"70":{"start":{"line":360,"column":20},"end":{"line":360,"column":78}},"71":{"start":{"line":361,"column":20},"end":{"line":361,"column":74}},"72":{"start":{"line":362,"column":20},"end":{"line":362,"column":86}},"73":{"start":{"line":368,"column":8},"end":{"line":368,"column":51}},"74":{"start":{"line":370,"column":8},"end":{"line":370,"column":64}},"75":{"start":{"line":372,"column":8},"end":{"line":372,"column":76}},"76":{"start":{"line":376,"column":8},"end":{"line":376,"column":30}},"77":{"start":{"line":380,"column":6},"end":{"line":380,"column":26}},"78":{"start":{"line":384,"column":8},"end":{"line":384,"column":69}},"79":{"start":{"line":385,"column":8},"end":{"line":385,"column":47}}},"branchMap":{"1":{"line":84,"type":"if","locations":[{"start":{"line":84,"column":8},"end":{"line":84,"column":8}},{"start":{"line":84,"column":8},"end":{"line":84,"column":8}}]},"2":{"line":89,"type":"if","locations":[{"start":{"line":89,"column":8},"end":{"line":89,"column":8}},{"start":{"line":89,"column":8},"end":{"line":89,"column":8}}]},"3":{"line":94,"type":"if","locations":[{"start":{"line":94,"column":8},"end":{"line":94,"column":8}},{"start":{"line":94,"column":8},"end":{"line":94,"column":8}}]},"4":{"line":137,"type":"if","locations":[{"start":{"line":137,"column":8},"end":{"line":137,"column":8}},{"start":{"line":137,"column":8},"end":{"line":137,"column":8}}]},"5":{"line":140,"type":"if","locations":[{"start":{"line":140,"column":8},"end":{"line":140,"column":8}},{"start":{"line":140,"column":8},"end":{"line":140,"column":8}}]},"6":{"line":151,"type":"if","locations":[{"start":{"line":151,"column":8},"end":{"line":151,"column":8}},{"start":{"line":151,"column":8},"end":{"line":151,"column":8}}]},"7":{"line":152,"type":"if","locations":[{"start":{"line":152,"column":8},"end":{"line":152,"column":8}},{"start":{"line":152,"column":8},"end":{"line":152,"column":8}}]},"8":{"line":166,"type":"if","locations":[{"start":{"line":166,"column":8},"end":{"line":166,"column":8}},{"start":{"line":166,"column":8},"end":{"line":166,"column":8}}]},"9":{"line":171,"type":"if","locations":[{"start":{"line":171,"column":8},"end":{"line":171,"column":8}},{"start":{"line":171,"column":8},"end":{"line":171,"column":8}}]},"10":{"line":182,"type":"if","locations":[{"start":{"line":182,"column":8},"end":{"line":182,"column":8}},{"start":{"line":182,"column":8},"end":{"line":182,"column":8}}]},"11":{"line":206,"type":"if","locations":[{"start":{"line":206,"column":8},"end":{"line":206,"column":8}},{"start":{"line":206,"column":8},"end":{"line":206,"column":8}}]},"12":{"line":207,"type":"if","locations":[{"start":{"line":207,"column":8},"end":{"line":207,"column":8}},{"start":{"line":207,"column":8},"end":{"line":207,"column":8}}]},"13":{"line":210,"type":"if","locations":[{"start":{"line":210,"column":8},"end":{"line":210,"column":8}},{"start":{"line":210,"column":8},"end":{"line":210,"column":8}}]},"14":{"line":226,"type":"if","locations":[{"start":{"line":226,"column":8},"end":{"line":226,"column":8}},{"start":{"line":226,"column":8},"end":{"line":226,"column":8}}]},"15":{"line":227,"type":"if","locations":[{"start":{"line":227,"column":8},"end":{"line":227,"column":8}},{"start":{"line":227,"column":8},"end":{"line":227,"column":8}}]},"16":{"line":238,"type":"if","locations":[{"start":{"line":238,"column":8},"end":{"line":238,"column":8}},{"start":{"line":238,"column":8},"end":{"line":238,"column":8}}]},"17":{"line":247,"type":"if","locations":[{"start":{"line":247,"column":12},"end":{"line":247,"column":12}},{"start":{"line":247,"column":12},"end":{"line":247,"column":12}}]},"18":{"line":254,"type":"if","locations":[{"start":{"line":254,"column":8},"end":{"line":254,"column":8}},{"start":{"line":254,"column":8},"end":{"line":254,"column":8}}]},"19":{"line":268,"type":"if","locations":[{"start":{"line":268,"column":8},"end":{"line":268,"column":8}},{"start":{"line":268,"column":8},"end":{"line":268,"column":8}}]},"20":{"line":285,"type":"if","locations":[{"start":{"line":285,"column":8},"end":{"line":285,"column":8}},{"start":{"line":285,"column":8},"end":{"line":285,"column":8}}]},"21":{"line":297,"type":"if","locations":[{"start":{"line":297,"column":8},"end":{"line":297,"column":8}},{"start":{"line":297,"column":8},"end":{"line":297,"column":8}}]},"22":{"line":301,"type":"if","locations":[{"start":{"line":301,"column":8},"end":{"line":301,"column":8}},{"start":{"line":301,"column":8},"end":{"line":301,"column":8}}]},"23":{"line":311,"type":"if","locations":[{"start":{"line":311,"column":12},"end":{"line":311,"column":12}},{"start":{"line":311,"column":12},"end":{"line":311,"column":12}}]},"24":{"line":319,"type":"if","locations":[{"start":{"line":319,"column":16},"end":{"line":319,"column":16}},{"start":{"line":319,"column":16},"end":{"line":319,"column":16}}]},"25":{"line":335,"type":"if","locations":[{"start":{"line":335,"column":8},"end":{"line":335,"column":8}},{"start":{"line":335,"column":8},"end":{"line":335,"column":8}}]},"26":{"line":339,"type":"if","locations":[{"start":{"line":339,"column":8},"end":{"line":339,"column":8}},{"start":{"line":339,"column":8},"end":{"line":339,"column":8}}]},"27":{"line":350,"type":"if","locations":[{"start":{"line":350,"column":12},"end":{"line":350,"column":12}},{"start":{"line":350,"column":12},"end":{"line":350,"column":12}}]},"28":{"line":358,"type":"if","locations":[{"start":{"line":358,"column":16},"end":{"line":358,"column":16}},{"start":{"line":358,"column":16},"end":{"line":358,"column":16}}]},"29":{"line":370,"type":"if","locations":[{"start":{"line":370,"column":8},"end":{"line":370,"column":8}},{"start":{"line":370,"column":8},"end":{"line":370,"column":8}}]}}},"contracts/ERC20Basic.sol":{"l":{"17":2,"18":2,"21":2,"22":2,"23":2,"24":2,"34":6,"35":6,"36":6,"38":6,"39":6,"40":6,"41":6,"42":6,"56":1,"57":1,"58":1,"68":0,"72":6,"76":2,"77":2,"78":2,"79":2,"83":0,"93":6,"94":0,"96":6,"97":6,"98":6,"103":6,"105":6,"109":20,"110":20,"114":11,"115":11,"116":11},"path":"/Users/pabloruiz55/DocumentsBackup/dapps/AirdropCentral/contracts/ERC20Basic.sol","s":{"1":2,"2":2,"3":2,"4":2,"5":2,"6":2,"7":6,"8":6,"9":6,"10":6,"11":6,"12":6,"13":6,"14":6,"15":1,"16":1,"17":1,"18":0,"19":6,"20":2,"21":2,"22":2,"23":2,"24":0,"25":6,"26":0,"27":6,"28":6,"29":6,"30":6,"31":6,"32":20,"33":20,"34":11,"35":11,"36":11},"b":{"1":[2,0],"2":[2,0],"3":[6,0],"4":[6,0],"5":[6,0],"6":[0,6],"7":[6,0],"8":[20,0],"9":[11,0]},"f":{"1":2,"2":6,"3":1,"4":0,"5":6,"6":2,"7":0,"8":6,"9":6,"10":20,"11":11},"fnMap":{"1":{"name":"transfer","line":16,"loc":{"start":{"line":16,"column":2},"end":{"line":16,"column":70}}},"2":{"name":"transferFrom","line":33,"loc":{"start":{"line":33,"column":2},"end":{"line":33,"column":89}}},"3":{"name":"approve","line":55,"loc":{"start":{"line":55,"column":2},"end":{"line":55,"column":74}}},"4":{"name":"allowance","line":67,"loc":{"start":{"line":67,"column":2},"end":{"line":67,"column":84}}},"5":{"name":"balanceOf","line":71,"loc":{"start":{"line":71,"column":2},"end":{"line":71,"column":74}}},"6":{"name":"ERC20Basic","line":75,"loc":{"start":{"line":75,"column":2},"end":{"line":75,"column":58}}},"7":{"name":"getAddress","line":82,"loc":{"start":{"line":82,"column":2},"end":{"line":82,"column":52}}},"8":{"name":"mul","line":92,"loc":{"start":{"line":92,"column":2},"end":{"line":92,"column":68}}},"9":{"name":"div","line":101,"loc":{"start":{"line":101,"column":2},"end":{"line":101,"column":68}}},"10":{"name":"sub","line":108,"loc":{"start":{"line":108,"column":2},"end":{"line":108,"column":68}}},"11":{"name":"add","line":113,"loc":{"start":{"line":113,"column":2},"end":{"line":113,"column":68}}}},"statementMap":{"1":{"start":{"line":17,"column":4},"end":{"line":17,"column":29}},"2":{"start":{"line":18,"column":4},"end":{"line":18,"column":42}},"3":{"start":{"line":21,"column":4},"end":{"line":21,"column":58}},"4":{"start":{"line":22,"column":4},"end":{"line":22,"column":44}},"5":{"start":{"line":23,"column":4},"end":{"line":23,"column":36}},"6":{"start":{"line":24,"column":4},"end":{"line":24,"column":15}},"7":{"start":{"line":34,"column":4},"end":{"line":34,"column":29}},"8":{"start":{"line":35,"column":4},"end":{"line":35,"column":37}},"9":{"start":{"line":36,"column":4},"end":{"line":36,"column":48}},"10":{"start":{"line":38,"column":4},"end":{"line":38,"column":48}},"11":{"start":{"line":39,"column":4},"end":{"line":39,"column":44}},"12":{"start":{"line":40,"column":4},"end":{"line":40,"column":70}},"13":{"start":{"line":41,"column":4},"end":{"line":41,"column":31}},"14":{"start":{"line":42,"column":4},"end":{"line":42,"column":15}},"15":{"start":{"line":56,"column":4},"end":{"line":56,"column":41}},"16":{"start":{"line":57,"column":4},"end":{"line":57,"column":41}},"17":{"start":{"line":58,"column":4},"end":{"line":58,"column":15}},"18":{"start":{"line":68,"column":4},"end":{"line":68,"column":36}},"19":{"start":{"line":72,"column":4},"end":{"line":72,"column":27}},"20":{"start":{"line":76,"column":4},"end":{"line":76,"column":46}},"21":{"start":{"line":77,"column":4},"end":{"line":77,"column":37}},"22":{"start":{"line":78,"column":4},"end":{"line":78,"column":13}},"23":{"start":{"line":79,"column":4},"end":{"line":79,"column":19}},"24":{"start":{"line":83,"column":6},"end":{"line":83,"column":26}},"25":{"start":{"line":93,"column":4},"end":{"line":93,"column":3383}},"26":{"start":{"line":94,"column":6},"end":{"line":94,"column":14}},"27":{"start":{"line":96,"column":4},"end":{"line":96,"column":20}},"28":{"start":{"line":97,"column":4},"end":{"line":97,"column":21}},"29":{"start":{"line":98,"column":4},"end":{"line":98,"column":12}},"30":{"start":{"line":103,"column":4},"end":{"line":103,"column":20}},"31":{"start":{"line":105,"column":4},"end":{"line":105,"column":12}},"32":{"start":{"line":109,"column":4},"end":{"line":109,"column":17}},"33":{"start":{"line":110,"column":4},"end":{"line":110,"column":16}},"34":{"start":{"line":114,"column":4},"end":{"line":114,"column":20}},"35":{"start":{"line":115,"column":4},"end":{"line":115,"column":17}},"36":{"start":{"line":116,"column":4},"end":{"line":116,"column":12}}},"branchMap":{"1":{"line":17,"type":"if","locations":[{"start":{"line":17,"column":4},"end":{"line":17,"column":4}},{"start":{"line":17,"column":4},"end":{"line":17,"column":4}}]},"2":{"line":18,"type":"if","locations":[{"start":{"line":18,"column":4},"end":{"line":18,"column":4}},{"start":{"line":18,"column":4},"end":{"line":18,"column":4}}]},"3":{"line":34,"type":"if","locations":[{"start":{"line":34,"column":4},"end":{"line":34,"column":4}},{"start":{"line":34,"column":4},"end":{"line":34,"column":4}}]},"4":{"line":35,"type":"if","locations":[{"start":{"line":35,"column":4},"end":{"line":35,"column":4}},{"start":{"line":35,"column":4},"end":{"line":35,"column":4}}]},"5":{"line":36,"type":"if","locations":[{"start":{"line":36,"column":4},"end":{"line":36,"column":4}},{"start":{"line":36,"column":4},"end":{"line":36,"column":4}}]},"6":{"line":93,"type":"if","locations":[{"start":{"line":93,"column":4},"end":{"line":93,"column":4}},{"start":{"line":93,"column":4},"end":{"line":93,"column":4}}]},"7":{"line":97,"type":"if","locations":[{"start":{"line":97,"column":4},"end":{"line":97,"column":4}},{"start":{"line":97,"column":4},"end":{"line":97,"column":4}}]},"8":{"line":109,"type":"if","locations":[{"start":{"line":109,"column":4},"end":{"line":109,"column":4}},{"start":{"line":109,"column":4},"end":{"line":109,"column":4}}]},"9":{"line":115,"type":"if","locations":[{"start":{"line":115,"column":4},"end":{"line":115,"column":4}},{"start":{"line":115,"column":4},"end":{"line":115,"column":4}}]}}}} -------------------------------------------------------------------------------- /coverage/contracts/AirdropCentral.sol.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for contracts/AirdropCentral.sol 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / contracts/ AirdropCentral.sol 20 |

21 |
22 |
23 | 72.15% 24 | Statements 25 | 57/79 26 |
27 |
28 | 39.66% 29 | Branches 30 | 23/58 31 |
32 |
33 | 63.16% 34 | Functions 35 | 12/19 36 |
37 |
38 | 71.76% 39 | Lines 40 | 61/85 41 |
42 |
43 |
44 |
45 |

  46 | 
1208 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 | 39 85 | 40 86 | 41 87 | 42 88 | 43 89 | 44 90 | 45 91 | 46 92 | 47 93 | 48 94 | 49 95 | 50 96 | 51 97 | 52 98 | 53 99 | 54 100 | 55 101 | 56 102 | 57 103 | 58 104 | 59 105 | 60 106 | 61 107 | 62 108 | 63 109 | 64 110 | 65 111 | 66 112 | 67 113 | 68 114 | 69 115 | 70 116 | 71 117 | 72 118 | 73 119 | 74 120 | 75 121 | 76 122 | 77 123 | 78 124 | 79 125 | 80 126 | 81 127 | 82 128 | 83 129 | 84 130 | 85 131 | 86 132 | 87 133 | 88 134 | 89 135 | 90 136 | 91 137 | 92 138 | 93 139 | 94 140 | 95 141 | 96 142 | 97 143 | 98 144 | 99 145 | 100 146 | 101 147 | 102 148 | 103 149 | 104 150 | 105 151 | 106 152 | 107 153 | 108 154 | 109 155 | 110 156 | 111 157 | 112 158 | 113 159 | 114 160 | 115 161 | 116 162 | 117 163 | 118 164 | 119 165 | 120 166 | 121 167 | 122 168 | 123 169 | 124 170 | 125 171 | 126 172 | 127 173 | 128 174 | 129 175 | 130 176 | 131 177 | 132 178 | 133 179 | 134 180 | 135 181 | 136 182 | 137 183 | 138 184 | 139 185 | 140 186 | 141 187 | 142 188 | 143 189 | 144 190 | 145 191 | 146 192 | 147 193 | 148 194 | 149 195 | 150 196 | 151 197 | 152 198 | 153 199 | 154 200 | 155 201 | 156 202 | 157 203 | 158 204 | 159 205 | 160 206 | 161 207 | 162 208 | 163 209 | 164 210 | 165 211 | 166 212 | 167 213 | 168 214 | 169 215 | 170 216 | 171 217 | 172 218 | 173 219 | 174 220 | 175 221 | 176 222 | 177 223 | 178 224 | 179 225 | 180 226 | 181 227 | 182 228 | 183 229 | 184 230 | 185 231 | 186 232 | 187 233 | 188 234 | 189 235 | 190 236 | 191 237 | 192 238 | 193 239 | 194 240 | 195 241 | 196 242 | 197 243 | 198 244 | 199 245 | 200 246 | 201 247 | 202 248 | 203 249 | 204 250 | 205 251 | 206 252 | 207 253 | 208 254 | 209 255 | 210 256 | 211 257 | 212 258 | 213 259 | 214 260 | 215 261 | 216 262 | 217 263 | 218 264 | 219 265 | 220 266 | 221 267 | 222 268 | 223 269 | 224 270 | 225 271 | 226 272 | 227 273 | 228 274 | 229 275 | 230 276 | 231 277 | 232 278 | 233 279 | 234 280 | 235 281 | 236 282 | 237 283 | 238 284 | 239 285 | 240 286 | 241 287 | 242 288 | 243 289 | 244 290 | 245 291 | 246 292 | 247 293 | 248 294 | 249 295 | 250 296 | 251 297 | 252 298 | 253 299 | 254 300 | 255 301 | 256 302 | 257 303 | 258 304 | 259 305 | 260 306 | 261 307 | 262 308 | 263 309 | 264 310 | 265 311 | 266 312 | 267 313 | 268 314 | 269 315 | 270 316 | 271 317 | 272 318 | 273 319 | 274 320 | 275 321 | 276 322 | 277 323 | 278 324 | 279 325 | 280 326 | 281 327 | 282 328 | 283 329 | 284 330 | 285 331 | 286 332 | 287 333 | 288 334 | 289 335 | 290 336 | 291 337 | 292 338 | 293 339 | 294 340 | 295 341 | 296 342 | 297 343 | 298 344 | 299 345 | 300 346 | 301 347 | 302 348 | 303 349 | 304 350 | 305 351 | 306 352 | 307 353 | 308 354 | 309 355 | 310 356 | 311 357 | 312 358 | 313 359 | 314 360 | 315 361 | 316 362 | 317 363 | 318 364 | 319 365 | 320 366 | 321 367 | 322 368 | 323 369 | 324 370 | 325 371 | 326 372 | 327 373 | 328 374 | 329 375 | 330 376 | 331 377 | 332 378 | 333 379 | 334 380 | 335 381 | 336 382 | 337 383 | 338 384 | 339 385 | 340 386 | 341 387 | 342 388 | 343 389 | 344 390 | 345 391 | 346 392 | 347 393 | 348 394 | 349 395 | 350 396 | 351 397 | 352 398 | 353 399 | 354 400 | 355 401 | 356 402 | 357 403 | 358 404 | 359 405 | 360 406 | 361 407 | 362 408 | 363 409 | 364 410 | 365 411 | 366 412 | 367 413 | 368 414 | 369 415 | 370 416 | 371 417 | 372 418 | 373 419 | 374 420 | 375 421 | 376 422 | 377 423 | 378 424 | 379 425 | 380 426 | 381 427 | 382 428 | 383 429 | 384 430 | 385 431 | 386 432 | 387 433 | 388  434 |   435 |   436 |   437 |   438 |   439 |   440 |   441 |   442 |   443 |   444 |   445 |   446 |   447 |   448 |   449 |   450 |   451 |   452 |   453 |   454 |   455 |   456 |   457 |   458 |   459 |   460 |   461 |   462 |   463 |   464 |   465 |   466 |   467 |   468 |   469 |   470 |   471 |   472 |   473 |   474 |   475 |   476 |   477 |   478 |   479 |   480 |   481 |   482 |   483 |   484 |   485 |   486 |   487 |   488 |   489 |   490 |   491 |   492 |   493 |   494 |   495 |   496 |   497 |   498 |   499 |   500 |   501 |   502 |   503 |   504 |   505 |   506 |   507 |   508 |   509 |   510 |   511 |   512 |   513 |   514 |   515 |   516 | 517 | 518 |   519 |   520 |   521 | 522 | 523 |   524 |   525 |   526 | 527 | 528 |   529 |   530 |   531 |   532 |   533 |   534 |   535 |   536 |   537 |   538 |   539 | 540 |   541 |   542 |   543 |   544 |   545 |   546 |   547 |   548 |   549 |   550 |   551 |   552 |   553 |   554 |   555 |   556 |   557 |   558 |   559 |   560 |   561 |   562 |   563 |   564 |   565 |   566 |   567 |   568 |   569 | 570 | 571 |   572 | 573 | 574 |   575 |   576 |   577 |   578 |   579 |   580 |   581 |   582 |   583 | 584 | 585 |   586 | 587 |   588 |   589 |   590 |   591 |   592 |   593 |   594 |   595 |   596 |   597 |   598 | 599 | 600 | 601 |   602 |   603 | 604 | 605 |   606 |   607 |   608 |   609 |   610 |   611 |   612 |   613 |   614 |   615 |   616 |   617 |   618 |   619 |   620 |   621 |   622 |   623 |   624 |   625 |   626 |   627 |   628 |   629 |   630 |   631 |   632 |   633 |   634 |   635 |   636 |   637 |   638 | 639 | 640 |   641 | 642 | 643 |   644 |   645 | 646 |   647 |   648 | 649 | 650 |   651 |   652 | 653 | 654 | 655 | 656 |   657 |   658 | 659 | 660 |   661 | 662 |   663 |   664 |   665 |   666 |   667 |   668 |   669 |   670 |   671 |   672 |   673 | 674 |   675 | 676 |   677 | 678 | 679 | 680 |   681 |   682 |   683 |   684 |   685 |   686 | 687 | 688 |   689 |   690 |   691 |   692 |   693 |   694 |   695 |   696 |   697 |   698 |   699 |   700 | 701 | 702 | 703 |   704 | 705 |   706 |   707 |   708 |   709 |   710 |   711 |   712 |   713 |   714 |   715 |   716 |   717 |   718 |   719 |   720 |   721 |   722 |   723 |   724 |   725 |   726 |   727 |   728 |   729 |   730 |   731 |   732 |   733 |   734 |   735 |   736 |   737 |   738 |   739 |   740 |   741 |   742 |   743 |   744 |   745 |   746 |   747 |   748 |   749 |   750 |   751 |   752 |   753 |   754 |   755 |   756 |   757 |   758 |   759 |   760 |   761 |   762 |   763 |   764 |   765 |   766 |   767 |   768 |   769 |   770 | 771 | 772 |   773 | 774 |   775 | 776 | 777 |   778 | 779 |   780 |   781 |   782 | 783 |   784 |   785 |   786 |   787 | 788 |   789 |   790 | 791 |   792 | 793 | 794 | 795 |   796 |   797 |   798 |   799 |   800 | 801 |   802 | 803 |   804 | 805 |   806 |   807 |   808 |   809 |   810 |   811 |   812 |   813 |   814 |   815 |   816 | 817 | 818 |   819 |   820 |  
pragma solidity 0.4.18;
 821 |  
 822 | import './ERC20Basic.sol';
 823 |  
 824 | /// @author Pablo Ruiz <me@pabloruiz.co>
 825 | /// @Title Airdrop Central - To submit your token follow the instructions at:
 826 | /// https://github.com/pabloruiz55/AirdropCentral
 827 |  
 828 | //////////////////
 829 |  
 830 | //
 831 | // Permissions
 832 | //                               Admin      Airdropper       User
 833 | // approve/ revoke submissions     x
 834 | // pause / unpause                 x
 835 | // signupUsersManually             x
 836 | // airdropTokens                                x
 837 | // returnTokensToAirdropper                     x
 838 | // signUpForAirdrops                                          x
 839 | // quitFromAirdrops                                           x
 840 | // getTokensAvailableToMe                                     x
 841 | // withdrawTokens                                             x
 842 |  
 843 | ////////
 844 |  
 845 | contract AirdropCentral {
 846 |     using SafeMath for uint256;
 847 |  
 848 |     // The owner / admin of the Airdrop Central
 849 |     // In charge of accepting airdrop submissions
 850 |     address public owner;
 851 |  
 852 |     // How many tokens the owner keeps of each airdrop as transaction fee
 853 |     uint public ownersCut = 2; // 2% commision in tokens
 854 |  
 855 |     // Id of each airdrop (token address + id #)
 856 |     struct TokenAirdropID {
 857 |         address tokenAddress;
 858 |         uint airdropAddressID; // The id of the airdrop within a token address
 859 |     }
 860 |  
 861 |     struct TokenAirdrop {
 862 |         address tokenAddress;
 863 |         uint airdropAddressID; // The id of the airdrop within a token address
 864 |         address tokenOwner;
 865 |         uint airdropDate; // The airdrop creation date
 866 |         uint airdropExpirationDate; // When airdrop expires
 867 |         uint tokenBalance; // Current balance
 868 |         uint totalDropped; // Total to distribute
 869 |         uint usersAtDate; // How many users were signed at airdrop date
 870 |     }
 871 |  
 872 |     struct User {
 873 |         address userAddress;
 874 |         uint signupDate; // Determines which airdrops the user has access to
 875 |         // User -> Airdrop id# -> balance
 876 |         mapping (address => mapping (uint => uint)) withdrawnBalances;
 877 |     }
 878 |  
 879 |     // Maps the tokens available to airdrop central contract. Keyed by token address
 880 |     mapping (address => TokenAirdrop[]) public airdroppedTokens;
 881 |     TokenAirdropID[] public airdrops;
 882 |  
 883 |     // List of users that signed up
 884 |     mapping (address => User) public signups;
 885 |     uint public userSignupCount = 0;
 886 |  
 887 |     // Admins with permission to accept submissions
 888 |     mapping (address => bool) admins;
 889 |  
 890 |     // Whether or not the contract is paused (in case of a problem is detected)
 891 |     bool public paused = false;
 892 |  
 893 |     // List of approved/rejected token/sender addresses
 894 |     mapping (address => bool) public tokenWhitelist;
 895 |     mapping (address => bool) public tokenBlacklist;
 896 |     mapping (address => bool) public airdropperBlacklist;
 897 |  
 898 |     //
 899 |     // Modifiers
 900 |     //
 901 |  
 902 |     modifier onlyOwner {
 903 |         Erequire(msg.sender == owner);
 904 |         _;
 905 |     }
 906 |  
 907 |     modifier onlyAdmin {
 908 |         Erequire(msg.sender == owner || admins[msg.sender]);
 909 |         _;
 910 |     }
 911 |  
 912 |     modifier ifNotPaused {
 913 |         Erequire(!paused);
 914 |         _;
 915 |     }
 916 |  
 917 |     //
 918 |     // Events
 919 |     //
 920 |  
 921 |     event E_AirdropSubmitted(address _tokenAddress, address _airdropper,uint _totalTokensToDistribute,uint creationDate, uint _expirationDate);
 922 |     event E_Signup(address _userAddress,uint _signupDate);
 923 |     event E_TokensWithdrawn(address _tokenAddress,address _userAddress, uint _tokensWithdrawn, uint _withdrawalDate);
 924 |  
 925 |     function AirdropCentral() public {
 926 |         owner = msg.sender;
 927 |     }
 928 |  
 929 |     /////////////////////
 930 |     // Owner / Admin functions
 931 |     /////////////////////
 932 |  
 933 |     /**
 934 |      * @dev pause or unpause the contract in case a problem is detected
 935 |      */
 936 |     function setPaused(bool _isPaused) public onlyOwner{
 937 |         paused = _isPaused;
 938 |     }
 939 |  
 940 |     /**
 941 |      * @dev allows owner to grant/revoke admin privileges to other accounts
 942 |      * @param _admin is the account to be granted/revoked admin privileges
 943 |      * @param isAdmin is whether or not to grant or revoke privileges.
 944 |      */
 945 |     function setAdmin(address _admin, bool isAdmin) public onlyOwner{
 946 |         admins[_admin] = isAdmin;
 947 |     }
 948 |  
 949 |     /**
 950 |      * @dev removes a token and/or account from the blacklist to allow
 951 |      * them to submit a token again.
 952 |      * @param _airdropper is the account to remove from blacklist
 953 |      * @param _tokenAddress is the token address to remove from blacklist
 954 |      */
 955 |     function removeFromBlacklist(address _airdropper, address _tokenAddress) public onlyOwner {
 956 |         Eif(_airdropper != address(0))
 957 |             airdropperBlacklist[_airdropper] = false;
 958 |  
 959 |         Eif(_tokenAddress != address(0))
 960 |             tokenBlacklist[_tokenAddress] = false;
 961 |     }
 962 |  
 963 |     /**
 964 |      * @dev approves a given token and account address to make it available for airdrop
 965 |      * This is necessary to avoid malicious contracts to be added.
 966 |      * @param _airdropper is the account to add to the whitelist
 967 |      * @param _tokenAddress is the token address to add to the whitelist
 968 |      */
 969 |     function approveSubmission(address _airdropper, address _tokenAddress) public onlyAdmin {
 970 |         Erequire(!airdropperBlacklist[_airdropper]);
 971 |         Erequire(!tokenBlacklist[_tokenAddress]);
 972 |  
 973 |         tokenWhitelist[_tokenAddress] = true;
 974 |     }
 975 |  
 976 |     /**
 977 |      * @dev removes token and airdropper from whitelist.
 978 |      * Also adds them to a blacklist to prevent further submissions of any
 979 |      * To be used in case of an emgency where the owner failed to detect
 980 |      * a problem with the address submitted.
 981 |      * @param _airdropper is the account to add to the blacklist and remove from whitelist
 982 |      * @param _tokenAddress is the token address to add to the blacklist and remove from whitelist
 983 |      */
 984 |     function revokeSubmission(address _airdropper, address _tokenAddress) public onlyAdmin {
 985 |         Eif(_tokenAddress != address(0)){
 986 |             tokenWhitelist[_tokenAddress] = false;
 987 |             tokenBlacklist[_tokenAddress] = true;
 988 |         }
 989 |  
 990 |         Eif(_airdropper != address(0)){
 991 |             airdropperBlacklist[_airdropper] = true;
 992 |         }
 993 |  
 994 |     }
 995 |  
 996 |     /**
 997 |      * @dev allows admins to add users to the list manually
 998 |      * Use to add people who explicitely asked to be added...
 999 |      */
1000 |     function signupUsersManually(address _user) public onlyAdmin {
1001 |         require(signups[_user].userAddress == address(0));
1002 |         signups[_user] = User(_user,now);
1003 |         userSignupCount++;
1004 |  
1005 |         E_Signup(msg.sender,now);
1006 |     }
1007 |  
1008 |  
1009 |     /////////////////////
1010 |     // Airdropper functions
1011 |     /////////////////////
1012 |  
1013 |     /**
1014 |      * @dev Transfers tokens to contract and sets the Token Airdrop
1015 |      * @notice Before calling this function, you must have given the Airdrop Central
1016 |      * an allowance of the tokens to distribute.
1017 |      * Call approve([this contract's address],_totalTokensToDistribute); on the ERC20 token cotnract first
1018 |      * @param _tokenAddress is the address of the token
1019 |      * @param _totalTokensToDistribute is the tokens that will be evenly distributed among all current users
1020 |      * Enter the number of tokens (the function multiplies by the token decimals)
1021 |      * @param _expirationTime is in how many seconds will the airdrop expire from now
1022 |      * user should first know how many users are signed to know final approximate distribution
1023 |      */
1024 |     function airdropTokens(address _tokenAddress, uint _totalTokensToDistribute, uint _expirationTime) public ifNotPaused {
1025 |         Erequire(tokenWhitelist[_tokenAddress]);
1026 |         Erequire(!airdropperBlacklist[msg.sender]);
1027 |  
1028 |         ERC20Basic token = ERC20Basic(_tokenAddress);
1029 |         Erequire(token.balanceOf(msg.sender) >= _totalTokensToDistribute);
1030 |  
1031 |         //Multiply number entered by token decimals.
1032 |         _totalTokensToDistribute = _totalTokensToDistribute.mul(10 ** uint256(token.decimals()));
1033 |  
1034 |         // Calculate owner's tokens and tokens to airdrop
1035 |         uint tokensForOwner = _totalTokensToDistribute.mul(ownersCut).div(100);
1036 |         _totalTokensToDistribute = _totalTokensToDistribute.sub(tokensForOwner);
1037 |  
1038 |         // Store the airdrop unique id in array (token address + id)
1039 |         TokenAirdropID memory taid = TokenAirdropID(_tokenAddress,airdroppedTokens[_tokenAddress].length);
1040 |         TokenAirdrop memory ta = TokenAirdrop(_tokenAddress,airdroppedTokens[_tokenAddress].length,msg.sender,now,now+_expirationTime,_totalTokensToDistribute,_totalTokensToDistribute,userSignupCount);
1041 |         airdroppedTokens[_tokenAddress].push(ta);
1042 |         airdrops.push(taid);
1043 |  
1044 |         // Transfer the tokens
1045 |         Erequire(token.transferFrom(msg.sender,this,_totalTokensToDistribute));
1046 |         Erequire(token.transferFrom(msg.sender,owner,tokensForOwner));
1047 |  
1048 |         E_AirdropSubmitted(_tokenAddress,ta.tokenOwner,ta.totalDropped,ta.airdropDate,ta.airdropExpirationDate);
1049 |  
1050 |     }
1051 |  
1052 |     /**
1053 |      * @dev returns unclaimed tokens to the airdropper after the airdrop expires
1054 |      * @param _tokenAddress is the address of the token
1055 |      */
1056 |     function returnTokensToAirdropper(address _tokenAddress) public ifNotPaused {
1057 |         Erequire(tokenWhitelist[_tokenAddress]); // Token must be whitelisted first
1058 |  
1059 |         // Get the token
1060 |         ERC20Basic token = ERC20Basic(_tokenAddress);
1061 |  
1062 |         uint tokensToReturn = 0;
1063 |  
1064 |         for (uint i =0; i<airdroppedTokens[_tokenAddress].length; i++){
1065 |             TokenAirdrop storage ta = airdroppedTokens[_tokenAddress][i];
1066 |             Iif(msg.sender == ta.tokenOwner &&
1067 |                 airdropHasExpired(_tokenAddress,i)){
1068 |  
1069 |                 tokensToReturn = tokensToReturn.add(ta.tokenBalance);
1070 |                 ta.tokenBalance = 0;
1071 |             }
1072 |         }
1073 |         Erequire(token.transfer(msg.sender,tokensToReturn));
1074 |         E_TokensWithdrawn(_tokenAddress,msg.sender,tokensToReturn,now);
1075 |  
1076 |     }
1077 |  
1078 |     /////////////////////
1079 |     // User functions
1080 |     /////////////////////
1081 |  
1082 |     /**
1083 |      * @dev user can signup to the Airdrop Central to receive token airdrops
1084 |      * Airdrops made before the user registration won't be available to them.
1085 |      */
1086 |     function signUpForAirdrops() public ifNotPaused{
1087 |         Erequire(signups[msg.sender].userAddress == address(0));
1088 |         signups[msg.sender] = User(msg.sender,now);
1089 |         userSignupCount++;
1090 |  
1091 |         E_Signup(msg.sender,now);
1092 |     }
1093 |  
1094 |     /**
1095 |      * @dev removes user from airdrop list.
1096 |      * Beware that token distribution for existing airdrops won't change.
1097 |      * For example: if 100 tokens were to be distributed to 10 people (10 each).
1098 |      * if one quitted from the list, the other 9 will still get 10 each.
1099 |      * @notice WARNING: Quiting from the airdrop central will make you lose
1100 |      * tokens not yet withdrawn. Make sure to withdraw all pending tokens before
1101 |      * removing yourself from this list. Signing up later will not give you the older tokens back
1102 |      */
1103 |     function quitFromAirdrops() public ifNotPaused{
1104 |         require(signups[msg.sender].userAddress == msg.sender);
1105 |         delete signups[msg.sender];
1106 |         userSignupCount--;
1107 |     }
1108 |  
1109 |     /**
1110 |      * @dev calculates the amount of tokens the user will be able to withdraw
1111 |      * Given a token address, the function checks all airdrops with the same address
1112 |      * @param _tokenAddress is the token the user wants to check his balance for
1113 |      * @return totalTokensAvailable is the tokens calculated
1114 |      */
1115 |     function getTokensAvailableToMe(address _tokenAddress) view public returns (uint){
1116 |         require(tokenWhitelist[_tokenAddress]); // Token must be whitelisted first
1117 |  
1118 |         // Get User instance, given the sender account
1119 |         User storage user = signups[msg.sender];
1120 |         require(user.userAddress != address(0));
1121 |  
1122 |         uint totalTokensAvailable= 0;
1123 |         for (uint i =0; i<airdroppedTokens[_tokenAddress].length; i++){
1124 |             TokenAirdrop storage ta = airdroppedTokens[_tokenAddress][i];
1125 |  
1126 |             uint _withdrawnBalance = user.withdrawnBalances[_tokenAddress][i];
1127 |  
1128 |             //Check that user signed up before the airdrop was done. If so, he is entitled to the tokens
1129 |             //And the airdrop must not have expired
1130 |             if(ta.airdropDate >= user.signupDate &&
1131 |                 now <= ta.airdropExpirationDate){
1132 |  
1133 |                 // The user will get a portion of the total tokens airdroped,
1134 |                 // divided by the users at the moment the airdrop was created
1135 |                 uint tokensAvailable = ta.totalDropped.div(ta.usersAtDate);
1136 |  
1137 |                 // if the user has not alreay withdrawn the tokens, count them
1138 |                 if(_withdrawnBalance < tokensAvailable){
1139 |                     totalTokensAvailable = totalTokensAvailable.add(tokensAvailable);
1140 |  
1141 |                 }
1142 |             }
1143 |         }
1144 |         return totalTokensAvailable;
1145 |     }
1146 |  
1147 |     /**
1148 |      * @dev calculates and withdraws the amount of tokens the user has been awarded by airdrops
1149 |      * Given a token address, the function checks all airdrops with the same
1150 |      * address and withdraws the corresponding tokens for the user.
1151 |      * @param _tokenAddress is the token the user wants to check his balance for
1152 |      */
1153 |     function withdrawTokens(address _tokenAddress) ifNotPaused public {
1154 |         Erequire(tokenWhitelist[_tokenAddress]); // Token must be whitelisted first
1155 |  
1156 |         // Get User instance, given the sender account
1157 |         User storage user = signups[msg.sender];
1158 |         Erequire(user.userAddress != address(0));
1159 |  
1160 |         uint totalTokensToTransfer = 0;
1161 |         // For each airdrop made for this token (token owner may have done several airdrops at any given point)
1162 |         for (uint i =0; i<airdroppedTokens[_tokenAddress].length; i++){
1163 |             TokenAirdrop storage ta = airdroppedTokens[_tokenAddress][i];
1164 |  
1165 |             uint _withdrawnBalance = user.withdrawnBalances[_tokenAddress][i];
1166 |  
1167 |             //Check that user signed up before the airdrop was done. If so, he is entitled to the tokens
1168 |             //And the airdrop must not have expired
1169 |             Eif(ta.airdropDate >= user.signupDate &&
1170 |                 now <= ta.airdropExpirationDate){
1171 |  
1172 |                 // The user will get a portion of the total tokens airdroped,
1173 |                 // divided by the users at the moment the airdrop was created
1174 |                 uint tokensToTransfer = ta.totalDropped.div(ta.usersAtDate);
1175 |  
1176 |                 // if the user has not alreay withdrawn the tokens
1177 |                 Eif(_withdrawnBalance < tokensToTransfer){
1178 |                     // Register the tokens withdrawn by the user and total tokens withdrawn
1179 |                     user.withdrawnBalances[_tokenAddress][i] = tokensToTransfer;
1180 |                     ta.tokenBalance = ta.tokenBalance.sub(tokensToTransfer);
1181 |                     totalTokensToTransfer = totalTokensToTransfer.add(tokensToTransfer);
1182 |  
1183 |                 }
1184 |             }
1185 |         }
1186 |         // Get the token
1187 |         ERC20Basic token = ERC20Basic(_tokenAddress);
1188 |         // Transfer tokens from all airdrops that correspond to this user
1189 |         Erequire(token.transfer(msg.sender,totalTokensToTransfer));
1190 |  
1191 |         E_TokensWithdrawn(_tokenAddress,msg.sender,totalTokensToTransfer,now);
1192 |     }
1193 |  
1194 |     function airdropsCount() public view returns (uint){
1195 |         return airdrops.length;
1196 |     }
1197 |  
1198 |     function getAddress() public view returns (address){
1199 |       return address(this);
1200 |     }
1201 |  
1202 |     function airdropHasExpired(address _tokenAddress, uint _id) public view returns (bool){
1203 |         TokenAirdrop storage ta = airdroppedTokens[_tokenAddress][_id];
1204 |         return (now > ta.airdropExpirationDate);
1205 |     }
1206 | }
1207 |  
1209 |
1210 |
1211 | 1215 | 1216 | 1217 | 1224 | 1225 | 1226 | 1227 | --------------------------------------------------------------------------------