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(...).
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
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
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
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
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;
}
}
}