Originally posted Oct 18 2016; updated 14:05 Oct 22 2016 UTC with live contract details; updated Jan 7 2017 with significant bug; updated Jan 12 2017 with newly deployed contract with the bug fix.
This is not investment advise as to whether Hacker Gold is a good investment or not. This is just a quick look at the smart contract and the concept behind Hacker Gold.
Significant Bug!:
- 07 Jan 17 PSA: HackerGold’s HKG token has a bug and will need to be re-issued
- 11 Jan 17 HackerGold successful swap. The new HackerGold smart contract address is 0x14f37b574242d366558db61f3335289a5035c506.
A code audit was just conducted on Ether.Camp’s HackerGold Smart Contracts – see EtherCamp’s Hacker Gold (HKG) public code audit.
Links:
- Contract address 0xb582baaf5e749d6aa98a22355a9d08b4c4d013c8 – 11 Jan 17 The contract at this address has a bug and is obsolete.
- Wallet address 0xed42264e005d9052799a5971e439d5353bdb3f24
- Whitepaper from https://hack.ether.camp/whitepaper
- Github repository
- 323 ideas currently
- HackerGold sale site
- Virtual Accelerator – Past, Present and Future
- AMA Today Monday 17th October 17:00 GMT. Replies in this thread. Your questions are welcome.
There have been some complaints about the USD 50 million (4,000,000 ETH) cap, and investors basically get voting rights to the Hacker Gold competition, and the ethers raised go towards building the Hacker Gold virtual accelerator platform, not the startups competing on this platform:
- Ethercamp Just Set A Cap On Their Crowdsale Of Almost 50 Million USD. Why Does Ethercamp Need 50 Million USD?
- HKG value structure – HackerGold
- EtherCamps HKG Is A Stellar Idea Spolied By Greed And Their AMA Is Not Until The 18th Which Is Right Before The Crowdsale
- BANNED – Sockpuppet accounts promoting projects are not tolerated.
- I Shit You Not. EtherCamp Set A CAP Of Almost 50 Million USD On Their Crowdsale.
- 10 Things to know about Ether.Camp’s Crowdsale
Update Oct 20 2016 And two potential judges have declined:
- I was asked to judge the hack.ether.camp hackathon. I pulled out. This is why.
- Why I have stood down as a judge of hack.ether.camp
To purchase Hacker Gold tokens, just send ethers to the contract address 0xb582baaf5e749d6aa98a22355a9d08b4c4d013c8, with a gas value of 100,000. The method () payable
calls the method createHKG(...)
that will generate the tokens for your sending address. Do it at your own risk – send a small amount first to confirm that it works as you expect. The HKG tokens are ERC: Token standard #20 compliant.
Token Price
From HackerGold sale site:
From the live contract code:
1 2 3 4 5 6 7 |
1476799200, // P1: GMT: 18-Oct-2016 14:00 => The Sale Starts 1478181600, // P2: GMT: 03-Nov-2016 14:00 => 1st Price Ladder 1479391200, // P3: GMT: 17-Nov-2016 14:00 => Price Stable, // Hackathon Starts 1480600800, // P4: GMT: 01-Dec-2016 14:00 => 2nd Price Ladder 1481810400, // P5: GMT: 15-Dec-2016 14:00 => Price Stable 1482415200 // P6: GMT: 22-Dec-2016 14:00 => Sale Ends, Hackathon Ends |
Source Code For Replacement Contract From EtherScan.io
11 Jan 17 Updated. See link above re replacement contract. Following is the source code from the new contract address 0x14f37b574242d366558db61f3335289a5035c506.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 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 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
pragma solidity ^ 0.4 .0; /* * Token - is a smart contract interface * for managing common functionality of * a token. * * ERC.20 Token standard: https://github.com/eth ereum/EIPs/issues/20 */ contract TokenInterface { // total amount of tokens uint totalSupplyVar; /** * * balanceOf() - constant function check concrete tokens balance * * @param owner - account owner * * @return the value of balance */ function balanceOf(address owner) constant returns(uint256 balance); function transfer(address to, uint256 value) returns(bool success); function transferFrom(address from, address to, uint256 value) returns(bool success); /** * * approve() - function approves to a person to spend some tokens from * owner balance. * * @param spender - person whom this right been granted. * @param value - value to spend. * * @return true in case of succes, otherwise failure * */ function approve(address spender, uint256 value) returns(bool success); /** * * allowance() - constant function to check how much is * permitted to spend to 3rd person from owner balance * * @param owner - owner of the balance * @param spender - permitted to spend from this balance person * * @return - remaining right to spend * */ function allowance(address owner, address spender) constant returns(uint256 remaining); function totalSupply() constant returns(uint256 totalSupply) { return totalSupplyVar; } // events notifications event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } pragma solidity ^ 0.4 .2; /* * StandardToken - is a smart contract * for managing common functionality of * a token. * * ERC.20 Token standard: * https://github.com/eth ereum/EIPs/issues/20 */ contract StandardToken is TokenInterface { // token ownership mapping(address => uint256) balances; // spending permision management mapping(address => mapping(address => uint256)) allowed; function StandardToken() {} /** * transfer() - transfer tokens from msg.sender balance * to requested account * * @param to - target address to transfer tokens * @param value - ammount of tokens to transfer * * @return - success / failure of the transaction */ function transfer(address to, uint256 value) returns(bool success) { if (balances[msg.sender] >= value && value > 0) { // do actual tokens transfer balances[msg.sender] -= value; balances[to] += value; // rise the Transfer event Transfer(msg.sender, to, value); return true; } else { return false; } } /** * transferFrom() - used to move allowed funds from other owner * account * * @param from - move funds from account * @param to - move funds to account * @param value - move the value * * @return - return true on success false otherwise */ function transferFrom(address from, address to, uint256 value) returns(bool success) { if (balances[from] >= value && allowed[from][msg.sender] >= value && value > 0) { // do the actual transfer balances[from] -= value; balances[to] += value; // addjust the permision, after part of // permited to spend value was used allowed[from][msg.sender] -= value; // rise the Transfer event Transfer(from, to, value); return true; } else { return false; } } /** * * balanceOf() - constant function check concrete tokens balance * * @param owner - account owner * * @return the value of balance */ function balanceOf(address owner) constant returns(uint256 balance) { return balances[owner]; } /** * * approve() - function approves to a person to spend some tokens from * owner balance. * * @param spender - person whom this right been granted. * @param value - value to spend. * * @return true in case of succes, otherwise failure * */ function approve(address spender, uint256 value) returns(bool success) { // now spender can use balance in // ammount of value from owner balance allowed[msg.sender][spender] = value; // rise event about the transaction Approval(msg.sender, spender, value); return true; } /** * * allowance() - constant function to check how mouch is * permited to spend to 3rd person from owner balance * * @param owner - owner of the balance * @param spender - permited to spend from this balance person * * @return - remaining right to spend * */ function allowance(address owner, address spender) constant returns(uint256 remaining) { return allowed[owner][spender]; } } pragma solidity ^ 0.4 .0; /** * * @title Hacker Gold * * The official token powering the hack.ether.camp virtual accelerator. * This is the only way to acquire tokens from startups during the event. * * Whitepaper https://hack.ether.camp/whitepaper * */ contract HackerGold is StandardToken { // Name of the token string public name = "HackerGold"; // Decimal places uint8 public decimals = 3; // Token abbreviation string public symbol = "HKG"; // 1 ether = 200 hkg uint BASE_PRICE = 200; // 1 ether = 150 hkg uint MID_PRICE = 150; // 1 ether = 100 hkg uint FIN_PRICE = 100; // Safety cap uint SAFETY_LIMIT = 4000000 ether; // Zeros after the point uint DECIMAL_ZEROS = 1000; // Total value in wei uint totalValue; // Address of multisig wallet holding ether from sale address wallet; // Structure of sale increase milestones struct milestones_struct { uint p1; uint p2; uint p3; uint p4; uint p5; uint p6; } // Milestones instance milestones_struct milestones; /** * Constructor of the contract. * * Passes address of the account holding the value. * HackerGold contract itself does not hold any value * * @param multisig address of MultiSig wallet which will hold the value */ function HackerGold(address multisig) { wallet = multisig; // set time periods for sale milestones = milestones_struct( 1476972000, // P1: GMT: 20-Oct-2016 14:00 => The Sale Starts 1478181600, // P2: GMT: 03-Nov-2016 14:00 => 1st Price Ladder 1479391200, // P3: GMT: 17-Nov-2016 14:00 => Price Stable, // Hackathon Starts 1480600800, // P4: GMT: 01-Dec-2016 14:00 => 2nd Price Ladder 1481810400, // P5: GMT: 15-Dec-2016 14:00 => Price Stable 1482415200 // P6: GMT: 22-Dec-2016 14:00 => Sale Ends, Hackathon Ends ); // assign recovery balance totalSupplyVar = 16110893000; balances[0x342e62732b76875da9305083ea8ae63125a4e667] = 16110893000; totalValue = 85362 ether; } /** * Fallback function: called on ether sent. * * It calls to createHKG function with msg.sender * as a value for holder argument */ function() payable { createHKG(msg.sender); } /** * Creates HKG tokens. * * Runs sanity checks including safety cap * Then calculates current price by getPrice() function, creates HKG tokens * Finally sends a value of transaction to the wallet * * Note: due to lack of floating point types in Solidity, * contract assumes that last 3 digits in tokens amount are stood after the point. * It means that if stored HKG balance is 100000, then its real value is 100 HKG * * @param holder token holder */ function createHKG(address holder) payable { if (now < milestones.p1) throw; if (now >= milestones.p6) throw; if (msg.value == 0) throw; // safety cap if (getTotalValue() + msg.value > SAFETY_LIMIT) throw; uint tokens = msg.value * getPrice() * DECIMAL_ZEROS / 1 ether; totalSupplyVar += tokens; balances[holder] += tokens; totalValue += msg.value; if (!wallet.send(msg.value)) throw; } /** * Denotes complete price structure during the sale. * * @return HKG amount per 1 ETH for the current moment in time */ function getPrice() constant returns(uint result) { if (now < milestones.p1) return 0; if (now >= milestones.p1 && now < milestones.p2) { return BASE_PRICE; } if (now >= milestones.p2 && now < milestones.p3) { uint days_in = 1 + (now - milestones.p2) / 1 days; return BASE_PRICE - days_in * 25 / 7; // daily decrease 3.5 } if (now >= milestones.p3 && now < milestones.p4) { return MID_PRICE; } if (now >= milestones.p4 && now < milestones.p5) { days_in = 1 + (now - milestones.p4) / 1 days; return MID_PRICE - days_in * 25 / 7; // daily decrease 3.5 } if (now >= milestones.p5 && now < milestones.p6) { return FIN_PRICE; } if (now >= milestones.p6) { return 0; } } /** * Returns total stored HKG amount. * * Contract assumes that last 3 digits of this value are behind the decimal place. i.e. 10001 is 10.001 * Thus, result of this function should be divided by 1000 to get HKG value * * @return result stored HKG amount */ function getTotalSupply() constant returns(uint result) { return totalSupplyVar; } /** * It is used for test purposes. * * Returns the result of 'now' statement of Solidity language * * @return unix timestamp for current moment in time */ function getNow() constant returns(uint result) { return now; } /** * Returns total value passed through the contract * * @return result total value in wei */ function getTotalValue() constant returns(uint result) { return totalValue; } } |
Source Code From EtherScan.io
Contract address 0xb582baaf5e749d6aa98a22355a9d08b4c4d013c8.
Note that there is a significant bug in transferFrom(...)
on line #133 below. The buggy statement balances[to] =+ value;
should read balances[to] += value;
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 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 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
pragma solidity ^0.4.0; /* * Token - is a smart contract interface * for managing common functionality of * a token. * * ERC.20 Token standard: https://github.com/eth ereum/EIPs/issues/20 */ contract TokenInterface { // total amount of tokens uint totalSupply; /** * * balanceOf() - constant function check concrete tokens balance * * @param owner - account owner * * @return the value of balance */ function balanceOf(address owner) constant returns (uint256 balance); function transfer(address to, uint256 value) returns (bool success); function transferFrom(address from, address to, uint256 value) returns (bool success); /** * * approve() - function approves to a person to spend some tokens from * owner balance. * * @param spender - person whom this right been granted. * @param value - value to spend. * * @return true in case of succes, otherwise failure * */ function approve(address spender, uint256 value) returns (bool success); /** * * allowance() - constant function to check how much is * permitted to spend to 3rd person from owner balance * * @param owner - owner of the balance * @param spender - permitted to spend from this balance person * * @return - remaining right to spend * */ function allowance(address owner, address spender) constant returns (uint256 remaining); // events notifications event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } /* * StandardToken - is a smart contract * for managing common functionality of * a token. * * ERC.20 Token standard: * https://github.com/eth ereum/EIPs/issues/20 */ contract StandardToken is TokenInterface { // token ownership mapping (address => uint256) balances; // spending permision management mapping (address => mapping (address => uint256)) allowed; function StandardToken(){ } /** * transfer() - transfer tokens from msg.sender balance * to requested account * * @param to - target address to transfer tokens * @param value - ammount of tokens to transfer * * @return - success / failure of the transaction */ function transfer(address to, uint256 value) returns (bool success) { if (balances[msg.sender] >= value && value > 0) { // do actual tokens transfer balances[msg.sender] -= value; balances[to] += value; // rise the Transfer event Transfer(msg.sender, to, value); return true; } else { return false; } } /** * transferFrom() - * * @param from - * @param to - * @param value - * * @return */ function transferFrom(address from, address to, uint256 value) returns (bool success) { if ( balances[from] >= value && allowed[from][msg.sender] >= value && value > 0) { // do the actual transfer balances[from] -= value; balances[to] =+ value; // addjust the permision, after part of // permited to spend value was used allowed[from][msg.sender] -= value; // rise the Transfer event Transfer(from, to, value); return true; } else { return false; } } /** * * balanceOf() - constant function check concrete tokens balance * * @param owner - account owner * * @return the value of balance */ function balanceOf(address owner) constant returns (uint256 balance) { return balances[owner]; } /** * * approve() - function approves to a person to spend some tokens from * owner balance. * * @param spender - person whom this right been granted. * @param value - value to spend. * * @return true in case of succes, otherwise failure * */ function approve(address spender, uint256 value) returns (bool success) { // now spender can use balance in // ammount of value from owner balance allowed[msg.sender][spender] = value; // rise event about the transaction Approval(msg.sender, spender, value); return true; } /** * * allowance() - constant function to check how mouch is * permited to spend to 3rd person from owner balance * * @param owner - owner of the balance * @param spender - permited to spend from this balance person * * @return - remaining right to spend * */ function allowance(address owner, address spender) constant returns (uint256 remaining) { return allowed[owner][spender]; } } /** * * @title Hacker Gold * * The official token powering the hack.ether.camp virtual accelerator. * This is the only way to acquire tokens from startups during the event. * * Whitepaper https://hack.ether.camp/whitepaper * */ contract HackerGold is StandardToken { // Name of the token string public name = "HackerGold"; // Decimal places uint8 public decimals = 3; // Token abbreviation string public symbol = "HKG"; // 1 ether = 200 hkg uint BASE_PRICE = 200; // 1 ether = 150 hkg uint MID_PRICE = 150; // 1 ether = 100 hkg uint FIN_PRICE = 100; // Safety cap uint SAFETY_LIMIT = 4000000 ether; // Zeros after the point uint DECIMAL_ZEROS = 1000; // Total value in wei uint totalValue; // Address of multisig wallet holding ether from sale address wallet; // Structure of sale increase milestones struct milestones_struct { uint p1; uint p2; uint p3; uint p4; uint p5; uint p6; } // Milestones instance milestones_struct milestones; /** * Constructor of the contract. * * Passes address of the account holding the value. * HackerGold contract itself does not hold any value * * @param multisig address of MultiSig wallet which will hold the value */ function HackerGold(address multisig) { wallet = multisig; // set time periods for sale milestones = milestones_struct( 1476799200, // P1: GMT: 18-Oct-2016 14:00 => The Sale Starts 1478181600, // P2: GMT: 03-Nov-2016 14:00 => 1st Price Ladder 1479391200, // P3: GMT: 17-Nov-2016 14:00 => Price Stable, // Hackathon Starts 1480600800, // P4: GMT: 01-Dec-2016 14:00 => 2nd Price Ladder 1481810400, // P5: GMT: 15-Dec-2016 14:00 => Price Stable 1482415200 // P6: GMT: 22-Dec-2016 14:00 => Sale Ends, Hackathon Ends ); } /** * Fallback function: called on ether sent. * * It calls to createHKG function with msg.sender * as a value for holder argument */ function () payable { createHKG(msg.sender); } /** * Creates HKG tokens. * * Runs sanity checks including safety cap * Then calculates current price by getPrice() function, creates HKG tokens * Finally sends a value of transaction to the wallet * * Note: due to lack of floating point types in Solidity, * contract assumes that last 3 digits in tokens amount are stood after the point. * It means that if stored HKG balance is 100000, then its real value is 100 HKG * * @param holder token holder */ function createHKG(address holder) payable { if (now < milestones.p1) throw; if (now >= milestones.p6) throw; if (msg.value == 0) throw; // safety cap if (getTotalValue() + msg.value > SAFETY_LIMIT) throw; uint tokens = msg.value * getPrice() * DECIMAL_ZEROS / 1 ether; totalSupply += tokens; balances[holder] += tokens; totalValue += msg.value; if (!wallet.send(msg.value)) throw; } /** * Denotes complete price structure during the sale. * * @return HKG amount per 1 ETH for the current moment in time */ function getPrice() constant returns (uint result) { if (now < milestones.p1) return 0; if (now >= milestones.p1 && now < milestones.p2) { return BASE_PRICE; } if (now >= milestones.p2 && now < milestones.p3) { uint days_in = 1 + (now - milestones.p2) / 1 days; return BASE_PRICE - days_in * 25 / 7; // daily decrease 3.5 } if (now >= milestones.p3 && now < milestones.p4) { return MID_PRICE; } if (now >= milestones.p4 && now < milestones.p5) { days_in = 1 + (now - milestones.p4) / 1 days; return MID_PRICE - days_in * 25 / 7; // daily decrease 3.5 } if (now >= milestones.p5 && now < milestones.p6) { return FIN_PRICE; } if (now >= milestones.p6){ return 0; } } /** * Returns total stored HKG amount. * * Contract assumes that last 3 digits of this value are behind the decimal place. i.e. 10001 is 10.001 * Thus, result of this function should be divided by 1000 to get HKG value * * @return result stored HKG amount */ function getTotalSupply() constant returns (uint result) { return totalSupply; } /** * It is used for test purposes. * * Returns the result of 'now' statement of Solidity language * * @return unix timestamp for current moment in time */ function getNow() constant returns (uint result) { return now; } /** * Returns total value passed through the contract * * @return result total value in wei */ function getTotalValue() constant returns (uint result) { return totalValue; } } |
Source Code From Repository
The source code below from github.com/ether-camp/virtual-accelerator seems to be cleaned up after the public code audit.
TokenInterface.sol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
pragma solidity ^0.4.0; /* * Token - is a smart contract interface * for managing common functionality of * a token. * * ERC.20 Token standard: https://github.com/eth ereum/EIPs/issues/20 */ contract TokenInterface { // total amount of tokens uint totalSupply; /** * * balanceOf() - constant function check concrete tokens balance * * @param owner - account owner * * @return the value of balance */ function balanceOf(address owner) constant returns (uint256 balance); function transfer(address to, uint256 value) returns (bool success); function transferFrom(address from, address to, uint256 value) returns (bool success); /** * * approve() - function approves to a person to spend some tokens from * owner balance. * * @param spender - person whom this right been granted. * @param value - value to spend. * * @return true in case of succes, otherwise failure * */ function approve(address spender, uint256 value) returns (bool success); /** * * allowance() - constant function to check how much is * permitted to spend to 3rd person from owner balance * * @param owner - owner of the balance * @param spender - permitted to spend from this balance person * * @return - remaining right to spend * */ function allowance(address owner, address spender) constant returns (uint256 remaining); // events notifications event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } |
StandardToken.sol
Note that there is a significant bug in transferFrom(...)
on line #76 below. The buggy statement balances[to] =+ value;
should read balances[to] += value;
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
import "TokenInterface.sol"; pragma solidity ^0.4.2; /* * StandardToken - is a smart contract * for managing common functionality of * a token. * * ERC.20 Token standard: * https://github.com/eth ereum/EIPs/issues/20 */ contract StandardToken is TokenInterface { // token ownership mapping (address => uint256) balances; // spending permision management mapping (address => mapping (address => uint256)) allowed; function StandardToken(){ } /** * transfer() - transfer tokens from msg.sender balance * to requested account * * @param to - target address to transfer tokens * @param value - ammount of tokens to transfer * * @return - success / failure of the transaction */ function transfer(address to, uint256 value) returns (bool success) { if (balances[msg.sender] >= value && value > 0) { // do actual tokens transfer balances[msg.sender] -= value; balances[to] += value; // rise the Transfer event Transfer(msg.sender, to, value); return true; } else { return false; } } /** * transferFrom() - * * @param from - * @param to - * @param value - * * @return */ function transferFrom(address from, address to, uint256 value) returns (bool success) { if ( balances[from] >= value && allowed[from][msg.sender] >= value && value > 0) { // do the actual transfer balances[from] -= value; balances[to] =+ value; // addjust the permision, after part of // permited to spend value was used allowed[from][msg.sender] -= value; // rise the Transfer event Transfer(from, to, value); return true; } else { return false; } } /** * * balanceOf() - constant function check concrete tokens balance * * @param owner - account owner * * @return the value of balance */ function balanceOf(address owner) constant returns (uint256 balance) { return balances[owner]; } /** * * approve() - function approves to a person to spend some tokens from * owner balance. * * @param spender - person whom this right been granted. * @param value - value to spend. * * @return true in case of succes, otherwise failure * */ function approve(address spender, uint256 value) returns (bool success) { // now spender can use balance in // ammount of value from owner balance allowed[msg.sender][spender] = value; // rise event about the transaction Approval(msg.sender, spender, value); return true; } /** * * allowance() - constant function to check how mouch is * permited to spend to 3rd person from owner balance * * @param owner - owner of the balance * @param spender - permited to spend from this balance person * * @return - remaining right to spend * */ function allowance(address owner, address spender) constant returns (uint256 remaining) { return allowed[owner][spender]; } } |
HackerGold.sol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
import "StandardToken.sol"; pragma solidity ^0.4.0; /** * * @title Hacker Gold * * The official token powering the hack.ether.camp virtual accelerator. * This is the only way to acquire tokens from startups during the event. * * Whitepaper https://hack.ether.camp/whitepaper * */ contract HackerGold is StandardToken { // Name of the token string public name = "HackerGold"; // Decimal places uint8 public decimals = 3; // Token abbreviation string public symbol = "HKG"; // 1 ether = 200 hkg uint BASE_PRICE = 200; // 1 ether = 150 hkg uint MID_PRICE = 150; // 1 ether = 100 hkg uint FIN_PRICE = 100; // Safety cap uint SAFETY_LIMIT = 4000000 ether; // Zeros after the point uint DECIMAL_ZEROS = 1000; // Total value in wei uint totalValue; // Address of multisig wallet holding ether from sale address wallet; // Structure of sale increase milestones struct milestones_struct { uint p1; uint p2; uint p3; uint p4; uint p5; uint p6; } // Milestones instance milestones_struct milestones; /** * Constructor of the contract. * * Passes address of the account holding the value. * HackerGold contract itself does not hold any value * * @param multisig address of MultiSig wallet which will hold the value */ function HackerGold(address multisig) { wallet = multisig; // set time periods for sale milestones = milestones_struct( 1476972000, // P1: GMT: 20-Oct-2016 14:00 => The Sale Starts 1478181600, // P2: GMT: 03-Nov-2016 14:00 => 1st Price Ladder 1479391200, // P3: GMT: 17-Nov-2016 14:00 => Price Stable, // Hackathon Starts 1480600800, // P4: GMT: 01-Dec-2016 14:00 => 2nd Price Ladder 1481810400, // P5: GMT: 15-Dec-2016 14:00 => Price Stable 1482415200 // P6: GMT: 22-Dec-2016 14:00 => Sale Ends, Hackathon Ends ); } /** * Fallback function: called on ether sent. * * It calls to createHKG function with msg.sender * as a value for holder argument */ function () payable { createHKG(msg.sender); } /** * Creates HKG tokens. * * Runs sanity checks including safety cap * Then calculates current price by getPrice() function, creates HKG tokens * Finally sends a value of transaction to the wallet * * Note: due to lack of floating point types in Solidity, * contract assumes that last 3 digits in tokens amount are stood after the point. * It means that if stored HKG balance is 100000, then its real value is 100 HKG * * @param holder token holder */ function createHKG(address holder) payable { if (now < milestones.p1) throw; if (now > milestones.p6) throw; if (msg.value == 0) throw; // safety cap if (getTotalValue() + msg.value > SAFETY_LIMIT) throw; uint tokens = msg.value * getPrice() * DECIMAL_ZEROS / 1 ether; totalSupply += tokens; balances[holder] += tokens; totalValue += msg.value; if (!wallet.send(msg.value)) throw; } /** * Denotes complete price structure during the sale. * * @return HKG amount per 1 ETH for the current moment in time */ function getPrice() constant returns (uint result) { if (now < milestones.p1) return 0; if (now >= milestones.p1 && now < milestones.p2) { return BASE_PRICE; } if (now >= milestones.p2 && now < milestones.p3) { uint days_in = 1 + (now - milestones.p2) / 1 days; return BASE_PRICE - days_in * 25 / 7; // daily decrease 3.5 } if (now >= milestones.p3 && now < milestones.p4) { return MID_PRICE; } if (now >= milestones.p4 && now < milestones.p5) { days_in = 1 + (now - milestones.p4) / 1 days; return MID_PRICE - days_in * 25 / 7; // daily decrease 3.5 } if (now >= milestones.p5 && now < milestones.p6) { return FIN_PRICE; } if (now >= milestones.p6){ return 0; } } /** * Returns total stored HKG amount. * * Contract assumes that last 3 digits of this value are behind the decimal place. i.e. 10001 is 10.001 * Thus, result of this function should be divided by 1000 to get HKG value * * @return result stored HKG amount */ function getTotalSupply() constant returns (uint result) { return totalSupply; } /** * It is used for test purposes. * * Returns the result of 'now' statement of Solidity language * * @return unix timestamp for current moment in time */ function getNow() constant returns (uint result) { return now; } /** * Returns total value passed through the contract * * @return result total value in wei */ function getTotalValue() constant returns (uint result) { return totalValue; } } |
wallet.sol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 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 273 274 275 276 277 278 |
pragma solidity ^0.4.0; //sol Wallet // Multi-sig, daily-limited account proxy/wallet. // @authors: // Gav Wood <g@ethdev.com> // inheritable "property" contract that enables methods to be protected by requiring the acquiescence of either a // single, or, crucially, each of a number of, designated owners. // usage: // use modifiers onlyowner (just own owned) or onlymanyowners(hash), whereby the same hash must be provided by // some number (specified in constructor) of the set of owners (specified in the constructor, modifiable) before the // interior is executed. contract multiowned { // TYPES // struct for the status of a pending operation. struct PendingState { uint yetNeeded; uint ownersDone; uint index; } // EVENTS // this contract only has six types of events: it can accept a confirmation, in which case // we record owner and operation (hash) alongside it. event Confirmation(address owner, bytes32 operation); event Revoke(address owner, bytes32 operation); // some others are in the case of an owner changing. event OwnerChanged(address oldOwner, address newOwner); event OwnerAdded(address newOwner); event OwnerRemoved(address oldOwner); // the last one is emitted if the required signatures change event RequirementChanged(uint newRequirement); // MODIFIERS // simple single-sig function modifier. modifier onlyowner { if (isOwner(msg.sender)) _; } // multi-sig function modifier: the operation must have an intrinsic hash in order // that later attempts can be realised as the same underlying operation and // thus count as confirmations. modifier onlymanyowners(bytes32 _operation) { if (confirmAndCheck(_operation)) _; } // METHODS // constructor is given number of sigs required to do protected "onlymanyowners" transactions // as well as the selection of addresses capable of confirming them. function multiowned(address[] _owners, uint _required) { m_numOwners = _owners.length + 1; m_owners[1] = uint(msg.sender); m_ownerIndex[uint(msg.sender)] = 1; for (uint i = 0; i < _owners.length; ++i) { m_owners[2 + i] = uint(_owners[i]); m_ownerIndex[uint(_owners[i])] = 2 + i; } m_required = _required; } // Revokes a prior confirmation of the given operation function revoke(bytes32 _operation) external { uint ownerIndex = m_ownerIndex[uint(msg.sender)]; // make sure they're an owner if (ownerIndex == 0) return; uint ownerIndexBit = 2**ownerIndex; var pending = m_pending[_operation]; if (pending.ownersDone & ownerIndexBit > 0) { pending.yetNeeded++; pending.ownersDone -= ownerIndexBit; Revoke(msg.sender, _operation); } } // Replaces an owner `_from` with another `_to`. function changeOwner(address _from, address _to) onlymanyowners(sha3(msg.data)) external { if (isOwner(_to)) return; uint ownerIndex = m_ownerIndex[uint(_from)]; if (ownerIndex == 0) return; clearPending(); m_owners[ownerIndex] = uint(_to); m_ownerIndex[uint(_from)] = 0; m_ownerIndex[uint(_to)] = ownerIndex; OwnerChanged(_from, _to); } function addOwner(address _owner) onlymanyowners(sha3(msg.data)) external { if (isOwner(_owner)) return; clearPending(); if (m_numOwners >= c_maxOwners) reorganizeOwners(); if (m_numOwners >= c_maxOwners) return; m_numOwners++; m_owners[m_numOwners] = uint(_owner); m_ownerIndex[uint(_owner)] = m_numOwners; OwnerAdded(_owner); } function removeOwner(address _owner) onlymanyowners(sha3(msg.data)) external { uint ownerIndex = m_ownerIndex[uint(_owner)]; if (ownerIndex == 0) return; if (m_required > m_numOwners - 1) return; m_owners[ownerIndex] = 0; m_ownerIndex[uint(_owner)] = 0; clearPending(); reorganizeOwners(); //make sure m_numOwner is equal to the number of owners and always points to the optimal free slot OwnerRemoved(_owner); } function changeRequirement(uint _newRequired) onlymanyowners(sha3(msg.data)) external { if (_newRequired > m_numOwners) return; m_required = _newRequired; clearPending(); RequirementChanged(_newRequired); } // Gets an owner by 0-indexed position (using numOwners as the count) function getOwner(uint ownerIndex) external constant returns (address) { return address(m_owners[ownerIndex + 1]); } function isOwner(address _addr) returns (bool) { return m_ownerIndex[uint(_addr)] > 0; } function hasConfirmed(bytes32 _operation, address _owner) constant returns (bool) { var pending = m_pending[_operation]; uint ownerIndex = m_ownerIndex[uint(_owner)]; // make sure they're an owner if (ownerIndex == 0) return false; // determine the bit to set for this owner. uint ownerIndexBit = 2**ownerIndex; return !(pending.ownersDone & ownerIndexBit == 0); } // INTERNAL METHODS function confirmAndCheck(bytes32 _operation) internal returns (bool) { // determine what index the present sender is: uint ownerIndex = m_ownerIndex[uint(msg.sender)]; // make sure they're an owner if (ownerIndex == 0) return; var pending = m_pending[_operation]; // if we're not yet working on this operation, switch over and reset the confirmation status. if (pending.yetNeeded == 0) { // reset count of confirmations needed. pending.yetNeeded = m_required; // reset which owners have confirmed (none) - set our bitmap to 0. pending.ownersDone = 0; pending.index = m_pendingIndex.length++; m_pendingIndex[pending.index] = _operation; } // determine the bit to set for this owner. uint ownerIndexBit = 2**ownerIndex; // make sure we (the message sender) haven't confirmed this operation previously. if (pending.ownersDone & ownerIndexBit == 0) { Confirmation(msg.sender, _operation); // ok - check if count is enough to go ahead. if (pending.yetNeeded <= 1) { // enough confirmations: reset and run interior. delete m_pendingIndex[m_pending[_operation].index]; delete m_pending[_operation]; return true; } else { // not enough: record that this owner in particular confirmed. pending.yetNeeded--; pending.ownersDone |= ownerIndexBit; } } } function reorganizeOwners() private { uint free = 1; while (free < m_numOwners) { while (free < m_numOwners && m_owners[free] != 0) free++; while (m_numOwners > 1 && m_owners[m_numOwners] == 0) m_numOwners--; if (free < m_numOwners && m_owners[m_numOwners] != 0 && m_owners[free] == 0) { m_owners[free] = m_owners[m_numOwners]; m_ownerIndex[m_owners[free]] = free; m_owners[m_numOwners] = 0; } } } function clearPending() internal { uint length = m_pendingIndex.length; for (uint i = 0; i < length; ++i) if (m_pendingIndex[i] != 0) delete m_pending[m_pendingIndex[i]]; delete m_pendingIndex; } // FIELDS // the number of owners that must confirm the same operation before it is run. uint public m_required; // pointer used to find a free slot in m_owners uint public m_numOwners; // list of owners uint[256] m_owners; uint constant c_maxOwners = 250; // index on the list of owners to allow reverse lookup mapping(uint => uint) m_ownerIndex; // the ongoing operations. mapping(bytes32 => PendingState) m_pending; bytes32[] m_pendingIndex; } // inheritable "property" contract that enables methods to be protected by placing a linear limit (specifiable) // on a particular resource per calendar day. is multiowned to allow the limit to be altered. resource that method // uses is specified in the modifier. contract daylimit is multiowned { // MODIFIERS // simple modifier for daily limit. modifier limitedDaily(uint _value) { if (underLimit(_value)) _; } // METHODS // constructor - stores initial daily limit and records the present day's index. function daylimit(uint _limit) { m_dailyLimit = _limit; m_lastDay = today(); } // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data)) external { m_dailyLimit = _newLimit; } // resets the amount already spent today. needs many of the owners to confirm. function resetSpentToday() onlymanyowners(sha3(msg.data)) external { m_spentToday = 0; } // INTERNAL METHODS // checks to see if there is at least `_value` left from the daily limit today. if there is, subtracts it and // returns true. otherwise just returns false. function underLimit(uint _value) internal onlyowner returns (bool) { // reset the spend limit if we're on a different day to last time. if (today() > m_lastDay) { m_spentToday = 0; m_lastDay = today(); } // check to see if there's enough left - if so, subtract and return true. // overflow protection // dailyLimit check if (m_spentToday + _value >= m_spentToday && m_spentToday + _value <= m_dailyLimit) { m_spentToday += _value; return true; } return false; } // determines today's index. function today() private constant returns (uint) { return now / 1 days; } // FIELDS uint public m_dailyLimit; uint public m_spentToday; uint public m_lastDay; } // interface contract for multisig proxy contracts; see below for docs. contract multisig { // EVENTS // logged events: // Funds has arrived into the wallet (record how much). event Deposit(address _from, uint value); // Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going). event SingleTransact(address owner, uint value, address to, bytes data); // Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going). event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data); // Confirmation still needed for a transaction. event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data); // FUNCTIONS // TODO: document function changeOwner(address _from, address _to) external; function execute(address _to, uint _value, bytes _data) external returns (bytes32); function confirm(bytes32 _h) returns (bool); } // usage: // bytes32 h = Wallet(w).from(oneOwner).execute(to, value, data); // Wallet(w).from(anotherOwner).confirm(h); contract Wallet is multisig, multiowned, daylimit { // TYPES // Transaction structure to remember details of transaction lest it need be saved for a later call. struct Transaction { address to; uint value; bytes data; } // METHODS // constructor - just pass on the owner array to the multiowned and // the limit to daylimit function Wallet(address[] _owners, uint _required, uint _daylimit) multiowned(_owners, _required) daylimit(_daylimit) { } // kills the contract sending everything to `_to`. function kill(address _to) onlymanyowners(sha3(msg.data)) external { suicide(_to); } // gets called when no other function matches function() payable { // just being sent some cash? if (msg.value > 0) Deposit(msg.sender, msg.value); } // Outside-visible transact entry point. Executes transaction immediately if below daily spend limit. // If not, goes into multisig process. We provide a hash on return to allow the sender to provide // shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value // and _data arguments). They still get the option of using them if they want, anyways. function execute(address _to, uint _value, bytes _data) external onlyowner returns (bytes32 _r) { // first, take the opportunity to check that we're under the daily limit. if (underLimit(_value)) { SingleTransact(msg.sender, _value, _to, _data); // yes - just execute the call. _to.call.value(_value)(_data); return 0; } // determine our operation hash. _r = sha3(msg.data, block.number); if (!confirm(_r) && m_txs[_r].to == 0) { m_txs[_r].to = _to; m_txs[_r].value = _value; m_txs[_r].data = _data; ConfirmationNeeded(_r, msg.sender, _value, _to, _data); } } // confirm a transaction through just the hash. we use the previous transactions map, m_txs, in order // to determine the body of the transaction from the hash provided. function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) { if (m_txs[_h].to != 0) { m_txs[_h].to.call.value(m_txs[_h].value)(m_txs[_h].data); MultiTransact(msg.sender, _h, m_txs[_h].value, m_txs[_h].to, m_txs[_h].data); delete m_txs[_h]; return true; } } // INTERNAL METHODS function clearPending() internal { uint length = m_pendingIndex.length; for (uint i = 0; i < length; ++i) delete m_txs[m_pendingIndex[i]]; super.clearPending(); } // FIELDS // pending transactions we have at present. mapping (bytes32 => Transaction) m_txs; } |