list warranties

list warranties

pragma solidity ^0.4.4;

contract owned {
    address owner;

    modifier ownerOnly() {
        if (msg.sender != owner) throw;
        _;
    }

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

    function getOwner() constant returns (address) {
        return owner;
    }
}

contract mortal is owned {
    function kill() {
        if (msg.sender == owner) selfdestruct(owner);
    }
}

contract PriceCalculator {
    function getWarrantyPrice(string productId, uint startDate, uint endDate, uint productPrice) constant returns (uint) {
        uint yrs = (endDate - startDate) / 1 years;
        /*the price is allways 5% per year*/
        return productPrice * yrs / 20;
    }
}

contract stateful {
    enum RetailerStatus {Undefined, Requested, Accepted, Rejected, Terminated}
    enum InsuranceStatus {Undefined, Requested, Active, Terminated}
    enum WarrantyStatus {Undefined, Created, Confirmed, Canceled}
    enum UserRole {Undefined, Retailer, Insurance, Owner}
}

contract related is stateful{
    struct PartnerRelations {
        RetailerStatus status;
        uint sales /*the total amount of policies sold by retailer*/;
        uint payments /*the total amount paid by retailer*/;
        uint claims /*the total amount the insurance has paid to the retailer in claims*/;
    }
}

contract InsuranceManager is owned, related {
    struct Insurance {
        string name;
        InsuranceStatus status;
        PriceCalculator priceCalculator;
        uint sales;
        uint payments;
        uint claims;
    }

    mapping (address => Insurance) insurances;
    mapping (uint=>address) insuranceList;
    uint public insuranceCount;

    event InsuranceStatusChanged(
        address indexed insurance,
        InsuranceStatus status
    );

    function isInsurance(address insurance) constant returns (bool) {
        return insurances[insurance].status != InsuranceStatus.Undefined;
    }

    function createInsurance(string name, address priceCalculator) {
        Insurance insurance = insurances[msg.sender];
        InsuranceStatus previousStatus = insurance.status;
        insurance.status = InsuranceStatus.Requested;
        if(previousStatus != InsuranceStatus.Undefined) throw;

        insurance.name = name;
        insurance.priceCalculator = PriceCalculator(priceCalculator);
        insuranceList[insuranceCount++] = msg.sender;

        InsuranceStatusChanged(msg.sender, InsuranceStatus.Requested);
    }

    function setInsuranceState(address insuranceAddress, InsuranceStatus status) ownerOnly {
        Insurance insurance = insurances[insuranceAddress];
        if(insurance.status == InsuranceStatus.Undefined) throw;

        insurance.status = status;
    }

    function getInsurance(uint index) constant returns (string name, address, InsuranceStatus) {
        Insurance insurance = insurances[insuranceList[index]];
        return (insurance.name, insuranceList[index], insurance.status);
    }

    function getInsuranceByAddress(address insuranceAddress) constant returns (string name, address, InsuranceStatus) {
            Insurance insurance = insurances[insuranceAddress];
            return (insurance.name, insuranceAddress, insurance.status);
        }

    function getInsuranceStatus(address insuranceAddress) constant returns (InsuranceStatus) {
        return insurances[insuranceAddress].status;
    }

    function getWarrantyPrice(address insuranceAddress, string productId, uint startDate, uint endDate, uint productPrice) constant returns (uint) {
        Insurance insurance = insurances[insuranceAddress];
        if(insurance.status != InsuranceStatus.Active) throw;
        return insurance.priceCalculator.getWarrantyPrice(productId, startDate, endDate, productPrice);
    }

    function getInsuranceBalance(address insuranceAddress) constant returns (uint, uint, uint ) {
        Insurance insurance = insurances[insuranceAddress];
        return (insurance.sales, insurance.payments, insurance.claims);
    }

    function increaseSalesBalance(address insurance, uint amount) {
        insurances[insurance].sales += amount;
    }

    function decreaseSalesBalance(address insurance, uint amount) {
        insurances[insurance].sales -= amount;
    }

    function increasePaymentsBalance(address insurance, uint amount) {
        insurances[insurance].payments += amount;
    }

    function decreasePaymentsBalance(address insurance, uint amount) {
        insurances[insurance].payments -= amount;
    }

    function increaseClaimsBalance(address insurance, uint amount) {
        insurances[insurance].claims += amount;
    }

    function decreaseClaimsBalance(address insurance, uint amount) {
        insurances[insurance].claims -= amount;
    }
}

contract RetailerManager is owned, related {
    InsuranceManager insuranceManager;

    function RetailerManager(address _insuranceManager){
        insuranceManager = InsuranceManager(_insuranceManager);
    }

    function setSubContractAddresses (address _insuranceManager) ownerOnly {
        insuranceManager = InsuranceManager(_insuranceManager);
    }

    modifier insuranceOnly {
        if(!isInsurance(msg.sender)) throw;
        _;
    }

    function isInsurance(address insurance) constant returns (bool) {
        return insuranceManager.getInsuranceStatus(insurance) != InsuranceStatus.Undefined;
    }

    struct Retailer {
        string companyName;
        mapping (address=>PartnerRelations) partnerRelations /*the mapping holds the relation of the partner with each insurance company*/;
        uint insuranceCount;
        mapping (uint=>address) insurances;
        RetailerStatus status/*in order to easily check for the existence of a retailer the first status is also set on the retailer itself*/;
        uint sales;
        uint payments;
        uint claims;
    }

    mapping (address=>Retailer) retailers;
    mapping (uint=>address) retailerList;
    uint public retailerCount;

    event RetailerRequest(
        string indexed companyName,
        address retailerAddress,
        address indexed insurance
    );

    event RetailerStatusChanged(
        address indexed retailer,
        address indexed insurance,
        RetailerStatus status
    );

    /**
    the retailer send a transaction to request registration with an insurer
    */
    function requestRegistration(string companyName, address insurance) {
        Retailer retailer = retailers[msg.sender];
        retailer.companyName = companyName;
        /*make sure the insurance company exists*/
        if(insuranceManager.getInsuranceStatus(insurance) != InsuranceStatus.Active) {
            throw;
        }
        /*make sure no previous request was made*/
        if(retailer.partnerRelations[insurance].status != RetailerStatus.Undefined){
            throw;
        }

        if(retailer.status == RetailerStatus.Undefined){
            retailerList[retailerCount++] = msg.sender;
        }

        retailer.partnerRelations[insurance].status = RetailerStatus.Requested;
        retailer.insurances[retailer.insuranceCount++] = insurance;
        retailer.status = RetailerStatus.Accepted;
        RetailerRequest(companyName, msg.sender, insurance);
    }

    function getInsurance(address retailer, uint idx) constant returns (address) {
        return retailers[retailer].insurances[idx];
    }

    function getRequestState(address retailer, address insurance) constant returns (RetailerStatus) {
        return retailers[retailer].partnerRelations[insurance].status;
    }

    /**
    sets the status of a retailer's request.
    only the insurance to which the request was made can do this
    */
    function setRequestState(address retailer, RetailerStatus status) insuranceOnly {
        retailers[retailer].partnerRelations[msg.sender].status = status;
        RetailerStatusChanged(retailer, msg.sender, status);
    }

    function getRetailerStatus(address retailer, address insurance) returns (RetailerStatus){
        return retailers[retailer].partnerRelations[insurance].status;
    }

    function getRetailerStatus(address retailer) returns (RetailerStatus){
        return retailers[retailer].status;
    }

    /**
    get the nth retailer in the list
    */
    function getRetailer(uint index, address insuranceAddress) constant returns (address, string, RetailerStatus, RetailerStatus) {
        address retailerAddress = retailerList[index];
        Retailer retailer = retailers[retailerAddress];
        return (retailerAddress, retailer.companyName, retailer.status, retailer.partnerRelations[insuranceAddress].status);
    }

    function getRetailerByAddress(address retailerAddress, address insuranceAddress) constant returns (address, string, RetailerStatus, RetailerStatus) {
        Retailer retailer = retailers[retailerAddress];
        return (retailerAddress, retailer.companyName, retailer.status, retailer.partnerRelations[insuranceAddress].status);
    }

    function getRetailerBalances(address retailer, address insurance) constant returns (uint, uint, uint) {
        PartnerRelations partnerRelation = retailers[retailer].partnerRelations[insurance];
        return (partnerRelation.sales, partnerRelation.payments, partnerRelation.claims);
    }

    function getRetailerTotalBalances(address retailerAddress) constant returns (uint, uint, uint) {
        Retailer retailer = retailers[retailerAddress];
        return (retailer.sales, retailer.payments, retailer.claims);
    }

    function increaseSalesBalance(address retailer, address insurance, uint price) {
        retailers[retailer].partnerRelations[insurance].sales += price;
        retailers[retailer].sales += price;
    }

    function decreaseSalesBalance(address retailer, address insurance, uint price) {
        retailers[retailer].partnerRelations[insurance].sales -= price;
        retailers[retailer].sales -= price;
    }

    function increasePaymentsBalance(address retailer, address insurance, uint amount) {
        retailers[retailer].partnerRelations[insurance].payments += amount;
        retailers[retailer].payments += amount;
    }

    function decreasePaymentsBalance(address retailer, address insurance, uint amount) {
        retailers[retailer].partnerRelations[insurance].payments -= amount;
        retailers[retailer].payments -= amount;
    }

    function increaseClaimsBalance(address retailer, address insurance, uint amount) {
        retailers[retailer].partnerRelations[insurance].claims += amount;
        retailers[retailer].claims += amount;
    }

    function decreaseClaimsBalance(address retailer, address insurance, uint amount) {
        retailers[retailer].partnerRelations[insurance].claims -= amount;
        retailers[retailer].claims -= amount;
    }
}

