removing extraneous require calls where the check is already made higher in the call stack. leaving commented for clarity.

/*
    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);  subtract call below will enforce this
        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)); already confirmed higher in call stack!
        //require(userAddressToAccountBalance[fromAddress] >= collateralAmount);   // ensure sufficient balance
        // subtract call will enforce 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)); already confirmed higher in call stack!
        // require(collateralPoolBalance >= collateralAmount); subtract call below will enforce this!
        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(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);  subtract call below will enforce this
        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); subtract call below will enforce this!
        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);
        }
    }
}


wip: Even wispier

wip: Even wispier

//SPDX-License-Identifier: MIT
pragma solidity ^0.8;

// FIXME: Use 4.x pre-release which slims down the 721 implementation
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Address.sol";

import "./IKetherHomepage.sol";

// XXX
import "hardhat/console.sol";

// TODO: Name this something really cool
contract Wrapper {
  constructor(address target, bytes calldata payload) {
    (bool success,) = target.call(payload);
    require(success);
    selfdestruct();
  }
}

contract KetherNFT is ERC721 {
  /// instance is the KetherHomepage contract that this wrapper interfaces with.
  IKetherHomepage public instance;

  /// metadataSigner provides oracle authenticity for tokenURI content.
  address public metadataSigner;

  // TODO: Do we want to emit events?

  constructor(address _ketherContract, address _metadataSigner) ERC721("Thousand Ether Homepage Ad", "1KAD") {
    instance = IKetherHomepage(_ketherContract);
    metadataSigner = _metadataSigner;
  }

  function _wrapPayload(uint _idx, address _owner) internal pure bytes32 {
    return abi.encodeWithSignature("setAdOwner(uint256,address)", _idx, address(this));
  }

  function precompute(uint _idx, address _owner) pure public (bytes32 salt, address wrapper) {
    bytes32 salt = bytes32(_owner);

    address predictedAddress = address(uint160(uint(keccak256(abi.encodePacked(
      bytes1(0xff),
      address(this),
      salt,
      keccak256(abi.encodePacked( // FIXME: Should this be encodeWithSignature?
        type(Wrapper).creationCode,
        address(instance), _wrapPayload(_idx, _owner),
      ))
    )))));
    return salt, predictedAddress;
  }

  /// wrap mints an NFT if the ad unit's ownership has been trasnferred to this contract.
  function wrap(uint _idx, address _owner) external {
    bytes32 salt, address precomputerWrapper = precompute(_owner);

    require(instance.ads[_idx].owner == precomputedWrapper, "KetherNFT: owner needs to be our wrapper");

    // Wrapper self-destructs on construction
    new Wrapper{salt: salt}(_wrapPayload(_idx, _owner));

    require(instance.ads[_idx].owner == address(this), "KetherNFT: owner needs to be KetherNFT");
    _mint(_owner, _idx);
  }

  function unwrap(uint _idx, address _newOwner) external {
    require(ownerOf(_idx) == msg.sender, "KetherNFT: unwrap for sender that is not owner");

    instance.setAdOwner(_idx, _newOwner);
    _burn(_idx);
  }

  // TODO: Should we have a setTokenURI function so owners can change the rendering of their token?
  // TODO: If we let people set their own tokenURI, do we need another NSFW flag option here?

  function tokenURI(uint256 _tokenId) public view virtual override(ERC721) returns (string memory) {
    // FIXME: Replace with IPFS URI? Perhaps set on wrap?
    return "ipfs://1000ether.com/ad/TODO"; // FIXME: Need to convert the uint256 to string, maybe Strings.uint2str?
  }

  /// publish is a delegated proxy for KetherHomapage's publish function.
  ///
  /// Publish allows for setting the link, image, and NSFW status for the ad
  /// unit that is identified by the idx which was returned during the buy step.
  /// The link and image must be full web3-recognizeable URLs, such as:
  ///  - bzz://a5c10851ef054c268a2438f10a21f6efe3dc3dcdcc2ea0e6a1a7a38bf8c91e23
  ///  - bzz://mydomain.eth/ad.png
  ///  - https://cdn.mydomain.com/ad.png
  ///  - https://ipfs.io/ipfs/Qme7ss3ARVgxv6rXqVPiikMJ8u2NLgmgszg13pYrDKEoiu
  ///  - ipfs://Qme7ss3ARVgxv6rXqVPiikMJ8u2NLgmgszg13pYrDKEoiu
  /// Images should be valid PNG.
  /// Content-addressable storage links like IPFS are encouraged.
  function publish(uint _idx, string calldata _link, string calldata _image, string calldata _title, bool _NSFW) external {
    require(getApproved(_idx) == msg.sender, "KetherNFT: publish for sender that is not approved");

    instance.publish(_idx, _link, _image, _title, _NSFW);
  }

}

//SPDX-License-Identifier: MIT
pragma solidity ^0.8;

// FIXME: Use 4.x pre-release which slims down the 721 implementation
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Address.sol";

import "./IKetherHomepage.sol";

// XXX
import "hardhat/console.sol";

// 1. Precompute deterministic contract address 0xSWAP
// 2. Call on-chain KetherHomepage.setAdOwner(_idx, 0xSWAP)
// 3. Call on-chain deploy TransientOwnerSwapper(address(KetherNFT), _idx) to address 0xSWAP
//    -> Inside, it calls KetherNFT.wrap(_idx)?

contract TransientOwnerSwapper {
  uint idx;
  address to;
  IKetherHomepage kether;

  constructor(IKetherHomepage _kether, KetherNFT _target, uint _idx) {
    idx = _idx;
    to = address(_target);
    kether = _kether;

    _target.wrap(_idx, msg.sender);

    selfdestruct();
  }

  function transfer() external {
    _kether.setAdOwner(idx, to);
  }
}

contract Wrapper {
  address authorized;

  constructor(address _authorized) {
    authorized = _authorized;
  }

  function call(address target, bytes memory payload) (bool, bytes memory) {
    require(msg.sender == authorized, "Wrapper: call must be done by authorized sender");

    return target.call(payload);
  }
}

interface Transferer {
  function transfer(address _from, address _to, uint _tokenId) external;
}

contract KetherNFT is ERC721 {
  /// instance is the KetherHomepage contract that this wrapper interfaces with.
  IKetherHomepage public instance;

  /// metadataSigner provides oracle authenticity for tokenURI content.
  address public metadataSigner;

  // TODO: Do we want to emit events?

  constructor(address _ketherContract, address _metadataSigner) ERC721("Thousand Ether Homepage Ad", "1KAD") {
    instance = IKetherHomepage(_ketherContract);
    metadataSigner = _metadataSigner;
  }

  function precompute(address _owner) pure public (bytes32 salt, address wrapper) {
    bytes32 salt = bytes32(_owner);

    address predictedAddress = address(uint160(uint(keccak256(abi.encodePacked(
      bytes1(0xff),
      address(this),
      salt,
      keccak256(abi.encodePacked(
        type(D).creationCode,
        arg
      ))
    )))));
    return salt, predictedAddress;
  }

  /// wrap mints an NFT if the ad unit's ownership has been trasnferred to this contract.
  function wrap(uint _idx, address _owner) external {
    bytes32 salt, address precomputerWrapper = precompute(_owner);

    require(instance.ads[_idx].owner == precomputedWrapper, "KetherNFT: owner needs to be our wrapper");

    // TODO: Check if wrapper already exists on precomputed address, use that instead.
    Wrapper w = new Wrapper{salt: salt}(address(this));
    require(address(w) == precomputedWrapper, "KetherNFT: precomputedWrapper is incorrect");

    (bool success,) = w.call(
      address(instance),
      abi.encodeWithSignature("setAdOwner(uint256,address)", _idx, address(this)));
    require(success, "KetherNFT: setAdOwner call failed");

    require(instance.ads[_idx].owner == address(this), "KetherNFT: owner needs to be KetherNFT");
    _mint(_owner, _idx);
  }

  function unwrap(uint _idx, address _newOwner) external {
    require(ownerOf(_idx) == msg.sender, "KetherNFT: unwrap for sender that is not owner");

    (bool success,) = w.call(
      address(instance),
      abi.encodeWithSignature("setAdOwner(uint256,address)", _idx, msg.sender));
    require(success, "KetherNFT: setAdOwner call failed");

    _burn(_idx);
  }

  // TODO: Should we have a setTokenURI function so owners can change the rendering of their token?
  // TODO: If we let people set their own tokenURI, do we need another NSFW flag option here?

  function tokenURI(uint256 _tokenId) public view virtual override(ERC721) returns (string memory) {
    // FIXME: Replace with IPFS URI? Perhaps set on wrap?
    return "ipfs://1000ether.com/ad/TODO"; // FIXME: Need to convert the uint256 to string, maybe Strings.uint2str?
  }

  /// publish is a delegated proxy for KetherHomapage's publish function.
  ///
  /// Publish allows for setting the link, image, and NSFW status for the ad
  /// unit that is identified by the idx which was returned during the buy step.
  /// The link and image must be full web3-recognizeable URLs, such as:
  ///  - bzz://a5c10851ef054c268a2438f10a21f6efe3dc3dcdcc2ea0e6a1a7a38bf8c91e23
  ///  - bzz://mydomain.eth/ad.png
  ///  - https://cdn.mydomain.com/ad.png
  ///  - https://ipfs.io/ipfs/Qme7ss3ARVgxv6rXqVPiikMJ8u2NLgmgszg13pYrDKEoiu
  ///  - ipfs://Qme7ss3ARVgxv6rXqVPiikMJ8u2NLgmgszg13pYrDKEoiu
  /// Images should be valid PNG.
  /// Content-addressable storage links like IPFS are encouraged.
  function publish(uint _idx, string calldata _link, string calldata _image, string calldata _title, bool _NSFW) external {
    require(getApproved(_idx) == msg.sender, "KetherNFT: publish for sender that is not approved");

    // TODO: Finish this lol
    (bool success,) = w.call(
      address(instance),
      abi.encodeWithSignature("publish(uint256,string,string,string,bool)", _idx, _link, _image, _title, _NSFW));

    require(success, "KetherNFT: publish call failed");
  }

}


added basic clone functionality

added basic clone functionality

pragma solidity ^0.5.0;

import "./external/MiniMeToken.sol";
import "./external/ERC20.sol";
import "./external/Owned.sol";

/**
    The goal of this contract is to allow investing directly in the value of a person.
    1. Investors mint time tokens up to a maximum based on the user's age
    2. Each time token has a reserve backing to ensure a price floor on the value of the person's time
    3. The medao owner can generate a set amount of tokens over time as compensation for work done
**/
contract MeDao is Owned, TokenController {

    address public factory;
    uint public blockInitialized;

    MiniMeToken public timeToken;
    ERC20 public reserveToken;
    int public birthTimestamp;
    uint public maxTokenSupply;
    uint public lastPayTimestamp;

    address public identity;
    string public hash;
    address[] public clones;

    constructor () public {
        blockInitialized = block.number;
    }

    function initialize (
        address _owner,
        MiniMeToken _timeToken,
        ERC20 _reserveToken,
        int _birthTimestamp,
        uint _tokenClaim
    ) public {
        require(blockInitialized == 0, 'contract already initialized');
        require(_birthTimestamp < int(now), 'invalid birth timestamp');

        blockInitialized = block.number;
        factory = msg.sender;

        owner = _owner;
        identity = _owner;
        timeToken = _timeToken;
        reserveToken = _reserveToken;
        birthTimestamp = _birthTimestamp;

        uint elapsedSeconds = uint(int(now) - birthTimestamp);
        maxTokenSupply = calculateWorkTime(elapsedSeconds);
        lastPayTimestamp = now;

        require(timeToken.generateTokens(owner, _tokenClaim), "failed to generate tokens");
    }

    function getClones () public view returns (address[] memory) {
        return clones;
    }

    function getTotalClones () public view returns (uint) {
        return clones.length;
    }

    function calculateTokenClaim (uint reserveAmount) public view returns (uint) {
        return timeToken.totalSupply() * reserveAmount / reserveToken.balanceOf(address(this));
    }

    function calculateReserveClaim (uint tokenAmount) public view returns (uint) {
        return reserveToken.balanceOf(address(this)) * tokenAmount / timeToken.totalSupply();
    }

    function calculateWorkTime (uint elapsedSeconds) public pure returns (uint) {
        return (elapsedSeconds * 1 ether) * 40 / 168;
    }

    function pay () public onlyOwner {
        uint elapsedSeconds = now - lastPayTimestamp;
        uint workTime = calculateWorkTime(elapsedSeconds);
        uint fundedTime = workTime * timeToken.totalSupply() / maxTokenSupply;
        maxTokenSupply += workTime;
        lastPayTimestamp = now;
        require(timeToken.generateTokens(owner, fundedTime), "failed to generate tokens");
        emit Pay_event(fundedTime);
    }

    function deposit (uint reserveAmount) public {
        uint availableSeconds = maxTokenSupply - timeToken.totalSupply();
        uint claimedTokens = calculateTokenClaim(reserveAmount);
        require(availableSeconds >= claimedTokens, "invalid reserve amount");
        require(reserveToken.transferFrom(msg.sender, address(this), reserveAmount), "failed to transfer");
        require(timeToken.generateTokens(msg.sender, claimedTokens), "failed to generate tokens");
        emit Deposit_event(msg.sender, reserveAmount, claimedTokens);
    }

    function withdraw (uint tokenAmount) public {
        uint reserveClaim = calculateReserveClaim(tokenAmount);
        require(timeToken.destroyTokens(msg.sender, tokenAmount), "failed to destroy tokens");
        require(reserveToken.transfer(msg.sender, reserveClaim), "failed to transfer");
        emit Withdraw_event(msg.sender, tokenAmount, reserveClaim);
    }

    function burn (uint tokenAmount) public {
        require(timeToken.destroyTokens(msg.sender, tokenAmount), "failed to burn tokens");
        emit Burn_event(msg.sender, tokenAmount);
    }

    function setHash (string memory newHash) public onlyOwner {
        hash = newHash;
        emit NewHash_event(newHash);
    }

    function setIdentity (address newIdentity) public onlyOwner {
        identity = newIdentity;
        emit NewIdentity_event(newIdentity);
    }

    event Pay_event (uint tokenAmount);
    event Clone_event (address token);
    event Deposit_event (address msgSender, uint reserveAmount, uint tokenAmount);
    event Withdraw_event (address msgSender, uint tokenAmount, uint reserveAmount);
    event Burn_event (address msgSender, uint tokenAmount);
    event NewHash_event (string newHash);
    event NewIdentity_event (address newIdentity);

/// Token Controller Functions

    function proxyPayment (address _owner) public payable returns(bool) {
        _owner;
        return false;
    }

    function onTransfer (address _from, address _to, uint _amount) public returns(bool) {
        _from; _amount;
        if(_to == address(this) || _to == address(0x0))
            return false;

        return true;
    }

    function onApprove (address _owner, address _spender, uint _amount) public returns(bool) {
        _owner; _spender; _amount;
        return true;
    }

}

