ETH Price: $2,168.23 (+4.30%)

Transaction Decoder

Block:
10722679 at Aug-24-2020 11:03:08 AM +UTC
Transaction Fee:
0.018500697 ETH $40.11
Gas Used:
207,873 Gas / 89 Gwei

Emitted Events:

170 UniswapV2Pair.Transfer( from=[Receiver] 0xea4d68cf86bce59bf2bfa039b97794ce2c43debc, to=[Sender] 0x5411a469381ae1e64ab214a3d10ffe57a20cb96c, value=8455009234499956460 )
171 0xea4d68cf86bce59bf2bfa039b97794ce2c43debc.0x7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5( 0x7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5, 0x0000000000000000000000005411a469381ae1e64ab214a3d10ffe57a20cb96c, 00000000000000000000000000000000000000000000000075563a1a2b046eec )
172 ANT.Transfer( from=[Receiver] 0xea4d68cf86bce59bf2bfa039b97794ce2c43debc, to=[Sender] 0x5411a469381ae1e64ab214a3d10ffe57a20cb96c, value=2800061154537643748 )
173 0xea4d68cf86bce59bf2bfa039b97794ce2c43debc.0xe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e0486( 0xe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e0486, 0x0000000000000000000000005411a469381ae1e64ab214a3d10ffe57a20cb96c, 00000000000000000000000000000000000000000000000026dbd0c8e1961ee4 )

Account State Difference:

  Address   Before After State Difference Code
(Hiveon: Old Pool)
772.139132346092784715 Eth772.157633043092784715 Eth0.018500697
0x5411a469...7a20CB96C
0.053911553988678315 Eth
Nonce: 20
0.035410856988678315 Eth
Nonce: 21
0.018500697
0x960b236A...6A7B288C0
0xEA4D68CF...e2c43dEBC
0xfa19de40...a6d686Efe

Execution Trace

