Change some if..throw to asserts.

Change some if..throw to asserts.

pragma solidity ^0.4.10;
import './SafeMath.sol';

contract TokenSyndicate {
    uint256 public constant kwei = 1000;

    address public tokenContract;
    uint256 public tokenExchangeRate;
    uint256 public minBountyPerKwei;
    uint256 public maxPresaleEthAllowed;
    uint256 public presaleStartBlock;
    uint256 public presaleEndBlock;
    address public winner;

    uint256 public totalPresale;
    uint256 public totalBounties;

    mapping(address => uint256) public presaleBalances;
    mapping(address => uint256) public bountyBalances;

    event LogCreatePresaleInvestment(address indexed _to, uint256 bounty, uint256 presale);
    event LogRefundPresaleInvestment(address indexed _to, uint256 bounty, uint256 presale);
    event LogWithdrawTokens(address indexed _to, uint256 tokens);
    event LogWithdrawBounty(address indexed _to, uint256 bounty);

    function TokenSyndicate(
    address _tokenContract,
    uint256 _tokenExchangeRate,
    uint256 _minBountyPerKwei,
    uint256 _maxPresaleEthAllowed,
    uint256 _presaleStartBlock,
    uint256 _presaleEndBlock){
        if (_minBountyPerKwei >= kwei) throw;  // you may not have a bounty of 100% or more.
        if (_minBountyPerKwei == 0) throw;     // you must provide a bounty.
        if (_maxPresaleEthAllowed == 0) throw;
        if (_tokenContract == address(0)) throw;
        if (_tokenExchangeRate == 0) throw;
        if(_presaleStartBlock >= _presaleEndBlock) throw;     // the presale must start before it finishes.

        tokenContract = _tokenContract;
        tokenExchangeRate = _tokenExchangeRate;
        minBountyPerKwei = _minBountyPerKwei;
        maxPresaleEthAllowed = _maxPresaleEthAllowed;
        presaleStartBlock = _presaleStartBlock;
        presaleEndBlock = _presaleEndBlock;

        totalPresale = 0;
        totalBounties = 0;
        winner = address(0);
    }

    /*
        Invest in this contract in order to have tokens purchased on your behalf when the buyTokens() contract
        is called without a `throw`.
    */
    function createPresaleInvestment(uint256 _bountyPerKwei) payable external {
        assert(block.number > presaleStartBlock);
        assert(block.number < presaleEndBlock);
        assert(_bountyPerKwei >= minBountyPerKwei);
        assert(msg.value > 0);

        /*
            As the EVM does not currently support decimals, we are multiplying both msg.value and the bounty
            by 1000 before calculating the bounty ratio in order to gain a reasonable degree of precision.
        */
        uint256 bountyWithKweiPrecision = SafeMath.div(SafeMath.mul(msg.value, kwei), SafeMath.mul(_bountyPerKwei, kwei));
        uint256 final_bounty = SafeMath.div(msg.value, bountyWithKweiPrecision);
        uint256 final_presale = SafeMath.sub(msg.value, final_bounty);

        bountyBalances[msg.sender] += final_bounty;
        presaleBalances[msg.sender] += final_presale;
        totalBounties += final_bounty;
        totalPresale += final_presale;
        assert(totalPresale <= maxPresaleEthAllowed);
        LogCreatePresaleInvestment(msg.sender, final_bounty, final_presale);       // create an event
    }

    /*
        Get the presaleBalance (ETH) and bountyBalance (ETH) for an address.
    */
    function balanceOf(address _owner) constant returns (uint256 presaleBalance, uint256 bountyBalance) {
        return (presaleBalances[_owner], bountyBalances[_owner]);
    }

    /*
        If the 'winner' address is address(0), there has been no winner yet.
    */
    modifier onlyWithoutWinner() {
        assert(winner == address(0));
        _;
    }

    /*
        If the 'winner' address is anything other than address(0), there has been a winner.
    */
    modifier onlyWithWinner() {
        assert(winner != address(0));
        _;
    }

    /*
           Attempt to purchase the tokens from the token contract.
           Whichever address manages to successfully purchase/create the tokens will be the 'winner'.
           The 'winner' is allowed to withdraw the bounties from this contract.
    */
    function buyTokens() external onlyWithoutWinner {
        winner = msg.sender;
        if(!tokenContract.call.value(totalPresale)(bytes4(sha3("createTokens()")))) throw;
    }

    function withdrawTokens() onlyWithWinner {
        uint256 tokens = SafeMath.mul(presaleBalances[msg.sender], tokenExchangeRate);
        assert(tokens > 0);

        totalPresale = SafeMath.sub(totalPresale, presaleBalances[msg.sender]);
        presaleBalances[msg.sender] = 0;

        /*
               Attempt to transfer tokens to msg.sender.
               Note: we are relying on the token contract to return a success bool (true for success). If this
               bool is not implemented as expected it may be possible for an account to withdraw more tokens than
               it is entitled to.
        */
        if(!tokenContract.call(bytes4(sha3('transfer(address,uint256)')), msg.sender, tokens)) throw;
        LogWithdrawTokens(msg.sender, tokens);
    }

    /*
        Collect the bounty for successfully executing the token purchase.
    */
    function withdrawBounty() external onlyWithWinner {
        assert(msg.sender == winner);
        assert(totalBounties > 0);

        uint256 entitlement = totalBounties;
        totalBounties = 0;

        msg.sender.transfer(entitlement);
        LogWithdrawBounty(msg.sender, entitlement);
    }

    /*
        Refund an accounts investment and bounty.
        This is only possible if there has not been a 'winner' (ie, if tokens have not been purchased).
    */
    function refundPresaleInvestment() external onlyWithoutWinner {
        uint256 bountyValue = bountyBalances[msg.sender];
        uint256 presaleValue = presaleBalances[msg.sender];
        uint256 totalValue = SafeMath.add(bountyValue, presaleValue);

        if(bountyValue == 0) throw;
        if(presaleValue == 0) throw;

        bountyBalances[msg.sender] = 0;
        presaleBalances[msg.sender] = 0;
        totalBounties = SafeMath.sub(totalBounties, bountyValue);
        totalPresale = SafeMath.sub(totalPresale, presaleValue);
        msg.sender.transfer(totalValue);
        LogRefundPresaleInvestment(msg.sender, bountyValue, presaleValue);
    }
}

pragma solidity ^0.4.10;
import './SafeMath.sol';

contract TokenSyndicate {
    uint256 public constant kwei = 1000;

    address public tokenContract;
    uint256 public tokenExchangeRate;
    uint256 public minBountyPerKwei;
    uint256 public maxPresaleEthAllowed;
    uint256 public presaleStartBlock;
    uint256 public presaleEndBlock;
    address public winner;

    uint256 public totalPresale;
    uint256 public totalBounties;

    mapping(address => uint256) public presaleBalances;
    mapping(address => uint256) public bountyBalances;

    event LogCreatePresaleInvestment(address indexed _to, uint256 bounty, uint256 presale);
    event LogRefundPresaleInvestment(address indexed _to, uint256 bounty, uint256 presale);
    event LogWithdrawTokens(address indexed _to, uint256 tokens);
    event LogWithdrawBounty(address indexed _to, uint256 bounty);

    function TokenSyndicate(
    address _tokenContract,
    uint256 _tokenExchangeRate,
    uint256 _minBountyPerKwei,
    uint256 _maxPresaleEthAllowed,
    uint256 _presaleStartBlock,
    uint256 _presaleEndBlock){
        if (_minBountyPerKwei >= kwei) throw;  // you may not have a bounty of 100% or more.
        if (_minBountyPerKwei == 0) throw;     // you must provide a bounty.
        if (_maxPresaleEthAllowed == 0) throw;
        if (_tokenContract == address(0)) throw;
        if (_tokenExchangeRate == 0) throw;
        if(_presaleStartBlock >= _presaleEndBlock) throw;     // the presale must start before it finishes.

        tokenContract = _tokenContract;
        tokenExchangeRate = _tokenExchangeRate;
        minBountyPerKwei = _minBountyPerKwei;
        maxPresaleEthAllowed = _maxPresaleEthAllowed;
        presaleStartBlock = _presaleStartBlock;
        presaleEndBlock = _presaleEndBlock;

        totalPresale = 0;
        totalBounties = 0;
        winner = address(0);
    }

    /*
        Invest in this contract in order to have tokens purchased on your behalf when the buyTokens() contract
        is called without a `throw`.
    */
    function createPresaleInvestment(uint256 bountyPerKwei) payable external {
        if(block.number < presaleStartBlock) throw; // you must call within the block time bounds of the presale.
        if(block.number > presaleEndBlock) throw;   // as above ^
        if(bountyPerKwei < minBountyPerKwei) throw;       // you must provide a bounty/kw above or equal to the minimum bounty/kw.
        if(msg.value == 0) throw;                   // you must provide some eth.

        /*
            As the EVM does not currently support decimals, we are multiplying both msg.value and the bounty
            by 1000 before calculating the bounty ratio in order to gain a reasonable degree of precision.
        */
        uint256 bountyWithKweiPrecision = SafeMath.div(SafeMath.mul(msg.value, kwei), SafeMath.mul(bountyPerKwei, kwei));
        uint256 final_bounty = SafeMath.div(msg.value, bountyWithKweiPrecision);
        uint256 final_presale = SafeMath.sub(msg.value, final_bounty);

        bountyBalances[msg.sender] += final_bounty;
        presaleBalances[msg.sender] += final_presale;
        totalBounties += final_bounty;
        totalPresale += final_presale;
        assert(totalPresale <= maxPresaleEthAllowed);
        LogCreatePresaleInvestment(msg.sender, final_bounty, final_presale);       // create an event
    }

    /*
        Get the presaleBalance (ETH) and bountyBalance (ETH) for an address.
    */
    function balanceOf(address _owner) constant returns (uint256 presaleBalance, uint256 bountyBalance) {
        return (presaleBalances[_owner], bountyBalances[_owner]);
    }

    /*
        If the 'winner' address is address(0), there has been no winner yet.
    */
    modifier onlyWithoutWinner() {
        assert(winner == address(0));
        _;
    }

    /*
        If the 'winner' address is anything other than address(0), there has been a winner.
    */
    modifier onlyWithWinner() {
        assert(winner != address(0));
        _;
    }

    /*
           Attempt to purchase the tokens from the token contract.
           Whichever address manages to successfully purchase/create the tokens will be the 'winner'.
           The 'winner' is allowed to withdraw the bounties from this contract.
    */
    function buyTokens() external onlyWithoutWinner {
        winner = msg.sender;
        if(!tokenContract.call.value(totalPresale)(bytes4(sha3("createTokens()")))) throw;
    }

    function withdrawTokens() onlyWithWinner {
        uint256 tokens = SafeMath.mul(presaleBalances[msg.sender], tokenExchangeRate);
        assert(tokens > 0);

        totalPresale = SafeMath.sub(totalPresale, presaleBalances[msg.sender]);
        presaleBalances[msg.sender] = 0;

        /*
               Attempt to transfer tokens to msg.sender.
               Note: we are relying on the token contract to return a success bool (true for success). If this
               bool is not implemented as expected it may be possible for an account to withdraw more tokens than
               it is entitled to.
        */
        if(!tokenContract.call(bytes4(sha3('transfer(address,uint256)')), msg.sender, tokens)) throw;
        LogWithdrawTokens(msg.sender, tokens);
    }

    /*
        Collect the bounty for successfully executing the token purchase.
    */
    function withdrawBounty() external onlyWithWinner {
        assert(msg.sender == winner);
        assert(totalBounties > 0);

        uint256 entitlement = totalBounties;
        totalBounties = 0;

        msg.sender.transfer(entitlement);
        LogWithdrawBounty(msg.sender, entitlement);
    }

    /*
        Refund an accounts investment and bounty.
        This is only possible if there has not been a 'winner' (ie, if tokens have not been purchased).
    */
    function refundPresaleInvestment() external onlyWithoutWinner {
        uint256 bountyValue = bountyBalances[msg.sender];
        uint256 presaleValue = presaleBalances[msg.sender];
        uint256 totalValue = SafeMath.add(bountyValue, presaleValue);

        if(bountyValue == 0) throw;
        if(presaleValue == 0) throw;

        bountyBalances[msg.sender] = 0;
        presaleBalances[msg.sender] = 0;
        totalBounties = SafeMath.sub(totalBounties, bountyValue);
        totalPresale = SafeMath.sub(totalPresale, presaleValue);
        msg.sender.transfer(totalValue);
        LogRefundPresaleInvestment(msg.sender, bountyValue, presaleValue);
    }
}


