From f92cbb24dcd6093fa0527d9d879f9c5235ff7907 Mon Sep 17 00:00:00 2001 From: Jordi Baylina Date: Wed, 22 Feb 2017 07:55:37 +0100 Subject: [PATCH 1/4] ERC20 fully compatible --- legends_token.sol | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/legends_token.sol b/legends_token.sol index 9069d11..3aacbc1 100644 --- a/legends_token.sol +++ b/legends_token.sol @@ -7,12 +7,16 @@ import "./erc20.sol"; * @title LegendsToken */ contract LegendsToken is ERC20 { + string public name = 'VIP'; //The Token's name: e.g. DigixDAO Tokens + uint8 public decimals = 17; // 1Token ¨= 1$ (1ETH ¨= 10$) + string public symbol = 'VIP'; //An identifier: e.g. REP + string public version = 'VIP_0.1'; mapping (address => uint) ownerVIP; mapping (address => mapping (address => uint)) allowed; uint public totalVIP; uint public start; - + address public legendsCrowdfund; bool public testing; @@ -23,7 +27,7 @@ contract LegendsToken is ERC20 { } _; } - + modifier isActive() { if (block.timestamp < start) { throw; @@ -47,14 +51,14 @@ contract LegendsToken is ERC20 { modifier senderHasSufficient(uint VIP) { if (ownerVIP[msg.sender] < VIP) { - throw; + return false; } _; } modifier transferApproved(address from, uint VIP) { if (allowed[from][msg.sender] < VIP || ownerVIP[from] < VIP) { - throw; + return false; } _; } @@ -89,7 +93,7 @@ contract LegendsToken is ERC20 { testing = _testing; totalVIP = ownerVIP[_preallocation] = 25000 ether; } - + /** * @dev Add to token balance on address. Must be from crowdfund. * @param recipient Address to add tokens to. From 1dd0459a956707dd193a3f7b01a539d544761871 Mon Sep 17 00:00:00 2001 From: Jordi Baylina Date: Wed, 22 Feb 2017 08:19:38 +0100 Subject: [PATCH 2/4] modifiers does not accept return so move it to the method --- legends_crowdfund.sol | 164 ++++++++++++++++++++++++------------------ 1 file changed, 96 insertions(+), 68 deletions(-) diff --git a/legends_crowdfund.sol b/legends_crowdfund.sol index 81a712f..ce83ad5 100644 --- a/legends_crowdfund.sol +++ b/legends_crowdfund.sol @@ -1,46 +1,47 @@ pragma solidity ^0.4.9; -import "./legends_token.sol"; +import "./erc20.sol"; /** - * @title LegendsCrowdfund + * @title LegendsToken */ -contract LegendsCrowdfund { - - address public creator; - address public exitAddress; - +contract LegendsToken is ERC20 { + string public name = 'VIP'; //The Token's name: e.g. DigixDAO Tokens + uint8 public decimals = 17; // 1Token ¨= 1$ (1ETH ¨= 10$) + string public symbol = 'VIP'; //An identifier: e.g. REP + string public version = 'VIP_0.1'; + + mapping (address => uint) ownerVIP; + mapping (address => mapping (address => uint)) allowed; + uint public totalVIP; uint public start; - uint public limitVIP; - - LegendsToken public legendsToken; - mapping (address => uint) public recipientETH; - mapping (address => uint) public recipientVIP; - - uint public totalETH; - uint public totalVIP; + address public legendsCrowdfund; - event VIPPurchase(address indexed sender, address indexed recipient, uint ETH, uint VIP); + bool public testing; - modifier saleActive() { - if (address(legendsToken) == 0) { + modifier fromCrowdfund() { + if (msg.sender != legendsCrowdfund) { throw; } + _; + } + + modifier isActive() { if (block.timestamp < start) { throw; } _; } - modifier hasValue() { - if (msg.value == 0) { + modifier isNotActive() { + if (!testing && block.timestamp >= start) { throw; } _; } - + modifier recipientIsValid(address recipient) { if (recipient == 0 || recipient == address(this)) { throw; @@ -48,78 +49,105 @@ contract LegendsCrowdfund { _; } - modifier isCreator() { - if (msg.sender != creator) { + modifier allowanceIsZero(address spender, uint value) { + // To change the approve amount you first have to reduce the addresses´ + // allowance to zero by calling `approve(_spender,0)` if it is not + // already 0 to mitigate the race condition described here: + // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + if ((value != 0) && (allowed[msg.sender][spender] != 0)) { throw; } _; } - modifier tokenContractNotSet() { - if (address(legendsToken) != 0) { - throw; - } - _; - } + /** + * @dev Tokens have been added to an address by the crowdfunding contract. + * @param recipient Address receiving the VIP. + * @param VIP Amount of VIP added. + */ + event TokensAdded(address indexed recipient, uint VIP); /** * @dev Constructor. - * @param _exitAddress Address that all ETH should be forwarded to. - * @param _start Timestamp of when the crowdsale will start. - * @param _limitVIP Maximum amount of VIP that can be allocated in total. Denominated in wei. + * @param _legendsCrowdfund Address of crowdfund contract. + * @param _preallocation Address to receive the pre-allocation. + * @param _start Timestamp when the token becomes active. */ - function LegendsCrowdfund(address _exitAddress, uint _start, uint _limitVIP) { - creator = msg.sender; - exitAddress = _exitAddress; + function LegendsToken(address _legendsCrowdfund, address _preallocation, uint _start, bool _testing) { + legendsCrowdfund = _legendsCrowdfund; start = _start; - limitVIP = _limitVIP; + testing = _testing; + totalVIP = ownerVIP[_preallocation] = 25000 ether; } /** - * @dev Set the address of the token contract. Must be called by creator of this. Can only be set once. - * @param _legendsToken Address of the token contract. + * @dev Add to token balance on address. Must be from crowdfund. + * @param recipient Address to add tokens to. + * @return VIP Amount of VIP to add. */ - function setTokenContract(LegendsToken _legendsToken) external isCreator tokenContractNotSet { - legendsToken = _legendsToken; + function addTokens(address recipient, uint VIP) external isNotActive fromCrowdfund { + ownerVIP[recipient] += VIP; + totalVIP += VIP; + TokensAdded(recipient, VIP); } /** - * @dev Forward Ether to the exit address. Store all ETH and VIP information in public state and logs. - * @param recipient Address that tokens should be attributed to. + * @dev Implements ERC20 totalSupply() */ - function purchaseMembership(address recipient) external payable saleActive hasValue recipientIsValid(recipient) { - - // Attempt to send the ETH to the exit address. - if (!exitAddress.send(msg.value)) { - throw; - } - - // Update ETH amounts. - recipientETH[recipient] += msg.value; - totalETH += msg.value; + function totalSupply() constant returns (uint256 totalSupply) { + totalSupply = totalVIP; + } - // Calculate VIP amount. - uint VIP = msg.value * 10; // $1 / VIP based on $10 / ETH value. + /** + * @dev Implements ERC20 balanceOf() + */ + function balanceOf(address _owner) constant returns (uint256 balance) { + balance = ownerVIP[_owner]; + } - // Are we in the pre-sale? - if (block.timestamp - start < 2 weeks) { - VIP = (VIP * 10) / 9; // 10% discount. + /** + * @dev Implements ERC20 transfer() + */ + function transfer(address _to, uint256 _value) isActive recipientIsValid(_to) returns (bool success) { + if (ownerVIP[msg.sender] >= _value) { + ownerVIP[msg.sender] -= _value; + ownerVIP[_to] += _value; + Transfer(msg.sender, _to, _value); + return true; + } else { + return false; } + } - // Update VIP amounts. - recipientVIP[recipient] += VIP; - totalVIP += VIP; - - // Check we have not exceeded the maximum VIP. - if (totalVIP > limitVIP) { - throw; + /** + * @dev Implements ERC20 transferFrom() + */ + function transferFrom(address _from, address _to, uint256 _value) isActive recipientIsValid(_to) returns (bool success) { + if (allowed[_from][msg.sender] >= _value && ownerVIP[_from] >= _value) { + ownerVIP[_to] += _value; + ownerVIP[_from] -= _value; + allowed[_from][msg.sender] -= _value; + Transfer(_from, _to, _value); + return true; + } else { + return false; } + } - // Tell the token contract about the increase. - legendsToken.addTokens(recipient, VIP); + /** + * @dev Implements ERC20 approve() + */ + function approve(address _spender, uint256 _value) isActive allowanceIsZero(_spender, _value) returns (bool success) { + allowed[msg.sender][_spender] = _value; + Approval(msg.sender, _spender, _value); + return true; + } - // Log this purchase. - VIPPurchase(msg.sender, recipient, msg.value, VIP); + /** + * @dev Implements ERC20 allowance() + */ + function allowance(address _owner, address _spender) constant returns (uint256 remaining) { + remaining = allowed[_owner][_spender]; } } From c077c890ce66debcfae980c3dc320d627a3b9985 Mon Sep 17 00:00:00 2001 From: Jordi Baylina Date: Wed, 22 Feb 2017 09:10:49 +0100 Subject: [PATCH 3/4] Undo the wrong replacement --- legends_crowdfund.sol | 162 +++++++++++++++++------------------------- legends_token.sol | 44 +++++------- 2 files changed, 86 insertions(+), 120 deletions(-) diff --git a/legends_crowdfund.sol b/legends_crowdfund.sol index ce83ad5..f1e413e 100644 --- a/legends_crowdfund.sol +++ b/legends_crowdfund.sol @@ -1,42 +1,41 @@ pragma solidity ^0.4.9; -import "./erc20.sol"; +import "./legends_token.sol"; /** - * @title LegendsToken + * @title LegendsCrowdfund */ -contract LegendsToken is ERC20 { - string public name = 'VIP'; //The Token's name: e.g. DigixDAO Tokens - uint8 public decimals = 17; // 1Token ¨= 1$ (1ETH ¨= 10$) - string public symbol = 'VIP'; //An identifier: e.g. REP - string public version = 'VIP_0.1'; - - mapping (address => uint) ownerVIP; - mapping (address => mapping (address => uint)) allowed; - uint public totalVIP; +contract LegendsCrowdfund { + + address public creator; + address public exitAddress; + uint public start; + uint public limitVIP; + + LegendsToken public legendsToken; + + mapping (address => uint) public recipientETH; + mapping (address => uint) public recipientVIP; - address public legendsCrowdfund; + uint public totalETH; + uint public totalVIP; - bool public testing; + event VIPPurchase(address indexed sender, address indexed recipient, uint ETH, uint VIP); - modifier fromCrowdfund() { - if (msg.sender != legendsCrowdfund) { + modifier saleActive() { + if (address(legendsToken) == 0) { throw; } - _; - } - - modifier isActive() { if (block.timestamp < start) { throw; } _; } - modifier isNotActive() { - if (!testing && block.timestamp >= start) { + modifier hasValue() { + if (msg.value == 0) { throw; } _; @@ -49,105 +48,78 @@ contract LegendsToken is ERC20 { _; } - modifier allowanceIsZero(address spender, uint value) { - // To change the approve amount you first have to reduce the addresses´ - // allowance to zero by calling `approve(_spender,0)` if it is not - // already 0 to mitigate the race condition described here: - // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 - if ((value != 0) && (allowed[msg.sender][spender] != 0)) { + modifier isCreator() { + if (msg.sender != creator) { throw; } _; } - /** - * @dev Tokens have been added to an address by the crowdfunding contract. - * @param recipient Address receiving the VIP. - * @param VIP Amount of VIP added. - */ - event TokensAdded(address indexed recipient, uint VIP); + modifier tokenContractNotSet() { + if (address(legendsToken) != 0) { + throw; + } + _; + } /** * @dev Constructor. - * @param _legendsCrowdfund Address of crowdfund contract. - * @param _preallocation Address to receive the pre-allocation. - * @param _start Timestamp when the token becomes active. + * @param _exitAddress Address that all ETH should be forwarded to. + * @param _start Timestamp of when the crowdsale will start. + * @param _limitVIP Maximum amount of VIP that can be allocated in total. Denominated in wei. */ - function LegendsToken(address _legendsCrowdfund, address _preallocation, uint _start, bool _testing) { - legendsCrowdfund = _legendsCrowdfund; + function LegendsCrowdfund(address _exitAddress, uint _start, uint _limitVIP) { + creator = msg.sender; + exitAddress = _exitAddress; start = _start; - testing = _testing; - totalVIP = ownerVIP[_preallocation] = 25000 ether; + limitVIP = _limitVIP; } /** - * @dev Add to token balance on address. Must be from crowdfund. - * @param recipient Address to add tokens to. - * @return VIP Amount of VIP to add. + * @dev Set the address of the token contract. Must be called by creator of this. Can only be set once. + * @param _legendsToken Address of the token contract. */ - function addTokens(address recipient, uint VIP) external isNotActive fromCrowdfund { - ownerVIP[recipient] += VIP; - totalVIP += VIP; - TokensAdded(recipient, VIP); + function setTokenContract(LegendsToken _legendsToken) external isCreator tokenContractNotSet { + legendsToken = _legendsToken; } /** - * @dev Implements ERC20 totalSupply() + * @dev Forward Ether to the exit address. Store all ETH and VIP information in public state and logs. + * @param recipient Address that tokens should be attributed to. */ - function totalSupply() constant returns (uint256 totalSupply) { - totalSupply = totalVIP; - } + function purchaseMembership(address recipient) external payable saleActive hasValue recipientIsValid(recipient) { - /** - * @dev Implements ERC20 balanceOf() - */ - function balanceOf(address _owner) constant returns (uint256 balance) { - balance = ownerVIP[_owner]; - } + // Attempt to send the ETH to the exit address. + if (!exitAddress.send(msg.value)) { + throw; + } - /** - * @dev Implements ERC20 transfer() - */ - function transfer(address _to, uint256 _value) isActive recipientIsValid(_to) returns (bool success) { - if (ownerVIP[msg.sender] >= _value) { - ownerVIP[msg.sender] -= _value; - ownerVIP[_to] += _value; - Transfer(msg.sender, _to, _value); - return true; - } else { - return false; + // Update ETH amounts. + recipientETH[recipient] += msg.value; + totalETH += msg.value; + + // Calculate VIP amount. + uint VIP = msg.value * 10; // $1 / VIP based on $10 / ETH value. + + // Are we in the pre-sale? + if (block.timestamp - start < 2 weeks) { + VIP = (VIP * 10) / 9; // 10% discount. } - } - /** - * @dev Implements ERC20 transferFrom() - */ - function transferFrom(address _from, address _to, uint256 _value) isActive recipientIsValid(_to) returns (bool success) { - if (allowed[_from][msg.sender] >= _value && ownerVIP[_from] >= _value) { - ownerVIP[_to] += _value; - ownerVIP[_from] -= _value; - allowed[_from][msg.sender] -= _value; - Transfer(_from, _to, _value); - return true; - } else { - return false; + // Update VIP amounts. + recipientVIP[recipient] += VIP; + totalVIP += VIP; + + // Check we have not exceeded the maximum VIP. + if (totalVIP > limitVIP) { + throw; } - } - /** - * @dev Implements ERC20 approve() - */ - function approve(address _spender, uint256 _value) isActive allowanceIsZero(_spender, _value) returns (bool success) { - allowed[msg.sender][_spender] = _value; - Approval(msg.sender, _spender, _value); - return true; - } + // Tell the token contract about the increase. + legendsToken.addTokens(recipient, VIP); - /** - * @dev Implements ERC20 allowance() - */ - function allowance(address _owner, address _spender) constant returns (uint256 remaining) { - remaining = allowed[_owner][_spender]; + // Log this purchase. + VIPPurchase(msg.sender, recipient, msg.value, VIP); } } diff --git a/legends_token.sol b/legends_token.sol index 3aacbc1..ce83ad5 100644 --- a/legends_token.sol +++ b/legends_token.sol @@ -49,20 +49,6 @@ contract LegendsToken is ERC20 { _; } - modifier senderHasSufficient(uint VIP) { - if (ownerVIP[msg.sender] < VIP) { - return false; - } - _; - } - - modifier transferApproved(address from, uint VIP) { - if (allowed[from][msg.sender] < VIP || ownerVIP[from] < VIP) { - return false; - } - _; - } - modifier allowanceIsZero(address spender, uint value) { // To change the approve amount you first have to reduce the addresses´ // allowance to zero by calling `approve(_spender,0)` if it is not @@ -122,22 +108,30 @@ contract LegendsToken is ERC20 { /** * @dev Implements ERC20 transfer() */ - function transfer(address _to, uint256 _value) isActive recipientIsValid(_to) senderHasSufficient(_value) returns (bool success) { - ownerVIP[msg.sender] -= _value; - ownerVIP[_to] += _value; - Transfer(msg.sender, _to, _value); - return true; + function transfer(address _to, uint256 _value) isActive recipientIsValid(_to) returns (bool success) { + if (ownerVIP[msg.sender] >= _value) { + ownerVIP[msg.sender] -= _value; + ownerVIP[_to] += _value; + Transfer(msg.sender, _to, _value); + return true; + } else { + return false; + } } /** * @dev Implements ERC20 transferFrom() */ - function transferFrom(address _from, address _to, uint256 _value) isActive recipientIsValid(_to) transferApproved(_from, _value) returns (bool success) { - ownerVIP[_to] += _value; - ownerVIP[_from] -= _value; - allowed[_from][msg.sender] -= _value; - Transfer(_from, _to, _value); - return true; + function transferFrom(address _from, address _to, uint256 _value) isActive recipientIsValid(_to) returns (bool success) { + if (allowed[_from][msg.sender] >= _value && ownerVIP[_from] >= _value) { + ownerVIP[_to] += _value; + ownerVIP[_from] -= _value; + allowed[_from][msg.sender] -= _value; + Transfer(_from, _to, _value); + return true; + } else { + return false; + } } /** From b70165d7ebd1cb2f1de64bd2d1d0b8c421a4efe5 Mon Sep 17 00:00:00 2001 From: Jordi Baylina Date: Wed, 22 Feb 2017 09:53:21 +0100 Subject: [PATCH 4/4] decimals is 18. The croudsale already multiply this --- legends_token.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/legends_token.sol b/legends_token.sol index ce83ad5..5ffe87e 100644 --- a/legends_token.sol +++ b/legends_token.sol @@ -8,7 +8,7 @@ import "./erc20.sol"; */ contract LegendsToken is ERC20 { string public name = 'VIP'; //The Token's name: e.g. DigixDAO Tokens - uint8 public decimals = 17; // 1Token ¨= 1$ (1ETH ¨= 10$) + uint8 public decimals = 18; // 1Token ¨= 1$ (1ETH ¨= 10$) string public symbol = 'VIP'; //An identifier: e.g. REP string public version = 'VIP_0.1';