Original post Oct 24 2016. Updated Nov 12 2016 with deployed contract and source code, and crowdfunding statistics.
This is not advise as to whether Golem is a good investment or not. This is just a quick look at what Golem is offering and how they are doing it.
Golem is going create the first decentralized global market for computing power combined with flexible tools for developers to distribute and monetize their software.
The first transaction 0x0a75…be15 in block 2,607,801 at Nov-11-2016 03:12:28 PM +UTC.
The last valid transaction 0xa8d9…2ea7 was for 0.85579574 ETH in block 2,607,934 at Nov-11-2016 03:41:36 PM +UTC.
The crowdfunding was finalized
in transaction 0x1bdf…e681 in block 2,607,939 at Nov-11-2016 03:43:05 PM +UTC.
The crowdfunding raised 820,000 ETH (~ USD 8,620,660) within 30 minutes and 37 seconds from commencement, with 522 addresses and 647 events.
From https://etherscan.io/token/Golem:
Links:
- Nov 12 2016 – The Golem Token Sale: Irrational Exuberance?
- Nov 12 2016 – Blockchain for CPU? Analyzing Golem’s Ethereum Token Sale
- Nov 12 2016 – Golem Network Token (GNT) Audit
- Nov 11 2016 – Considerations against the Golem Crowdsale
- Nov 11 2016 – Golem crowdfunding contract deployed, start block is 2607800
- Nov 9 2016 – Crowdfunding — how to prepare
- Nov 9 2016 – Golem Crowdfunding Starts November 11
- Oct 28 2016 – Confused about economics of Golem + how GNT works & the HUGE markets we’re disrupting? Clarification post
- Oct 28 2016 – The Economics of the Golem Network Token
- Oct 28 2016 – Golem Network Token (GNT) Code Now Available
- Oct 28 2016 – PSA: The Golem ICO Tokens do NOT give you any percentage of revenue from the transactions on the network
- Oct 28 2016 – Golem Network Token (GNT) Code Now Available
- Oct 26 2016 – Golem – How It Works & Why It’s Awesome – A comprehensive guide that anyone can understand
- Oct 24 2016 – Designing A Better Internet with Ethereum and Golem
- Oct 21 2016 – Golem crowdfunding whitepaper: Release candidate, for community review
- The Golem Project – Crowdfunding Whitepaper – release candidate – Oct 2016
- Oct 17 2016 – Golem development team: So Who The Heck Are We, Anyway?
- Oct 17 2016 – The Crowdsale Analyst: Golem – Preliminary Thoughts
- Oct 14 2016 – Golem – Draft Crowdfunding Whitepaper
- Website – https://golem.network/
- Github – https://github.com/imapp-pl/golem
- Golem presentation in Shanghai Devcon2
Deployed Source Code
Following is the source code deployed to the Ethereum blockchain at address 0xa74476443119a942de498590fe1f2454d7d4ac0d.
The deployed contract has the following parameters:
- golemFactory – 0x7da82c7ab4771ff031b66538d2fb9b0b047f6cf9
- migrationMaster – 0x7da82c7ab4771ff031b66538d2fb9b0b047f6cf9
- fundingStartBlock – 2,607,800
- fundingEndBlock – 2,734,100
- tokenCreationRate – 1,000 . 1 ETH = 1,000 tokens
- tokenCreationMin – 1.5 x 10^26 token base unit. = 150,000 ETH ~ USD 1,586,850
- tokenCreationCap – 8.2 x 10^26 token base unit. = 820,00 ETH ~ USD 8,674,780
To participate in the crowdfunding, you will have to send the data field “0xefc81a8c” with your ether transaction to 0xa74476443119a942de498590fe1f2454d7d4ac0d. This calls the create()
method (web3.sha3("create()").substring(0,10)="0xefc81a8c"
). Gas needs to be set to at least 70,000. Crowdfunding starts ~ 15:00 Nov 11 2016 UTC or 02:00 Nov 12 2016 AEST.
Note that the contract below does not implement the ERC20 functions transferFrom(...)
and approve(...)
.
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 |
pragma solidity ^0.4.4; /// @title Golem Network Token (GNT) - crowdfunding code for Golem Project contract GolemNetworkToken { string public constant name = "Golem Network Token"; string public constant symbol = "GNT"; uint8 public constant decimals = 18; // 18 decimal places, the same as ETH. uint256 public constant tokenCreationRate = 1000; // The funding cap in weis. uint256 public constant tokenCreationCap = 820000 ether * tokenCreationRate; uint256 public constant tokenCreationMin = 150000 ether * tokenCreationRate; uint256 public fundingStartBlock; uint256 public fundingEndBlock; // The flag indicates if the GNT contract is in Funding state. bool public funding = true; // Receives ETH and its own GNT endowment. address public golemFactory; // Has control over token migration to next version of token. address public migrationMaster; GNTAllocation lockedAllocation; // The current total token supply. uint256 totalTokens; mapping (address => uint256) balances; address public migrationAgent; uint256 public totalMigrated; event Transfer(address indexed _from, address indexed _to, uint256 _value); event Migrate(address indexed _from, address indexed _to, uint256 _value); event Refund(address indexed _from, uint256 _value); function GolemNetworkToken(address _golemFactory, address _migrationMaster, uint256 _fundingStartBlock, uint256 _fundingEndBlock) { if (_golemFactory == 0) throw; if (_migrationMaster == 0) throw; if (_fundingStartBlock <= block.number) throw; if (_fundingEndBlock <= _fundingStartBlock) throw; lockedAllocation = new GNTAllocation(_golemFactory); migrationMaster = _migrationMaster; golemFactory = _golemFactory; fundingStartBlock = _fundingStartBlock; fundingEndBlock = _fundingEndBlock; } /// @notice Transfer `_value` GNT tokens from sender's account /// `msg.sender` to provided account address `_to`. /// @notice This function is disabled during the funding. /// @dev Required state: Operational /// @param _to The address of the tokens recipient /// @param _value The amount of token to be transferred /// @return Whether the transfer was successful or not function transfer(address _to, uint256 _value) returns (bool) { // Abort if not in Operational state. if (funding) throw; var senderBalance = balances[msg.sender]; if (senderBalance >= _value && _value > 0) { senderBalance -= _value; balances[msg.sender] = senderBalance; balances[_to] += _value; Transfer(msg.sender, _to, _value); return true; } return false; } function totalSupply() external constant returns (uint256) { return totalTokens; } function balanceOf(address _owner) external constant returns (uint256) { return balances[_owner]; } // Token migration support: /// @notice Migrate tokens to the new token contract. /// @dev Required state: Operational Migration /// @param _value The amount of token to be migrated function migrate(uint256 _value) external { // Abort if not in Operational Migration state. if (funding) throw; if (migrationAgent == 0) throw; // Validate input value. if (_value == 0) throw; if (_value > balances[msg.sender]) throw; balances[msg.sender] -= _value; totalTokens -= _value; totalMigrated += _value; MigrationAgent(migrationAgent).migrateFrom(msg.sender, _value); Migrate(msg.sender, migrationAgent, _value); } /// @notice Set address of migration target contract and enable migration /// process. /// @dev Required state: Operational Normal /// @dev State transition: -> Operational Migration /// @param _agent The address of the MigrationAgent contract function setMigrationAgent(address _agent) external { // Abort if not in Operational Normal state. if (funding) throw; if (migrationAgent != 0) throw; if (msg.sender != migrationMaster) throw; migrationAgent = _agent; } function setMigrationMaster(address _master) external { if (msg.sender != migrationMaster) throw; if (_master == 0) throw; migrationMaster = _master; } // Crowdfunding: /// @notice Create tokens when funding is active. /// @dev Required state: Funding Active /// @dev State transition: -> Funding Success (only if cap reached) function create() payable external { // Abort if not in Funding Active state. // The checks are split (instead of using or operator) because it is // cheaper this way. if (!funding) throw; if (block.number < fundingStartBlock) throw; if (block.number > fundingEndBlock) throw; // Do not allow creating 0 or more than the cap tokens. if (msg.value == 0) throw; if (msg.value > (tokenCreationCap - totalTokens) / tokenCreationRate) throw; var numTokens = msg.value * tokenCreationRate; totalTokens += numTokens; // Assign new tokens to the sender balances[msg.sender] += numTokens; // Log token creation event Transfer(0, msg.sender, numTokens); } /// @notice Finalize crowdfunding /// @dev If cap was reached or crowdfunding has ended then: /// create GNT for the Golem Factory and developer, /// transfer ETH to the Golem Factory address. /// @dev Required state: Funding Success /// @dev State transition: -> Operational Normal function finalize() external { // Abort if not in Funding Success state. if (!funding) throw; if ((block.number <= fundingEndBlock || totalTokens < tokenCreationMin) && totalTokens < tokenCreationCap) throw; // Switch to Operational state. This is the only place this can happen. funding = false; // Create additional GNT for the Golem Factory and developers as // the 18% of total number of tokens. // All additional tokens are transfered to the account controller by // GNTAllocation contract which will not allow using them for 6 months. uint256 percentOfTotal = 18; uint256 additionalTokens = totalTokens * percentOfTotal / (100 - percentOfTotal); totalTokens += additionalTokens; balances[lockedAllocation] += additionalTokens; Transfer(0, lockedAllocation, additionalTokens); // Transfer ETH to the Golem Factory address. if (!golemFactory.send(this.balance)) throw; } /// @notice Get back the ether sent during the funding in case the funding /// has not reached the minimum level. /// @dev Required state: Funding Failure function refund() external { // Abort if not in Funding Failure state. if (!funding) throw; if (block.number <= fundingEndBlock) throw; if (totalTokens >= tokenCreationMin) throw; var gntValue = balances[msg.sender]; if (gntValue == 0) throw; balances[msg.sender] = 0; totalTokens -= gntValue; var ethValue = gntValue / tokenCreationRate; Refund(msg.sender, ethValue); if (!msg.sender.send(ethValue)) throw; } } /// @title Migration Agent interface contract MigrationAgent { function migrateFrom(address _from, uint256 _value); } /// @title GNT Allocation - Time-locked vault of tokens allocated /// to developers and Golem Factory contract GNTAllocation { // Total number of allocations to distribute additional tokens among // developers and the Golem Factory. The Golem Factory has right to 20000 // allocations, developers to 10000 allocations, divides among individual // developers by numbers specified in `allocations` table. uint256 constant totalAllocations = 30000; // Addresses of developer and the Golem Factory to allocations mapping. mapping (address => uint256) allocations; GolemNetworkToken gnt; uint256 unlockedAt; uint256 tokensCreated = 0; function GNTAllocation(address _golemFactory) internal { gnt = GolemNetworkToken(msg.sender); unlockedAt = now + 6 * 30 days; // For the Golem Factory: allocations[_golemFactory] = 20000; // 12/18 pp of 30000 allocations. // For developers: allocations[0x9d3F257827B17161a098d380822fa2614FF540c8] = 2500; // 25.0% of developers' allocations (10000). allocations[0xd7406E50b73972Fa4aa533a881af68B623Ba3F66] = 730; // 7.3% of developers' allocations. allocations[0xd15356D05A7990dE7eC94304B0fD538e550c09C0] = 730; allocations[0x3971D17B62b825b151760E2451F818BfB64489A7] = 730; allocations[0x95e337d09f1bc67681b1cab7ed1125ea2bae5ca8] = 730; allocations[0x0025C58dB686b8CEce05CB8c50C1858b63Aa396E] = 730; allocations[0xB127FC62dE6ca30aAc9D551591daEDdeBB2eFD7A] = 630; // 6.3% of developers' allocations. allocations[0x21AF2E2c240a71E9fB84e90d71c2B2AddE0D0e81] = 630; allocations[0x682AA1C3b3E102ACB9c97B861d595F9fbfF0f1B8] = 630; allocations[0x6edd429c77803606cBd6Bb501CC701a6CAD6be01] = 630; allocations[0x5E455624372FE11b39464e93d41D1F6578c3D9f6] = 310; // 3.1% of developers' allocations. allocations[0xB7c7EaD515Ca275d53e30B39D8EBEdb3F19dA244] = 138; // 1.38% of developers' allocations. allocations[0xD513b1c3fe31F3Fe0b1E42aa8F55e903F19f1730] = 135; // 1.35% of developers' allocations. allocations[0x70cac7f8E404EEFce6526823452e428b5Ab09b00] = 100; // 1.0% of developers' allocations. allocations[0xe0d5861e7be0fac6c85ecde6e8bf76b046a96149] = 100; allocations[0x17488694D2feE4377Ec718836bb9d4910E81D9Cf] = 100; allocations[0xb481372086dEc3ca2FCCD3EB2f462c9C893Ef3C5] = 100; allocations[0xFB6D91E69CD7990651f26a3aa9f8d5a89159fC92] = 70; // 0.7% of developers' allocations. allocations[0xE2ABdAe2980a1447F445cb962f9c0bef1B63EE13] = 70; allocations[0x729A5c0232712caAf365fDd03c39cb361Bd41b1C] = 70; allocations[0x12FBD8fef4903f62e30dD79AC7F439F573E02697] = 70; allocations[0x657013005e5cFAF76f75d03b465cE085d402469A] = 42; // 0.42% of developers' allocations. allocations[0xD0AF9f75EA618163944585bF56aCA98204d0AB66] = 25; // 0.25% of developers' allocations. } /// @notice Allow developer to unlock allocated tokens by transferring them /// from GNTAllocation to developer's address. function unlock() external { if (now < unlockedAt) throw; // During first unlock attempt fetch total number of locked tokens. if (tokensCreated == 0) tokensCreated = gnt.balanceOf(this); var allocation = allocations[msg.sender]; allocations[msg.sender] = 0; var toTransfer = tokensCreated * allocation / totalAllocations; // Will fail if allocation (and therefore toTransfer) is 0. if (!gnt.transfer(msg.sender, toTransfer)) throw; } } |
Source code from Github
Crowdfunding source code from https://github.com/imapp-pl/golem-crowdfunding at Oct 28 2016 14:57:36 UTC. Still to be audited.
Token.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 279 280 281 282 |
pragma solidity ^0.4.1; contract MigrationAgent { function migrateFrom(address _from, uint256 _value); } contract GolemNetworkToken { string public constant name = "Golem Network Token"; string public constant symbol = "GNT"; uint8 public constant decimals = 18; // 18 decimal places, the same as ETH. uint256 public constant tokenCreationRate = 1000; // The funding cap in weis. uint256 public constant tokenCreationCap = 820000 ether * tokenCreationRate; uint256 public constant tokenCreationMin = 150000 ether * tokenCreationRate; uint256 fundingStartBlock; uint256 fundingEndBlock; // The flag indicates if the GNT contract is in "funding" mode. bool fundingMode = true; // Receives ETH and its own GNT endowment. address public golemFactory; // Has control over token migration to next version of token. address public migrationMaster; // The currect total token supply. uint256 totalTokens; mapping (address => uint256) balances; address public migrationAgent; uint256 public totalMigrated; event Transfer(address indexed _from, address indexed _to, uint256 _value); event Migrate(address indexed _from, address indexed _to, uint256 _value); event Refund(address indexed _from, uint256 _value); // Checks if in Funding Active state. Aborts transaction otherwise. modifier inFundingActive { if (!fundingMode) throw; // FundingActive: b ≥ Start and b ≤ End and t < Max if (block.number < fundingStartBlock || block.number > fundingEndBlock || totalTokens >= tokenCreationCap) throw; _; } // Checks if in Funding Failure state. Aborts transaction otherwise. modifier inFundingFailure { if (!fundingMode) throw; // FundingFailure: b > End and t < Min if (block.number <= fundingEndBlock || totalTokens >= tokenCreationMin) throw; _; } // Checks if in Funding Success state. Aborts transaction otherwise. modifier inFundingSuccess { if (!fundingMode) throw; // FundingSuccess: (b > End and t ≥ Min) or t ≥ Max if ((block.number <= fundingEndBlock || totalTokens < tokenCreationMin) && totalTokens < tokenCreationCap) throw; _; } // Checks if in Operational state. Aborts transaction otherwise. modifier inOperational { if (fundingMode) throw; _; } // Checks if in Operational Normal state. Aborts transaction otherwise. modifier inNormal { if (fundingMode) throw; if (migrationAgent != 0) throw; _; } // Checks if in Operational Migration state. Aborts transaction otherwise. modifier inMigration { if (fundingMode) throw; if (migrationAgent == 0) throw; _; } function GolemNetworkToken(address _golemFactory, address _migrationMaster, uint256 _fundingStartBlock, uint256 _fundingEndBlock) { migrationMaster = _migrationMaster; golemFactory = _golemFactory; fundingStartBlock = _fundingStartBlock; fundingEndBlock = _fundingEndBlock; } function transfer(address _to, uint256 _value) inOperational returns (bool) { var senderBalance = balances[msg.sender]; if (senderBalance >= _value && _value > 0) { senderBalance -= _value; balances[msg.sender] = senderBalance; balances[_to] += _value; Transfer(msg.sender, _to, _value); return true; } return false; } function totalSupply() external constant returns (uint256) { return totalTokens; } function balanceOf(address _owner) external constant returns (uint256) { return balances[_owner]; } // Token migration support: function migrate(uint256 _value) inMigration external { if (_value == 0 || _value > balances[msg.sender]) throw; balances[msg.sender] -= _value; totalTokens -= _value; totalMigrated += _value; MigrationAgent(migrationAgent).migrateFrom(msg.sender, _value); Migrate(msg.sender, migrationAgent, _value); } function setMigrationAgent(address _agent) inNormal external { if (msg.sender != migrationMaster) throw; migrationAgent = _agent; } function setMigrationMaster(address _master) external { if (msg.sender != migrationMaster) throw; migrationMaster = _master; } // Crowdfunding: function fundingActive() constant external returns (bool) { // Copy of inFundingActive. if (!fundingMode) return false; // b ≥ Start and b ≤ End and t < Max if (block.number < fundingStartBlock || block.number > fundingEndBlock || totalTokens >= tokenCreationCap) return false; return true; } // Helper function to get number of tokens left during the funding. function numberOfTokensLeft() constant external returns (uint256) { if (!fundingMode) return 0; if (block.number > fundingEndBlock) return 0; return tokenCreationCap - totalTokens; } function finalized() constant external returns (bool) { return !fundingMode; } // Create tokens when funding is active // Update state when funding period lapses and/or min/max funding occurs function() payable inFundingActive external { if (msg.value == 0) throw; // Do not create more than cap var numTokens = msg.value * tokenCreationRate; totalTokens += numTokens; if (totalTokens > tokenCreationCap) throw; // Assign new tokens to the sender balances[msg.sender] += numTokens; // Log token creation event Transfer(0, msg.sender, numTokens); } // If cap was reached or crowdfunding has ended then: // Transfer ETH to the golemFactory address // Create GNT for the golemFactory (representing the company) // Create GNT for the developers // Update GNT state (number of tokens) function finalize() inFundingSuccess external { // Switch to Operational state. This is the only place this can happen. fundingMode = false; // 1. Transfer ETH to the golemFactory address if (!golemFactory.send(this.balance)) throw; // Create additional GNT for the Factory (representing the company) // and developers. createAdditionalTokens(); } function refund() inFundingFailure external { var gntValue = balances[msg.sender]; if (gntValue == 0) throw; balances[msg.sender] = 0; totalTokens -= gntValue; var ethValue = gntValue / tokenCreationRate; if (!msg.sender.send(ethValue)) throw; Refund(msg.sender, ethValue); } struct Dev { address addr; uint share; } // Creates additional 12% of tokens for the Factory and 6% for developers. function createAdditionalTokens() internal { // TODO: SET before THE CROWDFUNDING! // Invariants: // dev0Percent + dev1Percent + dev2Percent + dev3Percent + dev4Percent + dev5Percent = 100 // dev0Percent > 0 && dev1Percent > 0 && dev2Percent > 0 && dev3Percent > 0 && dev4Percent > 0 && dev5Percent > 0 uint256 percentTokensGolemFactory = 12; uint256 percentTokensDevelopers = 6; // List of developer addresses and their shares. // The sum of shares is 10000. var devs = [ Dev(0xde00, 2500) Dev(0xde01, 730) Dev(0xde02, 730) Dev(0xde03, 730) Dev(0xde04, 730) Dev(0xde05, 730) Dev(0xde06, 630) Dev(0xde07, 630) Dev(0xde08, 630) Dev(0xde09, 630) Dev(0xde10, 310) Dev(0xde11, 153) Dev(0xde12, 150) Dev(0xde13, 100) Dev(0xde14, 100) Dev(0xde15, 100) Dev(0xde16, 70) Dev(0xde17, 70) Dev(0xde18, 70) Dev(0xde19, 70) Dev(0xde20, 70) Dev(0xde21, 42) Dev(0xde22, 25) ]; var numAdditionalTokens = totalTokens * (percentTokensGolemFactory + percentTokensDevelopers) / (100 - percentTokensGolemFactory - percentTokensDevelopers); var numTokensForDevs = numAdditionalTokens * percentTokensDevelopers / (percentTokensGolemFactory + percentTokensDevelopers); uint256 numTokensAssigned = 0; var len = devs.length; for (uint256 i = 0; i < len; ++i) { var dev = devs[i]; var n = dev.share * numTokensForDevs / 10000; numTokensAssigned += n; balances[dev.addr] += n; // Log token creation event for developers Transfer(0, dev.addr, n); } var numTokensForGolemFactory = numAdditionalTokens - numTokensAssigned; balances[golemFactory] += numTokensForGolemFactory; // Log token creation event for golemFactory Transfer(0, golemFactory, numTokensForGolemFactory); // Update GNT state (number of tokens) totalTokens += numAdditionalTokens; } } |
ProxyAccount.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 |
pragma solidity ^0.4.1; import "./Token.sol"; contract TimeLockedGNTProxyAccount { address public owner; uint256 public availableAfter; GolemNetworkToken public gnt; // Modifiers modifier ownerOnly { if (msg.sender != owner) throw; _; } modifier notLocked { if (now < availableAfter) throw; _; } // Creation and initialization function TimeLockedGNTProxyAccount(uint256 _availableAfter) { owner = msg.sender; availableAfter = _availableAfter; } function setGNTContract(address _gnt) ownerOnly external { gnt = GolemNetworkToken(_gnt); } // Token interface function transfer(address _to, uint256 _value) notLocked ownerOnly returns (bool success) { return gnt.transfer(_to, _value); } // Migration interface function migrate(uint256 _value) ownerOnly external { gnt.migrate(_value); } // Default function - do not allow any eth transfers to this contract function() payable { throw; } } contract TimeLockedGolemFactoryProxyAccount is TimeLockedGNTProxyAccount { // Creation and initialization function TimeLockedGolemFactoryProxyAccount(uint256 _availableAfter) TimeLockedGNTProxyAccount(_availableAfter) { } // Modifiers modifier gntOnly { if (msg.sender != address(gnt)) throw; _; } // Golem Factory privileged API function setMigrationMaster(address _migrationMaster) ownerOnly external { gnt.setMigrationMaster(_migrationMaster); } // Migration interface function setMigrationAgent(address _agent) ownerOnly external { gnt.setMigrationAgent(_agent); } // Default function - allow transfers from the GNT contract only function() gntOnly payable { } // Withdraw - transfer ETH to to the Golem Factory function withdraw() ownerOnly { if (!owner.send(this.balance)) throw; } } |
ExampleMigration.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 |
pragma solidity ^0.4.1; import * as Source from "./Token.sol"; contract GNTTargetToken { address migrationAgent; // ERC20 variables uint256 totalTokens; mapping (address => uint256) balances; // ERC20 events event Transfer(address indexed _from, address indexed _to, uint256 _value); function GNTTargetToken(address _migrationAgent) { migrationAgent = _migrationAgent; //Additional constructor code gets here } // Migration related methods function createToken(address _target, uint256 _amount) { if (msg.sender != migrationAgent) throw; balances[_target] += _amount; totalTokens += _amount; Transfer(migrationAgent, _target, _amount); } function finalizeMigration() { if (msg.sender != migrationAgent) throw; migrationAgent = 0; } // ERC20 interface (implemented according to the requirements) function transfer(address _to, uint256 _value) returns (bool success) { if (balances[msg.sender] >= _value && _value > 0) { balances[msg.sender] -= _value; balances[_to] += _value; Transfer(msg.sender, _to, _value); return true; } return false; } function totalSupply() constant returns (uint256) { return totalTokens; } function balanceOf(address _owner) constant returns (uint256 balance) { return balances[_owner]; } } //Test the whole process against this: https://www.kingoftheether.com/contract-safety-checklist.html contract MigrationAgent { address owner; address gntSourceToken; address gntTargetToken; uint256 tokenSupply; function MigrationAgent(address _gntSourceToken) { owner = msg.sender; gntSourceToken = _gntSourceToken; if (!Source.GolemNetworkToken(gntSourceToken).finalized()) throw; tokenSupply = Source.GolemNetworkToken(gntSourceToken).totalSupply(); } function safetyInvariantCheck(uint256 _value) private { if (gntTargetToken == 0) throw; if (Source.GolemNetworkToken(gntSourceToken).totalSupply() + GNTTargetToken(gntTargetToken).totalSupply() != tokenSupply - _value) throw; } function setTargetToken(address _gntTargetToken) { if (msg.sender != owner) throw; if (gntTargetToken != 0) throw; //Allow this change once only gntTargetToken = _gntTargetToken; } //Interface implementation function migrateFrom(address _from, uint256 _value) { if (msg.sender != gntSourceToken) throw; if (gntTargetToken == 0) throw; //Right here gntSourceToken has already been updated, but corresponding GNT have not been created in the gntTargetToken contract yet safetyInvariantCheck(_value); GNTTargetToken(gntTargetToken).createToken(_from, _value); //Right here totalSupply invariant must hold safetyInvariantCheck(0); } function finalizeMigration() { if (msg.sender != owner) throw; safetyInvariantCheck(0); //Additional, strict test //if (gntSourceToken.totalSupply() > 0) throw; GNTTargetToken(gntTargetToken).finalizeMigration(); gntSourceToken = 0; gntTargetToken = 0; tokenSupply = 0; } } |
BadWallet.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 |
pragma solidity ^0.4.1; import * as Source from "./Token.sol"; contract BadWallet { uint16 extra_work = 0; // amount of work to be done when accepting payment uint16 public out_i; address wallet; function BadWallet() { } function get_out_i() returns (uint16 a) { return out_i; } function set_extra_work(uint16 _extra_work) { extra_work = _extra_work; } function get_extra_work() returns (uint16 a) { return extra_work; } function deploy_contract(address _golemFactory, uint256 _fundingStartBlock, uint256 _fundingEndBlock) returns (address a) { wallet = new Source.GolemNetworkToken(_golemFactory, _golemFactory, _fundingStartBlock, _fundingEndBlock); return wallet; } function finalize(address _crowdfundingContract) { Source.GolemNetworkToken(_crowdfundingContract).finalize(); } /* trap function which will burn gas, causing send to fail */ function() payable { for (uint16 i = 1; i <= extra_work; i++) { out_i = i; } } } |