[#7] Add support for withdraw pattern

[#7] Add support for withdraw pattern

/// Partnership
/// Requires all pre-defined partners agreement on transactions and operations.
contract Partnership
{
	event Funded();
	event Deposit(address _from, uint _value);
	event TransactionProposed(bytes32 _id, address _initiator, string _description);
	event TransactionCanceled(bytes32 _id, address _actor);
	event TransactionPassed(bytes32 _id, address _finalSigner, string _description);
	event TransactionSent(bytes32 _transaction, address _executor, string _description);
	event Withdrawal(address _partner, uint _amount);

	/// Price in wei of each equal share of the partnership
	uint public sharePrice;

	/// Flag indicating whether or not all partners have paid for their share
	bool public funded;

	/// Array of partner addresses
	address [] public partners;

	/// Collection of partner records
	mapping(address => Partner) public partnerRecords;

	/// Count of partners
	uint public partnerCount;

	/// Count of partners who have paid for their share
	uint public paidPartnerCount;

	/// Collection of pending transactions (ie send X ETH to Y with Z data)
	mapping(bytes32 => Transaction) public transactions;

	/// Count of transactions awaiting confirmation, execution, or cancelation
	uint public activeTransactionCount;

	/// Available withdrawals
	mapping(address => uint) public withdrawableAmounts;

	struct Partner {
		/// Flag indicating that this record has been initialized
		bool isPartner;
		/// Flag indicating that the partner has paid for their share
		bool paid;
		/// Total amount loaned to the partnership by the partner
		uint loanBalance;
	}

	struct Transaction {
		/// Flag indicating that this record has been initialized
		bool valid;
		/// Proposed recipient for the transaction (0 indicates a new contract will be created)
		address to;
		/// Proposed amount to send (0 indicates no wei)
		uint value;
		/// Optional array of data to send with the transaction
		bytes data;
		/// Optional description of proposed transaction
		string description;
		/// Account that created the transaction
		address creator;
		/// Total number of partners that have confirmed/voted
		uint voteCount;
		/// Collection of partners that have confirmed/voted
		mapping(address => uint) votes;
		/// Flag indicating that all partners have confirmed
		bool passed;
		/// Flag indicatint that the transaction has been sent
		bool sent;
	}

	modifier onlyFunded {
		if (!funded)
	       		throw;
		_
	}

	modifier onlyPartner {
		if (!isPartner(msg.sender))
			throw;
		_
	}

	modifier onlyDao {
		if (msg.sender != address(this))
			throw;
		_
	}

	function Partnership(address[] _partners, uint _sharePrice) {
		funded = false;
		partners = _partners;
		sharePrice = _sharePrice;
		for (uint i = 0; i < _partners.length; i++) {
			partnerRecords[_partners[i]].isPartner = true;
		}
		partnerCount = _partners.length;
		paidPartnerCount = 0;
	}

	/// This executes when funds are sent to the contract
	function() {
		if (msg.value > 0) {
			if (funded) {
				if (isPartner(msg.sender)) {
					partnerRecords[msg.sender].loanBalance += msg.value;
				}
			}
			else {
				if (isPartner(msg.sender)) {
					if (partnerRecords[msg.sender].paid) {
						throw;
					}
					else {
						if (msg.value == sharePrice) {
							partnerRecords[msg.sender].paid = true;
							paidPartnerCount = paidPartnerCount + 1;
							if (paidPartnerCount == partnerCount) {
								funded = true;
								Funded();
							}
						}
						else {
							throw;
						}
					}
				}
				else {
					throw;
				}
			}
			Deposit(msg.sender, msg.value);
		}
	}

	/// Adds a proposed transaction to be confirmed by other partners
	function proposeTransaction(address _to, uint _value, bytes _data, string _description) onlyFunded onlyPartner external returns (bytes32) {

		// generate hash for easy specification in confirm and execute
		bytes32 id = sha3(msg.data, block.number);

		// grab the presumably blank transaction
		var transaction = transactions[id];

		transaction.valid = true;
		transaction.to = _to;
		transaction.value = _value;
		transaction.data = _data;
		transaction.description = _description;
		transaction.creator = msg.sender;
		transaction.voteCount = 1;
		transaction.votes[msg.sender] = 1;
		transaction.passed = false;
		transaction.sent = false;

		activeTransactionCount += 1;

		TransactionProposed(id, msg.sender, _description);

		return id;
	}

	/// Cancels a transaction that has not yet passed
	function cancelTransaction(bytes32 _id) onlyFunded onlyPartner external {

		var transaction = transactions[_id];

		// ensure this is a transaction we've set up
		if (!transaction.valid)
			throw;

		// ensure this transaction hasn't passed
		if (transaction.passed)
			throw;

		// only the creator can cancel
		if (transaction.creator != msg.sender)
			throw;

		delete transactions[_id];

		activeTransactionCount -= 1;

		TransactionCanceled(_id, msg.sender);
	}

	/// Confirms an existing proposed transaction
	function confirmTransaction(bytes32 _id) onlyFunded onlyPartner external {

		var transaction = transactions[_id];

		// ensure this is a transaction we've set up
		if (!transaction.valid)
			throw;

		// ignore second confirmation
		if (transaction.votes[msg.sender] == 1)
			throw;

		// register the vote
		transaction.voteCount += 1;
		transaction.votes[msg.sender] = 1;

		if (transaction.voteCount == partnerCount) {
			transaction.passed = true;
			TransactionPassed(_id, msg.sender, transaction.description);
		}
	}

	/// Executes a passed transaction
	function executeTransaction(bytes32 _id) onlyFunded onlyPartner external {

		var transaction = transactions[_id];

		// ignore transactions that have not passed yet
		if (!transaction.passed)
			throw;

		// ignore transactions that have already been sent
		if (transaction.sent)
			throw;

		// register the sent transaction
		transaction.sent = true;

		activeTransactionCount -= 1;

		// send the transaction
		if (transactions[_id].to.call.value(transactions[_id].value)(transactions[_id].data)) {

			TransactionSent(_id, msg.sender, transaction.description);

			// clear the transaction structure to free memory
			delete transactions[_id];
		}
		else {
			// roll back if the call failed
			transaction.sent = false;

			activeTransactionCount += 1;
		}
	}

	/// Distribute ETH to a partner or external recipient
	function distribute(address _recipient, uint _amount) onlyDao external {

		withdrawableAmounts[_recipient] += _amount;
	}

	/// Distribute ETH evenly amongst all partners
	function distributeEvenly(uint _amount) onlyDao external {

		var payout = _amount / partnerCount;

		for (uint i = 0; i < partnerCount; i++) {
			withdrawableAmounts[partners[i]] += payout;
		}
	}

	/// Mark down partner's loan and make it available for withdrawal
	function repayLoan(address _partner, uint _amount) onlyDao external {

		// ignore invalid partners
		if (!partnerRecords[_partner].isPartner)
			throw;

		// ignore invalid amounts
		if (_amount > partnerRecords[_partner].loanBalance)
			throw;

		partnerRecords[_partner].loanBalance -= _amount;
		withdrawableAmounts[_partner] += _amount;
	}

	/// Allow partner or external recipient to withdraw funds marked as withdrawable
	function withdraw(uint _amount) onlyFunded external {

		// ignore requests for more than the amount allowed
		if (_amount > withdrawableAmounts[msg.sender])
			throw;

		// ignore requests for more than the available balance
		if (_amount > this.balance)
			throw;

		// mark the withdrawal as successful
		withdrawableAmounts[msg.sender] -= _amount;

		// send the wei
		if (msg.sender.send(_amount)) {
			Withdrawal(msg.sender, _amount);
		}
		else {
			// roll back if the send failed
			withdrawableAmounts[msg.sender] += _amount;
		}
	}

	/// Dissolve DAO and send the remaining ETH to a beneficiary
	function dissolve(address _beneficiary) onlyDao external {

		// ignore unset beneficiary
		if (_beneficiary == 0)
			throw;

		// prevent lost balance
		if (_beneficiary == address(this))
		    throw;

		suicide(_beneficiary);
	}

	function isPartner(address _address) internal returns (bool) {
		return partnerRecords[_address].isPartner;
	}

}

/// Partnership
/// Requires all pre-defined partners agreement on transactions and operations.
contract Partnership
{
	event Funded();
	event Deposit(address _from, uint _value);
	event TransactionProposed(bytes32 _id, address _initiator, string _description);
	event TransactionCanceled(bytes32 _id, address _actor);
	event TransactionPassed(bytes32 _id, address _finalSigner, string _description);
	event TransactionSent(bytes32 _transaction, address _executor, string _description);
	event Withdrawal(address _partner, uint _amount);

	/// Price in wei of each equal share of the partnership
	uint public sharePrice;

	/// Flag indicating whether or not all partners have paid for their share
	bool public funded;

	/// Array of partner addresses
	address [] public partners;

	/// Collection of partner records
	mapping(address => Partner) public partnerRecords;

	/// Count of partners
	uint public partnerCount;

	/// Count of partners who have paid for their share
	uint public paidPartnerCount;

	/// Collection of pending transactions (ie send X ETH to Y with Z data)
	mapping(bytes32 => Transaction) public transactions;

	/// Count of transactions awaiting confirmation, execution, or cancelation
	uint public activeTransactionCount;

	struct Partner {
		/// Flag indicating that this record has been initialized
		bool isPartner;
		/// Flag indicating that the partner has paid for their share
		bool paid;
		/// Total amount loaned to the partnership by the partner
		uint loanBalance;
		/// Amount released for withdrawal by the partner
		uint withdrawableAmount;
	}

	struct Transaction {
		/// Flag indicating that this record has been initialized
		bool valid;
		/// Proposed recipient for the transaction (0 indicates a new contract will be created)
		address to;
		/// Proposed amount to send (0 indicates no wei)
		uint value;
		/// Optional array of data to send with the transaction
		bytes data;
		/// Optional description of proposed transaction
		string description;
		/// Account that created the transaction
		address creator;
		/// Total number of partners that have confirmed/voted
		uint voteCount;
		/// Collection of partners that have confirmed/voted
		mapping(address => uint) votes;
		/// Flag indicating that all partners have confirmed
		bool passed;
		/// Flag indicatint that the transaction has been sent
		bool sent;
	}

	modifier onlyFunded {
		if (!funded)
	       		throw;
		_
	}

	modifier onlyPartner {
		if (!isPartner(msg.sender))
			throw;
		_
	}

	modifier onlyDao {
		if (msg.sender != address(this))
			throw;
		_
	}

	function Partnership(address[] _partners, uint _sharePrice) {
		funded = false;
		partners = _partners;
		sharePrice = _sharePrice;
		for (uint i = 0; i < _partners.length; i++) {
			partnerRecords[_partners[i]].isPartner = true;
		}
		partnerCount = _partners.length;
		paidPartnerCount = 0;
	}

	/// This executes when funds are sent to the contract
	function() {
		if (msg.value > 0) {
			if (funded) {
				if (isPartner(msg.sender)) {
					partnerRecords[msg.sender].loanBalance += msg.value;
				}
			}
			else {
				if (isPartner(msg.sender)) {
					if (partnerRecords[msg.sender].paid) {
						throw;
					}
					else {
						if (msg.value == sharePrice) {
							partnerRecords[msg.sender].paid = true;
							paidPartnerCount = paidPartnerCount + 1;
							if (paidPartnerCount == partnerCount) {
								funded = true;
								Funded();
							}
						}
						else {
							throw;
						}
					}
				}
				else {
					throw;
				}
			}
			Deposit(msg.sender, msg.value);
		}
	}

	/// Adds a proposed transaction to be confirmed by other partners
	function proposeTransaction(address _to, uint _value, bytes _data, string _description) onlyFunded onlyPartner external returns (bytes32) {

		// generate hash for easy specification in confirm and execute
		bytes32 id = sha3(msg.data, block.number);

		// grab the presumably blank transaction
		var transaction = transactions[id];

		transaction.valid = true;
		transaction.to = _to;
		transaction.value = _value;
		transaction.data = _data;
		transaction.description = _description;
		transaction.creator = msg.sender;
		transaction.voteCount = 1;
		transaction.votes[msg.sender] = 1;
		transaction.passed = false;
		transaction.sent = false;

		activeTransactionCount += 1;

		TransactionProposed(id, msg.sender, _description);

		return id;
	}

	/// Cancels a transaction that has not yet passed
	function cancelTransaction(bytes32 _id) onlyFunded onlyPartner external {

		var transaction = transactions[_id];

		// ensure this is a transaction we've set up
		if (!transaction.valid)
			throw;

		// ensure this transaction hasn't passed
		if (transaction.passed)
			throw;

		// only the creator can cancel
		if (transaction.creator != msg.sender)
			throw;

		delete transactions[_id];

		activeTransactionCount -= 1;

		TransactionCanceled(_id, msg.sender);
	}

	/// Confirms an existing proposed transaction
	function confirmTransaction(bytes32 _id) onlyFunded onlyPartner external {

		var transaction = transactions[_id];

		// ensure this is a transaction we've set up
		if (!transaction.valid)
			throw;

		// ignore second confirmation
		if (transaction.votes[msg.sender] == 1)
			throw;

		// register the vote
		transaction.voteCount += 1;
		transaction.votes[msg.sender] = 1;

		if (transaction.voteCount == partnerCount) {
			transaction.passed = true;
			TransactionPassed(_id, msg.sender, transaction.description);
		}
	}

	/// Executes a passed transaction
	function executeTransaction(bytes32 _id) onlyFunded onlyPartner external {

		var transaction = transactions[_id];

		// ignore transactions that have not passed yet
		if (!transaction.passed)
			throw;

		// ignore transactions that have already been sent
		if (transaction.sent)
			throw;

		// register the sent transaction
		transaction.sent = true;

		activeTransactionCount -= 1;

		// send the transaction
		if (transactions[_id].to.call.value(transactions[_id].value)(transactions[_id].data)) {

			TransactionSent(_id, msg.sender, transaction.description);

			// clear the transaction structure to free memory
			delete transactions[_id];
		}
		else {
			// roll back if the call failed
			transaction.sent = false;

			activeTransactionCount += 1;
		}
	}

	/// Distribute ETH to a partner
	function distribute(address _partner, uint _amount) onlyDao external {

		// ignore invalid partners
		if (!isPartner(_partner))
			throw;

		partnerRecords[_partner].withdrawableAmount += _amount;
	}

	/// Distribute ETH evenly amongst all partners
	function distributeEvenly(uint _amount) onlyDao external {

		var payout = _amount / partnerCount;

		for (uint i = 0; i < partnerCount; i++) {
			partnerRecords[partners[i]].withdrawableAmount += payout;
		}
	}

	/// Mark down partner's loan and make it available for withdrawal
	function repayLoan(address _partner, uint _amount) onlyDao external {

		// ignore invalid partners
		if (!partnerRecords[_partner].isPartner)
			throw;

		// ignore invalid amounts
		if (_amount > partnerRecords[_partner].loanBalance)
			throw;

		partnerRecords[_partner].loanBalance -= _amount;
		partnerRecords[_partner].withdrawableAmount += _amount;
	}

	/// Allow partner to withdraw funds marked as withdrawable
	function withdraw(uint _amount) onlyFunded onlyPartner external {

		// ignore requests for more than the amount allowed
		if (_amount > partnerRecords[msg.sender].withdrawableAmount)
			throw;

		// ignore requests for more than the available balance
		if (_amount > this.balance)
			throw;

		// mark the withdrawal as successful
		partnerRecords[msg.sender].withdrawableAmount -= _amount;

		// send the wei
		if (msg.sender.send(_amount)) {
			Withdrawal(msg.sender, _amount);
		}
		else {
			// roll back if the send failed
			partnerRecords[msg.sender].withdrawableAmount += _amount;
		}
	}

	/// Dissolve DAO and send the remaining ETH to a beneficiary
	function dissolve(address _beneficiary) onlyDao external {

		// ignore unset beneficiary
		if (_beneficiary == 0)
			throw;

		// prevent lost balance
		if (_beneficiary == address(this))
		    throw;

		suicide(_beneficiary);
	}

	function isPartner(address _address) internal returns (bool) {
		return partnerRecords[_address].isPartner;
	}

}


Update interface ID for DNS registrar

Update interface ID for DNS registrar

pragma solidity ^0.8.4;
pragma experimental ABIEncoderV2;

import "../dnssec-oracle/BytesUtils.sol";
import "../dnssec-oracle/DNSSEC.sol";
import "../registry/ENSRegistry.sol";
import "../root/Root.sol";
import "./DNSClaimChecker.sol";
import "./PublicSuffixList.sol";
import "../resolvers/profiles/AddrResolver.sol";

interface IDNSRegistrar {
    function claim(bytes memory name, bytes memory proof) external;
    function proveAndClaim(bytes memory name, DNSSEC.RRSetWithSignature[] memory input, bytes memory proof) external;
    function proveAndClaimWithResolver(bytes memory name, DNSSEC.RRSetWithSignature[] memory input, bytes memory proof, address resolver, address addr) external;
}

/**
 * @dev An ENS registrar that allows the owner of a DNS name to claim the
 *      corresponding name in ENS.
 */
contract DNSRegistrar is IDNSRegistrar {
    using BytesUtils for bytes;

    DNSSEC public oracle;
    ENS public ens;
    PublicSuffixList public suffixes;

    bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));
    bytes4 constant private DNSSEC_CLAIM_ID = bytes4(
        keccak256("claim(bytes,bytes)") ^
        keccak256("proveAndClaim(bytes,bytes,bytes)") ^
        keccak256("oracle()")
    );

    event Claim(bytes32 indexed node, address indexed owner, bytes dnsname);
    event NewOracle(address oracle);
    event NewPublicSuffixList(address suffixes);

    constructor(DNSSEC _dnssec, PublicSuffixList _suffixes, ENS _ens) {
        oracle = _dnssec;
        emit NewOracle(address(oracle));
        suffixes = _suffixes;
        emit NewPublicSuffixList(address(suffixes));
        ens = _ens;
    }

    /**
     * @dev This contract's owner-only functions can be invoked by the owner of the ENS root.
     */
    modifier onlyOwner {
        Root root = Root(ens.owner(bytes32(0)));
        address owner = root.owner();
        require(msg.sender == owner);
        _;
    }

    function setOracle(DNSSEC _dnssec) public onlyOwner {
        oracle = _dnssec;
        emit NewOracle(address(oracle));
    }

    function setPublicSuffixList(PublicSuffixList _suffixes) public onlyOwner {
        suffixes = _suffixes;
        emit NewPublicSuffixList(address(suffixes));
    }

    /**
     * @dev Claims a name by proving ownership of its DNS equivalent.
     * @param name The name to claim, in DNS wire format.
     * @param proof A DNS RRSet proving ownership of the name. Must be verified
     *        in the DNSSEC oracle before calling. This RRSET must contain a TXT
     *        record for '_ens.' + name, with the value 'a=0x...'. Ownership of
     *        the name will be transferred to the address specified in the TXT
     *        record.
     */
    function claim(bytes memory name, bytes memory proof) public override {
        (bytes32 rootNode, bytes32 labelHash, address addr) = _claim(name, proof);
        ens.setSubnodeOwner(rootNode, labelHash, addr);
    }

    /**
     * @dev Submits proofs to the DNSSEC oracle, then claims a name using those proofs.
     * @param name The name to claim, in DNS wire format.
     * @param input The data to be passed to the Oracle's `submitProofs` function. The last
     *        proof must be the TXT record required by the registrar.
     * @param proof The proof record for the first element in input.
     */
    function proveAndClaim(bytes memory name, DNSSEC.RRSetWithSignature[] memory input, bytes memory proof) public override {
        proof = oracle.submitRRSets(input, proof);
        claim(name, proof);
    }

    function proveAndClaimWithResolver(bytes memory name, DNSSEC.RRSetWithSignature[] memory input, bytes memory proof, address resolver, address addr) public override {
        proof = oracle.submitRRSets(input, proof);
        (bytes32 rootNode, bytes32 labelHash, address owner) = _claim(name, proof);
        require(msg.sender == owner, "Only owner can call proveAndClaimWithResolver");
        ens.setSubnodeRecord(rootNode, labelHash, owner, resolver, 0);
        if(addr != address(0)) {
            require(resolver != address(0), "Cannot set addr if resolver is not set");
            bytes32 node = keccak256(abi.encodePacked(rootNode, labelHash));
            AddrResolver(resolver).setAddr(node, addr);
        }
    }

    function supportsInterface(bytes4 interfaceID) external pure returns (bool) {
        return interfaceID == INTERFACE_META_ID ||
               interfaceID == type(IDNSRegistrar).interfaceId;
    }

    function _claim(bytes memory name, bytes memory proof) internal returns(bytes32 rootNode, bytes32 labelHash, address addr) {
        // Get the first label
        uint labelLen = name.readUint8(0);
        labelHash = name.keccak(1, labelLen);

        // Parent name must be in the public suffix list.
        bytes memory parentName = name.substring(labelLen + 1, name.length - labelLen - 1);
        require(suffixes.isPublicSuffix(parentName), "Parent name must be a public suffix");

        // Make sure the parent name is enabled
        rootNode = enableNode(parentName, 0);

        (addr,) = DNSClaimChecker.getOwnerAddress(oracle, name, proof);

        emit Claim(keccak256(abi.encodePacked(rootNode, labelHash)), addr, name);
    }

    function enableNode(bytes memory domain, uint offset) internal returns(bytes32 node) {
        uint len = domain.readUint8(offset);
        if(len == 0) {
            return bytes32(0);
        }

        bytes32 parentNode = enableNode(domain, offset + len + 1);
        bytes32 label = domain.keccak(offset + 1, len);
        node = keccak256(abi.encodePacked(parentNode, label));
        address owner = ens.owner(node);
        require(owner == address(0) || owner == address(this), "Cannot enable a name owned by someone else");
        if(owner != address(this)) {
            if(parentNode == bytes32(0)) {
                Root root = Root(ens.owner(bytes32(0)));
                root.setSubnodeOwner(label, address(this));
            } else {
                ens.setSubnodeOwner(parentNode, label, address(this));
            }
        }
        return node;
    }
}