contract Insurechain is mortal, stateful{
    InsuranceManager insuranceManager;
    RetailerManager retailerManager;

    function Insurechain(address _insuranceManager, address _retailerManager) {
        insuranceManager = InsuranceManager(_insuranceManager);
        retailerManager = RetailerManager(_retailerManager);
    }

    function setSubContractAddresses (address _insuranceManager, address _retailerManager) ownerOnly {
        insuranceManager = InsuranceManager(_insuranceManager);
        retailerManager = RetailerManager(_retailerManager);
    }

    struct Claim {
        address retailer /*in theory another retailer than the one who sold the insurance can make a claim*/;
        uint amount;
        string description;
    }

    struct Warranty {
        address retailer;
        uint startDate;
        uint endDate;
        string policyNumber;
        WarrantyStatus status;
        uint productPrice;
        uint warrantyPrice;
        mapping (uint => Claim) claims;
        uint claimCount;
    }

    // mapping of insurance -> productId -> serialNumber -> Warranty
    mapping (address=>mapping( string=>mapping( string=>uint ))) warranties;
    uint public warrantyCount;
    mapping (uint=>Warranty) warrantyList;

    modifier insuranceOnly {
        if(!isInsurance(msg.sender)) throw;
        _;
    }

    function isInsurance(address insurance) constant returns (bool) {
        return insuranceManager.getInsuranceStatus(insurance) != InsuranceStatus.Undefined;
    }

    modifier registeredRetailerOnly(address insurance) {
        if(!isRegisteredRetailer(insurance, msg.sender)) throw;
        _;
    }

    function isRegisteredRetailer(address insurance, address retailer) constant returns (bool) {
        return isInsurance(insurance) && retailerManager.getRequestState(retailer, insurance) == RetailerStatus.Accepted;
    }

    function getRole(address user) constant returns (UserRole) {
        if(user == owner) return UserRole.Owner;
        if(retailerManager.getRetailerStatus(user) == RetailerStatus.Accepted) return UserRole.Retailer;
        if(insuranceManager.getInsuranceStatus(user) == InsuranceStatus.Active) return UserRole.Insurance;

        return UserRole.Undefined;
    }

    function getWarrantyQuote(string productId, address insurance, uint startDate, uint endDate, uint productPrice)
                              constant returns(uint warrantyPrice) {
        return insuranceManager.getWarrantyPrice(insurance, productId, startDate, endDate, productPrice);
    }

    /**
        Creates a new warranty.
        productId: The EAN13 that identifies the product
        serialNumber: the particular product serial number
        insurance: the eth address of the insurance
        startDate: start date of the extended warranty
        endDate: start date of the extended warranty
        price: the price in cents
    */
    function createWarranty(string productId, string serialNumber, address insurance, uint startDate, uint endDate, uint productPrice) registeredRetailerOnly(insurance) {
        uint idx = warranties[insurance][productId][serialNumber];
        if(warrantyList[idx].status != WarrantyStatus.Undefined) throw;

        warranties[insurance][productId][serialNumber] = ++warrantyCount;
        Warranty warranty = warrantyList[warrantyCount];

        warranty.status = WarrantyStatus.Created;
        warranty.startDate = startDate;
        warranty.endDate = endDate;
        warranty.productPrice = productPrice;
        warranty.retailer = msg.sender;
        warranty.warrantyPrice = insuranceManager.getWarrantyPrice(insurance, productId, startDate, endDate, productPrice);
        retailerManager.increaseSalesBalance(msg.sender, insurance, warranty.warrantyPrice);
        insuranceManager.increaseSalesBalance(insurance, warranty.warrantyPrice);
    }

    /**
        Confirms a warranty
        productId: The EAN13 that identifies the product
        serialNumber: the particular product serial number
        policyNumber: the policy number of the warranty
    */
    function confirmWarranty(string productId, string serialNumber, string policyNumber) insuranceOnly {
        uint idx = warranties[msg.sender][productId][serialNumber];
        Warranty warranty = warrantyList[idx];
        if(warranty.status != WarrantyStatus.Created) throw;

        warranty.status = WarrantyStatus.Confirmed;
        warranty.policyNumber = policyNumber;
    }

    /**
        Cacnels a warranty
        productId: The EAN13 that identifies the product
        serialNumber: the particular product serial number
        policyNumber: the policy number of the warranty
    */
    function cancelWarranty(string productId, string serialNumber, address insuranceAddress) registeredRetailerOnly(insuranceAddress) {
        uint idx = warranties[insuranceAddress][productId][serialNumber];
        Warranty warranty = warrantyList[idx];
        /*a warranty can only be canceled if it exists and no claims have been made*/
        if(warranty.status == WarrantyStatus.Undefined || warranty.claimCount > 0) throw;

        warranty.status = WarrantyStatus.Canceled;
        retailerManager.decreaseSalesBalance(msg.sender, insuranceAddress, warranty.warrantyPrice);
        insuranceManager.decreaseSalesBalance(insuranceAddress, warranty.warrantyPrice);
    }

    function getWarranty(string productId, string serialNumber, address insurance) constant returns (uint startDate, uint endDate, WarrantyStatus status,
                         string policyNumber, uint warrantyPrice, uint claimCount) {
        return getWarrantyByIndex(warranties[insurance][productId][serialNumber]);
    }

    function getWarrantyByIndex(uint idx)  constant returns (uint startDate, uint endDate, WarrantyStatus status,
                         string policyNumber, uint warrantyPrice, uint claimCount) {
        Warranty warranty = warrantyList[idx+1];
        return (warranty.startDate, warranty.endDate, warranty.status, warranty.policyNumber, warranty.warrantyPrice, warranty.claimCount);
    }

    function isWarrantyValid(address insurance, string productId, string serialNumber) constant returns(bool) {
        uint idx = warranties[insurance][productId][serialNumber];
        /*the index can not be zero based because else the first warranty would be the default but I don't want to make it 1 based for the user*/
        Warranty warranty = warrantyList[idx];
        return warranty.status == WarrantyStatus.Confirmed && warranty.startDate < now && warranty.endDate > now;
    }

    /**
        create a new claim for an insured product
        productId: The EAN13 that identifies the product
        serialNumber: the particular product serial number
    */
    function createClaim(string productId, string serialNumber, address insurance, uint amount, string description) registeredRetailerOnly(insurance) {
        /*create only works for existing and valid warranties*/
        if(!isWarrantyValid(insurance, productId, serialNumber)) throw;

        uint idx = warranties[insurance][productId][serialNumber];
        Warranty warranty = warrantyList[idx];

        Claim claim = warranty.claims[warranty.claimCount++];
        claim.retailer = msg.sender;
        claim.amount = amount;
        claim.description = description;

        /*increase the retailer's account*/
        retailerManager.increaseClaimsBalance(msg.sender, insurance, amount);
        insuranceManager.increaseClaimsBalance(insurance, amount);
    }

    function getClaim(string productId, string serialNumber, address insurance, uint idx) constant returns (address retailer, uint amount, string description) {
        uint wIdx = warranties[insurance][productId][serialNumber];
        Claim claim = warrantyList[idx].claims[wIdx];
        return (claim.retailer, claim.amount, claim.description);
    }
}

pragma solidity ^0.4.4;

contract owned {
    address owner;

    modifier ownerOnly() {
        if (msg.sender != owner) throw;
        _;
    }

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

    function getOwner() constant returns (address) {
        return owner;
    }
}

contract mortal is owned {
    function kill() {
        if (msg.sender == owner) selfdestruct(owner);
    }
}

contract PriceCalculator {
    function getWarrantyPrice(string productId, uint startDate, uint endDate, uint productPrice) constant returns (uint) {
        uint yrs = (endDate - startDate) / 1 years;
        /*the price is allways 5% per year*/
        return productPrice * yrs / 20;
    }
}

contract stateful {
    enum RetailerStatus {Undefined, Requested, Accepted, Rejected, Terminated}
    enum InsuranceStatus {Undefined, Requested, Active, Terminated}
    enum WarrantyStatus {Undefined, Created, Confirmed, Canceled}
    enum UserRole {Undefined, Retailer, Insurance, Owner}
}

contract related is stateful{
    struct PartnerRelations {
        RetailerStatus status;
        uint sales /*the total amount of policies sold by retailer*/;
        uint payments /*the total amount paid by retailer*/;
        uint claims /*the total amount the insurance has paid to the retailer in claims*/;
    }
}

contract InsuranceManager is owned, related {
    struct Insurance {
        string name;
        InsuranceStatus status;
        PriceCalculator priceCalculator;
        uint sales;
        uint payments;
        uint claims;
    }

    mapping (address => Insurance) insurances;
    mapping (uint=>address) insuranceList;
    uint public insuranceCount;

    event InsuranceStatusChanged(
        address indexed insurance,
        InsuranceStatus status
    );

    function isInsurance(address insurance) constant returns (bool) {
        return insurances[insurance].status != InsuranceStatus.Undefined;
    }

    function createInsurance(string name, address priceCalculator) {
        Insurance insurance = insurances[msg.sender];
        InsuranceStatus previousStatus = insurance.status;
        insurance.status = InsuranceStatus.Requested;
        if(previousStatus != InsuranceStatus.Undefined) throw;

        insurance.name = name;
        insurance.priceCalculator = PriceCalculator(priceCalculator);
        insuranceList[insuranceCount++] = msg.sender;

        InsuranceStatusChanged(msg.sender, InsuranceStatus.Requested);
    }

    function setInsuranceState(address insuranceAddress, InsuranceStatus status) ownerOnly {
        Insurance insurance = insurances[insuranceAddress];
        if(insurance.status == InsuranceStatus.Undefined) throw;

        insurance.status = status;
    }

    function getInsurance(uint index) constant returns (string name, address, InsuranceStatus) {
        Insurance insurance = insurances[insuranceList[index]];
        return (insurance.name, insuranceList[index], insurance.status);
    }

    function getInsuranceByAddress(address insuranceAddress) constant returns (string name, address, InsuranceStatus) {
            Insurance insurance = insurances[insuranceAddress];
            return (insurance.name, insuranceAddress, insurance.status);
        }

    function getInsuranceStatus(address insuranceAddress) constant returns (InsuranceStatus) {
        return insurances[insuranceAddress].status;
    }

    function getWarrantyPrice(address insuranceAddress, string productId, uint startDate, uint endDate, uint productPrice) constant returns (uint) {
        Insurance insurance = insurances[insuranceAddress];
        if(insurance.status != InsuranceStatus.Active) throw;
        return insurance.priceCalculator.getWarrantyPrice(productId, startDate, endDate, productPrice);
    }

    function getInsuranceBalance(address insuranceAddress) constant returns (uint, uint, uint ) {
        Insurance insurance = insurances[insuranceAddress];
        return (insurance.sales, insurance.payments, insurance.claims);
    }

    function increaseSalesBalance(address insurance, uint amount) {
        insurances[insurance].sales += amount;
    }

    function decreaseSalesBalance(address insurance, uint amount) {
        insurances[insurance].sales -= amount;
    }

    function increasePaymentsBalance(address insurance, uint amount) {
        insurances[insurance].payments += amount;
    }

    function decreasePaymentsBalance(address insurance, uint amount) {
        insurances[insurance].payments -= amount;
    }

    function increaseClaimsBalance(address insurance, uint amount) {
        insurances[insurance].claims += amount;
    }

    function decreaseClaimsBalance(address insurance, uint amount) {
        insurances[insurance].claims -= amount;
    }
}