removing uneeded address() calls

removing uneeded address() calls

/*
    Copyright 2017 Phillip A. Elsasser

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

pragma solidity 0.4.18;

import "./libraries/MathLib.sol";
import "./tokens/MarketToken.sol";
import "./Linkable.sol";
import "./MarketContract.sol";

import "zeppelin-solidity/contracts/token/SafeERC20.sol";
import "zeppelin-solidity/contracts/token/ERC20.sol";

/// @title MarketCollateralPool is a contract controlled by a specific Market Contract.  It holds collateral balances
/// as well as user balances and open positions.  It should be instantiated and then linked by a MarketContract.
/// @author Phil Elsasser <phil@marketprotcol.io>
contract MarketCollateralPool is Linkable {
    using MathLib for uint;
    using MathLib for int;
    using SafeERC20 for ERC20;

    struct UserNetPosition {
        address userAddress;
        Position[] positions;   // all open positions (lifo upon exit - allows us to not reindex array!)
        int netPosition;        // net position across all prices / executions
    }

    struct Position {
        uint price;
        int qty;
    }

    uint public collateralPoolBalance;                                 // current balance of all collateral committed
    mapping(address => UserNetPosition) addressToUserPosition;
    mapping(address => uint) public userAddressToAccountBalance;       // stores account balances allowed to be allocated to orders
    address public MKT_TOKEN_ADDRESS;
    MarketToken MKT_TOKEN;
    MarketContract MKT_CONTRACT;

    event UpdatedUserBalance(address indexed user, uint balance);
    event UpdatedPoolBalance(uint balance);

    /// @dev instantiates a collateral pool that is unique to the supplied address of a MarketContract. This pairing
    /// is 1:1
    /// @param marketContractAddress deployed address of a MarketContract
    function MarketCollateralPool(address marketContractAddress) Linkable(marketContractAddress) public {
        MKT_CONTRACT = MarketContract(marketContractAddress);
        MKT_TOKEN_ADDRESS = MKT_CONTRACT.MKT_TOKEN_ADDRESS();
        MKT_TOKEN = MarketToken(MKT_TOKEN_ADDRESS);
    }

    /// @notice get the net position for a give user address
    /// @param userAddress address to return position for
    /// @return the users current open position.
    function getUserPosition(address userAddress) external view returns (int) {
        return addressToUserPosition[userAddress].netPosition;
    }

    /// @param userAddress address of user
    /// @return the users currently unallocated token balance
    function getUserAccountBalance(address userAddress) external view returns (uint) {
        return userAddressToAccountBalance[userAddress];
    }

    /*
    // EXTERNAL METHODS
    */

    /// @notice deposits tokens to the smart contract to fund the user account and provide needed tokens for collateral
    /// pool upon trade matching.
    /// @param depositAmount qty of ERC20 tokens to deposit to the smart contract to cover open orders and collateral
    function depositTokensForTrading(uint256 depositAmount) external {
        // user must call approve!
        require(MKT_TOKEN.isUserEnabledForContract(MKT_CONTRACT, msg.sender));
        uint256 balanceAfterDeposit = userAddressToAccountBalance[msg.sender].add(depositAmount);
        ERC20(MKT_CONTRACT.BASE_TOKEN_ADDRESS()).safeTransferFrom(msg.sender, this, depositAmount);
        userAddressToAccountBalance[msg.sender] = balanceAfterDeposit;
        UpdatedUserBalance(msg.sender, balanceAfterDeposit);
    }

    // @notice called by a user after settlement has occurred.  This function will finalize all accounting around any
    // outstanding positions and return all remaining collateral to the caller. This should only be called after
    // settlement has occurred.
    function settleAndClose() external {
        require(MKT_CONTRACT.isSettled());
        require(MKT_TOKEN.isUserEnabledForContract(MKT_CONTRACT, msg.sender));
        UserNetPosition storage userNetPos = addressToUserPosition[msg.sender];
        if (userNetPos.netPosition != 0) {
            // this user has a position that we need to settle based upon the settlement price of the contract
            reduceUserNetPosition(
                userNetPos,
                msg.sender,
                userNetPos.netPosition * - 1,
                MKT_CONTRACT.settlementPrice()
            );
        }
        // transfer all balances back to user.
        withdrawTokens(userAddressToAccountBalance[msg.sender]);
    }

    /// @dev called by our linked MarketContract when a trade occurs to update both maker and takers positions.
    /// @param maker address of the maker in the trade
    /// @param taker address of the taker in the trade
    /// @param qty quantity transacted between parties
    /// @param price agreed price of the matched trade.
    function updatePositions(
        address maker,
        address taker,
        int qty,
        uint price
    ) external onlyLinked
    {
        updatePosition(
            maker,
            qty,
            price
        );
        // continue process for taker, but qty is opposite sign for taker
        updatePosition(
            taker,
            qty * -1,
            price
        );
    }

    /*
    // PUBLIC METHODS
    */

    /// @notice removes token from users trading account
    /// @param withdrawAmount qty of token to attempt to withdraw
    function withdrawTokens(uint256 withdrawAmount) public {
        require(userAddressToAccountBalance[msg.sender] >= withdrawAmount);   // ensure sufficient balance
        uint256 balanceAfterWithdrawal = userAddressToAccountBalance[msg.sender].subtract(withdrawAmount);
        userAddressToAccountBalance[msg.sender] = balanceAfterWithdrawal;   // update balance before external call!
        ERC20(MKT_CONTRACT.BASE_TOKEN_ADDRESS()).safeTransfer(msg.sender, withdrawAmount);
        UpdatedUserBalance(msg.sender, balanceAfterWithdrawal);
    }

    /*
    // PRIVATE METHODS
    */

    /// @notice moves collateral from a user's account to the pool upon trade execution.
    /// @param fromAddress address of user entering trade
    /// @param collateralAmount amount of collateral to transfer from user account to collateral pool
    function commitCollateralToPool(
        address fromAddress,
        uint collateralAmount
    ) private
    {
        require(MKT_TOKEN.isUserEnabledForContract(MKT_CONTRACT, msg.sender));
        require(userAddressToAccountBalance[fromAddress] >= collateralAmount);   // ensure sufficient balance
        uint newBalance = userAddressToAccountBalance[fromAddress].subtract(collateralAmount);
        userAddressToAccountBalance[fromAddress] = newBalance;
        collateralPoolBalance = collateralPoolBalance.add(collateralAmount);
        UpdatedUserBalance(fromAddress, newBalance);
        UpdatedPoolBalance(collateralPoolBalance);
    }

    /// @notice withdraws collateral from pool to a user account upon exit or trade settlement
    /// @param toAddress address of user
    /// @param collateralAmount amount to transfer from pool to user.
    function withdrawCollateralFromPool(
        address toAddress,
        uint collateralAmount
    ) private
    {
        require(MKT_TOKEN.isUserEnabledForContract(MKT_CONTRACT, msg.sender));
        require(collateralPoolBalance >= collateralAmount); // ensure sufficient balance
        uint newBalance = userAddressToAccountBalance[toAddress].add(collateralAmount);
        userAddressToAccountBalance[toAddress] = newBalance;
        collateralPoolBalance = collateralPoolBalance.subtract(collateralAmount);
        UpdatedUserBalance(toAddress, newBalance);
        UpdatedPoolBalance(collateralPoolBalance);
    }

    /// @dev handles all needed internal accounting when a user enters into a new trade
    /// @param userAddress storage struct containing position information for this user
    /// @param qty signed quantity this users position is changing by, + for buy and - for sell
    /// @param price transacted price of the new position / trade
    function updatePosition(
        address userAddress,
        int qty,
        uint price
    ) private
    {
        UserNetPosition storage userNetPosition = addressToUserPosition[userAddress];
        if (userNetPosition.netPosition == 0 || userNetPosition.netPosition.isSameSign(qty)) {
            // new position or adding to open pos
            addUserNetPosition(
                userNetPosition,
                userAddress,
                qty,
                price
            );
        } else {  // opposite side from open position, reduce, flattened, or flipped.
            if (userNetPosition.netPosition >= qty * -1) { // pos is reduced or flattened
                reduceUserNetPosition(
                    userNetPosition,
                    userAddress,
                    qty,
                    price
                );
            } else {    // pos is flipped, reduce and then create new open pos!

                reduceUserNetPosition(
                    userNetPosition,
                    userAddress,
                    userNetPosition.netPosition * -1,
                    price
                ); // flatten completely

                int newNetPos = userNetPosition.netPosition + qty;            // the portion remaining after flattening
                addUserNetPosition(
                    userNetPosition,
                    userAddress,
                    newNetPos,
                    price
                );
            }
        }
        userNetPosition.netPosition = userNetPosition.netPosition.add(qty);   // keep track of total net pos across all prices for user.
    }

    /// @dev calculates the needed collateral for a new position and commits it to the pool removing it from the
    /// users account and creates the needed Position struct to record the new position.
    /// @param userNetPosition current positions held by user
    /// @param userAddress address of user entering into the position
    /// @param qty signed quantity of the trade
    /// @param price agreed price of trade
    function addUserNetPosition(
        UserNetPosition storage userNetPosition,
        address userAddress,
        int qty,
        uint price
    ) private
    {
        uint neededCollateral = MathLib.calculateNeededCollateral(
            MKT_CONTRACT.PRICE_FLOOR(),
            MKT_CONTRACT.PRICE_CAP(),
            MKT_CONTRACT.QTY_DECIMAL_PLACES(),
            qty,
            price
        );
        commitCollateralToPool(userAddress, neededCollateral);
        userNetPosition.positions.push(Position(price, qty));   // append array with new position
    }

    /// @dev reduces net position correctly allocating collateral back to user
    /// @param userNetPos storage struct for this users position
    /// @param userAddress address of user who is reducing their pos
    /// @param qty signed quantity of the qty to reduce this users position by
    /// @param price transacted price
    function reduceUserNetPosition(
        UserNetPosition storage userNetPos,
        address userAddress,
        int qty,
        uint price
    ) private
    {
        uint collateralToReturnToUserAccount = 0;
        int qtyToReduce = qty;                      // note: this sign is opposite of our users position
        assert(userNetPos.positions.length != 0);   // sanity check
        while (qtyToReduce != 0) {   //TODO: ensure we dont run out of gas here!
            Position storage position = userNetPos.positions[userNetPos.positions.length - 1];  // get the last pos (LIFO)
            if (position.qty.abs() <= qtyToReduce.abs()) {   // this position is completely consumed!
                collateralToReturnToUserAccount = collateralToReturnToUserAccount.add(
                    MathLib.calculateNeededCollateral(
                        MKT_CONTRACT.PRICE_FLOOR(),
                        MKT_CONTRACT.PRICE_CAP(),
                        MKT_CONTRACT.QTY_DECIMAL_PLACES(),
                        position.qty,
                        price
                    )
                );
                qtyToReduce = qtyToReduce.add(position.qty);
                userNetPos.positions.length--;  // remove this position from our array.
            } else {  // this position stays, just reduce the qty.
                position.qty = position.qty.add(qtyToReduce);
                // pos is opp sign of qty we are reducing here!
                collateralToReturnToUserAccount = collateralToReturnToUserAccount.add(
                    MathLib.calculateNeededCollateral(
                        MKT_CONTRACT.PRICE_FLOOR(),
                        MKT_CONTRACT.PRICE_CAP(),
                        MKT_CONTRACT.QTY_DECIMAL_PLACES(),
                        qtyToReduce * -1,
                        price
                    )
                );
                //qtyToReduce = 0; // completely reduced now!
                break;
            }
        }

        if (collateralToReturnToUserAccount != 0) {  // allocate funds back to user acct.
            withdrawCollateralFromPool(userAddress, collateralToReturnToUserAccount);
        }
    }
}