pragma solidity ^0.8.4;
pragma experimental ABIEncoderV2;

import "../dnssec-oracle/BytesUtils.sol";
import "../dnssec-oracle/DNSSEC.sol";
import "../registry/ENSRegistry.sol";
import "../root/Root.sol";
import "./DNSClaimChecker.sol";
import "./PublicSuffixList.sol";
import "../resolvers/profiles/AddrResolver.sol";

/**
 * @dev An ENS registrar that allows the owner of a DNS name to claim the
 *      corresponding name in ENS.
 */
contract DNSRegistrar {
    using BytesUtils for bytes;

    DNSSEC public oracle;
    ENS public ens;
    PublicSuffixList public suffixes;

    bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));
    bytes4 constant private DNSSEC_CLAIM_ID = bytes4(
        keccak256("claim(bytes,bytes)") ^
        keccak256("proveAndClaim(bytes,bytes,bytes)") ^
        keccak256("oracle()")
    );

    event Claim(bytes32 indexed node, address indexed owner, bytes dnsname);
    event NewOracle(address oracle);
    event NewPublicSuffixList(address suffixes);

    constructor(DNSSEC _dnssec, PublicSuffixList _suffixes, ENS _ens) public {
        oracle = _dnssec;
        emit NewOracle(address(oracle));
        suffixes = _suffixes;
        emit NewPublicSuffixList(address(suffixes));
        ens = _ens;
    }

    /**
     * @dev This contract's owner-only functions can be invoked by the owner of the ENS root.
     */
    modifier onlyOwner {
        Root root = Root(ens.owner(bytes32(0)));
        address owner = root.owner();
        require(msg.sender == owner);
        _;
    }

    function setOracle(DNSSEC _dnssec) public onlyOwner {
        oracle = _dnssec;
        emit NewOracle(address(oracle));
    }

    function setPublicSuffixList(PublicSuffixList _suffixes) public onlyOwner {
        suffixes = _suffixes;
        emit NewPublicSuffixList(address(suffixes));
    }

    /**
     * @dev Claims a name by proving ownership of its DNS equivalent.
     * @param name The name to claim, in DNS wire format.
     * @param proof A DNS RRSet proving ownership of the name. Must be verified
     *        in the DNSSEC oracle before calling. This RRSET must contain a TXT
     *        record for '_ens.' + name, with the value 'a=0x...'. Ownership of
     *        the name will be transferred to the address specified in the TXT
     *        record.
     */
    function claim(bytes memory name, bytes memory proof) public {
        (bytes32 rootNode, bytes32 labelHash, address addr) = _claim(name, proof);
        ens.setSubnodeOwner(rootNode, labelHash, addr);
    }

    /**
     * @dev Submits proofs to the DNSSEC oracle, then claims a name using those proofs.
     * @param name The name to claim, in DNS wire format.
     * @param input The data to be passed to the Oracle's `submitProofs` function. The last
     *        proof must be the TXT record required by the registrar.
     * @param proof The proof record for the first element in input.
     */
    function proveAndClaim(bytes memory name, DNSSEC.RRSetWithSignature[] memory input, bytes memory proof) public {
        proof = oracle.submitRRSets(input, proof);
        claim(name, proof);
    }

    function proveAndClaimWithResolver(bytes memory name, DNSSEC.RRSetWithSignature[] memory input, bytes memory proof, address resolver, address addr) public {
        proof = oracle.submitRRSets(input, proof);
        (bytes32 rootNode, bytes32 labelHash, address owner) = _claim(name, proof);
        require(msg.sender == owner, "Only owner can call proveAndClaimWithResolver");
        ens.setSubnodeRecord(rootNode, labelHash, owner, resolver, 0);
        if(addr != address(0)) {
            require(resolver != address(0), "Cannot set addr if resolver is not set");
            bytes32 node = keccak256(abi.encodePacked(rootNode, labelHash));
            AddrResolver(resolver).setAddr(node, addr);
        }
    }

    function supportsInterface(bytes4 interfaceID) external pure returns (bool) {
        return interfaceID == INTERFACE_META_ID ||
               interfaceID == DNSSEC_CLAIM_ID;
    }

    function _claim(bytes memory name, bytes memory proof) internal returns(bytes32 rootNode, bytes32 labelHash, address addr) {
        // Get the first label
        uint labelLen = name.readUint8(0);
        labelHash = name.keccak(1, labelLen);

        // Parent name must be in the public suffix list.
        bytes memory parentName = name.substring(labelLen + 1, name.length - labelLen - 1);
        require(suffixes.isPublicSuffix(parentName), "Parent name must be a public suffix");

        // Make sure the parent name is enabled
        rootNode = enableNode(parentName, 0);

        (addr,) = DNSClaimChecker.getOwnerAddress(oracle, name, proof);

        emit Claim(keccak256(abi.encodePacked(rootNode, labelHash)), addr, name);
    }

    function enableNode(bytes memory domain, uint offset) internal returns(bytes32 node) {
        uint len = domain.readUint8(offset);
        if(len == 0) {
            return bytes32(0);
        }

        bytes32 parentNode = enableNode(domain, offset + len + 1);
        bytes32 label = domain.keccak(offset + 1, len);
        node = keccak256(abi.encodePacked(parentNode, label));
        address owner = ens.owner(node);
        require(owner == address(0) || owner == address(this), "Cannot enable a name owned by someone else");
        if(owner != address(this)) {
            if(parentNode == bytes32(0)) {
                Root root = Root(ens.owner(bytes32(0)));
                root.setSubnodeOwner(label, address(this));
            } else {
                ens.setSubnodeOwner(parentNode, label, address(this));
            }
        }
        return node;
    }
}