contract RetailerManager is owned, related {
    InsuranceManager insuranceManager;

    function RetailerManager(address _insuranceManager){
        insuranceManager = InsuranceManager(_insuranceManager);
    }

    function setSubContractAddresses (address _insuranceManager) ownerOnly {
        insuranceManager = InsuranceManager(_insuranceManager);
    }

    modifier insuranceOnly {
        if(!isInsurance(msg.sender)) throw;
        _;
    }

    function isInsurance(address insurance) constant returns (bool) {
        return insuranceManager.getInsuranceStatus(insurance) != InsuranceStatus.Undefined;
    }

    struct Retailer {
        string companyName;
        mapping (address=>PartnerRelations) partnerRelations /*the mapping holds the relation of the partner with each insurance company*/;
        uint insuranceCount;
        mapping (uint=>address) insurances;
        RetailerStatus status/*in order to easily check for the existence of a retailer the first status is also set on the retailer itself*/;
        uint sales;
        uint payments;
        uint claims;
    }

    mapping (address=>Retailer) retailers;
    mapping (uint=>address) retailerList;
    uint public retailerCount;

    event RetailerRequest(
        string indexed companyName,
        address retailerAddress,
        address indexed insurance
    );

    event RetailerStatusChanged(
        address indexed retailer,
        address indexed insurance,
        RetailerStatus status
    );

    /**
    the retailer send a transaction to request registration with an insurer
    */
    function requestRegistration(string companyName, address insurance) {
        Retailer retailer = retailers[msg.sender];
        retailer.companyName = companyName;
        /*make sure the insurance company exists*/
        if(insuranceManager.getInsuranceStatus(insurance) != InsuranceStatus.Active) {
            throw;
        }
        /*make sure no previous request was made*/
        if(retailer.partnerRelations[insurance].status != RetailerStatus.Undefined){
            throw;
        }

        if(retailer.status == RetailerStatus.Undefined){
            retailerList[retailerCount++] = msg.sender;
        }

        retailer.partnerRelations[insurance].status = RetailerStatus.Requested;
        retailer.insurances[retailer.insuranceCount++] = insurance;
        retailer.status = RetailerStatus.Accepted;
        RetailerRequest(companyName, msg.sender, insurance);
    }

    function getInsurance(address retailer, uint idx) constant returns (address) {
        return retailers[retailer].insurances[idx];
    }

    function getRequestState(address retailer, address insurance) constant returns (RetailerStatus) {
        return retailers[retailer].partnerRelations[insurance].status;
    }

    /**
    sets the status of a retailer's request.
    only the insurance to which the request was made can do this
    */
    function setRequestState(address retailer, RetailerStatus status) insuranceOnly {
        retailers[retailer].partnerRelations[msg.sender].status = status;
        RetailerStatusChanged(retailer, msg.sender, status);
    }

    function getRetailerStatus(address retailer, address insurance) returns (RetailerStatus){
        return retailers[retailer].partnerRelations[insurance].status;
    }

    function getRetailerStatus(address retailer) returns (RetailerStatus){
        return retailers[retailer].status;
    }

    /**
    get the nth retailer in the list
    */
    function getRetailer(uint index, address insuranceAddress) constant returns (address, string, RetailerStatus, RetailerStatus) {
        address retailerAddress = retailerList[index];
        Retailer retailer = retailers[retailerAddress];
        return (retailerAddress, retailer.companyName, retailer.status, retailer.partnerRelations[insuranceAddress].status);
    }

    function getRetailerByAddress(address retailerAddress, address insuranceAddress) constant returns (address, string, RetailerStatus, RetailerStatus) {
        Retailer retailer = retailers[retailerAddress];
        return (retailerAddress, retailer.companyName, retailer.status, retailer.partnerRelations[insuranceAddress].status);
    }

    function getRetailerBalances(address retailer, address insurance) constant returns (uint, uint, uint) {
        PartnerRelations partnerRelation = retailers[retailer].partnerRelations[insurance];
        return (partnerRelation.sales, partnerRelation.payments, partnerRelation.claims);
    }

    function getRetailerTotalBalances(address retailerAddress) constant returns (uint, uint, uint) {
        Retailer retailer = retailers[retailerAddress];
        return (retailer.sales, retailer.payments, retailer.claims);
    }

    function increaseSalesBalance(address retailer, address insurance, uint price) {
        retailers[retailer].partnerRelations[insurance].sales += price;
        retailers[retailer].sales += price;
    }

    function decreaseSalesBalance(address retailer, address insurance, uint price) {
        retailers[retailer].partnerRelations[insurance].sales -= price;
        retailers[retailer].sales -= price;
    }

    function increasePaymentsBalance(address retailer, address insurance, uint amount) {
        retailers[retailer].partnerRelations[insurance].payments += amount;
        retailers[retailer].payments += amount;
    }

    function decreasePaymentsBalance(address retailer, address insurance, uint amount) {
        retailers[retailer].partnerRelations[insurance].payments -= amount;
        retailers[retailer].payments -= amount;
    }

    function increaseClaimsBalance(address retailer, address insurance, uint amount) {
        retailers[retailer].partnerRelations[insurance].claims += amount;
        retailers[retailer].claims += amount;
    }

    function decreaseClaimsBalance(address retailer, address insurance, uint amount) {
        retailers[retailer].partnerRelations[insurance].claims -= amount;
        retailers[retailer].claims -= amount;
    }
}

contract Insurechain is mortal, stateful{
    InsuranceManager insuranceManager;
    RetailerManager retailerManager;

    function Insurechain(address _insuranceManager, address _retailerManager) {
        insuranceManager = InsuranceManager(_insuranceManager);
        retailerManager = RetailerManager(_retailerManager);
    }

    function setSubContractAddresses (address _insuranceManager, address _retailerManager) ownerOnly {
        insuranceManager = InsuranceManager(_insuranceManager);
        retailerManager = RetailerManager(_retailerManager);
    }

    struct Claim {
        address retailer /*in theory another retailer than the one who sold the insurance can make a claim*/;
        uint amount;
        string description;
    }

    struct Warranty {
        address retailer;
        uint startDate;
        uint endDate;
        string policyNumber;
        WarrantyStatus status;
        uint productPrice;
        uint warrantyPrice;
        mapping (uint => Claim) claims;
        uint claimCount;
    }

    // mapping of insurance -> productId -> serialNumber -> Warranty
    mapping (address=>mapping( string=>mapping( string=>uint ))) warranties;
    uint public warrantyCount;
    mapping (uint=>Warranty) warrantyList;

    modifier insuranceOnly {
        if(!isInsurance(msg.sender)) throw;
        _;
    }

    function isInsurance(address insurance) constant returns (bool) {
        return insuranceManager.getInsuranceStatus(insurance) != InsuranceStatus.Undefined;
    }

    modifier registeredRetailerOnly(address insurance) {
        if(!isRegisteredRetailer(insurance, msg.sender)) throw;
        _;
    }

    function isRegisteredRetailer(address insurance, address retailer) constant returns (bool) {
        return isInsurance(insurance) && retailerManager.getRequestState(retailer, insurance) == RetailerStatus.Accepted;
    }

    function getRole(address user) constant returns (UserRole) {
        if(user == owner) return UserRole.Owner;
        if(retailerManager.getRetailerStatus(user) == RetailerStatus.Accepted) return UserRole.Retailer;
        if(insuranceManager.getInsuranceStatus(user) == InsuranceStatus.Active) return UserRole.Insurance;

        return UserRole.Undefined;
    }

    function getWarrantyQuote(string productId, address insurance, uint startDate, uint endDate, uint productPrice)
                              constant returns(uint warrantyPrice) {
        return insuranceManager.getWarrantyPrice(insurance, productId, startDate, endDate, productPrice);
    }

    /**
        Creates a new warranty.
        productId: The EAN13 that identifies the product
        serialNumber: the particular product serial number
        insurance: the eth address of the insurance
        startDate: start date of the extended warranty
        endDate: start date of the extended warranty
        price: the price in cents
    */
    function createWarranty(string productId, string serialNumber, address insurance, uint startDate, uint endDate, uint productPrice) registeredRetailerOnly(insurance) {
        uint idx = warranties[insurance][productId][serialNumber];
        Warranty warranty = warrantyList[idx];
        if(warranty.status != WarrantyStatus.Undefined) throw;

        warranty.status = WarrantyStatus.Created;
        warranty.startDate = startDate;
        warranty.endDate = endDate;
        warranty.productPrice = productPrice;
        warranty.retailer = msg.sender;
        warranty.warrantyPrice = insuranceManager.getWarrantyPrice(insurance, productId, startDate, endDate, productPrice);
        warrantyList[++warrantyCount] = warranty;
        warranties[insurance][productId][serialNumber] = warrantyCount;
        retailerManager.increaseSalesBalance(msg.sender, insurance, warranty.warrantyPrice);
        insuranceManager.increaseSalesBalance(insurance, warranty.warrantyPrice);
    }

    /**
        Confirms a warranty
        productId: The EAN13 that identifies the product
        serialNumber: the particular product serial number
        policyNumber: the policy number of the warranty
    */
    function confirmWarranty(string productId, string serialNumber, string policyNumber) insuranceOnly {
        uint idx = warranties[msg.sender][productId][serialNumber];
        Warranty warranty = warrantyList[idx];
        if(warranty.status != WarrantyStatus.Created) throw;

        warranty.status = WarrantyStatus.Confirmed;
        warranty.policyNumber = policyNumber;
    }

    /**
        Cacnels a warranty
        productId: The EAN13 that identifies the product
        serialNumber: the particular product serial number
        policyNumber: the policy number of the warranty
    */
    function cancelWarranty(string productId, string serialNumber, address insuranceAddress) registeredRetailerOnly(insuranceAddress) {
        uint idx = warranties[insuranceAddress][productId][serialNumber];
        Warranty warranty = warrantyList[idx];
        /*a warranty can only be canceled if it exists and no claims have been made*/
        if(warranty.status == WarrantyStatus.Undefined || warranty.claimCount > 0) throw;

        warranty.status = WarrantyStatus.Canceled;
        retailerManager.decreaseSalesBalance(msg.sender, insuranceAddress, warranty.warrantyPrice);
        insuranceManager.decreaseSalesBalance(insuranceAddress, warranty.warrantyPrice);
    }

    function getWarranty(string productId, string serialNumber, address insurance) constant returns (uint startDate, uint endDate, WarrantyStatus status,
                         string policyNumber, uint warrantyPrice, uint claimCount) {
        return getWarrantyByIndex(warranties[insurance][productId][serialNumber]);
    }

    function getWarrantyByIndex(uint idx)  constant returns (uint startDate, uint endDate, WarrantyStatus status,
                         string policyNumber, uint warrantyPrice, uint claimCount) {
        Warranty warranty = warrantyList[idx];
        return (warranty.startDate, warranty.endDate, warranty.status, warranty.policyNumber, warranty.warrantyPrice, warranty.claimCount);
    }

    function isWarrantyValid(address insurance, string productId, string serialNumber) constant returns(bool) {
        uint idx = warranties[insurance][productId][serialNumber];
        /*the index can not be zero based because else the first warranty would be the default but I don't want to make it 1 based for the user*/
        Warranty warranty = warrantyList[idx];
        return warranty.status == WarrantyStatus.Confirmed && warranty.startDate < now && warranty.endDate > now;
    }

    /**
        create a new claim for an insured product
        productId: The EAN13 that identifies the product
        serialNumber: the particular product serial number
    */
    function createClaim(string productId, string serialNumber, address insurance, uint amount, string description) registeredRetailerOnly(insurance) {
        /*create only works for existing and valid warranties*/
        if(!isWarrantyValid(insurance, productId, serialNumber)) throw;

        uint idx = warranties[insurance][productId][serialNumber];
        Warranty warranty = warrantyList[idx];

        Claim claim = warranty.claims[warranty.claimCount++];
        claim.retailer = msg.sender;
        claim.amount = amount;
        claim.description = description;

        /*increase the retailer's account*/
        retailerManager.increaseClaimsBalance(msg.sender, insurance, amount);
        insuranceManager.increaseClaimsBalance(insurance, amount);
    }

    function getClaim(string productId, string serialNumber, address insurance, uint idx) constant returns (address retailer, uint amount, string description) {
        uint wIdx = warranties[insurance][productId][serialNumber];
        Claim claim = warrantyList[idx].claims[wIdx];
        return (claim.retailer, claim.amount, claim.description);
    }
}