/*
    Copyright 2017 Phillip A. Elsasser

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

pragma solidity 0.4.18;

import "./libraries/MathLib.sol";
import "./tokens/MarketToken.sol";
import "./Linkable.sol";
import "./MarketContract.sol";

import "zeppelin-solidity/contracts/token/SafeERC20.sol";
import "zeppelin-solidity/contracts/token/ERC20.sol";

/// @title MarketCollateralPool is a contract controlled by a specific Market Contract.  It holds collateral balances
/// as well as user balances and open positions.  It should be instantiated and then linked by a MarketContract.
/// @author Phil Elsasser <phil@marketprotcol.io>
contract MarketCollateralPool is Linkable {
    using MathLib for uint;
    using MathLib for int;
    using SafeERC20 for ERC20;

    struct UserNetPosition {
        address userAddress;
        Position[] positions;   // all open positions (lifo upon exit - allows us to not reindex array!)
        int netPosition;        // net position across all prices / executions
    }

    struct Position {
        uint price;
        int qty;
    }

    uint public collateralPoolBalance;                                 // current balance of all collateral committed
    mapping(address => UserNetPosition) addressToUserPosition;
    mapping(address => uint) public userAddressToAccountBalance;       // stores account balances allowed to be allocated to orders
    address public MKT_TOKEN_ADDRESS;
    MarketToken MKT_TOKEN;
    MarketContract MKT_CONTRACT;

    event UpdatedUserBalance(address indexed user, uint balance);
    event UpdatedPoolBalance(uint balance);

    /// @dev instantiates a collateral pool that is unique to the supplied address of a MarketContract. This pairing
    /// is 1:1
    /// @param marketContractAddress deployed address of a MarketContract
    function MarketCollateralPool(address marketContractAddress) Linkable(marketContractAddress) public {
        MKT_CONTRACT = MarketContract(marketContractAddress);
        MKT_TOKEN_ADDRESS = MKT_CONTRACT.MKT_TOKEN_ADDRESS();
        MKT_TOKEN = MarketToken(MKT_TOKEN_ADDRESS);
    }

    /// @notice get the net position for a give user address
    /// @param userAddress address to return position for
    /// @return the users current open position.
    function getUserPosition(address userAddress) external view returns (int) {
        return addressToUserPosition[userAddress].netPosition;
    }

    /// @param userAddress address of user
    /// @return the users currently unallocated token balance
    function getUserAccountBalance(address userAddress) external view returns (uint) {
        return userAddressToAccountBalance[userAddress];
    }

    /*
    // EXTERNAL METHODS
    */

    /// @notice deposits tokens to the smart contract to fund the user account and provide needed tokens for collateral
    /// pool upon trade matching.
    /// @param depositAmount qty of ERC20 tokens to deposit to the smart contract to cover open orders and collateral
    function depositTokensForTrading(uint256 depositAmount) external {
        // user must call approve!
        require(MKT_TOKEN.isUserEnabledForContract(address(MKT_CONTRACT), msg.sender));
        uint256 balanceAfterDeposit = userAddressToAccountBalance[msg.sender].add(depositAmount);
        ERC20(MKT_CONTRACT.BASE_TOKEN_ADDRESS()).safeTransferFrom(msg.sender, this, depositAmount);
        userAddressToAccountBalance[msg.sender] = balanceAfterDeposit;
        UpdatedUserBalance(msg.sender, balanceAfterDeposit);
    }

    // @notice called by a user after settlement has occurred.  This function will finalize all accounting around any
    // outstanding positions and return all remaining collateral to the caller. This should only be called after
    // settlement has occurred.
    function settleAndClose() external {
        require(MKT_CONTRACT.isSettled());
        require(MKT_TOKEN.isUserEnabledForContract(address(MKT_CONTRACT), msg.sender));
        UserNetPosition storage userNetPos = addressToUserPosition[msg.sender];
        if (userNetPos.netPosition != 0) {
            // this user has a position that we need to settle based upon the settlement price of the contract
            reduceUserNetPosition(
                userNetPos,
                msg.sender,
                userNetPos.netPosition * - 1,
                MKT_CONTRACT.settlementPrice()
            );
        }
        // transfer all balances back to user.
        withdrawTokens(userAddressToAccountBalance[msg.sender]);
    }

    /// @dev called by our linked MarketContract when a trade occurs to update both maker and takers positions.
    /// @param maker address of the maker in the trade
    /// @param taker address of the taker in the trade
    /// @param qty quantity transacted between parties
    /// @param price agreed price of the matched trade.
    function updatePositions(
        address maker,
        address taker,
        int qty,
        uint price
    ) external onlyLinked
    {
        updatePosition(
            maker,
            qty,
            price
        );
        // continue process for taker, but qty is opposite sign for taker
        updatePosition(
            taker,
            qty * -1,
            price
        );
    }

    /*
    // PUBLIC METHODS
    */

    /// @notice removes token from users trading account
    /// @param withdrawAmount qty of token to attempt to withdraw
    function withdrawTokens(uint256 withdrawAmount) public {
        require(userAddressToAccountBalance[msg.sender] >= withdrawAmount);   // ensure sufficient balance
        uint256 balanceAfterWithdrawal = userAddressToAccountBalance[msg.sender].subtract(withdrawAmount);
        userAddressToAccountBalance[msg.sender] = balanceAfterWithdrawal;   // update balance before external call!
        ERC20(MKT_CONTRACT.BASE_TOKEN_ADDRESS()).safeTransfer(msg.sender, withdrawAmount);
        UpdatedUserBalance(msg.sender, balanceAfterWithdrawal);
    }

    /*
    // PRIVATE METHODS
    */

    /// @notice moves collateral from a user's account to the pool upon trade execution.
    /// @param fromAddress address of user entering trade
    /// @param collateralAmount amount of collateral to transfer from user account to collateral pool
    function commitCollateralToPool(
        address fromAddress,
        uint collateralAmount
    ) private
    {
        require(MKT_TOKEN.isUserEnabledForContract(address(MKT_CONTRACT), msg.sender));
        require(userAddressToAccountBalance[fromAddress] >= collateralAmount);   // ensure sufficient balance
        uint newBalance = userAddressToAccountBalance[fromAddress].subtract(collateralAmount);
        userAddressToAccountBalance[fromAddress] = newBalance;
        collateralPoolBalance = collateralPoolBalance.add(collateralAmount);
        UpdatedUserBalance(fromAddress, newBalance);
        UpdatedPoolBalance(collateralPoolBalance);
    }

    /// @notice withdraws collateral from pool to a user account upon exit or trade settlement
    /// @param toAddress address of user
    /// @param collateralAmount amount to transfer from pool to user.
    function withdrawCollateralFromPool(
        address toAddress,
        uint collateralAmount
    ) private
    {
        require(MKT_TOKEN.isUserEnabledForContract(address(MKT_CONTRACT), msg.sender));
        require(collateralPoolBalance >= collateralAmount); // ensure sufficient balance
        uint newBalance = userAddressToAccountBalance[toAddress].add(collateralAmount);
        userAddressToAccountBalance[toAddress] = newBalance;
        collateralPoolBalance = collateralPoolBalance.subtract(collateralAmount);
        UpdatedUserBalance(toAddress, newBalance);
        UpdatedPoolBalance(collateralPoolBalance);
    }

    /// @dev handles all needed internal accounting when a user enters into a new trade
    /// @param userAddress storage struct containing position information for this user
    /// @param qty signed quantity this users position is changing by, + for buy and - for sell
    /// @param price transacted price of the new position / trade
    function updatePosition(
        address userAddress,
        int qty,
        uint price
    ) private
    {
        UserNetPosition storage userNetPosition = addressToUserPosition[userAddress];
        if (userNetPosition.netPosition == 0 || userNetPosition.netPosition.isSameSign(qty)) {
            // new position or adding to open pos
            addUserNetPosition(
                userNetPosition,
                userAddress,
                qty,
                price
            );
        } else {  // opposite side from open position, reduce, flattened, or flipped.
            if (userNetPosition.netPosition >= qty * -1) { // pos is reduced or flattened
                reduceUserNetPosition(
                    userNetPosition,
                    userAddress,
                    qty,
                    price
                );
            } else {    // pos is flipped, reduce and then create new open pos!

                reduceUserNetPosition(
                    userNetPosition,
                    userAddress,
                    userNetPosition.netPosition * -1,
                    price
                ); // flatten completely

                int newNetPos = userNetPosition.netPosition + qty;            // the portion remaining after flattening
                addUserNetPosition(
                    userNetPosition,
                    userAddress,
                    newNetPos,
                    price
                );
            }
        }
        userNetPosition.netPosition = userNetPosition.netPosition.add(qty);   // keep track of total net pos across all prices for user.
    }

    /// @dev calculates the needed collateral for a new position and commits it to the pool removing it from the
    /// users account and creates the needed Position struct to record the new position.
    /// @param userNetPosition current positions held by user
    /// @param userAddress address of user entering into the position
    /// @param qty signed quantity of the trade
    /// @param price agreed price of trade
    function addUserNetPosition(
        UserNetPosition storage userNetPosition,
        address userAddress,
        int qty,
        uint price
    ) private
    {
        uint neededCollateral = MathLib.calculateNeededCollateral(
            MKT_CONTRACT.PRICE_FLOOR(),
            MKT_CONTRACT.PRICE_CAP(),
            MKT_CONTRACT.QTY_DECIMAL_PLACES(),
            qty,
            price
        );
        commitCollateralToPool(userAddress, neededCollateral);
        userNetPosition.positions.push(Position(price, qty));   // append array with new position
    }

    /// @dev reduces net position correctly allocating collateral back to user
    /// @param userNetPos storage struct for this users position
    /// @param userAddress address of user who is reducing their pos
    /// @param qty signed quantity of the qty to reduce this users position by
    /// @param price transacted price
    function reduceUserNetPosition(
        UserNetPosition storage userNetPos,
        address userAddress,
        int qty,
        uint price
    ) private
    {
        uint collateralToReturnToUserAccount = 0;
        int qtyToReduce = qty;                      // note: this sign is opposite of our users position
        assert(userNetPos.positions.length != 0);   // sanity check
        while (qtyToReduce != 0) {   //TODO: ensure we dont run out of gas here!
            Position storage position = userNetPos.positions[userNetPos.positions.length - 1];  // get the last pos (LIFO)
            if (position.qty.abs() <= qtyToReduce.abs()) {   // this position is completely consumed!
                collateralToReturnToUserAccount = collateralToReturnToUserAccount.add(
                    MathLib.calculateNeededCollateral(
                        MKT_CONTRACT.PRICE_FLOOR(),
                        MKT_CONTRACT.PRICE_CAP(),
                        MKT_CONTRACT.QTY_DECIMAL_PLACES(),
                        position.qty,
                        price
                    )
                );
                qtyToReduce = qtyToReduce.add(position.qty);
                userNetPos.positions.length--;  // remove this position from our array.
            } else {  // this position stays, just reduce the qty.
                position.qty = position.qty.add(qtyToReduce);
                // pos is opp sign of qty we are reducing here!
                collateralToReturnToUserAccount = collateralToReturnToUserAccount.add(
                    MathLib.calculateNeededCollateral(
                        MKT_CONTRACT.PRICE_FLOOR(),
                        MKT_CONTRACT.PRICE_CAP(),
                        MKT_CONTRACT.QTY_DECIMAL_PLACES(),
                        qtyToReduce * -1,
                        price
                    )
                );
                //qtyToReduce = 0; // completely reduced now!
                break;
            }
        }

        if (collateralToReturnToUserAccount != 0) {  // allocate funds back to user acct.
            withdrawCollateralFromPool(userAddress, collateralToReturnToUserAccount);
        }
    }
}