Drop emission scalers

Drop emission scalers

pragma solidity ^0.4.24;

import './RobotLiability.sol';
import './Lighthouse.sol';
import './XRT.sol';

import 'ens/contracts/ENS.sol';
import 'ens/contracts/ENSRegistry.sol';
import 'ens/contracts/PublicResolver.sol';

contract LiabilityFactory {
    constructor(
        address _robot_liability_lib,
        address _lighthouse_lib,
        XRT _xrt
    ) public {
        robotLiabilityLib = _robot_liability_lib;
        lighthouseLib = _lighthouse_lib;
        xrt = _xrt;
    }

    /**
     * @dev New liability created
     */
    event NewLiability(address indexed liability);

    /**
     * @dev New lighthouse created
     */
    event NewLighthouse(address indexed lighthouse, string name);

    /**
     * @dev Robonomics network protocol token
     */
    XRT public xrt;

    /**
     * @dev Ethereum name system
     */
    ENS public ens;

    /**
     * @dev Robonomics ENS resolver
     */
    PublicResolver public resolver;

    bytes32 constant lighthouseNode
        // lighthouse.0.robonomics.eth
        = 0x1e42a8e8e1e8cf36e83d096dcc74af801d0a194a14b897f9c8dfd403b4eebeda;

    /**
     *  @dev Set ENS registry contract address
     */
    function setENS(ENS _ens) public {
      require(address(ens) == 0);
      ens = _ens;
      resolver = PublicResolver(ens.resolver(lighthouseNode));
    }

    /**
     * @dev Total GAS utilized by Robonomics network
     */
    uint256 public totalGasUtilizing = 0;

    /**
     * @dev GAS utilized by liability contracts
     */
    mapping(address => uint256) public gasUtilizing;

    /**
     * @dev Used market orders accounting
     */
    mapping(bytes32 => bool) public usedHash;

    /**
     * @dev Lighthouse accounting
     */
    mapping(address => bool) public isLighthouse;

    /**
     * @dev Robot liability shared code smart contract
     */
    address public robotLiabilityLib;

    /**
     * @dev Lightouse shared code smart contract
     */
    address public lighthouseLib;

    /**
     * @dev XRT emission value for utilized gas
     */
    function winnerFromGas(uint256 _gas) public view returns (uint256) {
        // Basic equal formula
        uint256 wn = _gas;

        /* Additional emission table
        if (totalGasUtilizing < 347 * (10 ** 10)) {
            wn *= 6;
        } else if (totalGasUtilizing < 2 * 347 * (10 ** 10)) {
            wn *= 4;
        } else if (totalGasUtilizing < 3 * 347 * (10 ** 10)) {
            wn = wn * 2667 / 1000;
        } else if (totalGasUtilizing < 4 * 347 * (10 ** 10)) {
            wn = wn * 1778 / 1000;
        } else if (totalGasUtilizing < 5 * 347 * (10 ** 10)) {
            wn = wn * 1185 / 1000;
        } */

        return wn ;
    }

    /**
     * @dev Only lighthouse guard
     */
    modifier onlyLighthouse {
        require(isLighthouse[msg.sender]);
        _;
    }

    /**
     * @dev Parameter can be used only once
     * @param _hash Single usage hash
     */
    function usedHashGuard(bytes32 _hash) internal {
        require(!usedHash[_hash]);
        usedHash[_hash] = true;
    }

    /**
     * @dev Create robot liability smart contract
     * @param _ask ABI-encoded ASK order message
     * @param _bid ABI-encoded BID order message
     */
    function createLiability(
        bytes _ask,
        bytes _bid
    )
        external
        onlyLighthouse
        returns (RobotLiability liability)
    {
        // Store in memory available gas
        uint256 gasinit = gasleft();

        // Create liability
        liability = new RobotLiability(robotLiabilityLib);
        emit NewLiability(liability);

        // Parse messages
        require(liability.call(abi.encodePacked(bytes4(0x82fbaa25), _ask))); // liability.ask(...)
        usedHashGuard(liability.askHash());

        require(liability.call(abi.encodePacked(bytes4(0x66193359), _bid))); // liability.bid(...)
        usedHashGuard(liability.bidHash());

        // Transfer lighthouse fee to lighthouse worker directly
        require(xrt.transferFrom(liability.promisor(),
                                 tx.origin,
                                 liability.lighthouseFee()));

        // Transfer liability security and hold on contract
        ERC20 token = liability.token();
        require(token.transferFrom(liability.promisee(),
                                   liability,
                                   liability.cost()));

        // Transfer validator fee and hold on contract
        if (address(liability.validator()) != 0 && liability.validatorFee() > 0)
            require(xrt.transferFrom(liability.promisee(),
                                     liability,
                                     liability.validatorFee()));

        // Accounting gas usage of transaction
        uint256 gas = gasinit - gasleft() + 110525; // Including observation error
        totalGasUtilizing       += gas;
        gasUtilizing[liability] += gas;
     }

    /**
     * @dev Create lighthouse smart contract
     * @param _minimalFreeze Minimal freeze value of XRT token
     * @param _timeoutBlocks Max time of lighthouse silence in blocks
     * @param _name Lighthouse subdomain,
     *              example: for 'my-name' will created 'my-name.lighthouse.0.robonomics.eth' domain
     */
    function createLighthouse(
        uint256 _minimalFreeze,
        uint256 _timeoutBlocks,
        string  _name
    )
        external
        returns (address lighthouse)
    {
        // Name reservation check
        bytes32 subnode = keccak256(abi.encodePacked(lighthouseNode, keccak256(_name)));
        require(ens.resolver(subnode) == 0);

        // Create lighthouse
        lighthouse = new Lighthouse(lighthouseLib, _minimalFreeze, _timeoutBlocks);
        emit NewLighthouse(lighthouse, _name);
        isLighthouse[lighthouse] = true;

        // Register subnode
        ens.setSubnodeOwner(lighthouseNode, keccak256(_name), this);

        // Register lighthouse address
        ens.setResolver(subnode, resolver);
        resolver.setAddr(subnode, lighthouse);
    }

    /**
     * @dev Is called whan after liability finalization
     * @param _gas Liability finalization gas expenses
     */
    function liabilityFinalized(
        uint256 _gas
    )
        external
        returns (bool)
    {
        require(gasUtilizing[msg.sender] > 0);

        uint256 gas = _gas - gasleft();
        totalGasUtilizing        += gas;
        gasUtilizing[msg.sender] += gas;
        require(xrt.mint(tx.origin, winnerFromGas(gasUtilizing[msg.sender])));
        return true;
    }
}