0xea4d68cf86bce59bf2bfa039b97794ce2c43debc.CALL( )
  • UniswapV2Pair.transfer( to=0x5411a469381AE1e64aB214a3d10ffe57a20CB96C, value=8455009234499956460 ) => ( True )
  • ANT.transfer( _to=0x5411a469381AE1e64aB214a3d10ffe57a20CB96C, _value=2800061154537643748 ) => ( success=True )
    • ANPlaceholder.onTransfer( _from=0xEA4D68CF86BcE59Bf2bFA039B97794ce2c43dEBC, _to=0x5411a469381AE1e64aB214a3d10ffe57a20CB96C, _amount=2800061154537643748 ) => ( True )
      File 1 of 3: UniswapV2Pair
      // File: contracts/interfaces/IUniswapV2Pair.sol
      
      pragma solidity >=0.5.0;
      
      interface IUniswapV2Pair {
          event Approval(address indexed owner, address indexed spender, uint value);
          event Transfer(address indexed from, address indexed to, uint value);
      
          function name() external pure returns (string memory);
          function symbol() external pure returns (string memory);
          function decimals() external pure returns (uint8);
          function totalSupply() external view returns (uint);
          function balanceOf(address owner) external view returns (uint);
          function allowance(address owner, address spender) external view returns (uint);
      
          function approve(address spender, uint value) external returns (bool);
          function transfer(address to, uint value) external returns (bool);
          function transferFrom(address from, address to, uint value) external returns (bool);
      
          function DOMAIN_SEPARATOR() external view returns (bytes32);
          function PERMIT_TYPEHASH() external pure returns (bytes32);
          function nonces(address owner) external view returns (uint);
      
          function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
      
          event Mint(address indexed sender, uint amount0, uint amount1);
          event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
          event Swap(
              address indexed sender,
              uint amount0In,
              uint amount1In,
              uint amount0Out,
              uint amount1Out,
              address indexed to
          );
          event Sync(uint112 reserve0, uint112 reserve1);
      
          function MINIMUM_LIQUIDITY() external pure returns (uint);
          function factory() external view returns (address);
          function token0() external view returns (address);
          function token1() external view returns (address);
          function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
          function price0CumulativeLast() external view returns (uint);
          function price1CumulativeLast() external view returns (uint);
          function kLast() external view returns (uint);
      
          function mint(address to) external returns (uint liquidity);
          function burn(address to) external returns (uint amount0, uint amount1);
          function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
          function skim(address to) external;
          function sync() external;
      
          function initialize(address, address) external;
      }
      
      // File: contracts/interfaces/IUniswapV2ERC20.sol
      
      pragma solidity >=0.5.0;
      
      interface IUniswapV2ERC20 {
          event Approval(address indexed owner, address indexed spender, uint value);
          event Transfer(address indexed from, address indexed to, uint value);
      
          function name() external pure returns (string memory);
          function symbol() external pure returns (string memory);
          function decimals() external pure returns (uint8);
          function totalSupply() external view returns (uint);
          function balanceOf(address owner) external view returns (uint);
          function allowance(address owner, address spender) external view returns (uint);
      
          function approve(address spender, uint value) external returns (bool);
          function transfer(address to, uint value) external returns (bool);
          function transferFrom(address from, address to, uint value) external returns (bool);
      
          function DOMAIN_SEPARATOR() external view returns (bytes32);
          function PERMIT_TYPEHASH() external pure returns (bytes32);
          function nonces(address owner) external view returns (uint);
      
          function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
      }
      
      // File: contracts/libraries/SafeMath.sol
      
      pragma solidity =0.5.16;
      
      // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
      
      library SafeMath {
          function add(uint x, uint y) internal pure returns (uint z) {
              require((z = x + y) >= x, 'ds-math-add-overflow');
          }
      
          function sub(uint x, uint y) internal pure returns (uint z) {
              require((z = x - y) <= x, 'ds-math-sub-underflow');
          }
      
          function mul(uint x, uint y) internal pure returns (uint z) {
              require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
          }
      }
      
      // File: contracts/UniswapV2ERC20.sol
      
      pragma solidity =0.5.16;
      
      
      
      contract UniswapV2ERC20 is IUniswapV2ERC20 {
          using SafeMath for uint;
      
          string public constant name = 'Uniswap V2';
          string public constant symbol = 'UNI-V2';
          uint8 public constant decimals = 18;
          uint  public totalSupply;
          mapping(address => uint) public balanceOf;
          mapping(address => mapping(address => uint)) public allowance;
      
          bytes32 public DOMAIN_SEPARATOR;
          // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
          bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
          mapping(address => uint) public nonces;
      
          event Approval(address indexed owner, address indexed spender, uint value);
          event Transfer(address indexed from, address indexed to, uint value);
      
          constructor() public {
              uint chainId;
              assembly {
                  chainId := chainid
              }
              DOMAIN_SEPARATOR = keccak256(
                  abi.encode(
                      keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
                      keccak256(bytes(name)),
                      keccak256(bytes('1')),
                      chainId,
                      address(this)
                  )
              );
          }
      
          function _mint(address to, uint value) internal {
              totalSupply = totalSupply.add(value);
              balanceOf[to] = balanceOf[to].add(value);
              emit Transfer(address(0), to, value);
          }
      
          function _burn(address from, uint value) internal {
              balanceOf[from] = balanceOf[from].sub(value);
              totalSupply = totalSupply.sub(value);
              emit Transfer(from, address(0), value);
          }
      
          function _approve(address owner, address spender, uint value) private {
              allowance[owner][spender] = value;
              emit Approval(owner, spender, value);
          }
      
          function _transfer(address from, address to, uint value) private {
              balanceOf[from] = balanceOf[from].sub(value);
              balanceOf[to] = balanceOf[to].add(value);
              emit Transfer(from, to, value);
          }
      
          function approve(address spender, uint value) external returns (bool) {
              _approve(msg.sender, spender, value);
              return true;
          }
      
          function transfer(address to, uint value) external returns (bool) {
              _transfer(msg.sender, to, value);
              return true;
          }
      
          function transferFrom(address from, address to, uint value) external returns (bool) {
              if (allowance[from][msg.sender] != uint(-1)) {
                  allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
              }
              _transfer(from, to, value);
              return true;
          }
      
          function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
              require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
              bytes32 digest = keccak256(
                  abi.encodePacked(
                      '\x19\x01',
                      DOMAIN_SEPARATOR,
                      keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
                  )
              );
              address recoveredAddress = ecrecover(digest, v, r, s);
              require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE');
              _approve(owner, spender, value);
          }
      }
      
      // File: contracts/libraries/Math.sol
      
      pragma solidity =0.5.16;
      
      // a library for performing various math operations
      
      library Math {
          function min(uint x, uint y) internal pure returns (uint z) {
              z = x < y ? x : y;
          }
      
          // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
          function sqrt(uint y) internal pure returns (uint z) {
              if (y > 3) {
                  z = y;
                  uint x = y / 2 + 1;
                  while (x < z) {
                      z = x;
                      x = (y / x + x) / 2;
                  }
              } else if (y != 0) {
                  z = 1;
              }
          }
      }
      
      // File: contracts/libraries/UQ112x112.sol
      
      pragma solidity =0.5.16;
      
      // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))
      
      // range: [0, 2**112 - 1]
      // resolution: 1 / 2**112
      
      library UQ112x112 {
          uint224 constant Q112 = 2**112;
      
          // encode a uint112 as a UQ112x112
          function encode(uint112 y) internal pure returns (uint224 z) {
              z = uint224(y) * Q112; // never overflows
          }
      
          // divide a UQ112x112 by a uint112, returning a UQ112x112
          function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {
              z = x / uint224(y);
          }
      }
      
      // File: contracts/interfaces/IERC20.sol
      
      pragma solidity >=0.5.0;
      
      interface IERC20 {
          event Approval(address indexed owner, address indexed spender, uint value);
          event Transfer(address indexed from, address indexed to, uint value);
      
          function name() external view returns (string memory);
          function symbol() external view returns (string memory);
          function decimals() external view returns (uint8);
          function totalSupply() external view returns (uint);
          function balanceOf(address owner) external view returns (uint);
          function allowance(address owner, address spender) external view returns (uint);
      
          function approve(address spender, uint value) external returns (bool);
          function transfer(address to, uint value) external returns (bool);
          function transferFrom(address from, address to, uint value) external returns (bool);
      }
      
      // File: contracts/interfaces/IUniswapV2Factory.sol
      
      pragma solidity >=0.5.0;
      
      interface IUniswapV2Factory {
          event PairCreated(address indexed token0, address indexed token1, address pair, uint);
      
          function feeTo() external view returns (address);
          function feeToSetter() external view returns (address);
      
          function getPair(address tokenA, address tokenB) external view returns (address pair);
          function allPairs(uint) external view returns (address pair);
          function allPairsLength() external view returns (uint);
      
          function createPair(address tokenA, address tokenB) external returns (address pair);
      
          function setFeeTo(address) external;
          function setFeeToSetter(address) external;
      }
      
      // File: contracts/interfaces/IUniswapV2Callee.sol
      
      pragma solidity >=0.5.0;
      
      interface IUniswapV2Callee {
          function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external;
      }
      
      // File: contracts/UniswapV2Pair.sol
      
      pragma solidity =0.5.16;
      
      
      
      
      
      
      
      
      contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 {
          using SafeMath  for uint;
          using UQ112x112 for uint224;
      
          uint public constant MINIMUM_LIQUIDITY = 10**3;
          bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
      
          address public factory;
          address public token0;
          address public token1;
      
          uint112 private reserve0;           // uses single storage slot, accessible via getReserves
          uint112 private reserve1;           // uses single storage slot, accessible via getReserves
          uint32  private blockTimestampLast; // uses single storage slot, accessible via getReserves
      
          uint public price0CumulativeLast;
          uint public price1CumulativeLast;
          uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event
      
          uint private unlocked = 1;
          modifier lock() {
              require(unlocked == 1, 'UniswapV2: LOCKED');
              unlocked = 0;
              _;
              unlocked = 1;
          }
      
          function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
              _reserve0 = reserve0;
              _reserve1 = reserve1;
              _blockTimestampLast = blockTimestampLast;
          }
      
          function _safeTransfer(address token, address to, uint value) private {
              (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
              require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED');
          }
      
          event Mint(address indexed sender, uint amount0, uint amount1);
          event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
          event Swap(
              address indexed sender,
              uint amount0In,
              uint amount1In,
              uint amount0Out,
              uint amount1Out,
              address indexed to
          );
          event Sync(uint112 reserve0, uint112 reserve1);
      
          constructor() public {
              factory = msg.sender;
          }
      
          // called once by the factory at time of deployment
          function initialize(address _token0, address _token1) external {
              require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check
              token0 = _token0;
              token1 = _token1;
          }
      
          // update reserves and, on the first call per block, price accumulators
          function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private {
              require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'UniswapV2: OVERFLOW');
              uint32 blockTimestamp = uint32(block.timestamp % 2**32);
              uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
              if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
                  // * never overflows, and + overflow is desired
                  price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;
                  price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;
              }
              reserve0 = uint112(balance0);
              reserve1 = uint112(balance1);
              blockTimestampLast = blockTimestamp;
              emit Sync(reserve0, reserve1);
          }
      
          // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k)
          function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
              address feeTo = IUniswapV2Factory(factory).feeTo();
              feeOn = feeTo != address(0);
              uint _kLast = kLast; // gas savings
              if (feeOn) {
                  if (_kLast != 0) {
                      uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1));
                      uint rootKLast = Math.sqrt(_kLast);
                      if (rootK > rootKLast) {
                          uint numerator = totalSupply.mul(rootK.sub(rootKLast));
                          uint denominator = rootK.mul(5).add(rootKLast);
                          uint liquidity = numerator / denominator;
                          if (liquidity > 0) _mint(feeTo, liquidity);
                      }
                  }
              } else if (_kLast != 0) {
                  kLast = 0;
              }
          }
      
          // this low-level function should be called from a contract which performs important safety checks
          function mint(address to) external lock returns (uint liquidity) {
              (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
              uint balance0 = IERC20(token0).balanceOf(address(this));
              uint balance1 = IERC20(token1).balanceOf(address(this));
              uint amount0 = balance0.sub(_reserve0);
              uint amount1 = balance1.sub(_reserve1);
      
              bool feeOn = _mintFee(_reserve0, _reserve1);
              uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
              if (_totalSupply == 0) {
                  liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
                 _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
              } else {
                  liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
              }
              require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED');
              _mint(to, liquidity);
      
              _update(balance0, balance1, _reserve0, _reserve1);
              if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
              emit Mint(msg.sender, amount0, amount1);
          }
      
          // this low-level function should be called from a contract which performs important safety checks
          function burn(address to) external lock returns (uint amount0, uint amount1) {
              (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
              address _token0 = token0;                                // gas savings
              address _token1 = token1;                                // gas savings
              uint balance0 = IERC20(_token0).balanceOf(address(this));
              uint balance1 = IERC20(_token1).balanceOf(address(this));
              uint liquidity = balanceOf[address(this)];
      
              bool feeOn = _mintFee(_reserve0, _reserve1);
              uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
              amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution
              amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution
              require(amount0 > 0 && amount1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED');
              _burn(address(this), liquidity);
              _safeTransfer(_token0, to, amount0);
              _safeTransfer(_token1, to, amount1);
              balance0 = IERC20(_token0).balanceOf(address(this));
              balance1 = IERC20(_token1).balanceOf(address(this));
      
              _update(balance0, balance1, _reserve0, _reserve1);
              if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
              emit Burn(msg.sender, amount0, amount1, to);
          }
      
          // this low-level function should be called from a contract which performs important safety checks
          function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
              require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT');
              (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
              require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY');
      
              uint balance0;
              uint balance1;
              { // scope for _token{0,1}, avoids stack too deep errors
              address _token0 = token0;
              address _token1 = token1;
              require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO');
              if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
              if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
              if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);
              balance0 = IERC20(_token0).balanceOf(address(this));
              balance1 = IERC20(_token1).balanceOf(address(this));
              }
              uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
              uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
              require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT');
              { // scope for reserve{0,1}Adjusted, avoids stack too deep errors
              uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));
              uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));
              require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K');
              }
      
              _update(balance0, balance1, _reserve0, _reserve1);
              emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
          }
      
          // force balances to match reserves
          function skim(address to) external lock {
              address _token0 = token0; // gas savings
              address _token1 = token1; // gas savings
              _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0));
              _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1));
          }
      
          // force reserves to match balances
          function sync() external lock {
              _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1);
          }
      }

      File 2 of 3: ANT
      pragma solidity ^0.4.8;
      
      contract ERC20 {
        function totalSupply() constant returns (uint);
        function balanceOf(address who) constant returns (uint);
        function allowance(address owner, address spender) constant returns (uint);
      
        function transfer(address to, uint value) returns (bool ok);
        function transferFrom(address from, address to, uint value) returns (bool ok);
        function approve(address spender, uint value) returns (bool ok);
        event Transfer(address indexed from, address indexed to, uint value);
        event Approval(address indexed owner, address indexed spender, uint value);
      }
      
      
      contract SafeMath {
        function safeMul(uint a, uint b) internal returns (uint) {
          uint c = a * b;
          assert(a == 0 || c / a == b);
          return c;
        }
      
        function safeDiv(uint a, uint b) internal returns (uint) {
          assert(b > 0);
          uint c = a / b;
          assert(a == b * c + a % b);
          return c;
        }
      
        function safeSub(uint a, uint b) internal returns (uint) {
          assert(b <= a);
          return a - b;
        }
      
        function safeAdd(uint a, uint b) internal returns (uint) {
          uint c = a + b;
          assert(c>=a && c>=b);
          return c;
        }
      
        function max64(uint64 a, uint64 b) internal constant returns (uint64) {
          return a >= b ? a : b;
        }
      
        function min64(uint64 a, uint64 b) internal constant returns (uint64) {
          return a < b ? a : b;
        }
      
        function max256(uint256 a, uint256 b) internal constant returns (uint256) {
          return a >= b ? a : b;
        }
      
        function min256(uint256 a, uint256 b) internal constant returns (uint256) {
          return a < b ? a : b;
        }
      
        function assert(bool assertion) internal {
          if (!assertion) {
            throw;
          }
        }
      }
      contract ApproveAndCallReceiver {
          function receiveApproval(address _from, uint256 _amount, address _token, bytes _data);
      }
      
      contract Controlled {
          /// @notice The address of the controller is the only address that can call
          ///  a function with this modifier
          modifier onlyController { if (msg.sender != controller) throw; _; }
      
          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 AbstractSale {
        function saleFinalized() constant returns (bool);
      }
      
      contract SaleWallet {
        // Public variables
        address public multisig;
        uint public finalBlock;
        AbstractSale public tokenSale;
      
        // @dev Constructor initializes public variables
        // @param _multisig The address of the multisig that will receive the funds
        // @param _finalBlock Block after which the multisig can request the funds
        function SaleWallet(address _multisig, uint _finalBlock, address _tokenSale) {
          multisig = _multisig;
          finalBlock = _finalBlock;
          tokenSale = AbstractSale(_tokenSale);
        }
      
        // @dev Receive all sent funds without any further logic
        function () public payable {}
      
        // @dev Withdraw function sends all the funds to the wallet if conditions are correct
        function withdraw() public {
          if (msg.sender != multisig) throw;                       // Only the multisig can request it
          if (block.number > finalBlock) return doWithdraw();      // Allow after the final block
          if (tokenSale.saleFinalized()) return doWithdraw();      // Allow when sale is finalized
        }
      
        function doWithdraw() internal {
          if (!multisig.send(this.balance)) throw;
        }
      }
      
      contract Controller {
          /// @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 ANPlaceholder is Controller {
        address public sale;
        ANT public token;
      
        function ANPlaceholder(address _sale, address _ant) {
          sale = _sale;
          token = ANT(_ant);
        }
      
        function changeController(address network) public {
          if (msg.sender != sale) throw;
          token.changeController(network);
          suicide(network);
        }
      
        // In between the sale and the network. Default settings for allowing token transfers.
        function proxyPayment(address _owner) payable public returns (bool) {
          throw;
          return false;
        }
      
        function onTransfer(address _from, address _to, uint _amount) public returns (bool) {
          return true;
        }
      
        function onApprove(address _owner, address _spender, uint _amount) public returns (bool) {
          return true;
        }
      }
      
      
      
      
      contract MiniMeToken is ERC20, 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
      
      
          /// @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;
      
          // `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 => Checkpoint[]) 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;
      
          // Flag that determines if the token is transferable or not.
          bool public transfersEnabled;
      
          // The factory used to create new clone tokens
          MiniMeTokenFactory public tokenFactory;
      
      ////////////////
      // Constructor
      ////////////////
      
          /// @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 _parentSnapShotBlock 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 _transfersEnabled If true, tokens will be able to be transferred
          function MiniMeToken(
              address _tokenFactory,
              address _parentToken,
              uint _parentSnapShotBlock,
              string _tokenName,
              uint8 _decimalUnits,
              string _tokenSymbol,
              bool _transfersEnabled
          ) {
              tokenFactory = MiniMeTokenFactory(_tokenFactory);
              name = _tokenName;                                 // Set the name
              decimals = _decimalUnits;                          // Set the decimals
              symbol = _tokenSymbol;                             // Set the symbol
              parentToken = MiniMeToken(_parentToken);
              parentSnapShotBlock = _parentSnapShotBlock;
              transfersEnabled = _transfersEnabled;
              creationBlock = block.number;
          }
      
      
      ///////////////////
      // ERC20 Methods
      ///////////////////
      
          /// @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) returns (bool success) {
              if (!transfersEnabled) throw;
              return doTransfer(msg.sender, _to, _amount);
          }
      
          /// @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
          ) 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) {
                  if (!transfersEnabled) throw;
      
                  // The standard ERC 20 transferFrom functionality
                  if (allowed[_from][msg.sender] < _amount) throw;
                  allowed[_from][msg.sender] -= _amount;
              }
              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) {
      
                 if (_amount == 0) {
                     return true;
                 }
      
                 // Do not allow transfer to 0x0 or the token contract itself
                 if ((_to == 0) || (_to == address(this))) throw;
      
                 // 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) {
                     throw;
                 }
      
                 // Alerts the token controller of the transfer
                 if (isContract(controller)) {
                     if (!Controller(controller).onTransfer(_from, _to, _amount)) throw;
                 }
      
                 // First update the balance array with the new value for the address
                 //  sending the tokens
                 updateValueAtNow(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);
                 if (previousBalanceTo + _amount < previousBalanceTo) throw; // Check for overflow
                 updateValueAtNow(balances[_to], previousBalanceTo + _amount);
      
                 // An event to make the transfer easy to find on the blockchain
                 Transfer(_from, _to, _amount);
      
                 return true;
          }
      
          /// @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);
          }
      
          /// @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) returns (bool success) {
              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 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 (isContract(controller)) {
                  if (!Controller(controller).onApprove(msg.sender, _spender, _amount))
                      throw;
              }
      
              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];
          }
      
          /// @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) {
              approve(_spender, _amount);
      
              // This portion is copied from ConsenSys's Standard Token Contract. It
              //  calls the receiveApproval function that is part of the contract that
              //  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 the plain vanilla approve would be used
              ApproveAndCallReceiver(_spender).receiveApproval(
                 msg.sender,
                 _amount,
                 this,
                 _extraData
              );
              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 `_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`
          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);
              }
          }
      
          /// @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);
              }
          }
      
          function min(uint a, uint b) internal returns (uint) {
            return a < b ? a : b;
          }
      
      ////////////////
      // 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 higher 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
              ) returns(address) {
              if (_snapshotBlock > block.number) _snapshotBlock = block.number;
              MiniMeToken cloneToken = tokenFactory.createCloneToken(
                  this,
                  _snapshotBlock,
                  _cloneTokenName,
                  _cloneDecimalUnits,
                  _cloneTokenSymbol,
                  _transfersEnabled
                  );
      
              cloneToken.changeController(msg.sender);
      
              // An event to make the token easy to find on the blockchain
              NewCloneToken(address(cloneToken), _snapshotBlock);
              return address(cloneToken);
          }
      
      ////////////////
      // Generate and destroy tokens
      ////////////////
      
          /// @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
          ) onlyController returns (bool) {
              uint curTotalSupply = getValueAt(totalSupplyHistory, block.number);
              if (curTotalSupply + _amount < curTotalSupply) throw; // Check for overflow
              updateValueAtNow(totalSupplyHistory, curTotalSupply + _amount);
              var previousBalanceTo = balanceOf(_owner);
              if (previousBalanceTo + _amount < previousBalanceTo) throw; // Check for overflow
              updateValueAtNow(balances[_owner], previousBalanceTo + _amount);
              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
          ) onlyController returns (bool) {
              uint curTotalSupply = getValueAt(totalSupplyHistory, block.number);
              if (curTotalSupply < _amount) throw;
              updateValueAtNow(totalSupplyHistory, curTotalSupply - _amount);
              var previousBalanceFrom = balanceOf(_owner);
              if (previousBalanceFrom < _amount) throw;
              updateValueAtNow(balances[_owner], previousBalanceFrom - _amount);
              Transfer(_owner, 0, _amount);
              return true;
          }
      
      ////////////////
      // 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 {
              transfersEnabled = _transfersEnabled;
          }
      
      ////////////////
      // 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 newCheckPoint = checkpoints[ checkpoints.length++ ];
                     newCheckPoint.fromBlock =  uint128(block.number);
                     newCheckPoint.value = uint128(_value);
                 } else {
                     Checkpoint 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
          function isContract(address _addr) constant internal returns(bool) {
              uint size;
              if (_addr == 0) return false;
              assembly {
                  size := extcodesize(_addr)
              }
              return size>0;
          }
      
          /// @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 {
              if (isContract(controller)) {
                  if (! Controller(controller).proxyPayment.value(msg.value)(msg.sender))
                      throw;
              } else {
                  throw;
              }
          }
      
      
      ////////////////
      // Events
      ////////////////
          event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock);
      }
      
      
      ////////////////
      // 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;
          }
      }
      
      
      /*
          Copyright 2017, Jorge Izquierdo (Aragon Foundation)
      
          Based on VestedToken.sol from https://github.com/OpenZeppelin/zeppelin-solidity
      
          SafeMath – Copyright (c) 2016 Smart Contract Solutions, Inc.
          MiniMeToken – Copyright 2017, Jordi Baylina (Giveth)
       */
      
      // @dev MiniMeIrrevocableVestedToken is a derived version of MiniMeToken adding the
      // ability to createTokenGrants which are basically a transfer that limits the
      // receiver of the tokens how can he spend them over time.
      
      // For simplicity, token grants are not saved in MiniMe type checkpoints.
      // Vanilla cloning ANT will clone it into a MiniMeToken without vesting.
      // More complex cloning could account for past vesting calendars.
      
      contract MiniMeIrrevocableVestedToken is MiniMeToken, SafeMath {
        // Keep the struct at 2 sstores (1 slot for value + 64 * 3 (dates) + 20 (address) = 2 slots (2nd slot is 212 bytes, lower than 256))
        struct TokenGrant {
          address granter;
          uint256 value;
          uint64 cliff;
          uint64 vesting;
          uint64 start;
        }
      
        event NewTokenGrant(address indexed from, address indexed to, uint256 value, uint64 start, uint64 cliff, uint64 vesting);
      
        mapping (address => TokenGrant[]) public grants;
      
        mapping (address => bool) canCreateGrants;
        address vestingWhitelister;
      
        modifier canTransfer(address _sender, uint _value) {
          if (_value > spendableBalanceOf(_sender)) throw;
          _;
        }
      
        modifier onlyVestingWhitelister {
          if (msg.sender != vestingWhitelister) throw;
          _;
        }
      
        function MiniMeIrrevocableVestedToken (
            address _tokenFactory,
            address _parentToken,
            uint _parentSnapShotBlock,
            string _tokenName,
            uint8 _decimalUnits,
            string _tokenSymbol,
            bool _transfersEnabled
        ) MiniMeToken(_tokenFactory, _parentToken, _parentSnapShotBlock, _tokenName, _decimalUnits, _tokenSymbol, _transfersEnabled) {
          vestingWhitelister = msg.sender;
          doSetCanCreateGrants(vestingWhitelister, true);
        }
      
        // @dev Add canTransfer modifier before allowing transfer and transferFrom to go through
        function transfer(address _to, uint _value)
                 canTransfer(msg.sender, _value)
                 public
                 returns (bool success) {
          return super.transfer(_to, _value);
        }
      
        function transferFrom(address _from, address _to, uint _value)
                 canTransfer(_from, _value)
                 public
                 returns (bool success) {
          return super.transferFrom(_from, _to, _value);
        }
      
        function spendableBalanceOf(address _holder) constant public returns (uint) {
          return transferableTokens(_holder, uint64(now));
        }
      
        function grantVestedTokens(
          address _to,
          uint256 _value,
          uint64 _start,
          uint64 _cliff,
          uint64 _vesting) public {
      
          // Check start, cliff and vesting are properly order to ensure correct functionality of the formula.
          if (_cliff < _start) throw;
          if (_vesting < _start) throw;
          if (_vesting < _cliff) throw;
      
          if (!canCreateGrants[msg.sender]) throw;
          if (tokenGrantsCount(_to) > 20) throw;   // To prevent a user being spammed and have his balance locked (out of gas attack when calculating vesting).
      
          TokenGrant memory grant = TokenGrant(msg.sender, _value, _cliff, _vesting, _start);
          grants[_to].push(grant);
      
          if (!transfer(_to, _value)) throw;
      
          NewTokenGrant(msg.sender, _to, _value, _cliff, _vesting, _start);
        }
      
        function setCanCreateGrants(address _addr, bool _allowed)
                 onlyVestingWhitelister public {
          doSetCanCreateGrants(_addr, _allowed);
        }
      
        function doSetCanCreateGrants(address _addr, bool _allowed)
                 internal {
          canCreateGrants[_addr] = _allowed;
        }
      
        function changeVestingWhitelister(address _newWhitelister) onlyVestingWhitelister public {
          doSetCanCreateGrants(vestingWhitelister, false);
          vestingWhitelister = _newWhitelister;
          doSetCanCreateGrants(vestingWhitelister, true);
        }
      
        // @dev Not allow token grants
        function revokeTokenGrant(address _holder, uint _grantId) public {
          throw;
        }
      
        //
        function tokenGrantsCount(address _holder) constant public returns (uint index) {
          return grants[_holder].length;
        }
      
        function tokenGrant(address _holder, uint _grantId) constant public returns (address granter, uint256 value, uint256 vested, uint64 start, uint64 cliff, uint64 vesting) {
          TokenGrant grant = grants[_holder][_grantId];
      
          granter = grant.granter;
          value = grant.value;
          start = grant.start;
          cliff = grant.cliff;
          vesting = grant.vesting;
      
          vested = vestedTokens(grant, uint64(now));
        }
      
        function vestedTokens(TokenGrant grant, uint64 time) internal constant returns (uint256) {
          return calculateVestedTokens(
            grant.value,
            uint256(time),
            uint256(grant.start),
            uint256(grant.cliff),
            uint256(grant.vesting)
          );
        }
      
        //  transferableTokens
        //   |                         _/--------   NonVestedTokens
        //   |                       _/
        //   |                     _/
        //   |                   _/
        //   |                 _/
        //   |                /
        //   |              .|
        //   |            .  |
        //   |          .    |
        //   |        .      |
        //   |      .        |
        //   |    .          |
        //   +===+===========+---------+----------> time
        //      Start       Clift    Vesting
      
        function calculateVestedTokens(
          uint256 tokens,
          uint256 time,
          uint256 start,
          uint256 cliff,
          uint256 vesting) internal constant returns (uint256)
          {
      
          // Shortcuts for before cliff and after vesting cases.
          if (time < cliff) return 0;
          if (time >= vesting) return tokens;
      
          // Interpolate all vested tokens.
          // As before cliff the shortcut returns 0, we can use just this function to
          // calculate it.
      
          // vestedTokens = tokens * (time - start) / (vesting - start)
          uint256 vestedTokens = safeDiv(
                                        safeMul(
                                          tokens,
                                          safeSub(time, start)
                                          ),
                                        safeSub(vesting, start)
                                        );
      
          return vestedTokens;
        }
      
        function nonVestedTokens(TokenGrant grant, uint64 time) internal constant returns (uint256) {
          // Of all the tokens of the grant, how many of them are not vested?
          // grantValue - vestedTokens
          return safeSub(grant.value, vestedTokens(grant, time));
        }
      
        // @dev The date in which all tokens are transferable for the holder
        // Useful for displaying purposes (not used in any logic calculations)
        function lastTokenIsTransferableDate(address holder) constant public returns (uint64 date) {
          date = uint64(now);
          uint256 grantIndex = tokenGrantsCount(holder);
          for (uint256 i = 0; i < grantIndex; i++) {
            date = max64(grants[holder][i].vesting, date);
          }
          return date;
        }
      
        // @dev How many tokens can a holder transfer at a point in time
        function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
          uint256 grantIndex = tokenGrantsCount(holder);
      
          if (grantIndex == 0) return balanceOf(holder); // shortcut for holder without grants
      
          // Iterate through all the grants the holder has, and add all non-vested tokens
          uint256 nonVested = 0;
          for (uint256 i = 0; i < grantIndex; i++) {
            nonVested = safeAdd(nonVested, nonVestedTokens(grants[holder][i], time));
          }
      
          // Balance - totalNonVested is the amount of tokens a holder can transfer at any given time
          return safeSub(balanceOf(holder), nonVested);
        }
      }
      
      /*
          Copyright 2017, Jorge Izquierdo (Aragon Foundation)
      */
      
      contract ANT is MiniMeIrrevocableVestedToken {
        // @dev ANT constructor just parametrizes the MiniMeIrrevocableVestedToken constructor
        function ANT(
          address _tokenFactory
        ) MiniMeIrrevocableVestedToken(
          _tokenFactory,
          0x0,                    // no parent token
          0,                      // no snapshot block number from parent
          "Aragon Network Token", // Token name
          18,                     // Decimals
          "ANT",                  // Symbol
          true                    // Enable transfers
          ) {}
      }

      File 3 of 3: ANPlaceholder
      contract ANT {
        function changeController(address network);
      }
      
      contract Controller {
          /// @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 ANPlaceholder is Controller {
        address public sale;
        ANT public token;
      
        function ANPlaceholder(address _sale, address _ant) {
          sale = _sale;
          token = ANT(_ant);
        }
      
        function changeController(address network) public {
          if (msg.sender != sale) throw;
          token.changeController(network);
          suicide(network);
        }
      
        // In between the sale and the network. Default settings for allowing token transfers.
        function proxyPayment(address _owner) payable public returns (bool) {
          throw;
          return false;
        }
      
        function onTransfer(address _from, address _to, uint _amount) public returns (bool) {
          return true;
        }
      
        function onApprove(address _owner, address _spender, uint _amount) public returns (bool) {
          return true;
        }
      }