can't join twice

can't join twice

pragma solidity ^0.4.11;
contract PotOfGold {

    struct Pot {
        string name;
        uint buyIn;

        address[] players;

        uint lastPlayerBlockNumber; // uint8(uint256(sha3(block.blockhash(lastPlayerBlockNumber+1)))) % 3 == loser index

        address loser;
    }

    address public owner;

    Pot[] allPots;
    mapping(string => Pot) nameToPot;

    event newPot(string name, uint buyIn, address creator);
    event potJoin(string name, address newPlayer);
    event potExpired(string name);
    event potClosed(string name, address loser);

    function PotOfGold() {
        owner = msg.sender;
    }

    function ownerWithdraw(){
        require(msg.sender == owner);

        int toWithdraw = int(this.balance - 100 finney); // leave 0.1 ether for gas (?)
        require(toWithdraw > 0);

        owner.transfer(uint(toWithdraw));
    }

    function createPot(string name) payable {
        require(msg.value > 0); // must bet something
        require(bytes(name).length > 0); // name mustn't be empty
        require(nameToPot[name].buyIn == 0); // there isn't already a pot with this name

        Pot pot = nameToPot[name];
        pot.name = name;
        pot.buyIn = msg.value;
        pot.players.push(msg.sender);

        allPots.push(pot);

        newPot(name, msg.value, msg.sender);
    }

    function joinPot(string name) payable {
        Pot pot = nameToPot[name];
        require(pot.buyIn > 0); // pot exists
        require(pot.loser == 0); // pot isn't over
        require(pot.players.length < 3); // pot isn't full
        require(msg.value == pot.buyIn); // must pay buyIn amount
        require(pot.players[0] != msg.sender && pot.players[1] != msg.sender);

        pot.players.push(msg.sender);
        if(pot.players.length == 3){
            pot.lastPlayerBlockNumber = block.number;
        }

        potJoin(name, msg.sender);
    }

    function solvePot(string name){
        Pot pot = nameToPot[name];
        require(pot.loser == 0); // pot isn't over
        require(pot.players.length == 3); // pot full
        require(block.number > pot.lastPlayerBlockNumber);

        bytes32 blockHash = block.blockhash(pot.lastPlayerBlockNumber + 1);
        if(blockHash == 0) { // pot expired due to hash storage limits - players didn't solve pot
            require(pot.loser == 0); // need this?
            pot.loser = msg.sender; // doesn't matter, everybody loses a fee

            for(uint i = 0; i < pot.players.length; i++){
                pot.players[i].transfer((pot.buyIn * 99) / 100); // return money minus 1% fee
            }

            potExpired(name);
            return;
        }

        bytes32 potShaResult = sha3(msg.sender, blockHash);
        uint8 loserIndex = uint8(uint256(potShaResult) % 3);

        require(pot.loser == 0); // need this?
        pot.loser = pot.players[loserIndex];

        address winner1 = pot.players[(loserIndex + 1) % 3];
        address winner2 = pot.players[(loserIndex + 2) % 3];

        uint winAmount = ((pot.buyIn / 2) * 99) / 100;
        uint returnAmount = pot.buyIn + winAmount;

        winner1.transfer(returnAmount);
        winner2.transfer(returnAmount);

        potClosed(name, pot.loser);
    }
}

pragma solidity ^0.4.11;
contract PotOfGold {

    struct Pot {
        string name;
        uint buyIn;

        address[] players;

        uint lastPlayerBlockNumber; // uint8(uint256(sha3(block.blockhash(lastPlayerBlockNumber+1)))) % 3 == loser index

        address loser;
    }

    address public owner;

    Pot[] allPots;
    mapping(string => Pot) nameToPot;

    event newPot(string name, uint buyIn, address creator);
    event potJoin(string name, address newPlayer);
    event potExpired(string name);
    event potClosed(string name, address loser);

    function PotOfGold() {
        owner = msg.sender;
    }

    function ownerWithdraw(){
        require(msg.sender == owner);

        int toWithdraw = int(this.balance - 100 finney); // leave 0.1 ether for gas (?)
        require(toWithdraw > 0);

        owner.transfer(uint(toWithdraw));
    }

    function createPot(string name) payable {
        require(msg.value > 0); // must bet something
        require(bytes(name).length > 0); // name mustn't be empty
        require(nameToPot[name].buyIn == 0); // there isn't already a pot with this name

        Pot pot = nameToPot[name];
        pot.name = name;
        pot.buyIn = msg.value;
        pot.players.push(msg.sender);

        allPots.push(pot);

        newPot(name, msg.value, msg.sender);
    }

    function joinPot(string name) payable {
        Pot pot = nameToPot[name];
        require(pot.buyIn > 0); // pot exists
        require(pot.loser == 0); // pot isn't over
        require(pot.players.length < 3); // pot isn't full
        require(msg.value == pot.buyIn); // must pay buyIn amount

        pot.players.push(msg.sender);
        if(pot.players.length == 3){
           pot.lastPlayerBlockNumber = block.number;
        }

        potJoin(name, msg.sender);
    }

    /*function leavePot(string name) {
        Pot pot = nameToPot[name];
        if(pot.buyIn == 0) throw; // no pot
        if(pot.loser != 0) throw; // pot is over
        if(pot.players.length == 3) throw; // pot is full but waiting for a loser

        if(pot.players[0] != msg.sender && pot.players[1] != msg.sender) throw; // no such player in pot

        address[] newPlayers;
        for(uint i = 0; i < pot.players.length; i++){
            if(pot.players[i] != msg.sender){
                newPlayers.push(pot.players[i]);
            }
        }

        pot.players = newPlayers;

        msg.sender.transfer((pot.buyIn * 99) / 100); // leaving fee 1%
    }*/

    function solvePot(string name){
        Pot pot = nameToPot[name];
        require(pot.loser == 0); // pot isn't over
        require(pot.players.length == 3); // pot full
        require(block.number > pot.lastPlayerBlockNumber);

        bytes32 blockHash = block.blockhash(pot.lastPlayerBlockNumber + 1);
        if(blockHash == 0) { // pot expired due to hash storage limits - players didn't solve pot
            require(pot.loser == 0); // need this?
            pot.loser = msg.sender; // doesn't matter, everybody loses a fee

            for(uint i = 0; i < pot.players.length; i++){
                pot.players[i].transfer((pot.buyIn * 99) / 100); // return money minus 1% fee
            }

            potExpired(name);
            return;
        }

        bytes32 potShaResult = sha3(msg.sender, blockHash);
        uint8 loserIndex = uint8(uint256(potShaResult) % 3);

        require(pot.loser == 0); // need this?
        pot.loser = pot.players[loserIndex];

        address winner1 = pot.players[(loserIndex + 1) % 3];
        address winner2 = pot.players[(loserIndex + 2) % 3];

        uint winAmount = ((pot.buyIn / 2) * 99) / 100;
        uint returnAmount = pot.buyIn + winAmount;

        winner1.transfer(returnAmount);
        winner2.transfer(returnAmount);

        potClosed(name, pot.loser);
    }
}


renamed type to changerType

renamed type to changerType

pragma solidity ^0.4.10;
import './BancorEventsDispatcher.sol';
import './TokenChangerInterface.sol';
import './SmartTokenInterface.sol';
import './SafeMath.sol';

/*
    Open issues:
    - add miner abuse protection
    - assumes that the reserve tokens either return true for transfer/transferFrom or throw - possibly remove the reliance on the return value
*/

// interfaces

contract BancorFormula {
    function calculatePurchaseReturn(uint256 _supply, uint256 _reserveBalance, uint16 _reserveRatio, uint256 _depositAmount) public constant returns (uint256 amount);
    function calculateSaleReturn(uint256 _supply, uint256 _reserveBalance, uint16 _reserveRatio, uint256 _sellAmount) public constant returns (uint256 amount);
}