pragma solidity ^0.4.24;

import './RobotLiability.sol';
import './Lighthouse.sol';
import './XRT.sol';

import 'ens/contracts/ENS.sol';
import 'ens/contracts/ENSRegistry.sol';
import 'ens/contracts/PublicResolver.sol';

contract LiabilityFactory {
    constructor(
        address _robot_liability_lib,
        address _lighthouse_lib,
        XRT _xrt
    ) public {
        robotLiabilityLib = _robot_liability_lib;
        lighthouseLib = _lighthouse_lib;
        xrt = _xrt;
    }

    /**
     * @dev New liability created
     */
    event NewLiability(address indexed liability);

    /**
     * @dev New lighthouse created
     */
    event NewLighthouse(address indexed lighthouse, string name);

    /**
     * @dev Robonomics network protocol token
     */
    XRT public xrt;

    /**
     * @dev Ethereum name system
     */
    ENS public ens;

    /**
     * @dev Robonomics ENS resolver
     */
    PublicResolver public resolver;

    bytes32 constant lighthouseNode
        // lighthouse.0.robonomics.eth
        = 0x1e42a8e8e1e8cf36e83d096dcc74af801d0a194a14b897f9c8dfd403b4eebeda;

    /**
     *  @dev Set ENS registry contract address
     */
    function setENS(ENS _ens) public {
      require(address(ens) == 0);
      ens = _ens;
      resolver = PublicResolver(ens.resolver(lighthouseNode));
    }

    /**
     * @dev Total GAS utilized by Robonomics network
     */
    uint256 public totalGasUtilizing = 0;

    /**
     * @dev GAS utilized by liability contracts
     */
    mapping(address => uint256) public gasUtilizing;

    /**
     * @dev Used market orders accounting
     */
    mapping(bytes32 => bool) public usedHash;

    /**
     * @dev Lighthouse accounting
     */
    mapping(address => bool) public isLighthouse;

    /**
     * @dev Robot liability shared code smart contract
     */
    address public robotLiabilityLib;

    /**
     * @dev Lightouse shared code smart contract
     */
    address public lighthouseLib;

    /**
     * @dev XRT emission value for utilized gas
     */
    function winnerFromGas(uint256 _gas) public view returns (uint256) {
        // Basic equal formula
        uint256 wn = _gas;

        /* Additional emission table */
        if (totalGasUtilizing < 347 * (10 ** 10)) {
            wn *= 6;
        } else if (totalGasUtilizing < 2 * 347 * (10 ** 10)) {
            wn *= 4;
        } else if (totalGasUtilizing < 3 * 347 * (10 ** 10)) {
            wn = wn * 2667 / 1000;
        } else if (totalGasUtilizing < 4 * 347 * (10 ** 10)) {
            wn = wn * 1778 / 1000;
        } else if (totalGasUtilizing < 5 * 347 * (10 ** 10)) {
            wn = wn * 1185 / 1000;
        }

        return wn ;
    }

    /**
     * @dev Only lighthouse guard
     */
    modifier onlyLighthouse {
        require(isLighthouse[msg.sender]);
        _;
    }

    /**
     * @dev Parameter can be used only once
     * @param _hash Single usage hash
     */
    function usedHashGuard(bytes32 _hash) internal {
        require(!usedHash[_hash]);
        usedHash[_hash] = true;
    }

    /**
     * @dev Create robot liability smart contract
     * @param _ask ABI-encoded ASK order message
     * @param _bid ABI-encoded BID order message
     */
    function createLiability(
        bytes _ask,
        bytes _bid
    )
        external
        onlyLighthouse
        returns (RobotLiability liability)
    {
        // Store in memory available gas
        uint256 gasinit = gasleft();

        // Create liability
        liability = new RobotLiability(robotLiabilityLib);
        emit NewLiability(liability);

        // Parse messages
        require(liability.call(abi.encodePacked(bytes4(0x82fbaa25), _ask))); // liability.ask(...)
        usedHashGuard(liability.askHash());

        require(liability.call(abi.encodePacked(bytes4(0x66193359), _bid))); // liability.bid(...)
        usedHashGuard(liability.bidHash());

        // Transfer lighthouse fee to lighthouse worker directly
        require(xrt.transferFrom(liability.promisor(),
                                 tx.origin,
                                 liability.lighthouseFee()));

        // Transfer liability security and hold on contract
        ERC20 token = liability.token();
        require(token.transferFrom(liability.promisee(),
                                   liability,
                                   liability.cost()));

        // Transfer validator fee and hold on contract
        if (address(liability.validator()) != 0 && liability.validatorFee() > 0)
            require(xrt.transferFrom(liability.promisee(),
                                     liability,
                                     liability.validatorFee()));

        // Accounting gas usage of transaction
        uint256 gas = gasinit - gasleft() + 110525; // Including observation error
        totalGasUtilizing       += gas;
        gasUtilizing[liability] += gas;
     }

    /**
     * @dev Create lighthouse smart contract
     * @param _minimalFreeze Minimal freeze value of XRT token
     * @param _timeoutBlocks Max time of lighthouse silence in blocks
     * @param _name Lighthouse subdomain,
     *              example: for 'my-name' will created 'my-name.lighthouse.0.robonomics.eth' domain
     */
    function createLighthouse(
        uint256 _minimalFreeze,
        uint256 _timeoutBlocks,
        string  _name
    )
        external
        returns (address lighthouse)
    {
        // Name reservation check
        bytes32 subnode = keccak256(abi.encodePacked(lighthouseNode, keccak256(_name)));
        require(ens.resolver(subnode) == 0);

        // Create lighthouse
        lighthouse = new Lighthouse(lighthouseLib, _minimalFreeze, _timeoutBlocks);
        emit NewLighthouse(lighthouse, _name);
        isLighthouse[lighthouse] = true;

        // Register subnode
        ens.setSubnodeOwner(lighthouseNode, keccak256(_name), this);

        // Register lighthouse address
        ens.setResolver(subnode, resolver);
        resolver.setAddr(subnode, lighthouse);
    }

    /**
     * @dev Is called whan after liability finalization
     * @param _gas Liability finalization gas expenses
     */
    function liabilityFinalized(
        uint256 _gas
    )
        external
        returns (bool)
    {
        require(gasUtilizing[msg.sender] > 0);

        uint256 gas = _gas - gasleft();
        totalGasUtilizing        += gas;
        gasUtilizing[msg.sender] += gas;
        require(xrt.mint(tx.origin, winnerFromGas(gasUtilizing[msg.sender])));
        return true;
    }
}