pragma solidity ^0.5.0;

import "./external/MiniMeToken.sol";
import "./external/ERC20.sol";
import "./external/Owned.sol";

/**
    The goal of this contract is to allow investing directly in the value of a person.
    1. Investors mint time tokens up to a maximum based on the user's age
    2. Each time token has a reserve backing to ensure a price floor on the value of the person's time
    3. The medao owner can generate a set amount of tokens over time as compensation for work done
**/
contract MeDao is Owned, TokenController {

    address public factory;
    uint public blockInitialized;

    MiniMeToken public timeToken;
    ERC20 public reserveToken;
    int public birthTimestamp;
    uint public maxTokenSupply;
    uint public lastPayTimestamp;

    address public identity;
    string public hash;

    constructor () public {
        blockInitialized = block.number;
    }

    function initialize (
        address _owner,
        MiniMeToken _timeToken,
        ERC20 _reserveToken,
        int _birthTimestamp,
        uint _tokenClaim
    ) public {
        require(blockInitialized == 0, 'contract already initialized');
        require(_birthTimestamp < int(now), 'invalid birth timestamp');

        blockInitialized = block.number;
        factory = msg.sender;

        owner = _owner;
        identity = _owner;
        timeToken = _timeToken;
        reserveToken = _reserveToken;
        birthTimestamp = _birthTimestamp;

        uint elapsedSeconds = uint(int(now) - birthTimestamp);
        maxTokenSupply = calculateWorkTime(elapsedSeconds);
        lastPayTimestamp = now;

        require(timeToken.generateTokens(owner, _tokenClaim), "failed to generate tokens");
    }

    function calculateTokenClaim (uint reserveAmount) public view returns (uint) {
        return timeToken.totalSupply() * reserveAmount / reserveToken.balanceOf(address(this));
    }

    function calculateReserveClaim (uint tokenAmount) public view returns (uint) {
        return reserveToken.balanceOf(address(this)) * tokenAmount / timeToken.totalSupply();
    }

    function calculateWorkTime (uint elapsedSeconds) public pure returns (uint) {
        return (elapsedSeconds * 1 ether) * 40 / 168;
    }

    function pay () public onlyOwner {
        uint elapsedSeconds = now - lastPayTimestamp;
        uint workTime = calculateWorkTime(elapsedSeconds);
        uint fundedTime = workTime * timeToken.totalSupply() / maxTokenSupply;
        maxTokenSupply += workTime;
        lastPayTimestamp = now;
        require(timeToken.generateTokens(owner, fundedTime), "failed to generate tokens");
        emit Pay_event(fundedTime);
    }

    function deposit (uint reserveAmount) public {
        uint availableSeconds = maxTokenSupply - timeToken.totalSupply();
        uint claimedTokens = calculateTokenClaim(reserveAmount);
        require(availableSeconds >= claimedTokens, "invalid reserve amount");
        require(reserveToken.transferFrom(msg.sender, address(this), reserveAmount), "failed to transfer");
        require(timeToken.generateTokens(msg.sender, claimedTokens), "failed to generate tokens");
        emit Deposit_event(msg.sender, reserveAmount, claimedTokens);
    }

    function withdraw (uint tokenAmount) public {
        uint reserveClaim = calculateReserveClaim(tokenAmount);
        require(timeToken.destroyTokens(msg.sender, tokenAmount), "failed to destroy tokens");
        require(reserveToken.transfer(msg.sender, reserveClaim), "failed to transfer");
        emit Withdraw_event(msg.sender, tokenAmount, reserveClaim);
    }

    function burn (uint tokenAmount) public {
        require(timeToken.destroyTokens(msg.sender, tokenAmount), "failed to burn tokens");
        emit Burn_event(msg.sender, tokenAmount);
    }

    function setHash (string memory newHash) public onlyOwner {
        hash = newHash;
        emit NewHash_event(newHash);
    }

    function setIdentity (address newIdentity) public onlyOwner {
        identity = newIdentity;
        emit NewIdentity_event(newIdentity);
    }

    event Pay_event (uint tokenAmount);
    event Deposit_event (address msgSender, uint reserveAmount, uint tokenAmount);
    event Withdraw_event (address msgSender, uint tokenAmount, uint reserveAmount);
    event Burn_event (address msgSender, uint tokenAmount);
    event NewHash_event (string newHash);
    event NewIdentity_event (address newIdentity);

/// Token Controller Functions

    function proxyPayment (address _owner) public payable returns(bool) {
        _owner;
        return false;
    }

    function onTransfer (address _from, address _to, uint _amount) public returns(bool) {
        _from; _amount;
        if(_to == address(this) || _to == address(0x0))
            return false;

        return true;
    }

    function onApprove (address _owner, address _spender, uint _amount) public returns(bool) {
        _owner; _spender; _amount;
        return true;
    }

}