Refactors the Mintable Token contract

Refactors the Mintable Token contract

pragma solidity ^0.4.11;

import './StandardToken.sol';
import '../ownership/Ownable.sol';

/**
 * @title Mintable token
 * @dev Simple ERC20 Token example, with mintable token creation
 * @dev Issue: * https://github.com/OpenZeppelin/zeppelin-solidity/issues/120
 * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
 */

contract MintableToken is StandardToken, Ownable {
  event Mint(address indexed to, uint amount);
  event MintFinished();

  bool public mintingFinished = false;

  modifier canMint() {
    if(mintingFinished) throw;
    _;
  }

  /**
   * @dev Function to mint tokens
   * @param _to The address that will recieve the minted tokens.
   * @param _amount The amount of tokens to mint.
   * @return A boolean that indicates if the operation was successful.
   */
  function mint(address _to, uint _amount) onlyOwner canMint returns (bool) {
    totalSupply = totalSupply.add(_amount);
    balances[_to] = balances[_to].add(_amount);
    Mint(_to, _amount);
    return true;
  }

  /**
   * @dev Function to stop minting new tokens.
   * @return True if the operation was successful.
   */
  function finishMinting() onlyOwner returns (bool) {
    mintingFinished = true;
    MintFinished();
    return true;
  }
}

pragma solidity ^0.4.11;

import './StandardToken.sol';
import '../ownership/Ownable.sol';

/**
 * @title Mintable token
 * @dev Simple ERC20 Token example, with mintable token creation
 * @dev Issue: * https://github.com/OpenZeppelin/zeppelin-solidity/issues/120
 * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
 */

contract MintableToken is StandardToken, Ownable {
  event Mint(address indexed to, uint value);
  event MintFinished();

  bool public mintingFinished = false;
  uint public totalSupply = 0;

  modifier canMint() {
    if(mintingFinished) throw;
    _;
  }

  /**
   * @dev Function to mint tokens
   * @param _to The address that will recieve the minted tokens.
   * @param _amount The amount of tokens to mint.
   * @return A boolean that indicates if the operation was successful.
   */
  function mint(address _to, uint _amount) onlyOwner canMint returns (bool) {
    totalSupply = totalSupply.add(_amount);
    balances[_to] = balances[_to].add(_amount);
    Mint(_to, _amount);
    return true;
  }

  /**
   * @dev Function to stop minting new tokens.
   * @return True if the operation was successful.
   */
  function finishMinting() onlyOwner returns (bool) {
    mintingFinished = true;
    MintFinished();
    return true;
  }
}


Improve accuracy and performance

Improve accuracy and performance

If base <= ~20, then the upper bound of ln(base) is 3.
So the case of returning 3 can be extended from base <= 8 to base <= ~20.
This improves:
- The accuracy for 16 <= base <= ~20, which in the old version returned 4 instead of 3.
- The performance for 9 <= base <= ~20, which in the old version were calculated via floorLog2.

pragma solidity ^0.4.11;
import './SafeMath.sol';
import './interfaces/IBancorFormula.sol';

/*
    Open issues:
    - The formula is not yet super accurate, especially for very small/very high ratios
    - Improve dynamic precision support
*/

contract BancorFormula is IBancorFormula, SafeMath {

    uint256 constant MAX_FIXED_EXP_32 = 0x386bfdba29;
    string public version = '0.2';

    function BancorFormula() {
    }

    /**
        @dev given a token supply, reserve, CRR and a deposit amount (in the reserve token), calculates the return for a given change (in the main token)

        Formula:
        Return = _supply * ((1 + _depositAmount / _reserveBalance) ^ (_reserveRatio / 100) - 1)

        @param _supply             token total supply
        @param _reserveBalance     total reserve
        @param _reserveRatio       constant reserve ratio, 1-100
        @param _depositAmount      deposit amount, in reserve token

        @return purchase return amount
    */
    function calculatePurchaseReturn(uint256 _supply, uint256 _reserveBalance, uint16 _reserveRatio, uint256 _depositAmount) public constant returns (uint256) {
        // validate input
        require(_supply != 0 && _reserveBalance != 0 && _reserveRatio > 0 && _reserveRatio <= 100);

        // special case for 0 deposit amount
        if (_depositAmount == 0)
            return 0;

        uint256 baseN = safeAdd(_depositAmount, _reserveBalance);
        uint256 temp;

        // special case if the CRR = 100
        if (_reserveRatio == 100) {
            temp = safeMul(_supply, baseN) / _reserveBalance;
            return safeSub(temp, _supply);
        }

        uint8 precision = getBestPrecision(baseN, _reserveBalance, _reserveRatio, 100);
        uint256 resN = power(baseN, _reserveBalance, _reserveRatio, 100, precision);

        temp = safeMul(_supply, resN) >> precision;

        return safeSub(temp, _supply);
     }

    /**
        @dev given a token supply, reserve, CRR and a sell amount (in the main token), calculates the return for a given change (in the reserve token)

        Formula:
        Return = _reserveBalance * (1 - (1 - _sellAmount / _supply) ^ (1 / (_reserveRatio / 100)))

        @param _supply             token total supply
        @param _reserveBalance     total reserve
        @param _reserveRatio       constant reserve ratio, 1-100
        @param _sellAmount         sell amount, in the token itself

        @return sale return amount
    */
    function calculateSaleReturn(uint256 _supply, uint256 _reserveBalance, uint16 _reserveRatio, uint256 _sellAmount) public constant returns (uint256) {
        // validate input
        require(_supply != 0 && _reserveBalance != 0 && _reserveRatio > 0 && _reserveRatio <= 100 && _sellAmount <= _supply);

        // special case for 0 sell amount
        if (_sellAmount == 0)
            return 0;

        uint256 baseD = safeSub(_supply, _sellAmount);
        uint256 temp1;
        uint256 temp2;

        // special case if the CRR = 100
        if (_reserveRatio == 100) {
            temp1 = safeMul(_reserveBalance, _supply);
            temp2 = safeMul(_reserveBalance, baseD);
            return safeSub(temp1, temp2) / _supply;
        }

        // special case for selling the entire supply
        if (_sellAmount == _supply)
            return _reserveBalance;

        uint8 precision = getBestPrecision(_supply, baseD, 100, _reserveRatio);
        uint256 resN = power(_supply, baseD, 100, _reserveRatio, precision);

        temp1 = safeMul(_reserveBalance, resN);
        temp2 = safeMul(_reserveBalance, uint256(1) << precision);

        return safeSub(temp1, temp2) / resN;
    }

    /**
        @dev Calculate (_baseN / _baseD) ^ (_expN / _expD)
        Returns result upshifted by precision

        This method is overflow-safe
    */
    function power(uint256 _baseN, uint256 _baseD, uint32 _expN, uint32 _expD, uint8 _precision) constant returns (uint256 resN) {
        uint256 logbase = ln(_baseN, _baseD, _precision);
        // Not using safeDiv here, since safeDiv protects against
        // precision loss. It's unavoidable, however
        // Both `ln` and `fixedExp` are overflow-safe.
        resN = fixedExp(safeMul(logbase, _expN) / _expD, _precision);
        return resN;
    }

    /**
        input range:
            - numerator: [1, uint256_max >> precision]
            - denominator: [1, uint256_max >> precision]
        output range:
            [0, 0x9b43d4f8d6]

        This method asserts outside of bounds

    */
    function ln(uint256 _numerator, uint256 _denominator, uint8 _precision) public constant returns (uint256) {
        // denominator > numerator: less than one yields negative values. Unsupported
        assert(_denominator <= _numerator);

        // log(1) is the lowest we can go
        assert(_denominator != 0 && _numerator != 0);

        // Upper bits are scaled off by precision
        uint256 MAX_VAL = uint256(1) << (256 - _precision);
        assert(_numerator < MAX_VAL);
        assert(_denominator < MAX_VAL);

        return fixedLoge( (_numerator << _precision) / _denominator, _precision);
    }

    /**
        input range:
            [0x100000000,uint256_max]
        output range:
            [0, 0x9b43d4f8d6]

        This method asserts outside of bounds

    */
    function fixedLoge(uint256 _x, uint8 _precision) constant returns (uint256 logE) {
        /*
        Since `fixedLog2_min` output range is max `0xdfffffffff`
        (40 bits, or 5 bytes), we can use a very large approximation
        for `ln(2)`. This one is used since it's the max accuracy
        of Python `ln(2)`

        0xb17217f7d1cf78 = ln(2) * (1 << 56)

        */
        //Cannot represent negative numbers (below 1)
        assert(_x >= uint256(1) << _precision);

        uint256 log2 = fixedLog2(_x, _precision);
        logE = (log2 * 0xb17217f7d1cf78) >> 56;
    }

    /**
        Returns log2(x >> 32) << 32 [1]
        So x is assumed to be already upshifted 32 bits, and
        the result is also upshifted 32 bits.

        [1] The function returns a number which is lower than the
        actual value

        input-range :
            [0x100000000,uint256_max]
        output-range:
            [0,0xdfffffffff]

        This method asserts outside of bounds

    */
    function fixedLog2(uint256 _x, uint8 _precision) constant returns (uint256) {
        uint256 FIXED_ONE = uint256(1) << _precision;
        uint256 FIXED_TWO = uint256(2) << _precision;

        // Numbers below 1 are negative.
        assert( _x >= FIXED_ONE);

        uint256 hi = 0;
        while (_x >= FIXED_TWO) {
            _x >>= 1;
            hi += FIXED_ONE;
        }

        for (uint8 i = 0; i < _precision; ++i) {
            _x = (_x * _x) / FIXED_ONE;
            if (_x >= FIXED_TWO) {
                _x >>= 1;
                hi += uint256(1) << (_precision - 1 - i);
            }
        }

        return hi;
    }

    /**
        fixedExp is a 'protected' version of `fixedExpUnsafe`, which
        asserts instead of overflows
    */
    function fixedExp(uint256 _x, uint8 _precision) constant returns (uint256) {
        assert(_x <= MAX_FIXED_EXP_32);
        return fixedExpUnsafe(_x, _precision);
    }

    /**
        fixedExp
        Calculates e^x according to maclauren summation:

        e^x = 1+x+x^2/2!...+x^n/n!

        and returns e^(x>>32) << 32, that is, upshifted for accuracy

        Input range:
            - Function ok at    <= 242329958953
            - Function fails at >= 242329958954

        This method is is visible for testcases, but not meant for direct use.

        The values in this method been generated via the following python snippet:

        def calculateFactorials():
            """Method to print out the factorials for fixedExp"""

            ni = []
            ni.append( 295232799039604140847618609643520000000) # 34!
            ITERATIONS = 34
            for n in range( 1,  ITERATIONS,1 ) :
                ni.append(math.floor(ni[n - 1] / n))
            print( "\n        ".join(["xi = (xi * _x) >> _precision;\n        res += xi * %s;" % hex(int(x)) for x in ni]))

    */
    function fixedExpUnsafe(uint256 _x, uint8 _precision) constant returns (uint256) {
        uint256 xi = _x;
        uint256 res = uint256(0xde1bc4d19efcac82445da75b00000000) << _precision;

        res += xi * 0xde1bc4d19efcac82445da75b00000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x6f0de268cf7e5641222ed3ad80000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x2504a0cd9a7f7215b60f9be480000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x9412833669fdc856d83e6f920000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x1d9d4d714865f4de2b3fafea0000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x4ef8ce836bba8cfb1dff2a70000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xb481d807d1aa66d04490610000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x16903b00fa354cda08920c2000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x281cdaac677b334ab9e732000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x402e2aad725eb8778fd85000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x5d5a6c9f31fe2396a2af000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x7c7890d442a82f73839400000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x9931ed54034526b58e400000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xaf147cf24ce150cf7e00000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xbac08546b867cdaa200000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xbac08546b867cdaa20000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xafc441338061b2820000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x9c3cabbc0056d790000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x839168328705c30000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x694120286c049c000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x50319e98b3d2c000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x3a52a1e36b82000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x289286e0fce000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x1b0c59eb53400;
        xi = (xi * _x) >> _precision;
        res += xi * 0x114f95b55400;
        xi = (xi * _x) >> _precision;
        res += xi * 0xaa7210d200;
        xi = (xi * _x) >> _precision;
        res += xi * 0x650139600;
        xi = (xi * _x) >> _precision;
        res += xi * 0x39b78e80;
        xi = (xi * _x) >> _precision;
        res += xi * 0x1fd8080;
        xi = (xi * _x) >> _precision;
        res += xi * 0x10fbc0;
        xi = (xi * _x) >> _precision;
        res += xi * 0x8c40;
        xi = (xi * _x) >> _precision;
        res += xi * 0x462;
        xi = (xi * _x) >> _precision;
        res += xi * 0x22;

        return res / 0xde1bc4d19efcac82445da75b00000000;
    }

    function getBestPrecision(uint256 _baseN, uint256 _baseD, uint256 _expN, uint256 _expD) constant returns (uint8) {
        uint8 precision = floorLog2(MAX_FIXED_EXP_32*_expD/(lnUpperBound(_baseN,_baseD)*_expN));
        return precision >= 32 ? precision : 32;
    }

    function lnUpperBound(uint256 baseN, uint256 baseD) constant returns (uint8) {
        assert(baseN > baseD);

        scaled_baseN = baseN * 100000;
        if (scaled_baseN <= baseD *  271828) // baseN / baseD < e^1
            return 1;
        if (scaled_baseN <= baseD *  738905) // baseN / baseD < e^2
            return 2;
        if (scaled_baseN <= baseD * 2008553) // baseN / baseD < e^3
            return 3;

        return floorLog2(baseN/baseD);
    }

    function floorLog2(uint256 n) constant returns (uint8) {
        uint256 t = 0;
        for (int k = 7; k >= 0; k--) {
            if (n > (uint256(1)<<(1<<k))-1) {
                uint256 s = uint256(1) << k;
                n >>= s;
                t |= s;
            }
        }
        return uint8(t | (n >> 1));
    }
}