Add optimization for EnumerableSet (#2588)

Co-authored-by: Reason <f219cc0614ae6860f43a3cd84b5cf31fc312cd9d@Lee.com>

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;

        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) { // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        require(set._values.length > index, "EnumerableSet: index out of bounds");
        return set._values[index];
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;

        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) { // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        require(set._values.length > index, "EnumerableSet: index out of bounds");
        return set._values[index];
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }
}


remove commented code

remove commented code

//pragma solidity 0.4.1;

import {RequestLib} from "contracts/RequestLib.sol";
import {Digger} from "contracts/Digger.sol";

contract TransactionRequest is Digger {
    using RequestLib for RequestLib.Request;

    /*
     *  addressArgs[0] - meta.owner
     *  addressArgs[1] - paymentData.donationBenefactor
     *  addressArgs[2] - txnData.toAddress
     *
     *  uintArgs[0]  - paymentData.donation
     *  uintArgs[1]  - paymentData.payment
     *  uintArgs[2]  - schedule.claimWindowSize
     *  uintArgs[3]  - schedule.freezePeriod
     *  uintArgs[4]  - schedule.reservedWindowSize
     *  uintArgs[5]  - schedule.temporalUnit
     *  uintArgs[6]  - schedule.windowStart
     *  uintArgs[7]  - schedule.windowSize
     *  uintArgs[8]  - txnData.callGas
     *  uintArgs[9]  - txnData.callValue
     *  uintArgs[10] - txnData.requiredStackDepth
     */
    function TransactionRequest(address[4] addressArgs,
                                uint[11] uintArgs,
                                bytes callData) {
        txnRequest.initialize(addressArgs, uintArgs, callData);
    }

    RequestLib.Request txnRequest;

    /*
     *  Actions
     */
    function execute() public returns (bool) {
        return txnRequest.execute();
    }

    function cancel() public returns (bool) {
        return txnRequest.cancel();
    }

    function claim() public returns (bool) {
        return txnRequest.claim();
    }

    /*
     *  Data accessor functions.
     */
    //
    //  TODO: figure out why returning RequestLib.serialize() isn't working.
    //
    function requestData() constant returns (address[6],
                                             bool[3],
                                             uint[15],
                                             uint8[1]) {
        if (txnRequest.serialize()) {
            return (
                txnRequest.serializedValues.addressValues,
                txnRequest.serializedValues.boolValues,
                txnRequest.serializedValues.uintValues,
                txnRequest.serializedValues.uint8Values
            );
        } else {
            throw;
        }
    }

    function callData() constant returns (bytes) {
        return txnRequest.txnData.callData;
    }

    /*
     *  Pull based payment functions.
     */
    function refundClaimDeposit() public returns (bool) {
        return txnRequest.refundClaimDeposit();
    }

    function sendDonation() public returns (bool) {
        return txnRequest.sendDonation();
    }

    function sendPayment() public returns (bool) {
        return txnRequest.sendPayment();
    }

    function sendOwnerEther() public returns (bool) {
        return txnRequest.sendOwnerEther();
    }
}