Add public to PullPaymentCapable data

Add public to PullPaymentCapable data

/*
 * PullPaymentCapable
 * Base contract supporting async send for pull payments.
 * Inherit from this contract and use asyncSend instead of send.
 */
contract PullPaymentCapable {
  mapping(address => uint) public payments;

  // store sent amount as credit to be pulled, called by payer
  function asyncSend(address dest, uint amount) internal {
    payments[dest] += amount;
  }

  // withdraw accumulated balance, called by payee
  function withdrawPayments() external {
    uint payment = payments[msg.sender];
    payments[msg.sender] = 0;
    if (!msg.sender.send(payment)) {
      payments[msg.sender] = payment;
    }
  }
}

/*
 * PullPaymentCapable
 * Base contract supporting async send for pull payments.
 * Inherit from this contract and use asyncSend instead of send.
 */
contract PullPaymentCapable {
  mapping(address => uint) payments;

  // store sent amount as credit to be pulled, called by payer
  function asyncSend(address dest, uint amount) internal {
    payments[dest] += amount;
  }

  // withdraw accumulated balance, called by payee
  function withdrawPayments() external {
    uint payment = payments[msg.sender];
    payments[msg.sender] = 0;
    if (!msg.sender.send(payment)) {
      payments[msg.sender] = payment;
    }
  }
}


