From fabd2045d2edfaf01a1ec5d2ca4570e7582a3ac3 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 17:13:28 +0200 Subject: [PATCH 01/40] Each contract their own file --- contracts/ApproveAndCallFallback.sol | 5 ++ contracts/Controlled.sol | 17 ++++++ contracts/MiniMeToken.sol | 90 +--------------------------- contracts/MinimeTokenFactory.sol | 43 +++++++++++++ contracts/TokenController.sol | 26 ++++++++ 5 files changed, 92 insertions(+), 89 deletions(-) create mode 100644 contracts/ApproveAndCallFallback.sol create mode 100644 contracts/Controlled.sol create mode 100644 contracts/MinimeTokenFactory.sol create mode 100644 contracts/TokenController.sol diff --git a/contracts/ApproveAndCallFallback.sol b/contracts/ApproveAndCallFallback.sol new file mode 100644 index 00000000..287f9a92 --- /dev/null +++ b/contracts/ApproveAndCallFallback.sol @@ -0,0 +1,5 @@ +pragma solidity 0.4.11; + +contract ApproveAndCallFallBack { + function receiveApproval(address from, uint256 _amount, address _token, bytes _data); +} diff --git a/contracts/Controlled.sol b/contracts/Controlled.sol new file mode 100644 index 00000000..863f4726 --- /dev/null +++ b/contracts/Controlled.sol @@ -0,0 +1,17 @@ +pragma solidity 0.4.11; + +contract Controlled { + /// @notice The address of the controller is the only address that can call + /// a function with this modifier + modifier onlyController { require(msg.sender == controller); _; } + + address public controller; + + function Controlled() { controller = msg.sender;} + + /// @notice Changes the controller of the contract + /// @param _newController The new controller of the contract + function changeController(address _newController) onlyController { + controller = _newController; + } +} diff --git a/contracts/MiniMeToken.sol b/contracts/MiniMeToken.sol index 404d071b..b066908c 100644 --- a/contracts/MiniMeToken.sol +++ b/contracts/MiniMeToken.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.6; +pragma solidity 0.4.11; /* Copyright 2016, Jordi Baylina @@ -26,51 +26,6 @@ pragma solidity ^0.4.6; /// @dev It is ERC20 compliant, but still needs to under go further testing. -/// @dev The token controller contract must implement these functions -contract TokenController { - /// @notice Called when `_owner` sends ether to the MiniMe Token contract - /// @param _owner The address that sent the ether to create tokens - /// @return True if the ether is accepted, false if it throws - function proxyPayment(address _owner) payable returns(bool); - - /// @notice Notifies the controller about a token transfer allowing the - /// controller to react if desired - /// @param _from The origin of the transfer - /// @param _to The destination of the transfer - /// @param _amount The amount of the transfer - /// @return False if the controller does not authorize the transfer - function onTransfer(address _from, address _to, uint _amount) returns(bool); - - /// @notice Notifies the controller about an approval allowing the - /// controller to react if desired - /// @param _owner The address that calls `approve()` - /// @param _spender The spender in the `approve()` call - /// @param _amount The amount in the `approve()` call - /// @return False if the controller does not authorize the approval - function onApprove(address _owner, address _spender, uint _amount) - returns(bool); -} - -contract Controlled { - /// @notice The address of the controller is the only address that can call - /// a function with this modifier - modifier onlyController { require(msg.sender == controller); _; } - - address public controller; - - function Controlled() { controller = msg.sender;} - - /// @notice Changes the controller of the contract - /// @param _newController The new controller of the contract - function changeController(address _newController) onlyController { - controller = _newController; - } -} - -contract ApproveAndCallFallBack { - function receiveApproval(address from, uint256 _amount, address _token, bytes _data); -} - /// @dev The actual token contract, the default controller is the msg.sender /// that deploys the contract, so usually this token will be deployed by a /// token controller contract, which Giveth will call a "Campaign" @@ -557,46 +512,3 @@ contract MiniMeToken is Controlled { ); } - - -//////////////// -// MiniMeTokenFactory -//////////////// - -/// @dev This contract is used to generate clone contracts from a contract. -/// In solidity this is the way to create a contract from a contract of the -/// same class -contract MiniMeTokenFactory { - - /// @notice Update the DApp by creating a new token with new functionalities - /// the msg.sender becomes the controller of this clone token - /// @param _parentToken Address of the token being cloned - /// @param _snapshotBlock Block of the parent token that will - /// determine the initial distribution of the clone token - /// @param _tokenName Name of the new token - /// @param _decimalUnits Number of decimals of the new token - /// @param _tokenSymbol Token Symbol for the new token - /// @param _transfersEnabled If true, tokens will be able to be transferred - /// @return The address of the new token contract - function createCloneToken( - address _parentToken, - uint _snapshotBlock, - string _tokenName, - uint8 _decimalUnits, - string _tokenSymbol, - bool _transfersEnabled - ) returns (MiniMeToken) { - MiniMeToken newToken = new MiniMeToken( - this, - _parentToken, - _snapshotBlock, - _tokenName, - _decimalUnits, - _tokenSymbol, - _transfersEnabled - ); - - newToken.changeController(msg.sender); - return newToken; - } -} diff --git a/contracts/MinimeTokenFactory.sol b/contracts/MinimeTokenFactory.sol new file mode 100644 index 00000000..6953e470 --- /dev/null +++ b/contracts/MinimeTokenFactory.sol @@ -0,0 +1,43 @@ +pragma solidity 0.4.11; + +//////////////// +// MiniMeTokenFactory +//////////////// + +/// @dev This contract is used to generate clone contracts from a contract. +/// In solidity this is the way to create a contract from a contract of the +/// same class +contract MiniMeTokenFactory { + + /// @notice Update the DApp by creating a new token with new functionalities + /// the msg.sender becomes the controller of this clone token + /// @param _parentToken Address of the token being cloned + /// @param _snapshotBlock Block of the parent token that will + /// determine the initial distribution of the clone token + /// @param _tokenName Name of the new token + /// @param _decimalUnits Number of decimals of the new token + /// @param _tokenSymbol Token Symbol for the new token + /// @param _transfersEnabled If true, tokens will be able to be transferred + /// @return The address of the new token contract + function createCloneToken( + address _parentToken, + uint _snapshotBlock, + string _tokenName, + uint8 _decimalUnits, + string _tokenSymbol, + bool _transfersEnabled + ) returns (MiniMeToken) { + MiniMeToken newToken = new MiniMeToken( + this, + _parentToken, + _snapshotBlock, + _tokenName, + _decimalUnits, + _tokenSymbol, + _transfersEnabled + ); + + newToken.changeController(msg.sender); + return newToken; + } +} diff --git a/contracts/TokenController.sol b/contracts/TokenController.sol new file mode 100644 index 00000000..3ee4c976 --- /dev/null +++ b/contracts/TokenController.sol @@ -0,0 +1,26 @@ +pragma solidity 0.4.11; + +/// @dev The token controller contract must implement these functions +interface TokenController { + /// @notice Called when `_owner` sends ether to the MiniMe Token contract + /// @param _owner The address that sent the ether to create tokens + /// @return True if the ether is accepted, false if it throws + function proxyPayment(address _owner) payable returns(bool); + + /// @notice Notifies the controller about a token transfer allowing the + /// controller to react if desired + /// @param _from The origin of the transfer + /// @param _to The destination of the transfer + /// @param _amount The amount of the transfer + /// @return False if the controller does not authorize the transfer + function onTransfer(address _from, address _to, uint _amount) returns(bool); + + /// @notice Notifies the controller about an approval allowing the + /// controller to react if desired + /// @param _owner The address that calls `approve()` + /// @param _spender The spender in the `approve()` call + /// @param _amount The amount in the `approve()` call + /// @return False if the controller does not authorize the approval + function onApprove(address _owner, address _spender, uint _amount) + returns(bool); +} From 5bec4a102bf78f2c6b9cfb397696740e1a9815b6 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 17:24:05 +0200 Subject: [PATCH 02/40] Add import statements --- contracts/MiniMeToken.sol | 5 +++++ contracts/{MinimeTokenFactory.sol => MiniMeTokenFactory.sol} | 2 ++ 2 files changed, 7 insertions(+) rename contracts/{MinimeTokenFactory.sol => MiniMeTokenFactory.sol} (98%) diff --git a/contracts/MiniMeToken.sol b/contracts/MiniMeToken.sol index b066908c..449fb85a 100644 --- a/contracts/MiniMeToken.sol +++ b/contracts/MiniMeToken.sol @@ -1,5 +1,10 @@ pragma solidity 0.4.11; +import './Controlled.sol'; +import './TokenController.sol'; +import './ApproveAndCallFallback.sol'; +import './MiniMeTokenFactory.sol'; + /* Copyright 2016, Jordi Baylina diff --git a/contracts/MinimeTokenFactory.sol b/contracts/MiniMeTokenFactory.sol similarity index 98% rename from contracts/MinimeTokenFactory.sol rename to contracts/MiniMeTokenFactory.sol index 6953e470..3d8f0e9d 100644 --- a/contracts/MinimeTokenFactory.sol +++ b/contracts/MiniMeTokenFactory.sol @@ -1,5 +1,7 @@ pragma solidity 0.4.11; +import './MiniMeToken.sol'; + //////////////// // MiniMeTokenFactory //////////////// From 0be4b8fbd0b40ec2c7f443c026ebd1fbf43feb83 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 17:25:16 +0200 Subject: [PATCH 03/40] Upgrade to solidity ^0.4.13 --- contracts/ApproveAndCallFallback.sol | 2 +- contracts/Controlled.sol | 2 +- contracts/MiniMeToken.sol | 2 +- contracts/MiniMeTokenFactory.sol | 2 +- contracts/SampleCampaign-TokenController.sol | 2 +- contracts/TokenController.sol | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/ApproveAndCallFallback.sol b/contracts/ApproveAndCallFallback.sol index 287f9a92..dbbee687 100644 --- a/contracts/ApproveAndCallFallback.sol +++ b/contracts/ApproveAndCallFallback.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.13; contract ApproveAndCallFallBack { function receiveApproval(address from, uint256 _amount, address _token, bytes _data); diff --git a/contracts/Controlled.sol b/contracts/Controlled.sol index 863f4726..2f6e10b0 100644 --- a/contracts/Controlled.sol +++ b/contracts/Controlled.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.13; contract Controlled { /// @notice The address of the controller is the only address that can call diff --git a/contracts/MiniMeToken.sol b/contracts/MiniMeToken.sol index 449fb85a..61f6f1d1 100644 --- a/contracts/MiniMeToken.sol +++ b/contracts/MiniMeToken.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.13; import './Controlled.sol'; import './TokenController.sol'; diff --git a/contracts/MiniMeTokenFactory.sol b/contracts/MiniMeTokenFactory.sol index 3d8f0e9d..6a0ed1ab 100644 --- a/contracts/MiniMeTokenFactory.sol +++ b/contracts/MiniMeTokenFactory.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.13; import './MiniMeToken.sol'; diff --git a/contracts/SampleCampaign-TokenController.sol b/contracts/SampleCampaign-TokenController.sol index 890b8ca1..8d4f36d7 100644 --- a/contracts/SampleCampaign-TokenController.sol +++ b/contracts/SampleCampaign-TokenController.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.6; +pragma solidity ^0.4.13; /* Copyright 2017, Jordi Baylina diff --git a/contracts/TokenController.sol b/contracts/TokenController.sol index 3ee4c976..e685513e 100644 --- a/contracts/TokenController.sol +++ b/contracts/TokenController.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.13; /// @dev The token controller contract must implement these functions interface TokenController { From bce811fbf089631c5346c38117b1b587bba1fce7 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 18:12:22 +0200 Subject: [PATCH 04/40] Add Snapshot contract --- contracts/Snapshot.sol | 115 +++++++++++++++++++++++++++++++++++++ contracts/SnapshotTest.sol | 36 ++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 contracts/Snapshot.sol create mode 100644 contracts/SnapshotTest.sol diff --git a/contracts/Snapshot.sol b/contracts/Snapshot.sol new file mode 100644 index 00000000..5dbe91e9 --- /dev/null +++ b/contracts/Snapshot.sol @@ -0,0 +1,115 @@ +pragma solidity ^0.4.13; + +contract Snapshot { + + /// @dev `Checkpoint` is the structure that attaches a block number to a + /// given value, the block number attached is the one that last changed the + /// value + struct Values { + + // `fromBlock` is the block number that the value was generated from + uint256 snapshot; + + // `value` is the amount of tokens at a specific block number + uint256 value; + } + + uint256 internal nextSnapshot; + + event SnapshotCreated(uint256 snapshot); + + function Snapshot() + internal + { + nextSnapshot = 0; + } + + function createSnapshot() + internal + returns (uint256) + { + uint256 snapshot = nextSnapshot; + nextSnapshot += 1; + SnapshotCreated(snapshot); + return snapshot; + } + + function getValue( + Values[] storage values, + uint _defaultValue + ) + internal + constant + returns (uint) + { + return getValueAt(values, nextSnapshot, _defaultValue); + } + + /// @dev `getValueAt` retrieves the number of tokens at a given block number + /// @param values The history of values being queried + /// @param _snapshot The block number to retrieve the value at + /// @return The number of tokens being queried + function getValueAt( + Values[] storage values, + uint _snapshot, + uint _defaultValue + ) + internal + constant + returns (uint) + { + if (values.length == 0) { + return _defaultValue; + } + + // Shortcut for the actual value + uint last = values.length - 1; + uint lastSnapshot = values[last].snapshot; + if (_snapshot >= lastSnapshot) { + return values[last].value; + } + uint firstSnapshot = values[0].snapshot; + if (_snapshot < firstSnapshot) { + return _defaultValue; + } + + // Binary search of the value in the array + uint min = 0; + uint max = last; + while (max > min) { + uint mid = (max + min + 1) / 2; + if (values[mid].snapshot <= _snapshot) { + min = mid; + } else { + max = mid - 1; + } + } + return values[min].value; + } + + /// @dev `setValue` used to update the `balances` map and the + /// `totalSupplyHistory` + /// @param values The history of data being updated + /// @param _value The new number of tokens + function setValue( + Values[] storage values, + uint256 _value + ) + internal + { + uint last = values.length - 1; + bool empty = values.length == 0; + bool frozen = !empty && values[last].snapshot < nextSnapshot; + if (empty || frozen) { + // Create a new entry + values.push(Values({ + snapshot: nextSnapshot, + value: _value + })); + } else { + // Overwrite existing entry + values[last].value = _value; + } + } + +} diff --git a/contracts/SnapshotTest.sol b/contracts/SnapshotTest.sol new file mode 100644 index 00000000..59218965 --- /dev/null +++ b/contracts/SnapshotTest.sol @@ -0,0 +1,36 @@ +pragma solidity ^0.4.13; + +import './Snapshot.sol'; + +contract SnapshotTest is Snapshot { + + Values[] myNumber; + + function create() + external + returns (uint256) + { + return Snapshot.createSnapshot(); + } + + function get() + external + returns (uint256) + { + return getValue(myNumber, 0); + } + + function get(uint256 snapshot) + external + returns (uint256) + { + return getValueAt(myNumber, snapshot, 0); + } + + function set(uint256 value) + external + { + return setValue(myNumber, value); + } + +} From b5f0819a6cfb72a79a557589386b793f8f2d36da Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 18:45:39 +0200 Subject: [PATCH 05/40] Use Snapshot in MiniMeToken --- contracts/MiniMeToken.sol | 172 +++++++++++++------------------------- 1 file changed, 57 insertions(+), 115 deletions(-) diff --git a/contracts/MiniMeToken.sol b/contracts/MiniMeToken.sol index 61f6f1d1..5ec2d25a 100644 --- a/contracts/MiniMeToken.sol +++ b/contracts/MiniMeToken.sol @@ -4,6 +4,7 @@ import './Controlled.sol'; import './TokenController.sol'; import './ApproveAndCallFallback.sol'; import './MiniMeTokenFactory.sol'; +import './Snapshot.sol'; /* Copyright 2016, Jordi Baylina @@ -34,33 +35,20 @@ import './MiniMeTokenFactory.sol'; /// @dev The actual token contract, the default controller is the msg.sender /// that deploys the contract, so usually this token will be deployed by a /// token controller contract, which Giveth will call a "Campaign" -contract MiniMeToken is Controlled { +contract MiniMeToken is Controlled, Snapshot { string public name; //The Token's name: e.g. DigixDAO Tokens uint8 public decimals; //Number of decimals of the smallest unit string public symbol; //An identifier: e.g. REP string public version = 'MMT_0.1'; //An arbitrary versioning scheme - - /// @dev `Checkpoint` is the structure that attaches a block number to a - /// given value, the block number attached is the one that last changed the - /// value - struct Checkpoint { - - // `fromBlock` is the block number that the value was generated from - uint128 fromBlock; - - // `value` is the amount of tokens at a specific block number - uint128 value; - } - // `parentToken` is the Token address that was cloned to produce this token; // it will be 0x0 for a token that was not cloned MiniMeToken public parentToken; // `parentSnapShotBlock` is the block number from the Parent Token that was // used to determine the initial distribution of the Clone Token - uint public parentSnapShotBlock; + uint public parentSnapshot; // `creationBlock` is the block number that the Clone Token was created uint public creationBlock; @@ -68,13 +56,13 @@ contract MiniMeToken is Controlled { // `balances` is the map that tracks the balance of each address, in this // contract when the balance changes the block number that the change // occurred is also included in the map - mapping (address => Checkpoint[]) balances; + mapping (address => Values[]) balances; // `allowed` tracks any extra transfer rights as in all ERC20 tokens mapping (address => mapping (address => uint256)) allowed; // Tracks the history of the `totalSupply` of the token - Checkpoint[] totalSupplyHistory; + Values[] totalSupplyHistory; // Flag that determines if the token is transferable or not. bool public transfersEnabled; @@ -92,7 +80,7 @@ contract MiniMeToken is Controlled { /// deployed first /// @param _parentToken Address of the parent token, set to 0x0 if it is a /// new token - /// @param _parentSnapShotBlock Block of the parent token that will + /// @param _parentSnapshot Block of the parent token that will /// determine the initial distribution of the clone token, set to 0 if it /// is a new token /// @param _tokenName Name of the new token @@ -102,7 +90,7 @@ contract MiniMeToken is Controlled { function MiniMeToken( address _tokenFactory, address _parentToken, - uint _parentSnapShotBlock, + uint _parentSnapshot, string _tokenName, uint8 _decimalUnits, string _tokenSymbol, @@ -113,7 +101,7 @@ contract MiniMeToken is Controlled { decimals = _decimalUnits; // Set the decimals symbol = _tokenSymbol; // Set the symbol parentToken = MiniMeToken(_parentToken); - parentSnapShotBlock = _parentSnapShotBlock; + parentSnapshot = _parentSnapshot; transfersEnabled = _transfersEnabled; creationBlock = block.number; } @@ -168,7 +156,7 @@ contract MiniMeToken is Controlled { return true; } - require(parentSnapShotBlock < block.number); + require(parentSnapshot < block.number); // Do not allow transfer to 0x0 or the token contract itself require((_to != 0) && (_to != address(this))); @@ -187,13 +175,13 @@ contract MiniMeToken is Controlled { // First update the balance array with the new value for the address // sending the tokens - updateValueAtNow(balances[_from], previousBalanceFrom - _amount); + setValue(balances[_from], previousBalanceFrom - _amount); // Then update the balance array with the new value for the address // receiving the tokens var previousBalanceTo = balanceOfAt(_to, block.number); require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow - updateValueAtNow(balances[_to], previousBalanceTo + _amount); + setValue(balances[_to], previousBalanceTo + _amount); // An event to make the transfer easy to find on the blockchain Transfer(_from, _to, _amount); @@ -274,55 +262,53 @@ contract MiniMeToken is Controlled { // Query balance and totalSupply in History //////////////// - /// @dev Queries the balance of `_owner` at a specific `_blockNumber` + /// @dev Queries the balance of `_owner` at a specific `_snapshot` /// @param _owner The address from which the balance will be retrieved - /// @param _blockNumber The block number when the balance is queried - /// @return The balance at `_blockNumber` - function balanceOfAt(address _owner, uint _blockNumber) constant - returns (uint) { - - // These next few lines are used when the balance of the token is - // requested before a check point was ever created for this token, it - // requires that the `parentToken.balanceOfAt` be queried at the - // genesis block for that token as this contains initial balance of - // this token - if ((balances[_owner].length == 0) - || (balances[_owner][0].fromBlock > _blockNumber)) { - if (address(parentToken) != 0) { - return parentToken.balanceOfAt(_owner, min(_blockNumber, parentSnapShotBlock)); - } else { - // Has no parent - return 0; - } - - // This will return the expected balance during normal situations - } else { - return getValueAt(balances[_owner], _blockNumber); + /// @param _snapshot The block number when the balance is queried + /// @return The balance at `_snapshot` + function balanceOfAt(address _owner, uint _snapshot) + constant + returns (uint) + { + Values[] storage values = balances[_owner]; + + // If there is a value, return it + if (hasValueAt(values, _snapshot)) { + return getValueAt(values, _snapshot, 0); } + + // Try parent contract at the fork + if (address(parentToken) != 0) { + // TODO: Make snapshot numbers continue over the fork, + // be sure to use `min(_snapshot, parentSnapshot)` + return parentToken.balanceOfAt(_owner, parentSnapshot); + } + + // Default to an empty balance + return 0; } - /// @notice Total amount of tokens at a specific `_blockNumber`. - /// @param _blockNumber The block number when the totalSupply is queried - /// @return The total amount of tokens at `_blockNumber` - function totalSupplyAt(uint _blockNumber) constant returns(uint) { - - // These next few lines are used when the totalSupply of the token is - // requested before a check point was ever created for this token, it - // requires that the `parentToken.totalSupplyAt` be queried at the - // genesis block for this token as that contains totalSupply of this - // token at this block number. - if ((totalSupplyHistory.length == 0) - || (totalSupplyHistory[0].fromBlock > _blockNumber)) { - if (address(parentToken) != 0) { - return parentToken.totalSupplyAt(min(_blockNumber, parentSnapShotBlock)); - } else { - return 0; - } - - // This will return the expected totalSupply during normal situations - } else { - return getValueAt(totalSupplyHistory, _blockNumber); + /// @notice Total amount of tokens at a specific `_snapshot`. + /// @param _snapshot The block number when the totalSupply is queried + /// @return The total amount of tokens at `_snapshot` + function totalSupplyAt(uint _snapshot) + constant + returns(uint) + { + Values[] storage values = totalSupplyHistory; + + // If there is a value, return it + if (hasValueAt(values, _snapshot)) { + return getValueAt(values, _snapshot, 0); } + + // Try parent contract at the fork + if (address(parentToken) != 0) { + return parentToken.totalSupplyAt(parentSnapshot); + } + + // Default to an empty balance + return 0; } //////////////// @@ -377,8 +363,8 @@ contract MiniMeToken is Controlled { require(curTotalSupply + _amount >= curTotalSupply); // Check for overflow uint previousBalanceTo = balanceOf(_owner); require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow - updateValueAtNow(totalSupplyHistory, curTotalSupply + _amount); - updateValueAtNow(balances[_owner], previousBalanceTo + _amount); + setValue(totalSupplyHistory, curTotalSupply + _amount); + setValue(balances[_owner], previousBalanceTo + _amount); Transfer(0, _owner, _amount); return true; } @@ -394,8 +380,8 @@ contract MiniMeToken is Controlled { require(curTotalSupply >= _amount); uint previousBalanceFrom = balanceOf(_owner); require(previousBalanceFrom >= _amount); - updateValueAtNow(totalSupplyHistory, curTotalSupply - _amount); - updateValueAtNow(balances[_owner], previousBalanceFrom - _amount); + setValue(totalSupplyHistory, curTotalSupply - _amount); + setValue(balances[_owner], previousBalanceFrom - _amount); Transfer(_owner, 0, _amount); return true; } @@ -415,50 +401,6 @@ contract MiniMeToken is Controlled { // Internal helper functions to query and set a value in a snapshot array //////////////// - /// @dev `getValueAt` retrieves the number of tokens at a given block number - /// @param checkpoints The history of values being queried - /// @param _block The block number to retrieve the value at - /// @return The number of tokens being queried - function getValueAt(Checkpoint[] storage checkpoints, uint _block - ) constant internal returns (uint) { - if (checkpoints.length == 0) return 0; - - // Shortcut for the actual value - if (_block >= checkpoints[checkpoints.length-1].fromBlock) - return checkpoints[checkpoints.length-1].value; - if (_block < checkpoints[0].fromBlock) return 0; - - // Binary search of the value in the array - uint min = 0; - uint max = checkpoints.length-1; - while (max > min) { - uint mid = (max + min + 1)/ 2; - if (checkpoints[mid].fromBlock<=_block) { - min = mid; - } else { - max = mid-1; - } - } - return checkpoints[min].value; - } - - /// @dev `updateValueAtNow` used to update the `balances` map and the - /// `totalSupplyHistory` - /// @param checkpoints The history of data being updated - /// @param _value The new number of tokens - function updateValueAtNow(Checkpoint[] storage checkpoints, uint _value - ) internal { - if ((checkpoints.length == 0) - || (checkpoints[checkpoints.length -1].fromBlock < block.number)) { - Checkpoint storage newCheckPoint = checkpoints[ checkpoints.length++ ]; - newCheckPoint.fromBlock = uint128(block.number); - newCheckPoint.value = uint128(_value); - } else { - Checkpoint storage oldCheckPoint = checkpoints[checkpoints.length-1]; - oldCheckPoint.value = uint128(_value); - } - } - /// @dev Internal function to determine if an address is a contract /// @param _addr The address being queried /// @return True if `_addr` is a contract From b36beb7a55975f62b312d944ecf8ffcec47d174a Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 20:43:12 +0200 Subject: [PATCH 06/40] Optimize Snapshot values --- contracts/Snapshot.sol | 138 +++++++++++++++++++++++++++++++++---- contracts/SnapshotTest.sol | 5 ++ 2 files changed, 130 insertions(+), 13 deletions(-) diff --git a/contracts/Snapshot.sol b/contracts/Snapshot.sol index 5dbe91e9..fbb1562b 100644 --- a/contracts/Snapshot.sol +++ b/contracts/Snapshot.sol @@ -2,6 +2,10 @@ pragma solidity ^0.4.13; contract Snapshot { +//////////////// +// Types +//////////////// + /// @dev `Checkpoint` is the structure that attaches a block number to a /// given value, the block number attached is the one that last changed the /// value @@ -14,26 +18,88 @@ contract Snapshot { uint256 value; } +//////////////// +// State +//////////////// + uint256 internal nextSnapshot; + bool internal nextSnapshotModified; + +//////////////// +// Events +//////////////// + event SnapshotCreated(uint256 snapshot); - function Snapshot() +//////////////// +// Constructor +//////////////// + + function Snapshot(uint256 snapshotStart) internal { - nextSnapshot = 0; + require(snapshotStart < 2**256 - 1); + + // We can start at non-zero counter so the snapshots can + // continue from some other contract's snapshots. This is + // useful for forking. + nextSnapshot = snapshotStart + 1; + nextSnapshotModified = false; } +//////////////// +// Public functions +//////////////// + function createSnapshot() - internal + public returns (uint256) { + require(nextSnapshot < 2**256 - 1); + + // If no modifications have been made, the previous snapshot + // is identical to the current one. We can return the previous + // entry. + // TODO: Is this optimization worth it? It only avoids one + // storage counter increment. + if (!nextSnapshotModified) { + return nextSnapshot - 1; + } + uint256 snapshot = nextSnapshot; nextSnapshot += 1; SnapshotCreated(snapshot); + nextSnapshotModified = false; return snapshot; } +//////////////// +// Internal functions +//////////////// + + function hasValue( + Values[] storage values + ) + internal + constant + returns (bool) + { + return values.length > 0; + } + + function hasValueAt( + Values[] storage values, + uint _snapshot + ) + internal + constant + returns (bool) + { + require(_snapshot < nextSnapshot); + return values.length > 0 && values[0].snapshot <= _snapshot; + } + function getValue( Values[] storage values, uint _defaultValue @@ -42,7 +108,12 @@ contract Snapshot { constant returns (uint) { - return getValueAt(values, nextSnapshot, _defaultValue); + if (values.length == 0) { + return _defaultValue; + } else { + uint last = values.length - 1; + return values[last].value; + } } /// @dev `getValueAt` retrieves the number of tokens at a given block number @@ -58,11 +129,14 @@ contract Snapshot { constant returns (uint) { + require(_snapshot < nextSnapshot); + + // Empty value if (values.length == 0) { return _defaultValue; } - // Shortcut for the actual value + // Shortcut for the out of bounds snapshots uint last = values.length - 1; uint lastSnapshot = values[last].snapshot; if (_snapshot >= lastSnapshot) { @@ -97,19 +171,57 @@ contract Snapshot { ) internal { - uint last = values.length - 1; + // TODO: simplify or break into smaller functions + + // Always create a new entry if there currently is no value bool empty = values.length == 0; - bool frozen = !empty && values[last].snapshot < nextSnapshot; - if (empty || frozen) { + if (empty) { // Create a new entry values.push(Values({ snapshot: nextSnapshot, value: _value })); - } else { - // Overwrite existing entry - values[last].value = _value; - } - } + // Flag next snapshot as modified + if (!nextSnapshotModified) { + nextSnapshotModified = true; + } + return; + } + + uint last = values.length - 1; + bool frozen = values[last].snapshot < nextSnapshot; + if (frozen) { + + // Do nothing if the value was not modified + bool unmodified = values[last].value != _value; + if (unmodified) { + return; + } + + // Create new entry + values.push(Values({ + snapshot: nextSnapshot, + value: _value + })); + + // Flag next snapshot as modified + if (!nextSnapshotModified) { + nextSnapshotModified = true; + } + + } else { // We are updating the nextSnapshot + + bool unmodifiedd = last > 0 && values[last - 1].value == _value; + if (unmodifiedd) { + // Remove nextSnapshot entry + delete values[last]; + values.length--; + return; + } + + // Overwrite next snapshot entry + values[last].value = _value; + } + } } diff --git a/contracts/SnapshotTest.sol b/contracts/SnapshotTest.sol index 59218965..3bd93b88 100644 --- a/contracts/SnapshotTest.sol +++ b/contracts/SnapshotTest.sol @@ -6,6 +6,11 @@ contract SnapshotTest is Snapshot { Values[] myNumber; + function SnapshotTest() + Snapshot(0) + { + } + function create() external returns (uint256) From 674c466cb28eeac403fd6abaeb381117bbb9fabb Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 20:43:32 +0200 Subject: [PATCH 07/40] Add SnapshotTokenBase --- contracts/SnapshotTokenBase.sol | 226 ++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 contracts/SnapshotTokenBase.sol diff --git a/contracts/SnapshotTokenBase.sol b/contracts/SnapshotTokenBase.sol new file mode 100644 index 00000000..0c6c51de --- /dev/null +++ b/contracts/SnapshotTokenBase.sol @@ -0,0 +1,226 @@ +pragma solidity ^0.4.13; + +import './Snapshot.sol'; + + +contract SnapshotTokenBase is Snapshot { + + // `parentToken` is the Token address that was cloned to produce this token; + // it will be 0x0 for a token that was not cloned + SnapshotTokenBase public parentToken; + + // `parentSnapShotBlock` is the block number from the Parent Token that was + // used to determine the initial distribution of the Clone Token + uint256 public parentSnapshot; + + // `balances` is the map that tracks the balance of each address, in this + // contract when the balance changes the block number that the change + // occurred is also included in the map + mapping (address => Values[]) balances; + + // Tracks the history of the `totalSupply` of the token + Values[] totalSupplyValues; + +//////////////// +// Events +//////////////// + + event Transfer(address indexed _from, address indexed _to, uint256 _amount); + +//////////////// +// Constructor +//////////////// + + /// @notice Constructor to create a MiniMeToken + /// @param _parentToken Address of the parent token, set to 0x0 if it is a + /// new token + function SnapshotTokenBase( + SnapshotTokenBase _parentToken + ) + public + Snapshot(_parentToken.createSnapshot()) + { + parentToken = _parentToken; + parentSnapshot = _parentToken.createSnapshot(); + } + +/////////////////// +// ERC20 Basic Methods +/////////////////// + + /// @dev This function makes it easy to get the total number of tokens + /// @return The total number of tokens + function totalSupply() + public + constant + returns (uint) + { + return getValue(totalSupplyValues, 0); + } + + /// @param _owner The address that's balance is being requested + /// @return The balance of `_owner` at the current block + function balanceOf(address _owner) + public + constant + returns (uint256 balance) + { + return getValue(balances[_owner], 0); + } + + /// @notice Send `_amount` tokens to `_to` from `msg.sender` + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return Whether the transfer was successful or not + function transfer(address _to, uint256 _amount) + public + returns (bool success) + { + return transfer(msg.sender, _to, _amount); + } + +//////////////// +// Query balance and totalSupply in History +//////////////// + + /// @notice Total amount of tokens at a specific `_snapshot`. + /// @param _snapshot The block number when the totalSupply is queried + /// @return The total amount of tokens at `_snapshot` + function totalSupplyAt(uint _snapshot) + public + constant + returns(uint) + { + Values[] storage values = totalSupplyValues; + + // If there is a value, return it + if (hasValueAt(values, _snapshot)) { + return getValueAt(values, _snapshot, 0); + } + + // Try parent contract at the fork + if (address(parentToken) != 0) { + return parentToken.totalSupplyAt(parentSnapshot); + } + + // Default to an empty balance + return 0; + } + + /// @dev Queries the balance of `_owner` at a specific `_snapshot` + /// @param _owner The address from which the balance will be retrieved + /// @param _snapshot The block number when the balance is queried + /// @return The balance at `_snapshot` + function balanceOfAt(address _owner, uint _snapshot) + public + constant + returns (uint) + { + Values[] storage values = balances[_owner]; + + // If there is a value, return it + if (hasValueAt(values, _snapshot)) { + return getValueAt(values, _snapshot, 0); + } + + // Try parent contract at the fork + if (address(parentToken) != 0) { + // TODO: Make snapshot numbers continue over the fork, + // be sure to use `min(_snapshot, parentSnapshot)` + return parentToken.balanceOfAt(_owner, parentSnapshot); + } + + // Default to an empty balance + return 0; + } + +//////////////// +// Generate and destroy tokens +//////////////// + + /// @dev This is the actual transfer function in the token contract, it can + /// only be called by other functions in this contract. + /// @param _from The address holding the tokens being transferred + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return True if the transfer was successful + function transfer(address _from, address _to, uint _amount) + internal + returns(bool) + { + if (_amount == 0) { + return true; + } + + // Do not allow transfer to 0x0 or the token contract itself + require(_to != 0); + require(_to != address(this)); + + // If the amount being transfered is more than the balance of the + // account the transfer returns false + var previousBalanceFrom = balanceOf(_from); + if (previousBalanceFrom < _amount) { + return false; + } + + // First update the balance array with the new value for the address + // sending the tokens + uint256 newBalanceFrom = previousBalanceFrom - _amount; + setValue(balances[_from], newBalanceFrom); + + // Then update the balance array with the new value for the address + // receiving the tokens + uint256 previousBalanceTo = balanceOf(_to); + uint256 newBalanceTo = previousBalanceTo + _amount; + assert(newBalanceTo >= previousBalanceTo); // Check for overflow + setValue(balances[_to], newBalanceTo); + + // An event to make the transfer easy to find on the blockchain + Transfer(_from, _to, _amount); + return true; + } + + /// @notice Generates `_amount` tokens that are assigned to `_owner` + /// @param _owner The address that will be assigned the new tokens + /// @param _amount The quantity of tokens generated + /// @return True if the tokens are generated correctly + function generateTokens(address _owner, uint _amount) + internal + returns (bool) + { + uint curTotalSupply = totalSupply(); + uint256 newTotalSupply = curTotalSupply + _amount; + require(newTotalSupply >= curTotalSupply); // Check for overflow + + uint previousBalanceTo = balanceOf(_owner); + uint256 newBalanceTo = previousBalanceTo + _amount; + assert(newBalanceTo >= previousBalanceTo); // Check for overflow + + setValue(totalSupplyValues, newTotalSupply); + setValue(balances[_owner], newBalanceTo); + + Transfer(0, _owner, _amount); + return true; + } + + /// @notice Burns `_amount` tokens from `_owner` + /// @param _owner The address that will lose the tokens + /// @param _amount The quantity of tokens to burn + /// @return True if the tokens are burned correctly + function destroyTokens(address _owner, uint _amount) + internal + returns (bool) + { + uint curTotalSupply = totalSupply(); + require(curTotalSupply >= _amount); + + uint previousBalanceFrom = balanceOf(_owner); + require(previousBalanceFrom >= _amount); + + setValue(totalSupplyValues, curTotalSupply - _amount); + setValue(balances[_owner], previousBalanceFrom - _amount); + + Transfer(_owner, 0, _amount); + return true; + } +} From a124eb0c6b91aeb970fab93b87c4fcfa7a58fd56 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 23:21:16 +0200 Subject: [PATCH 08/40] Add interfaces --- contracts/IBasicToken.sol | 38 +++++++++ contracts/IERC20Token.sol | 81 +++++++++++++++++++ contracts/ISnapshot.sol | 19 +++++ contracts/ISnapshotToken.sol | 61 ++++++++++++++ contracts/ISnapshotTokenParent.sol | 21 +++++ ...kenController.sol => ITokenController.sol} | 2 +- 6 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 contracts/IBasicToken.sol create mode 100644 contracts/IERC20Token.sol create mode 100644 contracts/ISnapshot.sol create mode 100644 contracts/ISnapshotToken.sol create mode 100644 contracts/ISnapshotTokenParent.sol rename contracts/{TokenController.sol => ITokenController.sol} (97%) diff --git a/contracts/IBasicToken.sol b/contracts/IBasicToken.sol new file mode 100644 index 00000000..d45b4240 --- /dev/null +++ b/contracts/IBasicToken.sol @@ -0,0 +1,38 @@ +pragma solidity ^0.4.13; + + +interface IBasicToken { + +//////////////// +// Events +//////////////// + + event Transfer(address indexed _from, address indexed _to, uint256 _amount); + +/////////////////// +// ERC20 Basic Methods +/////////////////// + + /// @dev This function makes it easy to get the total number of tokens + /// @return The total number of tokens + function totalSupply() + public + constant + returns (uint); + + /// @param _owner The address that's balance is being requested + /// @return The balance of `_owner` at the current block + function balanceOf(address _owner) + public + constant + returns (uint256 balance); + + /// @notice Send `_amount` tokens to `_to` from `msg.sender` + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return Whether the transfer was successful or not + function transfer(address _to, uint256 _amount) + public + returns (bool success); + +} diff --git a/contracts/IERC20Token.sol b/contracts/IERC20Token.sol new file mode 100644 index 00000000..9d12bcaf --- /dev/null +++ b/contracts/IERC20Token.sol @@ -0,0 +1,81 @@ +pragma solidity ^0.4.13; + + +// is IBasicToken +interface IERC20Token { + +//////////////// +// Events +//////////////// + + event Transfer(address indexed _from, address indexed _to, uint256 _amount); + +/////////////////// +// ERC20 Basic Methods +/////////////////// + + /// @dev This function makes it easy to get the total number of tokens + /// @return The total number of tokens + function totalSupply() + public + constant + returns (uint); + + /// @param _owner The address that's balance is being requested + /// @return The balance of `_owner` at the current block + function balanceOf(address _owner) + public + constant + returns (uint256 balance); + + /// @notice Send `_amount` tokens to `_to` from `msg.sender` + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return Whether the transfer was successful or not + function transfer(address _to, uint256 _amount) + public + returns (bool success); + + /// @dev This function makes it easy to read the `allowed[]` map + /// @param _owner The address of the account that owns the token + /// @param _spender The address of the account able to transfer the tokens + /// @return Amount of remaining tokens of _owner that _spender is allowed + /// to spend + function allowance(address _owner, address _spender) + public + constant + returns (uint256 remaining); + + /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on + /// its behalf. This is a modified version of the ERC20 approve function + /// to be a little bit safer + /// @param _spender The address of the account able to transfer the tokens + /// @param _amount The amount of tokens to be approved for transfer + /// @return True if the approval was successful + function approve(address _spender, uint256 _amount) + public + returns (bool success); + + /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on + /// its behalf, and then a function is triggered in the contract that is + /// being approved, `_spender`. This allows users to use their tokens to + /// interact with contracts in one function call instead of two + /// @param _spender The address of the contract able to transfer the tokens + /// @param _amount The amount of tokens to be approved for transfer + /// @return True if the function call was successful + function approveAndCall(address _spender, uint256 _amount, bytes _extraData) + public + returns (bool success); + + + /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it + /// is approved by `_from` + /// @param _from The address holding the tokens being transferred + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return True if the transfer was successful + function transferFrom(address _from, address _to, uint256 _amount) + public + returns (bool success); + +} diff --git a/contracts/ISnapshot.sol b/contracts/ISnapshot.sol new file mode 100644 index 00000000..8c153659 --- /dev/null +++ b/contracts/ISnapshot.sol @@ -0,0 +1,19 @@ +pragma solidity ^0.4.13; + +contract ISnapshot { + +//////////////// +// Events +//////////////// + + event SnapshotCreated(uint256 snapshot); + +//////////////// +// Public functions +//////////////// + + function createSnapshot() + public + returns (uint256); + +} diff --git a/contracts/ISnapshotToken.sol b/contracts/ISnapshotToken.sol new file mode 100644 index 00000000..00771b17 --- /dev/null +++ b/contracts/ISnapshotToken.sol @@ -0,0 +1,61 @@ +pragma solidity ^0.4.13; + +// is ISnapshot, IBasicToken, ISnapshotTokenParent +interface ISnapshotToken { + +//////////////// +// Events +//////////////// + + event SnapshotCreated(uint256 snapshot); + + event Transfer(address indexed _from, address indexed _to, uint256 _amount); + +//////////////// +// Public functions +//////////////// + + function createSnapshot() + public + returns (uint256); + + /// @dev This function makes it easy to get the total number of tokens + /// @return The total number of tokens + function totalSupply() + public + constant + returns (uint); + + /// @param _owner The address that's balance is being requested + /// @return The balance of `_owner` at the current block + function balanceOf(address _owner) + public + constant + returns (uint256 balance); + + /// @notice Send `_amount` tokens to `_to` from `msg.sender` + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return Whether the transfer was successful or not + function transfer(address _to, uint256 _amount) + public + returns (bool success); + + /// @notice Total amount of tokens at a specific `_snapshot`. + /// @param _snapshot The block number when the totalSupply is queried + /// @return The total amount of tokens at `_snapshot` + function totalSupplyAt(uint _snapshot) + public + constant + returns(uint); + + /// @dev Queries the balance of `_owner` at a specific `_snapshot` + /// @param _owner The address from which the balance will be retrieved + /// @param _snapshot The block number when the balance is queried + /// @return The balance at `_snapshot` + function balanceOfAt(address _owner, uint _snapshot) + public + constant + returns (uint); + +} diff --git a/contracts/ISnapshotTokenParent.sol b/contracts/ISnapshotTokenParent.sol new file mode 100644 index 00000000..013b15f3 --- /dev/null +++ b/contracts/ISnapshotTokenParent.sol @@ -0,0 +1,21 @@ +pragma solidity ^0.4.13; + +interface ISnapshotTokenParent { + + /// @notice Total amount of tokens at a specific `_snapshot`. + /// @param _snapshot The block number when the totalSupply is queried + /// @return The total amount of tokens at `_snapshot` + function totalSupplyAt(uint _snapshot) + public + constant + returns(uint); + + /// @dev Queries the balance of `_owner` at a specific `_snapshot` + /// @param _owner The address from which the balance will be retrieved + /// @param _snapshot The block number when the balance is queried + /// @return The balance at `_snapshot` + function balanceOfAt(address _owner, uint _snapshot) + public + constant + returns (uint); +} diff --git a/contracts/TokenController.sol b/contracts/ITokenController.sol similarity index 97% rename from contracts/TokenController.sol rename to contracts/ITokenController.sol index e685513e..f1501cd4 100644 --- a/contracts/TokenController.sol +++ b/contracts/ITokenController.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.13; /// @dev The token controller contract must implement these functions -interface TokenController { +interface ITokenController { /// @notice Called when `_owner` sends ether to the MiniMe Token contract /// @param _owner The address that sent the ether to create tokens /// @return True if the ether is accepted, false if it throws From c752cbcee365a3e0893bfad7165c01ec841746ef Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 23:21:48 +0200 Subject: [PATCH 09/40] Add Helpers --- contracts/Helpers.sol | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 contracts/Helpers.sol diff --git a/contracts/Helpers.sol b/contracts/Helpers.sol new file mode 100644 index 00000000..bd0a9be2 --- /dev/null +++ b/contracts/Helpers.sol @@ -0,0 +1,33 @@ +pragma solidity ^0.4.13; + +contract Helpers { + + function Helpers() internal {} + + function min(uint256 a, uint256 b) + internal + constant + returns (uint256) + { + return a < b ? a : b; + } + + /// @dev Internal function to determine if an address is a contract + /// @param _addr The address being queried + /// @return True if `_addr` is a contract + function isContract(address _addr) + internal + constant + returns (bool) + { + uint size; + if (_addr == 0) { + return false; // TODO: Is this necessary? + } + assembly { + size := extcodesize(_addr) + } + return size > 0; + } + +} From d90f9335301507b934f71a12cf8d5cb7bc92a340 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 23:23:09 +0200 Subject: [PATCH 10/40] Fork from parent token --- contracts/SnapshotTokenBase.sol | 42 +++++++++++++++++---------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/contracts/SnapshotTokenBase.sol b/contracts/SnapshotTokenBase.sol index 0c6c51de..7315ca45 100644 --- a/contracts/SnapshotTokenBase.sol +++ b/contracts/SnapshotTokenBase.sol @@ -1,13 +1,20 @@ pragma solidity ^0.4.13; import './Snapshot.sol'; +import './ISnapshotToken.sol'; +import './ISnapshotTokenParent.sol'; +import './Helpers.sol'; - -contract SnapshotTokenBase is Snapshot { +contract SnapshotTokenBase is + ISnapshotToken, + ISnapshotTokenParent, + Snapshot, + Helpers +{ // `parentToken` is the Token address that was cloned to produce this token; // it will be 0x0 for a token that was not cloned - SnapshotTokenBase public parentToken; + ISnapshotTokenParent public parentToken; // `parentSnapShotBlock` is the block number from the Parent Token that was // used to determine the initial distribution of the Clone Token @@ -35,13 +42,14 @@ contract SnapshotTokenBase is Snapshot { /// @param _parentToken Address of the parent token, set to 0x0 if it is a /// new token function SnapshotTokenBase( - SnapshotTokenBase _parentToken + ISnapshotTokenParent _parentToken, + uint256 _parentSnapshot ) public - Snapshot(_parentToken.createSnapshot()) + Snapshot(_parentSnapshot) { parentToken = _parentToken; - parentSnapshot = _parentToken.createSnapshot(); + parentSnapshot = _parentSnapshot; } /////////////////// @@ -76,7 +84,7 @@ contract SnapshotTokenBase is Snapshot { public returns (bool success) { - return transfer(msg.sender, _to, _amount); + return snapshotBaseTransfer(msg.sender, _to, _amount); } //////////////// @@ -98,9 +106,9 @@ contract SnapshotTokenBase is Snapshot { return getValueAt(values, _snapshot, 0); } - // Try parent contract at the fork + // Try parent contract at or before the fork if (address(parentToken) != 0) { - return parentToken.totalSupplyAt(parentSnapshot); + return parentToken.totalSupplyAt(min(_snapshot, parentSnapshot)); } // Default to an empty balance @@ -123,11 +131,9 @@ contract SnapshotTokenBase is Snapshot { return getValueAt(values, _snapshot, 0); } - // Try parent contract at the fork + // Try parent contract at or before the fork if (address(parentToken) != 0) { - // TODO: Make snapshot numbers continue over the fork, - // be sure to use `min(_snapshot, parentSnapshot)` - return parentToken.balanceOfAt(_owner, parentSnapshot); + return parentToken.balanceOfAt(_owner, min(_snapshot, parentSnapshot)); } // Default to an empty balance @@ -144,7 +150,7 @@ contract SnapshotTokenBase is Snapshot { /// @param _to The address of the recipient /// @param _amount The amount of tokens to be transferred /// @return True if the transfer was successful - function transfer(address _from, address _to, uint _amount) + function snapshotBaseTransfer(address _from, address _to, uint _amount) internal returns(bool) { @@ -152,10 +158,6 @@ contract SnapshotTokenBase is Snapshot { return true; } - // Do not allow transfer to 0x0 or the token contract itself - require(_to != 0); - require(_to != address(this)); - // If the amount being transfered is more than the balance of the // account the transfer returns false var previousBalanceFrom = balanceOf(_from); @@ -184,7 +186,7 @@ contract SnapshotTokenBase is Snapshot { /// @param _owner The address that will be assigned the new tokens /// @param _amount The quantity of tokens generated /// @return True if the tokens are generated correctly - function generateTokens(address _owner, uint _amount) + function snapshotBaseGenerateTokens(address _owner, uint _amount) internal returns (bool) { @@ -207,7 +209,7 @@ contract SnapshotTokenBase is Snapshot { /// @param _owner The address that will lose the tokens /// @param _amount The quantity of tokens to burn /// @return True if the tokens are burned correctly - function destroyTokens(address _owner, uint _amount) + function snapshotBaseDestroyTokens(address _owner, uint _amount) internal returns (bool) { From e1b2c5ea5ead9a90f702c8f7d0cdab06359c92e5 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 23:23:27 +0200 Subject: [PATCH 11/40] Add AllowanceBase --- contracts/AllowanceBase.sol | 119 ++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 contracts/AllowanceBase.sol diff --git a/contracts/AllowanceBase.sol b/contracts/AllowanceBase.sol new file mode 100644 index 00000000..7601b27b --- /dev/null +++ b/contracts/AllowanceBase.sol @@ -0,0 +1,119 @@ +pragma solidity ^0.4.13; + +import './ApproveAndCallFallback.sol'; + +contract AllowanceBase { + +//////////////// +// State +//////////////// + + // `allowed` tracks any extra transfer rights as in all ERC20 tokens + mapping (address => mapping (address => uint256)) allowed; + +//////////////// +// Events +//////////////// + + event Approval( + address indexed _owner, + address indexed _spender, + uint256 _amount + ); + +//////////////// +// Constructor +//////////////// + + function AllowanceBase() + internal + { + } + +//////////////// +// Public functions +//////////////// + + /// @dev This function makes it easy to read the `allowed[]` map + /// @param _owner The address of the account that owns the token + /// @param _spender The address of the account able to transfer the tokens + /// @return Amount of remaining tokens of _owner that _spender is allowed + /// to spend + function allowance(address _owner, address _spender) + public + constant + returns (uint256 remaining) + { + return allowed[_owner][_spender]; + } + + /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on + /// its behalf. This is a modified version of the ERC20 approve function + /// to be a little bit safer + /// @param _spender The address of the account able to transfer the tokens + /// @param _amount The amount of tokens to be approved for transfer + /// @return True if the approval was successful + function approve(address _spender, uint256 _amount) + public + returns (bool success) + { + // 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 + require((_amount == 0) || (allowed[msg.sender][_spender] == 0)); + + allowed[msg.sender][_spender] = _amount; + Approval(msg.sender, _spender, _amount); + return true; + } + + /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on + /// its behalf, and then a function is triggered in the contract that is + /// being approved, `_spender`. This allows users to use their tokens to + /// interact with contracts in one function call instead of two + /// @param _spender The address of the contract able to transfer the tokens + /// @param _amount The amount of tokens to be approved for transfer + /// @return True if the function call was successful + function approveAndCall(address _spender, uint256 _amount, bytes _extraData + ) returns (bool success) { + require(approve(_spender, _amount)); + + ApproveAndCallFallBack(_spender).receiveApproval( + msg.sender, + _amount, + this, + _extraData + ); + + return true; + } + + /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it + /// is approved by `_from` + /// @param _from The address holding the tokens being transferred + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return True if the transfer was successful + function transferFrom(address _from, address _to, uint256 _amount) + public + returns (bool success) + { + // The standard ERC 20 transferFrom functionality + if (allowed[_from][msg.sender] < _amount) { + return false; + } + + allowed[_from][msg.sender] -= _amount; + return allowanceBaseTransfer(_from, _to, _amount); + } + +//////////////// +// Abstract functions +//////////////// + + function allowanceBaseTransfer(address from, address to, uint256 amount) + internal + returns (bool); + +} From 6763b38b76f288bcfec1304ea00a024159f93fd7 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 23:25:28 +0200 Subject: [PATCH 12/40] Use interfaces and bases --- contracts/Controlled.sol | 23 ++- contracts/MiniMeToken.sol | 340 +++++++++---------------------- contracts/MiniMeTokenFactory.sol | 12 +- 3 files changed, 125 insertions(+), 250 deletions(-) diff --git a/contracts/Controlled.sol b/contracts/Controlled.sol index 2f6e10b0..6e0d878f 100644 --- a/contracts/Controlled.sol +++ b/contracts/Controlled.sol @@ -1,17 +1,30 @@ pragma solidity ^0.4.13; +import './ITokenController.sol'; + contract Controlled { + + ITokenController public controller; + /// @notice The address of the controller is the only address that can call /// a function with this modifier - modifier onlyController { require(msg.sender == controller); _; } - - address public controller; + modifier onlyController + { + require(msg.sender == address(controller)); + _; + } - function Controlled() { controller = msg.sender;} + function Controlled() + { + controller = ITokenController(msg.sender); + } /// @notice Changes the controller of the contract /// @param _newController The new controller of the contract - function changeController(address _newController) onlyController { + function changeController(ITokenController _newController) + public + onlyController + { controller = _newController; } } diff --git a/contracts/MiniMeToken.sol b/contracts/MiniMeToken.sol index 5ec2d25a..23eccfb5 100644 --- a/contracts/MiniMeToken.sol +++ b/contracts/MiniMeToken.sol @@ -1,10 +1,13 @@ pragma solidity ^0.4.13; import './Controlled.sol'; -import './TokenController.sol'; +import './ITokenController.sol'; +import './IERC20Token.sol'; import './ApproveAndCallFallback.sol'; import './MiniMeTokenFactory.sol'; -import './Snapshot.sol'; +import './SnapshotTokenBase.sol'; +import './AllowanceBase.sol'; +import './Helpers.sol'; /* Copyright 2016, Jordi Baylina @@ -35,41 +38,35 @@ import './Snapshot.sol'; /// @dev The actual token contract, the default controller is the msg.sender /// that deploys the contract, so usually this token will be deployed by a /// token controller contract, which Giveth will call a "Campaign" -contract MiniMeToken is Controlled, Snapshot { + +// Helpers is inherited through SnapshotTokenBase +contract MiniMeToken is + IERC20Token, + ISnapshotToken, + SnapshotTokenBase, + AllowanceBase, + Controlled +{ string public name; //The Token's name: e.g. DigixDAO Tokens uint8 public decimals; //Number of decimals of the smallest unit string public symbol; //An identifier: e.g. REP string public version = 'MMT_0.1'; //An arbitrary versioning scheme - // `parentToken` is the Token address that was cloned to produce this token; - // it will be 0x0 for a token that was not cloned - MiniMeToken public parentToken; - - // `parentSnapShotBlock` is the block number from the Parent Token that was - // used to determine the initial distribution of the Clone Token - uint public parentSnapshot; - - // `creationBlock` is the block number that the Clone Token was created - uint public creationBlock; - - // `balances` is the map that tracks the balance of each address, in this - // contract when the balance changes the block number that the change - // occurred is also included in the map - mapping (address => Values[]) balances; - - // `allowed` tracks any extra transfer rights as in all ERC20 tokens - mapping (address => mapping (address => uint256)) allowed; - - // Tracks the history of the `totalSupply` of the token - Values[] totalSupplyHistory; - // Flag that determines if the token is transferable or not. bool public transfersEnabled; // The factory used to create new clone tokens MiniMeTokenFactory public tokenFactory; +//////////////// +// Events +//////////////// + + event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount); + + event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock); + //////////////// // Constructor //////////////// @@ -89,23 +86,38 @@ contract MiniMeToken is Controlled, Snapshot { /// @param _transfersEnabled If true, tokens will be able to be transferred function MiniMeToken( address _tokenFactory, - address _parentToken, + ISnapshotTokenParent _parentToken, uint _parentSnapshot, string _tokenName, uint8 _decimalUnits, string _tokenSymbol, bool _transfersEnabled - ) { + ) + SnapshotTokenBase(_parentToken, _parentSnapshot) + AllowanceBase() + Controlled() + { tokenFactory = MiniMeTokenFactory(_tokenFactory); name = _tokenName; // Set the name decimals = _decimalUnits; // Set the decimals symbol = _tokenSymbol; // Set the symbol - parentToken = MiniMeToken(_parentToken); - parentSnapshot = _parentSnapshot; transfersEnabled = _transfersEnabled; - creationBlock = block.number; } +//////////////// +// Fallback +//////////////// + + /// @notice The fallback function: If the contract's controller has not been + /// set to 0, then the `proxyPayment` method is called which relays the + /// ether and creates tokens as described in the token controller contract + function () + public + payable + { + require(isContract(controller)); + require(controller.proxyPayment.value(msg.value)(msg.sender)); + } /////////////////// // ERC20 Methods @@ -115,32 +127,26 @@ contract MiniMeToken is Controlled, Snapshot { /// @param _to The address of the recipient /// @param _amount The amount of tokens to be transferred /// @return Whether the transfer was successful or not - function transfer(address _to, uint256 _amount) returns (bool success) { - require(transfersEnabled); - return doTransfer(msg.sender, _to, _amount); + /// Overrides the public function in SnapshotTokenBase + function transfer(address _to, uint256 _amount) + public + returns (bool success) + { + return transfer(msg.sender, _to, _amount); } - /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it - /// is approved by `_from` + /// @dev This is the actual transfer function in the token contract, it can + /// only be called by other functions in this contract. /// @param _from The address holding the tokens being transferred /// @param _to The address of the recipient /// @param _amount The amount of tokens to be transferred /// @return True if the transfer was successful - function transferFrom(address _from, address _to, uint256 _amount - ) returns (bool success) { - - // The controller of this contract can move tokens around at will, - // this is important to recognize! Confirm that you trust the - // controller of this contract, which in most situations should be - // another open source smart contract or 0x0 - if (msg.sender != controller) { - require(transfersEnabled); - - // The standard ERC 20 transferFrom functionality - if (allowed[_from][msg.sender] < _amount) return false; - allowed[_from][msg.sender] -= _amount; - } - return doTransfer(_from, _to, _amount); + /// Implements the abstract function from AllowanceBase + function allowanceBaseTransfer(address _from, address _to, uint _amount) + internal + returns(bool) + { + return transfer(_from, _to, _amount); } /// @dev This is the actual transfer function in the token contract, it can @@ -149,50 +155,23 @@ contract MiniMeToken is Controlled, Snapshot { /// @param _to The address of the recipient /// @param _amount The amount of tokens to be transferred /// @return True if the transfer was successful - function doTransfer(address _from, address _to, uint _amount - ) internal returns(bool) { - - if (_amount == 0) { - return true; - } - - require(parentSnapshot < block.number); - - // Do not allow transfer to 0x0 or the token contract itself - require((_to != 0) && (_to != address(this))); - - // If the amount being transfered is more than the balance of the - // account the transfer returns false - var previousBalanceFrom = balanceOfAt(_from, block.number); - if (previousBalanceFrom < _amount) { - return false; - } - - // Alerts the token controller of the transfer - if (isContract(controller)) { - require(TokenController(controller).onTransfer(_from, _to, _amount)); - } - - // First update the balance array with the new value for the address - // sending the tokens - setValue(balances[_from], previousBalanceFrom - _amount); - - // Then update the balance array with the new value for the address - // receiving the tokens - var previousBalanceTo = balanceOfAt(_to, block.number); - require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow - setValue(balances[_to], previousBalanceTo + _amount); + /// Implements the abstract function from AllowanceBase + function transfer(address _from, address _to, uint _amount) + internal + returns(bool) + { + require(transfersEnabled); - // An event to make the transfer easy to find on the blockchain - Transfer(_from, _to, _amount); + // Alerts the token controller of the transfer + if (isContract(controller)) { + require(controller.onTransfer(_from, _to, _amount)); + } - return true; - } + // Do not allow transfer to 0x0 or the token contract itself + require(_to != 0); + require(_to != address(this)); - /// @param _owner The address that's balance is being requested - /// @return The balance of `_owner` at the current block - function balanceOf(address _owner) constant returns (uint256 balance) { - return balanceOfAt(_owner, block.number); + return snapshotBaseTransfer(_from, _to, _amount); } /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on @@ -201,33 +180,19 @@ contract MiniMeToken is Controlled, Snapshot { /// @param _spender The address of the account able to transfer the tokens /// @param _amount The amount of tokens to be approved for transfer /// @return True if the approval was successful - function approve(address _spender, uint256 _amount) returns (bool success) { + /// Overrides the public function in AllowanceBase + function approve(address _spender, uint256 _amount) + public + returns (bool success) + { require(transfersEnabled); - // 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 - require((_amount == 0) || (allowed[msg.sender][_spender] == 0)); - // Alerts the token controller of the approve function call if (isContract(controller)) { - require(TokenController(controller).onApprove(msg.sender, _spender, _amount)); + require(controller.onApprove(msg.sender, _spender, _amount)); } - allowed[msg.sender][_spender] = _amount; - Approval(msg.sender, _spender, _amount); - return true; - } - - /// @dev This function makes it easy to read the `allowed[]` map - /// @param _owner The address of the account that owns the token - /// @param _spender The address of the account able to transfer the tokens - /// @return Amount of remaining tokens of _owner that _spender is allowed - /// to spend - function allowance(address _owner, address _spender - ) constant returns (uint256 remaining) { - return allowed[_owner][_spender]; + return AllowanceBase.approve(_spender, _amount); } /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on @@ -237,8 +202,11 @@ contract MiniMeToken is Controlled, Snapshot { /// @param _spender The address of the contract able to transfer the tokens /// @param _amount The amount of tokens to be approved for transfer /// @return True if the function call was successful - function approveAndCall(address _spender, uint256 _amount, bytes _extraData - ) returns (bool success) { + /// Overrides the public function in AllowanceBase + function approveAndCall(address _spender, uint256 _amount, bytes _extraData) + public + returns (bool success) + { require(approve(_spender, _amount)); ApproveAndCallFallBack(_spender).receiveApproval( @@ -251,66 +219,6 @@ contract MiniMeToken is Controlled, Snapshot { return true; } - /// @dev This function makes it easy to get the total number of tokens - /// @return The total number of tokens - function totalSupply() constant returns (uint) { - return totalSupplyAt(block.number); - } - - -//////////////// -// Query balance and totalSupply in History -//////////////// - - /// @dev Queries the balance of `_owner` at a specific `_snapshot` - /// @param _owner The address from which the balance will be retrieved - /// @param _snapshot The block number when the balance is queried - /// @return The balance at `_snapshot` - function balanceOfAt(address _owner, uint _snapshot) - constant - returns (uint) - { - Values[] storage values = balances[_owner]; - - // If there is a value, return it - if (hasValueAt(values, _snapshot)) { - return getValueAt(values, _snapshot, 0); - } - - // Try parent contract at the fork - if (address(parentToken) != 0) { - // TODO: Make snapshot numbers continue over the fork, - // be sure to use `min(_snapshot, parentSnapshot)` - return parentToken.balanceOfAt(_owner, parentSnapshot); - } - - // Default to an empty balance - return 0; - } - - /// @notice Total amount of tokens at a specific `_snapshot`. - /// @param _snapshot The block number when the totalSupply is queried - /// @return The total amount of tokens at `_snapshot` - function totalSupplyAt(uint _snapshot) - constant - returns(uint) - { - Values[] storage values = totalSupplyHistory; - - // If there is a value, return it - if (hasValueAt(values, _snapshot)) { - return getValueAt(values, _snapshot, 0); - } - - // Try parent contract at the fork - if (address(parentToken) != 0) { - return parentToken.totalSupplyAt(parentSnapshot); - } - - // Default to an empty balance - return 0; - } - //////////////// // Clone Token Method //////////////// @@ -342,7 +250,7 @@ contract MiniMeToken is Controlled, Snapshot { _transfersEnabled ); - cloneToken.changeController(msg.sender); + cloneToken.changeController(ITokenController(msg.sender)); // An event to make the token easy to find on the blockchain NewCloneToken(address(cloneToken), _snapshotBlock); @@ -353,79 +261,43 @@ contract MiniMeToken is Controlled, Snapshot { // Generate and destroy tokens //////////////// - /// @notice Generates `_amount` tokens that are assigned to `_owner` + /// @notice Mints `_amount` tokens that are assigned to `_owner` /// @param _owner The address that will be assigned the new tokens /// @param _amount The quantity of tokens generated /// @return True if the tokens are generated correctly - function generateTokens(address _owner, uint _amount - ) onlyController returns (bool) { - uint curTotalSupply = totalSupply(); - require(curTotalSupply + _amount >= curTotalSupply); // Check for overflow - uint previousBalanceTo = balanceOf(_owner); - require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow - setValue(totalSupplyHistory, curTotalSupply + _amount); - setValue(balances[_owner], previousBalanceTo + _amount); - Transfer(0, _owner, _amount); - return true; + function generateTokens(address _owner, uint _amount) + public + onlyController + returns (bool) + { + return snapshotBaseGenerateTokens(_owner, _amount); } - /// @notice Burns `_amount` tokens from `_owner` /// @param _owner The address that will lose the tokens /// @param _amount The quantity of tokens to burn /// @return True if the tokens are burned correctly - function destroyTokens(address _owner, uint _amount - ) onlyController returns (bool) { - uint curTotalSupply = totalSupply(); - require(curTotalSupply >= _amount); - uint previousBalanceFrom = balanceOf(_owner); - require(previousBalanceFrom >= _amount); - setValue(totalSupplyHistory, curTotalSupply - _amount); - setValue(balances[_owner], previousBalanceFrom - _amount); - Transfer(_owner, 0, _amount); - return true; + function destroyTokens(address _owner, uint _amount) + public + onlyController + returns (bool) + { + return snapshotBaseDestroyTokens(_owner, _amount); } //////////////// // Enable tokens transfers //////////////// - /// @notice Enables token holders to transfer their tokens freely if true /// @param _transfersEnabled True if transfers are allowed in the clone - function enableTransfers(bool _transfersEnabled) onlyController { + function enableTransfers(bool _transfersEnabled) + public + onlyController + { transfersEnabled = _transfersEnabled; } -//////////////// -// Internal helper functions to query and set a value in a snapshot array -//////////////// - - /// @dev Internal function to determine if an address is a contract - /// @param _addr The address being queried - /// @return True if `_addr` is a contract - function isContract(address _addr) constant internal returns(bool) { - uint size; - if (_addr == 0) return false; - assembly { - size := extcodesize(_addr) - } - return size>0; - } - - /// @dev Helper function to return a min betwen the two uints - function min(uint a, uint b) internal returns (uint) { - return a < b ? a : b; - } - - /// @notice The fallback function: If the contract's controller has not been - /// set to 0, then the `proxyPayment` method is called which relays the - /// ether and creates tokens as described in the token controller contract - function () payable { - require(isContract(controller)); - require(TokenController(controller).proxyPayment.value(msg.value)(msg.sender)); - } - ////////// // Safety Methods ////////// @@ -446,16 +318,4 @@ contract MiniMeToken is Controlled, Snapshot { ClaimedTokens(_token, controller, balance); } -//////////////// -// Events -//////////////// - event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount); - event Transfer(address indexed _from, address indexed _to, uint256 _amount); - event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock); - event Approval( - address indexed _owner, - address indexed _spender, - uint256 _amount - ); - } diff --git a/contracts/MiniMeTokenFactory.sol b/contracts/MiniMeTokenFactory.sol index 6a0ed1ab..668d0c82 100644 --- a/contracts/MiniMeTokenFactory.sol +++ b/contracts/MiniMeTokenFactory.sol @@ -1,5 +1,7 @@ pragma solidity ^0.4.13; +import './ISnapshotTokenParent.sol'; +import './ITokenController.sol'; import './MiniMeToken.sol'; //////////////// @@ -14,7 +16,7 @@ contract MiniMeTokenFactory { /// @notice Update the DApp by creating a new token with new functionalities /// the msg.sender becomes the controller of this clone token /// @param _parentToken Address of the token being cloned - /// @param _snapshotBlock Block of the parent token that will + /// @param _snapshot Block of the parent token that will /// determine the initial distribution of the clone token /// @param _tokenName Name of the new token /// @param _decimalUnits Number of decimals of the new token @@ -22,8 +24,8 @@ contract MiniMeTokenFactory { /// @param _transfersEnabled If true, tokens will be able to be transferred /// @return The address of the new token contract function createCloneToken( - address _parentToken, - uint _snapshotBlock, + ISnapshotTokenParent _parentToken, + uint _snapshot, string _tokenName, uint8 _decimalUnits, string _tokenSymbol, @@ -32,14 +34,14 @@ contract MiniMeTokenFactory { MiniMeToken newToken = new MiniMeToken( this, _parentToken, - _snapshotBlock, + _snapshot, _tokenName, _decimalUnits, _tokenSymbol, _transfersEnabled ); - newToken.changeController(msg.sender); + newToken.changeController(ITokenController(msg.sender)); return newToken; } } From dbb6eeec8744a9faf6a3e782282416db4a421536 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 23:34:52 +0200 Subject: [PATCH 13/40] Factor out controller claims --- contracts/ControllerClaims.sol | 47 ++++++++++++++++++++++++++++++++++ contracts/IOwned.sol | 18 +++++++++++++ contracts/MiniMeToken.sol | 26 +++---------------- 3 files changed, 68 insertions(+), 23 deletions(-) create mode 100644 contracts/ControllerClaims.sol create mode 100644 contracts/IOwned.sol diff --git a/contracts/ControllerClaims.sol b/contracts/ControllerClaims.sol new file mode 100644 index 00000000..5fd52cd3 --- /dev/null +++ b/contracts/ControllerClaims.sol @@ -0,0 +1,47 @@ +pragma solidity ^0.4.13; + +import './Controlled.sol'; +import './IBasicToken.sol'; +import './IOwned.sol'; + +contract ControllerClaims is Controlled { + +//////////////// +// Events +//////////////// + + event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount); + + event ClaimedOwnership(address indexed _owned, address indexed _controller); + +/////////////////// +// Public functions +/////////////////// + + /// @notice This method can be used by the controller to extract mistakenly + /// sent tokens to this contract. + /// @param _token The address of the token contract that you want to recover + /// set to 0 in case you want to extract ether. + function claimTokens(IBasicToken _token) + public + onlyController + { + // Transfer Ether + if (address(_token) == 0) { + controller.transfer(this.balance); + return; + } + + uint balance = _token.balanceOf(this); + _token.transfer(controller, balance); + ClaimedTokens(_token, controller, balance); + } + + function claimOwnership(IOwned _owned) + public + onlyController + { + _owned.changeOwner(controller); + ClaimedOwnership(_owned, controller); + } +} diff --git a/contracts/IOwned.sol b/contracts/IOwned.sol new file mode 100644 index 00000000..982befe2 --- /dev/null +++ b/contracts/IOwned.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.4.13; + + +/// @dev `Owned` is a base level contract that assigns an `owner` that can be +/// later changed +contract IOwned { + + function owner() + public + returns (address); + + /// @notice `owner` can step down and assign some other address to this role + /// @param _newOwner The address of the new owner. 0x0 can be used to create + /// an unowned neutral vault, however that cannot be undone + function changeOwner(address _newOwner) + public; + +} diff --git a/contracts/MiniMeToken.sol b/contracts/MiniMeToken.sol index 23eccfb5..ff0dfc07 100644 --- a/contracts/MiniMeToken.sol +++ b/contracts/MiniMeToken.sol @@ -8,6 +8,7 @@ import './MiniMeTokenFactory.sol'; import './SnapshotTokenBase.sol'; import './AllowanceBase.sol'; import './Helpers.sol'; +import './ControllerClaims.sol'; /* Copyright 2016, Jordi Baylina @@ -45,7 +46,8 @@ contract MiniMeToken is ISnapshotToken, SnapshotTokenBase, AllowanceBase, - Controlled + Controlled, + ControllerClaims { string public name; //The Token's name: e.g. DigixDAO Tokens @@ -63,8 +65,6 @@ contract MiniMeToken is // Events //////////////// - event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount); - event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock); //////////////// @@ -298,24 +298,4 @@ contract MiniMeToken is transfersEnabled = _transfersEnabled; } -////////// -// Safety Methods -////////// - - /// @notice This method can be used by the controller to extract mistakenly - /// sent tokens to this contract. - /// @param _token The address of the token contract that you want to recover - /// set to 0 in case you want to extract ether. - function claimTokens(address _token) onlyController { - if (_token == 0x0) { - controller.transfer(this.balance); - return; - } - - MiniMeToken token = MiniMeToken(_token); - uint balance = token.balanceOf(this); - token.transfer(controller, balance); - ClaimedTokens(_token, controller, balance); - } - } From d0fd09b76fa648781c0dd71fb763942402534aad Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 11 Aug 2017 23:38:01 +0200 Subject: [PATCH 14/40] Sort function order --- contracts/MiniMeToken.sol | 103 ++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 48 deletions(-) diff --git a/contracts/MiniMeToken.sol b/contracts/MiniMeToken.sol index ff0dfc07..82bb6efc 100644 --- a/contracts/MiniMeToken.sol +++ b/contracts/MiniMeToken.sol @@ -120,7 +120,7 @@ contract MiniMeToken is } /////////////////// -// ERC20 Methods +// Public functions /////////////////// /// @notice Send `_amount` tokens to `_to` from `msg.sender` @@ -135,45 +135,6 @@ contract MiniMeToken is return transfer(msg.sender, _to, _amount); } - /// @dev This is the actual transfer function in the token contract, it can - /// only be called by other functions in this contract. - /// @param _from The address holding the tokens being transferred - /// @param _to The address of the recipient - /// @param _amount The amount of tokens to be transferred - /// @return True if the transfer was successful - /// Implements the abstract function from AllowanceBase - function allowanceBaseTransfer(address _from, address _to, uint _amount) - internal - returns(bool) - { - return transfer(_from, _to, _amount); - } - - /// @dev This is the actual transfer function in the token contract, it can - /// only be called by other functions in this contract. - /// @param _from The address holding the tokens being transferred - /// @param _to The address of the recipient - /// @param _amount The amount of tokens to be transferred - /// @return True if the transfer was successful - /// Implements the abstract function from AllowanceBase - function transfer(address _from, address _to, uint _amount) - internal - returns(bool) - { - require(transfersEnabled); - - // Alerts the token controller of the transfer - if (isContract(controller)) { - require(controller.onTransfer(_from, _to, _amount)); - } - - // Do not allow transfer to 0x0 or the token contract itself - require(_to != 0); - require(_to != address(this)); - - return snapshotBaseTransfer(_from, _to, _amount); - } - /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on /// its behalf. This is a modified version of the ERC20 approve function /// to be a little bit safer @@ -239,7 +200,10 @@ contract MiniMeToken is string _cloneTokenSymbol, uint _snapshotBlock, bool _transfersEnabled - ) returns(address) { + ) + public + returns(address) + { if (_snapshotBlock == 0) _snapshotBlock = block.number; MiniMeToken cloneToken = tokenFactory.createCloneToken( this, @@ -257,6 +221,20 @@ contract MiniMeToken is return address(cloneToken); } +//////////////// +// Enable tokens transfers +//////////////// + + /// @notice Enables token holders to transfer their tokens freely if true + /// @param _transfersEnabled True if transfers are allowed in the clone + function enableTransfers(bool _transfersEnabled) + public + onlyController + { + transfersEnabled = _transfersEnabled; + } + + //////////////// // Generate and destroy tokens //////////////// @@ -286,16 +264,45 @@ contract MiniMeToken is } //////////////// -// Enable tokens transfers +// Internal functions //////////////// - /// @notice Enables token holders to transfer their tokens freely if true - /// @param _transfersEnabled True if transfers are allowed in the clone - function enableTransfers(bool _transfersEnabled) - public - onlyController + /// @dev This is the actual transfer function in the token contract, it can + /// only be called by other functions in this contract. + /// @param _from The address holding the tokens being transferred + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return True if the transfer was successful + /// Implements the abstract function from AllowanceBase + function allowanceBaseTransfer(address _from, address _to, uint _amount) + internal + returns(bool) { - transfersEnabled = _transfersEnabled; + return transfer(_from, _to, _amount); } + /// @dev This is the actual transfer function in the token contract, it can + /// only be called by other functions in this contract. + /// @param _from The address holding the tokens being transferred + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return True if the transfer was successful + /// Implements the abstract function from AllowanceBase + function transfer(address _from, address _to, uint _amount) + internal + returns(bool) + { + require(transfersEnabled); + + // Alerts the token controller of the transfer + if (isContract(controller)) { + require(controller.onTransfer(_from, _to, _amount)); + } + + // Do not allow transfer to 0x0 or the token contract itself + require(_to != 0); + require(_to != address(this)); + + return snapshotBaseTransfer(_from, _to, _amount); + } } From 47289d3e65d0ff91e26401a5f023e5a67486c032 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Mon, 21 Aug 2017 15:23:00 +0200 Subject: [PATCH 15/40] Mixins for snapshots mechanisms --- .../ISnapshotable.sol} | 2 +- contracts/Snapshot/MixinSnapshotId.sol | 22 +++++ contracts/{ => Snapshot}/Snapshot.sol | 70 +++------------ contracts/Snapshot/SnapshotBlocks.sol | 18 ++++ contracts/Snapshot/SnapshotDaily.sol | 35 ++++++++ contracts/Snapshot/SnapshotDailyHybrid.sol | 87 +++++++++++++++++++ contracts/Snapshot/SnapshotOndemand.sol | 55 ++++++++++++ contracts/{ => Snapshot}/SnapshotTest.sol | 0 8 files changed, 229 insertions(+), 60 deletions(-) rename contracts/{ISnapshot.sol => Snapshot/ISnapshotable.sol} (90%) create mode 100644 contracts/Snapshot/MixinSnapshotId.sol rename contracts/{ => Snapshot}/Snapshot.sol (73%) create mode 100644 contracts/Snapshot/SnapshotBlocks.sol create mode 100644 contracts/Snapshot/SnapshotDaily.sol create mode 100644 contracts/Snapshot/SnapshotDailyHybrid.sol create mode 100644 contracts/Snapshot/SnapshotOndemand.sol rename contracts/{ => Snapshot}/SnapshotTest.sol (100%) diff --git a/contracts/ISnapshot.sol b/contracts/Snapshot/ISnapshotable.sol similarity index 90% rename from contracts/ISnapshot.sol rename to contracts/Snapshot/ISnapshotable.sol index 8c153659..47edc8f2 100644 --- a/contracts/ISnapshot.sol +++ b/contracts/Snapshot/ISnapshotable.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.13; -contract ISnapshot { +contract ISnapshotable { //////////////// // Events diff --git a/contracts/Snapshot/MixinSnapshotId.sol b/contracts/Snapshot/MixinSnapshotId.sol new file mode 100644 index 00000000..876f35e8 --- /dev/null +++ b/contracts/Snapshot/MixinSnapshotId.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.4.13; + +contract MixinSnapshotId { + +//////////////// +// Internal abstract functions +//////////////// + + // The snapshot Ids need to be monotonically increasing. + // Whenever the snaspshot id changes, a new snapshot will + // be created. As long as the same value is being returned, + // this snapshot will be updated. + // + // Values passed to `hasValueAt` and `valuteAt` are required + // to be strictly less than `mixinNextSnapshotId()`. + function mixinNextSnapshotId() + internal + returns (uint256); + + function mixinFlagSnapshotModified() + internal; +} diff --git a/contracts/Snapshot.sol b/contracts/Snapshot/Snapshot.sol similarity index 73% rename from contracts/Snapshot.sol rename to contracts/Snapshot/Snapshot.sol index fbb1562b..95073488 100644 --- a/contracts/Snapshot.sol +++ b/contracts/Snapshot/Snapshot.sol @@ -1,6 +1,9 @@ pragma solidity ^0.4.13; -contract Snapshot { +import './MixinSnapshotId.sol'; + +// Snapshot consumes MixinSnapshotId +contract Snapshot is MixinSnapshotId { //////////////// // Types @@ -18,62 +21,12 @@ contract Snapshot { uint256 value; } -//////////////// -// State -//////////////// - - uint256 internal nextSnapshot; - - bool internal nextSnapshotModified; - //////////////// // Events //////////////// event SnapshotCreated(uint256 snapshot); -//////////////// -// Constructor -//////////////// - - function Snapshot(uint256 snapshotStart) - internal - { - require(snapshotStart < 2**256 - 1); - - // We can start at non-zero counter so the snapshots can - // continue from some other contract's snapshots. This is - // useful for forking. - nextSnapshot = snapshotStart + 1; - nextSnapshotModified = false; - } - -//////////////// -// Public functions -//////////////// - - function createSnapshot() - public - returns (uint256) - { - require(nextSnapshot < 2**256 - 1); - - // If no modifications have been made, the previous snapshot - // is identical to the current one. We can return the previous - // entry. - // TODO: Is this optimization worth it? It only avoids one - // storage counter increment. - if (!nextSnapshotModified) { - return nextSnapshot - 1; - } - - uint256 snapshot = nextSnapshot; - nextSnapshot += 1; - SnapshotCreated(snapshot); - nextSnapshotModified = false; - return snapshot; - } - //////////////// // Internal functions //////////////// @@ -96,7 +49,7 @@ contract Snapshot { constant returns (bool) { - require(_snapshot < nextSnapshot); + require(_snapshot < mixinNextSnapshotId()); return values.length > 0 && values[0].snapshot <= _snapshot; } @@ -129,7 +82,7 @@ contract Snapshot { constant returns (uint) { - require(_snapshot < nextSnapshot); + require(_snapshot < mixinNextSnapshotId())); // Empty value if (values.length == 0) { @@ -173,9 +126,12 @@ contract Snapshot { { // TODO: simplify or break into smaller functions + uint256 nextSnapshot = mixinNextSnapshotId(); + // Always create a new entry if there currently is no value bool empty = values.length == 0; if (empty) { + // Create a new entry values.push(Values({ snapshot: nextSnapshot, @@ -183,9 +139,7 @@ contract Snapshot { })); // Flag next snapshot as modified - if (!nextSnapshotModified) { - nextSnapshotModified = true; - } + mixinFlagSnapshotModified(); return; } @@ -206,9 +160,7 @@ contract Snapshot { })); // Flag next snapshot as modified - if (!nextSnapshotModified) { - nextSnapshotModified = true; - } + mixinFlagSnapshotModified(); } else { // We are updating the nextSnapshot diff --git a/contracts/Snapshot/SnapshotBlocks.sol b/contracts/Snapshot/SnapshotBlocks.sol new file mode 100644 index 00000000..950fb01e --- /dev/null +++ b/contracts/Snapshot/SnapshotBlocks.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.4.13; + +import './MixinSnapshotId.sol'; + +contract SnapshotBlocks is MixinSnapshotId { + + function mixinNextSnapshotId() + internal + returns (uint256) + { + return block.number; + } + + function mixinFlagSnapshotModified() + internal + { + } +} diff --git a/contracts/Snapshot/SnapshotDaily.sol b/contracts/Snapshot/SnapshotDaily.sol new file mode 100644 index 00000000..b8116d93 --- /dev/null +++ b/contracts/Snapshot/SnapshotDaily.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.4.13; + +import './MixinSnapshotId.sol'; + +contract SnapshotDaily is MixinSnapshotId { + + function snapshotAt(uint256 timestamp) + public + constant + returns (uint256) + { + // Round down to the start of the day (00:00 UTC) + timestamp -= timestamp % 1 days; + + return timestamp; + } + + function mixinNextSnapshotId() + internal + returns (uint256) + { + // Take the current time in UTC + uint256 timestamp = block.timestamp; + + // Round down to the start of the day (00:00 UTC) + timestamp -= timestamp % 1 days; + + return timestamp; + } + + function mixinFlagSnapshotModified() + internal + { + } +} diff --git a/contracts/Snapshot/SnapshotDailyHybrid.sol b/contracts/Snapshot/SnapshotDailyHybrid.sol new file mode 100644 index 00000000..1cc6abb4 --- /dev/null +++ b/contracts/Snapshot/SnapshotDailyHybrid.sol @@ -0,0 +1,87 @@ +pragma solidity ^0.4.13; + +import './MixinSnapshotId.sol'; +import './ISnapshotable.sol'; + +contract SnapshotDailyHybrid is + MixinSnapshotId, + ISnapshotable +{ + + uint256 nextSnapshotId; + bool nextSnapshotModified; + + function SnapshotDailyHybrid() { + uint256 dayBase = 2**128 * (block.timestamp / 1 days); + nextSnapshotId = dayBase + 1; + nextSnapshotModified = false; + } + + function snapshotAt(uint256 timestamp) + public + constant + returns (uint256) + { + require(timestamp < 2**128 / 1 days); + + uint256 dayBase = 2**128 * (timestamp / 1 days); + return dayBase; + } + + function createSnapshot() + public + returns (uint256) + { + uint256 dayBase = 2**128 * (block.timestamp / 1 days); + + // New day has started, create snapshot for midnight + if (dayBase > nextSnapshotId) { + nextSnapshotId = dayBase + 1; + nextSnapshotModified = false; + + SnapshotCreated(dayBase); + return dayBase; + } + + // Same day, no modifications + if (!nextSnapshotModified) { + return nextSnapshotId - 1; + } + + // Increment the snapshot counter + uint256 snapshotId = nextSnapshotId; + nextSnapshotId += 1; + nextSnapshotModified = false; + + // Log and return + SnapshotCreated(snapshotId); + return snapshotId; + } + + function mixinNextSnapshotId() + internal + returns (uint256) + { + uint256 dayBase = 2**128 * (block.timestamp / 1 days); + + // New day has started + if (dayBase > nextSnapshotId) { + nextSnapshotId = dayBase + 1; + nextSnapshotModified = false; + + SnapshotCreated(dayBase); + return nextSnapshotId; + } + + // Within same day + return nextSnapshotId; + } + + function mixinFlagSnapshotModified() + internal + { + if (!nextSnapshotModified) { + nextSnapshotModified = true; + } + } +} diff --git a/contracts/Snapshot/SnapshotOndemand.sol b/contracts/Snapshot/SnapshotOndemand.sol new file mode 100644 index 00000000..91e8f882 --- /dev/null +++ b/contracts/Snapshot/SnapshotOndemand.sol @@ -0,0 +1,55 @@ +pragma solidity ^0.4.13; + +import './MixinSnapshotId.sol'; +import './ISnapshotable.sol'; + +contract SnapshotOndemand is MixinSnapshotId, ISnapshotable { + + uint256 nextSnapshotId; + bool nextSnapshotModified; + + function SnapshotOndemand(uint256 start) + internal + { + nextSnapshotId = start; + nextSnapshotModified = true; + } + + function createSnapshot() + public + returns (uint256) + { + require(nextSnapshotId < 2**256 - 1); + + // If the snapshot was not modified, return + // the previous snapshot id. Their states + // are identical. + if (!nextSnapshotModified) { + return nextSnapshotId - 1; + } + + // Increment the snapshot counter + uint256 snapshotId = nextSnapshotId; + nextSnapshotId += 1; + nextSnapshotModified = false; + + // Log and return + SnapshotCreated(snapshotId); + return snapshotId; + } + + function mixinNextSnapshotId() + internal + returns (uint256) + { + return nextSnapshotId; + } + + function mixinFlagSnapshotModified() + internal + { + if (!nextSnapshotModified) { + nextSnapshotModified = true; + } + } +} diff --git a/contracts/SnapshotTest.sol b/contracts/Snapshot/SnapshotTest.sol similarity index 100% rename from contracts/SnapshotTest.sol rename to contracts/Snapshot/SnapshotTest.sol From d932eaf47a1bb7dc5eb1b22bc7df872257ed364b Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Mon, 21 Aug 2017 15:40:43 +0200 Subject: [PATCH 16/40] Use SnapshotDailyHybrid --- contracts/ISnapshotToken.sol | 2 +- contracts/ITokenController.sol | 4 ++++ contracts/MiniMeToken.sol | 2 ++ contracts/Snapshot/Snapshot.sol | 2 +- contracts/Snapshot/SnapshotDailyHybrid.sol | 5 ++++- contracts/SnapshotTokenBase.sol | 10 +++++++--- 6 files changed, 19 insertions(+), 6 deletions(-) diff --git a/contracts/ISnapshotToken.sol b/contracts/ISnapshotToken.sol index 00771b17..9efdccea 100644 --- a/contracts/ISnapshotToken.sol +++ b/contracts/ISnapshotToken.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.13; -// is ISnapshot, IBasicToken, ISnapshotTokenParent +// is ISnapshotable, IBasicToken, ISnapshotTokenParent interface ISnapshotToken { //////////////// diff --git a/contracts/ITokenController.sol b/contracts/ITokenController.sol index f1501cd4..a16a3df6 100644 --- a/contracts/ITokenController.sol +++ b/contracts/ITokenController.sol @@ -2,6 +2,10 @@ pragma solidity ^0.4.13; /// @dev The token controller contract must implement these functions interface ITokenController { + + // Payable callback function to receive eth + function () payable; + /// @notice Called when `_owner` sends ether to the MiniMe Token contract /// @param _owner The address that sent the ether to create tokens /// @return True if the ether is accepted, false if it throws diff --git a/contracts/MiniMeToken.sol b/contracts/MiniMeToken.sol index 82bb6efc..ee4f9e04 100644 --- a/contracts/MiniMeToken.sol +++ b/contracts/MiniMeToken.sol @@ -6,6 +6,7 @@ import './IERC20Token.sol'; import './ApproveAndCallFallback.sol'; import './MiniMeTokenFactory.sol'; import './SnapshotTokenBase.sol'; +import './Snapshot/SnapshotDailyHybrid.sol'; import './AllowanceBase.sol'; import './Helpers.sol'; import './ControllerClaims.sol'; @@ -45,6 +46,7 @@ contract MiniMeToken is IERC20Token, ISnapshotToken, SnapshotTokenBase, + SnapshotDailyHybrid, AllowanceBase, Controlled, ControllerClaims diff --git a/contracts/Snapshot/Snapshot.sol b/contracts/Snapshot/Snapshot.sol index 95073488..7d75e6f4 100644 --- a/contracts/Snapshot/Snapshot.sol +++ b/contracts/Snapshot/Snapshot.sol @@ -82,7 +82,7 @@ contract Snapshot is MixinSnapshotId { constant returns (uint) { - require(_snapshot < mixinNextSnapshotId())); + require(_snapshot < mixinNextSnapshotId()); // Empty value if (values.length == 0) { diff --git a/contracts/Snapshot/SnapshotDailyHybrid.sol b/contracts/Snapshot/SnapshotDailyHybrid.sol index 1cc6abb4..ae9d6082 100644 --- a/contracts/Snapshot/SnapshotDailyHybrid.sol +++ b/contracts/Snapshot/SnapshotDailyHybrid.sol @@ -8,6 +8,9 @@ contract SnapshotDailyHybrid is ISnapshotable { + // Floor[2**128 / 1 days] + uint256 MAX_TIMESTAMP = 3938453320844195178974243141571391; + uint256 nextSnapshotId; bool nextSnapshotModified; @@ -22,7 +25,7 @@ contract SnapshotDailyHybrid is constant returns (uint256) { - require(timestamp < 2**128 / 1 days); + require(timestamp < MAX_TIMESTAMP); uint256 dayBase = 2**128 * (timestamp / 1 days); return dayBase; diff --git a/contracts/SnapshotTokenBase.sol b/contracts/SnapshotTokenBase.sol index 7315ca45..cccef14a 100644 --- a/contracts/SnapshotTokenBase.sol +++ b/contracts/SnapshotTokenBase.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.13; -import './Snapshot.sol'; +import './Snapshot/Snapshot.sol'; import './ISnapshotToken.sol'; import './ISnapshotTokenParent.sol'; import './Helpers.sol'; @@ -46,7 +46,7 @@ contract SnapshotTokenBase is uint256 _parentSnapshot ) public - Snapshot(_parentSnapshot) + Snapshot() { parentToken = _parentToken; parentSnapshot = _parentSnapshot; @@ -150,7 +150,11 @@ contract SnapshotTokenBase is /// @param _to The address of the recipient /// @param _amount The amount of tokens to be transferred /// @return True if the transfer was successful - function snapshotBaseTransfer(address _from, address _to, uint _amount) + function snapshotBaseTransfer( + address _from, + address _to, + uint _amount + ) internal returns(bool) { From c6e5cf1d55085c8ba934d3e531fea77407f2015d Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Mon, 21 Aug 2017 15:44:32 +0200 Subject: [PATCH 17/40] Remove test code --- contracts/Snapshot/SnapshotTest.sol | 41 ----------------------------- 1 file changed, 41 deletions(-) delete mode 100644 contracts/Snapshot/SnapshotTest.sol diff --git a/contracts/Snapshot/SnapshotTest.sol b/contracts/Snapshot/SnapshotTest.sol deleted file mode 100644 index 3bd93b88..00000000 --- a/contracts/Snapshot/SnapshotTest.sol +++ /dev/null @@ -1,41 +0,0 @@ -pragma solidity ^0.4.13; - -import './Snapshot.sol'; - -contract SnapshotTest is Snapshot { - - Values[] myNumber; - - function SnapshotTest() - Snapshot(0) - { - } - - function create() - external - returns (uint256) - { - return Snapshot.createSnapshot(); - } - - function get() - external - returns (uint256) - { - return getValue(myNumber, 0); - } - - function get(uint256 snapshot) - external - returns (uint256) - { - return getValueAt(myNumber, snapshot, 0); - } - - function set(uint256 value) - external - { - return setValue(myNumber, value); - } - -} From 3141cbb48c8395da459d711142668f3da05a1ac7 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 13:02:19 +0200 Subject: [PATCH 18/40] Refactor mixins --- .../Snapshot/{SnapshotDaily.sol => Daily.sol} | 8 ++++---- ...ailyHybrid.sol => DailyAndSnapshotable.sol} | 10 +++++----- contracts/Snapshot/EveryBlock.sol | 18 ++++++++++++++++++ .../{MixinSnapshotId.sol => MPolicy.sol} | 7 ++++--- contracts/Snapshot/Snapshot.sol | 16 ++++++++-------- contracts/Snapshot/SnapshotBlocks.sol | 18 ------------------ .../{SnapshotOndemand.sol => Snapshotable.sol} | 7 +++++-- 7 files changed, 44 insertions(+), 40 deletions(-) rename contracts/Snapshot/{SnapshotDaily.sol => Daily.sol} (78%) rename contracts/Snapshot/{SnapshotDailyHybrid.sol => DailyAndSnapshotable.sol} (92%) create mode 100644 contracts/Snapshot/EveryBlock.sol rename contracts/Snapshot/{MixinSnapshotId.sol => MPolicy.sol} (81%) delete mode 100644 contracts/Snapshot/SnapshotBlocks.sol rename contracts/Snapshot/{SnapshotOndemand.sol => Snapshotable.sol} (92%) diff --git a/contracts/Snapshot/SnapshotDaily.sol b/contracts/Snapshot/Daily.sol similarity index 78% rename from contracts/Snapshot/SnapshotDaily.sol rename to contracts/Snapshot/Daily.sol index b8116d93..0716275b 100644 --- a/contracts/Snapshot/SnapshotDaily.sol +++ b/contracts/Snapshot/Daily.sol @@ -1,8 +1,8 @@ pragma solidity ^0.4.13; -import './MixinSnapshotId.sol'; +import './MPolicy.sol'; -contract SnapshotDaily is MixinSnapshotId { +contract Daily is MPolicy { function snapshotAt(uint256 timestamp) public @@ -15,7 +15,7 @@ contract SnapshotDaily is MixinSnapshotId { return timestamp; } - function mixinNextSnapshotId() + function mNextSnapshotId() internal returns (uint256) { @@ -28,7 +28,7 @@ contract SnapshotDaily is MixinSnapshotId { return timestamp; } - function mixinFlagSnapshotModified() + function mFlagSnapshotModified() internal { } diff --git a/contracts/Snapshot/SnapshotDailyHybrid.sol b/contracts/Snapshot/DailyAndSnapshotable.sol similarity index 92% rename from contracts/Snapshot/SnapshotDailyHybrid.sol rename to contracts/Snapshot/DailyAndSnapshotable.sol index ae9d6082..6d84a687 100644 --- a/contracts/Snapshot/SnapshotDailyHybrid.sol +++ b/contracts/Snapshot/DailyAndSnapshotable.sol @@ -1,10 +1,10 @@ pragma solidity ^0.4.13; -import './MixinSnapshotId.sol'; +import './MPolicy.sol'; import './ISnapshotable.sol'; -contract SnapshotDailyHybrid is - MixinSnapshotId, +contract DailyAndSnapshotable is + MPolicy, ISnapshotable { @@ -61,7 +61,7 @@ contract SnapshotDailyHybrid is return snapshotId; } - function mixinNextSnapshotId() + function mNextSnapshotId() internal returns (uint256) { @@ -80,7 +80,7 @@ contract SnapshotDailyHybrid is return nextSnapshotId; } - function mixinFlagSnapshotModified() + function mFlagSnapshotModified() internal { if (!nextSnapshotModified) { diff --git a/contracts/Snapshot/EveryBlock.sol b/contracts/Snapshot/EveryBlock.sol new file mode 100644 index 00000000..e311b73b --- /dev/null +++ b/contracts/Snapshot/EveryBlock.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.4.13; + +import './MPolicy.sol'; + +contract EveryBlock is MPolicy { + + function mNextSnapshotId() + internal + returns (uint256) + { + return block.number; + } + + function mFlagSnapshotModified() + internal + { + } +} diff --git a/contracts/Snapshot/MixinSnapshotId.sol b/contracts/Snapshot/MPolicy.sol similarity index 81% rename from contracts/Snapshot/MixinSnapshotId.sol rename to contracts/Snapshot/MPolicy.sol index 876f35e8..fd7e2970 100644 --- a/contracts/Snapshot/MixinSnapshotId.sol +++ b/contracts/Snapshot/MPolicy.sol @@ -1,6 +1,7 @@ pragma solidity ^0.4.13; -contract MixinSnapshotId { +// Mixin for the snapshot policy +contract MPolicy { //////////////// // Internal abstract functions @@ -13,10 +14,10 @@ contract MixinSnapshotId { // // Values passed to `hasValueAt` and `valuteAt` are required // to be strictly less than `mixinNextSnapshotId()`. - function mixinNextSnapshotId() + function mNextSnapshotId() internal returns (uint256); - function mixinFlagSnapshotModified() + function mFlagSnapshotModified() internal; } diff --git a/contracts/Snapshot/Snapshot.sol b/contracts/Snapshot/Snapshot.sol index 7d75e6f4..ccd5e08f 100644 --- a/contracts/Snapshot/Snapshot.sol +++ b/contracts/Snapshot/Snapshot.sol @@ -1,9 +1,9 @@ pragma solidity ^0.4.13; -import './MixinSnapshotId.sol'; +import './MPolicy.sol'; -// Snapshot consumes MixinSnapshotId -contract Snapshot is MixinSnapshotId { +// Snapshot consumes MPolicy +contract Snapshot is MPolicy { //////////////// // Types @@ -49,7 +49,7 @@ contract Snapshot is MixinSnapshotId { constant returns (bool) { - require(_snapshot < mixinNextSnapshotId()); + require(_snapshot < mNextSnapshotId()); return values.length > 0 && values[0].snapshot <= _snapshot; } @@ -82,7 +82,7 @@ contract Snapshot is MixinSnapshotId { constant returns (uint) { - require(_snapshot < mixinNextSnapshotId()); + require(_snapshot < mNextSnapshotId()); // Empty value if (values.length == 0) { @@ -126,7 +126,7 @@ contract Snapshot is MixinSnapshotId { { // TODO: simplify or break into smaller functions - uint256 nextSnapshot = mixinNextSnapshotId(); + uint256 nextSnapshot = mNextSnapshotId(); // Always create a new entry if there currently is no value bool empty = values.length == 0; @@ -139,7 +139,7 @@ contract Snapshot is MixinSnapshotId { })); // Flag next snapshot as modified - mixinFlagSnapshotModified(); + mFlagSnapshotModified(); return; } @@ -160,7 +160,7 @@ contract Snapshot is MixinSnapshotId { })); // Flag next snapshot as modified - mixinFlagSnapshotModified(); + mFlagSnapshotModified(); } else { // We are updating the nextSnapshot diff --git a/contracts/Snapshot/SnapshotBlocks.sol b/contracts/Snapshot/SnapshotBlocks.sol deleted file mode 100644 index 950fb01e..00000000 --- a/contracts/Snapshot/SnapshotBlocks.sol +++ /dev/null @@ -1,18 +0,0 @@ -pragma solidity ^0.4.13; - -import './MixinSnapshotId.sol'; - -contract SnapshotBlocks is MixinSnapshotId { - - function mixinNextSnapshotId() - internal - returns (uint256) - { - return block.number; - } - - function mixinFlagSnapshotModified() - internal - { - } -} diff --git a/contracts/Snapshot/SnapshotOndemand.sol b/contracts/Snapshot/Snapshotable.sol similarity index 92% rename from contracts/Snapshot/SnapshotOndemand.sol rename to contracts/Snapshot/Snapshotable.sol index 91e8f882..bb89134f 100644 --- a/contracts/Snapshot/SnapshotOndemand.sol +++ b/contracts/Snapshot/Snapshotable.sol @@ -1,9 +1,12 @@ pragma solidity ^0.4.13; -import './MixinSnapshotId.sol'; +import './MPolicy.sol'; import './ISnapshotable.sol'; -contract SnapshotOndemand is MixinSnapshotId, ISnapshotable { +contract Snapshotable is + MPolicy, + ISnapshotable +{ uint256 nextSnapshotId; bool nextSnapshotModified; From 968ac734813a32eccdfa36a40a1f0e4457f49f27 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 13:04:50 +0200 Subject: [PATCH 19/40] Use refactored snapshots --- contracts/MiniMeToken.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/MiniMeToken.sol b/contracts/MiniMeToken.sol index ee4f9e04..ef1ffebb 100644 --- a/contracts/MiniMeToken.sol +++ b/contracts/MiniMeToken.sol @@ -6,7 +6,7 @@ import './IERC20Token.sol'; import './ApproveAndCallFallback.sol'; import './MiniMeTokenFactory.sol'; import './SnapshotTokenBase.sol'; -import './Snapshot/SnapshotDailyHybrid.sol'; +import './Snapshot/DailyAndSnapshotable.sol'; import './AllowanceBase.sol'; import './Helpers.sol'; import './ControllerClaims.sol'; @@ -46,7 +46,7 @@ contract MiniMeToken is IERC20Token, ISnapshotToken, SnapshotTokenBase, - SnapshotDailyHybrid, + DailyAndSnapshotable, AllowanceBase, Controlled, ControllerClaims From 0290e9a518d9fb814d6eef9b8e5bd37bebb6edfd Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Sun, 13 Aug 2017 12:39:56 +0200 Subject: [PATCH 20/40] Interface IApproveAndCallFallback --- contracts/AllowanceBase.sol | 7 ++++--- contracts/ApproveAndCallFallback.sol | 5 ----- contracts/IApproveAndCallFallback.sol | 15 +++++++++++++++ contracts/MiniMeToken.sol | 4 ++-- 4 files changed, 21 insertions(+), 10 deletions(-) delete mode 100644 contracts/ApproveAndCallFallback.sol create mode 100644 contracts/IApproveAndCallFallback.sol diff --git a/contracts/AllowanceBase.sol b/contracts/AllowanceBase.sol index 7601b27b..ac0143db 100644 --- a/contracts/AllowanceBase.sol +++ b/contracts/AllowanceBase.sol @@ -1,6 +1,7 @@ pragma solidity ^0.4.13; -import './ApproveAndCallFallback.sol'; +import './IApproveAndCallFallback.sol'; +import './IERC20Token.sol'; contract AllowanceBase { @@ -79,10 +80,10 @@ contract AllowanceBase { ) returns (bool success) { require(approve(_spender, _amount)); - ApproveAndCallFallBack(_spender).receiveApproval( + IApproveAndCallFallback(_spender).receiveApproval( msg.sender, _amount, - this, + IERC20Token(this), _extraData ); diff --git a/contracts/ApproveAndCallFallback.sol b/contracts/ApproveAndCallFallback.sol deleted file mode 100644 index dbbee687..00000000 --- a/contracts/ApproveAndCallFallback.sol +++ /dev/null @@ -1,5 +0,0 @@ -pragma solidity ^0.4.13; - -contract ApproveAndCallFallBack { - function receiveApproval(address from, uint256 _amount, address _token, bytes _data); -} diff --git a/contracts/IApproveAndCallFallback.sol b/contracts/IApproveAndCallFallback.sol new file mode 100644 index 00000000..34e5b55f --- /dev/null +++ b/contracts/IApproveAndCallFallback.sol @@ -0,0 +1,15 @@ +pragma solidity ^0.4.13; + +import './IERC20Token.sol'; + +contract IApproveAndCallFallback { + + function receiveApproval( + address from, + uint256 amount, + IERC20Token token, + bytes data + ) + public; + +} diff --git a/contracts/MiniMeToken.sol b/contracts/MiniMeToken.sol index ef1ffebb..91e651b5 100644 --- a/contracts/MiniMeToken.sol +++ b/contracts/MiniMeToken.sol @@ -3,7 +3,7 @@ pragma solidity ^0.4.13; import './Controlled.sol'; import './ITokenController.sol'; import './IERC20Token.sol'; -import './ApproveAndCallFallback.sol'; +import './IApproveAndCallFallback.sol'; import './MiniMeTokenFactory.sol'; import './SnapshotTokenBase.sol'; import './Snapshot/DailyAndSnapshotable.sol'; @@ -172,7 +172,7 @@ contract MiniMeToken is { require(approve(_spender, _amount)); - ApproveAndCallFallBack(_spender).receiveApproval( + IApproveAndCallFallback(_spender).receiveApproval( msg.sender, _amount, this, From 057d39db4154957f53d7062e8f8d60b9d9f31209 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Sun, 13 Aug 2017 12:40:12 +0200 Subject: [PATCH 21/40] Add Disbursal contract --- contracts/Disbursal.sol | 171 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 contracts/Disbursal.sol diff --git a/contracts/Disbursal.sol b/contracts/Disbursal.sol new file mode 100644 index 00000000..4225f6d3 --- /dev/null +++ b/contracts/Disbursal.sol @@ -0,0 +1,171 @@ +pragma solidity ^0.4.13; + +import './ISnapshotToken.sol'; +import './IBasicToken.sol'; +import './IERC20Token.sol'; +import './IApproveAndCallFallback.sol'; + +// TODO: Anyone can create a token and disburse it, but then everyone +// needs to pay extra gas for claim(). It is not possible to skip +// these mallicious disbursals. Some solution strategies: +// * Limit the people who can disburse to a trusted set +// * Allow claims in any order + +contract Disbursal is IApproveAndCallFallback { + +//////////////// +// Types +//////////////// + + struct Disbursment { + uint256 snapshot; + IBasicToken disbursedToken; + uint256 remainingAmount; + uint256 remainingShares; + } + +//////////////// +// State +//////////////// + + ISnapshotToken public SHARE_TOKEN; + + Disbursment[] disbursments; + + mapping(address => uint256) claimed; + +//////////////// +// Events +//////////////// + + event Disbursed( + uint256 disbursalIndex, + IBasicToken disbursedToken, + uint256 amount, + uint256 snapshot, + uint256 totalShares + ); + + event Claimed( + address beneficiary, + uint256 disbursalIndex, + IBasicToken disbursedToken, + uint256 amount + ); + +//////////////// +// Constructor +//////////////// + + function Disbursal( + ISnapshotToken shareToken + ) + public + { + SHARE_TOKEN = shareToken; + } + +//////////////// +// Public functions +//////////////// + + function claim() + public + { + claim(msg.sender); + } + + function claim(address beneficiary) + public + { + for(uint256 i = claimed[beneficiary]; i < disbursments.length; ++i) { + claim(beneficiary, i); + } + } + + function claim(address beneficiary, uint256 index) + public + { + require(index < disbursments.length); + require(claimed[beneficiary] == index); + + // Compute share + // NOTE: By mainting both remaining counters we have automatic + // distribution of rounding errors between claims, with the + // final claim being exact and issuing all the remaining tokens. + // TODO: Remove < 2¹²⁸ restrictions + // TODO: Correct rounding instead of floor. + Disbursment storage disbursment = disbursments[index]; + uint256 shares = SHARE_TOKEN.balanceOfAt(beneficiary, disbursment.snapshot); + assert(disbursment.remainingShares < 2**128); + assert(disbursment.remainingAmount < 2**128); + assert(shares <= disbursment.remainingShares); + uint256 amount = (disbursment.remainingAmount * shares) / disbursment.remainingShares; + assert(amount <= disbursment.remainingAmount); + + // Update state + disbursment.remainingAmount -= amount; + disbursment.remainingShares -= shares; + claimed[beneficiary] = index + 1; + + // Transfer tokens + IBasicToken token = disbursment.disbursedToken; + bool success = token.transfer(beneficiary, amount); + require(success); + + // Log and return + Claimed(beneficiary, index, token, amount); + } + + // ERC20 receiver + function receiveApproval(address from, uint256 amount, IERC20Token token, bytes data) + { + require(data.length == 0); + + // Transfer all allowed tokens to self. + require(amount < 2**128); + bool success = token.transferFrom(from, this, amount); + require(success); + + // Disburse these tokens + disburse(IBasicToken(token), amount); + } + + // TODO: ERC223 style receiver + +//////////////// +// Internal functions +//////////////// + + // TODO: Ideally we make this function public, and allow + // disbursal of any basic token. When counting how + // many tokens we need to disburse, a simple + // `balanceOf(this)` is insufficient, as it also + // contains the remaining amount from previous disbursments. + function disburse(IBasicToken token, uint256 amount) + internal + { + // Transfer all allowed tokens to self. + require(amount < 2**128); + + // Verify our balance + // TODO: we need to check for newly received tokens! + + // Create snapshot + uint256 snapshot = SHARE_TOKEN.createSnapshot(); + uint256 totalShares = SHARE_TOKEN.totalSupplyAt(snapshot); + require(totalShares < 2**128); + + // Create disbursal + uint256 index = disbursments.length; + disbursments.push(Disbursment({ + snapshot: snapshot, + disbursedToken: token, + remainingAmount: amount, + remainingShares: totalShares + })); + + // Log + Disbursed(index, token, amount, snapshot, totalShares); + } +} From 4219c4374941421992541208ffffe59340ca25e3 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Sun, 13 Aug 2017 14:54:20 +0200 Subject: [PATCH 22/40] Allow out of order claims --- contracts/Disbursal.sol | 115 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 9 deletions(-) diff --git a/contracts/Disbursal.sol b/contracts/Disbursal.sol index 4225f6d3..f8294da0 100644 --- a/contracts/Disbursal.sol +++ b/contracts/Disbursal.sol @@ -32,7 +32,7 @@ contract Disbursal is IApproveAndCallFallback { Disbursment[] disbursments; - mapping(address => uint256) claimed; + mapping(address => mapping(uint256 => bool)) claimed; //////////////// // Events @@ -69,6 +69,59 @@ contract Disbursal is IApproveAndCallFallback { // Public functions //////////////// + function claimable() + public + constant + returns (uint256[]) + { + return claimable(msg.sender); + } + + function claimable(address beneficiary) + public + constant + returns (uint256[]) + { + return claimable(beneficiary, 0, disbursments.length); + } + + function claimable(address beneficiary, uint256 from, uint256 to) + public + constant + returns (uint256[]) + { + require(from <= to); + require(to < disbursments.length); + uint256[] storage result; + for(uint256 i = from; i < to; ++i) { + if(claimable(beneficiary, i)) { + result.push(i); + } + } + return result; + } + + function claimable(address beneficiary, uint256 index) + public + constant + returns (bool) + { + // Invalid index + if(index >= disbursments.length) { + return false; + } + + // Already claimed + if(claimed[beneficiary][index] == true) { + return false; + } + + // Check if `beneficiary` has shares + Disbursment storage disbursment = disbursments[index]; + uint256 shares = SHARE_TOKEN.balanceOfAt(beneficiary, disbursment.snapshot); + return shares > 0; + } + function claim() public { @@ -78,8 +131,18 @@ contract Disbursal is IApproveAndCallFallback { function claim(address beneficiary) public { - for(uint256 i = claimed[beneficiary]; i < disbursments.length; ++i) { - claim(beneficiary, i); + for(uint256 i = 0; i < disbursments.length; ++i) { + if(claimed[beneficiary][i] == false) { + claim(beneficiary, i); + } + } + } + + function claim(address beneficiary, uint256[] indices) + public + { + for(uint256 i = 0; i < indices.length; ++i) { + claim(beneficiary, indices[i]); } } @@ -87,7 +150,7 @@ contract Disbursal is IApproveAndCallFallback { public { require(index < disbursments.length); - require(claimed[beneficiary] == index); + require(claimed[beneficiary][index] == false); // Compute share // NOTE: By mainting both remaining counters we have automatic @@ -100,13 +163,14 @@ contract Disbursal is IApproveAndCallFallback { assert(disbursment.remainingShares < 2**128); assert(disbursment.remainingAmount < 2**128); assert(shares <= disbursment.remainingShares); - uint256 amount = (disbursment.remainingAmount * shares) / disbursment.remainingShares; + uint256 amount = mulDiv(disbursment.remainingAmount, shares, disbursment.remainingShares); assert(amount <= disbursment.remainingAmount); // Update state + // TODO: Can we reduce the number of state writes? disbursment.remainingAmount -= amount; disbursment.remainingShares -= shares; - claimed[beneficiary] = index + 1; + claimed[beneficiary][index] = true; // Transfer tokens IBasicToken token = disbursment.disbursedToken; @@ -117,11 +181,16 @@ contract Disbursal is IApproveAndCallFallback { Claimed(beneficiary, index, token, amount); } - // ERC20 receiver - function receiveApproval(address from, uint256 amount, IERC20Token token, bytes data) + function disburseAllowance(IERC20Token token) + public { - require(data.length == 0); + uint256 amount = token.allowance(msg.sender, this); + disburseAllowance(token, msg.sender); + } + function disburseAllowance(IERC20Token token, address from, uint256 amount) + public + { // Transfer all allowed tokens to self. require(amount < 2**128); bool success = token.transferFrom(from, this, amount); @@ -131,6 +200,14 @@ contract Disbursal is IApproveAndCallFallback { disburse(IBasicToken(token), amount); } + // ERC20 receiver + function receiveApproval(address from, uint256 amount, IERC20Token token, bytes data) + public + { + require(data.length == 0); + disburseAllowance(token, from, amount) + } + // TODO: ERC223 style receiver //////////////// @@ -146,6 +223,7 @@ contract Disbursal is IApproveAndCallFallback { internal { // Transfer all allowed tokens to self. + require(amount > 0); require(amount < 2**128); // Verify our balance @@ -168,4 +246,23 @@ contract Disbursal is IApproveAndCallFallback { // Log Disbursed(index, token, amount, snapshot, totalShares); } + + function mulDiv(uint256 a, uint256 n, uint256 d) + internal + constant + returns (uint256) + { + require(a < 2**128); + require(d < 2**128); + require(n <= d); + + uint256 s = a * n; + + // Correct rounding + s += n / 2; + + uint256 f = s / d; + + return f; + } } From 7af979edfb1c5b91e15f65b67d99155617dc1b0b Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 13:45:28 +0200 Subject: [PATCH 23/40] Sort files in folders --- contracts/ControllerClaims.sol | 11 +--- .../SampleCampaign-TokenController.sol | 0 contracts/{ => Extensions}/Disbursal.sol | 0 .../Allowance.sol} | 23 +++---- contracts/{ => Helpers}/Helpers.sol | 0 contracts/Helpers/MAllowance.sol | 9 +++ contracts/Helpers/MMint.sol | 20 ++++++ .../SnapshotToken.sol} | 16 +++-- contracts/Helpers/TokenInfo.sol | 26 ++++++++ contracts/IOwned.sol | 18 ----- contracts/MiniMeToken.sol | 65 ++++++++++--------- contracts/MiniMeTokenFactory.sol | 2 +- contracts/Snapshot/DailyAndSnapshotable.sol | 2 +- contracts/Snapshot/Snapshotable.sol | 2 +- .../IApproveAndCallFallback.sol | 0 contracts/{ => Standards}/IBasicToken.sol | 0 contracts/Standards/IERC20Allowance.sol | 49 ++++++++++++++ contracts/{ => Standards}/IERC20Token.sol | 2 +- contracts/{ => Standards}/ISnapshotToken.sol | 0 .../{ => Standards}/ISnapshotTokenParent.sol | 0 .../{Snapshot => Standards}/ISnapshotable.sol | 0 21 files changed, 161 insertions(+), 84 deletions(-) rename contracts/{ => Examples}/SampleCampaign-TokenController.sol (100%) rename contracts/{ => Extensions}/Disbursal.sol (100%) rename contracts/{AllowanceBase.sol => Helpers/Allowance.sol} (90%) rename contracts/{ => Helpers}/Helpers.sol (100%) create mode 100644 contracts/Helpers/MAllowance.sol create mode 100644 contracts/Helpers/MMint.sol rename contracts/{SnapshotTokenBase.sol => Helpers/SnapshotToken.sol} (95%) create mode 100644 contracts/Helpers/TokenInfo.sol delete mode 100644 contracts/IOwned.sol rename contracts/{ => Standards}/IApproveAndCallFallback.sol (100%) rename contracts/{ => Standards}/IBasicToken.sol (100%) create mode 100644 contracts/Standards/IERC20Allowance.sol rename contracts/{ => Standards}/IERC20Token.sol (98%) rename contracts/{ => Standards}/ISnapshotToken.sol (100%) rename contracts/{ => Standards}/ISnapshotTokenParent.sol (100%) rename contracts/{Snapshot => Standards}/ISnapshotable.sol (100%) diff --git a/contracts/ControllerClaims.sol b/contracts/ControllerClaims.sol index 5fd52cd3..cab6ebf2 100644 --- a/contracts/ControllerClaims.sol +++ b/contracts/ControllerClaims.sol @@ -1,8 +1,7 @@ pragma solidity ^0.4.13; import './Controlled.sol'; -import './IBasicToken.sol'; -import './IOwned.sol'; +import './Standards/IBasicToken.sol'; contract ControllerClaims is Controlled { @@ -36,12 +35,4 @@ contract ControllerClaims is Controlled { _token.transfer(controller, balance); ClaimedTokens(_token, controller, balance); } - - function claimOwnership(IOwned _owned) - public - onlyController - { - _owned.changeOwner(controller); - ClaimedOwnership(_owned, controller); - } } diff --git a/contracts/SampleCampaign-TokenController.sol b/contracts/Examples/SampleCampaign-TokenController.sol similarity index 100% rename from contracts/SampleCampaign-TokenController.sol rename to contracts/Examples/SampleCampaign-TokenController.sol diff --git a/contracts/Disbursal.sol b/contracts/Extensions/Disbursal.sol similarity index 100% rename from contracts/Disbursal.sol rename to contracts/Extensions/Disbursal.sol diff --git a/contracts/AllowanceBase.sol b/contracts/Helpers/Allowance.sol similarity index 90% rename from contracts/AllowanceBase.sol rename to contracts/Helpers/Allowance.sol index ac0143db..29afcc54 100644 --- a/contracts/AllowanceBase.sol +++ b/contracts/Helpers/Allowance.sol @@ -1,9 +1,14 @@ pragma solidity ^0.4.13; -import './IApproveAndCallFallback.sol'; -import './IERC20Token.sol'; +import '../Standards/IERC20Allowance.sol'; +import '../Standards/IApproveAndCallFallback.sol'; +import './MAllowance.sol'; -contract AllowanceBase { +// Consumes the MAllowance mixin +contract Allowance is + IERC20Allowance, + MAllowance +{ //////////////// // State @@ -26,7 +31,7 @@ contract AllowanceBase { // Constructor //////////////// - function AllowanceBase() + function Allowance() internal { } @@ -106,15 +111,7 @@ contract AllowanceBase { } allowed[_from][msg.sender] -= _amount; - return allowanceBaseTransfer(_from, _to, _amount); + return mAllowanceTransfer(_from, _to, _amount); } -//////////////// -// Abstract functions -//////////////// - - function allowanceBaseTransfer(address from, address to, uint256 amount) - internal - returns (bool); - } diff --git a/contracts/Helpers.sol b/contracts/Helpers/Helpers.sol similarity index 100% rename from contracts/Helpers.sol rename to contracts/Helpers/Helpers.sol diff --git a/contracts/Helpers/MAllowance.sol b/contracts/Helpers/MAllowance.sol new file mode 100644 index 00000000..722e1d77 --- /dev/null +++ b/contracts/Helpers/MAllowance.sol @@ -0,0 +1,9 @@ +pragma solidity ^0.4.13; + +contract MAllowance { + + function mAllowanceTransfer(address from, address to, uint256 amount) + internal + returns (bool); + +} diff --git a/contracts/Helpers/MMint.sol b/contracts/Helpers/MMint.sol new file mode 100644 index 00000000..2849f93e --- /dev/null +++ b/contracts/Helpers/MMint.sol @@ -0,0 +1,20 @@ +pragma solidity ^0.4.13; + +contract MMint { + + /// @notice Generates `_amount` tokens that are assigned to `_owner` + /// @param _owner The address that will be assigned the new tokens + /// @param _amount The quantity of tokens generated + /// @return True if the tokens are generated correctly + function mGenerateTokens(address _owner, uint _amount) + internal + returns (bool); + + /// @notice Burns `_amount` tokens from `_owner` + /// @param _owner The address that will lose the tokens + /// @param _amount The quantity of tokens to burn + /// @return True if the tokens are burned correctly + function mDestroyTokens(address _owner, uint _amount) + internal + returns (bool); +} diff --git a/contracts/SnapshotTokenBase.sol b/contracts/Helpers/SnapshotToken.sol similarity index 95% rename from contracts/SnapshotTokenBase.sol rename to contracts/Helpers/SnapshotToken.sol index cccef14a..36905a2e 100644 --- a/contracts/SnapshotTokenBase.sol +++ b/contracts/Helpers/SnapshotToken.sol @@ -1,13 +1,15 @@ pragma solidity ^0.4.13; -import './Snapshot/Snapshot.sol'; -import './ISnapshotToken.sol'; -import './ISnapshotTokenParent.sol'; +import '../Snapshot/Snapshot.sol'; +import '../Standards/ISnapshotToken.sol'; +import '../Standards/ISnapshotTokenParent.sol'; +import './MMint.sol'; import './Helpers.sol'; -contract SnapshotTokenBase is +contract SnapshotToken is ISnapshotToken, ISnapshotTokenParent, + MMint, Snapshot, Helpers { @@ -41,7 +43,7 @@ contract SnapshotTokenBase is /// @notice Constructor to create a MiniMeToken /// @param _parentToken Address of the parent token, set to 0x0 if it is a /// new token - function SnapshotTokenBase( + function SnapshotToken( ISnapshotTokenParent _parentToken, uint256 _parentSnapshot ) @@ -190,7 +192,7 @@ contract SnapshotTokenBase is /// @param _owner The address that will be assigned the new tokens /// @param _amount The quantity of tokens generated /// @return True if the tokens are generated correctly - function snapshotBaseGenerateTokens(address _owner, uint _amount) + function mGenerateTokens(address _owner, uint _amount) internal returns (bool) { @@ -213,7 +215,7 @@ contract SnapshotTokenBase is /// @param _owner The address that will lose the tokens /// @param _amount The quantity of tokens to burn /// @return True if the tokens are burned correctly - function snapshotBaseDestroyTokens(address _owner, uint _amount) + function mDestroyTokens(address _owner, uint _amount) internal returns (bool) { diff --git a/contracts/Helpers/TokenInfo.sol b/contracts/Helpers/TokenInfo.sol new file mode 100644 index 00000000..ccecf750 --- /dev/null +++ b/contracts/Helpers/TokenInfo.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.4.13; + + +contract TokenInfo { + + string public name; //The Token's name: e.g. DigixDAO Tokens + uint8 public decimals; //Number of decimals of the smallest unit + string public symbol; //An identifier: e.g. REP + string public version; //An arbitrary versioning scheme + + /// @notice Constructor to create a MiniMeToken + /// @param _tokenName Name of the new token + /// @param _decimalUnits Number of decimals of the new token + /// @param _tokenSymbol Token Symbol for the new token + function TokenInfo( + string _tokenName, + uint8 _decimalUnits, + string _tokenSymbol, + string _version + ) { + name = _tokenName; // Set the name + decimals = _decimalUnits; // Set the decimals + symbol = _tokenSymbol; // Set the symbol + version = _version; + } +} diff --git a/contracts/IOwned.sol b/contracts/IOwned.sol deleted file mode 100644 index 982befe2..00000000 --- a/contracts/IOwned.sol +++ /dev/null @@ -1,18 +0,0 @@ -pragma solidity ^0.4.13; - - -/// @dev `Owned` is a base level contract that assigns an `owner` that can be -/// later changed -contract IOwned { - - function owner() - public - returns (address); - - /// @notice `owner` can step down and assign some other address to this role - /// @param _newOwner The address of the new owner. 0x0 can be used to create - /// an unowned neutral vault, however that cannot be undone - function changeOwner(address _newOwner) - public; - -} diff --git a/contracts/MiniMeToken.sol b/contracts/MiniMeToken.sol index 91e651b5..27b13e12 100644 --- a/contracts/MiniMeToken.sol +++ b/contracts/MiniMeToken.sol @@ -1,15 +1,16 @@ pragma solidity ^0.4.13; import './Controlled.sol'; +import './ControllerClaims.sol'; +import './Helpers/Allowance.sol'; +import './Helpers/Helpers.sol'; +import './Helpers/SnapshotToken.sol'; +import './Helpers/TokenInfo.sol'; import './ITokenController.sol'; -import './IERC20Token.sol'; -import './IApproveAndCallFallback.sol'; import './MiniMeTokenFactory.sol'; -import './SnapshotTokenBase.sol'; import './Snapshot/DailyAndSnapshotable.sol'; -import './AllowanceBase.sol'; -import './Helpers.sol'; -import './ControllerClaims.sol'; +import './Standards/IApproveAndCallFallback.sol'; +import './Standards/IERC20Token.sol'; /* Copyright 2016, Jordi Baylina @@ -41,21 +42,21 @@ import './ControllerClaims.sol'; /// that deploys the contract, so usually this token will be deployed by a /// token controller contract, which Giveth will call a "Campaign" -// Helpers is inherited through SnapshotTokenBase +// Helpers is inherited through SnapshotToken +// Consumes the MMint mixin from SnapshotToken contract MiniMeToken is IERC20Token, ISnapshotToken, - SnapshotTokenBase, + MMint, + SnapshotToken, DailyAndSnapshotable, - AllowanceBase, + Allowance, + TokenInfo, Controlled, ControllerClaims { - string public name; //The Token's name: e.g. DigixDAO Tokens - uint8 public decimals; //Number of decimals of the smallest unit - string public symbol; //An identifier: e.g. REP - string public version = 'MMT_0.1'; //An arbitrary versioning scheme + string private constant VERSION = "MMT_2.0"; // Flag that determines if the token is transferable or not. bool public transfersEnabled; @@ -77,32 +78,32 @@ contract MiniMeToken is /// @param _tokenFactory The address of the MiniMeTokenFactory contract that /// will create the Clone token contracts, the token factory needs to be /// deployed first - /// @param _parentToken Address of the parent token, set to 0x0 if it is a + /// @param parentToken Address of the parent token, set to 0x0 if it is a /// new token - /// @param _parentSnapshot Block of the parent token that will + /// @param parentSnapshot Block of the parent token that will /// determine the initial distribution of the clone token, set to 0 if it /// is a new token - /// @param _tokenName Name of the new token - /// @param _decimalUnits Number of decimals of the new token - /// @param _tokenSymbol Token Symbol for the new token + /// @param tokenName Name of the new token + /// @param decimalUnits Number of decimals of the new token + /// @param tokenSymbol Token Symbol for the new token /// @param _transfersEnabled If true, tokens will be able to be transferred function MiniMeToken( address _tokenFactory, - ISnapshotTokenParent _parentToken, - uint _parentSnapshot, - string _tokenName, - uint8 _decimalUnits, - string _tokenSymbol, + ISnapshotTokenParent parentToken, + uint parentSnapshot, + string tokenName, + uint8 decimalUnits, + string tokenSymbol, bool _transfersEnabled ) - SnapshotTokenBase(_parentToken, _parentSnapshot) - AllowanceBase() + SnapshotToken(parentToken, parentSnapshot) + DailyAndSnapshotable() + Allowance() + TokenInfo(tokenName, decimalUnits, tokenSymbol, VERSION) Controlled() + ControllerClaims() { tokenFactory = MiniMeTokenFactory(_tokenFactory); - name = _tokenName; // Set the name - decimals = _decimalUnits; // Set the decimals - symbol = _tokenSymbol; // Set the symbol transfersEnabled = _transfersEnabled; } @@ -155,7 +156,7 @@ contract MiniMeToken is require(controller.onApprove(msg.sender, _spender, _amount)); } - return AllowanceBase.approve(_spender, _amount); + return Allowance.approve(_spender, _amount); } /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on @@ -250,7 +251,7 @@ contract MiniMeToken is onlyController returns (bool) { - return snapshotBaseGenerateTokens(_owner, _amount); + return SnapshotToken.mGenerateTokens(_owner, _amount); } /// @notice Burns `_amount` tokens from `_owner` @@ -262,7 +263,7 @@ contract MiniMeToken is onlyController returns (bool) { - return snapshotBaseDestroyTokens(_owner, _amount); + return SnapshotToken.mDestroyTokens(_owner, _amount); } //////////////// @@ -276,7 +277,7 @@ contract MiniMeToken is /// @param _amount The amount of tokens to be transferred /// @return True if the transfer was successful /// Implements the abstract function from AllowanceBase - function allowanceBaseTransfer(address _from, address _to, uint _amount) + function mAllowanceTransfer(address _from, address _to, uint _amount) internal returns(bool) { diff --git a/contracts/MiniMeTokenFactory.sol b/contracts/MiniMeTokenFactory.sol index 668d0c82..3fb8f85e 100644 --- a/contracts/MiniMeTokenFactory.sol +++ b/contracts/MiniMeTokenFactory.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.13; -import './ISnapshotTokenParent.sol'; +import './Standards/ISnapshotTokenParent.sol'; import './ITokenController.sol'; import './MiniMeToken.sol'; diff --git a/contracts/Snapshot/DailyAndSnapshotable.sol b/contracts/Snapshot/DailyAndSnapshotable.sol index 6d84a687..ef7a2bf1 100644 --- a/contracts/Snapshot/DailyAndSnapshotable.sol +++ b/contracts/Snapshot/DailyAndSnapshotable.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.13; +import '../Standards/ISnapshotable.sol'; import './MPolicy.sol'; -import './ISnapshotable.sol'; contract DailyAndSnapshotable is MPolicy, diff --git a/contracts/Snapshot/Snapshotable.sol b/contracts/Snapshot/Snapshotable.sol index bb89134f..48797097 100644 --- a/contracts/Snapshot/Snapshotable.sol +++ b/contracts/Snapshot/Snapshotable.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.13; +import '../Standards/ISnapshotable.sol'; import './MPolicy.sol'; -import './ISnapshotable.sol'; contract Snapshotable is MPolicy, diff --git a/contracts/IApproveAndCallFallback.sol b/contracts/Standards/IApproveAndCallFallback.sol similarity index 100% rename from contracts/IApproveAndCallFallback.sol rename to contracts/Standards/IApproveAndCallFallback.sol diff --git a/contracts/IBasicToken.sol b/contracts/Standards/IBasicToken.sol similarity index 100% rename from contracts/IBasicToken.sol rename to contracts/Standards/IBasicToken.sol diff --git a/contracts/Standards/IERC20Allowance.sol b/contracts/Standards/IERC20Allowance.sol new file mode 100644 index 00000000..bf26a4d0 --- /dev/null +++ b/contracts/Standards/IERC20Allowance.sol @@ -0,0 +1,49 @@ +pragma solidity ^0.4.13; + + +// is IBasicToken +interface IERC20Allowance { + + /// @dev This function makes it easy to read the `allowed[]` map + /// @param _owner The address of the account that owns the token + /// @param _spender The address of the account able to transfer the tokens + /// @return Amount of remaining tokens of _owner that _spender is allowed + /// to spend + function allowance(address _owner, address _spender) + public + constant + returns (uint256 remaining); + + /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on + /// its behalf. This is a modified version of the ERC20 approve function + /// to be a little bit safer + /// @param _spender The address of the account able to transfer the tokens + /// @param _amount The amount of tokens to be approved for transfer + /// @return True if the approval was successful + function approve(address _spender, uint256 _amount) + public + returns (bool success); + + /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on + /// its behalf, and then a function is triggered in the contract that is + /// being approved, `_spender`. This allows users to use their tokens to + /// interact with contracts in one function call instead of two + /// @param _spender The address of the contract able to transfer the tokens + /// @param _amount The amount of tokens to be approved for transfer + /// @return True if the function call was successful + function approveAndCall(address _spender, uint256 _amount, bytes _extraData) + public + returns (bool success); + + + /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it + /// is approved by `_from` + /// @param _from The address holding the tokens being transferred + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return True if the transfer was successful + function transferFrom(address _from, address _to, uint256 _amount) + public + returns (bool success); + +} diff --git a/contracts/IERC20Token.sol b/contracts/Standards/IERC20Token.sol similarity index 98% rename from contracts/IERC20Token.sol rename to contracts/Standards/IERC20Token.sol index 9d12bcaf..8b55d4e7 100644 --- a/contracts/IERC20Token.sol +++ b/contracts/Standards/IERC20Token.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.13; -// is IBasicToken +// is IBasicToken, IERC20Allowance interface IERC20Token { //////////////// diff --git a/contracts/ISnapshotToken.sol b/contracts/Standards/ISnapshotToken.sol similarity index 100% rename from contracts/ISnapshotToken.sol rename to contracts/Standards/ISnapshotToken.sol diff --git a/contracts/ISnapshotTokenParent.sol b/contracts/Standards/ISnapshotTokenParent.sol similarity index 100% rename from contracts/ISnapshotTokenParent.sol rename to contracts/Standards/ISnapshotTokenParent.sol diff --git a/contracts/Snapshot/ISnapshotable.sol b/contracts/Standards/ISnapshotable.sol similarity index 100% rename from contracts/Snapshot/ISnapshotable.sol rename to contracts/Standards/ISnapshotable.sol From ff5bca9d3919856ddac31386a8922268fbeba25e Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 13:47:26 +0200 Subject: [PATCH 24/40] Remove factory and clone --- contracts/MiniMeToken.sol | 54 -------------------------------- contracts/MiniMeTokenFactory.sol | 47 --------------------------- 2 files changed, 101 deletions(-) delete mode 100644 contracts/MiniMeTokenFactory.sol diff --git a/contracts/MiniMeToken.sol b/contracts/MiniMeToken.sol index 27b13e12..7305ef6f 100644 --- a/contracts/MiniMeToken.sol +++ b/contracts/MiniMeToken.sol @@ -7,7 +7,6 @@ import './Helpers/Helpers.sol'; import './Helpers/SnapshotToken.sol'; import './Helpers/TokenInfo.sol'; import './ITokenController.sol'; -import './MiniMeTokenFactory.sol'; import './Snapshot/DailyAndSnapshotable.sol'; import './Standards/IApproveAndCallFallback.sol'; import './Standards/IERC20Token.sol'; @@ -61,15 +60,6 @@ contract MiniMeToken is // Flag that determines if the token is transferable or not. bool public transfersEnabled; - // The factory used to create new clone tokens - MiniMeTokenFactory public tokenFactory; - -//////////////// -// Events -//////////////// - - event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock); - //////////////// // Constructor //////////////// @@ -88,7 +78,6 @@ contract MiniMeToken is /// @param tokenSymbol Token Symbol for the new token /// @param _transfersEnabled If true, tokens will be able to be transferred function MiniMeToken( - address _tokenFactory, ISnapshotTokenParent parentToken, uint parentSnapshot, string tokenName, @@ -103,7 +92,6 @@ contract MiniMeToken is Controlled() ControllerClaims() { - tokenFactory = MiniMeTokenFactory(_tokenFactory); transfersEnabled = _transfersEnabled; } @@ -183,47 +171,6 @@ contract MiniMeToken is return true; } -//////////////// -// Clone Token Method -//////////////// - - /// @notice Creates a new clone token with the initial distribution being - /// this token at `_snapshotBlock` - /// @param _cloneTokenName Name of the clone token - /// @param _cloneDecimalUnits Number of decimals of the smallest unit - /// @param _cloneTokenSymbol Symbol of the clone token - /// @param _snapshotBlock Block when the distribution of the parent token is - /// copied to set the initial distribution of the new clone token; - /// if the block is zero than the actual block, the current block is used - /// @param _transfersEnabled True if transfers are allowed in the clone - /// @return The address of the new MiniMeToken Contract - function createCloneToken( - string _cloneTokenName, - uint8 _cloneDecimalUnits, - string _cloneTokenSymbol, - uint _snapshotBlock, - bool _transfersEnabled - ) - public - returns(address) - { - if (_snapshotBlock == 0) _snapshotBlock = block.number; - MiniMeToken cloneToken = tokenFactory.createCloneToken( - this, - _snapshotBlock, - _cloneTokenName, - _cloneDecimalUnits, - _cloneTokenSymbol, - _transfersEnabled - ); - - cloneToken.changeController(ITokenController(msg.sender)); - - // An event to make the token easy to find on the blockchain - NewCloneToken(address(cloneToken), _snapshotBlock); - return address(cloneToken); - } - //////////////// // Enable tokens transfers //////////////// @@ -237,7 +184,6 @@ contract MiniMeToken is transfersEnabled = _transfersEnabled; } - //////////////// // Generate and destroy tokens //////////////// diff --git a/contracts/MiniMeTokenFactory.sol b/contracts/MiniMeTokenFactory.sol deleted file mode 100644 index 3fb8f85e..00000000 --- a/contracts/MiniMeTokenFactory.sol +++ /dev/null @@ -1,47 +0,0 @@ -pragma solidity ^0.4.13; - -import './Standards/ISnapshotTokenParent.sol'; -import './ITokenController.sol'; -import './MiniMeToken.sol'; - -//////////////// -// MiniMeTokenFactory -//////////////// - -/// @dev This contract is used to generate clone contracts from a contract. -/// In solidity this is the way to create a contract from a contract of the -/// same class -contract MiniMeTokenFactory { - - /// @notice Update the DApp by creating a new token with new functionalities - /// the msg.sender becomes the controller of this clone token - /// @param _parentToken Address of the token being cloned - /// @param _snapshot Block of the parent token that will - /// determine the initial distribution of the clone token - /// @param _tokenName Name of the new token - /// @param _decimalUnits Number of decimals of the new token - /// @param _tokenSymbol Token Symbol for the new token - /// @param _transfersEnabled If true, tokens will be able to be transferred - /// @return The address of the new token contract - function createCloneToken( - ISnapshotTokenParent _parentToken, - uint _snapshot, - string _tokenName, - uint8 _decimalUnits, - string _tokenSymbol, - bool _transfersEnabled - ) returns (MiniMeToken) { - MiniMeToken newToken = new MiniMeToken( - this, - _parentToken, - _snapshot, - _tokenName, - _decimalUnits, - _tokenSymbol, - _transfersEnabled - ); - - newToken.changeController(ITokenController(msg.sender)); - return newToken; - } -} From c56eb859f343a03df92d732314e562107f3ad059 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 13:47:48 +0200 Subject: [PATCH 25/40] remove build files from source folder --- contracts/MiniMeToken.sol.js | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 contracts/MiniMeToken.sol.js diff --git a/contracts/MiniMeToken.sol.js b/contracts/MiniMeToken.sol.js deleted file mode 100644 index c95a7c46..00000000 --- a/contracts/MiniMeToken.sol.js +++ /dev/null @@ -1,12 +0,0 @@ -/* This is an autogenerated file. DO NOT EDIT MANUALLY */ - -exports.ApproveAndCallFallBackAbi = [{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_token","type":"address"},{"name":"_data","type":"bytes"}],"name":"receiveApproval","outputs":[],"payable":false,"type":"function"}]; -exports.ApproveAndCallFallBackByteCode = "0x"; -exports.ControlledAbi = [{"constant":false,"inputs":[{"name":"_newController","type":"address"}],"name":"changeController","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"controller","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"}]; -exports.ControlledByteCode = "0x6060604052341561000f57600080fd5b5b60008054600160a060020a03191633600160a060020a03161790555b5b61015c8061003c6000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416633cebb8238114610048578063f77c479114610076575b600080fd5b341561005357600080fd5b61007473ffffffffffffffffffffffffffffffffffffffff600435166100b2565b005b341561008157600080fd5b610089610114565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6000543373ffffffffffffffffffffffffffffffffffffffff9081169116146100da57600080fd5b6000805473ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff83161790555b5b50565b60005473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a723058203f3045b685137a5d9d154e3daf1770e03174caa4eafc08998d51f50d5015a1e00029"; -exports.MiniMeTokenAbi = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"creationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newController","type":"address"}],"name":"changeController","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_blockNumber","type":"uint256"}],"name":"balanceOfAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_cloneTokenName","type":"string"},{"name":"_cloneDecimalUnits","type":"uint8"},{"name":"_cloneTokenSymbol","type":"string"},{"name":"_snapshotBlock","type":"uint256"},{"name":"_transfersEnabled","type":"bool"}],"name":"createCloneToken","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"parentToken","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_amount","type":"uint256"}],"name":"generateTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_blockNumber","type":"uint256"}],"name":"totalSupplyAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"transfersEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"parentSnapShotBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_amount","type":"uint256"}],"name":"destroyTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"claimTokens","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"tokenFactory","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_transfersEnabled","type":"bool"}],"name":"enableTransfers","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"controller","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"inputs":[{"name":"_tokenFactory","type":"address"},{"name":"_parentToken","type":"address"},{"name":"_parentSnapShotBlock","type":"uint256"},{"name":"_tokenName","type":"string"},{"name":"_decimalUnits","type":"uint8"},{"name":"_tokenSymbol","type":"string"},{"name":"_transfersEnabled","type":"bool"}],"payable":false,"type":"constructor"},{"payable":true,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_token","type":"address"},{"indexed":true,"name":"_controller","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"ClaimedTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cloneToken","type":"address"},{"indexed":false,"name":"_snapshotBlock","type":"uint256"}],"name":"NewCloneToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Approval","type":"event"}]; -exports.MiniMeTokenByteCode = "0x606060405260408051908101604052600781527f4d4d545f302e3100000000000000000000000000000000000000000000000000602082015260049080516200004d9291602001906200015c565b5034156200005a57600080fd5b60405162001d6038038062001d6083398101604052808051919060200180519190602001805191906020018051820191906020018051919060200180518201919060200180519150505b5b60008054600160a060020a03191633600160a060020a03161790555b600b805461010060a860020a031916610100600160a060020a038a16021790556001848051620000f69291602001906200015c565b506002805460ff191660ff851617905560038280516200011b9291602001906200015c565b5060058054600160a060020a031916600160a060020a0388161790556006859055600b805460ff1916821515179055436007555b5050505050505062000206565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200019f57805160ff1916838001178555620001cf565b82800160010185558215620001cf579182015b82811115620001cf578251825591602001919060010190620001b2565b5b50620001de929150620001e2565b5090565b6200020391905b80821115620001de5760008155600101620001e9565b5090565b90565b611b4a80620002166000396000f3006060604052361561012d5763ffffffff60e060020a60003504166306fdde0381146101d9578063095ea7b314610264578063176345141461029a57806318160ddd146102bf57806323b872dd146102e4578063313ce567146103205780633cebb823146103495780634ee2cd7e1461036a57806354fd4d501461039e5780636638c0871461042957806370a08231146104ed57806380a540011461051e578063827f32c01461054d57806395d89b4114610583578063981b24d01461060e578063a9059cbb14610636578063bef97c871461066c578063c5bcc4f114610693578063cae9ca51146106b8578063d3ce77fe14610731578063dd62ed3e14610767578063df8de3e71461079e578063e77772fe146107bf578063f41e60c5146107ee578063f77c479114610808575b6101d75b60005461014690600160a060020a0316610837565b151561015157600080fd5b60008054600160a060020a03169063f48c305490349033906040516020015260405160e060020a63ffffffff8516028152600160a060020a0390911660048201526024016020604051808303818588803b15156101ad57600080fd5b6125ee5a03f115156101be57600080fd5b505050506040518051905015156101d457600080fd5b5b565b005b34156101e457600080fd5b6101ec610864565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156102295780820151818401525b602001610210565b50505050905090810190601f1680156102565780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561026f57600080fd5b610286600160a060020a0360043516602435610902565b604051901515815260200160405180910390f35b34156102a557600080fd5b6102ad610a6c565b60405190815260200160405180910390f35b34156102ca57600080fd5b6102ad610a72565b60405190815260200160405180910390f35b34156102ef57600080fd5b610286600160a060020a0360043581169060243516604435610a83565b604051901515815260200160405180910390f35b341561032b57600080fd5b610333610b25565b60405160ff909116815260200160405180910390f35b341561035457600080fd5b6101d7600160a060020a0360043516610b2e565b005b341561037557600080fd5b6102ad600160a060020a0360043516602435610b76565b60405190815260200160405180910390f35b34156103a957600080fd5b6101ec610cbc565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156102295780820151818401525b602001610210565b50505050905090810190601f1680156102565780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561043457600080fd5b6104d160046024813581810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284378201915050505050509190803560ff1690602001909190803590602001908201803590602001908080601f016020809104026020016040519081016040528181529291906020840183838082843750949650508435946020013515159350610d5a92505050565b604051600160a060020a03909116815260200160405180910390f35b34156104f857600080fd5b6102ad600160a060020a0360043516610f8a565b60405190815260200160405180910390f35b341561052957600080fd5b6104d1610f9e565b604051600160a060020a03909116815260200160405180910390f35b341561055857600080fd5b610286600160a060020a0360043516602435610fad565b604051901515815260200160405180910390f35b341561058e57600080fd5b6101ec611080565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156102295780820151818401525b602001610210565b50505050905090810190601f1680156102565780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561061957600080fd5b6102ad60043561111e565b60405190815260200160405180910390f35b341561064157600080fd5b610286600160a060020a0360043516602435611216565b604051901515815260200160405180910390f35b341561067757600080fd5b61028661123e565b604051901515815260200160405180910390f35b341561069e57600080fd5b6102ad611247565b60405190815260200160405180910390f35b34156106c357600080fd5b61028660048035600160a060020a03169060248035919060649060443590810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965061124d95505050505050565b604051901515815260200160405180910390f35b341561073c57600080fd5b610286600160a060020a036004351660243561136b565b604051901515815260200160405180910390f35b341561077257600080fd5b6102ad600160a060020a0360043581169060243516611438565b60405190815260200160405180910390f35b34156107a957600080fd5b6101d7600160a060020a0360043516611465565b005b34156107ca57600080fd5b6104d1611612565b604051600160a060020a03909116815260200160405180910390f35b34156107f957600080fd5b6101d76004351515611626565b005b341561081357600080fd5b6104d1611654565b604051600160a060020a03909116815260200160405180910390f35b600080600160a060020a0383161515610853576000915061085e565b823b90506000811191505b50919050565b60018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108fa5780601f106108cf576101008083540402835291602001916108fa565b820191906000526020600020905b8154815290600101906020018083116108dd57829003601f168201915b505050505081565b600b5460009060ff16151561091657600080fd5b8115806109465750600160a060020a03338116600090815260096020908152604080832093871683529290522054155b151561095157600080fd5b60005461096690600160a060020a0316610837565b15610a015760008054600160a060020a03169063da682aeb903390869086906040516020015260405160e060020a63ffffffff8616028152600160a060020a0393841660048201529190921660248201526044810191909152606401602060405180830381600087803b15156109db57600080fd5b6102c65a03f115156109ec57600080fd5b505050604051805190501515610a0157600080fd5b5b600160a060020a03338116600081815260096020908152604080832094881680845294909152908190208590557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259085905190815260200160405180910390a35060015b92915050565b60075481565b6000610a7d4361111e565b90505b90565b6000805433600160a060020a03908116911614610b1057600b5460ff161515610aab57600080fd5b600160a060020a038085166000908152600960209081526040808320339094168352929052205482901015610ae257506000610b1e565b600160a060020a03808516600090815260096020908152604080832033909416835292905220805483900390555b610b1b848484611663565b90505b9392505050565b60025460ff1681565b60005433600160a060020a03908116911614610b4957600080fd5b6000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b600160a060020a0382166000908152600860205260408120541580610bd65750600160a060020a038316600090815260086020526040812080548492908110610bbb57fe5b906000526020600020900160005b50546001608060020a0316115b15610c8c57600554600160a060020a031615610c7f57600554600654600160a060020a0390911690634ee2cd7e908590610c11908690611842565b60006040516020015260405160e060020a63ffffffff8516028152600160a060020a0390921660048301526024820152604401602060405180830381600087803b1515610c5d57600080fd5b6102c65a03f11515610c6e57600080fd5b505050604051805190509050610a66565b506000610a66565b610a66565b600160a060020a0383166000908152600860205260409020610cae908361185c565b9050610a66565b5b92915050565b60048054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108fa5780601f106108cf576101008083540402835291602001916108fa565b820191906000526020600020905b8154815290600101906020018083116108dd57829003601f168201915b505050505081565b600080831515610d68574393505b600b546101009004600160a060020a0316635b7b72c130868a8a8a8960006040516020015260405160e060020a63ffffffff8916028152600160a060020a038716600482019081526024820187905260ff8516606483015282151560a483015260c0604483019081529091608481019060c40187818151815260200191508051906020019080838360005b83811015610e0c5780820151818401525b602001610df3565b50505050905090810190601f168015610e395780820380516001836020036101000a031916815260200191505b50838103825285818151815260200191508051906020019080838360005b83811015610e705780820151818401525b602001610e57565b50505050905090810190601f168015610e9d5780820380516001836020036101000a031916815260200191505b5098505050505050505050602060405180830381600087803b1515610ec157600080fd5b6102c65a03f11515610ed257600080fd5b5050506040518051915050600160a060020a038116633cebb8233360405160e060020a63ffffffff8416028152600160a060020a039091166004820152602401600060405180830381600087803b1515610f2b57600080fd5b6102c65a03f11515610f3c57600080fd5b50505080600160a060020a03167f086c875b377f900b07ce03575813022f05dd10ed7640b5282cf6d3c3fc352ade8560405190815260200160405180910390a28091505b5095945050505050565b6000610f968243610b76565b90505b919050565b600554600160a060020a031681565b600080548190819033600160a060020a03908116911614610fcd57600080fd5b610fd5610a72565b915083820182901015610fe757600080fd5b610ff085610f8a565b90508381018190101561100257600080fd5b61100f600a8584016119d0565b600160a060020a0385166000908152600860205260409020611033908286016119d0565b84600160a060020a031660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8660405190815260200160405180910390a3600192505b5b505092915050565b60038054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108fa5780601f106108cf576101008083540402835291602001916108fa565b820191906000526020600020905b8154815290600101906020018083116108dd57829003601f168201915b505050505081565b600a546000901580611157575081600a600081548110151561113c57fe5b906000526020600020900160005b50546001608060020a0316115b156111fe57600554600160a060020a0316156111f157600554600654600160a060020a039091169063981b24d090611190908590611842565b60006040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156111cf57600080fd5b6102c65a03f115156111e057600080fd5b505050604051805190509050610f99565b506000610f99565b610f99565b611209600a8361185c565b9050610f99565b5b919050565b600b5460009060ff16151561122a57600080fd5b611235338484611663565b90505b92915050565b600b5460ff1681565b60065481565b60006112598484610902565b151561126457600080fd5b83600160a060020a0316638f4ffcb1338530866040518563ffffffff1660e060020a0281526004018085600160a060020a0316600160a060020a0316815260200184815260200183600160a060020a0316600160a060020a0316815260200180602001828103825283818151815260200191508051906020019080838360005b838110156112fd5780820151818401525b6020016112e4565b50505050905090810190601f16801561132a5780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b151561134b57600080fd5b6102c65a03f1151561135c57600080fd5b505050600190505b9392505050565b600080548190819033600160a060020a0390811691161461138b57600080fd5b611393610a72565b9150838210156113a257600080fd5b6113ab85610f8a565b9050838110156113ba57600080fd5b6113c7600a8584036119d0565b600160a060020a03851660009081526008602052604090206113eb908583036119d0565b600085600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8660405190815260200160405180910390a3600192505b5b505092915050565b600160a060020a038083166000908152600960209081526040808320938516835292905220545b92915050565b60008054819033600160a060020a0390811691161461148357600080fd5b600160a060020a03831615156114d157600054600160a060020a039081169030163180156108fc0290604051600060405180830381858888f1935050505015156114cc57600080fd5b61160c565b82915081600160a060020a03166370a082313060006040516020015260405160e060020a63ffffffff8416028152600160a060020a039091166004820152602401602060405180830381600087803b151561152b57600080fd5b6102c65a03f1151561153c57600080fd5b505050604051805160008054919350600160a060020a03808616935063a9059cbb92169084906040516020015260405160e060020a63ffffffff8516028152600160a060020a0390921660048301526024820152604401602060405180830381600087803b15156115ac57600080fd5b6102c65a03f115156115bd57600080fd5b50505060405180515050600054600160a060020a039081169084167ff931edb47c50b4b4104c187b5814a9aef5f709e17e2ecf9617e860cacade929c8360405190815260200160405180910390a35b5b505050565b600b546101009004600160a060020a031681565b60005433600160a060020a0390811691161461164157600080fd5b600b805460ff19168215151790555b5b50565b600054600160a060020a031681565b600080808315156116775760019250611839565b60065443901061168657600080fd5b600160a060020a038516158015906116b0575030600160a060020a031685600160a060020a031614155b15156116bb57600080fd5b6116c58643610b76565b9150838210156116d85760009250611839565b6000546116ed90600160a060020a0316610837565b156117885760008054600160a060020a031690634a393149908890889088906040516020015260405160e060020a63ffffffff8616028152600160a060020a0393841660048201529190921660248201526044810191909152606401602060405180830381600087803b151561176257600080fd5b6102c65a03f1151561177357600080fd5b50505060405180519050151561178857600080fd5b5b600160a060020a03861660009081526008602052604090206117ad908584036119d0565b6117b78543610b76565b9050838101819010156117c957600080fd5b600160a060020a03851660009081526008602052604090206117ed908286016119d0565b84600160a060020a031686600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8660405190815260200160405180910390a3600192505b50509392505050565b60008183106118515781611235565b825b90505b92915050565b60008060008085805490506000141561187857600093506119c7565b85548690600019810190811061188a57fe5b906000526020600020900160005b50546001608060020a031685106118ef578554869060001981019081106118bb57fe5b906000526020600020900160005b505470010000000000000000000000000000000090046001608060020a031693506119c7565b8560008154811015156118fe57fe5b906000526020600020900160005b50546001608060020a031685101561192757600093506119c7565b8554600093506000190191505b828211156119895760026001838501015b04905084868281548110151561195757fe5b906000526020600020900160005b50546001608060020a03161161197d57809250611984565b6001810391505b611934565b858381548110151561199757fe5b906000526020600020900160005b505470010000000000000000000000000000000090046001608060020a031693505b50505092915050565b815460009081901580611a0d575083544390859060001981019081106119f257fe5b906000526020600020900160005b50546001608060020a0316105b15611a835783548490611a238260018301611ad3565b81548110611a2d57fe5b906000526020600020900160005b5080546001608060020a03858116700100000000000000000000000000000000024382166fffffffffffffffffffffffffffffffff1990931692909217161781559150611acc565b835484906000198101908110611a9557fe5b906000526020600020900160005b5080546001608060020a0380861670010000000000000000000000000000000002911617815590505b5b50505050565b81548183558181151161160c5760008381526020902061160c918101908301611afd565b5b505050565b610a8091905b80821115611b175760008155600101611b03565b5090565b905600a165627a7a72305820a65b405eae3c826d2caab3069766b9c4b6f8bf64ce0b2eca671930e1a3736c480029"; -exports.MiniMeTokenFactoryAbi = [{"constant":false,"inputs":[{"name":"_parentToken","type":"address"},{"name":"_snapshotBlock","type":"uint256"},{"name":"_tokenName","type":"string"},{"name":"_decimalUnits","type":"uint8"},{"name":"_tokenSymbol","type":"string"},{"name":"_transfersEnabled","type":"bool"}],"name":"createCloneToken","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}]; -exports.MiniMeTokenFactoryByteCode = "0x6060604052341561000f57600080fd5b5b6120ac8061001f6000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416635b7b72c1811461003d575b600080fd5b341561004857600080fd5b6101016004803573ffffffffffffffffffffffffffffffffffffffff169060248035919060649060443590810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284378201915050505050509190803560ff1690602001909190803590602001908201803590602001908080601f01602080910402602001604051908101604052818152929190602084018383808284375094965050505091351515915061012a9050565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6000803088888888888861013c610310565b73ffffffffffffffffffffffffffffffffffffffff8089168252871660208201526040810186905260ff8416608082015281151560c082015260e0606082018181529060a0830190830187818151815260200191508051906020019080838360005b838110156101b75780820151818401525b60200161019e565b50505050905090810190601f1680156101e45780820380516001836020036101000a031916815260200191505b50838103825285818151815260200191508051906020019080838360005b8381101561021b5780820151818401525b602001610202565b50505050905090810190601f1680156102485780820380516001836020036101000a031916815260200191505b509950505050505050505050604051809103906000f080151561026a57600080fd5b90508073ffffffffffffffffffffffffffffffffffffffff16633cebb823336040517c010000000000000000000000000000000000000000000000000000000063ffffffff841602815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401600060405180830381600087803b15156102ed57600080fd5b6102c65a03f115156102fe57600080fd5b5050508091505b509695505050505050565b604051611d6080610321833901905600606060405260408051908101604052600781527f4d4d545f302e3100000000000000000000000000000000000000000000000000602082015260049080516200004d9291602001906200015c565b5034156200005a57600080fd5b60405162001d6038038062001d6083398101604052808051919060200180519190602001805191906020018051820191906020018051919060200180518201919060200180519150505b5b60008054600160a060020a03191633600160a060020a03161790555b600b805461010060a860020a031916610100600160a060020a038a16021790556001848051620000f69291602001906200015c565b506002805460ff191660ff851617905560038280516200011b9291602001906200015c565b5060058054600160a060020a031916600160a060020a0388161790556006859055600b805460ff1916821515179055436007555b5050505050505062000206565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200019f57805160ff1916838001178555620001cf565b82800160010185558215620001cf579182015b82811115620001cf578251825591602001919060010190620001b2565b5b50620001de929150620001e2565b5090565b6200020391905b80821115620001de5760008155600101620001e9565b5090565b90565b611b4a80620002166000396000f3006060604052361561012d5763ffffffff60e060020a60003504166306fdde0381146101d9578063095ea7b314610264578063176345141461029a57806318160ddd146102bf57806323b872dd146102e4578063313ce567146103205780633cebb823146103495780634ee2cd7e1461036a57806354fd4d501461039e5780636638c0871461042957806370a08231146104ed57806380a540011461051e578063827f32c01461054d57806395d89b4114610583578063981b24d01461060e578063a9059cbb14610636578063bef97c871461066c578063c5bcc4f114610693578063cae9ca51146106b8578063d3ce77fe14610731578063dd62ed3e14610767578063df8de3e71461079e578063e77772fe146107bf578063f41e60c5146107ee578063f77c479114610808575b6101d75b60005461014690600160a060020a0316610837565b151561015157600080fd5b60008054600160a060020a03169063f48c305490349033906040516020015260405160e060020a63ffffffff8516028152600160a060020a0390911660048201526024016020604051808303818588803b15156101ad57600080fd5b6125ee5a03f115156101be57600080fd5b505050506040518051905015156101d457600080fd5b5b565b005b34156101e457600080fd5b6101ec610864565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156102295780820151818401525b602001610210565b50505050905090810190601f1680156102565780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561026f57600080fd5b610286600160a060020a0360043516602435610902565b604051901515815260200160405180910390f35b34156102a557600080fd5b6102ad610a6c565b60405190815260200160405180910390f35b34156102ca57600080fd5b6102ad610a72565b60405190815260200160405180910390f35b34156102ef57600080fd5b610286600160a060020a0360043581169060243516604435610a83565b604051901515815260200160405180910390f35b341561032b57600080fd5b610333610b25565b60405160ff909116815260200160405180910390f35b341561035457600080fd5b6101d7600160a060020a0360043516610b2e565b005b341561037557600080fd5b6102ad600160a060020a0360043516602435610b76565b60405190815260200160405180910390f35b34156103a957600080fd5b6101ec610cbc565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156102295780820151818401525b602001610210565b50505050905090810190601f1680156102565780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561043457600080fd5b6104d160046024813581810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284378201915050505050509190803560ff1690602001909190803590602001908201803590602001908080601f016020809104026020016040519081016040528181529291906020840183838082843750949650508435946020013515159350610d5a92505050565b604051600160a060020a03909116815260200160405180910390f35b34156104f857600080fd5b6102ad600160a060020a0360043516610f8a565b60405190815260200160405180910390f35b341561052957600080fd5b6104d1610f9e565b604051600160a060020a03909116815260200160405180910390f35b341561055857600080fd5b610286600160a060020a0360043516602435610fad565b604051901515815260200160405180910390f35b341561058e57600080fd5b6101ec611080565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156102295780820151818401525b602001610210565b50505050905090810190601f1680156102565780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561061957600080fd5b6102ad60043561111e565b60405190815260200160405180910390f35b341561064157600080fd5b610286600160a060020a0360043516602435611216565b604051901515815260200160405180910390f35b341561067757600080fd5b61028661123e565b604051901515815260200160405180910390f35b341561069e57600080fd5b6102ad611247565b60405190815260200160405180910390f35b34156106c357600080fd5b61028660048035600160a060020a03169060248035919060649060443590810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965061124d95505050505050565b604051901515815260200160405180910390f35b341561073c57600080fd5b610286600160a060020a036004351660243561136b565b604051901515815260200160405180910390f35b341561077257600080fd5b6102ad600160a060020a0360043581169060243516611438565b60405190815260200160405180910390f35b34156107a957600080fd5b6101d7600160a060020a0360043516611465565b005b34156107ca57600080fd5b6104d1611612565b604051600160a060020a03909116815260200160405180910390f35b34156107f957600080fd5b6101d76004351515611626565b005b341561081357600080fd5b6104d1611654565b604051600160a060020a03909116815260200160405180910390f35b600080600160a060020a0383161515610853576000915061085e565b823b90506000811191505b50919050565b60018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108fa5780601f106108cf576101008083540402835291602001916108fa565b820191906000526020600020905b8154815290600101906020018083116108dd57829003601f168201915b505050505081565b600b5460009060ff16151561091657600080fd5b8115806109465750600160a060020a03338116600090815260096020908152604080832093871683529290522054155b151561095157600080fd5b60005461096690600160a060020a0316610837565b15610a015760008054600160a060020a03169063da682aeb903390869086906040516020015260405160e060020a63ffffffff8616028152600160a060020a0393841660048201529190921660248201526044810191909152606401602060405180830381600087803b15156109db57600080fd5b6102c65a03f115156109ec57600080fd5b505050604051805190501515610a0157600080fd5b5b600160a060020a03338116600081815260096020908152604080832094881680845294909152908190208590557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259085905190815260200160405180910390a35060015b92915050565b60075481565b6000610a7d4361111e565b90505b90565b6000805433600160a060020a03908116911614610b1057600b5460ff161515610aab57600080fd5b600160a060020a038085166000908152600960209081526040808320339094168352929052205482901015610ae257506000610b1e565b600160a060020a03808516600090815260096020908152604080832033909416835292905220805483900390555b610b1b848484611663565b90505b9392505050565b60025460ff1681565b60005433600160a060020a03908116911614610b4957600080fd5b6000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b600160a060020a0382166000908152600860205260408120541580610bd65750600160a060020a038316600090815260086020526040812080548492908110610bbb57fe5b906000526020600020900160005b50546001608060020a0316115b15610c8c57600554600160a060020a031615610c7f57600554600654600160a060020a0390911690634ee2cd7e908590610c11908690611842565b60006040516020015260405160e060020a63ffffffff8516028152600160a060020a0390921660048301526024820152604401602060405180830381600087803b1515610c5d57600080fd5b6102c65a03f11515610c6e57600080fd5b505050604051805190509050610a66565b506000610a66565b610a66565b600160a060020a0383166000908152600860205260409020610cae908361185c565b9050610a66565b5b92915050565b60048054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108fa5780601f106108cf576101008083540402835291602001916108fa565b820191906000526020600020905b8154815290600101906020018083116108dd57829003601f168201915b505050505081565b600080831515610d68574393505b600b546101009004600160a060020a0316635b7b72c130868a8a8a8960006040516020015260405160e060020a63ffffffff8916028152600160a060020a038716600482019081526024820187905260ff8516606483015282151560a483015260c0604483019081529091608481019060c40187818151815260200191508051906020019080838360005b83811015610e0c5780820151818401525b602001610df3565b50505050905090810190601f168015610e395780820380516001836020036101000a031916815260200191505b50838103825285818151815260200191508051906020019080838360005b83811015610e705780820151818401525b602001610e57565b50505050905090810190601f168015610e9d5780820380516001836020036101000a031916815260200191505b5098505050505050505050602060405180830381600087803b1515610ec157600080fd5b6102c65a03f11515610ed257600080fd5b5050506040518051915050600160a060020a038116633cebb8233360405160e060020a63ffffffff8416028152600160a060020a039091166004820152602401600060405180830381600087803b1515610f2b57600080fd5b6102c65a03f11515610f3c57600080fd5b50505080600160a060020a03167f086c875b377f900b07ce03575813022f05dd10ed7640b5282cf6d3c3fc352ade8560405190815260200160405180910390a28091505b5095945050505050565b6000610f968243610b76565b90505b919050565b600554600160a060020a031681565b600080548190819033600160a060020a03908116911614610fcd57600080fd5b610fd5610a72565b915083820182901015610fe757600080fd5b610ff085610f8a565b90508381018190101561100257600080fd5b61100f600a8584016119d0565b600160a060020a0385166000908152600860205260409020611033908286016119d0565b84600160a060020a031660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8660405190815260200160405180910390a3600192505b5b505092915050565b60038054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108fa5780601f106108cf576101008083540402835291602001916108fa565b820191906000526020600020905b8154815290600101906020018083116108dd57829003601f168201915b505050505081565b600a546000901580611157575081600a600081548110151561113c57fe5b906000526020600020900160005b50546001608060020a0316115b156111fe57600554600160a060020a0316156111f157600554600654600160a060020a039091169063981b24d090611190908590611842565b60006040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156111cf57600080fd5b6102c65a03f115156111e057600080fd5b505050604051805190509050610f99565b506000610f99565b610f99565b611209600a8361185c565b9050610f99565b5b919050565b600b5460009060ff16151561122a57600080fd5b611235338484611663565b90505b92915050565b600b5460ff1681565b60065481565b60006112598484610902565b151561126457600080fd5b83600160a060020a0316638f4ffcb1338530866040518563ffffffff1660e060020a0281526004018085600160a060020a0316600160a060020a0316815260200184815260200183600160a060020a0316600160a060020a0316815260200180602001828103825283818151815260200191508051906020019080838360005b838110156112fd5780820151818401525b6020016112e4565b50505050905090810190601f16801561132a5780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b151561134b57600080fd5b6102c65a03f1151561135c57600080fd5b505050600190505b9392505050565b600080548190819033600160a060020a0390811691161461138b57600080fd5b611393610a72565b9150838210156113a257600080fd5b6113ab85610f8a565b9050838110156113ba57600080fd5b6113c7600a8584036119d0565b600160a060020a03851660009081526008602052604090206113eb908583036119d0565b600085600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8660405190815260200160405180910390a3600192505b5b505092915050565b600160a060020a038083166000908152600960209081526040808320938516835292905220545b92915050565b60008054819033600160a060020a0390811691161461148357600080fd5b600160a060020a03831615156114d157600054600160a060020a039081169030163180156108fc0290604051600060405180830381858888f1935050505015156114cc57600080fd5b61160c565b82915081600160a060020a03166370a082313060006040516020015260405160e060020a63ffffffff8416028152600160a060020a039091166004820152602401602060405180830381600087803b151561152b57600080fd5b6102c65a03f1151561153c57600080fd5b505050604051805160008054919350600160a060020a03808616935063a9059cbb92169084906040516020015260405160e060020a63ffffffff8516028152600160a060020a0390921660048301526024820152604401602060405180830381600087803b15156115ac57600080fd5b6102c65a03f115156115bd57600080fd5b50505060405180515050600054600160a060020a039081169084167ff931edb47c50b4b4104c187b5814a9aef5f709e17e2ecf9617e860cacade929c8360405190815260200160405180910390a35b5b505050565b600b546101009004600160a060020a031681565b60005433600160a060020a0390811691161461164157600080fd5b600b805460ff19168215151790555b5b50565b600054600160a060020a031681565b600080808315156116775760019250611839565b60065443901061168657600080fd5b600160a060020a038516158015906116b0575030600160a060020a031685600160a060020a031614155b15156116bb57600080fd5b6116c58643610b76565b9150838210156116d85760009250611839565b6000546116ed90600160a060020a0316610837565b156117885760008054600160a060020a031690634a393149908890889088906040516020015260405160e060020a63ffffffff8616028152600160a060020a0393841660048201529190921660248201526044810191909152606401602060405180830381600087803b151561176257600080fd5b6102c65a03f1151561177357600080fd5b50505060405180519050151561178857600080fd5b5b600160a060020a03861660009081526008602052604090206117ad908584036119d0565b6117b78543610b76565b9050838101819010156117c957600080fd5b600160a060020a03851660009081526008602052604090206117ed908286016119d0565b84600160a060020a031686600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8660405190815260200160405180910390a3600192505b50509392505050565b60008183106118515781611235565b825b90505b92915050565b60008060008085805490506000141561187857600093506119c7565b85548690600019810190811061188a57fe5b906000526020600020900160005b50546001608060020a031685106118ef578554869060001981019081106118bb57fe5b906000526020600020900160005b505470010000000000000000000000000000000090046001608060020a031693506119c7565b8560008154811015156118fe57fe5b906000526020600020900160005b50546001608060020a031685101561192757600093506119c7565b8554600093506000190191505b828211156119895760026001838501015b04905084868281548110151561195757fe5b906000526020600020900160005b50546001608060020a03161161197d57809250611984565b6001810391505b611934565b858381548110151561199757fe5b906000526020600020900160005b505470010000000000000000000000000000000090046001608060020a031693505b50505092915050565b815460009081901580611a0d575083544390859060001981019081106119f257fe5b906000526020600020900160005b50546001608060020a0316105b15611a835783548490611a238260018301611ad3565b81548110611a2d57fe5b906000526020600020900160005b5080546001608060020a03858116700100000000000000000000000000000000024382166fffffffffffffffffffffffffffffffff1990931692909217161781559150611acc565b835484906000198101908110611a9557fe5b906000526020600020900160005b5080546001608060020a0380861670010000000000000000000000000000000002911617815590505b5b50505050565b81548183558181151161160c5760008381526020902061160c918101908301611afd565b5b505050565b610a8091905b80821115611b175760008155600101611b03565b5090565b905600a165627a7a72305820a65b405eae3c826d2caab3069766b9c4b6f8bf64ce0b2eca671930e1a3736c480029a165627a7a72305820276428d6222c43dee21a55759845b8ade771ea1b6d90ef46fcfff751688a5a690029"; -exports.TokenControllerAbi = [{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"onTransfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"onApprove","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"proxyPayment","outputs":[{"name":"","type":"bool"}],"payable":true,"type":"function"}]; -exports.TokenControllerByteCode = "0x"; From b3df899b78aaa3f3c075e977caced145fbac265c Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Sun, 13 Aug 2017 13:54:35 +0200 Subject: [PATCH 26/40] Add Vote contract --- contracts/Extensions/Vote.sol | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 contracts/Extensions/Vote.sol diff --git a/contracts/Extensions/Vote.sol b/contracts/Extensions/Vote.sol new file mode 100644 index 00000000..3650de44 --- /dev/null +++ b/contracts/Extensions/Vote.sol @@ -0,0 +1,44 @@ +import './ISnapshotToken.sol'; + +// https://en.wikipedia.org/wiki/Comparison_of_electoral_systems + +// https://en.wikipedia.org/wiki/Arrow%27s_impossibility_theorem +// https://en.wikipedia.org/wiki/Gibbard%E2%80%93Satterthwaite_theorem + +// * Votes are public +// * Voting is weighed by amount of tokens owned +// * Votes can be changed +// * + +// Cardinal systems are a natural fit for a token based voting system. +// * https://en.wikipedia.org/wiki/Approval_voting +// * https://en.wikipedia.org/wiki/Majority_judgment +// → https://en.wikipedia.org/wiki/Range_voting + +// TODO: Implement Range voting with: +// * Votes proportional to shares (i.e. one vote per share) +// * Proxy voting: ability to delegate voting power +// * Ability to trade voting power (is this the same as above?) + +// TODO: + +contract Vote { + + ISnapshotToken public constant TOKEN; + uint256 public constant SNAPSHOT; + string[] public constant CHOICES; + + uint256[] totals; + + Vote(ISnapshotToken token, string[] options) + { + TOKEN = token; + SNAPSHOT = token.createSnapshot(); + OPTIONS = options; + } + + function vote(uint256[] votes) + public + { + } +} From c880a68c75858b58998e0e5838a6f8f26cd2cdcf Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 15:03:27 +0200 Subject: [PATCH 27/40] Fix disbursal contract --- contracts/Extensions/Disbursal.sol | 69 +++++++++++------------------- 1 file changed, 26 insertions(+), 43 deletions(-) diff --git a/contracts/Extensions/Disbursal.sol b/contracts/Extensions/Disbursal.sol index f8294da0..75731de5 100644 --- a/contracts/Extensions/Disbursal.sol +++ b/contracts/Extensions/Disbursal.sol @@ -1,9 +1,9 @@ pragma solidity ^0.4.13; -import './ISnapshotToken.sol'; -import './IBasicToken.sol'; -import './IERC20Token.sol'; -import './IApproveAndCallFallback.sol'; +import '../Standards/ISnapshotToken.sol'; +import '../Standards/IBasicToken.sol'; +import '../Standards/IERC20Token.sol'; +import '../Standards/IApproveAndCallFallback.sol'; // TODO: Anyone can create a token and disburse it, but then everyone // needs to pay extra gas for claim(). It is not possible to skip @@ -69,33 +69,20 @@ contract Disbursal is IApproveAndCallFallback { // Public functions //////////////// - function claimable() + function claimables(address beneficiary, uint256 from) public constant - returns (uint256[]) + returns (uint256[100]) { - return claimable(msg.sender); - } - - function claimable(address beneficiary) - public - constant - returns (uint256[]) - { - return claimable(beneficiary, 0, disbursments.length); - } - - function claimable(address beneficiary, uint256 from, uint256 to) - public - constant - returns (uint256[]) - { - require(from <= to); - require(to < disbursments.length); - uint256[] storage result; - for(uint256 i = from; i < to; ++i) { - if(claimable(beneficiary, i)) { - result.push(i); + uint256[100] memory result; + uint j = 0; + for (uint256 i = from; i < disbursments.length; ++i) { + if (claimable(beneficiary, i)) { + result[j] = i; + j += 1; + if (j == 100) { + break; + } } } return result; @@ -185,7 +172,7 @@ contract Disbursal is IApproveAndCallFallback { public { uint256 amount = token.allowance(msg.sender, this); - disburseAllowance(token, msg.sender); + disburseAllowance(token, msg.sender, amount); } function disburseAllowance(IERC20Token token, address from, uint256 amount) @@ -205,7 +192,7 @@ contract Disbursal is IApproveAndCallFallback { public { require(data.length == 0); - disburseAllowance(token, from, amount) + disburseAllowance(token, from, amount); } // TODO: ERC223 style receiver @@ -247,22 +234,18 @@ contract Disbursal is IApproveAndCallFallback { Disbursed(index, token, amount, snapshot, totalShares); } - function mulDiv(uint256 a, uint256 n, uint256 d) + function mulDiv( + uint256 value, + uint256 numerator, + uint256 denominator + ) internal constant returns (uint256) { - require(a < 2**128); - require(d < 2**128); - require(n <= d); - - uint256 s = a * n; - - // Correct rounding - s += n / 2; - - uint256 f = s / d; - - return f; + require(value < 2**128); + require(numerator < 2**128); + require(numerator <= denominator); + return (value * numerator) / denominator; } } From edcb2cdb721ad2fa97fb80d17c817c9e2789768b Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 15:14:40 +0200 Subject: [PATCH 28/40] Fix voting contract --- contracts/Extensions/Vote.sol | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/contracts/Extensions/Vote.sol b/contracts/Extensions/Vote.sol index 3650de44..ca348531 100644 --- a/contracts/Extensions/Vote.sol +++ b/contracts/Extensions/Vote.sol @@ -1,4 +1,6 @@ -import './ISnapshotToken.sol'; +pragma solidity ^0.4.13; + +import '../Standards/ISnapshotToken.sol'; // https://en.wikipedia.org/wiki/Comparison_of_electoral_systems @@ -24,17 +26,30 @@ import './ISnapshotToken.sol'; contract Vote { - ISnapshotToken public constant TOKEN; - uint256 public constant SNAPSHOT; - string[] public constant CHOICES; + ISnapshotToken public TOKEN; + uint256 public SNAPSHOT; + bytes32[] public CHOICE_HASHES; + string[] public choices; uint256[] totals; - Vote(ISnapshotToken token, string[] options) - { + // Note: we use hashes because Solidity currently does not support passing + // string[] as an argument for external functions. + function Vote( + ISnapshotToken token, + bytes32[] choiceHashes + ) { TOKEN = token; SNAPSHOT = token.createSnapshot(); - OPTIONS = options; + CHOICE_HASHES = choiceHashes; + choices.length = CHOICE_HASHES.length; + } + + function initChoice(uint index, string choice) + { + require(index < CHOICE_HASHES.length); + require(keccak256(choice) == CHOICE_HASHES[index]); + choices[index] = choice; } function vote(uint256[] votes) From d8dc7721052d05f53dc1af927c3f3c3e82788467 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 15:35:45 +0200 Subject: [PATCH 29/40] Rename to SnapshotToken --- .../{MiniMeToken.sol => SnapshotToken.sol} | 28 +++--- package.json | 89 +++++++++---------- 2 files changed, 58 insertions(+), 59 deletions(-) rename contracts/{MiniMeToken.sol => SnapshotToken.sol} (93%) diff --git a/contracts/MiniMeToken.sol b/contracts/SnapshotToken.sol similarity index 93% rename from contracts/MiniMeToken.sol rename to contracts/SnapshotToken.sol index 7305ef6f..2d867fd1 100644 --- a/contracts/MiniMeToken.sol +++ b/contracts/SnapshotToken.sol @@ -4,15 +4,18 @@ import './Controlled.sol'; import './ControllerClaims.sol'; import './Helpers/Allowance.sol'; import './Helpers/Helpers.sol'; -import './Helpers/SnapshotToken.sol'; +import './Helpers/MMint.sol'; +import { SnapshotToken as SnapshotTokenBase } from './Helpers/SnapshotToken.sol'; import './Helpers/TokenInfo.sol'; import './ITokenController.sol'; import './Snapshot/DailyAndSnapshotable.sol'; import './Standards/IApproveAndCallFallback.sol'; +import './Standards/ISnapshotToken.sol'; +import './Standards/ISnapshotTokenParent.sol'; import './Standards/IERC20Token.sol'; /* - Copyright 2016, Jordi Baylina + Copyright 2016, Remco Bloemen, Jordi Baylina This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,8 +31,8 @@ import './Standards/IERC20Token.sol'; along with this program. If not, see . */ -/// @title MiniMeToken Contract -/// @author Jordi Baylina +/// @title SnapshotToken Contract +/// @author Remco Bloemen, Jordi Baylina /// @dev This token contract's goal is to make it easy for anyone to clone this /// token using the token distribution at a given block, this will allow DAO's /// and DApps to upgrade their features in a decentralized manner without @@ -43,11 +46,11 @@ import './Standards/IERC20Token.sol'; // Helpers is inherited through SnapshotToken // Consumes the MMint mixin from SnapshotToken -contract MiniMeToken is +contract SnapshotToken is IERC20Token, ISnapshotToken, MMint, - SnapshotToken, + SnapshotTokenBase, DailyAndSnapshotable, Allowance, TokenInfo, @@ -55,7 +58,7 @@ contract MiniMeToken is ControllerClaims { - string private constant VERSION = "MMT_2.0"; + string private constant VERSION = "ST_1.0"; // Flag that determines if the token is transferable or not. bool public transfersEnabled; @@ -65,9 +68,6 @@ contract MiniMeToken is //////////////// /// @notice Constructor to create a MiniMeToken - /// @param _tokenFactory The address of the MiniMeTokenFactory contract that - /// will create the Clone token contracts, the token factory needs to be - /// deployed first /// @param parentToken Address of the parent token, set to 0x0 if it is a /// new token /// @param parentSnapshot Block of the parent token that will @@ -77,7 +77,7 @@ contract MiniMeToken is /// @param decimalUnits Number of decimals of the new token /// @param tokenSymbol Token Symbol for the new token /// @param _transfersEnabled If true, tokens will be able to be transferred - function MiniMeToken( + function SnapshotToken( ISnapshotTokenParent parentToken, uint parentSnapshot, string tokenName, @@ -85,7 +85,7 @@ contract MiniMeToken is string tokenSymbol, bool _transfersEnabled ) - SnapshotToken(parentToken, parentSnapshot) + SnapshotTokenBase(parentToken, parentSnapshot) DailyAndSnapshotable() Allowance() TokenInfo(tokenName, decimalUnits, tokenSymbol, VERSION) @@ -197,7 +197,7 @@ contract MiniMeToken is onlyController returns (bool) { - return SnapshotToken.mGenerateTokens(_owner, _amount); + return SnapshotTokenBase.mGenerateTokens(_owner, _amount); } /// @notice Burns `_amount` tokens from `_owner` @@ -209,7 +209,7 @@ contract MiniMeToken is onlyController returns (bool) { - return SnapshotToken.mDestroyTokens(_owner, _amount); + return SnapshotTokenBase.mDestroyTokens(_owner, _amount); } //////////////// diff --git a/package.json b/package.json index f2c548ee..73f2cb6c 100644 --- a/package.json +++ b/package.json @@ -1,47 +1,46 @@ { - "name": "minimetoken", - "version": "0.1.7", - "description": "MiniMe contract", - "main": "dist/minimetoken.js", - "directories": { - "test": "test" - }, - "scripts": { - "test": "mocha --compilers js:babel-core/register", - "build": "rm -rf dist/* && babel-node js/compile.js && babel js/minimetoken.js -o dist/minimetoken.js" - }, - "repository": { - "type": "git", - "url": "https://github.com/Giveth/minime.git" - }, - "keywords": [ - "dao", - "solidity", - "token", - "charity", - "smart", - "contract", - "minime", - "giveth", - "ethereum" - ], - "author": "Jordi Baylina", - "license": "GPL-3.0", - "bugs": { - "url": "https://github.com/Giveth/minimi/issues" - }, - "homepage": "https://github.com/Giveth/minime", - "dependencies": { - "async": "^2.1.4", - "bignumber.js": "^4.0.0", - "ethconnector": "0.0.24", - "lodash": "^4.17.4", - "runethtx": "0.0.7" - }, - "devDependencies": { - "babel-cli": "^6.22.2", - "babel-plugin-add-module-exports": "^0.2.1", - "babel-preset-es2015": "^6.22.0", - "babel-preset-stage-2": "^6.22.0" - } + "name": "snapshottoken", + "version": "0.1.0", + "description": "SnapshotToken contract", + "directories": { + "test": "test" + }, + "scripts": { + "test": "mocha --compilers js:babel-core/register", + "build": "rm -rf dist/* && babel-node js/compile.js && babel js/minimetoken.js -o dist/minimetoken.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/Neufund/snapshottoken.git" + }, + "keywords": [ + "dao", + "solidity", + "token", + "charity", + "smart", + "contract", + "minime", + "giveth", + "ethereum" + ], + "author": "Remco Bloemen, Jordi Baylina", + "license": "GPL-3.0", + "bugs": { + "url": "https://github.com/Neufund/snapshottoken/issues" + }, + "homepage": "https://github.com/Neufund/snapshottoken", + "dependencies": { + "async": "^2.1.4", + "bignumber.js": "^4.0.0", + "ethconnector": "0.0.24", + "lodash": "^4.17.4", + "runethtx": "0.0.7" + }, + "devDependencies": { + "babel-cli": "^6.22.2", + "babel-plugin-add-module-exports": "^0.2.1", + "babel-preset-es2015": "^6.22.0", + "babel-preset-stage-2": "^6.22.0" + } } From 51e05d036f86ea8572f5d5e2bd9325dea622f055 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 20:32:26 +0200 Subject: [PATCH 30/40] Rename mTransfer --- contracts/Helpers/MMint.sol | 14 ++++++++++++++ contracts/Helpers/SnapshotToken.sol | 4 ++-- contracts/SnapshotToken.sol | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/contracts/Helpers/MMint.sol b/contracts/Helpers/MMint.sol index 2849f93e..3e3dc677 100644 --- a/contracts/Helpers/MMint.sol +++ b/contracts/Helpers/MMint.sol @@ -2,6 +2,20 @@ pragma solidity ^0.4.13; contract MMint { + /// @dev This is the actual transfer function in the token contract, it can + /// only be called by other functions in this contract. + /// @param _from The address holding the tokens being transferred + /// @param _to The address of the recipient + /// @param _amount The amount of tokens to be transferred + /// @return True if the transfer was successful + function mTransfer( + address _from, + address _to, + uint _amount + ) + internal + returns(bool); + /// @notice Generates `_amount` tokens that are assigned to `_owner` /// @param _owner The address that will be assigned the new tokens /// @param _amount The quantity of tokens generated diff --git a/contracts/Helpers/SnapshotToken.sol b/contracts/Helpers/SnapshotToken.sol index 36905a2e..f1d0a4aa 100644 --- a/contracts/Helpers/SnapshotToken.sol +++ b/contracts/Helpers/SnapshotToken.sol @@ -86,7 +86,7 @@ contract SnapshotToken is public returns (bool success) { - return snapshotBaseTransfer(msg.sender, _to, _amount); + return mTransfer(msg.sender, _to, _amount); } //////////////// @@ -152,7 +152,7 @@ contract SnapshotToken is /// @param _to The address of the recipient /// @param _amount The amount of tokens to be transferred /// @return True if the transfer was successful - function snapshotBaseTransfer( + function mTransfer( address _from, address _to, uint _amount diff --git a/contracts/SnapshotToken.sol b/contracts/SnapshotToken.sol index 2d867fd1..b810e97a 100644 --- a/contracts/SnapshotToken.sol +++ b/contracts/SnapshotToken.sol @@ -252,6 +252,6 @@ contract SnapshotToken is require(_to != 0); require(_to != address(this)); - return snapshotBaseTransfer(_from, _to, _amount); + return mTransfer(_from, _to, _amount); } } From 7223df1d1b815df758aee608a9bb6f47ed965047 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 20:33:01 +0200 Subject: [PATCH 31/40] Fix constructor name --- contracts/Snapshot/DailyAndSnapshotable.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/Snapshot/DailyAndSnapshotable.sol b/contracts/Snapshot/DailyAndSnapshotable.sol index ef7a2bf1..252dfeb4 100644 --- a/contracts/Snapshot/DailyAndSnapshotable.sol +++ b/contracts/Snapshot/DailyAndSnapshotable.sol @@ -14,7 +14,7 @@ contract DailyAndSnapshotable is uint256 nextSnapshotId; bool nextSnapshotModified; - function SnapshotDailyHybrid() { + function DailyAndSnapshotable() { uint256 dayBase = 2**128 * (block.timestamp / 1 days); nextSnapshotId = dayBase + 1; nextSnapshotModified = false; From e84d3ccd159fe96e7a4f340422fa603c9b49def4 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 20:33:28 +0200 Subject: [PATCH 32/40] Always create log event --- contracts/Snapshot/DailyAndSnapshotable.sol | 7 ++++++- contracts/Snapshot/Snapshotable.sol | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/contracts/Snapshot/DailyAndSnapshotable.sol b/contracts/Snapshot/DailyAndSnapshotable.sol index 252dfeb4..9119c1b6 100644 --- a/contracts/Snapshot/DailyAndSnapshotable.sol +++ b/contracts/Snapshot/DailyAndSnapshotable.sol @@ -48,7 +48,12 @@ contract DailyAndSnapshotable is // Same day, no modifications if (!nextSnapshotModified) { - return nextSnapshotId - 1; + uint256 previousSnapshot = nextSnapshotId - 1; + + // Log the event anyway, some logic may depend + // depend on it. + SnapshotCreated(previousSnapshot); + return previousSnapshot; } // Increment the snapshot counter diff --git a/contracts/Snapshot/Snapshotable.sol b/contracts/Snapshot/Snapshotable.sol index 48797097..fe1fad2c 100644 --- a/contracts/Snapshot/Snapshotable.sol +++ b/contracts/Snapshot/Snapshotable.sol @@ -28,7 +28,12 @@ contract Snapshotable is // the previous snapshot id. Their states // are identical. if (!nextSnapshotModified) { - return nextSnapshotId - 1; + uint256 previousSnapshot = nextSnapshotId - 1; + + // Log the event anyway, some logic may depend + // depend on it. + SnapshotCreated(previousSnapshot); + return previousSnapshot; } // Increment the snapshot counter From 12e76ecc2ac5f8022a95a3f2d5a82453e1cde427 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 20:33:46 +0200 Subject: [PATCH 33/40] Remove unused log event --- contracts/Snapshot/Snapshot.sol | 6 ------ 1 file changed, 6 deletions(-) diff --git a/contracts/Snapshot/Snapshot.sol b/contracts/Snapshot/Snapshot.sol index ccd5e08f..f02b967a 100644 --- a/contracts/Snapshot/Snapshot.sol +++ b/contracts/Snapshot/Snapshot.sol @@ -21,12 +21,6 @@ contract Snapshot is MPolicy { uint256 value; } -//////////////// -// Events -//////////////// - - event SnapshotCreated(uint256 snapshot); - //////////////// // Internal functions //////////////// From d2fdd4e5902226e6b01bc41c22bd18154a336242 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 20:33:58 +0200 Subject: [PATCH 34/40] Fix modification check --- contracts/Snapshot/Snapshot.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/Snapshot/Snapshot.sol b/contracts/Snapshot/Snapshot.sol index f02b967a..a18e3436 100644 --- a/contracts/Snapshot/Snapshot.sol +++ b/contracts/Snapshot/Snapshot.sol @@ -142,7 +142,7 @@ contract Snapshot is MPolicy { if (frozen) { // Do nothing if the value was not modified - bool unmodified = values[last].value != _value; + bool unmodified = values[last].value == _value; if (unmodified) { return; } From 0d0a84000b5d612b23fc003c0f7e631a60bbe17e Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 20:35:08 +0200 Subject: [PATCH 35/40] No nested expressions --- contracts/Helpers/SnapshotToken.sol | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contracts/Helpers/SnapshotToken.sol b/contracts/Helpers/SnapshotToken.sol index f1d0a4aa..13805d60 100644 --- a/contracts/Helpers/SnapshotToken.sol +++ b/contracts/Helpers/SnapshotToken.sol @@ -225,8 +225,10 @@ contract SnapshotToken is uint previousBalanceFrom = balanceOf(_owner); require(previousBalanceFrom >= _amount); - setValue(totalSupplyValues, curTotalSupply - _amount); - setValue(balances[_owner], previousBalanceFrom - _amount); + uint newTotalSupply = curTotalSupply - _amount; + uint newBalanceFrom = previousBalanceFrom - _amount; + setValue(totalSupplyValues, newTotalSupply); + setValue(balances[_owner], newBalanceFrom); Transfer(_owner, 0, _amount); return true; From 7af653605aae8f8d7829a46b50036bf10ddf0c42 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 20:37:08 +0200 Subject: [PATCH 36/40] Don't assume continuity accross fork --- contracts/Helpers/SnapshotToken.sol | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/contracts/Helpers/SnapshotToken.sol b/contracts/Helpers/SnapshotToken.sol index 13805d60..75a5a07d 100644 --- a/contracts/Helpers/SnapshotToken.sol +++ b/contracts/Helpers/SnapshotToken.sol @@ -4,14 +4,12 @@ import '../Snapshot/Snapshot.sol'; import '../Standards/ISnapshotToken.sol'; import '../Standards/ISnapshotTokenParent.sol'; import './MMint.sol'; -import './Helpers.sol'; contract SnapshotToken is ISnapshotToken, ISnapshotTokenParent, MMint, - Snapshot, - Helpers + Snapshot { // `parentToken` is the Token address that was cloned to produce this token; @@ -110,7 +108,7 @@ contract SnapshotToken is // Try parent contract at or before the fork if (address(parentToken) != 0) { - return parentToken.totalSupplyAt(min(_snapshot, parentSnapshot)); + return parentToken.totalSupplyAt(parentSnapshot); } // Default to an empty balance @@ -135,7 +133,7 @@ contract SnapshotToken is // Try parent contract at or before the fork if (address(parentToken) != 0) { - return parentToken.balanceOfAt(_owner, min(_snapshot, parentSnapshot)); + return parentToken.balanceOfAt(_owner, parentSnapshot); } // Default to an empty balance From 2a75588e54fd8a57dbfccc2330633071f02c2b61 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 20:40:07 +0200 Subject: [PATCH 37/40] Add IsContract --- contracts/{Helpers/Helpers.sol => IsContract.sol} | 13 ++----------- contracts/SnapshotToken.sol | 10 +++++----- 2 files changed, 7 insertions(+), 16 deletions(-) rename contracts/{Helpers/Helpers.sol => IsContract.sol} (71%) diff --git a/contracts/Helpers/Helpers.sol b/contracts/IsContract.sol similarity index 71% rename from contracts/Helpers/Helpers.sol rename to contracts/IsContract.sol index bd0a9be2..f8031e9b 100644 --- a/contracts/Helpers/Helpers.sol +++ b/contracts/IsContract.sol @@ -1,16 +1,8 @@ pragma solidity ^0.4.13; -contract Helpers { +contract IsContract { - function Helpers() internal {} - - function min(uint256 a, uint256 b) - internal - constant - returns (uint256) - { - return a < b ? a : b; - } + function IsContract() internal {} /// @dev Internal function to determine if an address is a contract /// @param _addr The address being queried @@ -29,5 +21,4 @@ contract Helpers { } return size > 0; } - } diff --git a/contracts/SnapshotToken.sol b/contracts/SnapshotToken.sol index b810e97a..ec081df9 100644 --- a/contracts/SnapshotToken.sol +++ b/contracts/SnapshotToken.sol @@ -3,16 +3,16 @@ pragma solidity ^0.4.13; import './Controlled.sol'; import './ControllerClaims.sol'; import './Helpers/Allowance.sol'; -import './Helpers/Helpers.sol'; import './Helpers/MMint.sol'; -import { SnapshotToken as SnapshotTokenBase } from './Helpers/SnapshotToken.sol'; import './Helpers/TokenInfo.sol'; +import './IsContract.sol'; import './ITokenController.sol'; import './Snapshot/DailyAndSnapshotable.sol'; import './Standards/IApproveAndCallFallback.sol'; +import './Standards/IERC20Token.sol'; import './Standards/ISnapshotToken.sol'; import './Standards/ISnapshotTokenParent.sol'; -import './Standards/IERC20Token.sol'; +import { SnapshotToken as SnapshotTokenBase } from './Helpers/SnapshotToken.sol'; /* Copyright 2016, Remco Bloemen, Jordi Baylina @@ -44,7 +44,6 @@ import './Standards/IERC20Token.sol'; /// that deploys the contract, so usually this token will be deployed by a /// token controller contract, which Giveth will call a "Campaign" -// Helpers is inherited through SnapshotToken // Consumes the MMint mixin from SnapshotToken contract SnapshotToken is IERC20Token, @@ -55,7 +54,8 @@ contract SnapshotToken is Allowance, TokenInfo, Controlled, - ControllerClaims + ControllerClaims, + IsContract { string private constant VERSION = "ST_1.0"; From ed9989c3b2518e12e1e90f55362f1fe0f9c8cd71 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Tue, 22 Aug 2017 20:50:59 +0200 Subject: [PATCH 38/40] Version bumb --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 73f2cb6c..44f12aae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "snapshottoken", - "version": "0.1.0", + "version": "0.1.1", "description": "SnapshotToken contract", "directories": { "test": "test" From 71a2ce77a7ce93c8998d75a7ace477c3640cf53d Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Wed, 23 Aug 2017 16:48:29 +0200 Subject: [PATCH 39/40] Turn all interfaces into contracts --- contracts/ITokenController.sol | 2 +- contracts/Standards/IBasicToken.sol | 2 +- contracts/Standards/IERC20Allowance.sol | 2 +- contracts/Standards/IERC20Token.sol | 2 +- contracts/Standards/ISnapshotToken.sol | 2 +- contracts/Standards/ISnapshotTokenParent.sol | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/ITokenController.sol b/contracts/ITokenController.sol index a16a3df6..9fa40784 100644 --- a/contracts/ITokenController.sol +++ b/contracts/ITokenController.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.13; /// @dev The token controller contract must implement these functions -interface ITokenController { +contract ITokenController { // Payable callback function to receive eth function () payable; diff --git a/contracts/Standards/IBasicToken.sol b/contracts/Standards/IBasicToken.sol index d45b4240..591813e6 100644 --- a/contracts/Standards/IBasicToken.sol +++ b/contracts/Standards/IBasicToken.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.13; -interface IBasicToken { +contract IBasicToken { //////////////// // Events diff --git a/contracts/Standards/IERC20Allowance.sol b/contracts/Standards/IERC20Allowance.sol index bf26a4d0..d7d42e79 100644 --- a/contracts/Standards/IERC20Allowance.sol +++ b/contracts/Standards/IERC20Allowance.sol @@ -2,7 +2,7 @@ pragma solidity ^0.4.13; // is IBasicToken -interface IERC20Allowance { +contract IERC20Allowance { /// @dev This function makes it easy to read the `allowed[]` map /// @param _owner The address of the account that owns the token diff --git a/contracts/Standards/IERC20Token.sol b/contracts/Standards/IERC20Token.sol index 8b55d4e7..016dc48f 100644 --- a/contracts/Standards/IERC20Token.sol +++ b/contracts/Standards/IERC20Token.sol @@ -2,7 +2,7 @@ pragma solidity ^0.4.13; // is IBasicToken, IERC20Allowance -interface IERC20Token { +contract IERC20Token { //////////////// // Events diff --git a/contracts/Standards/ISnapshotToken.sol b/contracts/Standards/ISnapshotToken.sol index 9efdccea..c7f6a1c9 100644 --- a/contracts/Standards/ISnapshotToken.sol +++ b/contracts/Standards/ISnapshotToken.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.13; // is ISnapshotable, IBasicToken, ISnapshotTokenParent -interface ISnapshotToken { +contract ISnapshotToken { //////////////// // Events diff --git a/contracts/Standards/ISnapshotTokenParent.sol b/contracts/Standards/ISnapshotTokenParent.sol index 013b15f3..66828f66 100644 --- a/contracts/Standards/ISnapshotTokenParent.sol +++ b/contracts/Standards/ISnapshotTokenParent.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.13; -interface ISnapshotTokenParent { +contract ISnapshotTokenParent { /// @notice Total amount of tokens at a specific `_snapshot`. /// @param _snapshot The block number when the totalSupply is queried From 7c95aaf7bb3d19174bf7e816be1c307563ebfc26 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Wed, 23 Aug 2017 16:50:04 +0200 Subject: [PATCH 40/40] Increment version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 44f12aae..b541fd12 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "snapshottoken", - "version": "0.1.1", + "version": "0.1.2", "description": "SnapshotToken contract", "directories": { "test": "test"