//pragma solidity 0.4.1;

import {RequestLib} from "contracts/RequestLib.sol";
import {Digger} from "contracts/Digger.sol";

contract TransactionRequest is Digger {
    using RequestLib for RequestLib.Request;

    /*
     *  addressArgs[0] - meta.owner
     *  addressArgs[1] - paymentData.donationBenefactor
     *  addressArgs[2] - txnData.toAddress
     *
     *  uintArgs[0]  - paymentData.donation
     *  uintArgs[1]  - paymentData.payment
     *  uintArgs[2]  - schedule.claimWindowSize
     *  uintArgs[3]  - schedule.freezePeriod
     *  uintArgs[4]  - schedule.reservedWindowSize
     *  uintArgs[5]  - schedule.temporalUnit
     *  uintArgs[6]  - schedule.windowStart
     *  uintArgs[7]  - schedule.windowSize
     *  uintArgs[8]  - txnData.callGas
     *  uintArgs[9]  - txnData.callValue
     *  uintArgs[10] - txnData.requiredStackDepth
     */
    function TransactionRequest(address[4] addressArgs,
                                uint[11] uintArgs,
                                bytes callData) {
        txnRequest.initialize(addressArgs, uintArgs, callData);
    }

    RequestLib.Request txnRequest;

    /*
     *  Actions
     */
    function execute() public returns (bool) {
        return txnRequest.execute();
    }

    function cancel() public returns (bool) {
        return txnRequest.cancel();
    }

    function claim() public returns (bool) {
        return txnRequest.claim();
    }

    /*
     *  Data accessor functions.
     */
    //
    //  TODO: figure out why returning RequestLib.serialize() isn't working.
    //
    function requestData() constant returns (address[6],
                                             bool[3],
                                             uint[15],
                                             uint8[1]) {
        if (txnRequest.serialize()) {
            return (
                txnRequest.serializedValues.addressValues,
                txnRequest.serializedValues.boolValues,
                txnRequest.serializedValues.uintValues,
                txnRequest.serializedValues.uint8Values
            );
        } else {
            throw;
        }
    }
    //function requestData() constant returns (address[6],
    //                                         bool[3],
    //                                         uint[15],
    //                                         uint8[1]) {
    //    // Address values
    //    address[6] memory addressValues = [
    //        txnRequest.claimData.claimedBy,
    //        txnRequest.meta.createdBy,
    //        txnRequest.meta.owner,
    //        txnRequest.paymentData.donationBenefactor,
    //        txnRequest.paymentData.paymentBenefactor,
    //        txnRequest.txnData.toAddress
    //    ];

    //    // Boolean values
    //    bool[3] memory boolValues = [
    //        txnRequest.meta.isCancelled,
    //        txnRequest.meta.wasCalled,
    //        txnRequest.meta.wasSuccessful
    //    ];

    //    // UInt256 values
    //    uint[15] memory uintValues = [
    //        txnRequest.claimData.claimDeposit,
    //        txnRequest.paymentData.anchorGasPrice,
    //        txnRequest.paymentData.donation,
    //        txnRequest.paymentData.donationOwed,
    //        txnRequest.paymentData.payment,
    //        txnRequest.paymentData.paymentOwed,
    //        txnRequest.schedule.claimWindowSize,
    //        txnRequest.schedule.freezePeriod,
    //        txnRequest.schedule.reservedWindowSize,
    //        uint(txnRequest.schedule.temporalUnit),
    //        txnRequest.schedule.windowStart,
    //        txnRequest.schedule.windowSize,
    //        txnRequest.txnData.callGas,
    //        txnRequest.txnData.callValue,
    //        txnRequest.txnData.requiredStackDepth
    //    ];

    //    // Uint8 values
    //    uint8[1] memory uint8Values = [
    //        txnRequest.claimData.paymentModifier
    //    ];

    //    return (
    //        addressValues,
    //        boolValues,
    //        uintValues,
    //        uint8Values
    //    );
    //}

    function callData() constant returns (bytes) {
        return txnRequest.txnData.callData;
    }

    /*
     *  Pull based payment functions.
     */
    function refundClaimDeposit() public returns (bool) {
        return txnRequest.refundClaimDeposit();
    }

    function sendDonation() public returns (bool) {
        return txnRequest.sendDonation();
    }

    function sendPayment() public returns (bool) {
        return txnRequest.sendPayment();
    }

    function sendOwnerEther() public returns (bool) {
        return txnRequest.sendOwnerEther();
    }
}


