/ contracts / token / MiniMeToken.sol
MiniMeToken.sol
  1  pragma solidity ^0.5.2;
  2  
  3  /*
  4      Copyright 2016, Jordi Baylina
  5      This program is free software: you can redistribute it and/or modify
  6      it under the terms of the GNU General Public License as published by
  7      the Free Software Foundation, either version 3 of the License, or
  8      (at your option) any later version.
  9      This program is distributed in the hope that it will be useful,
 10      but WITHOUT ANY WARRANTY; without even the implied warranty of
 11      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12      GNU General Public License for more details.
 13      You should have received a copy of the GNU General Public License
 14      along with this program.  If not, see <http://www.gnu.org/licenses/>.
 15   */
 16  /**
 17   * @title MiniMeToken Contract
 18   * @author Jordi Baylina
 19   * @dev This token contract's goal is to make it easy for anyone to clone this
 20   *  token using the token distribution at a given block, this will allow DAO's
 21   *  and DApps to upgrade their features in a decentralized manner without
 22   *  affecting the original token
 23   * @dev It is ERC20 compliant, but still needs to under go further testing.
 24   */
 25  
 26  import "../common/Controlled.sol";
 27  import "./TokenController.sol";
 28  import "./ApproveAndCallFallBack.sol";
 29  import "./MiniMeTokenInterface.sol";
 30  import "./TokenFactory.sol";
 31  
 32  /**
 33   * @dev The actual token contract, the default controller is the msg.sender
 34   *  that deploys the contract, so usually this token will be deployed by a
 35   *  token controller contract, which Giveth will call a "Campaign"
 36   */
 37  
 38  
 39  contract MiniMeToken is MiniMeTokenInterface, Controlled {
 40  
 41      string public name;                //The Token's name: e.g. DigixDAO Tokens
 42      uint8 public decimals;             //Number of decimals of the smallest unit
 43      string public symbol;              //An identifier: e.g. REP
 44      string public constant VERSION = "MMT_0.1"; //An arbitrary versioning scheme
 45  
 46      /**
 47       * @dev `Checkpoint` is the structure that attaches a block number to a
 48       *  given value, the block number attached is the one that last changed the
 49       *  value
 50       */
 51      struct Checkpoint {
 52  
 53          // `fromBlock` is the block number that the value was generated from
 54          uint128 fromBlock;
 55  
 56          // `value` is the amount of tokens at a specific block number
 57          uint128 value;
 58      }
 59  
 60      // `parentToken` is the Token address that was cloned to produce this token;
 61      //  it will be 0x0 for a token that was not cloned
 62      MiniMeToken public parentToken;
 63  
 64      // `parentSnapShotBlock` is the block number from the Parent Token that was
 65      //  used to determine the initial distribution of the Clone Token
 66      uint public parentSnapShotBlock;
 67  
 68      // `creationBlock` is the block number that the Clone Token was created
 69      uint public creationBlock;
 70  
 71      // `balances` is the map that tracks the balance of each address, in this
 72      //  contract when the balance changes the block number that the change
 73      //  occurred is also included in the map
 74      mapping (address => Checkpoint[]) balances;
 75  
 76      // `allowed` tracks any extra transfer rights as in all ERC20 tokens
 77      mapping (address => mapping (address => uint256)) allowed;
 78  
 79      // Tracks the history of the `totalSupply` of the token
 80      Checkpoint[] totalSupplyHistory;
 81  
 82      // Flag that determines if the token is transferable or not.
 83      bool public transfersEnabled;
 84  
 85      // The factory used to create new clone tokens
 86      TokenFactory public tokenFactory;
 87  
 88  ////////////////
 89  // Constructor
 90  ////////////////
 91  
 92      /** 
 93       * @notice Constructor to create a MiniMeToken
 94       * @param _tokenFactory The address of the MiniMeTokenFactory contract that
 95       *  will create the Clone token contracts, the token factory needs to be
 96       *  deployed first
 97       * @param _parentToken Address of the parent token, set to 0x0 if it is a
 98       *  new token
 99       * @param _parentSnapShotBlock Block of the parent token that will
100       *  determine the initial distribution of the clone token, set to 0 if it
101       *  is a new token
102       * @param _tokenName Name of the new token
103       * @param _decimalUnits Number of decimals of the new token
104       * @param _tokenSymbol Token Symbol for the new token
105       * @param _transfersEnabled If true, tokens will be able to be transferred
106       */
107      constructor(
108          address _tokenFactory,
109          address _parentToken,
110          uint _parentSnapShotBlock,
111          string memory _tokenName,
112          uint8 _decimalUnits,
113          string memory _tokenSymbol,
114          bool _transfersEnabled
115      ) 
116          public
117      {
118          tokenFactory = TokenFactory(_tokenFactory);
119          name = _tokenName;                                 // Set the name
120          decimals = _decimalUnits;                          // Set the decimals
121          symbol = _tokenSymbol;                             // Set the symbol
122          parentToken = MiniMeToken(address(uint160(_parentToken)));
123          parentSnapShotBlock = _parentSnapShotBlock;
124          transfersEnabled = _transfersEnabled;
125          creationBlock = block.number;
126      }
127  
128  
129  ///////////////////
130  // ERC20 Methods
131  ///////////////////
132  
133      /**
134       * @notice Send `_amount` tokens to `_to` from `msg.sender`
135       * @param _to The address of the recipient
136       * @param _amount The amount of tokens to be transferred
137       * @return Whether the transfer was successful or not
138       */
139      function transfer(address _to, uint256 _amount) external returns (bool success) {
140          require(transfersEnabled);
141          return doTransfer(msg.sender, _to, _amount);
142      }
143  
144      /**
145       * @notice Send `_amount` tokens to `_to` from `_from` on the condition it
146       *  is approved by `_from`
147       * @param _from The address holding the tokens being transferred
148       * @param _to The address of the recipient
149       * @param _amount The amount of tokens to be transferred
150       * @return True if the transfer was successful
151       */
152      function transferFrom(
153          address _from,
154          address _to,
155          uint256 _amount
156      ) 
157          external 
158          returns (bool success)
159      {
160  
161          // The controller of this contract can move tokens around at will,
162          //  this is important to recognize! Confirm that you trust the
163          //  controller of this contract, which in most situations should be
164          //  another open source smart contract or 0x0
165          if (msg.sender != controller) {
166              require(transfersEnabled);
167  
168              // The standard ERC 20 transferFrom functionality
169              if (allowed[_from][msg.sender] < _amount) { 
170                  return false;
171              }
172              allowed[_from][msg.sender] -= _amount;
173          }
174          return doTransfer(_from, _to, _amount);
175      }
176  
177      /**
178       * @dev This is the actual transfer function in the token contract, it can
179       *  only be called by other functions in this contract.
180       * @param _from The address holding the tokens being transferred
181       * @param _to The address of the recipient
182       * @param _amount The amount of tokens to be transferred
183       * @return True if the transfer was successful
184       */
185      function doTransfer(
186          address _from,
187          address _to,
188          uint _amount
189      ) 
190          internal
191          returns(bool)
192      {
193  
194          if (_amount == 0) {
195              return true;
196          }
197  
198          require(parentSnapShotBlock < block.number);
199  
200          // Do not allow transfer to 0x0 or the token contract itself
201          require((_to != address(0)) && (_to != address(this)));
202  
203          // If the amount being transfered is more than the balance of the
204          //  account the transfer returns false
205          uint256 previousBalanceFrom = balanceOfAt(_from, block.number);
206          if (previousBalanceFrom < _amount) {
207              return false;
208          }
209  
210          // Alerts the token controller of the transfer
211          if (isContract(controller)) {
212              require(TokenController(controller).onTransfer(_from, _to, _amount));
213          }
214  
215          // First update the balance array with the new value for the address
216          //  sending the tokens
217          updateValueAtNow(balances[_from], previousBalanceFrom - _amount);
218  
219          // Then update the balance array with the new value for the address
220          //  receiving the tokens
221          uint256 previousBalanceTo = balanceOfAt(_to, block.number);
222          require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow
223          updateValueAtNow(balances[_to], previousBalanceTo + _amount);
224  
225          // An event to make the transfer easy to find on the blockchain
226          emit Transfer(_from, _to, _amount);
227  
228          return true;
229      }
230  
231      function doApprove(
232          address _from,
233          address _spender,
234          uint256 _amount
235      )
236          internal 
237          returns (bool)
238      {
239          require(transfersEnabled);
240  
241          // To change the approve amount you first have to reduce the addresses`
242          //  allowance to zero by calling `approve(_spender,0)` if it is not
243          //  already 0 to mitigate the race condition described here:
244          //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
245          require((_amount == 0) || (allowed[_from][_spender] == 0));
246  
247          // Alerts the token controller of the approve function call
248          if (isContract(controller)) {
249              require(TokenController(controller).onApprove(_from, _spender, _amount));
250          }
251  
252          allowed[_from][_spender] = _amount;
253          emit Approval(_from, _spender, _amount);
254          return true;
255      }
256  
257      /**
258       * @param _owner The address that's balance is being requested
259       * @return The balance of `_owner` at the current block
260       */
261      function balanceOf(address _owner) external view returns (uint256 balance) {
262          return balanceOfAt(_owner, block.number);
263      }
264  
265      /**
266       * @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
267       *  its behalf. This is a modified version of the ERC20 approve function
268       *  to be a little bit safer
269       * @param _spender The address of the account able to transfer the tokens
270       * @param _amount The amount of tokens to be approved for transfer
271       * @return True if the approval was successful
272       */
273      function approve(address _spender, uint256 _amount) external returns (bool success) {
274          doApprove(msg.sender, _spender, _amount);
275      }
276  
277      /**
278       * @dev This function makes it easy to read the `allowed[]` map
279       * @param _owner The address of the account that owns the token
280       * @param _spender The address of the account able to transfer the tokens
281       * @return Amount of remaining tokens of _owner that _spender is allowed
282       *  to spend
283       */
284      function allowance(
285          address _owner,
286          address _spender
287      ) 
288          external
289          view
290          returns (uint256 remaining)
291      {
292          return allowed[_owner][_spender];
293      }
294      /**
295       * @notice `msg.sender` approves `_spender` to send `_amount` tokens on
296       *  its behalf, and then a function is triggered in the contract that is
297       *  being approved, `_spender`. This allows users to use their tokens to
298       *  interact with contracts in one function call instead of two
299       * @param _spender The address of the contract able to transfer the tokens
300       * @param _amount The amount of tokens to be approved for transfer
301       * @return True if the function call was successful
302       */
303      function approveAndCall(
304          address _spender,
305          uint256 _amount,
306          bytes calldata _extraData
307      ) 
308          external
309          returns (bool success)
310      {
311          require(doApprove(msg.sender, _spender, _amount));
312  
313          ApproveAndCallFallBack(_spender).receiveApproval(
314              msg.sender,
315              _amount,
316              address(this),
317              _extraData
318          );
319  
320          return true;
321      }
322  
323      /**
324       * @dev This function makes it easy to get the total number of tokens
325       * @return The total number of tokens
326       */
327      function totalSupply() external view returns (uint) {
328          return totalSupplyAt(block.number);
329      }
330  
331  
332  ////////////////
333  // Query balance and totalSupply in History
334  ////////////////
335  
336      /**
337       * @dev Queries the balance of `_owner` at a specific `_blockNumber`
338       * @param _owner The address from which the balance will be retrieved
339       * @param _blockNumber The block number when the balance is queried
340       * @return The balance at `_blockNumber`
341       */
342      function balanceOfAt(
343          address _owner,
344          uint _blockNumber
345      ) 
346          public
347          view
348          returns (uint) 
349      {
350  
351          // These next few lines are used when the balance of the token is
352          //  requested before a check point was ever created for this token, it
353          //  requires that the `parentToken.balanceOfAt` be queried at the
354          //  genesis block for that token as this contains initial balance of
355          //  this token
356          if ((balances[_owner].length == 0) || (balances[_owner][0].fromBlock > _blockNumber)) {
357              if (address(parentToken) != address(0)) {
358                  return parentToken.balanceOfAt(_owner, min(_blockNumber, parentSnapShotBlock));
359              } else {
360                  // Has no parent
361                  return 0;
362              }
363  
364          // This will return the expected balance during normal situations
365          } else {
366              return getValueAt(balances[_owner], _blockNumber);
367          }
368      }
369  
370      /**
371       * @notice Total amount of tokens at a specific `_blockNumber`.
372       * @param _blockNumber The block number when the totalSupply is queried
373       * @return The total amount of tokens at `_blockNumber`
374       */
375      function totalSupplyAt(uint _blockNumber) public view returns(uint) {
376  
377          // These next few lines are used when the totalSupply of the token is
378          //  requested before a check point was ever created for this token, it
379          //  requires that the `parentToken.totalSupplyAt` be queried at the
380          //  genesis block for this token as that contains totalSupply of this
381          //  token at this block number.
382          if ((totalSupplyHistory.length == 0) || (totalSupplyHistory[0].fromBlock > _blockNumber)) {
383              if (address(parentToken) != address(0)) {
384                  return parentToken.totalSupplyAt(min(_blockNumber, parentSnapShotBlock));
385              } else {
386                  return 0;
387              }
388  
389          // This will return the expected totalSupply during normal situations
390          } else {
391              return getValueAt(totalSupplyHistory, _blockNumber);
392          }
393      }
394  
395  ////////////////
396  // Clone Token Method
397  ////////////////
398  
399      /**
400       * @notice Creates a new clone token with the initial distribution being
401       *  this token at `snapshotBlock`
402       * @param _cloneTokenName Name of the clone token
403       * @param _cloneDecimalUnits Number of decimals of the smallest unit
404       * @param _cloneTokenSymbol Symbol of the clone token
405       * @param _snapshotBlock Block when the distribution of the parent token is
406       *  copied to set the initial distribution of the new clone token;
407       *  if the block is zero than the actual block, the current block is used
408       * @param _transfersEnabled True if transfers are allowed in the clone
409       * @return The address of the new MiniMeToken Contract
410       */
411      function createCloneToken(
412          string calldata _cloneTokenName,
413          uint8 _cloneDecimalUnits,
414          string calldata _cloneTokenSymbol,
415          uint _snapshotBlock,
416          bool _transfersEnabled
417          ) 
418              external
419              returns(address)
420          {
421          uint snapshotBlock = _snapshotBlock;
422          if (snapshotBlock == 0) {
423              snapshotBlock = block.number;
424          }
425          MiniMeToken cloneToken = MiniMeToken(
426              tokenFactory.createCloneToken(
427              address(this),
428              snapshotBlock,
429              _cloneTokenName,
430              _cloneDecimalUnits,
431              _cloneTokenSymbol,
432              _transfersEnabled
433              ));
434  
435          cloneToken.changeController(msg.sender);
436  
437          // An event to make the token easy to find on the blockchain
438          emit NewCloneToken(address(cloneToken), snapshotBlock);
439          return address(cloneToken);
440      }
441  
442  ////////////////
443  // Generate and destroy tokens
444  ////////////////
445      
446      /**
447       * @notice Generates `_amount` tokens that are assigned to `_owner`
448       * @param _owner The address that will be assigned the new tokens
449       * @param _amount The quantity of tokens generated
450       * @return True if the tokens are generated correctly
451       */
452      function generateTokens(
453          address _owner,
454          uint _amount
455      )
456          external
457          onlyController
458          returns (bool)
459      {
460          uint curTotalSupply = totalSupplyAt(block.number);
461          require(curTotalSupply + _amount >= curTotalSupply); // Check for overflow
462          uint previousBalanceTo = balanceOfAt(_owner, block.number);
463          require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow
464          updateValueAtNow(totalSupplyHistory, curTotalSupply + _amount);
465          updateValueAtNow(balances[_owner], previousBalanceTo + _amount);
466          emit Transfer(address(0), _owner, _amount);
467          return true;
468      }
469  
470      /**
471       * @notice Burns `_amount` tokens from `_owner`
472       * @param _owner The address that will lose the tokens
473       * @param _amount The quantity of tokens to burn
474       * @return True if the tokens are burned correctly
475       */
476      function destroyTokens(
477          address _owner,
478          uint _amount
479      ) 
480          external
481          onlyController
482          returns (bool)
483      {
484          uint curTotalSupply = totalSupplyAt(block.number);
485          require(curTotalSupply >= _amount);
486          uint previousBalanceFrom = balanceOfAt(_owner, block.number);
487          require(previousBalanceFrom >= _amount);
488          updateValueAtNow(totalSupplyHistory, curTotalSupply - _amount);
489          updateValueAtNow(balances[_owner], previousBalanceFrom - _amount);
490          emit Transfer(_owner, address(0), _amount);
491          return true;
492      }
493  
494  ////////////////
495  // Enable tokens transfers
496  ////////////////
497  
498      /**
499       * @notice Enables token holders to transfer their tokens freely if true
500       * @param _transfersEnabled True if transfers are allowed in the clone
501       */
502      function enableTransfers(bool _transfersEnabled) external onlyController {
503          transfersEnabled = _transfersEnabled;
504      }
505  
506  ////////////////
507  // Internal helper functions to query and set a value in a snapshot array
508  ////////////////
509  
510      /**
511       * @dev `getValueAt` retrieves the number of tokens at a given block number
512       * @param checkpoints The history of values being queried
513       * @param _block The block number to retrieve the value at
514       * @return The number of tokens being queried
515       */
516      function getValueAt(
517          Checkpoint[] storage checkpoints,
518          uint _block
519      ) 
520          internal
521          view
522          returns (uint)
523      {
524          if (checkpoints.length == 0) {
525              return 0;
526          }
527  
528          // Shortcut for the actual value
529          if (_block >= checkpoints[checkpoints.length-1].fromBlock) {
530              return checkpoints[checkpoints.length-1].value;
531          }
532          if (_block < checkpoints[0].fromBlock) {
533              return 0;
534          }
535  
536          // Binary search of the value in the array
537          uint min = 0;
538          uint max = checkpoints.length-1;
539          while (max > min) {
540              uint mid = (max + min + 1) / 2;
541              if (checkpoints[mid].fromBlock<=_block) {
542                  min = mid;
543              } else {
544                  max = mid-1;
545              }
546          }
547          return checkpoints[min].value;
548      }
549  
550      /**
551       * @dev `updateValueAtNow` used to update the `balances` map and the
552       *  `totalSupplyHistory`
553       * @param checkpoints The history of data being updated
554       * @param _value The new number of tokens
555       */
556      function updateValueAtNow(Checkpoint[] storage checkpoints, uint _value) internal {
557          if ((checkpoints.length == 0) || (checkpoints[checkpoints.length - 1].fromBlock < block.number)) {
558              Checkpoint storage newCheckPoint = checkpoints[checkpoints.length++];
559              newCheckPoint.fromBlock = uint128(block.number);
560              newCheckPoint.value = uint128(_value);
561          } else {
562              Checkpoint storage oldCheckPoint = checkpoints[checkpoints.length-1];
563              oldCheckPoint.value = uint128(_value);
564          }
565      }
566  
567      /**
568       * @dev Internal function to determine if an address is a contract
569       * @param _addr The address being queried
570       * @return True if `_addr` is a contract
571       */
572      function isContract(address _addr) internal returns(bool) {
573          uint size;
574          if (_addr == address(0)) {
575              return false;
576          }    
577          assembly {
578              size := extcodesize(_addr)
579          }
580          return size>0;
581      }
582  
583      /**
584       * @dev Helper function to return a min betwen the two uints
585       */
586      function min(uint a, uint b) internal pure returns (uint) {
587          return a < b ? a : b;
588      }
589  
590      /**
591       * @notice The fallback function: If the contract's controller has not been
592       *  set to 0, then the `proxyPayment` method is called which relays the
593       *  ether and creates tokens as described in the token controller contract
594       */
595      function () external payable {
596          require(isContract(controller));
597          require(TokenController(controller).proxyPayment.value(msg.value)(msg.sender));
598      }
599  
600  //////////
601  // Safety Methods
602  //////////
603  
604      /**
605       * @notice This method can be used by the controller to extract mistakenly
606       *  sent tokens to this contract.
607       * @param _token The address of the token contract that you want to recover
608       *  set to 0 in case you want to extract ether.
609       */
610      function claimTokens(address _token) external onlyController {
611          if (_token == address(0)) {
612              controller.transfer(address(this).balance);
613              return;
614          }
615  
616          MiniMeToken token = MiniMeToken(address(uint160(_token)));
617          uint balance = token.balanceOf(address(this));
618          token.transfer(controller, balance);
619          emit ClaimedTokens(_token, controller, balance);
620      }
621  
622  ////////////////
623  // Events
624  ////////////////
625      event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount);
626      event Transfer(address indexed _from, address indexed _to, uint256 _amount);
627      event NewCloneToken(address indexed _cloneToken, uint snapshotBlock);
628      event Approval(
629          address indexed _owner,
630          address indexed _spender,
631          uint256 _amount
632      );
633  
634  }