/*
    Bancor Changer v0.1

    The Bancor version of the token changer, allows changing between a smart token and other ERC20 tokens and between different ERC20 tokens and themselves

    ERC20 reserve token balance can be virtual, meaning that the calculations are based on the virtual balance instead of relying on
    the actual reserve balance. This is a security mechanism that prevents the need to keep a very large (and valuable) balance in a single contract
*/
contract BancorChanger is BancorEventsDispatcher, TokenChangerInterface, SafeMath {
    struct Reserve {
        uint256 virtualBalance;         // virtual balance
        uint8 ratio;                    // constant reserve ratio (CRR), 1-100
        bool isVirtualBalanceEnabled;   // true if virtual balance is enabled, false if not
        bool isEnabled;                 // is purchase of the smart token enabled with the reserve, can be set by the owner
        bool isSet;                     // used to tell if the mapping element is defined
    }

    string public version = '0.1';
    string public changerType = 'bancor';

    SmartTokenInterface public token;               // smart token governed by the changer
    BancorFormula public formula;                   // bancor calculation formula contract
    bool public isActive = false;                   // true if the change functionality can be used, false if not
    address[] public reserveTokens;                 // ERC20 standard token addresses
    mapping (address => Reserve) public reserves;   // reserve token addresses -> reserve data
    uint8 private totalReserveRatio = 0;            // used to prevent increasing the total reserve ratio above 100% efficiently

    // events, can be used to listen to the contract directly, as opposed to through the events contract
    event Change(address indexed _fromToken, address indexed _toToken, address indexed _trader, uint256 _amount, uint256 _return);

    /*
        _token      smart token governed by the changer
        _formula    address of a bancor formula contract
        _events     optional, address of a bancor events contract
    */
    function BancorChanger(address _token, address _formula, address _events)
        BancorEventsDispatcher(_events)
        validAddress(_token)
        validAddress(_formula)
    {
        token = SmartTokenInterface(_token);
        formula = BancorFormula(_formula);
    }

    // validates an address - currently only checks that it isn't null
    modifier validAddress(address _address) {
        require(_address != 0x0);
        _;
    }

    // validates a reserve token address - verifies that the address belongs to one of the reserve tokens
    modifier validReserve(address _address) {
        require(reserves[_address].isSet);
        _;
    }

    // validates a token address - verifies that the address belongs to one of the changable tokens
    modifier validToken(address _address) {
        require(_address == address(token) || reserves[_address].isSet);
        _;
    }

    // validates reserve ratio range
    modifier validReserveRatio(uint8 _ratio) {
        require(_ratio > 0 && _ratio <= 100);
        _;
    }

    // ensures that token changing is active
    modifier active() {
        assert(isActive);
        _;
    }

    // ensures that token changing is not active
    modifier inactive() {
        assert(!isActive);
        _;
    }

    /*
        returns the number of reserve tokens defined
    */
    function reserveTokenCount() public constant returns (uint16 count) {
        return uint16(reserveTokens.length);
    }

    /*
        returns the number of changeable tokens supported by the contract
        note that the number of changable tokens is the number of reserve token, plus 1 (that represents the smart token)
    */
    function changeableTokenCount() public constant returns (uint16 count) {
        return reserveTokenCount() + 1;
    }

    /*
        given a changable token index, returns the changable token contract address
    */
    function changeableToken(uint16 _tokenIndex) public constant returns (address tokenAddress) {
        if (_tokenIndex == 0)
            return token;
        return reserveTokens[_tokenIndex - 1];
    }

    /*
        defines a new reserve for the token
        can only be called by the changer owner while the changer is inactive

        _token                  address of the reserve token
        _ratio                  constant reserve ratio, 1-100
        _enableVirtualBalance   true to enable virtual balance for the reserve, false to disable it
    */
    function addReserve(address _token, uint8 _ratio, bool _enableVirtualBalance)
        public
        ownerOnly
        inactive
        validAddress(_token)
        validReserveRatio(_ratio)
        returns (bool success)
    {
        require(_token != address(this) && _token != address(token) && !reserves[_token].isSet && totalReserveRatio + _ratio <= 100); // validate input

        reserves[_token].virtualBalance = 0;
        reserves[_token].ratio = _ratio;
        reserves[_token].isVirtualBalanceEnabled = _enableVirtualBalance;
        reserves[_token].isEnabled = true;
        reserves[_token].isSet = true;
        reserveTokens.push(_token);
        totalReserveRatio += _ratio;
        return true;
    }

    /*
        updates one of the token reserves
        can only be called by the changer owner

        _reserveToken           address of the reserve token
        _ratio                  constant reserve ratio, 1-100
        _enableVirtualBalance   true to enable virtual balance for the reserve, false to disable it
        _virtualBalance         new reserve's virtual balance
    */
    function updateReserve(address _reserveToken, uint8 _ratio, bool _enableVirtualBalance, uint256 _virtualBalance)
        public
        ownerOnly
        validReserve(_reserveToken)
        validReserveRatio(_ratio)
        returns (bool success)
    {
        Reserve reserve = reserves[_reserveToken];
        require(totalReserveRatio - reserve.ratio + _ratio <= 100); // validate input

        totalReserveRatio = totalReserveRatio - reserve.ratio + _ratio;
        reserve.ratio = _ratio;
        reserve.isVirtualBalanceEnabled = _enableVirtualBalance;
        reserve.virtualBalance = _virtualBalance;
        return true;
    }

    /*
        disables purchasing with the given reserve token in case the reserve token got compromised
        can only be called by the changer owner
        note that selling is still enabled regardless of this flag and it cannot be disabled by the owner

        _reserveToken    reserve token contract address
        _disable         true to disable the token, false to re-enable it
    */
    function disableReserve(address _reserveToken, bool _disable)
        public
        ownerOnly
        validReserve(_reserveToken)
    {
        reserves[_reserveToken].isEnabled = !_disable;
    }

    /*
        returns the reserve's virtual balance if one is defined, otherwise returns the actual balance

        _reserveToken    reserve token contract address
    */
    function getReserveBalance(address _reserveToken)
        public
        constant
        validReserve(_reserveToken)
        returns (uint256 balance)
    {
        Reserve reserve = reserves[_reserveToken];
        ERC20TokenInterface reserveToken = ERC20TokenInterface(_reserveToken);
        return reserve.isVirtualBalanceEnabled ? reserve.virtualBalance : reserveToken.balanceOf(this);
    }

    /*
        allows the owner to execute the smart token's issue function

        _to         account to receive the new amount
        _amount     amount to increase the supply by
    */
    function issueToken(address _to, uint256 _amount) public ownerOnly returns (bool success) {
        return token.issue(_to, _amount);
    }

    /*
        allows the owner to execute the smart token's destroy function

        _from       account to remove the new amount from
        _amount     amount to decrease the supply by
    */
    function destroyToken(address _from, uint256 _amount) public ownerOnly returns (bool success) {
        return token.destroy(_from, _amount);
    }

    /*
        withdraws tokens from the reserve and sends them to an account
        can only be called by the changer owner

        _reserveToken    reserve token contract address
        _to              account to receive the new amount
        _amount          amount to withdraw (in the reserve token)
    */
    function withdraw(address _reserveToken, address _to, uint256 _amount)
        public
        ownerOnly
        validReserve(_reserveToken)
        validAddress(_to)
        returns (bool success)
    {
        require(_to != address(this) && _to != address(token) && _amount != 0); // validate input

        ERC20TokenInterface reserveToken = ERC20TokenInterface(_reserveToken);
        assert(reserveToken.transfer(_to, _amount));

        // update virtual balance if relevant
        Reserve reserve = reserves[_reserveToken];
        if (reserve.isVirtualBalanceEnabled)
            reserve.virtualBalance = safeSub(reserve.virtualBalance, _amount);

        return true;
    }

    /*
        sets the smart token's changer address to a different one instead of the current contract address
        can only be called by the owner
        the changer can be set to null to transfer ownership from the changer to the original smart token's owner

        _changer    new changer contract address (can also be set to 0x0 to remove the current changer)
    */
    function setTokenChanger(address _changer)
        public
        ownerOnly
        validAddress(_changer)
        returns (bool success)
    {
        require(_changer != address(this) && _changer != address(token)); // validate input
        return token.setChanger(_changer);
    }

    /*
        activates the change logic
        can only be called by the owner
        once changing is activated, it cannot be deactivated by the owner anymore
        activating the change logic also enables transfers in the smart token
    */
    function activate()
        public
        ownerOnly
        inactive
        returns (bool success)
    {
        assert(token.totalSupply() != 0 && reserveTokens.length > 0); // validate state
        token.disableTransfers(false);
        isActive = true;
        return true;
    }

    /*
        returns the expected return for changing a specific amount of _fromToken to _toToken

        _fromToken  token to change from
        _toToken    token to change to
        _amount     amount to change, in fromToken
    */
    function getReturn(address _fromToken, address _toToken, uint256 _amount)
        public
        constant
        validToken(_fromToken)
        validToken(_toToken)
        returns (uint256 amount)
    {
        require(_fromToken != _toToken); // validate input

        // change between the token and one of its reserves
        address tokenAddress = address(token);
        if (_toToken == tokenAddress)
            return getPurchaseReturn(_fromToken, _amount);
        else if (_fromToken == tokenAddress)
            return getSaleReturn(_toToken, _amount);

        // change between 2 reserves
        uint256 tempAmount = getPurchaseReturn(_fromToken, _amount);
        return getSaleReturn(_toToken, tempAmount);
    }

    /*
        returns the expected return for buying the token for a reserve token

        _reserveToken   reserve token contract address
        _depositAmount  amount to deposit (in the reserve token)
    */
    function getPurchaseReturn(address _reserveToken, uint256 _depositAmount)
        public
        constant
        active
        validReserve(_reserveToken)
        returns (uint256 amount)
    {
        Reserve reserve = reserves[_reserveToken];
        require(reserve.isEnabled && _depositAmount != 0); // validate input

        uint256 reserveBalance = getReserveBalance(_reserveToken);
        assert(reserveBalance != 0); // validate state

        uint256 tokenSupply = token.totalSupply();
        return formula.calculatePurchaseReturn(tokenSupply, reserveBalance, reserve.ratio, _depositAmount);
    }

    /*
        returns the expected return for selling the token for one of its reserve tokens

        _reserveToken   reserve token contract address
        _sellAmount     amount to sell (in the smart token)
    */
    function getSaleReturn(address _reserveToken, uint256 _sellAmount)
        public
        constant
        active
        validReserve(_reserveToken)
        returns (uint256 amount)
    {
        require(_sellAmount != 0 && _sellAmount <= token.balanceOf(msg.sender)); // validate input

        Reserve reserve = reserves[_reserveToken];
        uint256 reserveBalance = getReserveBalance(_reserveToken);
        assert(reserveBalance != 0); // validate state

        uint256 tokenSupply = token.totalSupply();
        return formula.calculateSaleReturn(tokenSupply, reserveBalance, reserve.ratio, _sellAmount);
    }

    /*
        changes a specific amount of _fromToken to _toToken

        _fromToken  token to change from
        _toToken    token to change to
        _amount     amount to change, in fromToken
        _minReturn  if the change results in an amount smaller than the minimum return, it is cancelled
    */
    function change(address _fromToken, address _toToken, uint256 _amount, uint256 _minReturn)
        public
        validToken(_fromToken)
        validToken(_toToken)
        returns (uint256 amount)
    {
        require(_fromToken != _toToken); // validate input

        // change between the token and one of its reserves
        address tokenAddress = address(token);
        if (_toToken == tokenAddress)
            return buy(_fromToken, _amount, _minReturn);
        else if (_fromToken == tokenAddress)
            return sell(_toToken, _amount, _minReturn);

        // change between 2 reserves
        uint256 tempAmount = buy(_fromToken, _amount, 0);
        return sell(_toToken, tempAmount, _minReturn);
    }

    /*
        buys the token by depositing one of its reserve tokens

        _reserveToken   reserve token contract address
        _depositAmount  amount to deposit (in the reserve token)
        _minReturn      if the change results in an amount smaller than the minimum return, it is cancelled
    */
    function buy(address _reserveToken, uint256 _depositAmount, uint256 _minReturn) public returns (uint256 amount) {
        amount = getPurchaseReturn(_reserveToken, _depositAmount);
        assert(amount != 0 && amount >= _minReturn); // ensure the trade gives something in return and meets the minimum requested amount

        // update virtual balance if relevant
        Reserve reserve = reserves[_reserveToken];
        if (reserve.isVirtualBalanceEnabled)
            reserve.virtualBalance = safeAdd(reserve.virtualBalance, _depositAmount);

        ERC20TokenInterface reserveToken = ERC20TokenInterface(_reserveToken);
        assert(reserveToken.transferFrom(msg.sender, this, _depositAmount)); // transfer _depositAmount funds from the caller in the reserve token
        assert(token.issue(msg.sender, amount)); // issue new funds to the caller in the smart token

        dispatchChange(_reserveToken, token, msg.sender, _depositAmount, amount);
        return amount;
    }

    /*
        sells the token by withdrawing from one of its reserve tokens

        _reserveToken   reserve token contract address
        _sellAmount     amount to sell (in the smart token)
        _minReturn      if the change results in an amount smaller the minimum return, it is cancelled
    */
    function sell(address _reserveToken, uint256 _sellAmount, uint256 _minReturn) public returns (uint256 amount) {
        amount = getSaleReturn(_reserveToken, _sellAmount);
        assert(amount != 0 && amount >= _minReturn); // ensure the trade gives something in return and meets the minimum requested amount

        ERC20TokenInterface reserveToken = ERC20TokenInterface(_reserveToken);
        uint256 reserveBalance = getReserveBalance(_reserveToken);
        assert(amount <= reserveBalance); // ensure that the trade won't result in negative reserve

        uint256 tokenSupply = token.totalSupply();
        assert(amount < reserveBalance || _sellAmount == tokenSupply); // ensure that the trade will only deplete the reserve if the total supply is depleted as well
        assert(token.destroy(msg.sender, _sellAmount)); // destroy _sellAmount from the caller's balance in the smart token
        assert(reserveToken.transfer(msg.sender, amount)); // transfer funds to the caller in the reserve token

        // update virtual balance if relevant
        Reserve reserve = reserves[_reserveToken];
        if (reserve.isVirtualBalanceEnabled)
            reserve.virtualBalance = safeSub(reserve.virtualBalance, amount);

        // if the supply was totally depleted, disconnect from the smart token
        if (_sellAmount == tokenSupply)
            token.setChanger(0x0);

        dispatchChange(token, _reserveToken, msg.sender, _sellAmount, amount);
        return amount;
    }

    // utility

    function dispatchChange(address _fromToken, address _toToken, address _trader, uint256 _amount, uint256 _return) private {
        Change(_fromToken, _toToken, _trader, _amount, _return);

        if (address(events) != 0x0)
            events.tokenChange(_fromToken, _toToken, _trader, _amount, _return);
    }

    // fallback
    function() {
        assert(false);
    }
}