adding documentation

adding documentation

/*
    Copyright 2017 Phillip A. Elsasser

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

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

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

/// @title OrderLib
/// @author Phil Elsasser <phil@marketprotcol.io>
library OrderLib {

    struct Order {
        address maker;
        address taker;
        address feeRecipient;
        uint makerFee;
        uint takerFee;
        uint price;
        uint expirationTimeStamp;
        int qty;
        bytes32 orderHash;
    }

    /// @dev factory for orders to be created with needed hash.
    /// @param contractAddress address of the calling contract, orders are unique to each contract
    /// @param orderAddresses array of 3 address. maker, taker, and feeRecipient
    /// @param unsignedOrderValues array of 4 unsigned integers. makerFee, takerFee, price, and expirationTimeStamp
    /// @param orderQty signed qty of the original order.
    function createOrder(address contractAddress,
        address[3] orderAddresses,
        uint[4] unsignedOrderValues,
        int orderQty
    ) internal pure returns (Order order) {
        order.maker = orderAddresses[0];
        order.taker = orderAddresses[1];
        order.feeRecipient = orderAddresses[2];
        order.makerFee = unsignedOrderValues[0];
        order.takerFee = unsignedOrderValues[1];
        order.price = unsignedOrderValues[2];
        order.expirationTimeStamp = unsignedOrderValues[3];
        order.qty = orderQty;
        order.orderHash = createOrderHash(contractAddress, orderAddresses, unsignedOrderValues, orderQty);
        return order;
    }

    /// @notice creates the hash for the given order parameters.
    /// @param contractAddress address of the calling contract, orders are unique to each contract
    /// @param orderAddresses array of 3 address. maker, taker, and feeRecipient
    /// @param unsignedOrderValues array of 4 unsigned integers. makerFee, takerFee, price, and expirationTimeStamp
    /// @param orderQty signed qty of the original order.
    function createOrderHash(
        address contractAddress,
        address[3] orderAddresses,
        uint[4] unsignedOrderValues,
        int orderQty
    ) public pure returns (bytes32) {
        return keccak256(
            contractAddress,
            orderAddresses[0],
            orderAddresses[1],
            orderAddresses[2],
            unsignedOrderValues[0],
            unsignedOrderValues[1],
            unsignedOrderValues[2],
            unsignedOrderValues[3],
            orderQty
        );
    }

    /// @notice confirms hash originated from signer
    /// @param signerAddress - address of order originator
    /// @param hash - original order hash
    /// @param v order signature
    /// @param r order signature
    /// @param s order signature
    function isValidSignature(
        address signerAddress,
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public pure returns (bool) {
        return signerAddress == ecrecover(keccak256("\x19Ethereum Signed Message:\n32", hash), v, r, s);
    }
}

/*
    Copyright 2017 Phillip A. Elsasser

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

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

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

library OrderLib {

    struct Order {
        address maker;
        address taker;
        address feeRecipient;
        uint makerFee;
        uint takerFee;
        uint price;
        uint expirationTimeStamp;
        int qty;
        bytes32 orderHash;
    }

    function createOrder(address contractAddress,
        address[3] orderAddressesArray,
        uint[4] unsignedOrderValues,
        int orderQty
    ) internal pure returns (Order order) {
        order.maker = orderAddressesArray[0];
        order.taker = orderAddressesArray[1];
        order.feeRecipient = orderAddressesArray[2];
        order.makerFee = unsignedOrderValues[0];
        order.takerFee = unsignedOrderValues[1];
        order.price = unsignedOrderValues[2];
        order.expirationTimeStamp = unsignedOrderValues[3];
        order.qty = orderQty;
        order.orderHash = createOrderHash(contractAddress, orderAddressesArray, unsignedOrderValues, orderQty);
        return order;
    }

    function createOrderHash(
        address contractAddress,
        address[3] orderAddressesArray,
        uint[4] unsignedOrderValues,
        int orderQty
    ) public pure returns (bytes32) {
        return keccak256(
            contractAddress,
            orderAddressesArray[0],
            orderAddressesArray[1],
            orderAddressesArray[2],
            unsignedOrderValues[0],
            unsignedOrderValues[1],
            unsignedOrderValues[2],
            unsignedOrderValues[3],
            orderQty
        );
    }

    function isValidSignature(
        address signerAddress,
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public pure returns (bool) {
        return signerAddress == ecrecover(keccak256("\x19Ethereum Signed Message:\n32", hash), v, r, s);
    }
}


Update contract to remove deprecated code

pragma solidity ^0.4.21;

/*
Simple escrow contract that mediates disputes using a burn contract
*/