pragma solidity ^0.4.11;
import './SafeMath.sol';
import './interfaces/IBancorFormula.sol';

/*
    Open issues:
    - The formula is not yet super accurate, especially for very small/very high ratios
    - Improve dynamic precision support
*/

contract BancorFormula is IBancorFormula, SafeMath {

    uint256 constant MAX_FIXED_EXP_32 = 0x386bfdba29;
    string public version = '0.2';

    function BancorFormula() {
    }

    /**
        @dev given a token supply, reserve, CRR and a deposit amount (in the reserve token), calculates the return for a given change (in the main token)

        Formula:
        Return = _supply * ((1 + _depositAmount / _reserveBalance) ^ (_reserveRatio / 100) - 1)

        @param _supply             token total supply
        @param _reserveBalance     total reserve
        @param _reserveRatio       constant reserve ratio, 1-100
        @param _depositAmount      deposit amount, in reserve token

        @return purchase return amount
    */
    function calculatePurchaseReturn(uint256 _supply, uint256 _reserveBalance, uint16 _reserveRatio, uint256 _depositAmount) public constant returns (uint256) {
        // validate input
        require(_supply != 0 && _reserveBalance != 0 && _reserveRatio > 0 && _reserveRatio <= 100);

        // special case for 0 deposit amount
        if (_depositAmount == 0)
            return 0;

        uint256 baseN = safeAdd(_depositAmount, _reserveBalance);
        uint256 temp;

        // special case if the CRR = 100
        if (_reserveRatio == 100) {
            temp = safeMul(_supply, baseN) / _reserveBalance;
            return safeSub(temp, _supply);
        }

        uint8 precision = getBestPrecision(baseN, _reserveBalance, _reserveRatio, 100);
        uint256 resN = power(baseN, _reserveBalance, _reserveRatio, 100, precision);

        temp = safeMul(_supply, resN) >> precision;

        return safeSub(temp, _supply);
     }

    /**
        @dev given a token supply, reserve, CRR and a sell amount (in the main token), calculates the return for a given change (in the reserve token)

        Formula:
        Return = _reserveBalance * (1 - (1 - _sellAmount / _supply) ^ (1 / (_reserveRatio / 100)))

        @param _supply             token total supply
        @param _reserveBalance     total reserve
        @param _reserveRatio       constant reserve ratio, 1-100
        @param _sellAmount         sell amount, in the token itself

        @return sale return amount
    */
    function calculateSaleReturn(uint256 _supply, uint256 _reserveBalance, uint16 _reserveRatio, uint256 _sellAmount) public constant returns (uint256) {
        // validate input
        require(_supply != 0 && _reserveBalance != 0 && _reserveRatio > 0 && _reserveRatio <= 100 && _sellAmount <= _supply);

        // special case for 0 sell amount
        if (_sellAmount == 0)
            return 0;

        uint256 baseD = safeSub(_supply, _sellAmount);
        uint256 temp1;
        uint256 temp2;

        // special case if the CRR = 100
        if (_reserveRatio == 100) {
            temp1 = safeMul(_reserveBalance, _supply);
            temp2 = safeMul(_reserveBalance, baseD);
            return safeSub(temp1, temp2) / _supply;
        }

        // special case for selling the entire supply
        if (_sellAmount == _supply)
            return _reserveBalance;

        uint8 precision = getBestPrecision(_supply, baseD, 100, _reserveRatio);
        uint256 resN = power(_supply, baseD, 100, _reserveRatio, precision);

        temp1 = safeMul(_reserveBalance, resN);
        temp2 = safeMul(_reserveBalance, uint256(1) << precision);

        return safeSub(temp1, temp2) / resN;
    }

    /**
        @dev Calculate (_baseN / _baseD) ^ (_expN / _expD)
        Returns result upshifted by precision

        This method is overflow-safe
    */
    function power(uint256 _baseN, uint256 _baseD, uint32 _expN, uint32 _expD, uint8 _precision) constant returns (uint256 resN) {
        uint256 logbase = ln(_baseN, _baseD, _precision);
        // Not using safeDiv here, since safeDiv protects against
        // precision loss. It's unavoidable, however
        // Both `ln` and `fixedExp` are overflow-safe.
        resN = fixedExp(safeMul(logbase, _expN) / _expD, _precision);
        return resN;
    }

    /**
        input range:
            - numerator: [1, uint256_max >> precision]
            - denominator: [1, uint256_max >> precision]
        output range:
            [0, 0x9b43d4f8d6]

        This method asserts outside of bounds

    */
    function ln(uint256 _numerator, uint256 _denominator, uint8 _precision) public constant returns (uint256) {
        // denominator > numerator: less than one yields negative values. Unsupported
        assert(_denominator <= _numerator);

        // log(1) is the lowest we can go
        assert(_denominator != 0 && _numerator != 0);

        // Upper bits are scaled off by precision
        uint256 MAX_VAL = uint256(1) << (256 - _precision);
        assert(_numerator < MAX_VAL);
        assert(_denominator < MAX_VAL);

        return fixedLoge( (_numerator << _precision) / _denominator, _precision);
    }

    /**
        input range:
            [0x100000000,uint256_max]
        output range:
            [0, 0x9b43d4f8d6]

        This method asserts outside of bounds

    */
    function fixedLoge(uint256 _x, uint8 _precision) constant returns (uint256 logE) {
        /*
        Since `fixedLog2_min` output range is max `0xdfffffffff`
        (40 bits, or 5 bytes), we can use a very large approximation
        for `ln(2)`. This one is used since it's the max accuracy
        of Python `ln(2)`

        0xb17217f7d1cf78 = ln(2) * (1 << 56)

        */
        //Cannot represent negative numbers (below 1)
        assert(_x >= uint256(1) << _precision);

        uint256 log2 = fixedLog2(_x, _precision);
        logE = (log2 * 0xb17217f7d1cf78) >> 56;
    }

    /**
        Returns log2(x >> 32) << 32 [1]
        So x is assumed to be already upshifted 32 bits, and
        the result is also upshifted 32 bits.

        [1] The function returns a number which is lower than the
        actual value

        input-range :
            [0x100000000,uint256_max]
        output-range:
            [0,0xdfffffffff]

        This method asserts outside of bounds

    */
    function fixedLog2(uint256 _x, uint8 _precision) constant returns (uint256) {
        uint256 FIXED_ONE = uint256(1) << _precision;
        uint256 FIXED_TWO = uint256(2) << _precision;

        // Numbers below 1 are negative.
        assert( _x >= FIXED_ONE);

        uint256 hi = 0;
        while (_x >= FIXED_TWO) {
            _x >>= 1;
            hi += FIXED_ONE;
        }

        for (uint8 i = 0; i < _precision; ++i) {
            _x = (_x * _x) / FIXED_ONE;
            if (_x >= FIXED_TWO) {
                _x >>= 1;
                hi += uint256(1) << (_precision - 1 - i);
            }
        }

        return hi;
    }

    /**
        fixedExp is a 'protected' version of `fixedExpUnsafe`, which
        asserts instead of overflows
    */
    function fixedExp(uint256 _x, uint8 _precision) constant returns (uint256) {
        assert(_x <= MAX_FIXED_EXP_32);
        return fixedExpUnsafe(_x, _precision);
    }

    /**
        fixedExp
        Calculates e^x according to maclauren summation:

        e^x = 1+x+x^2/2!...+x^n/n!

        and returns e^(x>>32) << 32, that is, upshifted for accuracy

        Input range:
            - Function ok at    <= 242329958953
            - Function fails at >= 242329958954

        This method is is visible for testcases, but not meant for direct use.

        The values in this method been generated via the following python snippet:

        def calculateFactorials():
            """Method to print out the factorials for fixedExp"""

            ni = []
            ni.append( 295232799039604140847618609643520000000) # 34!
            ITERATIONS = 34
            for n in range( 1,  ITERATIONS,1 ) :
                ni.append(math.floor(ni[n - 1] / n))
            print( "\n        ".join(["xi = (xi * _x) >> _precision;\n        res += xi * %s;" % hex(int(x)) for x in ni]))

    */
    function fixedExpUnsafe(uint256 _x, uint8 _precision) constant returns (uint256) {
        uint256 xi = _x;
        uint256 res = uint256(0xde1bc4d19efcac82445da75b00000000) << _precision;

        res += xi * 0xde1bc4d19efcac82445da75b00000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x6f0de268cf7e5641222ed3ad80000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x2504a0cd9a7f7215b60f9be480000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x9412833669fdc856d83e6f920000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x1d9d4d714865f4de2b3fafea0000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x4ef8ce836bba8cfb1dff2a70000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xb481d807d1aa66d04490610000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x16903b00fa354cda08920c2000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x281cdaac677b334ab9e732000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x402e2aad725eb8778fd85000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x5d5a6c9f31fe2396a2af000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x7c7890d442a82f73839400000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x9931ed54034526b58e400000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xaf147cf24ce150cf7e00000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xbac08546b867cdaa200000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xbac08546b867cdaa20000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xafc441338061b2820000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x9c3cabbc0056d790000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x839168328705c30000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x694120286c049c000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x50319e98b3d2c000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x3a52a1e36b82000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x289286e0fce000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x1b0c59eb53400;
        xi = (xi * _x) >> _precision;
        res += xi * 0x114f95b55400;
        xi = (xi * _x) >> _precision;
        res += xi * 0xaa7210d200;
        xi = (xi * _x) >> _precision;
        res += xi * 0x650139600;
        xi = (xi * _x) >> _precision;
        res += xi * 0x39b78e80;
        xi = (xi * _x) >> _precision;
        res += xi * 0x1fd8080;
        xi = (xi * _x) >> _precision;
        res += xi * 0x10fbc0;
        xi = (xi * _x) >> _precision;
        res += xi * 0x8c40;
        xi = (xi * _x) >> _precision;
        res += xi * 0x462;
        xi = (xi * _x) >> _precision;
        res += xi * 0x22;

        return res / 0xde1bc4d19efcac82445da75b00000000;
    }

    function getBestPrecision(uint256 _baseN, uint256 _baseD, uint256 _expN, uint256 _expD) constant returns (uint8) {
        uint8 precision = floorLog2(MAX_FIXED_EXP_32*_expD/(lnUpperBound(_baseN,_baseD)*_expN));
        return precision >= 32 ? precision : 32;
    }

    function lnUpperBound(uint256 baseN, uint256 baseD) constant returns (uint8) {
        assert(baseN > baseD);

        if (100000 * baseN <= 271828 * baseD) // baseN / baseD < e^1
            return 1;
        if (100000 * baseN <= 738905 * baseD) // baseN / baseD < e^2
            return 2;
        if (baseN <= 8 * baseD)               // baseN / baseD <= 2^3 < e^3
            return 3;

        return floorLog2(baseN/baseD);
    }

    function floorLog2(uint256 n) constant returns (uint8) {
        uint256 t = 0;
        for (int k = 7; k >= 0; k--) {
            if (n > (uint256(1)<<(1<<k))-1) {
                uint256 s = uint256(1) << k;
                n >>= s;
                t |= s;
            }
        }
        return uint8(t | (n >> 1));
    }
}