pragma solidity ^0.4.10;
import './BancorEventsDispatcher.sol';
import './TokenChangerInterface.sol';
import './SmartTokenInterface.sol';
import './SafeMath.sol';

/*
    Open issues:
    - add miner abuse protection
    - assumes that the reserve tokens either return true for transfer/transferFrom or throw - possibly remove the reliance on the return value
*/

// interfaces

contract BancorFormula {
    function calculatePurchaseReturn(uint256 _supply, uint256 _reserveBalance, uint16 _reserveRatio, uint256 _depositAmount) public constant returns (uint256 amount);
    function calculateSaleReturn(uint256 _supply, uint256 _reserveBalance, uint16 _reserveRatio, uint256 _sellAmount) public constant returns (uint256 amount);
}

/*
    Bancor Changer v0.1

    The Bancor version of the token changer, allows changing between a smart token and other ERC20 tokens and between different ERC20 tokens and themselves

    ERC20 reserve token balance can be virtual, meaning that the calculations are based on the virtual balance instead of relying on
    the actual reserve balance. This is a security mechanism that prevents the need to keep a very large (and valuable) balance in a single contract
*/
contract BancorChanger is BancorEventsDispatcher, TokenChangerInterface, SafeMath {
    struct Reserve {
        uint256 virtualBalance;         // virtual balance
        uint8 ratio;                    // constant reserve ratio (CRR), 1-100
        bool isVirtualBalanceEnabled;   // true if virtual balance is enabled, false if not
        bool isEnabled;                 // is purchase of the smart token enabled with the reserve, can be set by the owner
        bool isSet;                     // used to tell if the mapping element is defined
    }

    string public version = '0.1';
    string public type = 'bancor';

    SmartTokenInterface public token;               // smart token governed by the changer
    BancorFormula public formula;                   // bancor calculation formula contract
    bool public isActive = false;                   // true if the change functionality can be used, false if not
    address[] public reserveTokens;                 // ERC20 standard token addresses
    mapping (address => Reserve) public reserves;   // reserve token addresses -> reserve data
    uint8 private totalReserveRatio = 0;            // used to prevent increasing the total reserve ratio above 100% efficiently

    // events, can be used to listen to the contract directly, as opposed to through the events contract
    event Change(address indexed _fromToken, address indexed _toToken, address indexed _trader, uint256 _amount, uint256 _return);

    /*
        _token      smart token governed by the changer
        _formula    address of a bancor formula contract
        _events     optional, address of a bancor events contract
    */
    function BancorChanger(address _token, address _formula, address _events)
        BancorEventsDispatcher(_events)
        validAddress(_token)
        validAddress(_formula)
    {
        token = SmartTokenInterface(_token);
        formula = BancorFormula(_formula);
    }

    // validates an address - currently only checks that it isn't null
    modifier validAddress(address _address) {
        require(_address != 0x0);
        _;
    }

    // validates a reserve token address - verifies that the address belongs to one of the reserve tokens
    modifier validReserve(address _address) {
        require(reserves[_address].isSet);
        _;
    }

    // validates a token address - verifies that the address belongs to one of the changable tokens
    modifier validToken(address _address) {
        require(_address == address(token) || reserves[_address].isSet);
        _;
    }

    // validates reserve ratio range
    modifier validReserveRatio(uint8 _ratio) {
        require(_ratio > 0 && _ratio <= 100);
        _;
    }

    // ensures that token changing is active
    modifier active() {
        assert(isActive);
        _;
    }

    // ensures that token changing is not active
    modifier inactive() {
        assert(!isActive);
        _;
    }

    /*
        returns the number of reserve tokens defined
    */
    function reserveTokenCount() public constant returns (uint16 count) {
        return uint16(reserveTokens.length);
    }

    /*
        returns the number of changeable tokens supported by the contract
        note that the number of changable tokens is the number of reserve token, plus 1 (that represents the smart token)
    */
    function changeableTokenCount() public constant returns (uint16 count) {
        return reserveTokenCount() + 1;
    }

    /*
        given a changable token index, returns the changable token contract address
    */
    function changeableToken(uint16 _tokenIndex) public constant returns (address tokenAddress) {
        if (_tokenIndex == 0)
            return token;
        return reserveTokens[_tokenIndex - 1];
    }

    /*
        defines a new reserve for the token
        can only be called by the changer owner while the changer is inactive

        _token                  address of the reserve token
        _ratio                  constant reserve ratio, 1-100
        _enableVirtualBalance   true to enable virtual balance for the reserve, false to disable it
    */
    function addReserve(address _token, uint8 _ratio, bool _enableVirtualBalance)
        public
        ownerOnly
        inactive
        validAddress(_token)
        validReserveRatio(_ratio)
        returns (bool success)
    {
        require(_token != address(this) && _token != address(token) && !reserves[_token].isSet && totalReserveRatio + _ratio <= 100); // validate input

        reserves[_token].virtualBalance = 0;
        reserves[_token].ratio = _ratio;
        reserves[_token].isVirtualBalanceEnabled = _enableVirtualBalance;
        reserves[_token].isEnabled = true;
        reserves[_token].isSet = true;
        reserveTokens.push(_token);
        totalReserveRatio += _ratio;
        return true;
    }

    /*
        updates one of the token reserves
        can only be called by the changer owner

        _reserveToken           address of the reserve token
        _ratio                  constant reserve ratio, 1-100
        _enableVirtualBalance   true to enable virtual balance for the reserve, false to disable it
        _virtualBalance         new reserve's virtual balance
    */
    function updateReserve(address _reserveToken, uint8 _ratio, bool _enableVirtualBalance, uint256 _virtualBalance)
        public
        ownerOnly
        validReserve(_reserveToken)
        validReserveRatio(_ratio)
        returns (bool success)
    {
        Reserve reserve = reserves[_reserveToken];
        require(totalReserveRatio - reserve.ratio + _ratio <= 100); // validate input

        totalReserveRatio = totalReserveRatio - reserve.ratio + _ratio;
        reserve.ratio = _ratio;
        reserve.isVirtualBalanceEnabled = _enableVirtualBalance;
        reserve.virtualBalance = _virtualBalance;
        return true;
    }

    /*
        disables purchasing with the given reserve token in case the reserve token got compromised
        can only be called by the changer owner
        note that selling is still enabled regardless of this flag and it cannot be disabled by the owner

        _reserveToken    reserve token contract address
        _disable         true to disable the token, false to re-enable it
    */
    function disableReserve(address _reserveToken, bool _disable)
        public
        ownerOnly
        validReserve(_reserveToken)
    {
        reserves[_reserveToken].isEnabled = !_disable;
    }

    /*
        returns the reserve's virtual balance if one is defined, otherwise returns the actual balance

        _reserveToken    reserve token contract address
    */
    function getReserveBalance(address _reserveToken)
        public
        constant
        validReserve(_reserveToken)
        returns (uint256 balance)
    {
        Reserve reserve = reserves[_reserveToken];
        ERC20TokenInterface reserveToken = ERC20TokenInterface(_reserveToken);
        return reserve.isVirtualBalanceEnabled ? reserve.virtualBalance : reserveToken.balanceOf(this);
    }

    /*
        allows the owner to execute the smart token's issue function

        _to         account to receive the new amount
        _amount     amount to increase the supply by
    */
    function issueToken(address _to, uint256 _amount) public ownerOnly returns (bool success) {
        return token.issue(_to, _amount);
    }

    /*
        allows the owner to execute the smart token's destroy function

        _from       account to remove the new amount from
        _amount     amount to decrease the supply by
    */
    function destroyToken(address _from, uint256 _amount) public ownerOnly returns (bool success) {
        return token.destroy(_from, _amount);
    }

    /*
        withdraws tokens from the reserve and sends them to an account
        can only be called by the changer owner

        _reserveToken    reserve token contract address
        _to              account to receive the new amount
        _amount          amount to withdraw (in the reserve token)
    */
    function withdraw(address _reserveToken, address _to, uint256 _amount)
        public
        ownerOnly
        validReserve(_reserveToken)
        validAddress(_to)
        returns (bool success)
    {
        require(_to != address(this) && _to != address(token) && _amount != 0); // validate input

        ERC20TokenInterface reserveToken = ERC20TokenInterface(_reserveToken);
        assert(reserveToken.transfer(_to, _amount));

        // update virtual balance if relevant
        Reserve reserve = reserves[_reserveToken];
        if (reserve.isVirtualBalanceEnabled)
            reserve.virtualBalance = safeSub(reserve.virtualBalance, _amount);

        return true;
    }

    /*
        sets the smart token's changer address to a different one instead of the current contract address
        can only be called by the owner
        the changer can be set to null to transfer ownership from the changer to the original smart token's owner

        _changer    new changer contract address (can also be set to 0x0 to remove the current changer)
    */
    function setTokenChanger(address _changer)
        public
        ownerOnly
        validAddress(_changer)
        returns (bool success)
    {
        require(_changer != address(this) && _changer != address(token)); // validate input
        return token.setChanger(_changer);
    }

    /*
        activates the change logic
        can only be called by the owner
        once changing is activated, it cannot be deactivated by the owner anymore
        activating the change logic also enables transfers in the smart token
    */
    function activate()
        public
        ownerOnly
        inactive
        returns (bool success)
    {
        assert(token.totalSupply() != 0 && reserveTokens.length > 0); // validate state
        token.disableTransfers(false);
        isActive = true;
        return true;
    }

    /*
        returns the expected return for changing a specific amount of _fromToken to _toToken

        _fromToken  token to change from
        _toToken    token to change to
        _amount     amount to change, in fromToken
    */
    function getReturn(address _fromToken, address _toToken, uint256 _amount)
        public
        constant
        validToken(_fromToken)
        validToken(_toToken)
        returns (uint256 amount)
    {
        require(_fromToken != _toToken); // validate input

        // change between the token and one of its reserves
        address tokenAddress = address(token);
        if (_toToken == tokenAddress)
            return getPurchaseReturn(_fromToken, _amount);
        else if (_fromToken == tokenAddress)
            return getSaleReturn(_toToken, _amount);

        // change between 2 reserves
        uint256 tempAmount = getPurchaseReturn(_fromToken, _amount);
        return getSaleReturn(_toToken, tempAmount);
    }

    /*
        returns the expected return for buying the token for a reserve token

        _reserveToken   reserve token contract address
        _depositAmount  amount to deposit (in the reserve token)
    */
    function getPurchaseReturn(address _reserveToken, uint256 _depositAmount)
        public
        constant
        active
        validReserve(_reserveToken)
        returns (uint256 amount)
    {
        Reserve reserve = reserves[_reserveToken];
        require(reserve.isEnabled && _depositAmount != 0); // validate input

        uint256 reserveBalance = getReserveBalance(_reserveToken);
        assert(reserveBalance != 0); // validate state

        uint256 tokenSupply = token.totalSupply();
        return formula.calculatePurchaseReturn(tokenSupply, reserveBalance, reserve.ratio, _depositAmount);
    }

    /*
        returns the expected return for selling the token for one of its reserve tokens

        _reserveToken   reserve token contract address
        _sellAmount     amount to sell (in the smart token)
    */
    function getSaleReturn(address _reserveToken, uint256 _sellAmount)
        public
        constant
        active
        validReserve(_reserveToken)
        returns (uint256 amount)
    {
        require(_sellAmount != 0 && _sellAmount <= token.balanceOf(msg.sender)); // validate input

        Reserve reserve = reserves[_reserveToken];
        uint256 reserveBalance = getReserveBalance(_reserveToken);
        assert(reserveBalance != 0); // validate state

        uint256 tokenSupply = token.totalSupply();
        return formula.calculateSaleReturn(tokenSupply, reserveBalance, reserve.ratio, _sellAmount);
    }

    /*
        changes a specific amount of _fromToken to _toToken

        _fromToken  token to change from
        _toToken    token to change to
        _amount     amount to change, in fromToken
        _minReturn  if the change results in an amount smaller than the minimum return, it is cancelled
    */
    function change(address _fromToken, address _toToken, uint256 _amount, uint256 _minReturn)
        public
        validToken(_fromToken)
        validToken(_toToken)
        returns (uint256 amount)
    {
        require(_fromToken != _toToken); // validate input

        // change between the token and one of its reserves
        address tokenAddress = address(token);
        if (_toToken == tokenAddress)
            return buy(_fromToken, _amount, _minReturn);
        else if (_fromToken == tokenAddress)
            return sell(_toToken, _amount, _minReturn);

        // change between 2 reserves
        uint256 tempAmount = buy(_fromToken, _amount, 0);
        return sell(_toToken, tempAmount, _minReturn);
    }

    /*
        buys the token by depositing one of its reserve tokens

        _reserveToken   reserve token contract address
        _depositAmount  amount to deposit (in the reserve token)
        _minReturn      if the change results in an amount smaller than the minimum return, it is cancelled
    */
    function buy(address _reserveToken, uint256 _depositAmount, uint256 _minReturn) public returns (uint256 amount) {
        amount = getPurchaseReturn(_reserveToken, _depositAmount);
        assert(amount != 0 && amount >= _minReturn); // ensure the trade gives something in return and meets the minimum requested amount

        // update virtual balance if relevant
        Reserve reserve = reserves[_reserveToken];
        if (reserve.isVirtualBalanceEnabled)
            reserve.virtualBalance = safeAdd(reserve.virtualBalance, _depositAmount);

        ERC20TokenInterface reserveToken = ERC20TokenInterface(_reserveToken);
        assert(reserveToken.transferFrom(msg.sender, this, _depositAmount)); // transfer _depositAmount funds from the caller in the reserve token
        assert(token.issue(msg.sender, amount)); // issue new funds to the caller in the smart token

        dispatchChange(_reserveToken, token, msg.sender, _depositAmount, amount);
        return amount;
    }

    /*
        sells the token by withdrawing from one of its reserve tokens

        _reserveToken   reserve token contract address
        _sellAmount     amount to sell (in the smart token)
        _minReturn      if the change results in an amount smaller the minimum return, it is cancelled
    */
    function sell(address _reserveToken, uint256 _sellAmount, uint256 _minReturn) public returns (uint256 amount) {
        amount = getSaleReturn(_reserveToken, _sellAmount);
        assert(amount != 0 && amount >= _minReturn); // ensure the trade gives something in return and meets the minimum requested amount

        ERC20TokenInterface reserveToken = ERC20TokenInterface(_reserveToken);
        uint256 reserveBalance = getReserveBalance(_reserveToken);
        assert(amount <= reserveBalance); // ensure that the trade won't result in negative reserve

        uint256 tokenSupply = token.totalSupply();
        assert(amount < reserveBalance || _sellAmount == tokenSupply); // ensure that the trade will only deplete the reserve if the total supply is depleted as well
        assert(token.destroy(msg.sender, _sellAmount)); // destroy _sellAmount from the caller's balance in the smart token
        assert(reserveToken.transfer(msg.sender, amount)); // transfer funds to the caller in the reserve token

        // update virtual balance if relevant
        Reserve reserve = reserves[_reserveToken];
        if (reserve.isVirtualBalanceEnabled)
            reserve.virtualBalance = safeSub(reserve.virtualBalance, amount);

        // if the supply was totally depleted, disconnect from the smart token
        if (_sellAmount == tokenSupply)
            token.setChanger(0x0);

        dispatchChange(token, _reserveToken, msg.sender, _sellAmount, amount);
        return amount;
    }

    // utility

    function dispatchChange(address _fromToken, address _toToken, address _trader, uint256 _amount, uint256 _return) private {
        Change(_fromToken, _toToken, _trader, _amount, _return);

        if (address(events) != 0x0)
            events.tokenChange(_fromToken, _toToken, _trader, _amount, _return);
    }

    // fallback
    function() {
        assert(false);
    }
}