contract Escrow {

    enum State {UNINITIATED, AWAITING_PAYMENT, AWAITING_DELIVERY, COMPLETE}
    State public currentState;

    modifier inState(State expectedState) { require(currentState == expectedState); _; }
    modifier buyerOnly() { require(msg.sender == buyer); _; }
    modifier correctPrice() { require(msg.value == price); _; }

    address public buyer;
    address public seller;

    bool public buyer_in;
    bool public seller_in;

    uint public price;

    constructor(address _buyer, address _seller, uint _price){
        buyer = _buyer;
        seller = _seller;
        price = _price;
    }

    function initiateContract() correctPrice inState(State.UNINITIATED) payable {
        if (msg.sender == buyer) {
            buyer_in = true;
        }
        if (msg.sender == seller) {
            seller_in = true;
        }
        if (buyer_in && seller_in) {
            currentState = State.AWAITING_PAYMENT;
        }
    }

    function confirmPayment() buyerOnly correctPrice inState(State.AWAITING_PAYMENT) payable {
        currentState = State.AWAITING_DELIVERY;
    }

    function confirmDelivery() buyerOnly inState(State.AWAITING_DELIVERY) {
        buyer.transfer(price);
        seller.transfer(price * 2);
        currentState = State.COMPLETE;
    }
}

pragma solidity ^0.4.21;

/*
Simple escrow contract that mediates disputes using a burn contract
*/
contract Escrow {

    enum State {UNINITIATED, AWAITING_PAYMENT, AWAITING_DELIVERY, COMPLETE}
    State public currentState;

    modifier inState(State expectedState) { require(currentState == expectedState); _; }
    modifier buyerOnly() { require(msg.sender == buyer); _; }
    modifier correctPrice() { require(msg.value == price); _; }

    address public buyer;
    address public seller;

    bool public buyer_in;
    bool public seller_in;

    uint public price;

    function Escrow(address _buyer, address _seller, uint _price){
        buyer = _buyer;
        seller = _seller;
        price = _price;
    }

    function initiateContract() correctPrice inState(State.UNINITIATED) payable {
        if (msg.sender == buyer) {
            buyer_in = true;
        }
        if (msg.sender == seller) {
            seller_in = true;
        }
        if (buyer_in && seller_in) {
            currentState = State.AWAITING_PAYMENT;
        }
    }

    function confirmPayment() buyerOnly correctPrice inState(State.AWAITING_PAYMENT) payable {
        currentState = State.AWAITING_DELIVERY;
    }

    function confirmDelivery() buyerOnly inState(State.AWAITING_DELIVERY) {
        buyer.send(price);
        seller.send(price * 2);
        currentState = State.COMPLETE;
    }
}