ETH_NODE and ROOT_NODE constants can be private

pragma solidity ^0.8.4;

import "./ERC1155Fuse.sol";
import "../interfaces/INameWrapper.sol";
import "../interfaces/IMetadataService.sol";
import "@ensdomains/ens-contracts/contracts/registry/ENS.sol";
import "@ensdomains/ens-contracts/contracts/ethregistrar/BaseRegistrar.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./BytesUtil.sol";
import "hardhat/console.sol";

contract NameWrapper is Ownable, ERC1155Fuse, INameWrapper {
    using BytesUtils for bytes;
    ENS public immutable ens;
    BaseRegistrar public immutable registrar;
    IMetadataService public metadataService;
    bytes4 private constant ERC721_RECEIVED = 0x150b7a02;

    bytes32 private constant ETH_NODE =
        0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae;
    bytes32 private constant ROOT_NODE =
        0x0000000000000000000000000000000000000000000000000000000000000000;

    constructor(
        ENS _ens,
        BaseRegistrar _registrar,
        IMetadataService _metadataService
    ) {
        ens = _ens;
        registrar = _registrar;
        metadataService = _metadataService;

        /* Burn CANNOT_REPLACE_SUBDOMAIN and CANNOT_UNWRAP fuses for ROOT_NODE and ETH_NODE */

        _setData(
            uint256(ETH_NODE),
            address(0x0),
            uint96(CANNOT_REPLACE_SUBDOMAIN | CANNOT_UNWRAP)
        );
        _setData(
            uint256(ROOT_NODE),
            address(0x0),
            uint96(CANNOT_REPLACE_SUBDOMAIN | CANNOT_UNWRAP)
        );
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(ERC1155Fuse, IERC165)
        returns (bool)
    {
        return
            interfaceId == type(INameWrapper).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /* Metadata service */

    /**
     * @notice Set the metadata service. only admin can do this
     */

    function setMetadataService(IMetadataService _newMetadataService)
        public
        onlyOwner()
    {
        metadataService = _newMetadataService;
    }

    /**
     * @notice Get the metadata uri
     * @return String uri of the metadata service
     */

    function uri(uint256 tokenId) public view override returns (string memory) {
        return metadataService.uri(tokenId);
    }

    /**
     * @notice Checks if msg.sender is the owner or approved by the owner of a name
     * @param node namehash of the name to check
     */

    modifier onlyTokenOwner(bytes32 node) {
        require(
            isTokenOwnerOrApproved(node, msg.sender),
            "NameWrapper: msg.sender is not the owner or approved"
        );
        _;
    }

    /**
     * @notice Checks if owner or approved by owner
     * @param node namehash of the name to check
     * @param addr which address to check permissions for
     * @return whether or not is owner or approved
     */

    function isTokenOwnerOrApproved(bytes32 node, address addr)
        public
        view
        override
        returns (bool)
    {
        return
            ownerOf(uint256(node)) == addr ||
            isApprovedForAll(ownerOf(uint256(node)), addr);
    }

    /**
     * @notice Gets fuse permissions for a specific name
     * @dev Fuses are represented by a uint96 where each permission is represented by 1 bit
     *      The interface has predefined fuses for all registry permissions, but additional
     *      fuses can be added for other use cases
     * @param node namehash of the name to check
     * @return A number that represents the permissions a name has
     */

    function getFuses(bytes32 node) public view override returns (uint96) {
        (, uint96 fuses) = getData(uint256(node));
        return fuses;
    }

    /**
     * @notice Check whether a name can be unwrapped
     *
     * @param node namehash of the name to check
     * @return Boolean of whether or not can be wrapped
     */

    function canUnwrap(bytes32 node) public view override returns (bool) {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_UNWRAP == 0;
    }

    /**
     * @notice Check whether a name can burn fuses
     *
     * @param node namehash of the name to check
     * @return Boolean of whether or not can burn fuses
     */

    function canBurnFuses(bytes32 node) public view override returns (bool) {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_BURN_FUSES == 0;
    }

    /**
     * @notice Check whether a name can be transferred
     *
     * @param node namehash of the name to check
     * @return Boolean of whether or not can be transferred
     */

    function canTransfer(bytes32 node) public view override returns (bool) {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_TRANSFER == 0;
    }

    /**
     * @notice Check whether a name can set the resolver
     *
     * @param node namehash of the name to check
     * @return Boolean of whether or not resolver can be set
     */

    function canSetResolver(bytes32 node) public view override returns (bool) {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_SET_RESOLVER == 0;
    }

    /**
     * @notice Check whether a name can set the TTL
     *
     * @param node namehash of the name to check
     * @return Boolean of whether or not TTL can be set
     */

    function canSetTTL(bytes32 node) public view override returns (bool) {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_SET_TTL == 0;
    }

    /**
     * @notice Check whether a name can create a subdomain
     * @dev Creating a subdomain is defined as a subdomain that has a 0x0 owner and a new owner is set
     * @param node namehash of the name to check
     * @return Boolean of whether or not subdomains can be created
     */

    function canCreateSubdomain(bytes32 node)
        public
        view
        override
        returns (bool)
    {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_CREATE_SUBDOMAIN == 0;
    }

    /**
     * @notice Check whether a name can replace a subdomain
     * @dev Replacing a subdomain is defined as a subdomain that has an existing owner and is overwritten
     * @param node namehash of the name to check
     * @return Boolean of whether or not TTL can be set
     */

    function canReplaceSubdomain(bytes32 node)
        public
        view
        override
        returns (bool)
    {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_REPLACE_SUBDOMAIN == 0;
    }

    /**
     * @notice Check whether a name can call setSubnodeOwner/setSubnodeRecord
     * @dev Checks both canCreateSubdomain and canReplaceSubdomain and whether not they have been burnt
     *      and checks whether the owner of the subdomain is 0x0 for creating or already exists for
     *      replacing a subdomain. If either conditions are true, then it is possible to call
     *      setSubnodeOwner
     * @param node namehash of the name to check
     * @param label labelhash of the name to check
     * @return Boolean of whether or not setSubnodeOwner/setSubnodeRecord can be called
     */

    function canCallSetSubnodeOwner(bytes32 node, bytes32 label)
        public
        view
        returns (bool)
    {
        bytes32 subnode = _makeNode(node, label);
        address owner = ens.owner(subnode);

        return
            (owner == address(0) && canCreateSubdomain(node)) ||
            (owner != address(0) && canReplaceSubdomain(node));
    }

    /**
     * @notice Wraps a .eth domain, creating a new token and sending the original ERC721 token to this *         contract
     * @dev Can be called by the owner of the name in the .eth registrar or an authorised caller on the *      registrar
     * @param label label as a string of the .eth domain to wrap
     * @param _fuses initial fuses to set
     * @param wrappedOwner Owner of the name in this contract
     */

    function wrapETH2LD(
        string calldata label,
        address wrappedOwner,
        uint96 _fuses
    ) public override {
        bytes32 labelhash = keccak256(bytes(label));
        bytes32 node = _makeNode(ETH_NODE, labelhash);
        uint256 tokenId = uint256(labelhash);
        address owner = registrar.ownerOf(tokenId);

        require(
            owner == msg.sender ||
                registrar.isApprovedForAll(owner, msg.sender) ||
                isApprovedForAll(owner, msg.sender),
            "NameWrapper: Sender is not owner or authorised by the owner or authorised on the .eth registrar"
        );
        // transfer the token from the user to this contract
        address currentOwner = registrar.ownerOf(tokenId);
        registrar.transferFrom(currentOwner, address(this), tokenId);

        // transfer the ens record back to the new owner (this contract)
        _wrapETH2LD(labelhash, node, wrappedOwner, _fuses);
    }

    /**
     * @notice Wraps a non .eth domain, of any kind. Could be a DNSSEC name vitalik.xyz or a subdomain
     * @dev Can be called by the owner in the registry or an authorised caller in the registry
     * @param parentNode parent namehash of the name to wrap e.g. vitalik.xyz would be namehash('xyz')
     * @param label label as a string of the .eth domain to wrap e.g. vitalik.xyz would be 'vitalik'
     * @param _fuses initial fuses to set represented as a number. Check getFuses() for more info
     * @param wrappedOwner Owner of the name in this contract
     */

    function wrap(
        bytes32 parentNode,
        string calldata label,
        address wrappedOwner,
        uint96 _fuses
    ) public override {
        bytes32 labelhash = keccak256(bytes(label));
        bytes32 node = _makeNode(parentNode, labelhash);
        _wrap(parentNode, labelhash, wrappedOwner, _fuses);
        address owner = ens.owner(node);

        require(
            owner == msg.sender ||
                ens.isApprovedForAll(owner, msg.sender) ||
                isApprovedForAll(owner, msg.sender),
            "NameWrapper: Domain is not owned by the sender"
        );
        ens.setOwner(node, address(this));
        emit Wrap(parentNode, label, wrappedOwner, _fuses);
    }

    /**
     * @notice Unwraps a .eth domain. e.g. vitalik.eth
     * @dev Can be called by the owner in the wrapper or an authorised caller in the wrapper
     * @param label label as a string of the .eth domain to wrap e.g. vitalik.xyz would be 'vitalik'
     * @param newRegistrant sets the owner in the .eth registrar to this address
     * @param newController sets the owner in the registry to this address
     */

    function unwrapETH2LD(
        bytes32 label,
        address newRegistrant,
        address newController
    ) public override onlyTokenOwner(_makeNode(ETH_NODE, label)) {
        _unwrap(ETH_NODE, label, newController);
        registrar.transferFrom(address(this), newRegistrant, uint256(label));
        emit UnwrapETH2LD(label, newRegistrant, newController);
    }

    /**
     * @notice Unwraps a non .eth domain, of any kind. Could be a DNSSEC name vitalik.xyz or a subdomain
     * @dev Can be called by the owner in the wrapper or an authorised caller in the wrapper
     * @param parentNode parent namehash of the name to wrap e.g. vitalik.xyz would be namehash('xyz')
     * @param label label as a string of the .eth domain to wrap e.g. vitalik.xyz would be 'vitalik'
     * @param newController sets the owner in the registry to this address
     */

    function unwrap(
        bytes32 parentNode,
        bytes32 label,
        address newController
    ) public override onlyTokenOwner(_makeNode(parentNode, label)) {
        require(
            parentNode != ETH_NODE,
            "NameWrapper: .eth names must be unwrapped with unwrapETH2LD()"
        );
        _unwrap(parentNode, label, newController);
        emit Unwrap(parentNode, label, newController);
    }

    /**
     * @notice Burns any fuse passed to this function for a name
     * @dev Fuse burns are always additive and will not unburn already burnt fuses
     * @param parentNode parent namehash of the name. e.g. vitalik.xyz would be namehash('xyz')
     * @param labelhash labelhash of the name. e.g. vitalik.xyz would be labelhash('vitalik')
     * @param _fuses Fuses you want to burn.
     */

    function burnFuses(
        bytes32 parentNode,
        bytes32 labelhash,
        uint96 _fuses
    ) public onlyTokenOwner(_makeNode(parentNode, labelhash)) {
        bytes32 node = _makeNode(parentNode, labelhash);

        require(
            canBurnFuses(node),
            "NameWrapper: Fuse has been burned for burning fuses"
        );

        require(
            !canReplaceSubdomain(parentNode),
            "NameWrapper: Parent has not burned CAN_REPLACE_SUBDOMAIN fuse"
        );

        (address owner, uint96 fuses) = getData(uint256(node));

        uint96 newFuses = fuses | _fuses;

        _setData(uint256(node), owner, newFuses);

        require(
            !canUnwrap(node),
            "NameWrapper: Domain has not burned unwrap fuse"
        );

        emit BurnFuses(node, newFuses);
    }

    /**
     * @notice Sets records for the subdomain in the ENS Registry
     * @param node namehash of the name
     * @param owner newOwner in the registry
     * @param resolver the resolver contract in the registry
     * @param ttl ttl in the registry
     */

    function setSubnodeRecord(
        bytes32 node,
        bytes32 label,
        address owner,
        address resolver,
        uint64 ttl
    ) public onlyTokenOwner(node) {
        require(
            canCallSetSubnodeOwner(node, label),
            "NameWrapper: Fuse has been burned for creating or replacing a subdomain"
        );

        return ens.setSubnodeRecord(node, label, owner, resolver, ttl);
    }

    /**
     * @notice Sets the subnode owner in the registry
     * @param node parent namehash of the subnode
     * @param label labelhash of the subnode
     * @param owner newOwner in the registry
     */

    function setSubnodeOwner(
        bytes32 node,
        bytes32 label,
        address owner
    ) public override onlyTokenOwner(node) returns (bytes32) {
        require(
            canCallSetSubnodeOwner(node, label),
            "NameWrapper: Fuse has been burned for creating or replacing a subdomain"
        );

        return ens.setSubnodeOwner(node, label, owner);
    }

    /**
     * @notice Sets the subdomain owner in the registry and then wraps the subdomain
     * @param parentNode parent namehash of the subdomain
     * @param label label of the subdomain as a string
     * @param newOwner newOwner in the registry
     * @param _fuses initial fuses for the wrapped subdomain
     */

    function setSubnodeOwnerAndWrap(
        bytes32 parentNode,
        string calldata label,
        address newOwner,
        uint96 _fuses
    ) public override returns (bytes32 node) {
        bytes32 labelhash = keccak256(bytes(label));
        node = setSubnodeOwner(parentNode, labelhash, address(this));
        _wrap(parentNode, labelhash, newOwner, _fuses);
        emit Wrap(parentNode, label, newOwner, _fuses);
    }

    /**
     * @notice Sets the subdomain owner in the registry with records and then wraps the subdomain
     * @param parentNode parent namehash of the subdomain
     * @param label label of the subdomain as a string
     * @param newOwner newOwner in the registry
     * @param resolver resolver contract in the registry
     * @param ttl ttl in the regsitry
     * @param _fuses initial fuses for the wrapped subdomain
     */

    function setSubnodeRecordAndWrap(
        bytes32 parentNode,
        string calldata label,
        address newOwner,
        address resolver,
        uint64 ttl,
        uint96 _fuses
    ) public override returns (bytes32 node) {
        bytes32 labelhash = keccak256(bytes(label));
        node = setSubnodeRecord(parentNode, labelhash, address(this), resolver, ttl);
        _wrap(parentNode, labelhash, newOwner, _fuses);
        emit Wrap(parentNode, label, newOwner, _fuses);
    }

    /**
     * @notice Sets records for the name in the ENS Registry
     * @param node namehash of the name to set a record for
     * @param owner newOwner in the registry
     * @param resolver the resolver contract
     * @param ttl ttl in the registry
     */

    function setRecord(
        bytes32 node,
        address owner,
        address resolver,
        uint64 ttl
    ) public onlyTokenOwner(node) {
        require(
            canTransfer(node),
            "NameWrapper: Fuse is burned for transferring"
        );

        require(
            canSetResolver(node),
            "NameWrapper: Fuse is burned for setting resolver"
        );

        require(canSetTTL(node), "NameWrapper: Fuse is burned for setting TTL");
        ens.setRecord(node, owner, resolver, ttl);
    }

    /**
     * @notice Sets resolver contract in the registry
     * @param node namehash of the name
     * @param resolver the resolver contract
     */

    function setResolver(bytes32 node, address resolver)
        public
        override
        onlyTokenOwner(node)
    {
        require(
            canSetResolver(node),
            "NameWrapper: Fuse already burned for setting resolver"
        );
        ens.setResolver(node, resolver);
    }

    /**
     * @notice Sets TTL in the registry
     * @param node namehash of the name
     * @param ttl TTL in the registry
     */

    function setTTL(bytes32 node, uint64 ttl)
        public
        override
        onlyTokenOwner(node)
    {
        require(
            canSetTTL(node),
            "NameWrapper: Fuse already burned for setting TTL"
        );
        ens.setTTL(node, ttl);
    }

    /**
     * @notice Sets TTL in the registry
     * @dev only callable by the .eth registrar
     * @param operator sender of the tx, either owner or approved caller
     * @param from owner of the token previously
     * @param tokenId namehash of the name
     * @param data data represents the fuses that will be passed when calling transferFrom on the
     *             .eth registrar
     */

    function onERC721Received(
        address,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) public returns (bytes4) {
        //check if it's the eth registrar ERC721
        uint96 fuses = 0;
        require(
            msg.sender == address(registrar),
            "NameWrapper: Wrapper only supports .eth ERC721 token transfers"
        );

        require(
            data.length == 0 || data.length == 12,
            "NameWrapper: Data is not of length 0 or 12"
        );

        if (data.length == 12) {
            fuses = data.readUint96(0);
        }

        bytes32 node = _makeNode(ETH_NODE, bytes32(tokenId));
        _wrapETH2LD(bytes32(tokenId), node, from, fuses);
        emit WrapETH2LD(bytes32(tokenId), from, fuses);
        return ERC721_RECEIVED;
    }

    /***** Internal functions */

    function _canTransfer(uint96 fuses) internal pure override returns (bool) {
        return fuses & CANNOT_TRANSFER == 0;
    }

    function _makeNode(bytes32 node, bytes32 label)
        private
        pure
        returns (bytes32)
    {
        return keccak256(abi.encodePacked(node, label));
    }

    function _mint(
        bytes32 parentNode,
        bytes32 node,
        address newOwner,
        uint96 _fuses
    ) private {
        uint256 tokenId = uint256(node);
        address owner = ownerOf(tokenId);
        require(owner == address(0), "ERC1155: mint of existing token");
        require(newOwner != address(0), "ERC1155: mint to the zero address");
        require(
            newOwner != address(this),
            "NameWrapper: newOwner cannot be the NameWrapper contract"
        );
        _setData(tokenId, newOwner, _fuses);

        if (_fuses != CAN_DO_EVERYTHING) {
            require(
                !canReplaceSubdomain(parentNode),
                "NameWrapper: Cannot burn fuses: parent name can replace subdomain"
            );

            require(
                !canUnwrap(node),
                "NameWrapper: Cannot burn fuses: domain can be unwrapped"
            );
        }
        emit TransferSingle(msg.sender, address(0x0), newOwner, tokenId, 1);
    }

    function _burn(uint256 tokenId) private {
        address owner = ownerOf(tokenId);
        // Clear fuses and set owner to 0
        _setData(tokenId, address(0x0), 0);
        emit TransferSingle(msg.sender, owner, address(0x0), tokenId, 1);
    }

    function _wrap(
        bytes32 parentNode,
        bytes32 label,
        address wrappedOwner,
        uint96 _fuses
    ) private {
        require(
            parentNode != ETH_NODE,
            "NameWrapper: .eth domains need to use wrapETH2LD()"
        );

        bytes32 node = _makeNode(parentNode, label);

        _mint(parentNode, node, wrappedOwner, _fuses);
    }

    function _wrapETH2LD(
        bytes32 label,
        bytes32 node,
        address wrappedOwner,
        uint96 _fuses
    ) private {
        // transfer the ens record back to the new owner (this contract)
        registrar.reclaim(uint256(label), address(this));
        // mint a new ERC1155 token with fuses

        address oldWrappedOwner = ownerOf(uint256(node));
        if (oldWrappedOwner != address(0)) {
            _burn(uint256(node));
            emit UnwrapETH2LD(label, address(0), address(0));
        }
        _mint(ETH_NODE, node, wrappedOwner, _fuses);

        emit WrapETH2LD(label, wrappedOwner, _fuses);
    }

    function _unwrap(
        bytes32 parentNode,
        bytes32 label,
        address newOwner
    ) private {
        bytes32 node = _makeNode(parentNode, label);
        require(
            newOwner != address(0x0),
            "NameWrapper: Target owner cannot be 0x0"
        );
        require(
            newOwner != address(this),
            "NameWrapper: Target owner cannot be the NameWrapper contract"
        );
        require(canUnwrap(node), "NameWrapper: Domain is not unwrappable");

        // burn token and fuse data
        _burn(uint256(node));
        ens.setOwner(node, newOwner);
    }
}

pragma solidity ^0.8.4;

import "./ERC1155Fuse.sol";
import "../interfaces/INameWrapper.sol";
import "../interfaces/IMetadataService.sol";
import "@ensdomains/ens-contracts/contracts/registry/ENS.sol";
import "@ensdomains/ens-contracts/contracts/ethregistrar/BaseRegistrar.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./BytesUtil.sol";
import "hardhat/console.sol";

contract NameWrapper is Ownable, ERC1155Fuse, INameWrapper {
    using BytesUtils for bytes;
    ENS public immutable ens;
    BaseRegistrar public immutable registrar;
    IMetadataService public metadataService;
    bytes4 private constant ERC721_RECEIVED = 0x150b7a02;

    bytes32 public constant ETH_NODE =
        0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae;
    bytes32 public constant ROOT_NODE =
        0x0000000000000000000000000000000000000000000000000000000000000000;

    constructor(
        ENS _ens,
        BaseRegistrar _registrar,
        IMetadataService _metadataService
    ) {
        ens = _ens;
        registrar = _registrar;
        metadataService = _metadataService;

        /* Burn CANNOT_REPLACE_SUBDOMAIN and CANNOT_UNWRAP fuses for ROOT_NODE and ETH_NODE */

        _setData(
            uint256(ETH_NODE),
            address(0x0),
            uint96(CANNOT_REPLACE_SUBDOMAIN | CANNOT_UNWRAP)
        );
        _setData(
            uint256(ROOT_NODE),
            address(0x0),
            uint96(CANNOT_REPLACE_SUBDOMAIN | CANNOT_UNWRAP)
        );
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(ERC1155Fuse, IERC165)
        returns (bool)
    {
        return
            interfaceId == type(INameWrapper).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /* Metadata service */

    /**
     * @notice Set the metadata service. only admin can do this
     */

    function setMetadataService(IMetadataService _newMetadataService)
        public
        onlyOwner()
    {
        metadataService = _newMetadataService;
    }

    /**
     * @notice Get the metadata uri
     * @return String uri of the metadata service
     */

    function uri(uint256 tokenId) public view override returns (string memory) {
        return metadataService.uri(tokenId);
    }

    /**
     * @notice Checks if msg.sender is the owner or approved by the owner of a name
     * @param node namehash of the name to check
     */

    modifier onlyTokenOwner(bytes32 node) {
        require(
            isTokenOwnerOrApproved(node, msg.sender),
            "NameWrapper: msg.sender is not the owner or approved"
        );
        _;
    }

    /**
     * @notice Checks if owner or approved by owner
     * @param node namehash of the name to check
     * @param addr which address to check permissions for
     * @return whether or not is owner or approved
     */

    function isTokenOwnerOrApproved(bytes32 node, address addr)
        public
        view
        override
        returns (bool)
    {
        return
            ownerOf(uint256(node)) == addr ||
            isApprovedForAll(ownerOf(uint256(node)), addr);
    }

    /**
     * @notice Gets fuse permissions for a specific name
     * @dev Fuses are represented by a uint96 where each permission is represented by 1 bit
     *      The interface has predefined fuses for all registry permissions, but additional
     *      fuses can be added for other use cases
     * @param node namehash of the name to check
     * @return A number that represents the permissions a name has
     */

    function getFuses(bytes32 node) public view override returns (uint96) {
        (, uint96 fuses) = getData(uint256(node));
        return fuses;
    }

    /**
     * @notice Check whether a name can be unwrapped
     *
     * @param node namehash of the name to check
     * @return Boolean of whether or not can be wrapped
     */

    function canUnwrap(bytes32 node) public view override returns (bool) {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_UNWRAP == 0;
    }

    /**
     * @notice Check whether a name can burn fuses
     *
     * @param node namehash of the name to check
     * @return Boolean of whether or not can burn fuses
     */

    function canBurnFuses(bytes32 node) public view override returns (bool) {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_BURN_FUSES == 0;
    }

    /**
     * @notice Check whether a name can be transferred
     *
     * @param node namehash of the name to check
     * @return Boolean of whether or not can be transferred
     */

    function canTransfer(bytes32 node) public view override returns (bool) {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_TRANSFER == 0;
    }

    /**
     * @notice Check whether a name can set the resolver
     *
     * @param node namehash of the name to check
     * @return Boolean of whether or not resolver can be set
     */

    function canSetResolver(bytes32 node) public view override returns (bool) {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_SET_RESOLVER == 0;
    }

    /**
     * @notice Check whether a name can set the TTL
     *
     * @param node namehash of the name to check
     * @return Boolean of whether or not TTL can be set
     */

    function canSetTTL(bytes32 node) public view override returns (bool) {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_SET_TTL == 0;
    }

    /**
     * @notice Check whether a name can create a subdomain
     * @dev Creating a subdomain is defined as a subdomain that has a 0x0 owner and a new owner is set
     * @param node namehash of the name to check
     * @return Boolean of whether or not subdomains can be created
     */

    function canCreateSubdomain(bytes32 node)
        public
        view
        override
        returns (bool)
    {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_CREATE_SUBDOMAIN == 0;
    }

    /**
     * @notice Check whether a name can replace a subdomain
     * @dev Replacing a subdomain is defined as a subdomain that has an existing owner and is overwritten
     * @param node namehash of the name to check
     * @return Boolean of whether or not TTL can be set
     */

    function canReplaceSubdomain(bytes32 node)
        public
        view
        override
        returns (bool)
    {
        uint96 fuses = getFuses(node);
        return fuses & CANNOT_REPLACE_SUBDOMAIN == 0;
    }

    /**
     * @notice Check whether a name can call setSubnodeOwner/setSubnodeRecord
     * @dev Checks both canCreateSubdomain and canReplaceSubdomain and whether not they have been burnt
     *      and checks whether the owner of the subdomain is 0x0 for creating or already exists for
     *      replacing a subdomain. If either conditions are true, then it is possible to call
     *      setSubnodeOwner
     * @param node namehash of the name to check
     * @param label labelhash of the name to check
     * @return Boolean of whether or not setSubnodeOwner/setSubnodeRecord can be called
     */

    function canCallSetSubnodeOwner(bytes32 node, bytes32 label)
        public
        view
        returns (bool)
    {
        bytes32 subnode = _makeNode(node, label);
        address owner = ens.owner(subnode);

        return
            (owner == address(0) && canCreateSubdomain(node)) ||
            (owner != address(0) && canReplaceSubdomain(node));
    }

    /**
     * @notice Wraps a .eth domain, creating a new token and sending the original ERC721 token to this *         contract
     * @dev Can be called by the owner of the name in the .eth registrar or an authorised caller on the *      registrar
     * @param label label as a string of the .eth domain to wrap
     * @param _fuses initial fuses to set
     * @param wrappedOwner Owner of the name in this contract
     */

    function wrapETH2LD(
        string calldata label,
        address wrappedOwner,
        uint96 _fuses
    ) public override {
        bytes32 labelhash = keccak256(bytes(label));
        bytes32 node = _makeNode(ETH_NODE, labelhash);
        uint256 tokenId = uint256(labelhash);
        address owner = registrar.ownerOf(tokenId);

        require(
            owner == msg.sender ||
                registrar.isApprovedForAll(owner, msg.sender) ||
                isApprovedForAll(owner, msg.sender),
            "NameWrapper: Sender is not owner or authorised by the owner or authorised on the .eth registrar"
        );
        // transfer the token from the user to this contract
        address currentOwner = registrar.ownerOf(tokenId);
        registrar.transferFrom(currentOwner, address(this), tokenId);

        // transfer the ens record back to the new owner (this contract)
        _wrapETH2LD(labelhash, node, wrappedOwner, _fuses);
    }

    /**
     * @notice Wraps a non .eth domain, of any kind. Could be a DNSSEC name vitalik.xyz or a subdomain
     * @dev Can be called by the owner in the registry or an authorised caller in the registry
     * @param parentNode parent namehash of the name to wrap e.g. vitalik.xyz would be namehash('xyz')
     * @param label label as a string of the .eth domain to wrap e.g. vitalik.xyz would be 'vitalik'
     * @param _fuses initial fuses to set represented as a number. Check getFuses() for more info
     * @param wrappedOwner Owner of the name in this contract
     */

    function wrap(
        bytes32 parentNode,
        string calldata label,
        address wrappedOwner,
        uint96 _fuses
    ) public override {
        bytes32 labelhash = keccak256(bytes(label));
        bytes32 node = _makeNode(parentNode, labelhash);
        _wrap(parentNode, labelhash, wrappedOwner, _fuses);
        address owner = ens.owner(node);

        require(
            owner == msg.sender ||
                ens.isApprovedForAll(owner, msg.sender) ||
                isApprovedForAll(owner, msg.sender),
            "NameWrapper: Domain is not owned by the sender"
        );
        ens.setOwner(node, address(this));
        emit Wrap(parentNode, label, wrappedOwner, _fuses);
    }

    /**
     * @notice Unwraps a .eth domain. e.g. vitalik.eth
     * @dev Can be called by the owner in the wrapper or an authorised caller in the wrapper
     * @param label label as a string of the .eth domain to wrap e.g. vitalik.xyz would be 'vitalik'
     * @param newRegistrant sets the owner in the .eth registrar to this address
     * @param newController sets the owner in the registry to this address
     */

    function unwrapETH2LD(
        bytes32 label,
        address newRegistrant,
        address newController
    ) public override onlyTokenOwner(_makeNode(ETH_NODE, label)) {
        _unwrap(ETH_NODE, label, newController);
        registrar.transferFrom(address(this), newRegistrant, uint256(label));
        emit UnwrapETH2LD(label, newRegistrant, newController);
    }

    /**
     * @notice Unwraps a non .eth domain, of any kind. Could be a DNSSEC name vitalik.xyz or a subdomain
     * @dev Can be called by the owner in the wrapper or an authorised caller in the wrapper
     * @param parentNode parent namehash of the name to wrap e.g. vitalik.xyz would be namehash('xyz')
     * @param label label as a string of the .eth domain to wrap e.g. vitalik.xyz would be 'vitalik'
     * @param newController sets the owner in the registry to this address
     */

    function unwrap(
        bytes32 parentNode,
        bytes32 label,
        address newController
    ) public override onlyTokenOwner(_makeNode(parentNode, label)) {
        require(
            parentNode != ETH_NODE,
            "NameWrapper: .eth names must be unwrapped with unwrapETH2LD()"
        );
        _unwrap(parentNode, label, newController);
        emit Unwrap(parentNode, label, newController);
    }

    /**
     * @notice Burns any fuse passed to this function for a name
     * @dev Fuse burns are always additive and will not unburn already burnt fuses
     * @param parentNode parent namehash of the name. e.g. vitalik.xyz would be namehash('xyz')
     * @param labelhash labelhash of the name. e.g. vitalik.xyz would be labelhash('vitalik')
     * @param _fuses Fuses you want to burn.
     */

    function burnFuses(
        bytes32 parentNode,
        bytes32 labelhash,
        uint96 _fuses
    ) public onlyTokenOwner(_makeNode(parentNode, labelhash)) {
        bytes32 node = _makeNode(parentNode, labelhash);

        require(
            canBurnFuses(node),
            "NameWrapper: Fuse has been burned for burning fuses"
        );

        require(
            !canReplaceSubdomain(parentNode),
            "NameWrapper: Parent has not burned CAN_REPLACE_SUBDOMAIN fuse"
        );

        (address owner, uint96 fuses) = getData(uint256(node));

        uint96 newFuses = fuses | _fuses;

        _setData(uint256(node), owner, newFuses);

        require(
            !canUnwrap(node),
            "NameWrapper: Domain has not burned unwrap fuse"
        );

        emit BurnFuses(node, newFuses);
    }

    /**
     * @notice Sets records for the subdomain in the ENS Registry
     * @param node namehash of the name
     * @param owner newOwner in the registry
     * @param resolver the resolver contract in the registry
     * @param ttl ttl in the registry
     */

    function setSubnodeRecord(
        bytes32 node,
        bytes32 label,
        address owner,
        address resolver,
        uint64 ttl
    ) public onlyTokenOwner(node) {
        require(
            canCallSetSubnodeOwner(node, label),
            "NameWrapper: Fuse has been burned for creating or replacing a subdomain"
        );

        return ens.setSubnodeRecord(node, label, owner, resolver, ttl);
    }

    /**
     * @notice Sets the subnode owner in the registry
     * @param node parent namehash of the subnode
     * @param label labelhash of the subnode
     * @param owner newOwner in the registry
     */

    function setSubnodeOwner(
        bytes32 node,
        bytes32 label,
        address owner
    ) public override onlyTokenOwner(node) returns (bytes32) {
        require(
            canCallSetSubnodeOwner(node, label),
            "NameWrapper: Fuse has been burned for creating or replacing a subdomain"
        );

        return ens.setSubnodeOwner(node, label, owner);
    }

    /**
     * @notice Sets the subdomain owner in the registry and then wraps the subdomain
     * @param parentNode parent namehash of the subdomain
     * @param label label of the subdomain as a string
     * @param newOwner newOwner in the registry
     * @param _fuses initial fuses for the wrapped subdomain
     */

    function setSubnodeOwnerAndWrap(
        bytes32 parentNode,
        string calldata label,
        address newOwner,
        uint96 _fuses
    ) public override returns (bytes32 node) {
        bytes32 labelhash = keccak256(bytes(label));
        node = setSubnodeOwner(parentNode, labelhash, address(this));
        _wrap(parentNode, labelhash, newOwner, _fuses);
        emit Wrap(parentNode, label, newOwner, _fuses);
    }

    /**
     * @notice Sets the subdomain owner in the registry with records and then wraps the subdomain
     * @param parentNode parent namehash of the subdomain
     * @param label label of the subdomain as a string
     * @param newOwner newOwner in the registry
     * @param resolver resolver contract in the registry
     * @param ttl ttl in the regsitry
     * @param _fuses initial fuses for the wrapped subdomain
     */

    function setSubnodeRecordAndWrap(
        bytes32 parentNode,
        string calldata label,
        address newOwner,
        address resolver,
        uint64 ttl,
        uint96 _fuses
    ) public override returns (bytes32 node) {
        bytes32 labelhash = keccak256(bytes(label));
        node = setSubnodeRecord(parentNode, labelhash, address(this), resolver, ttl);
        _wrap(parentNode, labelhash, newOwner, _fuses);
        emit Wrap(parentNode, label, newOwner, _fuses);
    }

    /**
     * @notice Sets records for the name in the ENS Registry
     * @param node namehash of the name to set a record for
     * @param owner newOwner in the registry
     * @param resolver the resolver contract
     * @param ttl ttl in the registry
     */

    function setRecord(
        bytes32 node,
        address owner,
        address resolver,
        uint64 ttl
    ) public onlyTokenOwner(node) {
        require(
            canTransfer(node),
            "NameWrapper: Fuse is burned for transferring"
        );

        require(
            canSetResolver(node),
            "NameWrapper: Fuse is burned for setting resolver"
        );

        require(canSetTTL(node), "NameWrapper: Fuse is burned for setting TTL");
        ens.setRecord(node, owner, resolver, ttl);
    }

    /**
     * @notice Sets resolver contract in the registry
     * @param node namehash of the name
     * @param resolver the resolver contract
     */

    function setResolver(bytes32 node, address resolver)
        public
        override
        onlyTokenOwner(node)
    {
        require(
            canSetResolver(node),
            "NameWrapper: Fuse already burned for setting resolver"
        );
        ens.setResolver(node, resolver);
    }

    /**
     * @notice Sets TTL in the registry
     * @param node namehash of the name
     * @param ttl TTL in the registry
     */

    function setTTL(bytes32 node, uint64 ttl)
        public
        override
        onlyTokenOwner(node)
    {
        require(
            canSetTTL(node),
            "NameWrapper: Fuse already burned for setting TTL"
        );
        ens.setTTL(node, ttl);
    }

    /**
     * @notice Sets TTL in the registry
     * @dev only callable by the .eth registrar
     * @param operator sender of the tx, either owner or approved caller
     * @param from owner of the token previously
     * @param tokenId namehash of the name
     * @param data data represents the fuses that will be passed when calling transferFrom on the
     *             .eth registrar
     */

    function onERC721Received(
        address,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) public returns (bytes4) {
        //check if it's the eth registrar ERC721
        uint96 fuses = 0;
        require(
            msg.sender == address(registrar),
            "NameWrapper: Wrapper only supports .eth ERC721 token transfers"
        );

        require(
            data.length == 0 || data.length == 12,
            "NameWrapper: Data is not of length 0 or 12"
        );

        if (data.length == 12) {
            fuses = data.readUint96(0);
        }

        bytes32 node = _makeNode(ETH_NODE, bytes32(tokenId));
        _wrapETH2LD(bytes32(tokenId), node, from, fuses);
        emit WrapETH2LD(bytes32(tokenId), from, fuses);
        return ERC721_RECEIVED;
    }

    /***** Internal functions */

    function _canTransfer(uint96 fuses) internal pure override returns (bool) {
        return fuses & CANNOT_TRANSFER == 0;
    }

    function _makeNode(bytes32 node, bytes32 label)
        private
        pure
        returns (bytes32)
    {
        return keccak256(abi.encodePacked(node, label));
    }

    function _mint(
        bytes32 parentNode,
        bytes32 node,
        address newOwner,
        uint96 _fuses
    ) private {
        uint256 tokenId = uint256(node);
        address owner = ownerOf(tokenId);
        require(owner == address(0), "ERC1155: mint of existing token");
        require(newOwner != address(0), "ERC1155: mint to the zero address");
        require(
            newOwner != address(this),
            "NameWrapper: newOwner cannot be the NameWrapper contract"
        );
        _setData(tokenId, newOwner, _fuses);

        if (_fuses != CAN_DO_EVERYTHING) {
            require(
                !canReplaceSubdomain(parentNode),
                "NameWrapper: Cannot burn fuses: parent name can replace subdomain"
            );

            require(
                !canUnwrap(node),
                "NameWrapper: Cannot burn fuses: domain can be unwrapped"
            );
        }
        emit TransferSingle(msg.sender, address(0x0), newOwner, tokenId, 1);
    }

    function _burn(uint256 tokenId) private {
        address owner = ownerOf(tokenId);
        // Clear fuses and set owner to 0
        _setData(tokenId, address(0x0), 0);
        emit TransferSingle(msg.sender, owner, address(0x0), tokenId, 1);
    }

    function _wrap(
        bytes32 parentNode,
        bytes32 label,
        address wrappedOwner,
        uint96 _fuses
    ) private {
        require(
            parentNode != ETH_NODE,
            "NameWrapper: .eth domains need to use wrapETH2LD()"
        );

        bytes32 node = _makeNode(parentNode, label);

        _mint(parentNode, node, wrappedOwner, _fuses);
    }

    function _wrapETH2LD(
        bytes32 label,
        bytes32 node,
        address wrappedOwner,
        uint96 _fuses
    ) private {
        // transfer the ens record back to the new owner (this contract)
        registrar.reclaim(uint256(label), address(this));
        // mint a new ERC1155 token with fuses

        address oldWrappedOwner = ownerOf(uint256(node));
        if (oldWrappedOwner != address(0)) {
            _burn(uint256(node));
            emit UnwrapETH2LD(label, address(0), address(0));
        }
        _mint(ETH_NODE, node, wrappedOwner, _fuses);

        emit WrapETH2LD(label, wrappedOwner, _fuses);
    }

    function _unwrap(
        bytes32 parentNode,
        bytes32 label,
        address newOwner
    ) private {
        bytes32 node = _makeNode(parentNode, label);
        require(
            newOwner != address(0x0),
            "NameWrapper: Target owner cannot be 0x0"
        );
        require(
            newOwner != address(this),
            "NameWrapper: Target owner cannot be the NameWrapper contract"
        );
        require(canUnwrap(node), "NameWrapper: Domain is not unwrappable");

        // burn token and fuse data
        _burn(uint256(node));
        ens.setOwner(node, newOwner);
    }
}


fixing double spending htlc

fixing double spending htlc

contract MicropaymentsNetwork
{

    enum ChannelStage
    {
        Empty,
        PartiallyConfirmed,
        Confirmed,
        Closing,
        Closed
    }

    struct MicropaymentsChannel
    {
        ChannelStage stage;

        address from;
        uint fromBalance;

        address to;
        uint toBalance;

        uint balanceTimestamp;
        uint closingBlockNumber;

        mapping(bytes32 => bool) hashesUsed;
    }

    uint public constant closingDelay = 10;

    mapping(uint => MicropaymentsChannel) channels;
    mapping(uint => bool) reserved;

    function MicropaymentsNetwork()
    {
    }

    function isAvailable(uint _cid)
        constant
        returns (bool)
    {
        return !reserved[_cid];
    }

    function assertAvailable(uint _cid)
        internal
    {
        if (!isAvailable(_cid))
        {
            throw;
        }
    }

    function assertOnlyFrom(uint _cid)
        internal
    {
        if (msg.sender != channels[_cid].from)
        {
            throw;
        }
    }

    function assertOnlyTo(uint _cid)
        internal
    {
        if (msg.sender != channels[_cid].to)
        {
            throw;
        }
    }

    function assertOnlyParticipants(uint _cid)
        internal
    {
        if ((msg.sender != channels[_cid].from) && (msg.sender != channels[_cid].to))
        {
            throw;
        }
    }

    function assertAtStage(uint _cid, ChannelStage _stage)
        internal
    {
        if (channels[_cid].stage != _stage)
        {
            throw;
        }
    }

    function assertAtOneOfStages(uint _cid, ChannelStage _stage1, ChannelStage _stage2)
    {
        if ((channels[_cid].stage != _stage1) && (channels[_cid].stage != _stage2))
        {
            throw;
        }
    }

    function assertReadyToClose(uint _cid)
    {
        if (block.number < channels[_cid].closingBlockNumber)
        {
            throw;
        }
    }

    function assertYoungerBalance(uint _cid, uint _balanceTimestamp)
        internal
    {
        if (_balanceTimestamp <= channels[_cid].balanceTimestamp)
        {
            throw;
        }
    }

    function assertMatchingBalance(uint _cid, uint _balanceTimestamp)
        internal
    {
        if (_balanceTimestamp != channels[_cid].balanceTimestamp)
        {
            throw;
        }
    }

    function assertSaneBalance(uint _cid, uint _fromBalance, uint _toBalance)
        internal
    {
        if (channels[_cid].fromBalance + channels[_cid].toBalance < _fromBalance + _toBalance)
        {
            throw;
        }
    }

    function assertStillValid(uint _timeout)
        internal
    {
        if (_timeout < now)
        {
            throw;
        }
    }

    function assertSaneHTLC(uint _cid, int _fromToDelta)
        internal
    {
        if ((int(channels[_cid].fromBalance) - _fromToDelta < 0) ||
            (int(channels[_cid].toBalance) + _fromToDelta < 0))
        {
            throw;
        }
    }

    function assertHash(uint _cid, bytes32 _data, bytes32 _hash)
        internal
    {
        if ((channels[_cid].hashesUsed[_hash]) || (getHash(_data) != _hash))
        {
            throw;
        }
    }

    function assertSignedByBoth(
        uint _cid,
        bytes32 _sigHash,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
        internal
    {
        address signer = getSigner(_sigHash, _sigV, _sigR, _sigS);
        if (!(((channels[_cid].from == msg.sender) && (channels[_cid].to == signer)) ||
              ((channels[_cid].from == signer) && (channels[_cid].to == msg.sender))))
        {
            throw;
        }
    }

    function getHash(bytes32 _data)
        constant
        returns (bytes32)
    {
        return sha3(_data);
    }

    function getUpdateHash(
        uint _cid,
        uint _balanceTimestamp,
        uint _fromBalance,
        uint _toBalance)
        constant
        returns(bytes32)
    {
        return sha3(_cid, _balanceTimestamp, _fromBalance, _toBalance);
    }

    function getHTLCHash(
        uint _cid,
        uint _balanceTimestamp,
        uint _timeout,
        bytes32 _hash,
        int _fromToDelta)
        constant
        returns(bytes32)
    {
        return sha3(_cid, _timeout, _hash, _fromToDelta);
    }

    function getSigner(
        bytes32 _sigHash,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
        constant
        returns(address)
    {
        return ecrecover(_sigHash, _sigV, _sigR, _sigS);
    }

    function createChannel(uint _cid, address _from, address _to)
    {
        assertAvailable(_cid);

        reserved[_cid] = true;
        channels[_cid] = MicropaymentsChannel(ChannelStage.Empty, _from, 0, _to, 0, 0, 0);
    }

    function getStage(uint _cid)
        constant
        returns (uint8)
    {
        return uint8(channels[_cid].stage);
    }

    function getFrom(uint _cid)
        constant
        returns (address)
    {
        return channels[_cid].from;
    }

    function getFromBalance(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].fromBalance;
    }

    function getTo(uint _cid)
        constant
        returns (address)
    {
        return channels[_cid].to;
    }

    function getToBalance(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].toBalance;
    }

    function getBalanceTimestamp(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].balanceTimestamp;
    }

    function getClosingBlockNumber(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].closingBlockNumber;
    }

    function openChannel(uint _cid)
    {
        assertOnlyFrom(_cid);
        assertAtStage(_cid, ChannelStage.Empty);

        channels[_cid].stage = ChannelStage.PartiallyConfirmed;
        channels[_cid].fromBalance = msg.value;
    }

    function confirmChannel(uint _cid)
    {
        assertOnlyTo(_cid);
        assertAtStage(_cid, ChannelStage.PartiallyConfirmed);

        channels[_cid].stage = ChannelStage.Confirmed;
        channels[_cid].toBalance = msg.value;
    }

    function requestClosingChannel(uint _cid)
    {
        assertOnlyParticipants(_cid);
        assertAtOneOfStages(_cid, ChannelStage.PartiallyConfirmed, ChannelStage.Confirmed);

        if (channels[_cid].stage == ChannelStage.PartiallyConfirmed)
        {
            channels[_cid].stage = ChannelStage.Closed;
        }
        else
        {
            channels[_cid].stage = ChannelStage.Closing;
            channels[_cid].closingBlockNumber = block.number + closingDelay;
        }
    }

    function closeChannel(uint _cid)
    {
        assertOnlyParticipants(_cid);
        assertAtStage(_cid, ChannelStage.Closing);
        assertReadyToClose(_cid);

        channels[_cid].stage = ChannelStage.Closed;
    }

    function withdrawFrom(uint _cid)
    {
        assertOnlyFrom(_cid);
        assertAtStage(_cid, ChannelStage.Closed);

        uint balance = channels[_cid].fromBalance;
        channels[_cid].fromBalance = 0;
        channels[_cid].from.send(balance);
    }

    function withdrawTo(uint _cid)
    {
        assertOnlyTo(_cid);
        assertAtStage(_cid, ChannelStage.Closed);

        uint balance = channels[_cid].toBalance;
        channels[_cid].toBalance = 0;
        channels[_cid].to.send(balance);
    }

    function updateChannelState(
        uint _cid,
        uint _balanceTimestamp,
        uint _fromBalance,
        uint _toBalance,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
    {
        assertOnlyParticipants(_cid);
        assertAtOneOfStages(_cid, ChannelStage.Confirmed, ChannelStage.Closing);
        assertYoungerBalance(_cid, _balanceTimestamp);
        assertSaneBalance(_cid, _fromBalance, _toBalance);
        assertSignedByBoth(_cid, getUpdateHash(_cid, _balanceTimestamp, _fromBalance, _toBalance), _sigV, _sigR, _sigS);

        channels[_cid].balanceTimestamp = _balanceTimestamp;
        channels[_cid].fromBalance = _fromBalance;
        channels[_cid].toBalance = _toBalance;
    }

    function resolveHTLC(
        uint _cid,
        uint _balanceTimestamp,
        uint _timeout,
        bytes32 _hash,
        int _fromToDelta,
        bytes32 _data,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
    {
        assertOnlyParticipants(_cid);
        assertAtOneOfStages(_cid, ChannelStage.Confirmed, ChannelStage.Closing);
        assertMatchingBalance(_cid, _balanceTimestamp);
        assertStillValid(_timeout);
        assertSaneHTLC(_cid, _fromToDelta);
        assertHash(_cid, _data, _hash);
        assertSignedByBoth(_cid, getHTLCHash(_cid, _balanceTimestamp, _timeout, _hash, _fromToDelta), _sigV, _sigR, _sigS);

        channels[_cid].fromBalance = uint(int(channels[_cid].fromBalance) - _fromToDelta);
        channels[_cid].toBalance = uint(int(channels[_cid].toBalance) + _fromToDelta);
        channels[_cid].hashesUsed[_hash] = true;
    }
}

contract MicropaymentsNetwork
{

    enum ChannelStage
    {
        Empty,
        PartiallyConfirmed,
        Confirmed,
        Closing,
        Closed
    }

    struct MicropaymentsChannel
    {
        ChannelStage stage;

        address from;
        uint fromBalance;

        address to;
        uint toBalance;

        uint balanceTimestamp;
        uint closingBlockNumber;
    }

    uint public constant closingDelay = 10;

    mapping(uint => MicropaymentsChannel) channels;
    mapping(uint => bool) reserved;

    function MicropaymentsNetwork()
    {
    }

    function isAvailable(uint _cid)
        constant
        returns (bool)
    {
        return !reserved[_cid];
    }

    function assertAvailable(uint _cid)
        internal
    {
        if (!isAvailable(_cid))
        {
            throw;
        }
    }

    function assertOnlyFrom(uint _cid)
        internal
    {
        if (msg.sender != channels[_cid].from)
        {
            throw;
        }
    }

    function assertOnlyTo(uint _cid)
        internal
    {
        if (msg.sender != channels[_cid].to)
        {
            throw;
        }
    }

    function assertOnlyParticipants(uint _cid)
        internal
    {
        if ((msg.sender != channels[_cid].from) && (msg.sender != channels[_cid].to))
        {
            throw;
        }
    }

    function assertAtStage(uint _cid, ChannelStage _stage)
        internal
    {
        if (channels[_cid].stage != _stage)
        {
            throw;
        }
    }

    function assertAtOneOfStages(uint _cid, ChannelStage _stage1, ChannelStage _stage2)
    {
        if ((channels[_cid].stage != _stage1) && (channels[_cid].stage != _stage2))
        {
            throw;
        }
    }

    function assertReadyToClose(uint _cid)
    {
        if (block.number < channels[_cid].closingBlockNumber)
        {
            throw;
        }
    }

    function assertYoungerBalance(uint _cid, uint _balanceTimestamp)
        internal
    {
        if (_balanceTimestamp <= channels[_cid].balanceTimestamp)
        {
            throw;
        }
    }

    function assertMatchingBalance(uint _cid, uint _balanceTimestamp)
        internal
    {
        if (_balanceTimestamp != channels[_cid].balanceTimestamp)
        {
            throw;
        }
    }

    function assertSaneBalance(uint _cid, uint _fromBalance, uint _toBalance)
        internal
    {
        if (channels[_cid].fromBalance + channels[_cid].toBalance < _fromBalance + _toBalance)
        {
            throw;
        }
    }

    function assertStillValid(uint _timeout)
        internal
    {
        if (_timeout < now)
        {
            throw;
        }
    }

    function assertSaneHTLC(uint _cid, int _fromToDelta)
        internal
    {
        if ((int(channels[_cid].fromBalance) - _fromToDelta < 0) ||
            (int(channels[_cid].toBalance) + _fromToDelta < 0))
        {
            throw;
        }
    }

    function assertHash(bytes32 _data, bytes32 _hash)
        internal
    {
        if (getHash(_data) != _hash)
        {
            throw;
        }
    }

    function assertSignedByBoth(
        uint _cid,
        bytes32 _sigHash,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
        internal
    {
        address signer = getSigner(_sigHash, _sigV, _sigR, _sigS);
        if (!(((channels[_cid].from == msg.sender) && (channels[_cid].to == signer)) ||
              ((channels[_cid].from == signer) && (channels[_cid].to == msg.sender))))
        {
            throw;
        }
    }

    function getHash(bytes32 _data)
        constant
        returns (bytes32)
    {
        return sha3(_data);
    }

    function getUpdateHash(
        uint _cid,
        uint _balanceTimestamp,
        uint _fromBalance,
        uint _toBalance)
        constant
        returns(bytes32)
    {
        return sha3(_cid, _balanceTimestamp, _fromBalance, _toBalance);
    }

    function getHTLCHash(
        uint _cid,
        uint _balanceTimestamp,
        uint _timeout,
        bytes32 _hash,
        int _fromToDelta)
        constant
        returns(bytes32)
    {
        return sha3(_cid, _timeout, _hash, _fromToDelta);
    }

    function getSigner(
        bytes32 _sigHash,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
        constant
        returns(address)
    {
        return ecrecover(_sigHash, _sigV, _sigR, _sigS);
    }

    function createChannel(uint _cid, address _from, address _to)
    {
        assertAvailable(_cid);

        reserved[_cid] = true;
        channels[_cid] = MicropaymentsChannel(ChannelStage.Empty, _from, 0, _to, 0, 0, 0);
    }

    function getStage(uint _cid)
        constant
        returns (uint8)
    {
        return uint8(channels[_cid].stage);
    }

    function getFrom(uint _cid)
        constant
        returns (address)
    {
        return channels[_cid].from;
    }

    function getFromBalance(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].fromBalance;
    }

    function getTo(uint _cid)
        constant
        returns (address)
    {
        return channels[_cid].to;
    }

    function getToBalance(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].toBalance;
    }

    function getBalanceTimestamp(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].balanceTimestamp;
    }

    function getClosingBlockNumber(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].closingBlockNumber;
    }

    function openChannel(uint _cid)
    {
        assertOnlyFrom(_cid);
        assertAtStage(_cid, ChannelStage.Empty);

        channels[_cid].stage = ChannelStage.PartiallyConfirmed;
        channels[_cid].fromBalance = msg.value;
    }

    function confirmChannel(uint _cid)
    {
        assertOnlyTo(_cid);
        assertAtStage(_cid, ChannelStage.PartiallyConfirmed);

        channels[_cid].stage = ChannelStage.Confirmed;
        channels[_cid].toBalance = msg.value;
    }

    function requestClosingChannel(uint _cid)
    {
        assertOnlyParticipants(_cid);
        assertAtOneOfStages(_cid, ChannelStage.PartiallyConfirmed, ChannelStage.Confirmed);

        if (channels[_cid].stage == ChannelStage.PartiallyConfirmed)
        {
            channels[_cid].stage = ChannelStage.Closed;
        }
        else
        {
            channels[_cid].stage = ChannelStage.Closing;
            channels[_cid].closingBlockNumber = block.number + closingDelay;
        }
    }

    function closeChannel(uint _cid)
    {
        assertOnlyParticipants(_cid);
        assertAtStage(_cid, ChannelStage.Closing);
        assertReadyToClose(_cid);

        channels[_cid].stage = ChannelStage.Closed;
    }

    function withdrawFrom(uint _cid)
    {
        assertOnlyFrom(_cid);
        assertAtStage(_cid, ChannelStage.Closed);

        uint balance = channels[_cid].fromBalance;
        channels[_cid].fromBalance = 0;
        channels[_cid].from.send(balance);
    }

    function withdrawTo(uint _cid)
    {
        assertOnlyTo(_cid);
        assertAtStage(_cid, ChannelStage.Closed);

        uint balance = channels[_cid].toBalance;
        channels[_cid].toBalance = 0;
        channels[_cid].to.send(balance);
    }

    function updateChannelState(
        uint _cid,
        uint _balanceTimestamp,
        uint _fromBalance,
        uint _toBalance,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
    {
        assertOnlyParticipants(_cid);
        assertAtOneOfStages(_cid, ChannelStage.Confirmed, ChannelStage.Closing);
        assertYoungerBalance(_cid, _balanceTimestamp);
        assertSaneBalance(_cid, _fromBalance, _toBalance);
        assertSignedByBoth(_cid, getUpdateHash(_cid, _balanceTimestamp, _fromBalance, _toBalance), _sigV, _sigR, _sigS);

        channels[_cid].balanceTimestamp = _balanceTimestamp;
        channels[_cid].fromBalance = _fromBalance;
        channels[_cid].toBalance = _toBalance;
    }

    function resolveHTLC(
        uint _cid,
        uint _balanceTimestamp,
        uint _timeout,
        bytes32 _hash,
        int _fromToDelta,
        bytes32 _data,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
    {
        assertOnlyParticipants(_cid);
        assertAtOneOfStages(_cid, ChannelStage.Confirmed, ChannelStage.Closing);
        assertMatchingBalance(_cid, _balanceTimestamp);
        assertStillValid(_timeout);
        assertSaneHTLC(_cid, _fromToDelta);
        assertHash(_data, _hash);
        assertSignedByBoth(_cid, getHTLCHash(_cid, _balanceTimestamp, _timeout, _hash, _fromToDelta), _sigV, _sigR, _sigS);

        channels[_cid].fromBalance = uint(int(channels[_cid].fromBalance) - _fromToDelta);
        channels[_cid].toBalance = uint(int(channels[_cid].toBalance) + _fromToDelta);
    }
}


init naive impl.

init naive impl.

pragma solidity ^0.4.9;

contract Workflow {

    struct Activity {
        bytes32 name;
        bool included;
        bool executed;
        bool pending;

        // Outgoing relations:
        uint32[] include;
        uint32[] exclude;
        uint32[] response;

        // Incoming relations:
        uint32[] condition;
        uint32[] milestone;

        // Access rights:
        address[] whitelist;
    }

    event Execution(address sender, uint32 id, bool successful);
    Activity[] activities;
    address owner;

    /// names: array of activity names, where names[i] is the name of activity with id i
    /// included: array of activity included state, where included[i] is the included state of activity with id i
    /// executed: array of activity executed state, where executed[i] is the executed state of activity with id i
    /// pending: array of activity pending state, where pending[i] is the pending state of activity with id i
    /// include: array of include relations. The array is expected to have a structure such that i % 2 = 0 is the FROM activity and i + 1 is the TO activity
    /// exclude: array of exclude relations. The array is expected to have a structure such that i % 2 = 0 is the FROM activity and i + 1 is the TO activity
    /// response: array of response relations. The array is expected to have a structure such that i % 2 = 0 is the FROM activity and i + 1 is the TO activity
    /// condition: array of condition relations. The array is expected to have a structure such that i % 2 = 0 is the TO activity and i + 1 is the FROM activity
    /// milestone: array of milestone relations. The array is expected to have a structure such that i % 2 = 0 is the TO activity and i + 1 is the FROM activity
    function Workflow (
        bytes32[] names,
        bool[] included,
        bool[] executed,
        bool[] pending,
        uint32[] include,
        uint32[] exclude,
        uint32[] response,
        uint32[] condition,
        uint32[] milestone
    ) {
        owner = msg.sender;

        activities.length = names.length;

        for (var i = 0; i < names.length; i++) {
            activities[i].name      = names[i];
            activities[i].included  = included[i];
            activities[i].executed  = executed[i];
            activities[i].pending   = pending[i];
        }

        // We expect all relation arrays are formed such that i % 2 = 0 is where the data is to be stored, and i+1 is the data that is to be stored there
        for (i = 0; i < include.length; i++)
            activities[include[i++]].include.push(include[i]);
        for (i = 0; i < exclude.length; i++)
            activities[exclude[i++]].exclude.push(exclude[i]);
        for (i = 0; i < response.length; i++)
            activities[response[i++]].response.push(response[i]);
        for (i = 0; i < condition.length; i++)
            activities[condition[i++]].condition.push(condition[i]);
        for (i = 0; i < milestone.length; i++)
            activities[milestone[i++]].milestone.push(milestone[i]);

    }

    function addToWhitelist(uint32 id, address actor){
        if(msg.sender != owner)
            throw;

        activities[id].whitelist.push(actor);
    }

    function failWith(uint32 id) private {
        Execution(msg.sender, id, false);
        throw;
    }

    function execute(uint32 id) {
        // Check that activity is in executable state
        Activity memory a = activities[id];

        if(a.whitelist.length > 0) {
            for (var i = 0; i < a.whitelist.length; i++)
                if(a.whitelist[i] == msg.sender)
                    break;

            if(i == a.whitelist.length)
                failWith(id);
        }

        if(!a.included)
            failWith(id);

        for (i = 0; i < a.condition.length; i++)
            if(!activities[a.condition[i]].executed && activities[a.condition[i]].included)
                failWith(id);

        for (i = 0; i < a.condition.length; i++)
            if(activities[a.milestone[i]].pending && activities[a.condition[i]].included)
                failWith(id);

        // Effects on other activities
        for (i = 0; i < a.include.length; i++)
            activities[a.include[i]].included = true;

        for (i = 0; i < a.exclude.length; i++)
            activities[a.exclude[i]].included = false;

        for (i = 0; i < a.response.length; i++)
            activities[a.response[i]].pending = true;

        // Effect on executing activity
        a.executed = true;
        a.pending = false;
        Execution(msg.sender, id, true);

    }

    function sudoku() {
        if(msg.sender != owner)
            throw;

        selfdestruct(owner);
    }

}

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


Return original block number from getBlobInfo().

/**
 * @title BlobStore
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStore {

    struct BlobInfo {
        uint96 blockNumber;
        address owner;
    }

    mapping (bytes32 => BlobInfo) blobInfo;
    mapping (bytes32 => uint256[]) revisionBlockNumbers;

    event logBlob(bytes32 indexed hash, uint256 indexed revisionId, bytes blob) anonymous;
    event logRetraction(bytes32 indexed hash) anonymous;

    modifier isOwner(bytes32 hash) {
        if (blobInfo[hash].owner != msg.sender) {
            throw;
        }
        _
    }

    /**
     * @dev Stores a blob in the transaction log. It is guaranteed that each user will get a different hash when storing the same blob.
     * @param blob Blob that should be stored.
     * @return hash Hash of sender and blob.
     */
    function storeBlob(bytes blob, bool revisionable) external returns (bytes32 hash) {
        // Calculate the hash.
        hash = sha3(msg.sender, blob);
        // Store block number and owner in state.
        blobInfo[hash] = BlobInfo({
            blockNumber: uint96(block.number),
            owner: revisionable ? msg.sender : 0,
        });
        // Store the blob in a log in the current block.
        logBlob(hash, 0, blob);
    }

    function updateBlob(bytes32 hash, bytes blob) isOwner(hash) external {
        revisionBlockNumbers[hash].push(block.number);
        // Store the new blob in a log in the current block.
        logBlob(hash, revisionBlockNumbers[hash].length, blob);
    }

    function retractBlob(bytes32 hash) isOwner(hash) external {
        // Get a refund for the storage slots.
        delete blobInfo[hash];
        delete revisionBlockNumbers[hash];
        // Log the retraction.
        logRetraction(hash);
    }

    function getBlobInfo(bytes32 hash) constant external returns (address owner, uint256 originalBlockNumber, uint256 latestRevisionId, uint256 latestBlockNumber) {
        owner = blobInfo[hash].owner;
        latestRevisionId = revisionBlockNumbers[hash].length;
        originalBlockNumber = blobInfo[hash].blockNumber;
        if (latestRevisionId == 0) {
            latestBlockNumber = originalBlockNumber;
        }
        else {
            latestBlockNumber = revisionBlockNumbers[hash][latestRevisionId - 1];
        }
    }

    function getRevisionBlockNumber(bytes32 hash, uint256 revisionId) constant external returns (uint256 blockNumber) {
        if (revisionId == 0) {
            blockNumber = blobInfo[hash].blockNumber;
        }
        else {
            blockNumber = revisionBlockNumbers[hash][revisionId - 1];
        }
    }

    function() {
        throw;      // Do not maintain an ether balance.
    }

}

/**
 * @title BlobStore
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStore {

    struct BlobInfo {
        uint96 blockNumber;
        address owner;
    }

    mapping (bytes32 => BlobInfo) blobInfo;
    mapping (bytes32 => uint256[]) revisionBlockNumbers;

    event logBlob(bytes32 indexed hash, uint256 indexed revisionId, bytes blob) anonymous;
    event logRetraction(bytes32 indexed hash) anonymous;

    modifier isOwner(bytes32 hash) {
        if (blobInfo[hash].owner != msg.sender) {
            throw;
        }
        _
    }

    /**
     * @dev Stores a blob in the transaction log. It is guaranteed that each user will get a different hash when storing the same blob.
     * @param blob Blob that should be stored.
     * @return hash Hash of sender and blob.
     */
    function storeBlob(bytes blob, bool revisionable) external returns (bytes32 hash) {
        // Calculate the hash.
        hash = sha3(msg.sender, blob);
        // Store block number and owner in state.
        blobInfo[hash] = BlobInfo({
            blockNumber: uint96(block.number),
            owner: revisionable ? msg.sender : 0,
        });
        // Store the blob in a log in the current block.
        logBlob(hash, 0, blob);
    }

    function updateBlob(bytes32 hash, bytes blob) isOwner(hash) external {
        revisionBlockNumbers[hash].push(block.number);
        // Store the new blob in a log in the current block.
        logBlob(hash, revisionBlockNumbers[hash].length, blob);
    }

    function retractBlob(bytes32 hash) isOwner(hash) external {
        // Get a refund for the storage slots.
        delete blobInfo[hash];
        delete revisionBlockNumbers[hash];
        // Log the retraction.
        logRetraction(hash);
    }

    function getBlobInfo(bytes32 hash) constant external returns (address owner, uint256 revisions, uint256 blockNumber) {
        owner = blobInfo[hash].owner;
        revisions = revisionBlockNumbers[hash].length;
        if (revisions == 0) {
            blockNumber = blobInfo[hash].blockNumber;
        }
        else {
            blockNumber = revisionBlockNumbers[hash][revisions - 1];
        }
    }

    function getRevisionBlockNumber(bytes32 hash, uint256 revisionId) constant external returns (uint256 blockNumber) {
        if (revisionId == 0) {
            blockNumber = blobInfo[hash].blockNumber;
        }
        else {
            blockNumber = revisionBlockNumbers[hash][revisionId - 1];
        }
    }

    function() {
        throw;      // Do not maintain an ether balance.
    }

}


Remove block_numbers from NettingChannel contract. Fix #450

pragma solidity ^0.4.11;

import "./NettingChannelLibrary.sol";

contract NettingChannelContract {
    string constant public contract_version = "0.1._";

    using NettingChannelLibrary for NettingChannelLibrary.Data;
    NettingChannelLibrary.Data public data;

    event ChannelNewBalance(address token_address, address participant, uint balance);
    event ChannelClosed(address closing_address);
    event TransferUpdated(address node_address);
    event ChannelSettled();
    event ChannelSecretRevealed(bytes32 secret, address receiver_address);

    modifier settleTimeoutNotTooLow(uint t) {
        assert(t >= 6);
        _;
    }

    function NettingChannelContract(
        address token_address,
        address participant1,
        address participant2,
        uint timeout)
        settleTimeoutNotTooLow(timeout)
    {
        require(participant1 != participant2);

        data.participants[0].node_address = participant1;
        data.participants[1].node_address = participant2;
        data.participant_index[participant1] = 1;
        data.participant_index[participant2] = 2;

        data.token = Token(token_address);
        data.settle_timeout = timeout;
        data.opened = block.number;
    }

    /// @notice Caller makes a deposit into their channel balance.
    /// @param amount The amount caller wants to deposit.
    /// @return True if deposit is successful.
    function deposit(uint256 amount) returns (bool) {
        bool success;
        uint256 balance;

        (success, balance) = data.deposit(amount);

        if (success == true) {
            ChannelNewBalance(data.token, msg.sender, balance);
        }

        return success;
    }

    /// @notice Get the address and balance of both partners in a channel.
    /// @return The address and balance pairs.
    function addressAndBalance()
        constant
        returns (
        address participant1,
        uint balance1,
        address participant2,
        uint balance2)
    {
        NettingChannelLibrary.Participant storage node1 = data.participants[0];
        NettingChannelLibrary.Participant storage node2 = data.participants[1];

        participant1 = node1.node_address;
        balance1 = node1.balance;
        participant2 = node2.node_address;
        balance2 = node2.balance;
    }

    /// @notice Close the channel. Can only be called by a participant in the channel.
    function close(
        uint64 nonce,
        uint256 transferred_amount,
        bytes32 locksroot,
        bytes32 extra_hash,
        bytes signature
    ) {
        data.close(
            nonce,
            transferred_amount,
            locksroot,
            extra_hash,
            signature
        );
        ChannelClosed(msg.sender);
    }

    /// @notice Dispute the state after closing, called by the counterparty (the
    ///         participant who did not close the channel).
    function updateTransfer(
        uint64 nonce,
        uint256 transferred_amount,
        bytes32 locksroot,
        bytes32 extra_hash,
        bytes signature
    ) {
        data.updateTransfer(
            nonce,
            transferred_amount,
            locksroot,
            extra_hash,
            signature
        );
        TransferUpdated(msg.sender);
    }

    /// @notice Unlock a locked transfer.
    /// @param locked_encoded The locked transfer to be unlocked.
    /// @param merkle_proof The merke_proof for the locked transfer.
    /// @param secret The secret to unlock the locked transfer.
    function withdraw(bytes locked_encoded, bytes merkle_proof, bytes32 secret) {
        // throws if sender is not a participant
        data.withdraw(locked_encoded, merkle_proof, secret);
        ChannelSecretRevealed(secret, msg.sender);
    }

    /// @notice Settle the transfers and balances of the channel and pay out to
    ///         each participant. Can only be called after the channel is closed
    ///         and only after the number of blocks in the settlement timeout
    ///         have passed.
    function settle() {
        data.settle();
        ChannelSettled();
    }

    /// @notice Returns the number of blocks until the settlement timeout.
    /// @return The number of blocks until the settlement timeout.
    function settleTimeout() constant returns (uint) {
        return data.settle_timeout;
    }

    /// @notice Returns the address of the token.
    /// @return The address of the token.
    function tokenAddress() constant returns (address) {
        return data.token;
    }

    /// @notice Returns the block number for when the channel was opened.
    /// @return The block number for when the channel was opened.
    function opened() constant returns (uint) {
        return data.opened;
    }

    /// @notice Returns the block number for when the channel was closed.
    /// @return The block number for when the channel was closed.
    function closed() constant returns (uint) {
        return data.closed;
    }

    /// @notice Returns the address of the closing participant.
    /// @return The address of the closing participant.
    function closingAddress() constant returns (address) {
        return data.closing_address;
    }

    function () { revert(); }
}

pragma solidity ^0.4.11;

import "./NettingChannelLibrary.sol";

contract NettingChannelContract {
    string constant public contract_version = "0.1._";

    using NettingChannelLibrary for NettingChannelLibrary.Data;
    NettingChannelLibrary.Data public data;

    event ChannelNewBalance(address token_address, address participant, uint balance, uint block_number);
    event ChannelClosed(address closing_address, uint block_number);
    event TransferUpdated(address node_address, uint block_number);
    event ChannelSettled(uint block_number);
    event ChannelSecretRevealed(bytes32 secret, address receiver_address);

    modifier settleTimeoutNotTooLow(uint t) {
        assert(t >= 6);
        _;
    }

    function NettingChannelContract(
        address token_address,
        address participant1,
        address participant2,
        uint timeout)
        settleTimeoutNotTooLow(timeout)
    {
        require(participant1 != participant2);

        data.participants[0].node_address = participant1;
        data.participants[1].node_address = participant2;
        data.participant_index[participant1] = 1;
        data.participant_index[participant2] = 2;

        data.token = Token(token_address);
        data.settle_timeout = timeout;
        data.opened = block.number;
    }

    /// @notice Caller makes a deposit into their channel balance.
    /// @param amount The amount caller wants to deposit.
    /// @return True if deposit is successful.
    function deposit(uint256 amount) returns (bool) {
        bool success;
        uint256 balance;

        (success, balance) = data.deposit(amount);

        if (success == true) {
            ChannelNewBalance(data.token, msg.sender, balance, block.number);
        }

        return success;
    }

    /// @notice Get the address and balance of both partners in a channel.
    /// @return The address and balance pairs.
    function addressAndBalance()
        constant
        returns (
        address participant1,
        uint balance1,
        address participant2,
        uint balance2)
    {
        NettingChannelLibrary.Participant storage node1 = data.participants[0];
        NettingChannelLibrary.Participant storage node2 = data.participants[1];

        participant1 = node1.node_address;
        balance1 = node1.balance;
        participant2 = node2.node_address;
        balance2 = node2.balance;
    }

    /// @notice Close the channel. Can only be called by a participant in the channel.
    function close(
        uint64 nonce,
        uint256 transferred_amount,
        bytes32 locksroot,
        bytes32 extra_hash,
        bytes signature
    ) {
        data.close(
            nonce,
            transferred_amount,
            locksroot,
            extra_hash,
            signature
        );
        ChannelClosed(msg.sender, data.closed);
    }

    /// @notice Dispute the state after closing, called by the counterparty (the
    ///         participant who did not close the channel).
    function updateTransfer(
        uint64 nonce,
        uint256 transferred_amount,
        bytes32 locksroot,
        bytes32 extra_hash,
        bytes signature
    ) {
        data.updateTransfer(
            nonce,
            transferred_amount,
            locksroot,
            extra_hash,
            signature
        );
        TransferUpdated(msg.sender, block.number);
    }

    /// @notice Unlock a locked transfer.
    /// @param locked_encoded The locked transfer to be unlocked.
    /// @param merkle_proof The merke_proof for the locked transfer.
    /// @param secret The secret to unlock the locked transfer.
    function withdraw(bytes locked_encoded, bytes merkle_proof, bytes32 secret) {
        // throws if sender is not a participant
        data.withdraw(locked_encoded, merkle_proof, secret);
        ChannelSecretRevealed(secret, msg.sender);
    }

    /// @notice Settle the transfers and balances of the channel and pay out to
    ///         each participant. Can only be called after the channel is closed
    ///         and only after the number of blocks in the settlement timeout
    ///         have passed.
    function settle() {
        data.settle();
        ChannelSettled(block.number);
    }

    /// @notice Returns the number of blocks until the settlement timeout.
    /// @return The number of blocks until the settlement timeout.
    function settleTimeout() constant returns (uint) {
        return data.settle_timeout;
    }

    /// @notice Returns the address of the token.
    /// @return The address of the token.
    function tokenAddress() constant returns (address) {
        return data.token;
    }

    /// @notice Returns the block number for when the channel was opened.
    /// @return The block number for when the channel was opened.
    function opened() constant returns (uint) {
        return data.opened;
    }

    /// @notice Returns the block number for when the channel was closed.
    /// @return The block number for when the channel was closed.
    function closed() constant returns (uint) {
        return data.closed;
    }

    /// @notice Returns the address of the closing participant.
    /// @return The address of the closing participant.
    function closingAddress() constant returns (address) {
        return data.closing_address;
    }

    function () { revert(); }
}