return values on voting

return values on voting

contract PoezenVoting {
    uint public votingStart;
    uint public votingEnd;

 function PoezenVoting(uint _votingStart,
                            uint _votingEnd
                           )
    {
        votingStart = _votingStart;
        votingEnd = _votingEnd;
    }

    event VoteAdded();

    mapping(uint => uint) public voteresults;

    // It will represent a single voter.
    struct Voter
    {
        uint vote;   // index of the voted proposal
        uint voteTime;   // timestamp of vote
    }
    mapping(address => Voter) public voters;

    function vote(uint vote) {

        // check if voting is active
        if (now < votingStart || now > votingEnd){
            return 1;
        }

        if (voters[msg.sender].vote == 0){
            // case : user did not vote yet
            voteresults[vote]++;
            voters[msg.sender] = Voter(vote,now);
            VoteAdded();
            return 2;
        }else{
            // user already voted - and changes his vote
            voteresults[voters[msg.sender].vote]--;
            voteresults[vote]++;
            voters[msg.sender] = Voter(vote,now);
            VoteAdded();
            return 3;
        }
    }

}

contract PoezenVoting {
    uint public votingStart;
    uint public votingEnd;

 function PoezenVoting(uint _votingStart,
                            uint _votingEnd
                           )
    {
        votingStart = _votingStart;
        votingEnd = _votingEnd;
    }

    event VoteAdded();

    mapping(uint => uint) public voteresults;

    // It will represent a single voter.
    struct Voter
    {
        uint vote;   // index of the voted proposal
        uint voteTime;   // timestamp of vote
    }
    mapping(address => Voter) public voters;

    function vote(uint vote) {

        if (now < votingStart || now > votingEnd){
            return;
        }
        voteresults[vote]++;
        voters[msg.sender] = Voter(vote,now);
        VoteAdded();

    }

}


clean up documentation

clean up documentation