remove maxWeight

remove maxWeight

pragma solidity ^0.4.11;

import "./UserRegistry.sol";
import "./ConceptRegistry.sol";
import "./Assessment.sol";
import "./Math.sol";

//@purpose: To store concept data and create and manage assessments and members
contract Concept {
    address[] public parents; //The concepts that this concept is child to (ie: Calculus is child to Math)
    bytes data;
    address public userRegistry;
    address conceptRegistry;
    uint public lifetime;
    mapping (address => bool) public assessmentExists;

    uint[] propagationRates;

    address[] public members;
    mapping (address => MemberData) memberData;

    struct MemberData {
        address recentAssessment;
        uint index;
        mapping(address => uint) approval;
        ComponentWeight[] weights;
        mapping(address => uint) componentWeightIndex;
    }

    struct ComponentWeight {
        uint weight;
        uint date;
    }

    modifier onlyConcept() {
        require(ConceptRegistry(conceptRegistry).conceptExists(msg.sender));
        _;
    }

    event setAssessorIndex (address member, uint index);

    function Concept(address[] _parents, uint[] _propagationRates, uint _lifetime, bytes _data) {
        propagationRates = _propagationRates;
        parents = _parents;
        data = _data;
        conceptRegistry = msg.sender;
        lifetime = _lifetime;
        userRegistry = ConceptRegistry(conceptRegistry).userRegistry();
    }

    function getMemberLength() constant returns(uint) {
        return members.length;
    }

    function getParentsLength() constant returns(uint) {
        return parents.length;
    }

    /*
      @purpose: To add the firstUser to Mew
    */
    function addInitialMember(address _user, uint _weight) {
        if (ConceptRegistry(conceptRegistry).distributorAddress() == msg.sender)
            {
                this.addWeight(_user, _weight);
            }
    }

    /*
      @purpose: add the caller of this function to the arrays of potential assessors
      if they still have a weight in the concept
      @returns true if they are available as assessor
    */
    function setAvailability() returns(bool success){
        if (getWeight(msg.sender) > 0) {
            if (memberData[msg.sender].index == 0) {
                members.push(msg.sender);
                memberData[msg.sender].index = members.length;
                success = true;
            }
            else {
                removeMember(msg.sender);
            }
        }
   }

    /*
      //@purpose: returns a random member of the Concept or the zero address (both with approx. 50%)
      //Users with high weights are more likely to be called
      //@returns the address of the member (0x0 if there is no member)
    */
    function getWeightedRandomMember(uint seed) returns(address){
        uint weight1;
        uint weight2;
        address randomMember1;
        while (members.length > 1 && weight1 == 0) {
            uint index1 = Math.getRandom(seed, members.length - 1);
            randomMember1 = members[index1];
            weight1 = getWeight(randomMember1);
        }
        while (members.length > 1 && weight2 == 0) {
                uint index2 = Math.getRandom(seed * 2, members.length - 1);
                address randomMember2 = members[index2];
                weight2 = getWeight(randomMember2);
        }
        if (weight1 > weight2) {
            return randomMember1;
        }
    }

    /*
      @purpose: get the weight of a given member, also removes that member from the array
      if there legitimating assessment is expired
    */
    function getWeight(address _member) returns(uint weight){
        for (uint i=0; i < memberData[_member].weights.length; i++) {
            if (memberData[_member].weights[i].date > now){
                weight += memberData[_member].weights[i].weight;
            }
        }
        if (weight == 0) {
            removeMember(_member);
        }
    }
    /*
      @purpose: removes member at a given index from the members array by substituting they with
      the last member and then decreasing the size of the members array
      @returns the updated number of members in the concept
    */
    function removeMember(address _member) internal returns(uint){
        uint index = memberData[_member].index;
        if (index > 0){
            members[index] = members[members.length - 1]; //THIS NEEDS TO BE TESTED!
            memberData[_member].index = 0;
            members.length--;
        }
        return members.length;
    }

    /*
      @purpose: To make a new assessment
      @param: uint cost = the cost per assessor
      @param: uint size = the number of assessors
    */
    function makeAssessment(uint cost, uint size, uint _waitTime, uint _timeLimit) returns(bool) {
        if (size >= 5 && this.subtractBalance(msg.sender, cost*size)) {
            Assessment newAssessment = new Assessment(msg.sender, size, cost, _waitTime, _timeLimit);
            assessmentExists[address(newAssessment)] = true;
            newAssessment.setAssessorPool(block.number, address(this), size*5); //assemble the assessorPool by relevance
            return true;
        }
        else {
            return false;
        }
    }

    /*
      @purpose: To approve addresses to create assessments for users on this concept
      @param: _from = the address approved to create assessments
      @param: _amount = the maximum value of Tokens they are allowed to spend
    */
    function approve(address _from, uint _amount) returns(bool) {
        memberData[msg.sender].approval[_from] = _amount;
        return true;
    }

    //@purpose: allow approved address to create assessments for users on this concept
    function makeAssessmentFrom(address _assessee, uint _cost, uint _size, uint _waitTime, uint _timeLimit) returns(bool) {
        if (memberData[_assessee].approval[msg.sender] >= _cost * _size &&
           _size >= 5 &&
           this.subtractBalance(_assessee, _cost*_size)) {
            Assessment newAssessment = new Assessment(_assessee, _size, _cost, _waitTime, _timeLimit);
            assessmentExists[address(newAssessment)] = true;
            newAssessment.setAssessorPool(block.number, address(this), _size*20); //assemble the assessorPool by relevance
            memberData[_assessee].approval[msg.sender] -= _cost*_size;
            return true;
        }
        else {
            return false;
        }
    }

    /*
      @purpose: To add a member to a concept and to recursively add  a member to parent concept
      @param: address assessee = the address of the assessee
      @param: uint weight = the weight for the member
      @returns: nothing
    */
    function addMember(address _assessee, uint _weight) {
        if (assessmentExists[msg.sender]) {
            memberData[_assessee].recentAssessment = msg.sender;
            memberData[_assessee].index = 0;
            this.addWeight(_assessee, _weight);
        }
    }
    function addWeight(address _assessee, uint _weight) onlyConcept() {
        if (memberData[_assessee].index == 0) {
            members.push(_assessee);
            memberData[_assessee].index = members.length;
        }

        uint idx = memberData[_assessee].componentWeightIndex[msg.sender];
        if (idx > 0) {
            memberData[_assessee].weights[idx-1] = ComponentWeight(_weight, now + lifetime);
        } else {
            memberData[_assessee].weights.push(ComponentWeight(_weight, now + lifetime));
            memberData[_assessee].componentWeightIndex[msg.sender] = memberData[_assessee].weights.length;
        }

        for(uint i = 0; i < parents.length; i++) {
            if((_weight*propagationRates[i])/1000 > 0) {
                Concept(parents[i]).addWeight(_assessee, (_weight*propagationRates[i])/1000);
            }
        }
    }

    function subtractBalance(address _from, uint _amount) returns(bool) {
        if (assessmentExists[msg.sender] || msg.sender == address(this)) {
            return UserRegistry(userRegistry).subtractBalance(_from, _amount);
        }
        return false;
    }
}

