diff --git a/MiniMeToken.sol b/MiniMeToken.sol index 4a2662e..4b46626 100644 --- a/MiniMeToken.sol +++ b/MiniMeToken.sol @@ -19,29 +19,33 @@ pragma solidity ^0.4.6; /// @title MiniMeToken Contract /// @author Jordi Baylina -/// @dev This token contract's goal is to make it easy to clone this token and -/// spawn new tokens using the token distribution at a given block. +/// @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 +/// affecting the original token /// @dev It is ERC20 compliant, but still needs to under go further testing. -// The controller must implement this interface +/// @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 + /// @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 transfer + /// @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 + /// @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 ammount 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); @@ -63,6 +67,9 @@ contract Controlled { } } +/// @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 { string public name; //The Token's name: e.g. DigixDAO Tokens @@ -71,8 +78,9 @@ contract MiniMeToken is Controlled { string public version = 'MMT_0.1'; //An arbitrary versioning scheme - /// @dev `Checkpoint` is the structure that attaches a block number to the a - /// given value + /// @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 @@ -86,14 +94,16 @@ contract MiniMeToken is Controlled { // 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 + // `parentSnapShotBlock` is the block number from the Parent Token that was // used to determine the initial distribution of the Clone Token uint public parentSnapShotBlock; // `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 + // `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; // `allowed` tracks any extra transfer rights as in all ERC20 tokens @@ -114,7 +124,8 @@ contract MiniMeToken is Controlled { /// @notice Constructor to create a MiniMeToken /// @param _tokenFactory The address of the MiniMeTokenFactory contract that - /// will create the Clone token contracts + /// 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 _parentSnapShotBlock Block of the parent token that will @@ -166,10 +177,10 @@ contract MiniMeToken is Controlled { 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 + /// @dev 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) { if (!transfersEnabled) throw; @@ -180,6 +191,12 @@ contract MiniMeToken is Controlled { return doTransfer(_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 function doTransfer(address _from, address _to, uint _amount ) internal returns(bool) { @@ -197,6 +214,7 @@ contract MiniMeToken is Controlled { return false; } + // Alerts the token controller of the transfer if ((controller != 0)&&(isContract(controller))) { if (!TokenController(controller).onTransfer(_from, _to, _amount)) throw; @@ -224,7 +242,8 @@ contract MiniMeToken is Controlled { } /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on - /// its behalf + /// 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 @@ -232,10 +251,12 @@ contract MiniMeToken is Controlled { if (!transfersEnabled) throw; // 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 https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + // allowance to zero by calling `approve(_spender,0)` if it is not + // already 0 to mitigate the race condition described here: + // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 if ((_amount!=0) && (allowed[msg.sender][_spender] !=0)) throw; + // Alerts the token controller of the approve function call if ((controller != 0)&&(isContract(controller))) { if (!TokenController(controller).onApprove(msg.sender, _spender, _amount)) throw; @@ -246,6 +267,7 @@ contract MiniMeToken is Controlled { 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 @@ -257,7 +279,8 @@ contract MiniMeToken is Controlled { /// @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` + /// 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 @@ -271,7 +294,7 @@ contract MiniMeToken is Controlled { // is being approved (`_spender`). The function should look like: // `receiveApproval(address _from, uint256 _amount, address // _tokenContract, bytes _extraData)` It is assumed that the call - // *should* succeed, otherwise one would use vanilla approve instead. + // *should* succeed, otherwise the plain vanilla approve would be used if(!_spender.call( bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, @@ -283,7 +306,8 @@ contract MiniMeToken is Controlled { return true; } - /// @return The total amount of tokens + /// @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); } @@ -293,7 +317,7 @@ contract MiniMeToken is Controlled { // Query balance and totalSupply in History //////////////// - /// @notice Queries the balance of `_owner` at a specific `_blockNumber` + /// @dev Queries the balance of `_owner` at a specific `_blockNumber` /// @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` @@ -321,7 +345,7 @@ contract MiniMeToken is Controlled { // This will return the expected balance during normal situations } else { - return getValueAt( balances[_owner], _blockNumber); + return getValueAt(balances[_owner], _blockNumber); } } @@ -351,7 +375,7 @@ contract MiniMeToken is Controlled { // This will return the expected totalSupply during normal situations } else { - return getValueAt( totalSupplyHistory, _blockNumber); + return getValueAt(totalSupplyHistory, _blockNumber); } } @@ -362,7 +386,7 @@ contract MiniMeToken is Controlled { /// @notice Creates a new clone token with the initial distribution being /// this token at `_snapshotBlock` /// @param _cloneTokenName Name of the clone token - /// @param _cloneDecimalUnits Units 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; @@ -443,9 +467,14 @@ 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; @@ -465,6 +494,10 @@ contract MiniMeToken is Controlled { 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) @@ -478,7 +511,9 @@ contract MiniMeToken is Controlled { } } - // Internal function to determine if an address is a cntract + /// @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; assembly { @@ -488,8 +523,8 @@ contract MiniMeToken is Controlled { } /// @notice The fallback function: If the contract's controller has not been - /// set to 0, the ether is sent to the controller (normally the token - /// creation contract) using the `proxyPayment` method. + /// 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 { if (controller == 0) throw; if (isContract(controller)) { @@ -519,10 +554,21 @@ contract MiniMeToken is Controlled { // MiniMeTokenFactory //////////////// -// 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 +/// @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,