/*
    Copyright 2017-2018 Phillip A. Elsasser

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

pragma solidity ^0.4.24;

import "./libraries/MathLib.sol";
import "./MarketContract.sol";
import "./tokens/PositionToken.sol";

import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";

/// @title MarketCollateralPool
/// @notice This collateral pool houses all of the collateral for all market contracts currently in circulation.
/// This pool facilitates locking of collateral and minting / redemption of position tokens for that collateral.
/// @author Phil Elsasser <phil@marketprotocol.io>
contract MarketCollateralPool is Ownable {
    using MathLib for uint;
    using MathLib for int;
    using SafeERC20 for ERC20;

    mapping(address => uint) public contractAddressToCollateralPoolBalance;                 // current balance of all collateral committed
    enum MarketSide { Long, Short, Both}

    event TokensMinted(address indexed marketContract, uint qtyMinted, uint collateralLocked);
    event TokensRedeemed(address indexed marketContract, uint qtyRedeemed, uint collateralUnlocked, uint8 marketSide);
    event FactoryAddressRemoved(address indexed factoryAddress);

    constructor() public { }

    /*
    // EXTERNAL METHODS
    */

    // @notice called by a user after settlement has occurred.  This function will finalize all accounting around any
    // outstanding positions and return all remaining collateral to the caller. This should only be called after
    // settlement has occurred.
    /// @param marketContractAddress address of the MARKET Contract being traded.
    /// @param qtyToRedeem signed qtyToRedeem, positive (+) for long tokens, negative(-) for short tokens
    function settleAndClose(address marketContractAddress, int qtyToRedeem) external {
        MarketContract marketContract = MarketContract(marketContractAddress);
        require(marketContract.isSettled(), "Contract is not settled");

        // burn tokens being redeemed.
        MarketSide marketSide;
        uint absQtyToRedeem = qtyToRedeem.abs(); // convert to a uint for non signed functions
        if(qtyToRedeem > 0) {
            PositionToken(marketContract.LONG_POSITION_TOKEN()).redeemToken(absQtyToRedeem, msg.sender);
            marketSide = MarketSide.Long;
        } else {
            PositionToken(marketContract.SHORT_POSITION_TOKEN()).redeemToken(absQtyToRedeem, msg.sender);
            marketSide = MarketSide.Short;
        }

        // calculate amount of collateral to return and update pool balances
        uint collateralToReturn = MathLib.calculateNeededCollateral(
            marketContract.PRICE_FLOOR(),
            marketContract.PRICE_CAP(),
            marketContract.QTY_MULTIPLIER(),
            qtyToRedeem,
            marketContract.settlementPrice()
        );
        contractAddressToCollateralPoolBalance[marketContract] =
            contractAddressToCollateralPoolBalance[marketContract].subtract(collateralToReturn);

        // return collateral tokens
        ERC20(marketContract.COLLATERAL_TOKEN_ADDRESS()).safeTransfer(msg.sender, collateralToReturn);

        emit TokensRedeemed(
            marketContractAddress,
            absQtyToRedeem,
            collateralToReturn,
            uint8(marketSide)
        );
    }

    /// @notice Called by a user that would like to mint a new set of long and short token for a specified
    /// market contract.  This will transfer and lock the correct amount of collateral into the pool
    /// and issue them the requested qty of long and short tokens
    /// @param marketContractAddress            address of the market contract to redeem tokens for
    /// @param qtyToMint                      quantity of long / short tokens to mint.
    function mintPositionTokens(address marketContractAddress, uint qtyToMint) external {
        MarketContract marketContract = MarketContract(marketContractAddress);
        require(!marketContract.isSettled(), "Contract is already settled");

        uint neededCollateral = MathLib.multiply(qtyToMint, marketContract.COLLATERAL_PER_UNIT());

        // EXTERNAL CALL - transferring ERC20 tokens from sender to this contract.  User must have called
        // ERC20.approve in order for this call to succeed.
        ERC20(marketContract.COLLATERAL_TOKEN_ADDRESS()).safeTransferFrom(msg.sender, this, neededCollateral);

        // Update the collateral pool locked balance.
        contractAddressToCollateralPoolBalance[marketContractAddress] =
            contractAddressToCollateralPoolBalance[marketContractAddress].add(neededCollateral);

        // mint and distribute short and long position tokens to our caller
        PositionToken(marketContract.LONG_POSITION_TOKEN()).mintAndSendToken(qtyToMint, msg.sender);
        PositionToken(marketContract.SHORT_POSITION_TOKEN()).mintAndSendToken(qtyToMint, msg.sender);

        emit TokensMinted(marketContractAddress, qtyToMint, neededCollateral);
    }

    /// @notice Called by a user that currently holds both short and long position tokens and would like to redeem them
    /// for their collateral.
    /// @param marketContractAddress            address of the market contract to redeem tokens for
    /// @param qtyToRedeem                      quantity of long / short tokens to redeem.
    function redeemPositionTokens(address marketContractAddress, uint qtyToRedeem) external {
        MarketContract marketContract = MarketContract(marketContractAddress);

        // Redeem positions tokens by burning them.
        PositionToken(marketContract.LONG_POSITION_TOKEN()).redeemToken(qtyToRedeem, msg.sender);
        PositionToken(marketContract.SHORT_POSITION_TOKEN()).redeemToken(qtyToRedeem, msg.sender);

        // calculate collateral to return and update pool balance
        uint collateralToReturn = MathLib.multiply(qtyToRedeem, marketContract.COLLATERAL_PER_UNIT());
        contractAddressToCollateralPoolBalance[marketContractAddress] = contractAddressToCollateralPoolBalance[marketContractAddress].subtract(collateralToReturn);

        // transfer collateral back to user
        ERC20(marketContract.COLLATERAL_TOKEN_ADDRESS()).safeTransfer(msg.sender, collateralToReturn);

        emit TokensRedeemed(
            marketContractAddress,
            qtyToRedeem,
            collateralToReturn,
            uint8(MarketSide.Both)
        );
    }
}

/*
    Copyright 2017-2018 Phillip A. Elsasser

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

pragma solidity ^0.4.24;

import "./libraries/MathLib.sol";
import "./MarketContract.sol";
import "./tokens/PositionToken.sol";

import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";

/// @title MarketCollateralPool is a contract controlled by Market Contracts.  It holds collateral balances
/// as well as user balances and open positions.  It should be instantiated and then linked to a specific market
/// contract factory.
/// @author Phil Elsasser <phil@marketprotocol.io>
contract MarketCollateralPool is Ownable {
    using MathLib for uint;
    using MathLib for int;
    using SafeERC20 for ERC20;

    mapping(address => uint) public contractAddressToCollateralPoolBalance;                 // current balance of all collateral committed
    enum MarketSide { Long, Short, Both}

    event TokensMinted(address indexed marketContract, uint qtyMinted, uint collateralLocked);
    event TokensRedeemed(address indexed marketContract, uint qtyRedeemed, uint collateralUnlocked, uint8 marketSide);
    event FactoryAddressRemoved(address indexed factoryAddress);

    constructor() public { }

    /*
    // EXTERNAL METHODS
    */

    // @notice called by a user after settlement has occurred.  This function will finalize all accounting around any
    // outstanding positions and return all remaining collateral to the caller. This should only be called after
    // settlement has occurred.
    /// @param marketContractAddress address of the MARKET Contract being traded.
    /// @param qtyToRedeem signed qtyToRedeem, positive (+) for long tokens, negative(-) for short tokens
    function settleAndClose(address marketContractAddress, int qtyToRedeem) external {
        MarketContract marketContract = MarketContract(marketContractAddress);
        require(marketContract.isSettled(), "Contract is not settled");

        // burn tokens being redeemed.
        MarketSide marketSide;
        uint absQtyToRedeem = qtyToRedeem.abs(); // convert to a uint for non signed functions
        if(qtyToRedeem > 0) {
            PositionToken(marketContract.LONG_POSITION_TOKEN()).redeemToken(absQtyToRedeem, msg.sender);
            marketSide = MarketSide.Long;
        } else {
            PositionToken(marketContract.SHORT_POSITION_TOKEN()).redeemToken(absQtyToRedeem, msg.sender);
            marketSide = MarketSide.Short;
        }

        // calculate amount of collateral to return and update pool balances
        uint collateralToReturn = MathLib.calculateNeededCollateral(
            marketContract.PRICE_FLOOR(),
            marketContract.PRICE_CAP(),
            marketContract.QTY_MULTIPLIER(),
            qtyToRedeem,
            marketContract.settlementPrice()
        );
        contractAddressToCollateralPoolBalance[marketContract] =
            contractAddressToCollateralPoolBalance[marketContract].subtract(collateralToReturn);

        // return collateral tokens
        ERC20(marketContract.COLLATERAL_TOKEN_ADDRESS()).safeTransfer(msg.sender, collateralToReturn);

        emit TokensRedeemed(
            marketContractAddress,
            absQtyToRedeem,
            collateralToReturn,
            uint8(marketSide)
        );
    }

    /*
    // PUBLIC METHODS
    */

    /// Called by a user that wants to mint new PositionTokens (both long and short).  The user must approve (ERC20) the
    /// transfer of collateral tokens before this call, or it will fail!
    function mintPositionTokens(address marketContractAddress, uint qtyToMint) external {
        MarketContract marketContract = MarketContract(marketContractAddress);
        require(!marketContract.isSettled(), "Contract is already settled");

        uint neededCollateral = MathLib.multiply(qtyToMint, marketContract.COLLATERAL_PER_UNIT());

        // EXTERNAL CALL - transferring ERC20 tokens from sender to this contract.  User must have called
        // ERC20.approve in order for this call to succeed.
        ERC20(marketContract.COLLATERAL_TOKEN_ADDRESS()).safeTransferFrom(msg.sender, this, neededCollateral);

        // Update the collateral pool locked balance.
        contractAddressToCollateralPoolBalance[marketContractAddress] =
            contractAddressToCollateralPoolBalance[marketContractAddress].add(neededCollateral);

        // mint and distribute short and long position tokens to our caller
        PositionToken(marketContract.LONG_POSITION_TOKEN()).mintAndSendToken(qtyToMint, msg.sender);
        PositionToken(marketContract.SHORT_POSITION_TOKEN()).mintAndSendToken(qtyToMint, msg.sender);

        emit TokensMinted(marketContractAddress, qtyToMint, neededCollateral);
    }

    /// Called by a user that currently holds both short and long position tokens and would like to redeem them
    /// for their collateral.
    function redeemPositionTokens(address marketContractAddress, uint qtyToRedeem) external {
        MarketContract marketContract = MarketContract(marketContractAddress);

        // Redeem positions tokens by burning them.
        PositionToken(marketContract.LONG_POSITION_TOKEN()).redeemToken(qtyToRedeem, msg.sender);
        PositionToken(marketContract.SHORT_POSITION_TOKEN()).redeemToken(qtyToRedeem, msg.sender);

        // calculate collateral to return and update pool balance
        uint collateralToReturn = MathLib.multiply(qtyToRedeem, marketContract.COLLATERAL_PER_UNIT());
        contractAddressToCollateralPoolBalance[marketContractAddress] = contractAddressToCollateralPoolBalance[marketContractAddress].subtract(collateralToReturn);

        // transfer collateral back to user
        ERC20(marketContract.COLLATERAL_TOKEN_ADDRESS()).safeTransfer(msg.sender, collateralToReturn);

        emit TokensRedeemed(
            marketContractAddress,
            qtyToRedeem,
            collateralToReturn,
            uint8(MarketSide.Both)
        );
    }
}