contract TokenSales {
  using SafeMath for uint256;

  // Event for token purchase logging
  // @param token that was sold
  // @param seller who sold the tokens
  // @param purchaser who paid for the tokens
  // @param value weis paid for purchase
  // @param amount amount of tokens purchased
  event TokenPurchase(
    address indexed token,
    address indexed seller,
    address indexed purchaser,
    uint256 value,
    uint256 amount
  );

  mapping(address => mapping(address => uint)) public saleAmounts;
  mapping(address => mapping(address => uint)) public saleRates;

  // @dev create a sale of tokens.
  // @param _token - must be an ERC20 token
  // @param _rate - how many token units a buyer gets per wei.
  //   The rate is the conversion between wei and the smallest and indivisible token unit.
  //   So, if you are using a rate of 1 with a DetailedERC20 token with 3 decimals called TOK
  //   1 wei will give you 1 unit, or 0.001 TOK.
  // @param _addedTokens - the number of tokens to add to the sale
  function createSale(iERC20 token, uint256 rate, uint256 addedTokens) public {
    uint currentSaleAmount = saleAmounts[msg.sender][token];
    if(addedTokens > 0 || currentSaleAmount > 0) {
      saleRates[msg.sender][token] = rate;
    }
    if (addedTokens > 0) {
      saleAmounts[msg.sender][token] = currentSaleAmount.add(addedTokens);
      token.transferFrom(msg.sender, address(this), addedTokens);
    }
  }

  // @dev A payable function that takes ETH, and pays out in the token specified.
  // @param seller - address selling the token
  // @param token - the token address
  function buy(iERC20 token, address seller) public payable {
    uint size;
    address sender = msg.sender;
    assembly { size := extcodesize(sender) }
    require(size == 0); // Disallow calling from contracts, for safety
    uint256 weiAmount = msg.value;
    require(weiAmount > 0);

    uint rate = saleRates[seller][token];
    uint amount = saleAmounts[seller][token];
    require(rate > 0);

    uint256 tokens = weiAmount.mul(rate);
    saleAmounts[seller][token] = amount.sub(tokens);

    emit TokenPurchase(
      token,
      seller,
      msg.sender,
      weiAmount,
      tokens
    );

    token.transfer(msg.sender, tokens);
    seller.transfer(msg.value);
  }

  // dev Cancels all the sender's sales of a given token
  // @param token - the address of the token to be cancelled.
  function cancelSale(iERC20 token) public {
    uint amount = saleAmounts[msg.sender][token];
    require(amount > 0);

    delete saleAmounts[msg.sender][token];
    delete saleRates[msg.sender][token];

    if (amount > 0) {
      token.transfer(msg.sender, amount);
    }
  }

  // @dev fallback function always throws
  function () external payable {
    revert();
  }
}
// @title Token Sale Network
// A contract allowing users to buy a supply of tokens
// Adapted from OpenZeppelin's Crowdsale contract
// 
function () external payable {
    revert();
  }
// @dev fallback function always throws