├── LICENSE ├── README.md ├── build └── contracts │ ├── ERC20Interface.json │ ├── KyberAirDrop.json │ ├── KyberGenesisToken.json │ ├── Migrations.json │ ├── Ownable.json │ ├── StandardToken.json │ └── Token.json ├── contracts ├── KyberAirDrop.sol ├── KyberGenesisToken.sol ├── Migrations.sol ├── Ownable.sol └── StandardToken.sol ├── kgt_tracker.js ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── monitor.js ├── test ├── airdrop.js ├── gentoken.js └── helpers.js ├── truffle.js ├── upload.js └── upload.txt /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 KyberNetwork 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # airdrop of KNC and KGT tokens 2 | This repository consists of Kyber Genesis Token (KGT) smart contract and a smart contract to speed the airdropping process. 3 | In the airdrop every user get 2 KNC, and in addition user may also get 1 KGT. 4 | 5 | In addition, the repository consists of web3 javascript files that were used to initiate the airdrop transactions and monitor the progress. 6 | The scripts makes the transaction via infura public node, and the monitoring via local parity node that is run with `--no-wrap` flag. 7 | As otherwise it is not possible to fetch old events. 8 | 9 | 10 | The airdrop sequence is as follows: 11 | 1. Deploy KGT and airdrop contract. 12 | 2. Approve enough KNC tokens (other tokens are also supported) to the airdrop contract. 13 | 3. Compile a list of reciepient addresses and store them in `upload.txt` file. 14 | 4. Run `upload.js` script. 15 | 5. When airdrop ends, call `endMiniting` function in KGT contract. 16 | 17 | 18 | When used for future airdrop one should: 19 | 1. Code valid private key string in `upload.js`. 20 | 2. Change `emergencyERC20Drain` to send stuck tokens to a predefined address. Currently it sends it to kyber wallet. 21 | 3. Set desiriable gas fees. 22 | 4. Change hardcoded addresses to match actual token address and source wallet. 23 | -------------------------------------------------------------------------------- /build/contracts/ERC20Interface.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "ERC20Interface", 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "inputs": [ 7 | { 8 | "name": "_from", 9 | "type": "address" 10 | }, 11 | { 12 | "name": "_to", 13 | "type": "address" 14 | }, 15 | { 16 | "name": "_value", 17 | "type": "uint256" 18 | } 19 | ], 20 | "name": "transferFrom", 21 | "outputs": [ 22 | { 23 | "name": "", 24 | "type": "bool" 25 | } 26 | ], 27 | "payable": false, 28 | "type": "function" 29 | }, 30 | { 31 | "constant": false, 32 | "inputs": [ 33 | { 34 | "name": "_to", 35 | "type": "address" 36 | }, 37 | { 38 | "name": "_value", 39 | "type": "uint256" 40 | } 41 | ], 42 | "name": "transfer", 43 | "outputs": [ 44 | { 45 | "name": "", 46 | "type": "bool" 47 | } 48 | ], 49 | "payable": false, 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [], 54 | "payable": false, 55 | "type": "constructor" 56 | } 57 | ], 58 | "unlinked_binary": "0x6060604052341561000f57600080fd5b5b5b5b61010b806100216000396000f300606060405263ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166323b872dd81146046578063a9059cbb14608c575b600080fd5b3415605057600080fd5b607873ffffffffffffffffffffffffffffffffffffffff6004358116906024351660443560cc565b604051901515815260200160405180910390f35b3415609657600080fd5b607873ffffffffffffffffffffffffffffffffffffffff6004351660243560d6565b604051901515815260200160405180910390f35b60005b9392505050565b60005b929150505600a165627a7a723058205804f94c4627fad1cc5e047f290ce3d6335b096247a0eec46bc1ca694a7ffda30029", 59 | "networks": {}, 60 | "schema_version": "0.0.5", 61 | "updated_at": 1506361352317 62 | } -------------------------------------------------------------------------------- /build/contracts/KyberAirDrop.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "KyberAirDrop", 3 | "abi": [ 4 | { 5 | "constant": true, 6 | "inputs": [], 7 | "name": "dropAmount", 8 | "outputs": [ 9 | { 10 | "name": "", 11 | "type": "uint256" 12 | } 13 | ], 14 | "payable": false, 15 | "type": "function" 16 | }, 17 | { 18 | "constant": false, 19 | "inputs": [ 20 | { 21 | "name": "token", 22 | "type": "address" 23 | }, 24 | { 25 | "name": "tokenRepo", 26 | "type": "address" 27 | }, 28 | { 29 | "name": "recipients", 30 | "type": "address[]" 31 | }, 32 | { 33 | "name": "amount", 34 | "type": "uint256" 35 | }, 36 | { 37 | "name": "kgt", 38 | "type": "bool" 39 | }, 40 | { 41 | "name": "kgtToken", 42 | "type": "address" 43 | } 44 | ], 45 | "name": "airDrop", 46 | "outputs": [], 47 | "payable": false, 48 | "type": "function" 49 | }, 50 | { 51 | "constant": true, 52 | "inputs": [], 53 | "name": "numDrops", 54 | "outputs": [ 55 | { 56 | "name": "", 57 | "type": "uint256" 58 | } 59 | ], 60 | "payable": false, 61 | "type": "function" 62 | }, 63 | { 64 | "constant": true, 65 | "inputs": [], 66 | "name": "owner", 67 | "outputs": [ 68 | { 69 | "name": "", 70 | "type": "address" 71 | } 72 | ], 73 | "payable": false, 74 | "type": "function" 75 | }, 76 | { 77 | "constant": false, 78 | "inputs": [ 79 | { 80 | "name": "kgtToken", 81 | "type": "address" 82 | }, 83 | { 84 | "name": "newOwner", 85 | "type": "address" 86 | } 87 | ], 88 | "name": "tranferMinterOwnership", 89 | "outputs": [], 90 | "payable": false, 91 | "type": "function" 92 | }, 93 | { 94 | "constant": false, 95 | "inputs": [ 96 | { 97 | "name": "token", 98 | "type": "address" 99 | }, 100 | { 101 | "name": "amount", 102 | "type": "uint256" 103 | } 104 | ], 105 | "name": "emergencyERC20Drain", 106 | "outputs": [], 107 | "payable": false, 108 | "type": "function" 109 | }, 110 | { 111 | "constant": false, 112 | "inputs": [ 113 | { 114 | "name": "newOwner", 115 | "type": "address" 116 | } 117 | ], 118 | "name": "transferOwnership", 119 | "outputs": [], 120 | "payable": false, 121 | "type": "function" 122 | }, 123 | { 124 | "inputs": [ 125 | { 126 | "name": "dropper", 127 | "type": "address" 128 | } 129 | ], 130 | "payable": false, 131 | "type": "constructor" 132 | }, 133 | { 134 | "anonymous": false, 135 | "inputs": [ 136 | { 137 | "indexed": false, 138 | "name": "receiver", 139 | "type": "address" 140 | }, 141 | { 142 | "indexed": false, 143 | "name": "amount", 144 | "type": "uint256" 145 | } 146 | ], 147 | "name": "TokenDrop", 148 | "type": "event" 149 | } 150 | ], 151 | "unlinked_binary": "0x6060604052341561000f57600080fd5b60405160208061066f833981016040528080519150505b5b60008054600160a060020a03191633600160a060020a03161790555b6100598164010000000061053161006082021704565b5b506100ab565b60005433600160a060020a0390811691161461007b57600080fd5b600160a060020a038116156100a65760008054600160a060020a031916600160a060020a0383161790555b5b5b50565b6105b5806100ba6000396000f300606060405236156100675763ffffffff60e060020a60003504166305748be2811461006c578063608bc08c146100915780638bc30096146101125780638da5cb5b146101375780638e744f5414610166578063db0e16f11461018d578063f2fde38b146101b1575b600080fd5b341561007757600080fd5b61007f6101d2565b60405190815260200160405180910390f35b341561009c57600080fd5b610110600160a060020a036004803582169160248035909116919060649060443590810190830135806020818102016040519081016040528093929190818152602001838360200280828437509496505084359460208101351515945060400135600160a060020a031692506101d8915050565b005b341561011d57600080fd5b61007f610406565b60405190815260200160405180910390f35b341561014257600080fd5b61014a61040c565b604051600160a060020a03909116815260200160405180910390f35b341561017157600080fd5b610110600160a060020a036004358116906024351661041b565b005b341561019857600080fd5b610110600160a060020a036004351660243561049e565b005b34156101bc57600080fd5b610110600160a060020a0360043516610531565b005b60025481565b6000805433600160a060020a039081169116146101f457600080fd5b831580610208575083671bc16d674ec80000145b8061021a575083674563918244f40000145b151561022557600080fd5b600084111561033f575060005b845181101561033f5786600160a060020a03166323b872dd8787848151811061025757fe5b906020019060200201518760006040516020015260405160e060020a63ffffffff8616028152600160a060020a0393841660048201529190921660248201526044810191909152606401602060405180830381600087803b15156102ba57600080fd5b6102c65a03f115156102cb57600080fd5b5050506040518051905015156102dd57fe5b7fb88903f74059b09b78248a0df6ba49200ca616f185ca84aca28d3e74e754ab8685828151811061030a57fe5b9060200190602002015185604051600160a060020a03909216825260208201526040908101905180910390a15b600101610232565b5b82156103e25781600160a060020a031663bd075b84866040518263ffffffff1660e060020a0281526004018080602001828103825283818151815260200191508051906020019060200280838360005b838110156103a95780820151818401525b602001610390565b5050505090500192505050600060405180830381600087803b15156103cd57600080fd5b6102c65a03f115156103de57600080fd5b5050505b845160018054909101905583855160028054919092020190555b5b50505050505050565b60015481565b600054600160a060020a031681565b60005433600160a060020a0390811691161461043657600080fd5b81600160a060020a031663f2fde38b8260405160e060020a63ffffffff8416028152600160a060020a039091166004820152602401600060405180830381600087803b151561048457600080fd5b6102c65a03f1151561049557600080fd5b5050505b5b5050565b733eb01b3391ea15ce752d01cf3d3f09dec596f650600160a060020a03831663a9059cbb828460006040516020015260405160e060020a63ffffffff8516028152600160a060020a0390921660048301526024820152604401602060405180830381600087803b151561051057600080fd5b6102c65a03f1151561052157600080fd5b505050604051805150505b505050565b60005433600160a060020a0390811691161461054c57600080fd5b600160a060020a03811615610584576000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b5b505600a165627a7a7230582022542a7c8d6895ff72c8a3a6477c87721e083e9a78601147b117f634514099340029", 152 | "networks": { 153 | "1": { 154 | "links": {}, 155 | "events": { 156 | "0xb88903f74059b09b78248a0df6ba49200ca616f185ca84aca28d3e74e754ab86": { 157 | "anonymous": false, 158 | "inputs": [ 159 | { 160 | "indexed": false, 161 | "name": "receiver", 162 | "type": "address" 163 | }, 164 | { 165 | "indexed": false, 166 | "name": "amount", 167 | "type": "uint256" 168 | } 169 | ], 170 | "name": "TokenDrop", 171 | "type": "event" 172 | } 173 | }, 174 | "updated_at": 1506361363132 175 | }, 176 | "1506347582347": { 177 | "links": {}, 178 | "events": { 179 | "0xb88903f74059b09b78248a0df6ba49200ca616f185ca84aca28d3e74e754ab86": { 180 | "anonymous": false, 181 | "inputs": [ 182 | { 183 | "indexed": false, 184 | "name": "receiver", 185 | "type": "address" 186 | }, 187 | { 188 | "indexed": false, 189 | "name": "amount", 190 | "type": "uint256" 191 | } 192 | ], 193 | "name": "TokenDrop", 194 | "type": "event" 195 | } 196 | }, 197 | "updated_at": 1506347587261 198 | }, 199 | "1506347679606": { 200 | "links": {}, 201 | "events": { 202 | "0xb88903f74059b09b78248a0df6ba49200ca616f185ca84aca28d3e74e754ab86": { 203 | "anonymous": false, 204 | "inputs": [ 205 | { 206 | "indexed": false, 207 | "name": "receiver", 208 | "type": "address" 209 | }, 210 | { 211 | "indexed": false, 212 | "name": "amount", 213 | "type": "uint256" 214 | } 215 | ], 216 | "name": "TokenDrop", 217 | "type": "event" 218 | } 219 | }, 220 | "updated_at": 1506347684704 221 | }, 222 | "1506360949507": { 223 | "links": {}, 224 | "events": { 225 | "0xb88903f74059b09b78248a0df6ba49200ca616f185ca84aca28d3e74e754ab86": { 226 | "anonymous": false, 227 | "inputs": [ 228 | { 229 | "indexed": false, 230 | "name": "receiver", 231 | "type": "address" 232 | }, 233 | { 234 | "indexed": false, 235 | "name": "amount", 236 | "type": "uint256" 237 | } 238 | ], 239 | "name": "TokenDrop", 240 | "type": "event" 241 | } 242 | }, 243 | "updated_at": 1506360956360 244 | } 245 | }, 246 | "schema_version": "0.0.5", 247 | "updated_at": 1506361363132 248 | } -------------------------------------------------------------------------------- /build/contracts/KyberGenesisToken.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "KyberGenesisToken", 3 | "abi": [ 4 | { 5 | "constant": true, 6 | "inputs": [], 7 | "name": "name", 8 | "outputs": [ 9 | { 10 | "name": "", 11 | "type": "string" 12 | } 13 | ], 14 | "payable": false, 15 | "type": "function" 16 | }, 17 | { 18 | "constant": false, 19 | "inputs": [ 20 | { 21 | "name": "_spender", 22 | "type": "address" 23 | }, 24 | { 25 | "name": "_value", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "approve", 30 | "outputs": [ 31 | { 32 | "name": "", 33 | "type": "bool" 34 | } 35 | ], 36 | "payable": false, 37 | "type": "function" 38 | }, 39 | { 40 | "constant": true, 41 | "inputs": [], 42 | "name": "totalSupply", 43 | "outputs": [ 44 | { 45 | "name": "", 46 | "type": "uint256" 47 | } 48 | ], 49 | "payable": false, 50 | "type": "function" 51 | }, 52 | { 53 | "constant": false, 54 | "inputs": [ 55 | { 56 | "name": "_from", 57 | "type": "address" 58 | }, 59 | { 60 | "name": "_to", 61 | "type": "address" 62 | }, 63 | { 64 | "name": "_value", 65 | "type": "uint256" 66 | } 67 | ], 68 | "name": "transferFrom", 69 | "outputs": [ 70 | { 71 | "name": "", 72 | "type": "bool" 73 | } 74 | ], 75 | "payable": false, 76 | "type": "function" 77 | }, 78 | { 79 | "constant": true, 80 | "inputs": [], 81 | "name": "decimals", 82 | "outputs": [ 83 | { 84 | "name": "", 85 | "type": "uint256" 86 | } 87 | ], 88 | "payable": false, 89 | "type": "function" 90 | }, 91 | { 92 | "constant": false, 93 | "inputs": [], 94 | "name": "burn", 95 | "outputs": [], 96 | "payable": false, 97 | "type": "function" 98 | }, 99 | { 100 | "constant": true, 101 | "inputs": [ 102 | { 103 | "name": "", 104 | "type": "address" 105 | } 106 | ], 107 | "name": "balanceOf", 108 | "outputs": [ 109 | { 110 | "name": "", 111 | "type": "uint256" 112 | } 113 | ], 114 | "payable": false, 115 | "type": "function" 116 | }, 117 | { 118 | "constant": true, 119 | "inputs": [], 120 | "name": "owner", 121 | "outputs": [ 122 | { 123 | "name": "", 124 | "type": "address" 125 | } 126 | ], 127 | "payable": false, 128 | "type": "function" 129 | }, 130 | { 131 | "constant": true, 132 | "inputs": [], 133 | "name": "symbol", 134 | "outputs": [ 135 | { 136 | "name": "", 137 | "type": "string" 138 | } 139 | ], 140 | "payable": false, 141 | "type": "function" 142 | }, 143 | { 144 | "constant": false, 145 | "inputs": [ 146 | { 147 | "name": "_to", 148 | "type": "address" 149 | }, 150 | { 151 | "name": "_value", 152 | "type": "uint256" 153 | } 154 | ], 155 | "name": "transfer", 156 | "outputs": [ 157 | { 158 | "name": "", 159 | "type": "bool" 160 | } 161 | ], 162 | "payable": false, 163 | "type": "function" 164 | }, 165 | { 166 | "constant": false, 167 | "inputs": [ 168 | { 169 | "name": "recipients", 170 | "type": "address[]" 171 | } 172 | ], 173 | "name": "mint", 174 | "outputs": [], 175 | "payable": false, 176 | "type": "function" 177 | }, 178 | { 179 | "constant": false, 180 | "inputs": [ 181 | { 182 | "name": "token", 183 | "type": "address" 184 | }, 185 | { 186 | "name": "amount", 187 | "type": "uint256" 188 | } 189 | ], 190 | "name": "emergencyERC20Drain", 191 | "outputs": [], 192 | "payable": false, 193 | "type": "function" 194 | }, 195 | { 196 | "constant": true, 197 | "inputs": [ 198 | { 199 | "name": "_owner", 200 | "type": "address" 201 | }, 202 | { 203 | "name": "_spender", 204 | "type": "address" 205 | } 206 | ], 207 | "name": "allowance", 208 | "outputs": [ 209 | { 210 | "name": "", 211 | "type": "uint256" 212 | } 213 | ], 214 | "payable": false, 215 | "type": "function" 216 | }, 217 | { 218 | "constant": false, 219 | "inputs": [], 220 | "name": "endMinting", 221 | "outputs": [], 222 | "payable": false, 223 | "type": "function" 224 | }, 225 | { 226 | "constant": false, 227 | "inputs": [ 228 | { 229 | "name": "newOwner", 230 | "type": "address" 231 | } 232 | ], 233 | "name": "transferOwnership", 234 | "outputs": [], 235 | "payable": false, 236 | "type": "function" 237 | }, 238 | { 239 | "inputs": [ 240 | { 241 | "name": "minter", 242 | "type": "address" 243 | } 244 | ], 245 | "payable": false, 246 | "type": "constructor" 247 | }, 248 | { 249 | "anonymous": false, 250 | "inputs": [ 251 | { 252 | "indexed": true, 253 | "name": "_from", 254 | "type": "address" 255 | }, 256 | { 257 | "indexed": true, 258 | "name": "_to", 259 | "type": "address" 260 | }, 261 | { 262 | "indexed": false, 263 | "name": "_value", 264 | "type": "uint256" 265 | } 266 | ], 267 | "name": "Transfer", 268 | "type": "event" 269 | }, 270 | { 271 | "anonymous": false, 272 | "inputs": [ 273 | { 274 | "indexed": false, 275 | "name": "timestamp", 276 | "type": "uint256" 277 | } 278 | ], 279 | "name": "EndMinting", 280 | "type": "event" 281 | }, 282 | { 283 | "anonymous": false, 284 | "inputs": [ 285 | { 286 | "indexed": true, 287 | "name": "_owner", 288 | "type": "address" 289 | }, 290 | { 291 | "indexed": true, 292 | "name": "_spender", 293 | "type": "address" 294 | }, 295 | { 296 | "indexed": false, 297 | "name": "_value", 298 | "type": "uint256" 299 | } 300 | ], 301 | "name": "Approval", 302 | "type": "event" 303 | } 304 | ], 305 | "unlinked_binary": "0x60606040526000600155341561001457600080fd5b6040516020806108c8833981016040528080519150505b5b60008054600160a060020a03191633600160a060020a03161790555b61005e8164010000000061078561006582021704565b5b506100b0565b60005433600160a060020a0390811691161461008057600080fd5b600160a060020a038116156100ab5760008054600160a060020a031916600160a060020a0383161790555b5b5b50565b610809806100bf6000396000f300606060405236156100d85763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde0381146100dd578063095ea7b31461016857806318160ddd1461019e57806323b872dd146101c3578063313ce567146101ff57806344df8e701461022457806370a08231146102395780638da5cb5b1461026a57806395d89b4114610299578063a9059cbb14610168578063bd075b841461035a578063db0e16f1146103ab578063dd62ed3e146103cf578063ef70aebf14610406578063f2fde38b1461041b575b600080fd5b34156100e857600080fd5b6100f061043c565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561012d5780820151818401525b602001610114565b50505050905090810190601f16801561015a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561017357600080fd5b61018a600160a060020a0360043516602435610473565b604051901515815260200160405180910390f35b34156101a957600080fd5b6101b1610480565b60405190815260200160405180910390f35b34156101ce57600080fd5b61018a600160a060020a0360043581169060243516604435610473565b604051901515815260200160405180910390f35b341561020a57600080fd5b6101b1610494565b60405190815260200160405180910390f35b341561022f57600080fd5b610237610499565b005b341561024457600080fd5b6101b1600160a060020a0360043516610524565b60405190815260200160405180910390f35b341561027557600080fd5b61027d610536565b604051600160a060020a03909116815260200160405180910390f35b34156102a457600080fd5b6100f0610545565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561012d5780820151818401525b602001610114565b50505050905090810190601f16801561015a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561017357600080fd5b61018a600160a060020a0360043516602435610473565b604051901515815260200160405180910390f35b341561036557600080fd5b610237600460248135818101908301358060208181020160405190810160405280939291908181526020018383602002808284375094965061058995505050505050565b005b34156103b657600080fd5b610237600160a060020a0360043516602435610673565b005b34156103da57600080fd5b6101b1600160a060020a036004358116906024351661071f565b60405190815260200160405180910390f35b341561041157600080fd5b610237610728565b005b341561042657600080fd5b610237600160a060020a0360043516610785565b005b60408051908101604052601381527f4b796265722047656e6573697320546f6b656e00000000000000000000000000602082015281565b6000806000fd5b92915050565b60015481565b6000806000fd5b9392505050565b600081565b600160a060020a0333166000908152600260205260409020546001146104be57600080fd5b600033600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600160405190815260200160405180910390a3600160a060020a033316600090815260026020526040812055600180546000190190555b565b60026020526000908152604090205481565b600054600160a060020a031681565b60408051908101604052600381527f4b47540000000000000000000000000000000000000000000000000000000000602082015281565b6000806000fd5b92915050565b600080548190819033600160a060020a039081169116146105a957600080fd5b60009250600091505b8351821015610663578382815181106105c757fe5b90602001906020020151600160a060020a038116600090815260026020526040902054909150151561065757600160a060020a03811660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600160405190815260200160405180910390a3600160a060020a038116600090815260026020526040902060019081905592909201915b5b6001909101906105b2565b60018054840190555b5b50505050565b733eb01b3391ea15ce752d01cf3d3f09dec596f650600160a060020a03831663a9059cbb82846000604051602001526040517c010000000000000000000000000000000000000000000000000000000063ffffffff8516028152600160a060020a0390921660048301526024820152604401602060405180830381600087803b15156106fe57600080fd5b6102c65a03f1151561070f57600080fd5b505050604051805150505b505050565b60005b92915050565b60005433600160a060020a0390811691161461074357600080fd5b61074e61dead610785565b7fc70faf9076ff7f43f07da927c92edc2da02676c3cc3cbb054144c657b9b2d2d04260405190815260200160405180910390a15b5b565b60005433600160a060020a039081169116146107a057600080fd5b600160a060020a038116156107d8576000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b5b505600a165627a7a72305820868fbc5740f4b925a90927ddc03ea7058855b746b680f4e4a284667b318ce8170029", 306 | "networks": { 307 | "1": { 308 | "links": {}, 309 | "events": { 310 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": { 311 | "anonymous": false, 312 | "inputs": [ 313 | { 314 | "indexed": true, 315 | "name": "_from", 316 | "type": "address" 317 | }, 318 | { 319 | "indexed": true, 320 | "name": "_to", 321 | "type": "address" 322 | }, 323 | { 324 | "indexed": false, 325 | "name": "_value", 326 | "type": "uint256" 327 | } 328 | ], 329 | "name": "Transfer", 330 | "type": "event" 331 | }, 332 | "0xc70faf9076ff7f43f07da927c92edc2da02676c3cc3cbb054144c657b9b2d2d0": { 333 | "anonymous": false, 334 | "inputs": [ 335 | { 336 | "indexed": false, 337 | "name": "timestamp", 338 | "type": "uint256" 339 | } 340 | ], 341 | "name": "EndMinting", 342 | "type": "event" 343 | }, 344 | "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": { 345 | "anonymous": false, 346 | "inputs": [ 347 | { 348 | "indexed": true, 349 | "name": "_owner", 350 | "type": "address" 351 | }, 352 | { 353 | "indexed": true, 354 | "name": "_spender", 355 | "type": "address" 356 | }, 357 | { 358 | "indexed": false, 359 | "name": "_value", 360 | "type": "uint256" 361 | } 362 | ], 363 | "name": "Approval", 364 | "type": "event" 365 | } 366 | }, 367 | "updated_at": 1506361363128 368 | }, 369 | "1506347582347": { 370 | "links": {}, 371 | "events": { 372 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": { 373 | "anonymous": false, 374 | "inputs": [ 375 | { 376 | "indexed": true, 377 | "name": "_from", 378 | "type": "address" 379 | }, 380 | { 381 | "indexed": true, 382 | "name": "_to", 383 | "type": "address" 384 | }, 385 | { 386 | "indexed": false, 387 | "name": "_value", 388 | "type": "uint256" 389 | } 390 | ], 391 | "name": "Transfer", 392 | "type": "event" 393 | }, 394 | "0xc70faf9076ff7f43f07da927c92edc2da02676c3cc3cbb054144c657b9b2d2d0": { 395 | "anonymous": false, 396 | "inputs": [ 397 | { 398 | "indexed": false, 399 | "name": "timestamp", 400 | "type": "uint256" 401 | } 402 | ], 403 | "name": "EndMinting", 404 | "type": "event" 405 | }, 406 | "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": { 407 | "anonymous": false, 408 | "inputs": [ 409 | { 410 | "indexed": true, 411 | "name": "_owner", 412 | "type": "address" 413 | }, 414 | { 415 | "indexed": true, 416 | "name": "_spender", 417 | "type": "address" 418 | }, 419 | { 420 | "indexed": false, 421 | "name": "_value", 422 | "type": "uint256" 423 | } 424 | ], 425 | "name": "Approval", 426 | "type": "event" 427 | } 428 | }, 429 | "updated_at": 1506347587257 430 | }, 431 | "1506347679606": { 432 | "links": {}, 433 | "events": { 434 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": { 435 | "anonymous": false, 436 | "inputs": [ 437 | { 438 | "indexed": true, 439 | "name": "_from", 440 | "type": "address" 441 | }, 442 | { 443 | "indexed": true, 444 | "name": "_to", 445 | "type": "address" 446 | }, 447 | { 448 | "indexed": false, 449 | "name": "_value", 450 | "type": "uint256" 451 | } 452 | ], 453 | "name": "Transfer", 454 | "type": "event" 455 | }, 456 | "0xc70faf9076ff7f43f07da927c92edc2da02676c3cc3cbb054144c657b9b2d2d0": { 457 | "anonymous": false, 458 | "inputs": [ 459 | { 460 | "indexed": false, 461 | "name": "timestamp", 462 | "type": "uint256" 463 | } 464 | ], 465 | "name": "EndMinting", 466 | "type": "event" 467 | }, 468 | "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": { 469 | "anonymous": false, 470 | "inputs": [ 471 | { 472 | "indexed": true, 473 | "name": "_owner", 474 | "type": "address" 475 | }, 476 | { 477 | "indexed": true, 478 | "name": "_spender", 479 | "type": "address" 480 | }, 481 | { 482 | "indexed": false, 483 | "name": "_value", 484 | "type": "uint256" 485 | } 486 | ], 487 | "name": "Approval", 488 | "type": "event" 489 | } 490 | }, 491 | "updated_at": 1506347684706 492 | }, 493 | "1506360949507": { 494 | "links": {}, 495 | "events": { 496 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": { 497 | "anonymous": false, 498 | "inputs": [ 499 | { 500 | "indexed": true, 501 | "name": "_from", 502 | "type": "address" 503 | }, 504 | { 505 | "indexed": true, 506 | "name": "_to", 507 | "type": "address" 508 | }, 509 | { 510 | "indexed": false, 511 | "name": "_value", 512 | "type": "uint256" 513 | } 514 | ], 515 | "name": "Transfer", 516 | "type": "event" 517 | }, 518 | "0xc70faf9076ff7f43f07da927c92edc2da02676c3cc3cbb054144c657b9b2d2d0": { 519 | "anonymous": false, 520 | "inputs": [ 521 | { 522 | "indexed": false, 523 | "name": "timestamp", 524 | "type": "uint256" 525 | } 526 | ], 527 | "name": "EndMinting", 528 | "type": "event" 529 | }, 530 | "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": { 531 | "anonymous": false, 532 | "inputs": [ 533 | { 534 | "indexed": true, 535 | "name": "_owner", 536 | "type": "address" 537 | }, 538 | { 539 | "indexed": true, 540 | "name": "_spender", 541 | "type": "address" 542 | }, 543 | { 544 | "indexed": false, 545 | "name": "_value", 546 | "type": "uint256" 547 | } 548 | ], 549 | "name": "Approval", 550 | "type": "event" 551 | } 552 | }, 553 | "updated_at": 1506360956356 554 | } 555 | }, 556 | "schema_version": "0.0.5", 557 | "updated_at": 1506361363128 558 | } -------------------------------------------------------------------------------- /build/contracts/Migrations.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "Migrations", 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "inputs": [ 7 | { 8 | "name": "new_address", 9 | "type": "address" 10 | } 11 | ], 12 | "name": "upgrade", 13 | "outputs": [], 14 | "payable": false, 15 | "type": "function" 16 | }, 17 | { 18 | "constant": true, 19 | "inputs": [], 20 | "name": "last_completed_migration", 21 | "outputs": [ 22 | { 23 | "name": "", 24 | "type": "uint256" 25 | } 26 | ], 27 | "payable": false, 28 | "type": "function" 29 | }, 30 | { 31 | "constant": true, 32 | "inputs": [], 33 | "name": "owner", 34 | "outputs": [ 35 | { 36 | "name": "", 37 | "type": "address" 38 | } 39 | ], 40 | "payable": false, 41 | "type": "function" 42 | }, 43 | { 44 | "constant": false, 45 | "inputs": [ 46 | { 47 | "name": "completed", 48 | "type": "uint256" 49 | } 50 | ], 51 | "name": "setCompleted", 52 | "outputs": [], 53 | "payable": false, 54 | "type": "function" 55 | }, 56 | { 57 | "inputs": [], 58 | "payable": false, 59 | "type": "constructor" 60 | } 61 | ], 62 | "unlinked_binary": "0x6060604052341561000f57600080fd5b5b60008054600160a060020a03191633600160a060020a03161790555b5b6101e58061003c6000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630900f010811461005e578063445df0ac1461007f5780638da5cb5b146100a4578063fdacd576146100d3575b600080fd5b341561006957600080fd5b61007d600160a060020a03600435166100eb565b005b341561008a57600080fd5b610092610182565b60405190815260200160405180910390f35b34156100af57600080fd5b6100b7610188565b604051600160a060020a03909116815260200160405180910390f35b34156100de57600080fd5b61007d600435610197565b005b6000805433600160a060020a039081169116141561017c5781905080600160a060020a031663fdacd5766001546040517c010000000000000000000000000000000000000000000000000000000063ffffffff84160281526004810191909152602401600060405180830381600087803b151561016757600080fd5b6102c65a03f1151561017857600080fd5b5050505b5b5b5050565b60015481565b600054600160a060020a031681565b60005433600160a060020a03908116911614156101b45760018190555b5b5b505600a165627a7a72305820b0d43e799841311a01ff8e4326e79cd8be4fe0f9f4cfd8a6b8a06c697c9508610029", 63 | "networks": { 64 | "1": { 65 | "links": {}, 66 | "events": {}, 67 | "updated_at": 1506361363132 68 | }, 69 | "1506347582347": { 70 | "links": {}, 71 | "events": {}, 72 | "updated_at": 1506347587261 73 | }, 74 | "1506347679606": { 75 | "links": {}, 76 | "events": {}, 77 | "updated_at": 1506347684708 78 | }, 79 | "1506360949507": { 80 | "links": {}, 81 | "events": {}, 82 | "updated_at": 1506360956360 83 | } 84 | }, 85 | "schema_version": "0.0.5", 86 | "updated_at": 1506361363132 87 | } -------------------------------------------------------------------------------- /build/contracts/Ownable.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "Ownable", 3 | "abi": [ 4 | { 5 | "constant": true, 6 | "inputs": [], 7 | "name": "owner", 8 | "outputs": [ 9 | { 10 | "name": "", 11 | "type": "address" 12 | } 13 | ], 14 | "payable": false, 15 | "type": "function" 16 | }, 17 | { 18 | "constant": false, 19 | "inputs": [ 20 | { 21 | "name": "newOwner", 22 | "type": "address" 23 | } 24 | ], 25 | "name": "transferOwnership", 26 | "outputs": [], 27 | "payable": false, 28 | "type": "function" 29 | }, 30 | { 31 | "inputs": [], 32 | "payable": false, 33 | "type": "constructor" 34 | } 35 | ], 36 | "unlinked_binary": "0x6060604052341561000f57600080fd5b5b60008054600160a060020a03191633600160a060020a03161790555b5b6101218061003c6000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416638da5cb5b81146046578063f2fde38b146072575b600080fd5b3415605057600080fd5b60566090565b604051600160a060020a03909116815260200160405180910390f35b3415607c57600080fd5b608e600160a060020a0360043516609f565b005b600054600160a060020a031681565b60005433600160a060020a0390811691161460b957600080fd5b600160a060020a0381161560f0576000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b5b505600a165627a7a72305820c72865e5ecabb871af3a094cd33460f53c2b467dd2a6be7e049e36eafcb01fa20029", 37 | "networks": {}, 38 | "schema_version": "0.0.5", 39 | "updated_at": 1506361352317 40 | } -------------------------------------------------------------------------------- /build/contracts/StandardToken.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "StandardToken", 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "inputs": [ 7 | { 8 | "name": "_spender", 9 | "type": "address" 10 | }, 11 | { 12 | "name": "_value", 13 | "type": "uint256" 14 | } 15 | ], 16 | "name": "approve", 17 | "outputs": [ 18 | { 19 | "name": "success", 20 | "type": "bool" 21 | } 22 | ], 23 | "payable": false, 24 | "type": "function" 25 | }, 26 | { 27 | "constant": true, 28 | "inputs": [], 29 | "name": "totalSupply", 30 | "outputs": [ 31 | { 32 | "name": "", 33 | "type": "uint256" 34 | } 35 | ], 36 | "payable": false, 37 | "type": "function" 38 | }, 39 | { 40 | "constant": false, 41 | "inputs": [ 42 | { 43 | "name": "_from", 44 | "type": "address" 45 | }, 46 | { 47 | "name": "_to", 48 | "type": "address" 49 | }, 50 | { 51 | "name": "_value", 52 | "type": "uint256" 53 | } 54 | ], 55 | "name": "transferFrom", 56 | "outputs": [ 57 | { 58 | "name": "success", 59 | "type": "bool" 60 | } 61 | ], 62 | "payable": false, 63 | "type": "function" 64 | }, 65 | { 66 | "constant": true, 67 | "inputs": [ 68 | { 69 | "name": "_owner", 70 | "type": "address" 71 | } 72 | ], 73 | "name": "balanceOf", 74 | "outputs": [ 75 | { 76 | "name": "balance", 77 | "type": "uint256" 78 | } 79 | ], 80 | "payable": false, 81 | "type": "function" 82 | }, 83 | { 84 | "constant": false, 85 | "inputs": [ 86 | { 87 | "name": "_to", 88 | "type": "address" 89 | }, 90 | { 91 | "name": "_value", 92 | "type": "uint256" 93 | } 94 | ], 95 | "name": "transfer", 96 | "outputs": [ 97 | { 98 | "name": "success", 99 | "type": "bool" 100 | } 101 | ], 102 | "payable": false, 103 | "type": "function" 104 | }, 105 | { 106 | "constant": true, 107 | "inputs": [ 108 | { 109 | "name": "_owner", 110 | "type": "address" 111 | }, 112 | { 113 | "name": "_spender", 114 | "type": "address" 115 | } 116 | ], 117 | "name": "allowance", 118 | "outputs": [ 119 | { 120 | "name": "remaining", 121 | "type": "uint256" 122 | } 123 | ], 124 | "payable": false, 125 | "type": "function" 126 | }, 127 | { 128 | "inputs": [], 129 | "payable": false, 130 | "type": "constructor" 131 | }, 132 | { 133 | "anonymous": false, 134 | "inputs": [ 135 | { 136 | "indexed": true, 137 | "name": "_from", 138 | "type": "address" 139 | }, 140 | { 141 | "indexed": true, 142 | "name": "_to", 143 | "type": "address" 144 | }, 145 | { 146 | "indexed": false, 147 | "name": "_value", 148 | "type": "uint256" 149 | } 150 | ], 151 | "name": "Transfer", 152 | "type": "event" 153 | }, 154 | { 155 | "anonymous": false, 156 | "inputs": [ 157 | { 158 | "indexed": true, 159 | "name": "_owner", 160 | "type": "address" 161 | }, 162 | { 163 | "indexed": true, 164 | "name": "_spender", 165 | "type": "address" 166 | }, 167 | { 168 | "indexed": false, 169 | "name": "_value", 170 | "type": "uint256" 171 | } 172 | ], 173 | "name": "Approval", 174 | "type": "event" 175 | } 176 | ], 177 | "unlinked_binary": "0x6060604052341561000f57600080fd5b5b600160a060020a033316600090815260016020526040812068056bc75e2d631000009081905590555b5b610419806100496000396000f300606060405236156100755763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663095ea7b3811461007a57806318160ddd146100b057806323b872dd146100d557806370a0823114610111578063a9059cbb14610142578063dd62ed3e14610178575b600080fd5b341561008557600080fd5b61009c600160a060020a03600435166024356101af565b604051901515815260200160405180910390f35b34156100bb57600080fd5b6100c361021c565b60405190815260200160405180910390f35b34156100e057600080fd5b61009c600160a060020a0360043581169060243516604435610222565b604051901515815260200160405180910390f35b341561011c57600080fd5b6100c3600160a060020a036004351661030c565b60405190815260200160405180910390f35b341561014d57600080fd5b61009c600160a060020a036004351660243561032b565b604051901515815260200160405180910390f35b341561018357600080fd5b6100c3600160a060020a03600435811690602435166103c0565b60405190815260200160405180910390f35b600160a060020a03338116600081815260026020908152604080832094871680845294909152808220859055909291907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259085905190815260200160405180910390a35060015b92915050565b60005481565b600160a060020a0383166000908152600160205260408120548290108015906102725750600160a060020a0380851660009081526002602090815260408083203390941683529290522054829010155b151561027d57600080fd5b600160a060020a03808416600081815260016020908152604080832080548801905588851680845281842080548990039055600283528184203390961684529490915290819020805486900390559091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9085905190815260200160405180910390a35060015b9392505050565b600160a060020a0381166000908152600160205260409020545b919050565b600160a060020a0333166000908152600160205260408120548290101561035157600080fd5b600160a060020a033381166000818152600160205260408082208054879003905592861680825290839020805486019055917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9085905190815260200160405180910390a35060015b92915050565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b929150505600a165627a7a72305820688e69cbb7df4d5aa4c531bc651d08f191ab1160951b168fed1e789594e7e8fe0029", 178 | "networks": {}, 179 | "schema_version": "0.0.5", 180 | "updated_at": 1506336725465 181 | } -------------------------------------------------------------------------------- /build/contracts/Token.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "Token", 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "inputs": [ 7 | { 8 | "name": "_spender", 9 | "type": "address" 10 | }, 11 | { 12 | "name": "_value", 13 | "type": "uint256" 14 | } 15 | ], 16 | "name": "approve", 17 | "outputs": [ 18 | { 19 | "name": "success", 20 | "type": "bool" 21 | } 22 | ], 23 | "payable": false, 24 | "type": "function" 25 | }, 26 | { 27 | "constant": true, 28 | "inputs": [], 29 | "name": "totalSupply", 30 | "outputs": [ 31 | { 32 | "name": "", 33 | "type": "uint256" 34 | } 35 | ], 36 | "payable": false, 37 | "type": "function" 38 | }, 39 | { 40 | "constant": false, 41 | "inputs": [ 42 | { 43 | "name": "_from", 44 | "type": "address" 45 | }, 46 | { 47 | "name": "_to", 48 | "type": "address" 49 | }, 50 | { 51 | "name": "_value", 52 | "type": "uint256" 53 | } 54 | ], 55 | "name": "transferFrom", 56 | "outputs": [ 57 | { 58 | "name": "success", 59 | "type": "bool" 60 | } 61 | ], 62 | "payable": false, 63 | "type": "function" 64 | }, 65 | { 66 | "constant": true, 67 | "inputs": [ 68 | { 69 | "name": "_owner", 70 | "type": "address" 71 | } 72 | ], 73 | "name": "balanceOf", 74 | "outputs": [ 75 | { 76 | "name": "balance", 77 | "type": "uint256" 78 | } 79 | ], 80 | "payable": false, 81 | "type": "function" 82 | }, 83 | { 84 | "constant": false, 85 | "inputs": [ 86 | { 87 | "name": "_to", 88 | "type": "address" 89 | }, 90 | { 91 | "name": "_value", 92 | "type": "uint256" 93 | } 94 | ], 95 | "name": "transfer", 96 | "outputs": [ 97 | { 98 | "name": "success", 99 | "type": "bool" 100 | } 101 | ], 102 | "payable": false, 103 | "type": "function" 104 | }, 105 | { 106 | "constant": true, 107 | "inputs": [ 108 | { 109 | "name": "_owner", 110 | "type": "address" 111 | }, 112 | { 113 | "name": "_spender", 114 | "type": "address" 115 | } 116 | ], 117 | "name": "allowance", 118 | "outputs": [ 119 | { 120 | "name": "remaining", 121 | "type": "uint256" 122 | } 123 | ], 124 | "payable": false, 125 | "type": "function" 126 | }, 127 | { 128 | "anonymous": false, 129 | "inputs": [ 130 | { 131 | "indexed": true, 132 | "name": "_from", 133 | "type": "address" 134 | }, 135 | { 136 | "indexed": true, 137 | "name": "_to", 138 | "type": "address" 139 | }, 140 | { 141 | "indexed": false, 142 | "name": "_value", 143 | "type": "uint256" 144 | } 145 | ], 146 | "name": "Transfer", 147 | "type": "event" 148 | }, 149 | { 150 | "anonymous": false, 151 | "inputs": [ 152 | { 153 | "indexed": true, 154 | "name": "_owner", 155 | "type": "address" 156 | }, 157 | { 158 | "indexed": true, 159 | "name": "_spender", 160 | "type": "address" 161 | }, 162 | { 163 | "indexed": false, 164 | "name": "_value", 165 | "type": "uint256" 166 | } 167 | ], 168 | "name": "Approval", 169 | "type": "event" 170 | } 171 | ], 172 | "unlinked_binary": "0x", 173 | "networks": {}, 174 | "schema_version": "0.0.5", 175 | "updated_at": 1506336725465 176 | } -------------------------------------------------------------------------------- /contracts/KyberAirDrop.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | import "./Ownable.sol"; 3 | import "./KyberGenesisToken.sol"; 4 | 5 | contract KyberAirDrop is Ownable { 6 | uint public numDrops; 7 | uint public dropAmount; 8 | 9 | function KyberAirDrop( address dropper ) { 10 | transferOwnership(dropper); 11 | } 12 | 13 | event TokenDrop( address receiver, uint amount ); 14 | function airDrop( ERC20Interface token, 15 | address tokenRepo, 16 | address[] recipients, 17 | uint amount, 18 | bool kgt, 19 | KyberGenesisToken kgtToken ) onlyOwner { 20 | require( amount == 0 || amount == (2*(10**18)) || amount == (5*(10**18)) ); 21 | 22 | if( amount > 0 ) { 23 | for( uint i = 0 ; i < recipients.length ; i++ ) { 24 | assert( token.transferFrom( tokenRepo, recipients[i], amount ) ); 25 | TokenDrop( recipients[i], amount ); 26 | } 27 | } 28 | 29 | if( kgt ) { 30 | kgtToken.mint(recipients); 31 | } 32 | 33 | numDrops += recipients.length; 34 | dropAmount += recipients.length * amount; 35 | } 36 | 37 | function tranferMinterOwnership( KyberGenesisToken kgtToken, address newOwner ) onlyOwner { 38 | kgtToken.transferOwnership(newOwner); 39 | } 40 | 41 | function emergencyERC20Drain( ERC20Interface token, uint amount ) { 42 | // callable by anyone 43 | address kyberMultisig = 0x3EB01B3391EA15CE752d01Cf3D3F09deC596F650; 44 | token.transfer( kyberMultisig, amount ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /contracts/KyberGenesisToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | import "./Ownable.sol"; 3 | 4 | contract ERC20Interface { 5 | function transferFrom(address _from, address _to, uint _value) returns (bool){} 6 | function transfer(address _to, uint _value) returns (bool){} 7 | function ERC20Interface(){} 8 | } 9 | 10 | contract KyberGenesisToken is Ownable { 11 | string public constant name = "Kyber Genesis Token"; 12 | string public constant symbol = "KGT"; 13 | uint public constant decimals = 0; 14 | 15 | uint public totalSupply = 0; 16 | mapping(address=>uint) public balanceOf; 17 | 18 | function KyberGenesisToken( address minter ) { 19 | transferOwnership(minter); 20 | } 21 | 22 | event Transfer(address indexed _from, address indexed _to, uint _value); 23 | event EndMinting( uint timestamp ); 24 | 25 | function mint( address[] recipients ) onlyOwner { 26 | uint newRecipients = 0; 27 | for( uint i = 0 ; i < recipients.length ; i++ ){ 28 | address recipient = recipients[i]; 29 | if( balanceOf[recipient] == 0 ){ 30 | Transfer( address(0x0), recipient, 1 ); 31 | balanceOf[recipient] = 1; 32 | newRecipients++; 33 | } 34 | } 35 | 36 | totalSupply += newRecipients; 37 | } 38 | 39 | function endMinting() onlyOwner { 40 | transferOwnership(address(0xdead)); 41 | EndMinting(block.timestamp); 42 | } 43 | 44 | function burn() { 45 | require(balanceOf[msg.sender] == 1 ); 46 | Transfer( msg.sender, address(0x0), 1 ); 47 | balanceOf[msg.sender] = 0; 48 | totalSupply--; 49 | } 50 | 51 | function emergencyERC20Drain( ERC20Interface token, uint amount ){ 52 | // callable by anyone 53 | address kyberMultisig = 0x3EB01B3391EA15CE752d01Cf3D3F09deC596F650; 54 | token.transfer( kyberMultisig, amount ); 55 | } 56 | 57 | 58 | // ERC20 stubs 59 | function transfer(address _to, uint _value) returns (bool){ revert(); } 60 | function transferFrom(address _from, address _to, uint _value) returns (bool){ revert(); } 61 | function approve(address _spender, uint _value) returns (bool){ revert(); } 62 | function allowance(address _owner, address _spender) constant returns (uint){ return 0; } 63 | event Approval(address indexed _owner, address indexed _spender, uint _value); 64 | } 65 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.4; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | modifier restricted() { 8 | if (msg.sender == owner) _; 9 | } 10 | 11 | function Migrations() { 12 | owner = msg.sender; 13 | } 14 | 15 | function setCompleted(uint completed) restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contracts/Ownable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | 3 | 4 | /** 5 | * @title Ownable 6 | * @dev The Ownable contract has an owner address, and provides basic authorization control 7 | * functions, this simplifies the implementation of "user permissions". 8 | */ 9 | contract Ownable { 10 | address public owner; 11 | 12 | 13 | /** 14 | * @dev The Ownable constructor sets the original `owner` of the contract to the sender 15 | * account. 16 | */ 17 | function Ownable() { 18 | owner = msg.sender; 19 | } 20 | 21 | 22 | /** 23 | * @dev Throws if called by any account other than the owner. 24 | */ 25 | modifier onlyOwner() { 26 | require(msg.sender == owner); 27 | _; 28 | } 29 | 30 | 31 | /** 32 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 33 | * @param newOwner The address to transfer ownership to. 34 | */ 35 | function transferOwnership(address newOwner) onlyOwner { 36 | if (newOwner != address(0)) { 37 | owner = newOwner; 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /contracts/StandardToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | 3 | contract Token { 4 | /* This is a slight change to the ERC20 base standard. 5 | function totalSupply() constant returns (uint256 supply); 6 | is replaced with: 7 | uint256 public totalSupply; 8 | This automatically creates a getter function for the totalSupply. 9 | This is moved to the base contract since public getter functions are not 10 | currently recognised as an implementation of the matching abstract 11 | function by the compiler. 12 | */ 13 | /// total amount of tokens 14 | uint256 public totalSupply; 15 | 16 | /// @param _owner The address from which the balance will be retrieved 17 | /// @return The balance 18 | function balanceOf(address _owner) constant returns (uint256 balance); 19 | 20 | /// @notice send `_value` token to `_to` from `msg.sender` 21 | /// @param _to The address of the recipient 22 | /// @param _value The amount of token to be transferred 23 | /// @return Whether the transfer was successful or not 24 | function transfer(address _to, uint256 _value) returns (bool success); 25 | 26 | /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` 27 | /// @param _from The address of the sender 28 | /// @param _to The address of the recipient 29 | /// @param _value The amount of token to be transferred 30 | /// @return Whether the transfer was successful or not 31 | function transferFrom(address _from, address _to, uint256 _value) returns (bool success); 32 | 33 | /// @notice `msg.sender` approves `_spender` to spend `_value` tokens 34 | /// @param _spender The address of the account able to transfer the tokens 35 | /// @param _value The amount of tokens to be approved for transfer 36 | /// @return Whether the approval was successful or not 37 | function approve(address _spender, uint256 _value) returns (bool success); 38 | 39 | /// @param _owner The address of the account owning tokens 40 | /// @param _spender The address of the account able to transfer the tokens 41 | /// @return Amount of remaining tokens allowed to spent 42 | function allowance(address _owner, address _spender) constant returns (uint256 remaining); 43 | 44 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 45 | event Approval(address indexed _owner, address indexed _spender, uint256 _value); 46 | } 47 | contract StandardToken is Token { 48 | function StandardToken() { 49 | balances[msg.sender] = 100 * 10**18; 50 | totalSupply = 100 * 10**18; 51 | } 52 | function transfer(address _to, uint256 _value) returns (bool success) { 53 | //Default assumes totalSupply can't be over max (2^256 - 1). 54 | //If your token leaves out totalSupply and can issue more tokens as time goes on, you need to check if it doesn't wrap. 55 | //Replace the if with this one instead. 56 | //require(balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]); 57 | require(balances[msg.sender] >= _value); 58 | balances[msg.sender] -= _value; 59 | balances[_to] += _value; 60 | Transfer(msg.sender, _to, _value); 61 | return true; 62 | } 63 | 64 | function transferFrom(address _from, address _to, uint256 _value) returns (bool success) { 65 | //same as above. Replace this line with the following if you want to protect against wrapping uints. 66 | //require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]); 67 | require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value); 68 | balances[_to] += _value; 69 | balances[_from] -= _value; 70 | allowed[_from][msg.sender] -= _value; 71 | Transfer(_from, _to, _value); 72 | return true; 73 | } 74 | 75 | function balanceOf(address _owner) constant returns (uint256 balance) { 76 | return balances[_owner]; 77 | } 78 | 79 | function approve(address _spender, uint256 _value) returns (bool success) { 80 | allowed[msg.sender][_spender] = _value; 81 | Approval(msg.sender, _spender, _value); 82 | return true; 83 | } 84 | 85 | function allowance(address _owner, address _spender) constant returns (uint256 remaining) { 86 | return allowed[_owner][_spender]; 87 | } 88 | 89 | mapping (address => uint256) balances; 90 | mapping (address => mapping (address => uint256)) allowed; 91 | } 92 | -------------------------------------------------------------------------------- /kgt_tracker.js: -------------------------------------------------------------------------------- 1 | var BigNumber = require('bignumber.js'); 2 | var Tx = require('ethereumjs-tx'); 3 | var Web3 = require('web3'); 4 | const ethjsaccount = require('ethjs-account'); 5 | const signer = require('ethjs-signer') 6 | 7 | var gasLimit = new BigNumber( 100000 ); 8 | var kgtAddress = "0xfce10cbf5171dc12c215bbcca5dd75cbaea72506"; 9 | 10 | 11 | url = "http://localhost:8545/jsonrpc"; 12 | 13 | var web3 = new Web3(new Web3.providers.HttpProvider(url)); 14 | 15 | 16 | var kgtABI = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"burn","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"recipients","type":"address[]"}],"name":"mint","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"amount","type":"uint256"}],"name":"emergencyERC20Drain","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"endMinting","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"minter","type":"address"}],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"timestamp","type":"uint256"}],"name":"EndMinting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]; 17 | 18 | 19 | 20 | var kgt = new web3.eth.Contract(kgtABI,kgtAddress); 21 | kgt.getPastEvents('Transfer', { 22 | filter:{_from:"0x0000000000000000000000000000000000000000"}, 23 | fromBlock: 0, 24 | toBlock: 'latest' 25 | }, function(error, events){ 26 | for ( var i = 0 ; i < events.length ; i++ ) { 27 | console.log(events[i].returnValues._to); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | //var Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | //deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | var BigNumber = require('bignumber.js'); 2 | var GenToken = artifacts.require("./KyberGenesisToken.sol"); 3 | var AirDrop = artifacts.require("./KyberAirDrop.sol"); 4 | 5 | var dropper = "0xcBAC9e86E0B7160F1a8E4835ad01Dd51c514afce"; 6 | 7 | 8 | module.exports = function(deployer) { 9 | return AirDrop.new(dropper,{gas:500*1000,gasPrice:41*1000*1000*1000}).then(function(instance){ 10 | console.log(instance.address); 11 | return GenToken.new(instance.address,{gas:4000000,gasPrice:61*1000*1000*1000}); 12 | }); 13 | }; 14 | 15 | //00000000000000000000cBAC9e86E0B7160F1a8E4835ad01Dd51c514afce 16 | -------------------------------------------------------------------------------- /monitor.js: -------------------------------------------------------------------------------- 1 | var BigNumber = require('bignumber.js'); 2 | var Tx = require('ethereumjs-tx'); 3 | var Web3 = require('web3'); 4 | const ethjsaccount = require('ethjs-account'); 5 | const signer = require('ethjs-signer') 6 | 7 | var gasLimit = new BigNumber( 100000 ); 8 | var airdropAddress = "0x9148AB505Fd9eaB5141b2b36Ce815E2786b7f7cd"; 9 | 10 | 11 | url = "http://localhost:8545/jsonrpc"; 12 | 13 | var web3 = new Web3(new Web3.providers.HttpProvider(url)); 14 | 15 | 16 | var airdropABI =[ 17 | { 18 | "constant": true, 19 | "inputs": [], 20 | "name": "dropAmount", 21 | "outputs": [ 22 | { 23 | "name": "", 24 | "type": "uint256" 25 | } 26 | ], 27 | "payable": false, 28 | "type": "function" 29 | }, 30 | { 31 | "constant": false, 32 | "inputs": [ 33 | { 34 | "name": "token", 35 | "type": "address" 36 | }, 37 | { 38 | "name": "tokenRepo", 39 | "type": "address" 40 | }, 41 | { 42 | "name": "recipients", 43 | "type": "address[]" 44 | }, 45 | { 46 | "name": "amount", 47 | "type": "uint256" 48 | }, 49 | { 50 | "name": "kgt", 51 | "type": "bool" 52 | }, 53 | { 54 | "name": "kgtToken", 55 | "type": "address" 56 | } 57 | ], 58 | "name": "airDrop", 59 | "outputs": [], 60 | "payable": false, 61 | "type": "function" 62 | }, 63 | { 64 | "constant": true, 65 | "inputs": [], 66 | "name": "numDrops", 67 | "outputs": [ 68 | { 69 | "name": "", 70 | "type": "uint256" 71 | } 72 | ], 73 | "payable": false, 74 | "type": "function" 75 | }, 76 | { 77 | "constant": true, 78 | "inputs": [], 79 | "name": "owner", 80 | "outputs": [ 81 | { 82 | "name": "", 83 | "type": "address" 84 | } 85 | ], 86 | "payable": false, 87 | "type": "function" 88 | }, 89 | { 90 | "constant": false, 91 | "inputs": [ 92 | { 93 | "name": "kgtToken", 94 | "type": "address" 95 | }, 96 | { 97 | "name": "newOwner", 98 | "type": "address" 99 | } 100 | ], 101 | "name": "tranferMinterOwnership", 102 | "outputs": [], 103 | "payable": false, 104 | "type": "function" 105 | }, 106 | { 107 | "constant": false, 108 | "inputs": [ 109 | { 110 | "name": "newOwner", 111 | "type": "address" 112 | } 113 | ], 114 | "name": "transferOwnership", 115 | "outputs": [], 116 | "payable": false, 117 | "type": "function" 118 | }, 119 | { 120 | "inputs": [ 121 | { 122 | "name": "dropper", 123 | "type": "address" 124 | } 125 | ], 126 | "payable": false, 127 | "type": "constructor" 128 | }, 129 | { 130 | "anonymous": false, 131 | "inputs": [ 132 | { 133 | "indexed": false, 134 | "name": "receiver", 135 | "type": "address" 136 | }, 137 | { 138 | "indexed": false, 139 | "name": "amount", 140 | "type": "uint256" 141 | } 142 | ], 143 | "name": "TokenDrop", 144 | "type": "event" 145 | } 146 | ]; 147 | 148 | 149 | 150 | var airdrop = new web3.eth.Contract(airdropABI,airdropAddress); 151 | airdrop.getPastEvents('TokenDrop', { 152 | fromBlock: 0, 153 | toBlock: 'latest' 154 | }, function(error, events){ 155 | for ( var i = 0 ; i < events.length ; i++ ) { 156 | console.log(events[i].returnValues.receiver); 157 | } 158 | }); 159 | -------------------------------------------------------------------------------- /test/airdrop.js: -------------------------------------------------------------------------------- 1 | var Token = artifacts.require("./StandardToken.sol"); 2 | var BigNumber = require('bignumber.js'); 3 | var Helpers = require('./helpers.js'); 4 | var GenToken = artifacts.require("./KyberGenesisToken.sol"); 5 | var AirDrop = artifacts.require("./KyberAirDrop.sol"); 6 | 7 | var tokenOwner; 8 | var airDropOwner; 9 | var nonOwner; 10 | var genToken; 11 | var token; 12 | var airDrop; 13 | 14 | var expectedBalance; 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | contract('gen token', function(accounts) { 18 | 19 | beforeEach(function(done){ 20 | done(); 21 | }); 22 | afterEach(function(done){ 23 | done(); 24 | }); 25 | 26 | it("init token", function() { 27 | tokenOwner = accounts[0]; 28 | return Token.new({from:tokenOwner}).then(function(instance){ 29 | token = instance; 30 | return token.balanceOf(tokenOwner); 31 | }).then(function(result){ 32 | expectedBalance = new BigNumber(result); 33 | }); 34 | }); 35 | 36 | it("init airdrop", function() { 37 | airDropOwner = accounts[1]; 38 | nonOwner = accounts[2]; 39 | return AirDrop.new({from:airDropOwner}).then(function(instance){ 40 | airDrop = instance; 41 | return token.approve(airDrop.address, new BigNumber(10).pow(50)); 42 | }); 43 | }); 44 | 45 | it("init gen token", function() { 46 | return GenToken.new(airDrop.address).then(function(instance){ 47 | genToken = instance; 48 | }); 49 | }); 50 | 51 | it("drop gen and 2 knc", function() { 52 | var recipients = [accounts[3], accounts[4]]; 53 | var amount = new BigNumber(10**18 * 2); 54 | expectedBalance = expectedBalance.minus(amount*2); 55 | return airDrop.airDrop(token.address, 56 | tokenOwner, 57 | recipients, 58 | amount, 59 | true, 60 | genToken.address, 61 | {from:airDropOwner}).then(function(){ 62 | // check balance of original token 63 | return token.balanceOf(recipients[0]); 64 | }).then(function(result){ 65 | assert.equal(result.valueOf(), amount.valueOf(), "unexpected result"); 66 | return token.balanceOf(recipients[1]); 67 | }).then(function(result){ 68 | assert.equal(result.valueOf(), amount.valueOf(), "unexpected result"); 69 | return genToken.balanceOf(recipients[0]); 70 | }).then(function(result){ 71 | assert.equal(result.valueOf(), new BigNumber(1).valueOf(), "unexpected result"); 72 | return genToken.balanceOf(recipients[1]); 73 | }).then(function(result){ 74 | assert.equal(result.valueOf(), new BigNumber(1).valueOf(), "unexpected result"); 75 | return token.balanceOf(tokenOwner); 76 | }).then(function(result){ 77 | assert.equal(result.valueOf(), expectedBalance.valueOf(), "unexpected balance"); 78 | }); 79 | }); 80 | 81 | it("drop gen and 5 knc", function() { 82 | var recipients = [accounts[5], accounts[6]]; 83 | var amount = new BigNumber(10**18 * 5); 84 | expectedBalance = expectedBalance.minus(amount*2); 85 | return airDrop.airDrop(token.address, 86 | tokenOwner, 87 | recipients, 88 | amount, 89 | true, 90 | genToken.address, 91 | {from:airDropOwner}).then(function(){ 92 | // check balance of original token 93 | return token.balanceOf(recipients[0]); 94 | }).then(function(result){ 95 | assert.equal(result.valueOf(), amount.valueOf(), "unexpected result"); 96 | return token.balanceOf(recipients[1]); 97 | }).then(function(result){ 98 | assert.equal(result.valueOf(), amount.valueOf(), "unexpected result"); 99 | return genToken.balanceOf(recipients[0]); 100 | }).then(function(result){ 101 | assert.equal(result.valueOf(), new BigNumber(1).valueOf(), "unexpected result"); 102 | return genToken.balanceOf(recipients[1]); 103 | }).then(function(result){ 104 | assert.equal(result.valueOf(), new BigNumber(1).valueOf(), "unexpected result"); 105 | return token.balanceOf(tokenOwner); 106 | }).then(function(result){ 107 | assert.equal(result.valueOf(), expectedBalance.valueOf(), "unexpected balance"); 108 | }); 109 | }); 110 | 111 | it("drop 0 gen and 5 knc", function() { 112 | var recipients = [accounts[7], accounts[8]]; 113 | var amount = new BigNumber(10**18 * 5); 114 | expectedBalance = expectedBalance.minus(amount*2); 115 | return airDrop.airDrop(token.address, 116 | tokenOwner, 117 | recipients, 118 | amount, 119 | false, 120 | genToken.address, 121 | {from:airDropOwner}).then(function(){ 122 | // check balance of original token 123 | return token.balanceOf(recipients[0]); 124 | }).then(function(result){ 125 | assert.equal(result.valueOf(), amount.valueOf(), "unexpected result"); 126 | return token.balanceOf(recipients[1]); 127 | }).then(function(result){ 128 | assert.equal(result.valueOf(), amount.valueOf(), "unexpected result"); 129 | return genToken.balanceOf(recipients[0]); 130 | }).then(function(result){ 131 | assert.equal(result.valueOf(), new BigNumber(0).valueOf(), "unexpected result"); 132 | return genToken.balanceOf(recipients[1]); 133 | }).then(function(result){ 134 | assert.equal(result.valueOf(), new BigNumber(0).valueOf(), "unexpected result"); 135 | return token.balanceOf(tokenOwner); 136 | }).then(function(result){ 137 | assert.equal(result.valueOf(), expectedBalance.valueOf(), "unexpected balance"); 138 | }); 139 | }); 140 | 141 | it("drop 1 gen and 0 knc", function() { 142 | var recipients = [accounts[1], accounts[2]]; 143 | var amount = new BigNumber(0); 144 | expectedBalance = expectedBalance.minus(amount*2); 145 | return airDrop.airDrop(token.address, 146 | tokenOwner, 147 | recipients, 148 | amount, 149 | false, 150 | genToken.address, 151 | {from:airDropOwner}).then(function(){ 152 | // check balance of original token 153 | return token.balanceOf(recipients[0]); 154 | }).then(function(result){ 155 | assert.equal(result.valueOf(), amount.valueOf(), "unexpected result"); 156 | return token.balanceOf(recipients[1]); 157 | }).then(function(result){ 158 | assert.equal(result.valueOf(), amount.valueOf(), "unexpected result"); 159 | return genToken.balanceOf(recipients[0]); 160 | }).then(function(result){ 161 | assert.equal(result.valueOf(), new BigNumber(0).valueOf(), "unexpected result"); 162 | return genToken.balanceOf(recipients[1]); 163 | }).then(function(result){ 164 | assert.equal(result.valueOf(), new BigNumber(0).valueOf(), "unexpected result"); 165 | return token.balanceOf(tokenOwner); 166 | }).then(function(result){ 167 | assert.equal(result.valueOf(), expectedBalance.valueOf(), "unexpected balance"); 168 | }); 169 | }); 170 | 171 | it("drop 0 gen and 7 knc", function() { 172 | var recipients = [accounts[9], accounts[0]]; 173 | var amount = new BigNumber(10**18 * 7); 174 | return airDrop.airDrop(token.address, 175 | tokenOwner, 176 | recipients, 177 | amount, 178 | false, 179 | genToken.address, 180 | {from:airDropOwner}).then(function(){ 181 | // check balance of original token 182 | assert.fail("expected to throw"); 183 | }).catch(function(error){ 184 | assert( Helpers.throwErrorMessage(error), "expected throw got " + error); 185 | }); 186 | }); 187 | 188 | it("drop 0 gen and 5 knc from non owner", function() { 189 | var recipients = [accounts[9], accounts[0]]; 190 | var amount = new BigNumber(10**18 * 5); 191 | return airDrop.airDrop(token.address, 192 | tokenOwner, 193 | recipients, 194 | amount, 195 | false, 196 | genToken.address, 197 | {from:nonOwner}).then(function(){ 198 | // check balance of original token 199 | assert.fail("expected to throw"); 200 | }).catch(function(error){ 201 | assert( Helpers.throwErrorMessage(error), "expected throw got " + error); 202 | }); 203 | }); 204 | 205 | it("change kgt owner from non owner", function() { 206 | return airDrop.tranferMinterOwnership(genToken.address, 207 | accounts[9], 208 | {from:nonOwner} ).then(function(){ 209 | // check balance of original token 210 | assert.fail("expected to throw"); 211 | }).catch(function(error){ 212 | assert( Helpers.throwErrorMessage(error), "expected throw got " + error); 213 | }); 214 | }); 215 | 216 | it("change kgt owner from owner", function() { 217 | var newOwner = accounts[5]; 218 | return airDrop.tranferMinterOwnership(genToken.address, 219 | newOwner, 220 | {from:airDropOwner} ).then(function(){ 221 | // end minting in gen token 222 | return genToken.endMinting({from:newOwner}); 223 | }).then(function(result){ 224 | assert.equal("EndMinting", result.logs[0].event,"unexpected event"); 225 | }); 226 | }); 227 | 228 | 229 | }); 230 | -------------------------------------------------------------------------------- /test/gentoken.js: -------------------------------------------------------------------------------- 1 | var Token = artifacts.require("./StandardToken.sol"); 2 | var BigNumber = require('bignumber.js'); 3 | var Helpers = require('./helpers.js'); 4 | var GenToken = artifacts.require("./KyberGenesisToken.sol"); 5 | var AirDrop = artifacts.require("./KyberAirDrop.sol"); 6 | 7 | var owner; 8 | var airDropOwner; 9 | var nonOwner; 10 | var genToken; 11 | var token; 12 | var airDrop; 13 | //////////////////////////////////////////////////////////////////////////////// 14 | 15 | contract('gen token', function(accounts) { 16 | 17 | beforeEach(function(done){ 18 | done(); 19 | }); 20 | afterEach(function(done){ 21 | done(); 22 | }); 23 | 24 | it("init token", function() { 25 | owner = accounts[1]; 26 | nonOwner = accounts[2]; 27 | return GenToken.new(accounts[1]).then(function(instance){ 28 | genToken = instance; 29 | }); 30 | }); 31 | 32 | it("mint 3 addresses from owner", function() { 33 | var value = new BigNumber(1); 34 | return genToken.mint([accounts[0], accounts[1], accounts[2]],{from:owner}).then(function(){ 35 | return genToken.balanceOf(accounts[0]); 36 | }).then(function(result){ 37 | assert.equal(result.valueOf(), value.valueOf(), "unexpected balance" ); 38 | return genToken.balanceOf(accounts[1]); 39 | }).then(function(result){ 40 | assert.equal(result.valueOf(), value.valueOf(), "unexpected balance" ); 41 | return genToken.balanceOf(accounts[2]); 42 | }).then(function(result){ 43 | assert.equal(result.valueOf(), value.valueOf(), "unexpected balance" ); 44 | return genToken.balanceOf(accounts[3]); 45 | }).then(function(result){ 46 | assert.equal(result.valueOf(), (new BigNumber(0)).valueOf(), "unexpected balance" ); 47 | }); 48 | }); 49 | 50 | it("mint 3 addresses from non owner", function() { 51 | return genToken.mint([accounts[4], accounts[5], accounts[6]],{from:nonOwner}).then(function(){ 52 | assert.fail("expected to throw"); 53 | }).catch(function(error){ 54 | assert( Helpers.throwErrorMessage(error), "expected throw got " + error); 55 | }); 56 | }); 57 | 58 | it("burn from holder", function() { 59 | return genToken.burn({from:accounts[0]}).then(function(){ 60 | return genToken.balanceOf(accounts[0]); 61 | }).then(function(result){ 62 | assert.equal(result.valueOf(), (new BigNumber(0)).valueOf(), "unexpected balance" ); 63 | return genToken.balanceOf(accounts[1]); 64 | }).then(function(result){ 65 | assert.equal(result.valueOf(), (new BigNumber(1)).valueOf(), "unexpected balance" ); 66 | }) 67 | }); 68 | 69 | it("burn from non holder", function() { 70 | return genToken.burn({from:accounts[3]}).then(function(){ 71 | assert.fail("expected to throw"); 72 | }).catch(function(error){ 73 | assert( Helpers.throwErrorMessage(error), "expected throw got " + error); 74 | }); 75 | }); 76 | 77 | it("end minting from non owner", function() { 78 | return genToken.endMinting({from:nonOwner}).then(function(){ 79 | assert.fail("expected to throw"); 80 | }).catch(function(error){ 81 | assert( Helpers.throwErrorMessage(error), "expected throw got " + error); 82 | }); 83 | }); 84 | 85 | it("end minting from owner", function() { 86 | return genToken.endMinting({from:owner}).then(function(){ 87 | return genToken.owner(); 88 | }).then(function(result){ 89 | assert.equal(result.valueOf(), "0x000000000000000000000000000000000000dead", "unexpected owner"); 90 | }); 91 | }); 92 | 93 | it("mint 3 addresses from old owner after end of minting", function() { 94 | return genToken.mint([accounts[4], accounts[5], accounts[6]],{from:owner}).then(function(){ 95 | assert.fail("expected to throw"); 96 | }).catch(function(error){ 97 | assert( Helpers.throwErrorMessage(error), "expected throw got " + error); 98 | }); 99 | }); 100 | }); 101 | -------------------------------------------------------------------------------- /test/helpers.js: -------------------------------------------------------------------------------- 1 | var BigNumber = require('bignumber.js'); 2 | 3 | var m_w = 123456789; 4 | var m_z = 987654321; 5 | var mask = 0xffffffff; 6 | 7 | // Takes any integer 8 | function seed(i) { 9 | m_w = i; 10 | m_z = 987654321; 11 | } 12 | 13 | // Returns number between 0 (inclusive) and 1.0 (exclusive), 14 | // just like Math.random(). 15 | function random() 16 | { 17 | m_z = (36969 * (m_z & 65535) + (m_z >> 16)) & mask; 18 | m_w = (18000 * (m_w & 65535) + (m_w >> 16)) & mask; 19 | var result = ((m_z << 16) + m_w) & mask; 20 | result /= 4294967296; 21 | return result + 0.5; 22 | } 23 | 24 | module.exports.setSeed = function(i) { seed(i);}; 25 | 26 | module.exports.getRandomInt = function (min, max) { 27 | min = Math.ceil(min); 28 | max = Math.floor(max); 29 | return Math.floor(random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive 30 | }; 31 | 32 | //////////////////////////////////////////////////////////////////////////////// 33 | 34 | module.exports.getRandomBigInt = function() { 35 | var string = "0x"; 36 | for( var i = 0 ; i < 28 ; i++ ) { 37 | var rand = module.exports.getRandomInt(0,256); 38 | string += Number(rand).toString(16); 39 | } 40 | 41 | return (new BigNumber(string)).absoluteValue(); 42 | }; 43 | 44 | //////////////////////////////////////////////////////////////////////////////// 45 | 46 | module.exports.getRandomBigIntCapped = function( cap ) { 47 | var num = module.exports.getRandomBigInt(); 48 | if( num.greaterThanOrEqualTo( cap ) ) { 49 | if( cap.eq( new BigNumber(0) ) ) return cap; 50 | return num.modulo(cap); 51 | } 52 | else return num.absoluteValue(); 53 | }; 54 | 55 | 56 | 57 | //////////////////////////////////////////////////////////////////////////////// 58 | 59 | module.exports.getRandomAccount = function(accounts) { 60 | var numAccounts = accounts.length; 61 | return accounts[module.exports.getRandomInt(0,numAccounts)]; 62 | }; 63 | 64 | //////////////////////////////////////////////////////////////////////////////// 65 | 66 | module.exports.getRandomDifferentAccount = function(accounts, currentAccount ) { 67 | if( accounts.length <= 1 ) return null; 68 | var result; 69 | do { 70 | result = module.exports.getRandomAccount(accounts); 71 | } while( result == currentAccount ); 72 | 73 | return result; 74 | }; 75 | 76 | //////////////////////////////////////////////////////////////////////////////// 77 | 78 | module.exports.sendPromise = function(method, params) { 79 | return new Promise(function(fulfill, reject){ 80 | web3.currentProvider.sendAsync({ 81 | jsonrpc: '2.0', 82 | method, 83 | params: params || [], 84 | id: new Date().getTime() 85 | }, function(err,result) { 86 | if (err) { 87 | reject(err); 88 | } 89 | else { 90 | fulfill(result); 91 | } 92 | }); 93 | }); 94 | }; 95 | 96 | //////////////////////////////////////////////////////////////////////////////// 97 | 98 | module.exports.throwErrorMessage = function( error ) { 99 | if( error.message.search('invalid opcode') >= 0 ) return true; 100 | if( error.message.search('out of gas') >= 0 ) return true; 101 | return false; 102 | }; 103 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "localhost", 5 | port: 8545, 6 | network_id: "*" // Match any network id 7 | } 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /upload.js: -------------------------------------------------------------------------------- 1 | var BigNumber = require('bignumber.js'); 2 | var Tx = require('ethereumjs-tx'); 3 | var Web3 = require('web3'); 4 | const ethjsaccount = require('ethjs-account'); 5 | const signer = require('ethjs-signer') 6 | 7 | var gasLimit = new BigNumber( 100000 ); 8 | 9 | 10 | 11 | var kyberCrystalAddress = "0xdd974d5c2e2928dea5f71b9825b8b646686bd200"; 12 | var kyberMultisigWalletAddress = "0x8180a5CA4E3B94045e05A9313777955f7518D757"; 13 | var kgtAddress = "0xfCe10CBf5171dc12c215BbCCa5DD75cbAEa72506"; 14 | var airdropAddress = "0x9148AB505Fd9eaB5141b2b36Ce815E2786b7f7cd"; 15 | 16 | var request = require('request'); 17 | var sendRawTx = function( tx, nonce, callback ) { 18 | // Set the headers 19 | var headers = { 20 | //'User-Agent': 'Super Agent/0.0.1', 21 | 'Content-Type': 'Content-Type: application/json', 22 | }; 23 | 24 | // Configure the request 25 | var options = { 26 | url: 'https://mainnet.infura.io', 27 | method: 'POST', 28 | headers: headers, 29 | json:true, 30 | body: {"jsonrpc": "2.0",'method': 'eth_sendRawTransaction', 'params': [tx], "id" : parseInt(nonce.toString(10))} 31 | }; 32 | 33 | 34 | request(options, function (error, response, body) { 35 | if (!error && response.statusCode == 200) { 36 | // Print out the response body 37 | callback(null,body); 38 | } 39 | else { 40 | callback(error,null); 41 | } 42 | }); 43 | }; 44 | 45 | 46 | 47 | url = "https://mainnet.infura.io"; 48 | 49 | var web3 = new Web3(new Web3.providers.HttpProvider(url)); 50 | 51 | 52 | //var whitelistAddress = "0x9A98Fd382CC9cC54afb3352bf52A4a7427016e10"; 53 | var airdropABI =[ 54 | { 55 | "constant": true, 56 | "inputs": [], 57 | "name": "dropAmount", 58 | "outputs": [ 59 | { 60 | "name": "", 61 | "type": "uint256" 62 | } 63 | ], 64 | "payable": false, 65 | "type": "function" 66 | }, 67 | { 68 | "constant": false, 69 | "inputs": [ 70 | { 71 | "name": "token", 72 | "type": "address" 73 | }, 74 | { 75 | "name": "tokenRepo", 76 | "type": "address" 77 | }, 78 | { 79 | "name": "recipients", 80 | "type": "address[]" 81 | }, 82 | { 83 | "name": "amount", 84 | "type": "uint256" 85 | }, 86 | { 87 | "name": "kgt", 88 | "type": "bool" 89 | }, 90 | { 91 | "name": "kgtToken", 92 | "type": "address" 93 | } 94 | ], 95 | "name": "airDrop", 96 | "outputs": [], 97 | "payable": false, 98 | "type": "function" 99 | }, 100 | { 101 | "constant": true, 102 | "inputs": [], 103 | "name": "numDrops", 104 | "outputs": [ 105 | { 106 | "name": "", 107 | "type": "uint256" 108 | } 109 | ], 110 | "payable": false, 111 | "type": "function" 112 | }, 113 | { 114 | "constant": true, 115 | "inputs": [], 116 | "name": "owner", 117 | "outputs": [ 118 | { 119 | "name": "", 120 | "type": "address" 121 | } 122 | ], 123 | "payable": false, 124 | "type": "function" 125 | }, 126 | { 127 | "constant": false, 128 | "inputs": [ 129 | { 130 | "name": "kgtToken", 131 | "type": "address" 132 | }, 133 | { 134 | "name": "newOwner", 135 | "type": "address" 136 | } 137 | ], 138 | "name": "tranferMinterOwnership", 139 | "outputs": [], 140 | "payable": false, 141 | "type": "function" 142 | }, 143 | { 144 | "constant": false, 145 | "inputs": [ 146 | { 147 | "name": "newOwner", 148 | "type": "address" 149 | } 150 | ], 151 | "name": "transferOwnership", 152 | "outputs": [], 153 | "payable": false, 154 | "type": "function" 155 | }, 156 | { 157 | "inputs": [ 158 | { 159 | "name": "dropper", 160 | "type": "address" 161 | } 162 | ], 163 | "payable": false, 164 | "type": "constructor" 165 | }, 166 | { 167 | "anonymous": false, 168 | "inputs": [ 169 | { 170 | "indexed": false, 171 | "name": "receiver", 172 | "type": "address" 173 | }, 174 | { 175 | "indexed": false, 176 | "name": "amount", 177 | "type": "uint256" 178 | } 179 | ], 180 | "name": "TokenDrop", 181 | "type": "event" 182 | } 183 | ]; 184 | 185 | 186 | 187 | var airdrop = new web3.eth.Contract(airdropABI,airdropAddress); 188 | 189 | function User( address, cap ) { 190 | this.address = address; 191 | this.cap = cap; 192 | } 193 | 194 | var addresses = [ ]; 195 | var caps = [ ]; 196 | 197 | var list = []; 198 | 199 | //////////////////////////////////////////////////////////////////////////////// 200 | 201 | var signAndSend = function ( userPrivateKey, 202 | txData, 203 | destenationAddress, 204 | value, 205 | nonce, 206 | gasLimit ) { 207 | return new Promise(function (fulfill, reject){ 208 | var userAccount = privateKeyToAddress(userPrivateKey); 209 | console.log(nonce); 210 | var txParams = { 211 | nonce: "0x" + new BigNumber(nonce).toString(16), 212 | gasPrice: new BigNumber(6 * 1000 * 1000 * 1000 + 101), 213 | gasLimit: gasLimit, 214 | to: destenationAddress, 215 | value: "0x" + value.toString(16), 216 | data: txData, 217 | //chainId: 3 218 | }; 219 | 220 | if( destenationAddress === null ) { 221 | delete txParams.to; 222 | } 223 | 224 | var raw = signer.sign(txParams, userPrivateKey); 225 | sendRawTx(raw, new BigNumber(nonce), function(err,result){ 226 | if( err ) reject(err); 227 | else fulfill(result); 228 | }); 229 | }); 230 | }; 231 | 232 | //////////////////////////////////////////////////////////////////////////////// 233 | 234 | var getNoncePromise = function( address ) { 235 | return new Promise(function(fulfill, reject){ 236 | return web3.eth.getTransactionCount(address, function(err,result){ 237 | if( err ) return reject(err); 238 | return fulfill(result); 239 | }); 240 | }); 241 | }; 242 | 243 | //////////////////////////////////////////////////////////////////////////////// 244 | 245 | var uploadListBulk = function( addresses, amount, userPrivateKey, numTxs ) { 246 | var dropContract = airdrop; 247 | return new Promise(function (fulfill, reject){ 248 | var numAddressesInTx = parseInt(addresses.length / numTxs); 249 | var firstIndices = []; 250 | for (var i = 0 ; i < numTxs ; i++ ) { 251 | firstIndices.push( numAddressesInTx * i ); 252 | } 253 | 254 | 255 | return getNoncePromise(privateKeyToAddress(userPrivateKey)).then(function(nonce){ 256 | return firstIndices.reduce(function (promise, item) { 257 | var addressInput = []; 258 | for( var i = 0 ; i < numAddressesInTx ; i++ ) { 259 | var index = i + item; 260 | addressInput.push(addresses[index]); 261 | } 262 | 263 | return promise.then(function () { 264 | var data = dropContract.methods.airDrop(kyberCrystalAddress, 265 | kyberMultisigWalletAddress, 266 | addressInput, 267 | amount, 268 | true, 269 | kgtAddress ).encodeABI(); 270 | return signAndSend( userPrivateKey, data, dropContract.options.address,0,nonce,/*new BigNumber(27000 * 3).mul(addressInput.length+1)*/ new BigNumber(4*550 * 1000) ); 271 | }).then(function(result){ 272 | nonce = nonce + 1; 273 | console.log(result); 274 | }); 275 | }, Promise.resolve()).then(function(){fulfill(true);}).catch(function(error){console.log(error);}); 276 | }); 277 | }).catch(function(error){ 278 | console.log(error); 279 | reject(error); 280 | }); 281 | }; 282 | 283 | 284 | //////////////////////////////////////////////////////////////////////////////// 285 | 286 | var privateKeyToAddress = function( privateKey ) { 287 | return ethjsaccount.privateToAccount(privateKey).address; 288 | }; 289 | 290 | //////////////////////////////////////////////////////////////////////////////// 291 | 292 | var getPrivateKey = function( password, salt ) { 293 | var key = web3.utils.sha3(password + salt); 294 | return key; 295 | }; 296 | 297 | //////////////////////////////////////////////////////////////////////////////// 298 | 299 | 300 | var key = getPrivateKey( "put your key", 301 | "here" ); 302 | 303 | var amount = new BigNumber(2).mul(10**18); 304 | 305 | var addresses = []; 306 | var lineReader = require('readline').createInterface({ 307 | input: require('fs').createReadStream('upload.txt') 308 | }); 309 | 310 | lineReader.on('line', function (line) { 311 | var re = /0x([a-f]|[A-F]|[0-9])*/ 312 | var input = line.match(re)[0]; 313 | var address = web3.utils.toChecksumAddress( input ); 314 | addresses.push( address ); 315 | }); 316 | 317 | lineReader.on('close', function () { 318 | return uploadListBulk( addresses, amount, key, addresses.length / 8 ); 319 | }); 320 | -------------------------------------------------------------------------------- /upload.txt: -------------------------------------------------------------------------------- 1 | 0x9f51cA6a18c650555bE53206b7a20d91681dA7F6 2 | --------------------------------------------------------------------------------