Remove assert and send in favor of transfer for PullPayment.sol (#823)

* Removed assert from send() and changed to transfer()

* Slightly adapted docs

pragma solidity ^0.4.18;

import "../math/SafeMath.sol";

/**
 * @title PullPayment
 * @dev Base contract supporting async send for pull payments. Inherit from this
 * contract and use asyncSend instead of send or transfer.
 */
contract PullPayment {
  using SafeMath for uint256;

  mapping(address => uint256) public payments;
  uint256 public totalPayments;

  /**
  * @dev Withdraw accumulated balance, called by payee.
  */
  function withdrawPayments() public {
    address payee = msg.sender;
    uint256 payment = payments[payee];

    require(payment != 0);
    require(this.balance >= payment);

    totalPayments = totalPayments.sub(payment);
    payments[payee] = 0;

    payee.transfer(payment);
  }

  /**
  * @dev Called by the payer to store the sent amount as credit to be pulled.
  * @param dest The destination address of the funds.
  * @param amount The amount to transfer.
  */
  function asyncSend(address dest, uint256 amount) internal {
    payments[dest] = payments[dest].add(amount);
    totalPayments = totalPayments.add(amount);
  }
}

pragma solidity ^0.4.18;

import "../math/SafeMath.sol";

/**
 * @title PullPayment
 * @dev Base contract supporting async send for pull payments. Inherit from this
 * contract and use asyncSend instead of send.
 */
contract PullPayment {
  using SafeMath for uint256;

  mapping(address => uint256) public payments;
  uint256 public totalPayments;

  /**
  * @dev withdraw accumulated balance, called by payee.
  */
  function withdrawPayments() public {
    address payee = msg.sender;
    uint256 payment = payments[payee];

    require(payment != 0);
    require(this.balance >= payment);

    totalPayments = totalPayments.sub(payment);
    payments[payee] = 0;

    assert(payee.send(payment));
  }

  /**
  * @dev Called by the payer to store the sent amount as credit to be pulled.
  * @param dest The destination address of the funds.
  * @param amount The amount to transfer.
  */
  function asyncSend(address dest, uint256 amount) internal {
    payments[dest] = payments[dest].add(amount);
    totalPayments = totalPayments.add(amount);
  }
}


chack balance market

chack balance market

contract token {
    string public assetName;
    address public daoAddr;
    address public owner;
    mapping (address => uint) public tokenBalanceOf;
    DAO daoToken;

    /*Initial */
    function token(string _assetName) {
        assetName = _assetName;
        owner = msg.sender;
    }

    /* DAO functions */
    function emission(address _agentContrAddr, uint _amount) returns(bool result) {
        if(msg.sender==daoAddr || msg.sender==owner)
        {
            tokenBalanceOf[_agentContrAddr] += _amount;
            return true;
        }
        return false;
    }

    function burn(address _agentContrAddr, uint _amount) returns(bool result) {
        if(msg.sender==daoAddr && tokenBalanceOf[_agentContrAddr]>=_amount)
        {
            tokenBalanceOf[_agentContrAddr] -= _amount;
            return true;
        }
        return false;
    }

    function setDaoAddr(address _daoAddr) {
        DAO dao = DAO(_daoAddr);
        address agentContrAddr = dao.agentContractOf(msg.sender);
        if(dao.agentActiveOf(agentContrAddr)) {
            daoAddr = _daoAddr;
        }
    }

    /* Agent function */
    function sendToken(address receiver, uint amount) returns(bool result) {
        if (tokenBalanceOf[msg.sender] < amount) {return false;}
        tokenBalanceOf[msg.sender] -= amount;
        tokenBalanceOf[receiver] += amount;
        return true;
    }
}

contract DAO {
    address public daoFounder;
    address public daoFounderContr;
    address public daoMarketContr;
    address public daoGovermentContr;
    bool public initialization;
    uint public creditAmount;
    uint public sharesAmount;
    uint public creditTurn;
    uint public numAgents;

    token public daoShares;
    token public daoCredits;

    /* Assets data */
    Asset[] public assetsList;
    mapping (address => uint) public assetDataOf;
    mapping (address => bool) public assetExistOf;
    struct Asset {
        address assetAddr;
    }

    /* Agents data */
    Agent[] public agentsList;
    mapping (address => uint) public agentDataOf;
    mapping (address => bool) public agentActiveOf;
    mapping (address => address) public agentContractOf;
    struct Agent {
        address agentContrAddr;
        uint joinData;
    }

    function DAO(token _shares, token _credits, agent _daoFounderContr, market _daoMarketContr, goverment _daoGovermentContr) {
        daoFounder = msg.sender;
        daoShares = token(_shares);
        daoCredits = token(_credits);
        daoFounderContr = _daoFounderContr;
        daoMarketContr = _daoMarketContr;
        daoGovermentContr = _daoGovermentContr;
    }

    function setMarket(address _daoMarketContr) {
        if(msg.sender == daoFounder) {
        	daoMarketContr = _daoMarketContr;
        }
    }

    function initializationDaoBalances(uint _founderSharesAmount, uint _founderCreditsAmount) returns (bool result) {
        if(!initialization) {
			daoShares.emission(daoFounderContr, _founderSharesAmount);
			sharesAmount = _founderSharesAmount;
			daoCredits.emission(daoFounderContr, _founderCreditsAmount);
			creditAmount = _founderCreditsAmount;
			initialization = true;
			return true;
        }
    }

    function daoEfficiency() returns (uint daoEfficiency) {
        daoEfficiency = creditTurn*100/creditAmount;
    }

    function daoShareCost() returns (uint shareCost) {
        shareCost = creditTurn/sharesAmount;
    }

    function daoCreditPower() returns (uint creditPower) {
        creditPower = sharesAmount*100/creditTurn;
    }

    function daoShareSale(uint _shareAmount) returns (uint creditReward) {
        if(daoShares.tokenBalanceOf(msg.sender)>=_shareAmount) {
            creditReward = daoShareCost()*_shareAmount;
            daoCredits.emission(msg.sender, creditReward);
            daoShares.burn(msg.sender, _shareAmount);
        }
    }

    function daoShareBuy(uint _creditAmount) returns (uint shares) {
        if(daoCredits.tokenBalanceOf(msg.sender)>=_creditAmount) {
            shares = daoCreditPower()*_creditAmount;
            daoShares.emission(msg.sender, shares);
            daoCredits.burn(msg.sender, _creditAmount);
        }
    }

    function daoSharesEmission(address _agentContrAddr, uint _sharesAmount) {
        daoShares.emission(_agentContrAddr, _sharesAmount);
    }

    function daoCreditEmission(address _agentContrAddr, uint _creditsAmount) {
        daoCredits.emission(_agentContrAddr, _creditsAmount);
    }

    function setAgent(address _agentContAddr) returns(uint agentID) {
        if(daoShares.tokenBalanceOf(msg.sender)>0) {
            agentID = agentsList.length++;
            Agent a = agentsList[agentID];
            a.agentContrAddr = _agentContAddr;
            a.joinData = now;
            uint newAgentSharesAmount;
            numAgents = agentID + 1;
            newAgentSharesAmount = sharesAmount/numAgents*daoEfficiency();
            daoShares.emission(_agentContAddr, newAgentSharesAmount);
            agentDataOf[_agentContAddr] = agentID;
            agentActiveOf[_agentContAddr] = true;
            agent Agn = agent(_agentContAddr);
            agentContractOf[Agn.agentAddr()] = _agentContAddr;
            return agentID;
        }
    }

    function setAssets(address _assetAddr) returns(uint assetID) {
        if (agentActiveOf[msg.sender] == true) {
            assetID = assetsList.length++;
            Asset a = assetsList[assetID];
            a.assetAddr = _assetAddr;
            assetDataOf[_assetAddr] = assetID;
            assetExistOf[_assetAddr] = true;
            return assetID;
        }
    }
}

contract agent {
    address public agentAddr;
    address controlAddr;
    address daoAddr;
    DAO public dao;

    /* Agents contract list*/

    AgentContract[] public agentContractList;
    struct AgentContract {
        address agentContractAddr;
        string abi;
        string desc;
        bool active;
    }

    modifier controlCheck { if (msg.sender == controlAddr) _ }

    function agent() {
        agentAddr = msg.sender;
        controlAddr = msg.sender;
    }

    function addAsset(address _tokenAddr) {
        if (msg.sender == agentAddr) {
			dao.setAssets(_tokenAddr);
		}
    }

    function sendToken(address assetAddr, address receiver, uint amount) {
        if (msg.sender == agentAddr || msg.sender == dao.daoMarketContr()) {
			token asset = token(assetAddr);
			asset.sendToken(receiver, amount);
		}
    }

    function setDao(address _daoAddr) {
        if(msg.sender == agentAddr) {
        	daoAddr = _daoAddr;
			dao = DAO(daoAddr);
        }
    }

    function setControlAddr(address _controlAddr) returns(bool result) {
        if(msg.sender == agentAddr) {
            controlAddr = _controlAddr;
        }
    }

    function setNewAgent(address _agentAddr) controlCheck returns(bool result) {
        dao.setAgent(_agentAddr);
        return true;
    }

    function setAgentContract(address _agentContractAddr, string _abi, string _desc) controlCheck returns(uint contractID) {
        contractID = agentContractList.length++;
        AgentContract a = agentContractList[contractID];
        a.agentContractAddr = _agentContractAddr;
        a.abi = _abi;
        a.desc = _desc;
        a.active = true;
        return contractID;
    }

    function inactiveAgentContract(address _agentContractAddr) controlCheck returns(bool result) {

    }
}

contract market {
    address daoAddr;
    DAO public dao;

    struct Order {
        uint orderID;
        address owner;
        uint total;
        uint unitPrice;
        uint min;
        uint step;
        bool active;
    }

    struct SaleAssetList {
        address assetAddr;
        Order[] sellOrderList;
    }

    struct BuyAssetList {
        address assetAddr;
        Order[] buyOrderList;
    }

    SaleAssetList[] public sellAssetList;
    Order[] public sellOrderList;
    mapping (address => bool) public sellExistOf;
    mapping (address => uint) public sellDataOf;

    BuyAssetList[] public buyAssetList;
    Order[] public buyOrderList;
    mapping (address => bool) public buyExistOf;
    mapping (address => uint) public buyDataOf;

    function setDao(address _daoAddr) {
		daoAddr = _daoAddr;
		dao = DAO(daoAddr);
    }

    function addSell(address _assetAddr, uint _total, uint _unitPrice, uint _min, uint _step) returns(uint sellID) {
    	address agentContrAddr = dao.agentContractOf(msg.sender);
        if (dao.agentActiveOf(agentContrAddr) && dao.assetExistOf(_assetAddr)) {
        	uint assetID;
            if (sellExistOf[_assetAddr]) {
                assetID = sellDataOf[_assetAddr];
                SaleAssetList sellAssetOrders = sellAssetList[assetID];
            } else {
            	assetID = sellAssetList.length++;
				sellExistOf[_assetAddr] = true;
                sellAssetOrders = sellAssetList[assetID];
                sellAssetOrders.assetAddr = _assetAddr;
            }
			sellID = sellAssetOrders.sellOrderList.length++;

			Order order = sellAssetOrders.sellOrderList[sellID];
			order.orderID = sellID;
			order.owner = agentContrAddr;
			order.total = _total;
			order.unitPrice = _unitPrice;
			order.min = _min;
			order.step = _step;
			order.active = true;

			return sellID;
        }
    }

    function addBuy(address _assetAddr, uint _total, uint _unitPrice, uint _min, uint _step) returns(uint buyID) {
    	address agentContrAddr = dao.agentContractOf(msg.sender);
        if (dao.agentActiveOf(agentContrAddr) && dao.assetExistOf(_assetAddr)) {
        	uint assetID;
            if (buyExistOf[_assetAddr]) {
                assetID = buyDataOf[_assetAddr];
                BuyAssetList buyAssetOrders = buyAssetList[assetID];
            } else {
            	assetID = buyAssetList.length++;
				buyExistOf[_assetAddr] = true;
                buyAssetOrders = buyAssetList[assetID];
                buyAssetOrders.assetAddr = _assetAddr;
            }
			buyID = buyAssetOrders.buyOrderList.length++;

			Order order = buyAssetOrders.buyOrderList[buyID];
			order.orderID = buyID;
			order.owner = agentContrAddr;
			order.total = _total;
			order.unitPrice = _unitPrice;
			order.min = _min;
			order.step = _step;
			order.active = true;

			return buyID;
        }
    }

    function removeSell(address _assetAddr, uint _orderID) returns(bool result) {
    	if (sellExistOf[_assetAddr]) {
    		address agentContrAddr = dao.agentContractOf(msg.sender);
			uint assetID = sellDataOf[_assetAddr];
			Order order = sellAssetList[assetID].sellOrderList[_orderID];
			if (order.owner == agentContrAddr) {
				order.active = false;
				return true;
			}
		}
		return false;
    }

    function removeBuy(address _assetAddr, uint _orderID) returns(bool result) {
    	if (buyExistOf[_assetAddr]) {
    		address agentContrAddr = dao.agentContractOf(msg.sender);
			uint assetID = buyDataOf[_assetAddr];
			Order order = buyAssetList[assetID].buyOrderList[_orderID];
			if (order.owner == agentContrAddr) {
				order.active = false;
				return true;
			}
		}
		return false;
    }

    function getSell(address _assetAddr, uint _orderID) returns(address owner, uint total, uint unitPrice, uint min, uint step, bool active) {
		if (sellExistOf[_assetAddr]) {
			uint assetID = sellDataOf[_assetAddr];
			Order order = sellAssetList[assetID].sellOrderList[_orderID];
			return (order.owner, order.total, order.unitPrice, order.min, order.step, order.active);
		}
    }

    function getBuy(address _assetAddr, uint _orderID) returns(address owner, uint total, uint unitPrice, uint min, uint step, bool active) {
		if (buyExistOf[_assetAddr]) {
			uint assetID = buyDataOf[_assetAddr];
			Order order = buyAssetList[assetID].buyOrderList[_orderID];
			return (order.owner, order.total, order.unitPrice, order.min, order.step, order.active);
		}
    }

    function BuyDeal(address _assetAddr, uint _amount, uint _orderID) returns(bool result) {
		if (sellExistOf[_assetAddr]) {
            uint assetID = sellDataOf[_assetAddr];
			Order order = sellAssetList[assetID].sellOrderList[_orderID];
			if (order.total > 0 && order.active == true && _amount >= order.min && _amount <= order.total && ((_amount / order.step) * order.step) == _amount) {
				address agent_buy_addr = dao.agentContractOf(msg.sender);
				agent agent_buy = agent(agent_buy_addr);
				agent agent_sell = agent(order.owner);

				token credit = token(dao.daoCredits());
				if (credit.tokenBalanceOf(agent_buy_addr) < (order.unitPrice * _amount)) {
					return false;
				}
				token asset = token(sellAssetList[assetID].assetAddr);
				if (asset.tokenBalanceOf(order.owner) < _amount) {
					return false;
				}

				agent_buy.sendToken(dao.daoCredits(), order.owner, (order.unitPrice * _amount));
				agent_sell.sendToken(sellAssetList[assetID].assetAddr, agent_buy_addr, _amount);

				order.total = order.total - _amount;
				if (order.total == 0) {
					order.active = false;
				}
				return true;
			}
		}
        return false;
    }

    function SellDeal(address _assetAddr, uint _amount, uint _orderID) returns(bool result) {
        if (buyExistOf[_assetAddr]) {
			uint assetID = buyDataOf[_assetAddr];
			Order order = buyAssetList[assetID].buyOrderList[_orderID];
			if (order.total > 0 && order.active == true && _amount >= order.min && _amount <= order.total && ((_amount / order.step) * order.step) == _amount) {
				address agent_sell_addr = dao.agentContractOf(msg.sender);
				agent agent_sell = agent(agent_sell_addr);
				agent agent_buy = agent(order.owner);

				token credit = token(dao.daoCredits());
				if (credit.tokenBalanceOf(order.owner) < (order.unitPrice * _amount)) {
					return false;
				}
				token asset = token(buyAssetList[assetID].assetAddr);
				if (asset.tokenBalanceOf(agent_sell_addr) < _amount) {
					return false;
				}

				agent_sell.sendToken(buyAssetList[assetID].assetAddr, order.owner, _amount);
				agent_buy.sendToken(dao.daoCredits(), agent_sell_addr, (order.unitPrice * _amount));

				order.total = order.total - _amount;
				if (order.total == 0) {
					order.active = false;
				}
				return true;
			}
		}
		return false;
    }
}

contract goverment {
    address daoAddr;
    DAO public dao;
}

contract token {
    string public assetName;
    address public daoAddr;
    address public owner;
    mapping (address => uint) public tokenBalanceOf;
    DAO daoToken;

    /*Initial */
    function token(string _assetName) {
        assetName = _assetName;
        owner = msg.sender;
    }

    /* DAO functions */
    function emission(address _agentContrAddr, uint _amount) returns(bool result) {
        if(msg.sender==daoAddr || msg.sender==owner)
        {
            tokenBalanceOf[_agentContrAddr] += _amount;
            return true;
        }
        return false;
    }

    function burn(address _agentContrAddr, uint _amount) returns(bool result) {
        if(msg.sender==daoAddr && tokenBalanceOf[_agentContrAddr]>=_amount)
        {
            tokenBalanceOf[_agentContrAddr] -= _amount;
            return true;
        }
        return false;
    }

    function setDaoAddr(address _daoAddr) {
        DAO dao = DAO(_daoAddr);
        address agentContrAddr = dao.agentContractOf(msg.sender);
        if(dao.agentActiveOf(agentContrAddr)) {
            daoAddr = _daoAddr;
        }
    }

    /* Agent function */
    function sendToken(address receiver, uint amount) returns(bool result) {
        if (tokenBalanceOf[msg.sender] < amount) {return false;}
        tokenBalanceOf[msg.sender] -= amount;
        tokenBalanceOf[receiver] += amount;
        return true;
    }
}

contract DAO {
    address public daoFounder;
    address public daoFounderContr;
    address public daoMarketContr;
    address public daoGovermentContr;
    bool public initialization;
    uint public creditAmount;
    uint public sharesAmount;
    uint public creditTurn;
    uint public numAgents;

    token public daoShares;
    token public daoCredits;

    /* Assets data */
    Asset[] public assetsList;
    mapping (address => uint) public assetDataOf;
    mapping (address => bool) public assetExistOf;
    struct Asset {
        address assetAddr;
    }

    /* Agents data */
    Agent[] public agentsList;
    mapping (address => uint) public agentDataOf;
    mapping (address => bool) public agentActiveOf;
    mapping (address => address) public agentContractOf;
    struct Agent {
        address agentContrAddr;
        uint joinData;
    }

    function DAO(token _shares, token _credits, agent _daoFounderContr, market _daoMarketContr, goverment _daoGovermentContr) {
        daoFounder = msg.sender;
        daoShares = token(_shares);
        daoCredits = token(_credits);
        daoFounderContr = _daoFounderContr;
        daoMarketContr = _daoMarketContr;
        daoGovermentContr = _daoGovermentContr;
    }

    function setMarket(address _daoMarketContr) {
        if(msg.sender == daoFounder) {
        	daoMarketContr = _daoMarketContr;
        }
    }

    function initializationDaoBalances(uint _founderSharesAmount, uint _founderCreditsAmount) returns (bool result) {
        if(!initialization) {
			daoShares.emission(daoFounderContr, _founderSharesAmount);
			sharesAmount = _founderSharesAmount;
			daoCredits.emission(daoFounderContr, _founderCreditsAmount);
			creditAmount = _founderCreditsAmount;
			initialization = true;
			return true;
        }
    }

    function daoEfficiency() returns (uint daoEfficiency) {
        daoEfficiency = creditTurn*100/creditAmount;
    }

    function daoShareCost() returns (uint shareCost) {
        shareCost = creditTurn/sharesAmount;
    }

    function daoCreditPower() returns (uint creditPower) {
        creditPower = sharesAmount*100/creditTurn;
    }

    function daoShareSale(uint _shareAmount) returns (uint creditReward) {
        if(daoShares.tokenBalanceOf(msg.sender)>=_shareAmount) {
            creditReward = daoShareCost()*_shareAmount;
            daoCredits.emission(msg.sender, creditReward);
            daoShares.burn(msg.sender, _shareAmount);
        }
    }

    function daoShareBuy(uint _creditAmount) returns (uint shares) {
        if(daoCredits.tokenBalanceOf(msg.sender)>=_creditAmount) {
            shares = daoCreditPower()*_creditAmount;
            daoShares.emission(msg.sender, shares);
            daoCredits.burn(msg.sender, _creditAmount);
        }
    }

    function daoSharesEmission(address _agentContrAddr, uint _sharesAmount) {
        daoShares.emission(_agentContrAddr, _sharesAmount);
    }

    function daoCreditEmission(address _agentContrAddr, uint _creditsAmount) {
        daoCredits.emission(_agentContrAddr, _creditsAmount);
    }

    function setAgent(address _agentContAddr) returns(uint agentID) {
        if(daoShares.tokenBalanceOf(msg.sender)>0) {
            agentID = agentsList.length++;
            Agent a = agentsList[agentID];
            a.agentContrAddr = _agentContAddr;
            a.joinData = now;
            uint newAgentSharesAmount;
            numAgents = agentID + 1;
            newAgentSharesAmount = sharesAmount/numAgents*daoEfficiency();
            daoShares.emission(_agentContAddr, newAgentSharesAmount);
            agentDataOf[_agentContAddr] = agentID;
            agentActiveOf[_agentContAddr] = true;
            agent Agn = agent(_agentContAddr);
            agentContractOf[Agn.agentAddr()] = _agentContAddr;
            return agentID;
        }
    }

    function setAssets(address _assetAddr) returns(uint assetID) {
        if (agentActiveOf[msg.sender] == true) {
            assetID = assetsList.length++;
            Asset a = assetsList[assetID];
            a.assetAddr = _assetAddr;
            assetDataOf[_assetAddr] = assetID;
            assetExistOf[_assetAddr] = true;
            return assetID;
        }
    }
}

contract agent {
    address public agentAddr;
    address controlAddr;
    address daoAddr;
    DAO public dao;

    /* Agents contract list*/

    AgentContract[] public agentContractList;
    struct AgentContract {
        address agentContractAddr;
        string abi;
        string desc;
        bool active;
    }

    modifier controlCheck { if (msg.sender == controlAddr) _ }

    function agent() {
        agentAddr = msg.sender;
        controlAddr = msg.sender;
    }

    function addAsset(address _tokenAddr) {
        if (msg.sender == agentAddr) {
			dao.setAssets(_tokenAddr);
		}
    }

    function sendToken(address assetAddr, address receiver, uint amount) {
        if (msg.sender == agentAddr || msg.sender == dao.daoMarketContr()) {
			token asset = token(assetAddr);
			asset.sendToken(receiver, amount);
		}
    }

    function setDao(address _daoAddr) {
        if(msg.sender == agentAddr) {
        	daoAddr = _daoAddr;
			dao = DAO(daoAddr);
        }
    }

    function setControlAddr(address _controlAddr) returns(bool result) {
        if(msg.sender == agentAddr) {
            controlAddr = _controlAddr;
        }
    }

    function setNewAgent(address _agentAddr) controlCheck returns(bool result) {
        dao.setAgent(_agentAddr);
        return true;
    }

    function setAgentContract(address _agentContractAddr, string _abi, string _desc) controlCheck returns(uint contractID) {
        contractID = agentContractList.length++;
        AgentContract a = agentContractList[contractID];
        a.agentContractAddr = _agentContractAddr;
        a.abi = _abi;
        a.desc = _desc;
        a.active = true;
        return contractID;
    }

    function inactiveAgentContract(address _agentContractAddr) controlCheck returns(bool result) {

    }
}

contract market {
    address daoAddr;
    DAO public dao;

    struct Order {
        uint orderID;
        address owner;
        uint total;
        uint unitPrice;
        uint min;
        uint step;
        bool active;
    }

    struct SaleAssetList {
        address assetAddr;
        Order[] sellOrderList;
    }

    struct BuyAssetList {
        address assetAddr;
        Order[] buyOrderList;
    }

    SaleAssetList[] public sellAssetList;
    Order[] public sellOrderList;
    mapping (address => bool) public sellExistOf;
    mapping (address => uint) public sellDataOf;

    BuyAssetList[] public buyAssetList;
    Order[] public buyOrderList;
    mapping (address => bool) public buyExistOf;
    mapping (address => uint) public buyDataOf;

    function setDao(address _daoAddr) {
		daoAddr = _daoAddr;
		dao = DAO(daoAddr);
    }

    function addSell(address _assetAddr, uint _total, uint _unitPrice, uint _min, uint _step) returns(uint sellID) {
    	address agentContrAddr = dao.agentContractOf(msg.sender);
        if (dao.agentActiveOf(agentContrAddr) && dao.assetExistOf(_assetAddr)) {
        	uint assetID;
            if (sellExistOf[_assetAddr]) {
                assetID = sellDataOf[_assetAddr];
                SaleAssetList sellAssetOrders = sellAssetList[assetID];
            } else {
            	assetID = sellAssetList.length++;
				sellExistOf[_assetAddr] = true;
                sellAssetOrders = sellAssetList[assetID];
                sellAssetOrders.assetAddr = _assetAddr;
            }
			sellID = sellAssetOrders.sellOrderList.length++;

			Order order = sellAssetOrders.sellOrderList[sellID];
			order.orderID = sellID;
			order.owner = agentContrAddr;
			order.total = _total;
			order.unitPrice = _unitPrice;
			order.min = _min;
			order.step = _step;
			order.active = true;

			return sellID;
        }
    }

    function addBuy(address _assetAddr, uint _total, uint _unitPrice, uint _min, uint _step) returns(uint buyID) {
    	address agentContrAddr = dao.agentContractOf(msg.sender);
        if (dao.agentActiveOf(agentContrAddr) && dao.assetExistOf(_assetAddr)) {
        	uint assetID;
            if (buyExistOf[_assetAddr]) {
                assetID = buyDataOf[_assetAddr];
                BuyAssetList buyAssetOrders = buyAssetList[assetID];
            } else {
            	assetID = buyAssetList.length++;
				buyExistOf[_assetAddr] = true;
                buyAssetOrders = buyAssetList[assetID];
                buyAssetOrders.assetAddr = _assetAddr;
            }
			buyID = buyAssetOrders.buyOrderList.length++;

			Order order = buyAssetOrders.buyOrderList[buyID];
			order.orderID = buyID;
			order.owner = agentContrAddr;
			order.total = _total;
			order.unitPrice = _unitPrice;
			order.min = _min;
			order.step = _step;
			order.active = true;

			return buyID;
        }
    }

    function removeSell(address _assetAddr, uint _orderID) returns(bool result) {
    	if (sellExistOf[_assetAddr]) {
    		address agentContrAddr = dao.agentContractOf(msg.sender);
			uint assetID = sellDataOf[_assetAddr];
			Order order = sellAssetList[assetID].sellOrderList[_orderID];
			if (order.owner == agentContrAddr) {
				order.active = false;
				return true;
			}
		}
		return false;
    }

    function removeBuy(address _assetAddr, uint _orderID) returns(bool result) {
    	if (buyExistOf[_assetAddr]) {
    		address agentContrAddr = dao.agentContractOf(msg.sender);
			uint assetID = buyDataOf[_assetAddr];
			Order order = buyAssetList[assetID].buyOrderList[_orderID];
			if (order.owner == agentContrAddr) {
				order.active = false;
				return true;
			}
		}
		return false;
    }

    function getSell(address _assetAddr, uint _orderID) returns(address owner, uint total, uint unitPrice, uint min, uint step, bool active) {
		if (sellExistOf[_assetAddr]) {
			uint assetID = sellDataOf[_assetAddr];
			Order order = sellAssetList[assetID].sellOrderList[_orderID];
			return (order.owner, order.total, order.unitPrice, order.min, order.step, order.active);
		}
    }

    function getBuy(address _assetAddr, uint _orderID) returns(address owner, uint total, uint unitPrice, uint min, uint step, bool active) {
		if (buyExistOf[_assetAddr]) {
			uint assetID = buyDataOf[_assetAddr];
			Order order = buyAssetList[assetID].buyOrderList[_orderID];
			return (order.owner, order.total, order.unitPrice, order.min, order.step, order.active);
		}
    }

    function BuyDeal(address _assetAddr, uint _amount, uint _orderID) returns(bool result) {
		if (sellExistOf[_assetAddr]) {
            uint assetID = sellDataOf[_assetAddr];
			Order order = sellAssetList[assetID].sellOrderList[_orderID];
			if (order.total > 0 && order.active == true && _amount >= order.min && _amount <= order.total && ((_amount / order.step) * order.step) == _amount) {
				address agent_buy_addr = dao.agentContractOf(msg.sender);
				agent agent_buy = agent(agent_buy_addr);
				agent_buy.sendToken(dao.daoCredits(), order.owner, (order.unitPrice * _amount));

				agent agent_sell = agent(order.owner);
				agent_sell.sendToken(sellAssetList[assetID].assetAddr, agent_buy_addr, _amount);

				order.total = order.total - _amount;
				if (order.total == 0) {
					order.active = false;
				}
				return true;
			}
		}
        return false;
    }

    function SellDeal(address _assetAddr, uint _amount, uint _orderID) returns(bool result) {
        if (buyExistOf[_assetAddr]) {
			uint assetID = buyDataOf[_assetAddr];
			Order order = buyAssetList[assetID].buyOrderList[_orderID];
			if (order.total > 0 && order.active == true && _amount >= order.min && _amount <= order.total && ((_amount / order.step) * order.step) == _amount) {
				address agent_sell_addr = dao.agentContractOf(msg.sender);
				agent agent_sell = agent(agent_sell_addr);
				agent_sell.sendToken(buyAssetList[assetID].assetAddr, order.owner, _amount);

				agent agent_buy = agent(order.owner);
				agent_buy.sendToken(dao.daoCredits(), agent_sell_addr, (order.unitPrice * _amount));

				order.total = order.total - _amount;
				if (order.total == 0) {
					order.active = false;
				}
				return true;
			}
		}
		return false;
    }
}

contract goverment {
    address daoAddr;
    DAO public dao;
}


update global vars to public

update global vars to public

pragma solidity^0.4.11;

import "./PLCRVoting.sol";
import "./StandardToken.sol";

contract Parameterizer {
	mapping(bytes32 => uint) public params;

	struct ParamProposal {
		string name;
		uint value;
		address owner;
		uint deposit;
	}

	// maps pollIDs to intended data change if poll passes
	mapping(uint => ParamProposal) public proposalMap;

	// Global Variables
    StandardToken public token;
    PLCRVoting public voting;

	/// @param _minDeposit      minimum deposit for listing to be whitelisted
    /// @param _minParamDeposit minimum deposit to propose a parameter change
    /// @param _applyStageLen   length of period in which applicants wait to be whitelisted
    /// @param _dispensationPct percentage of losing party's deposit distributed to winning party
    /// @param _commitPeriodLen length of commit period for voting
    /// @param _revealPeriodLen length of reveal period for voting
    /// @param _voteQuorum      type of majority out of 100 necessary for vote success

	function Parameterizer(
		address tokenAddr,
		uint _minDeposit,
        uint _minParamDeposit,
        uint _applyStageLen,
        uint _commitPeriodLen,
        uint _revealPeriodLen,
        uint _dispensationPct,
        uint _voteQuorum
    ) {
		token = StandardToken(tokenAddr);
		voting = new PLCRVoting(tokenAddr);

		set("minDeposit", _minDeposit);
        set("minParamDeposit", _minParamDeposit);
        set("applyStageLen", _applyStageLen);
        set("commitPeriodLen", _commitPeriodLen);
        set("revealPeriodLen", _revealPeriodLen);
        set("dispensationPct", _dispensationPct);
        set("voteQuorum", _voteQuorum);
	}

	// changes parameter within canonical mapping
	function set(string name, uint value) internal {
		params[sha3(name)] = value;
	}

	// gets parameter by string name from hashMap
	function get(string name) public constant returns (uint value) {
		return params[sha3(name)];
	}

	// starts poll and takes tokens from msg.sender
	function changeParameter(string name, uint value) returns (uint) {
		uint deposit = get("minParamDeposit");
		require(token.transferFrom(msg.sender, this, deposit)); // escrow tokens (deposit amt)

		uint pollID = voting.startPoll("blah",
			get("voteQuorum"),
			get("commitPeriodLen"),
			get("revealPeriodLen")
		);

		// attach name and value to pollID
		proposalMap[pollID] = ParamProposal({
			name: name,
			value: value,
			owner: msg.sender,
			deposit: deposit
		});

		return pollID;
	}

	// updates canonical mapping with evaluation of poll result
	function processProposal(uint pollID) {
		ParamProposal storage prop = proposalMap[pollID];
		// check isPassed ==> update params mapping using set
		if (voting.isPassed(pollID)) {
			set(prop.name, prop.value);
		}
		// release escrowed tokens
		require(token.transfer(prop.owner, prop.deposit));
		prop.deposit = 0; // prevent double-withdrawal
	}
}

pragma solidity^0.4.11;

import "./PLCRVoting.sol";
import "./StandardToken.sol";

contract Parameterizer {
	mapping(bytes32 => uint) public params;

	struct ParamProposal {
		string name;
		uint value;
		address owner;
		uint deposit;
	}

	// maps pollIDs to intended data change if poll passes
	mapping(uint => ParamProposal) public proposalMap;

	PLCRVoting public voting;
	StandardToken token;

	/// @param _minDeposit      minimum deposit for listing to be whitelisted
    /// @param _minParamDeposit minimum deposit to propose a parameter change
    /// @param _applyStageLen   length of period in which applicants wait to be whitelisted
    /// @param _dispensationPct percentage of losing party's deposit distributed to winning party
    /// @param _commitPeriodLen length of commit period for voting
    /// @param _revealPeriodLen length of reveal period for voting
    /// @param _voteQuorum      type of majority out of 100 necessary for vote success

	function Parameterizer(
		address tokenAddr,
		uint _minDeposit,
        uint _minParamDeposit,
        uint _applyStageLen,
        uint _commitPeriodLen,
        uint _revealPeriodLen,
        uint _dispensationPct,
        uint _voteQuorum
    ) {
		token = StandardToken(tokenAddr);
		voting = new PLCRVoting(tokenAddr);

		set("minDeposit", _minDeposit);
        set("minParamDeposit", _minParamDeposit);
        set("applyStageLen", _applyStageLen);
        set("commitPeriodLen", _commitPeriodLen);
        set("revealPeriodLen", _revealPeriodLen);
        set("dispensationPct", _dispensationPct);
        set("voteQuorum", _voteQuorum);
	}

	// changes parameter within canonical mapping
	function set(string name, uint value) internal {
		params[sha3(name)] = value;
	}

	// gets parameter by string name from hashMap
	function get(string name) public constant returns (uint value) {
		return params[sha3(name)];
	}

	// starts poll and takes tokens from msg.sender
	function changeParameter(string name, uint value) returns (uint) {
		uint deposit = get("minParamDeposit");
		require(token.transferFrom(msg.sender, this, deposit)); // escrow tokens (deposit amt)

		uint pollID = voting.startPoll("blah",
			get("voteQuorum"),
			get("commitPeriodLen"),
			get("revealPeriodLen")
		);

		// attach name and value to pollID
		proposalMap[pollID] = ParamProposal({
			name: name,
			value: value,
			owner: msg.sender,
			deposit: deposit
		});

		return pollID;
	}

	// updates canonical mapping with evaluation of poll result
	function processProposal(uint pollID) {
		ParamProposal storage prop = proposalMap[pollID];
		// check isPassed ==> update params mapping using set
		if (voting.isPassed(pollID)) {
			set(prop.name, prop.value);
		}
		// release escrowed tokens
		require(token.transfer(prop.owner, prop.deposit));
		prop.deposit = 0; // prevent double-withdrawal
	}
}


More tests

More tests

import 'dapple/test.sol';
import '../contracts/dao-account.sol';

// Mock DaoChallenge with several test helper methods
contract DaoChallenge {
  address public challengeOwner;
  uint256 public tokenPrice = 1; // 1000000000000000; // 1 finney

  function DaoChallenge (address _challengeOwner) {
    challengeOwner = _challengeOwner;
  }

  function createAccount () returns (DaoAccount) {
    return new DaoAccount(msg.sender, challengeOwner);
  }

  function buyTokens (DaoAccount account) returns (uint256) {
    return account.buyTokens.value(msg.value)();
  }

  function transfer (DaoAccount origin, DaoAccount recipient, uint256 tokens) {
    origin.transfer(tokens, recipient);
  }

  function setTokenPrice (uint256 price) {
    tokenPrice = price;
  }
}

contract User {
  DaoAccount public account;

  function createAccount (DaoChallenge chal) returns (DaoAccount) {
    account = chal.createAccount();
    return account;
  }
  function buyTokens (DaoChallenge chal, uint256 amount) returns (uint256) {
    return chal.buyTokens.value(amount)(account);
  }
  function transfer (DaoChallenge chal, User recipient, uint256 tokens) {
    chal.transfer(account, recipient.account(), tokens);
  }
}

contract DaoAccountTest is Test {
    DaoChallenge chal;
    DaoAccount acc;
    Tester proxy_tester;
    address challenge_owner = address(this);

    User userA;

    function setUp() {
        chal = new DaoChallenge(challenge_owner);
        uint256 mockFunds = 1000;

        userA = new User();
        if(!userA.send(mockFunds)) throw; // Fund User A
        acc = userA.createAccount(chal);

        proxy_tester = new Tester();
        proxy_tester._target(acc);
    }
}

contract DaoAccountConstructorTest is DaoAccountTest {

    function testStoresChallengeOwner() {
        assertEq( address(this), acc.challengeOwner() );
    }

    function testStoresParentChallenge() {
        assertEq( address(chal), acc.daoChallenge() );
    }

    function testStoresUser() {
        assertEq( address(userA), acc.getOwnerAddress() );
    }

    function testInitialTokenBalanceShouldBeZero() {
      assertEq( acc.getTokenBalance(), 0 );
    }

    function testInitialEtherBalanceShouldBeZero() {
      assertEq( acc.balance, 0 );
    }

}

contract DaoAccountBuyTokenTest is DaoAccountTest {
    function testBuyTwoTokens() {
      uint256 tokens = userA.buyTokens(chal, chal.tokenPrice() * 2);
      assertEq( tokens, 2 );
      assertEq( acc.getTokenBalance(), 2 );
      assertEq( acc.balance, chal.tokenPrice() * 2 );
    }

    function testThrowNoFreeTokens() {
      userA.buyTokens(chal, 0);
    }

    function testThrowNoPartialTokens() {
      userA.buyTokens(chal, chal.tokenPrice() / 2);
    }

    function testDifferentTokenPrice() {
      userA.buyTokens(chal, chal.tokenPrice()); // 1 token
      chal.setTokenPrice(3);
      userA.buyTokens(chal, 6); // 2 tokens
      assertEq( acc.getTokenBalance(), 3);
    }

}

contract DaoAccountTransferTest is DaoAccountTest {
  User userB;
  DaoAccount accB;

  function setUp() {
    super.setUp();

    // Buy ten tokens
    userA.buyTokens(chal, chal.tokenPrice() * 10);

    userB = new User();
    accB = userB.createAccount(chal);
  }

  function testTranferOneToken () {
    userA.transfer(chal, userB, 1);

    assertEq( acc.getTokenBalance(), 9);
    assertEq( accB.getTokenBalance(), 1);
  }

  function testThrowTranferTooManyTokens () {
    userA.transfer(chal, userB, 11);
  }

  function testThrowTranferZeroTokens () {
    userA.transfer(chal, userB, 0);
  }

  function testThrowTranferFromEmptyBalance () {
    // First send all tokens
    userA.transfer(chal, userB, 10);

    // This should throw:
    userA.transfer(chal, userB, 1);
  }
}

contract DaoAccountReceiveTokensTest is DaoAccountTest {
  function setUp() {
    super.setUp();

    // Buy ten tokens
    userA.buyTokens(chal, chal.tokenPrice() * 10);
  }
}

import 'dapple/test.sol';
import '../contracts/dao-account.sol';

// Mock DaoChallenge with several test helper methods
contract DaoChallenge {
  uint256 public token_price = 1; // 1000000000000000; // 1 finney

  function createAccount (address challengeOwner) returns (DaoAccount) {
     DaoAccount account = new DaoAccount(this, token_price, challengeOwner);
     return account;
  }

  function buyTokens (DaoAccount account, uint256 amount) returns (uint256) {
    return account.buyTokens.value(amount)();
  }
}

contract DaoAccountTest is Test {
    DaoChallenge chal;
    DaoAccount acc;
    Tester proxy_tester;
    address challenge_owner = address(this);

    function setUp() {
        chal = new DaoChallenge();
        uint256 mockFunds = 1000;
        if(!chal.send(mockFunds)) throw; // Fund the mock DaoChallenge
        acc = chal.createAccount(address(this));
        proxy_tester = new Tester();
        proxy_tester._target(acc);
    }

    // Constructor

    function testConstructorStoresChallengeOwner() {
        assertEq( address(this), acc.challengeOwner() );
    }

    function testConstructorStoresParentChallenge() {
        assertEq( address(chal), acc.daoChallenge() );
    }

    function testConstructorInitialTokenBalanceShouldBeZero() {
      assertEq( acc.getTokenBalance(), 0 );
    }

    function testConstructorInitialEtherBalanceShouldBeZero() {
      assertEq( acc.balance, 0 );
    }

    // buyTokens()

    function testBuyTokensTwoTokens() {
      uint256 tokens = chal.buyTokens(acc, chal.token_price() * 2);
      assertEq( tokens, 2 );
      assertEq( acc.getTokenBalance(), 2 );
      assertEq( acc.balance, chal.token_price() * 2 );
    }

    function testThrowBuyTokensNoFreeTokens() {
      chal.buyTokens(acc, 0);
    }

    function testThrowBuyTokensNoPartialTokens() {
      chal.buyTokens(acc, chal.token_price() / 2);
    }
}