pragma solidity ^0.4.11;

import "./UserRegistry.sol";
import "./ConceptRegistry.sol";
import "./Assessment.sol";
import "./Math.sol";

//@purpose: To store concept data and create and manage assessments and members
contract Concept {
    address[] public parents; //The concepts that this concept is child to (ie: Calculus is child to Math)
    bytes data;
    address public userRegistry;
    address conceptRegistry;
    uint public maxWeight;
    uint public lifetime;
    mapping (address => bool) public assessmentExists;

    uint[] propagationRates;

    address[] public members;
    mapping (address => MemberData) memberData;

    struct MemberData {
        address recentAssessment;
        uint index;
        mapping(address => uint) approval;
        ComponentWeight[] weights;
        mapping(address => uint) componentWeightIndex;
    }

    struct ComponentWeight {
        uint weight;
        uint date;
    }

    modifier onlyConcept() {
        require(ConceptRegistry(conceptRegistry).conceptExists(msg.sender));
        _;
    }

    event setAssessorIndex (address member, uint index);

    function Concept(address[] _parents, uint[] _propagationRates, uint _lifetime, bytes _data) {
        propagationRates = _propagationRates;
        parents = _parents;
        data = _data;
        conceptRegistry = msg.sender;
        lifetime = _lifetime;
        userRegistry = ConceptRegistry(conceptRegistry).userRegistry();
    }

    function getMemberLength() constant returns(uint) {
        return members.length;
    }

    function getParentsLength() constant returns(uint) {
        return parents.length;
    }

    /*
      @purpose: To add the firstUser to Mew
    */
    function addInitialMember(address _user, uint _weight) {
        if (ConceptRegistry(conceptRegistry).distributorAddress() == msg.sender)
            {
                this.addWeight(_user, _weight);
            }
    }

    /*
      @purpose: add the caller of this function to the arrays of potential assessors
      if they still have a weight in the concept
      @returns true if they are available as assessor
    */
    function setAvailability() returns(bool success){
        if (getWeight(msg.sender) > 0) {
            if (memberData[msg.sender].index == 0) {
                members.push(msg.sender);
                memberData[msg.sender].index = members.length;
                success = true;
            }
            else {
                removeMember(msg.sender);
            }
        }
   }

    /*
      //@purpose: returns a random member of the Concept or the zero address (both with approx. 50%)
      //Users with high weights are more likely to be called
      //@returns the address of the member (0x0 if there is no member)
    */
    function getWeightedRandomMember(uint seed) returns(address){
        uint weight1;
        uint weight2;
        address randomMember1;
        while (members.length > 1 && weight1 == 0) {
            uint index1 = Math.getRandom(seed, members.length - 1);
            randomMember1 = members[index1];
            weight1 = getWeight(randomMember1);
        }
        while (members.length > 1 && weight2 == 0) {
                uint index2 = Math.getRandom(seed * 2, members.length - 1);
                address randomMember2 = members[index2];
                weight2 = getWeight(randomMember2);
        }
        if (weight1 > weight2) {
            return randomMember1;
        }
    }

    /*
      @purpose: get the weight of a given member, also removes that member from the array
      if there legitimating assessment is expired
    */
    function getWeight(address _member) returns(uint weight){
        for (uint i=0; i < memberData[_member].weights.length; i++) {
            if (memberData[_member].weights[i].date > now){
                weight += memberData[_member].weights[i].weight;
            }
        }
        if (weight == 0) {
            removeMember(_member);
        }
    }
    /*
      @purpose: removes member at a given index from the members array by substituting they with
      the last member and then decreasing the size of the members array
      @returns the updated number of members in the concept
    */
    function removeMember(address _member) internal returns(uint){
        uint index = memberData[_member].index;
        if (index > 0){
            members[index] = members[members.length - 1]; //THIS NEEDS TO BE TESTED!
            memberData[_member].index = 0;
            members.length--;
        }
        return members.length;
    }

    /*
      @purpose: To make a new assessment
      @param: uint cost = the cost per assessor
      @param: uint size = the number of assessors
    */
    function makeAssessment(uint cost, uint size, uint _waitTime, uint _timeLimit) returns(bool) {
        if (size >= 5 && this.subtractBalance(msg.sender, cost*size)) {
            Assessment newAssessment = new Assessment(msg.sender, size, cost, _waitTime, _timeLimit);
            assessmentExists[address(newAssessment)] = true;
            newAssessment.setAssessorPool(block.number, address(this), size*5); //assemble the assessorPool by relevance
            return true;
        }
        else {
            return false;
        }
    }

    /*
      @purpose: To approve addresses to create assessments for users on this concept
      @param: _from = the address approved to create assessments
      @param: _amount = the maximum value of Tokens they are allowed to spend
    */
    function approve(address _from, uint _amount) returns(bool) {
        memberData[msg.sender].approval[_from] = _amount;
        return true;
    }

    //@purpose: allow approved address to create assessments for users on this concept
    function makeAssessmentFrom(address _assessee, uint _cost, uint _size, uint _waitTime, uint _timeLimit) returns(bool) {
        if (memberData[_assessee].approval[msg.sender] >= _cost * _size &&
           _size >= 5 &&
           this.subtractBalance(_assessee, _cost*_size)) {
            Assessment newAssessment = new Assessment(_assessee, _size, _cost, _waitTime, _timeLimit);
            assessmentExists[address(newAssessment)] = true;
            newAssessment.setAssessorPool(block.number, address(this), _size*20); //assemble the assessorPool by relevance
            memberData[_assessee].approval[msg.sender] -= _cost*_size;
            return true;
        }
        else {
            return false;
        }
    }

    /*
      @purpose: To add a member to a concept and to recursively add  a member to parent concept, thereby halving the added weight with each generation and changing the maxWeight of each concept if necessary
      @param: address assessee = the address of the assessee
      @param: uint weight = the weight for the member
      @returns: nothing
    */
    function addMember(address _assessee, uint _weight) {
        if (assessmentExists[msg.sender]) {
            memberData[_assessee].recentAssessment = msg.sender;
            memberData[_assessee].index = 0;
            this.addWeight(_assessee, _weight);
        }
    }
    function addWeight(address _assessee, uint _weight) onlyConcept() {
        if (memberData[_assessee].index == 0) {
            members.push(_assessee);
            memberData[_assessee].index = members.length;
        }

        uint idx = memberData[_assessee].componentWeightIndex[msg.sender];
        if (idx > 0) {
            memberData[_assessee].weights[idx-1] = ComponentWeight(_weight, now + lifetime);
        } else {
            memberData[_assessee].weights.push(ComponentWeight(_weight, now + lifetime));
            memberData[_assessee].componentWeightIndex[msg.sender] = memberData[_assessee].weights.length;
        }

        if (_weight > maxWeight) {
            maxWeight = _weight;
        }

        for(uint i = 0; i < parents.length; i++) {
            if((_weight*propagationRates[i])/1000 > 0) {
                Concept(parents[i]).addWeight(_assessee, (_weight*propagationRates[i])/1000);
            }
        }
    }

    function subtractBalance(address _from, uint _amount) returns(bool) {
        if (assessmentExists[msg.sender] || msg.sender == address(this)) {
            return UserRegistry(userRegistry).subtractBalance(_from, _amount);
        }
        return false;
    }
}


fixed constructor issue and don't overwrite values in the mint process (exam questions :)

pragma solidity ^0.4.10;

//the very seventh example
contract Example7 {

    address owner;
    mapping (address => uint) accounts;

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

    function mint(address recipient, uint value) {
        if(msg.sender == owner) {
            accounts[recipient] += value;
        }
    }

    function transfer(address to, uint value) {
        if(accounts[msg.sender] >= value) {
            accounts[msg.sender] -= value;
            accounts[to] += value;
        }
    }

    function balance(address addr) constant returns (uint) {
        return accounts[addr];
    }
}

pragma solidity ^0.4.10;

//the very seventh example
contract Example7 {

    address owner;
    mapping (address => uint) accounts;

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

    function mint(address recipient, uint value) {
        if(msg.sender == owner) {
            accounts[recipient] = value;
        }
    }

    function transfer(address to, uint value) {
        if(accounts[msg.sender] >= value) {
            accounts[msg.sender] -= value;
            accounts[to] += value;
        }
    }

    function balance(address addr) constant returns (uint) {
        return accounts[addr];
    }
}


Create CompareOp

Create CompareOp

contract CompareOp {
	function isSuperior(bytes _old, bytes _new) constant returns (bool);
}

error: pathspec 'contracts/CompareOp.sol' did not match any file(s) known to git


Update EtherFundMeCrowdfunding.sol

Update EtherFundMeCrowdfunding.sol

pragma solidity ^0.4.16;

/// @title etherfund.me basic crowdfunding contract
contract EtherFundMeCrowdfunding {
    ///////////////////////////////////////////////////////////////////////////////
    /// Crowdfunding fields
    ///////////////////////////////////////////////////////////////////////////////
    /// The crowdfunding project name
    string public projectName;

    /// The crowdfunding project description
    string public projectDescription;

    /// The crowdfunding team contact
    string public teamEmail;

    /// The start time of crowdfunding
    uint public startsAt;

    /// The end time of crowdfunding
    uint public endsAt;

    /// Crowdfunding team wallet
    address public teamWallet;

    /// etherfund.me fee wallet
    address public feeReceiverWallet;

    /// etherfund.me deploy agent
    address public deployAgentWallet;

    /// if the funding goal is not reached, investors may withdraw their funds
    uint public fundingGoal;

    ///  How many distinct addresses have invested
    uint public investorCount = 0;

    ///  Has this crowdfunding been finalized
    bool public finalized;

    ///  Has this crowdfunding been paused
    bool public halted;

    ///  How much ETH each address has invested to this crowdfunding
    mapping (address => uint256) public investedAmountOf;

    /// etherfund.me final fee in %
    uint public constant ETHERFUNDME_FEE = 2;

    /// etherfund.me each transaction fee in %
    uint public constant ETHERFUNDME_ONLINE_FEE = 1;

    /// if a project reach 60% of their funding goal it becomes successful
    uint public constant GOAL_REACHED_CRITERION = 60;

    /// State machine
    /// Preparing: All contract initialization calls and variables have not been set yet
    /// Funding: Active crowdsale
    /// Success: Minimum funding goal reached
    /// Failure: Minimum funding goal not reached before ending time
    /// Finalized: The finalized has been called and succesfully executed
    /// Refunding: Refunds are loaded on the contract for reclaim
    enum State { Unknown, Preparing, Funding, Success, Failure, Finalized, Refunding }

    ///////////////////////////////////////////////////////////////////////////////
    /// Crowdfunding events
    ///////////////////////////////////////////////////////////////////////////////
    /// A new investment was made
    event Invested(address investor, uint weiAmount);
    /// Withdraw was processed for a contributor
    event Withdraw(address receiver, uint weiAmount);
    /// Returning funds for a contributor
    event Refund(address receiver, uint weiAmount);

    /// Modified allowing execution only if the crowdfunding is currently running
    modifier inState(State state) {
        require(getState() == state);
        _;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// Crowdfunding modifiers
    ///////////////////////////////////////////////////////////////////////////////
    /// Modified allowing execution only if deploy agent call
    modifier onlyDeployAgent() {
        require(msg.sender == deployAgentWallet);
        _;
    }

    /// Modified allowing execution only if not stopped
    modifier stopInEmergency {
        require(!halted);
        _;
    }

    /// Modified allowing execution only if stopped
    modifier onlyInEmergency {
        require(halted);
        _;
    }

    /// @dev Constructor
    /// @param _projectName crowdfunding project name
    /// @param _projectDescription crowdfunding project short description
    /// @param _teamEmail crowdfunding team contact
    /// @param _startsAt crowdfunding start time
    /// @param _endsAt crowdfunding end time
    /// @param _fundingGoal funding goal in wei
    /// @param _teamWallet  team address
    /// @param _feeReceiverWallet  fee receiver address
    function EtherFundMeCrowdfunding(
      string _projectName,
      string _projectDescription,
      string _teamEmail,
      uint _startsAt,
      uint _endsAt,
      uint _fundingGoal,
      address _teamWallet,
      address _feeReceiverWallet) {
        require(_startsAt != 0);
        require(_endsAt != 0);
        require(_fundingGoal != 0);
        require(_teamWallet != 0);
        require(_feeReceiverWallet != 0);

        deployAgentWallet = msg.sender;
        projectName = _projectName;
        projectDescription = _projectDescription;
        teamEmail = _teamEmail;
        startsAt = _startsAt;
        endsAt = _endsAt;
        fundingGoal = _fundingGoal;
        teamWallet = _teamWallet;
        feeReceiverWallet = _feeReceiverWallet;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// Crowdfunding methods
    ///////////////////////////////////////////////////////////////////////////////
    /// @dev Crowdfund state machine management.
    /// @return State current state
    function getState() public constant returns (State) {
        if (finalized)
            return State.Finalized;
        if (startsAt > now)
            return State.Preparing;
        if (now >= startsAt && now < endsAt)
            return State.Funding;
        if (isGoalReached())
            return State.Success;
        if (!isGoalReached() && this.balance > 0)
            return State.Refunding;
        return State.Failure;
    }

    /// @dev Goal was reached
    /// @return true if the crowdsale has raised enough money to be a succes
    function isGoalReached() public constant returns (bool reached) {
        return this.balance >= (fundingGoal * GOAL_REACHED_CRITERION) / 100;
    }

    /// @dev Fallback method
    function() payable {
        invest();
    }

    /// @dev Allow contributions to this crowdfunding.
    function invest() public payable stopInEmergency  {
        require(getState() == State.Funding);
        require(msg.value > 0);

        uint weiAmount = msg.value;
        address investor = msg.sender;

        if(investedAmountOf[investor] == 0) {
            // A new investor
            investorCount++;
        }

        // calculate online fee
        uint onlineFeeAmount = (weiAmount * ETHERFUNDME_ONLINE_FEE) / 100;
        Withdraw(feeReceiverWallet, onlineFeeAmount);
        // send online fee
        feeReceiverWallet.transfer(onlineFeeAmount);

        uint investedAmount = weiAmount - onlineFeeAmount;
        // Update investor
        investedAmountOf[investor] += investedAmount;
        // Tell us invest was success
        Invested(investor, investedAmount);
    }

    /// @dev Finalize a succcesful crowdfunding. The team can triggre a call the contract that provides post-crowdfunding actions, like releasing the funds.
    function finalize() public inState(State.Success) stopInEmergency  {
        require(msg.sender == deployAgentWallet || msg.sender == teamWallet);
        require(!finalized);

        finalized = true;

        uint feeAmount = (this.balance * ETHERFUNDME_FEE) / 100;
        uint teamAmount = this.balance - feeAmount;

        Withdraw(teamWallet, teamAmount);
        teamWallet.transfer(teamAmount);

        Withdraw(feeReceiverWallet, feeAmount);
        feeReceiverWallet.transfer(feeAmount);
    }

    /// @dev Investors can claim refund.
    function refund() public inState(State.Refunding) {
        uint weiValue = investedAmountOf[msg.sender];
        if (weiValue == 0) revert();
        investedAmountOf[msg.sender] = 0;
        Refund(msg.sender, weiValue);
        msg.sender.transfer(weiValue);
    }

    /// called by the deploy agent on emergency, triggers stopped state
    function halt() public onlyDeployAgent {
        halted = true;
    }

    /// called by the deploy agent on end of emergency, returns to normal state
    function unhalt() public onlyDeployAgent onlyInEmergency {
        halted = false;
    }
}

pragma solidity ^0.4.16;

/// @title etherfund.me  basic crowdfunding contract
contract EtherFundMeCrowdfunding {

	/// The crowdfunding project name
	string public name;

	/// The crowdfunding project description
	string public description;

  	/// The crowdfunding team contact
	string public teamContact;

	/// The start time of crowdfunding
   	uint public startsAt;

	/// The end time of crowdfunding
   	uint public endsAt;

	/// Crowdfunding team wallet
    	address public team;

	/// etherfund.me fee wallet
	address public feeReceiver;

	/// etherfund.me deploy agent
	address public deployAgent;

	/// if the funding goal is not reached, investors may withdraw their funds
	uint public fundingGoal;

	///  How many distinct addresses have invested
	uint public investorCount = 0;

	///  Has this crowdfunding been finalized
	bool public finalized;

	///  Has this crowdfunding been paused
	bool public halted;

	///  How much ETH each address has invested to this crowdfunding
	mapping (address => uint256) public investedAmountOf;

	/// etherfund.me final fee in %
	uint public constant ETHERFUNDME_FEE = 2;

	/// etherfund.me each transaction fee in %
	uint public constant ETHERFUNDME_ONLINE_FEE = 1;

    	/// if a project reach 60% of their funding goal it becomes successful
	uint public constant GOAL_REACHED_CRITERION = 60;

	/// State machine
	/// Preparing: All contract initialization calls and variables have not been set yet
	/// Funding: Active crowdsale
	/// Success: Minimum funding goal reached
	/// Failure: Minimum funding goal not reached before ending time
	/// Finalized: The finalized has been called and succesfully executed
	/// Refunding: Refunds are loaded on the contract for reclaim
	enum State { Unknown, Preparing, Funding, Success, Failure, Finalized, Refunding }

	/// A new investment was made
	event Invested(address investor, uint weiAmount);

	/// Withdraw was processed for a contributor
	event Withdraw(address receiver, uint weiAmount);

	/// Returning funds for a contributor
	event Refund(address receiver, uint weiAmount);

	/// Modified allowing execution only if the crowdfunding is currently running
	 modifier inState(State state) {
		require(getState() == state);
		_;
	 }

	 /// Modified allowing execution only if deploy agent call
	 modifier onlyDeployAgent() {
		require(msg.sender == deployAgent);
		_;
	 }

	 /// Modified allowing execution only if not stopped
	 modifier stopInEmergency {
		require(!halted);
		_;
	 }

	 /// Modified allowing execution only if stopped
	 modifier onlyInEmergency {
		require(halted);
		_;
	 }

	 /// @dev Constructor
	 /// @param _name crowdfunding project name
	 /// @param _description crowdfunding project short description
	 /// @param _teamContact crowdfunding team contact
	 /// @param _startsAt crowdfunding start time
	 /// @param _endsAt crowdfunding end time
	 /// @param _fundingGoal funding goal in wei
	 /// @param _team  team address
	 /// @param _feeReceiver  fee receiver address
	 function EtherFundMeCrowdfunding(string _name, string _description, string _teamContact, uint _startsAt, uint _endsAt, uint _fundingGoal, address _team, address _feeReceiver) {
		require(_startsAt != 0);
	 	require(_endsAt != 0);
		require(_fundingGoal != 0);
	 	require(_team != 0);
		require(_feeReceiver != 0);

		deployAgent = msg.sender;
		name = _name;
		description = _description;
		teamContact = _teamContact;
		startsAt = _startsAt;
		endsAt = _endsAt;
		fundingGoal = _fundingGoal;
		team = _team;
		feeReceiver = _feeReceiver;
	 }

	 /// @dev Crowdfund state machine management.
	 /// @return State current state
	function getState() public constant returns (State) {
		if (finalized)
			return State.Finalized;
		if (startsAt > now)
			return State.Preparing;
		if (now >= startsAt && now < endsAt)
			return State.Funding;
		if (isGoalReached())
			return State.Success;
		if (!isGoalReached() && this.balance > 0)
			return State.Refunding;
		return State.Failure;
	}

	/// @dev Goal was reached
	/// @return true if the crowdsale has raised enough money to be a succes
	function isGoalReached() public constant returns (bool reached) {
		return this.balance >= (fundingGoal * GOAL_REACHED_CRITERION) / 100;
	}

	 /// @dev Fallback method
	 function() payable {
		invest();
	 }

	 /// @dev Allow contributions to this crowdfunding.
	 function invest() public payable stopInEmergency  {
		require(getState() == State.Funding);
		require(msg.value > 0);

		uint weiAmount = msg.value;
		address investor = msg.sender;

		if(investedAmountOf[investor] == 0) {
			// A new investor
			investorCount++;
		}

    		// calculate online fee
		uint onlineFeeAmount = (weiAmount * ETHERFUNDME_ONLINE_FEE) / 100;
		Withdraw(feeReceiver, onlineFeeAmount);
		// send online fee
		feeReceiver.transfer(onlineFeeAmount);

		uint investedAmount = weiAmount - onlineFeeAmount;
		// Update investor
		investedAmountOf[investor] += investedAmount;
		// Tell us invest was success
		Invested(investor, investedAmount);
	 }

	 /// @dev Finalize a succcesful crowdfunding. The team can triggre a call the contract that provides post-crowdfunding actions, like releasing the funds.
	 function finalize() public inState(State.Success) stopInEmergency  {
		require(msg.sender == deployAgent || msg.sender == team);
		require(!finalized);

		finalized = true;

		uint feeAmount = (this.balance * ETHERFUNDME_FEE) / 100;
		uint teamAmount = this.balance - feeAmount;

		Withdraw(team, teamAmount);
		team.transfer(teamAmount);

		Withdraw(feeReceiver, feeAmount);
		feeReceiver.transfer(feeAmount);
	 }

	 /// @dev Investors can claim refund.
	 function refund() public inState(State.Refunding) {
		uint weiValue = investedAmountOf[msg.sender];
		if (weiValue == 0) revert();
		investedAmountOf[msg.sender] = 0;
		Refund(msg.sender, weiValue);
		msg.sender.transfer(weiValue);
	 }

	 /// called by the deploy agent on emergency, triggers stopped state
	 function halt() public onlyDeployAgent {
		halted = true;
	 }

	 /// called by the deploy agent on end of emergency, returns to normal state
	 function unhalt() public onlyDeployAgent onlyInEmergency {
		halted = false;
	 }
}