array slice converted to string

array slice converted to string

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

import "./ERC1155Fuse.sol";
import "./Controllable.sol";
import "./INameWrapper.sol";
import "./INameWrapperUpgrade.sol";
import "./IMetadataService.sol";
import "../registry/ENS.sol";
import "../ethregistrar/IBaseRegistrar.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./BytesUtil.sol";

error Unauthorised(bytes32 node, address addr);
error NameNotFound();
error IncompatibleParent();
error IncompatibleName(bytes name);
error IncorrectTokenType();
error LabelMismatch(bytes32 labelHash, bytes32 expectedLabelhash);
error LabelTooShort();
error LabelTooLong(string label);
error IncorrectTargetOwner(address owner);
error CannotUpgrade();

contract NameWrapper is
    Ownable,
    ERC1155Fuse,
    INameWrapper,
    Controllable,
    IERC721Receiver
{
    using BytesUtils for bytes;
    ENS public immutable override ens;
    IBaseRegistrar public immutable override registrar;
    IMetadataService public override metadataService;
    mapping(bytes32 => bytes) public override names;

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

    //A contract address to a new upgraded contract if any
    INameWrapperUpgrade public upgradeContract;

    constructor(
        ENS _ens,
        IBaseRegistrar _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)
        );
        names[ROOT_NODE] = "\x00";
        names[ETH_NODE] = "\x03eth\x00";
    }

    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 Set the address of the upgradeContract of the contract. only admin can do this
     * @dev The default value of upgradeContract is the 0 address. Use the 0 address at any time
     * to make the contract not upgradable.
     * @param _upgradeAddress address of an upgraded contract
     */

    function setUpgradeContract(INameWrapperUpgrade _upgradeAddress)
        public
        onlyOwner
    {
            if (address(upgradeContract) != address(0)){
                registrar.setApprovalForAll(address(upgradeContract), false);
                ens.setApprovalForAll(address(upgradeContract), false);
            }

            upgradeContract = _upgradeAddress;

            if (address(upgradeContract) != address(0)){
                registrar.setApprovalForAll(address(upgradeContract), true);
                ens.setApprovalForAll(address(upgradeContract), true);
            }
    }

    /**
     * @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) {
        if (!isTokenOwnerOrApproved(node, msg.sender)) {
            revert Unauthorised(node, msg.sender);
        }

        _;
    }

    /**
     * @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)
    {
        address owner = ownerOf(uint256(node));
        return owner == addr || isApprovedForAll(owner, 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 fuses A number that represents the permissions a name has
     * @return vulnerability The type of vulnerability
     * @return vulnerableNode Which node is vulnerable
     */
    function getFuses(bytes32 node)
        public
        view
        override
        returns (
            uint96 fuses,
            NameSafety vulnerability,
            bytes32 vulnerableNode
        )
    {
        bytes memory name = names[node];
        if (name.length < 1) {
            revert NameNotFound();
        }
        (, vulnerability, vulnerableNode) = _checkHierarchy(name, 0);
        (, fuses) = getData(uint256(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,
        address resolver
    ) public override {
        uint256 tokenId = uint256(keccak256(bytes(label)));
        address registrant = registrar.ownerOf(tokenId);
        if (
            registrant != msg.sender &&
            !isApprovedForAll(registrant, msg.sender) &&
            !registrar.isApprovedForAll(registrant, msg.sender)
        ) {
            revert Unauthorised(
                _makeNode(ETH_NODE, bytes32(tokenId)),
                msg.sender
            );
        }

        // transfer the token from the user to this contract
        registrar.transferFrom(registrant, address(this), tokenId);

        // transfer the ens record back to the new owner (this contract)
        registrar.reclaim(tokenId, address(this));

        _wrapETH2LD(label, wrappedOwner, _fuses, resolver);
    }

    /**
     * @dev Registers a new .eth second-level domain and wraps it.
     *      Only callable by authorised controllers.
     * @param label The label to register (Eg, 'foo' for 'foo.eth').
     * @param wrappedOwner The owner of the wrapped name.
     * @param duration The duration, in seconds, to register the name for.
     * @param resolver The resolver address to set on the ENS registry (optional).
     * @return expires The expiry date of the new name, in seconds since the Unix epoch.
     */
    function registerAndWrapETH2LD(
        string calldata label,
        address wrappedOwner,
        uint256 duration,
        address resolver,
        uint96 _fuses
    ) external override onlyController returns (uint256 expires) {
        uint256 tokenId = uint256(keccak256(bytes(label)));

        expires = registrar.register(tokenId, address(this), duration);
        _wrapETH2LD(label, wrappedOwner, _fuses, resolver);
    }

    /**
     * @dev Renews a .eth second-level domain.
     *      Only callable by authorised controllers.
     * @param tokenId The hash of the label to register (eg, `keccak256('foo')`, for 'foo.eth').
     * @param duration The number of seconds to renew the name for.
     * @return expires The expiry date of the name, in seconds since the Unix epoch.
     */
    function renew(uint256 tokenId, uint256 duration)
        external
        override
        onlyController
        returns (uint256 expires)
    {
        return registrar.renew(tokenId, duration);
    }

    /**
     * @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 name The name to wrap, in DNS format
     * @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(
        bytes calldata name,
        address wrappedOwner,
        uint96 _fuses,
        address resolver
    ) public override {
        (bytes32 labelhash, uint256 offset) = name.readLabel(0);
        bytes32 parentNode = name.namehash(offset);
        bytes32 node = _makeNode(parentNode, labelhash);

        if (parentNode == ETH_NODE) {
            revert IncompatibleParent();
        }

        address owner = ens.owner(node);

        if (
            owner != msg.sender &&
            !isApprovedForAll(owner, msg.sender) &&
            !ens.isApprovedForAll(owner, msg.sender)
        ) {
            revert Unauthorised(node, msg.sender);
        }

        if (resolver != address(0)) {
            ens.setResolver(node, resolver);
        }

        ens.setOwner(node, address(this));

        _wrap(node, name, 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 labelhash labelhash of the .eth domain
     * @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 labelhash,
        address newRegistrant,
        address newController
    ) public override onlyTokenOwner(_makeNode(ETH_NODE, labelhash)) {
        _unwrap(_makeNode(ETH_NODE, labelhash), newController);
        registrar.transferFrom(
            address(this),
            newRegistrant,
            uint256(labelhash)
        );
    }

    /**
     * @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 labelhash labelhash of the .eth domain
     * @param newController sets the owner in the registry to this address
     */

    function unwrap(
        bytes32 parentNode,
        bytes32 labelhash,
        address newController
    ) public override onlyTokenOwner(_makeNode(parentNode, labelhash)) {
        if (parentNode == ETH_NODE) {
            revert IncompatibleParent();
        }
        _unwrap(_makeNode(parentNode, labelhash), 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 node namehash of the name. e.g. vitalik.xyz would be namehash('vitalik.xyz')
     * @param _fuses Fuses you want to burn.
     */

    function burnFuses(bytes32 node, uint96 _fuses)
        public
        override
        onlyTokenOwner(node)
        operationAllowed(node, CANNOT_BURN_FUSES)
    {
        (address owner, uint96 fuses) = getData(uint256(node));

        uint96 newFuses = fuses | _fuses;

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

        emit FusesBurned(node, newFuses);
    }

    /**
     * @notice Upgrades a domain to a new name wrapper version.
     * @dev Can be called by the owner or an authorised caller
     * @param name The name to upgrade, in DNS format
     * @param wrappedOwner owner of the name in this contract
     */

    function upgrade(
        bytes calldata name,
        address wrappedOwner
    ) public {

        if (address(upgradeContract) == address(0)){
            revert CannotUpgrade();
        }

        (bytes32 labelhash, uint offset) = name.readLabel(0);
        bytes32 parentNode = name.namehash(offset);
        bytes32 node = _makeNode(parentNode, labelhash);

        if (!isTokenOwnerOrApproved(node, msg.sender)){
            revert Unauthorised(node, msg.sender);
        }

        address resolver = ens.resolver(node);

        (uint96 fuses,,) = getFuses(node);

        if(parentNode == ETH_NODE) {
            upgradeContract.wrapETH2LD(string(name[1:offset]), wrappedOwner, fuses, resolver);
        } else {
            upgradeContract.wrap(name, wrappedOwner, fuses, resolver);
        }

        // burn token and fuse data
        _burn(uint256(node));
    }

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

    function setSubnodeRecord(
        bytes32 parentNode,
        bytes32 labelhash,
        address owner,
        address resolver,
        uint64 ttl
    )
        public
        override
        onlyTokenOwner(parentNode)
        canCallSetSubnodeOwner(parentNode, labelhash)
    {
        ens.setSubnodeRecord(parentNode, labelhash, owner, resolver, ttl);
    }

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

    function setSubnodeOwner(
        bytes32 parentNode,
        bytes32 labelhash,
        address owner
    )
        public
        override
        onlyTokenOwner(parentNode)
        canCallSetSubnodeOwner(parentNode, labelhash)
        returns (bytes32)
    {
        return ens.setSubnodeOwner(parentNode, labelhash, 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 = _makeNode(parentNode, labelhash);
        bytes memory name = _addLabel(label, names[parentNode]);

        setSubnodeOwner(parentNode, labelhash, address(this));

        _wrap(node, name, 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 {
        bytes32 labelhash = keccak256(bytes(label));
        bytes32 node = _makeNode(parentNode, labelhash);
        bytes memory name = _addLabel(label, names[parentNode]);

        setSubnodeRecord(parentNode, labelhash, address(this), resolver, ttl);

        _wrap(node, name, 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
        override
        onlyTokenOwner(node)
        operationAllowed(
            node,
            CANNOT_TRANSFER | CANNOT_SET_RESOLVER | CANNOT_SET_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)
        operationAllowed(node, CANNOT_SET_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)
        operationAllowed(node, CANNOT_SET_TTL)
    {
        ens.setTTL(node, ttl);
    }

    /**
     * @dev Allows an operation only if none of the specified fuses are burned.
     * @param node The namehash of the name to check fuses on.
     * @param fuseMask A bitmask of fuses that must not be burned.
     */
    modifier operationAllowed(bytes32 node, uint96 fuseMask) {
        (, uint96 fuses) = getData(uint256(node));
        if (fuses & fuseMask != 0) {
            revert OperationProhibited(node);
        }
        _;
    }

    /**
     * @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 labelhash labelhash of the name to check
     */

    modifier canCallSetSubnodeOwner(bytes32 node, bytes32 labelhash) {
        bytes32 subnode = _makeNode(node, labelhash);
        address owner = ens.owner(subnode);
        (, uint96 fuses) = getData(uint256(node));

        if (
            (owner == address(0) && fuses & CANNOT_CREATE_SUBDOMAIN != 0) ||
            (owner != address(0) && fuses & CANNOT_REPLACE_SUBDOMAIN != 0)
        ) {
            revert OperationProhibited(node);
        }

        _;
    }

    /**
     * @notice Checks all Fuses in the mask are burned for the node
     * @param node namehash of the name
     * @param fuseMask the fuses you want to check
     * @return Boolean of whether or not all the selected fuses are burned
     */

    function allFusesBurned(bytes32 node, uint96 fuseMask)
        public
        view
        override
        returns (bool)
    {
        (, uint96 fuses) = getData(uint256(node));
        return fuses & fuseMask == fuseMask;
    }

    function onERC721Received(
        address to,
        address,
        uint256 tokenId,
        bytes calldata data
    ) public override returns (bytes4) {
        //check if it's the eth registrar ERC721
        if (msg.sender != address(registrar)) {
            revert IncorrectTokenType();
        }

        (
            string memory label,
            address owner,
            uint96 fuses,
            address resolver
        ) = abi.decode(data, (string, address, uint96, address));

        bytes32 labelhash = bytes32(tokenId);
        bytes32 labelhashFromData = keccak256(bytes(label));

        if (labelhashFromData != labelhash) {
            revert LabelMismatch(labelhashFromData, labelhash);
        }

        // transfer the ens record back to the new owner (this contract)
        registrar.reclaim(uint256(labelhash), address(this));

        _wrapETH2LD(label, owner, fuses, resolver);

        return IERC721Receiver(to).onERC721Received.selector;
    }

    /***** Internal functions */

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

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

    function _addLabel(string memory label, bytes memory name)
        internal
        pure
        returns (bytes memory ret)
    {
        if (bytes(label).length < 1) {
            revert LabelTooShort();
        }
        if (bytes(label).length > 255) {
            revert LabelTooLong(label);
        }
        return abi.encodePacked(uint8(bytes(label).length), label, name);
    }

    function _mint(
        bytes32 node,
        address wrappedOwner,
        uint96 _fuses
    ) internal override {
        address oldWrappedOwner = ownerOf(uint256(node));
        if (oldWrappedOwner != address(0)) {
            // burn and unwrap old token of old owner
            _burn(uint256(node));
            emit NameUnwrapped(node, address(0));
        }
        super._mint(node, wrappedOwner, _fuses);
    }

    function _wrap(
        bytes32 node,
        bytes memory name,
        address wrappedOwner,
        uint96 fuses
    ) internal {
        names[node] = name;

        _mint(node, wrappedOwner, fuses);

        emit NameWrapped(node, name, wrappedOwner, fuses);
    }

    function _wrapETH2LD(
        string memory label,
        address wrappedOwner,
        uint96 _fuses,
        address resolver
    ) private returns (bytes32 labelhash) {
        labelhash = keccak256(bytes(label));
        bytes32 node = _makeNode(ETH_NODE, labelhash);
        bytes memory name = _addLabel(label, "\x03eth\x00");

        if (resolver != address(0)) {
            ens.setResolver(node, resolver);
        }

        // mint a new ERC1155 token with fuses
        _wrap(node, name, wrappedOwner, _fuses);
    }

    function _unwrap(bytes32 node, address newOwner) private {
        if (newOwner == address(0x0) || newOwner == address(this)) {
            revert IncorrectTargetOwner(newOwner);
        }

        if (allFusesBurned(node, CANNOT_UNWRAP)) {
            revert OperationProhibited(node);
        }

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

        emit NameUnwrapped(node, newOwner);
    }

    function _setData(
        uint256 tokenId,
        address owner,
        uint96 fuses
    ) internal override {
        if (fuses != CAN_DO_EVERYTHING && fuses & CANNOT_UNWRAP == 0) {
            revert OperationProhibited(bytes32(tokenId));
        }
        super._setData(tokenId, owner, fuses);
    }

    /**
     * @dev Internal function that checks all a name's ancestors to ensure fuse values will be respected and parent controller/registrant are set to the Wrapper
     * @param name The name to check.
     * @param offset The offset into the name to start at.
     * @return node The calculated namehash for this part of the name.
     * @return vulnerability what kind of vulnerability the node has
     * @return vulnerableNode which node is at risk
     */
    function _checkHierarchy(bytes memory name, uint256 offset)
        internal
        view
        returns (
            bytes32 node,
            NameSafety vulnerability,
            bytes32 vulnerableNode
        )
    {
        // Read the first label. If it's the root, return immediately.
        (bytes32 labelhash, uint256 newOffset) = name.readLabel(offset);
        if (labelhash == bytes32(0)) {
            // Root node
            return (bytes32(0), NameSafety.Safe, 0);
        }

        // Check the parent name
        bytes32 parentNode;
        (parentNode, vulnerability, vulnerableNode) = _checkHierarchy(
            name,
            newOffset
        );

        node = _makeNode(parentNode, labelhash);

        // stop function checking any other nodes if a parent is not safe
        if (vulnerability != NameSafety.Safe) {
            return (node, vulnerability, vulnerableNode);
        }

        // Check the parent name's fuses to see if replacing subdomains is forbidden
        if (parentNode == ROOT_NODE) {
            // Save ourselves some gas; root node can't be replaced
            return (node, NameSafety.Safe, 0);
        }

        (vulnerability, vulnerableNode) = _checkOwnership(
            labelhash,
            node,
            parentNode
        );

        if (vulnerability != NameSafety.Safe) {
            return (node, vulnerability, vulnerableNode);
        }

        if (!allFusesBurned(parentNode, CANNOT_REPLACE_SUBDOMAIN)) {
            return (node, NameSafety.SubdomainReplacementAllowed, parentNode);
        }

        return (node, NameSafety.Safe, 0);
    }

    function _checkOwnership(
        bytes32 labelhash,
        bytes32 node,
        bytes32 parentNode
    ) internal view returns (NameSafety vulnerability, bytes32 vulnerableNode) {
        if (parentNode == ETH_NODE) {
            // Special case .eth: Check registrant or name isexpired

            try registrar.ownerOf(uint256(labelhash)) returns (
                address registrarOwner
            ) {
                if (registrarOwner != address(this)) {
                    return (NameSafety.RegistrantNotWrapped, node);
                }
            } catch {
                return (NameSafety.Expired, node);
            }
        }

        if (ens.owner(node) != address(this)) {
            return (NameSafety.ControllerNotWrapped, node);
        }
        return (NameSafety.Safe, 0);
    }
}

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

import "./ERC1155Fuse.sol";
import "./Controllable.sol";
import "./INameWrapper.sol";
import "./INameWrapperUpgrade.sol";
import "./IMetadataService.sol";
import "../registry/ENS.sol";
import "../ethregistrar/IBaseRegistrar.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./BytesUtil.sol";

error Unauthorised(bytes32 node, address addr);
error NameNotFound();
error IncompatibleParent();
error IncompatibleName(bytes name);
error IncorrectTokenType();
error LabelMismatch(bytes32 labelHash, bytes32 expectedLabelhash);
error LabelTooShort();
error LabelTooLong(string label);
error IncorrectTargetOwner(address owner);
error CannotUpgrade();

contract NameWrapper is
    Ownable,
    ERC1155Fuse,
    INameWrapper,
    Controllable,
    IERC721Receiver
{
    using BytesUtils for bytes;
    ENS public immutable override ens;
    IBaseRegistrar public immutable override registrar;
    IMetadataService public override metadataService;
    mapping(bytes32 => bytes) public override names;

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

    //A contract address to a new upgraded contract if any
    INameWrapperUpgrade public upgradeContract;

    constructor(
        ENS _ens,
        IBaseRegistrar _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)
        );
        names[ROOT_NODE] = "\x00";
        names[ETH_NODE] = "\x03eth\x00";
    }

    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 Set the address of the upgradeContract of the contract. only admin can do this
     * @dev The default value of upgradeContract is the 0 address. Use the 0 address at any time
     * to make the contract not upgradable.
     * @param _upgradeAddress address of an upgraded contract
     */

    function setUpgradeContract(INameWrapperUpgrade _upgradeAddress)
        public
        onlyOwner
    {
            if (address(upgradeContract) != address(0)){
                registrar.setApprovalForAll(address(upgradeContract), false);
                ens.setApprovalForAll(address(upgradeContract), false);
            }

            upgradeContract = _upgradeAddress;

            if (address(upgradeContract) != address(0)){
                registrar.setApprovalForAll(address(upgradeContract), true);
                ens.setApprovalForAll(address(upgradeContract), true);
            }
    }

    /**
     * @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) {
        if (!isTokenOwnerOrApproved(node, msg.sender)) {
            revert Unauthorised(node, msg.sender);
        }

        _;
    }

    /**
     * @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)
    {
        address owner = ownerOf(uint256(node));
        return owner == addr || isApprovedForAll(owner, 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 fuses A number that represents the permissions a name has
     * @return vulnerability The type of vulnerability
     * @return vulnerableNode Which node is vulnerable
     */
    function getFuses(bytes32 node)
        public
        view
        override
        returns (
            uint96 fuses,
            NameSafety vulnerability,
            bytes32 vulnerableNode
        )
    {
        bytes memory name = names[node];
        if (name.length < 1) {
            revert NameNotFound();
        }
        (, vulnerability, vulnerableNode) = _checkHierarchy(name, 0);
        (, fuses) = getData(uint256(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,
        address resolver
    ) public override {
        uint256 tokenId = uint256(keccak256(bytes(label)));
        address registrant = registrar.ownerOf(tokenId);
        if (
            registrant != msg.sender &&
            !isApprovedForAll(registrant, msg.sender) &&
            !registrar.isApprovedForAll(registrant, msg.sender)
        ) {
            revert Unauthorised(
                _makeNode(ETH_NODE, bytes32(tokenId)),
                msg.sender
            );
        }

        // transfer the token from the user to this contract
        registrar.transferFrom(registrant, address(this), tokenId);

        // transfer the ens record back to the new owner (this contract)
        registrar.reclaim(tokenId, address(this));

        _wrapETH2LD(label, wrappedOwner, _fuses, resolver);
    }

    /**
     * @dev Registers a new .eth second-level domain and wraps it.
     *      Only callable by authorised controllers.
     * @param label The label to register (Eg, 'foo' for 'foo.eth').
     * @param wrappedOwner The owner of the wrapped name.
     * @param duration The duration, in seconds, to register the name for.
     * @param resolver The resolver address to set on the ENS registry (optional).
     * @return expires The expiry date of the new name, in seconds since the Unix epoch.
     */
    function registerAndWrapETH2LD(
        string calldata label,
        address wrappedOwner,
        uint256 duration,
        address resolver,
        uint96 _fuses
    ) external override onlyController returns (uint256 expires) {
        uint256 tokenId = uint256(keccak256(bytes(label)));

        expires = registrar.register(tokenId, address(this), duration);
        _wrapETH2LD(label, wrappedOwner, _fuses, resolver);
    }

    /**
     * @dev Renews a .eth second-level domain.
     *      Only callable by authorised controllers.
     * @param tokenId The hash of the label to register (eg, `keccak256('foo')`, for 'foo.eth').
     * @param duration The number of seconds to renew the name for.
     * @return expires The expiry date of the name, in seconds since the Unix epoch.
     */
    function renew(uint256 tokenId, uint256 duration)
        external
        override
        onlyController
        returns (uint256 expires)
    {
        return registrar.renew(tokenId, duration);
    }

    /**
     * @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 name The name to wrap, in DNS format
     * @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(
        bytes calldata name,
        address wrappedOwner,
        uint96 _fuses,
        address resolver
    ) public override {
        (bytes32 labelhash, uint256 offset) = name.readLabel(0);
        bytes32 parentNode = name.namehash(offset);
        bytes32 node = _makeNode(parentNode, labelhash);

        if (parentNode == ETH_NODE) {
            revert IncompatibleParent();
        }

        address owner = ens.owner(node);

        if (
            owner != msg.sender &&
            !isApprovedForAll(owner, msg.sender) &&
            !ens.isApprovedForAll(owner, msg.sender)
        ) {
            revert Unauthorised(node, msg.sender);
        }

        if (resolver != address(0)) {
            ens.setResolver(node, resolver);
        }

        ens.setOwner(node, address(this));

        _wrap(node, name, 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 labelhash labelhash of the .eth domain
     * @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 labelhash,
        address newRegistrant,
        address newController
    ) public override onlyTokenOwner(_makeNode(ETH_NODE, labelhash)) {
        _unwrap(_makeNode(ETH_NODE, labelhash), newController);
        registrar.transferFrom(
            address(this),
            newRegistrant,
            uint256(labelhash)
        );
    }

    /**
     * @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 labelhash labelhash of the .eth domain
     * @param newController sets the owner in the registry to this address
     */

    function unwrap(
        bytes32 parentNode,
        bytes32 labelhash,
        address newController
    ) public override onlyTokenOwner(_makeNode(parentNode, labelhash)) {
        if (parentNode == ETH_NODE) {
            revert IncompatibleParent();
        }
        _unwrap(_makeNode(parentNode, labelhash), 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 node namehash of the name. e.g. vitalik.xyz would be namehash('vitalik.xyz')
     * @param _fuses Fuses you want to burn.
     */

    function burnFuses(bytes32 node, uint96 _fuses)
        public
        override
        onlyTokenOwner(node)
        operationAllowed(node, CANNOT_BURN_FUSES)
    {
        (address owner, uint96 fuses) = getData(uint256(node));

        uint96 newFuses = fuses | _fuses;

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

        emit FusesBurned(node, newFuses);
    }

    /**
    /**
     * @notice Upgrades a domain to a new name wrapper version.
     * @dev Can be called by the owner or an authorised caller
     * @param name The name to upgrade, in DNS format
     * @param wrappedOwner owner of the name in this contract
     */

    function upgrade(
        bytes calldata name,
        address wrappedOwner
    ) public {

        if (address(upgradeContract) == address(0)){
            revert CannotUpgrade();
        }

        (bytes32 labelhash, uint offset) = name.readLabel(0);
        bytes32 parentNode = name.namehash(offset);
        bytes32 node = _makeNode(parentNode, labelhash);

        if (!isTokenOwnerOrApproved(node, msg.sender)){
            revert Unauthorised(node, msg.sender);
        }

        address resolver = ens.resolver(node);

        (uint96 fuses,,) = getFuses(node);

        if(parentNode == ETH_NODE) {
            upgradeContract.wrapETH2LD(name[1:offset], wrappedOwner, fuses, resolver);
        } else {
            upgradeContract.wrap(name, wrappedOwner, fuses, resolver);
        }

        // burn token and fuse data
        _burn(uint256(node));
    }

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

    function setSubnodeRecord(
        bytes32 parentNode,
        bytes32 labelhash,
        address owner,
        address resolver,
        uint64 ttl
    )
        public
        override
        onlyTokenOwner(parentNode)
        canCallSetSubnodeOwner(parentNode, labelhash)
    {
        ens.setSubnodeRecord(parentNode, labelhash, owner, resolver, ttl);
    }

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

    function setSubnodeOwner(
        bytes32 parentNode,
        bytes32 labelhash,
        address owner
    )
        public
        override
        onlyTokenOwner(parentNode)
        canCallSetSubnodeOwner(parentNode, labelhash)
        returns (bytes32)
    {
        return ens.setSubnodeOwner(parentNode, labelhash, 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 = _makeNode(parentNode, labelhash);
        bytes memory name = _addLabel(label, names[parentNode]);

        setSubnodeOwner(parentNode, labelhash, address(this));

        _wrap(node, name, 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 {
        bytes32 labelhash = keccak256(bytes(label));
        bytes32 node = _makeNode(parentNode, labelhash);
        bytes memory name = _addLabel(label, names[parentNode]);

        setSubnodeRecord(parentNode, labelhash, address(this), resolver, ttl);

        _wrap(node, name, 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
        override
        onlyTokenOwner(node)
        operationAllowed(
            node,
            CANNOT_TRANSFER | CANNOT_SET_RESOLVER | CANNOT_SET_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)
        operationAllowed(node, CANNOT_SET_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)
        operationAllowed(node, CANNOT_SET_TTL)
    {
        ens.setTTL(node, ttl);
    }

    /**
     * @dev Allows an operation only if none of the specified fuses are burned.
     * @param node The namehash of the name to check fuses on.
     * @param fuseMask A bitmask of fuses that must not be burned.
     */
    modifier operationAllowed(bytes32 node, uint96 fuseMask) {
        (, uint96 fuses) = getData(uint256(node));
        if (fuses & fuseMask != 0) {
            revert OperationProhibited(node);
        }
        _;
    }

    /**
     * @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 labelhash labelhash of the name to check
     */

    modifier canCallSetSubnodeOwner(bytes32 node, bytes32 labelhash) {
        bytes32 subnode = _makeNode(node, labelhash);
        address owner = ens.owner(subnode);
        (, uint96 fuses) = getData(uint256(node));

        if (
            (owner == address(0) && fuses & CANNOT_CREATE_SUBDOMAIN != 0) ||
            (owner != address(0) && fuses & CANNOT_REPLACE_SUBDOMAIN != 0)
        ) {
            revert OperationProhibited(node);
        }

        _;
    }

    /**
     * @notice Checks all Fuses in the mask are burned for the node
     * @param node namehash of the name
     * @param fuseMask the fuses you want to check
     * @return Boolean of whether or not all the selected fuses are burned
     */

    function allFusesBurned(bytes32 node, uint96 fuseMask)
        public
        view
        override
        returns (bool)
    {
        (, uint96 fuses) = getData(uint256(node));
        return fuses & fuseMask == fuseMask;
    }

    function onERC721Received(
        address to,
        address,
        uint256 tokenId,
        bytes calldata data
    ) public override returns (bytes4) {
        //check if it's the eth registrar ERC721
        if (msg.sender != address(registrar)) {
            revert IncorrectTokenType();
        }

        (
            string memory label,
            address owner,
            uint96 fuses,
            address resolver
        ) = abi.decode(data, (string, address, uint96, address));

        bytes32 labelhash = bytes32(tokenId);
        bytes32 labelhashFromData = keccak256(bytes(label));

        if (labelhashFromData != labelhash) {
            revert LabelMismatch(labelhashFromData, labelhash);
        }

        // transfer the ens record back to the new owner (this contract)
        registrar.reclaim(uint256(labelhash), address(this));

        _wrapETH2LD(label, owner, fuses, resolver);

        return IERC721Receiver(to).onERC721Received.selector;
    }

    /***** Internal functions */

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

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

    function _addLabel(string memory label, bytes memory name)
        internal
        pure
        returns (bytes memory ret)
    {
        if (bytes(label).length < 1) {
            revert LabelTooShort();
        }
        if (bytes(label).length > 255) {
            revert LabelTooLong(label);
        }
        return abi.encodePacked(uint8(bytes(label).length), label, name);
    }

    function _mint(
        bytes32 node,
        address wrappedOwner,
        uint96 _fuses
    ) internal override {
        address oldWrappedOwner = ownerOf(uint256(node));
        if (oldWrappedOwner != address(0)) {
            // burn and unwrap old token of old owner
            _burn(uint256(node));
            emit NameUnwrapped(node, address(0));
        }
        super._mint(node, wrappedOwner, _fuses);
    }

    function _wrap(
        bytes32 node,
        bytes memory name,
        address wrappedOwner,
        uint96 fuses
    ) internal {
        names[node] = name;

        _mint(node, wrappedOwner, fuses);

        emit NameWrapped(node, name, wrappedOwner, fuses);
    }

    function _wrapETH2LD(
        string memory label,
        address wrappedOwner,
        uint96 _fuses,
        address resolver
    ) private returns (bytes32 labelhash) {
        labelhash = keccak256(bytes(label));
        bytes32 node = _makeNode(ETH_NODE, labelhash);
        bytes memory name = _addLabel(label, "\x03eth\x00");

        if (resolver != address(0)) {
            ens.setResolver(node, resolver);
        }

        // mint a new ERC1155 token with fuses
        _wrap(node, name, wrappedOwner, _fuses);
    }

    function _unwrap(bytes32 node, address newOwner) private {
        if (newOwner == address(0x0) || newOwner == address(this)) {
            revert IncorrectTargetOwner(newOwner);
        }

        if (allFusesBurned(node, CANNOT_UNWRAP)) {
            revert OperationProhibited(node);
        }

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

        emit NameUnwrapped(node, newOwner);
    }

    function _setData(
        uint256 tokenId,
        address owner,
        uint96 fuses
    ) internal override {
        if (fuses != CAN_DO_EVERYTHING && fuses & CANNOT_UNWRAP == 0) {
            revert OperationProhibited(bytes32(tokenId));
        }
        super._setData(tokenId, owner, fuses);
    }

    /**
     * @dev Internal function that checks all a name's ancestors to ensure fuse values will be respected and parent controller/registrant are set to the Wrapper
     * @param name The name to check.
     * @param offset The offset into the name to start at.
     * @return node The calculated namehash for this part of the name.
     * @return vulnerability what kind of vulnerability the node has
     * @return vulnerableNode which node is at risk
     */
    function _checkHierarchy(bytes memory name, uint256 offset)
        internal
        view
        returns (
            bytes32 node,
            NameSafety vulnerability,
            bytes32 vulnerableNode
        )
    {
        // Read the first label. If it's the root, return immediately.
        (bytes32 labelhash, uint256 newOffset) = name.readLabel(offset);
        if (labelhash == bytes32(0)) {
            // Root node
            return (bytes32(0), NameSafety.Safe, 0);
        }

        // Check the parent name
        bytes32 parentNode;
        (parentNode, vulnerability, vulnerableNode) = _checkHierarchy(
            name,
            newOffset
        );

        node = _makeNode(parentNode, labelhash);

        // stop function checking any other nodes if a parent is not safe
        if (vulnerability != NameSafety.Safe) {
            return (node, vulnerability, vulnerableNode);
        }

        // Check the parent name's fuses to see if replacing subdomains is forbidden
        if (parentNode == ROOT_NODE) {
            // Save ourselves some gas; root node can't be replaced
            return (node, NameSafety.Safe, 0);
        }

        (vulnerability, vulnerableNode) = _checkOwnership(
            labelhash,
            node,
            parentNode
        );

        if (vulnerability != NameSafety.Safe) {
            return (node, vulnerability, vulnerableNode);
        }

        if (!allFusesBurned(parentNode, CANNOT_REPLACE_SUBDOMAIN)) {
            return (node, NameSafety.SubdomainReplacementAllowed, parentNode);
        }

        return (node, NameSafety.Safe, 0);
    }

    function _checkOwnership(
        bytes32 labelhash,
        bytes32 node,
        bytes32 parentNode
    ) internal view returns (NameSafety vulnerability, bytes32 vulnerableNode) {
        if (parentNode == ETH_NODE) {
            // Special case .eth: Check registrant or name isexpired

            try registrar.ownerOf(uint256(labelhash)) returns (
                address registrarOwner
            ) {
                if (registrarOwner != address(this)) {
                    return (NameSafety.RegistrantNotWrapped, node);
                }
            } catch {
                return (NameSafety.Expired, node);
            }
        }

        if (ens.owner(node) != address(this)) {
            return (NameSafety.ControllerNotWrapped, node);
        }
        return (NameSafety.Safe, 0);
    }
}


support transfer of minting rights

support transfer of minting rights

pragma solidity 0.4.11;

/// @title Abstract token contract - Functions to be implemented by token contracts.
contract Token {
    function maxSupply() constant returns (uint256 supply) {}
    function totalSupply() constant returns (uint256) {}
    function addCollateral() returns (bool) {}
    function mint(address receiver, uint num) returns (bool) {}
} // FIXME: is it required to specify the complete interface or only the required parts?

contract Mint {

    event MintingRightTransferred(address indexed from, address indexed to);

    /*
     *  Data structures
     */

    struct MintingRight {
        uint startTime;
        uint endTime;
        uint total;
        uint issued;
    }

    mapping (address => MintingRight) minters;
    address owner;
    address mintingRightsGranter;
    Token token;
    uint public maxMintable;
    uint public totalMinted;
    uint public totalMintingRightsGranted;

    enum Stages {
        MintDeployed,
        MintSetUp,
        CollateralProvided
    }

    Stages public stage;

    /*
     *  Modifiers
     */
    modifier atStage(Stages _stage) {
        assert(stage == _stage);
        _;
    }

    modifier isValidPayload() {
        assert(msg.data.length == 4 || msg.data.length == 36);
        _;
    }
    /*
     *  Public functions
     */

     function Mint(uint _maxMintable)
        public
     {
        owner = msg.sender;
        maxMintable = _maxMintable;
        stage = Stages.MintDeployed;
     }

    /// @dev Setup function sets external contracts' addresses.
    /// @param _token Raiden token address.
    function setup(address _token, address _mintingRightsGranter)
        public
        atStage(Stages.MintDeployed)
    {
        assert(msg.sender == owner);
        // register token
        assert(_token != 0x0);
        assert(Token(_token).maxSupply() == Token(_token).totalSupply() + maxMintable);
        // register mintingRightsGranter
        assert(_mintingRightsGranter != 0x0);
        mintingRightsGranter = _mintingRightsGranter;
        stage = Stages.MintSetUp;
    }

    function isReady()
        public
        constant
        atStage(Stages.MintSetUp)
        returns (bool)
    {
        return true;
    }

    // forwards collateral to the token
    function addCollateral()
        public
        payable
        atStage(Stages.MintSetUp)
        returns (bool)
    {
        assert(msg.sender == mintingRightsGranter);
        assert(token.addCollateral.value(this.balance)()); // FIXME double check
    }

    function registerMintingRight(address eligible, uint num, uint startTime, uint endTime)
        public
        atStage(Stages.CollateralProvided)
        returns (bool)
    {
        assert(msg.sender == mintingRightsGranter);
        assert(!minters[eligible]);
        assert(startTime < endTime);
        minters[eligible] = MintingRight({startTime: startTime,
                                          endTime: endTime,
                                          total: num,
                                          issued: 0});
        totalMintingRightsGranted += num;
        assert(totalMintingRightsGranted <= maxMintable);
        return true;
    }

    function transferMintingRight(address _eligible)
        public
        isValidPayload
        atStage(Stages.CollateralProvided)
        returns (uint)
    {
        require(minters[msg.sender] != 0x0);
        minters[_eligible] = minters[msg.sender];
        minters[msg.sender] = 0;
        MintingRightTransferred(msg.sender, _eligible);
        return true;
    }

    // calc the max mintable amount for account
    function mintable(address account)
        public
        atStage(Stages.CollateralProvided)
        returns (uint)
    {
        uint elapsed;
        MintingRight minter = minters[account];
        if(!minter || now < minter.startTime)
            return 0;
        // calc max mintable
        uint period = minter.endTime - minter.startTime;
        if (now - minter.startTime <= period) {
            elapsed = now - minter.startTime;
        } else {
            elapsed = period;
        }
        uint mintableByNow = minter.total * elapsed / period;
        return mintableByNow - minter.issued;
    }

    // note: anyone can call mint
    function mint(uint num, address account)
        public
        atStage(Stages.CollateralProvided)
    {
        require(num>0);
        MintingRight minter = minters[account];
        assert(num <= mintable(account));
        minter.issued += num;
        totalMinted += num;
        assert(Token(token).mint(account, num));
        assert(minter.issued <= minter.total);
        assert(totalMinted <= totalMintingRightsGranted);
        assert(totalMinted <= maxMintable);
    }
}

pragma solidity 0.4.11;

/// @title Abstract token contract - Functions to be implemented by token contracts.
contract Token {
    function maxSupply() constant returns (uint256 supply) {}
    function totalSupply() constant returns (uint256) {}
    function addCollateral() returns (bool) {}
    function mint(address receiver, uint num) returns (bool) {}
} // FIXME: is it required to specify the complete interface or only the required parts?

contract Mint {

    /*
     *  Data structures
     */

    struct MintingRight {
        uint startTime;
        uint endTime;
        uint total;
        uint issued;
    }

    mapping (address => MintingRight) minters;
    address owner;
    address mintingRightsGranter;
    Token token;
    uint public maxMintable;
    uint public totalMinted;
    uint public totalMintingRightsGranted;

    enum Stages {
        MintDeployed,
        MintSetUp,
        CollateralProvided
    }

    Stages public stage;
    /*
     *  Modifiers
     */
    modifier atStage(Stages _stage) {
        assert(stage == _stage);
        _;
    }

    /*
     *  Public functions
     */

     function Mint(uint _maxMintable)
        public
     {
        owner = msg.sender;
        maxMintable = _maxMintable;
        stage = Stages.MintDeployed;
     }

    /// @dev Setup function sets external contracts' addresses.
    /// @param _token Raiden token address.
    function setup(address _token, address _mintingRightsGranter)
        public
        atStage(Stages.MintDeployed)
    {
        assert(msg.sender == owner);
        // register token
        assert(_token != 0x0);
        assert(Token(_token).maxSupply() == Token(_token).totalSupply() + maxMintable);
        // register mintingRightsGranter
        assert(_mintingRightsGranter != 0x0);
        mintingRightsGranter = _mintingRightsGranter;
        stage = Stages.MintSetUp;
    }

    function isReady()
        public
        constant
        atStage(Stages.MintSetUp)
        returns (bool)
    {
        return true;
    }

    // forwards collateral to the token
    function addCollateral()
        public
        payable
        atStage(Stages.MintSetUp)
        returns (bool)
    {
        assert(msg.sender == mintingRightsGranter);
        assert(token.addCollateral.value(this.balance)()); // FIXME double check
    }

    function registerMintingRight(address eligible, uint num, uint startTime, uint endTime)
        public
        atStage(Stages.CollateralProvided)
        returns (bool)
    {
        assert(msg.sender == mintingRightsGranter);
        assert(!minters[eligible]);
        assert(startTime < endTime);
        minters[eligible] = MintingRight({startTime: startTime,
                                          endTime: endTime,
                                          total: num,
                                          issued: 0});
        totalMintingRightsGranted += num;
        assert(totalMintingRightsGranted <= maxMintable);
        return true;
    }

    // calc the max mintable amount for account
    function mintable(address account)
        public
        atStage(Stages.CollateralProvided)
        returns (uint)
    {
        uint elapsed;
        MintingRight minter = minters[account];
        if(!minter || now < minter.startTime)
            return 0;
        // calc max mintable
        uint period = minter.endTime - minter.startTime;
        if (now - minter.startTime <= period) {
            elapsed = now - minter.startTime;
        } else {
            elapsed = period;
        }
        uint mintableByNow = minter.total * elapsed / period;
        return mintableByNow - minter.issued;
    }

    // note: anyone can call mint
    function mint(uint num, address account)
        public
        atStage(Stages.CollateralProvided)
    {
        require(num>0);
        MintingRight minter = minters[account];
        assert(num <= mintable(account));
        minter.issued += num;
        totalMinted += num;
        assert(Token(token).mint(account, num));
        assert(minter.issued <= minter.total);
        assert(totalMinted <= totalMintingRightsGranted);
        assert(totalMinted <= maxMintable);
    }
}


contracts/KetherSortition.sol: Add stepDown for magistrate

//SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;

import "@openzeppelin/contracts/access/Ownable.sol";

import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";

interface IKetherHomepage {
  function ads(uint _idx) external view returns (address,uint,uint,uint,uint,string memory,string memory,string memory,bool,bool);
  function getAdsLength() view external returns (uint);
}

interface IERC721 {
  function ownerOf(uint256) external view returns (address);
  function balanceOf(address) external view returns (uint256);
  function tokenOfOwnerByIndex(address, uint256) external view returns (uint256);
}

library Errors {
  string constant MustHaveBalance = "must have balance to nominate";
  string constant OnlyMagistrate = "only active magistrate can do this";
  string constant MustHaveEntropy = "election not executed";
  string constant AlreadyStarted = "election already started";
  string constant AlreadyExecuted = "election already executed";

  // TODO: deadcode
  string constant AlreadyNominated = "address already nominated";
  string constant TermNotExpired = "term has not expired";

  string constant NotEnoughLink = "not enough LINK";
}

// TODO: Emit events.

contract KetherSortition is Ownable, VRFConsumerBase {
  // MagistrateToken is tokenId of an NFT whose owner controls the royalties purse for this term.
  uint256 public magistrateToken;

  uint256 constant MIN_ELECTION_DURATION = 2 days;
  uint256 constant TERM_DURATION = 6 weeks;

  uint256 termStarted;
  uint256 termExpires;
  uint256 termNumber = 0;

  IERC721 ketherNFTContract;
  IKetherHomepage ketherContract;

  uint256[] public nominatedTokens;
  uint256 public nominatedPixels = 0;
  mapping(uint256 => uint256) nominations; // mapping of tokenId => termNumber

  uint256 electionEntropy;

  bool waitingForEntropy = false;
  bool gotEntropy = false;
  bool nominating = true;

  uint8 constant STATE_NOMINATING = 0;
  uint8 constant STATE_WAITING_FOR_ENTROPY = 1;
  uint8 constant STATE_GOT_ENTROPY = 2;
  uint8 state = 0;

  // nominating -[term expired & startElection() calls]> waitingForEntropy -[Chainlink calls into fullfillrandomness()]> gotEntropy -[completeElection()] -> nominating

  // Chainlink values
  bytes32 private s_keyHash;
  uint256 private s_fee;

  constructor(address _ketherNFTContract, address _ketherContract, address vrfCoordinator, address link, bytes32 keyHash, uint256 fee)
  public
  VRFConsumerBase(vrfCoordinator, link) {
    s_keyHash = keyHash;
    s_fee = fee;

    ketherNFTContract = IERC721(_ketherNFTContract);
    ketherContract = IKetherHomepage(_ketherContract);
  }

  // Internal helpers:

  /**
   * @dev Only callable by Chainlink VRF, async triggered via startElection().
   */
  function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
    require(state == STATE_WAITING_FOR_ENTROPY, Errors.AlreadyExecuted);
    electionEntropy = randomness;
    state = STATE_GOT_ENTROPY;
  }

  // Views:

  function getMagistrate() public view returns (address) {
    return getAdOwner(magistrateToken);
  }

  function getAdOwner(uint256 _idx) public view returns (address) {
    return ketherNFTContract.ownerOf(_idx);
  }

  function getAdPixels(uint256 _idx) public view returns (uint256) {
    (,,,uint width,uint height,,,,,) = ketherContract.ads(_idx);
    return width * height * 10;
  }

  function isNominated(uint256 _idx) public view returns (bool) {
    return nominations[idx] > termNumber;
  }

  function getNextMagistrateToken() public view returns (uint256) {
    require(state == STATE_GOT_ENTROPY, Errors.MustHaveEntropy);
    // FIXME: Check off-by-ones

    uint256 pixelChosen = electionEntropy.mod(nominatedPixels);
    uint256 curPixel = 0;
    address nominated;

    for(uint256 i = 0; i < nominatedTokens.length; i++) {
      uint256 idx = nominatedTokens[i];
      curPixel += getAdPixels(idx);
      if (curPixel > pixelChosen) {
        return idx;
      }
    }
  }

  // External interface:

  /**
   * @dev Nominate tokens held by the sender as candidates for magistrate in the next term.
   *      Nominations of tokens are independent of their owner.
   * @return Number of nominated pixels
   */
  function nominateSelf() external returns (uint256) {
    require(state == STATE_NOMINATING, Errors.AlreadyStarted);
    address sender = _msgSender();
    require(ketherNFTContract.balanceOf(sender) > 0, Errors.MustHaveBalance);

    uint256 pixels = 0;
    for (uint256 i = 0; i < ketherNFTContract.balanceOf(sender); i++) {
      uint256 idx = ketherNFTContract.tokenOfOwnerByIndex(sender, i);
      if (!isNominated(idx)) {
        pixels += getAdPixels(idx);
        nominations[idx] = termNumber + 1;
        nominatedTokens.push(idx);
        // TODO: emit nomintated event
      }
    }

    nominatedPixels += pixels;
    return pixels;
  }

  // TODO: do we want to have a unNominateSelf()

  /**
   * @dev Stop accepting nominations, start election.
   */
  function startElection() external {
    //FIXME: check that term expired
    require(state == STATE_NOMINATING, Errors.AlreadyExecuted);
    require(termExpires <= block.timestamp, Errors.TermNotExpired);
    require(LINK.balanceOf(address(this)) >= s_fee, Errors.NotEnoughLink);

    // TODO: check if this is a re-entry vector
    state = STATE_WAITING_FOR_ENTROPY;
    requestRandomness(s_keyHash, s_fee);
  }

  /**
   * @dev Assign new magistrate and open up for nominations for next election.
   */
  function completeElection() external {
    require(state == STATE_GOT_ENTROPY, Errors.MustHaveEntropy);
    magistrateToken = getNextMagistrateToken();

    // FIXME: This is going to stagger terms, do we want to align them to
    // royalty payouts? Or maybe we could assign payouts to terms on a payment
    // receiver.
    termNumber += 1;
    termStarted = block.timestamp;
    termExpires = termStarted + TERM_DURATION;

    delete nominatedTokens;
    nominatedPixels = 0;
    state = STATE_NOMINATING;
  }

  // Only magistrate:

  /// @dev Transfer balance controlled by magistrate.
  function withdraw(address payable to) public {
    require(_msgSender() == getMagistrate(), Errors.OnlyMagistrate);
    // NOTE: you have exclusive rights to withdraw until the end of your term.
    // afterwards it becomes a race as someone call call an election.

    // FIXME: Would it be fun if this required having a >2 LINK balance to
    // withdraw? If we wanna be super cute, could automagically buy LINK from
    // the proceeds before transferring the remaining balance.

    to.transfer(address(this).balance);
  }

  /// @dev Cut the term short, leaving enough time for new nominations.
  function stepDown() public {
    require(_msgSender() == getMagistrate(), Errors.OnlyMagistrate);

    uint256 timeRemaining = termExpires - block.timestamp;
    if (timeRemaining > MIN_ELECTION_DURATION) {
      termExpires = block.timestamp + MIN_ELECTION_DURATION;
    }

    // TODO: Emit event
  }

  // Only owner (admin helpers):

  // TODO: adminUpdateChainlinkValues(bytes32 keyHash, uint256 fee) external onlyOwner

  function adminDelayNextEpoch(uint256 nextEpoch) external onlyOwner {
    // XXX: Implement this.
    // TODO: Should this also allow adjusting the interval?
  }

  /**
   * @dev Withdraw remaining LINK, for rescuing once the experiment is over.
   */
  function adminWithdrawLINK(address to) external onlyOwner {
    // XXX: Add require to confirm that the contract is suspended
    LINK.transfer(to, LINK.balanceOf(this));
  }
}

//SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;

import "@openzeppelin/contracts/access/Ownable.sol";

import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";

interface IKetherHomepage {
  function ads(uint _idx) external view returns (address,uint,uint,uint,uint,string memory,string memory,string memory,bool,bool);
  function getAdsLength() view external returns (uint);
}

interface IERC721 {
  function ownerOf(uint256) external view returns (address);
  function balanceOf(address) external view returns (uint256);
  function tokenOfOwnerByIndex(address, uint256) external view returns (uint256);
}

library Errors {
  string constant MustHaveBalance = "must have balance to nominate";
  string constant OnlyMagistrate = "only active magistrate can do this";
  string constant MustHaveEntropy = "election not executed";
  string constant AlreadyStarted = "election already started";
  string constant AlreadyExecuted = "election already executed";

  // TODO: deadcode
  string constant AlreadyNominated = "address already nominated";
  string constant TermNotExpired = "term has not expired";

  string constant NotEnoughLink = "not enough LINK";
}

// TODO: Emit events.

contract KetherSortition is Ownable, VRFConsumerBase {
  // MagistrateToken is tokenId of an NFT whose owner controls the royalties purse for this term.
  uint256 public magistrateToken;

  uint256 constant TERM_DURATION = 30 days; // TODO: Confirm OpenSea's royalty interval
  uint256 termStarted;
  uint256 termExpires;
  uint256 termNumber = 0;

  IERC721 ketherNFTContract;
  IKetherHomepage ketherContract;

  uint256[] public nominatedTokens;
  uint256 public nominatedPixels = 0;
  mapping(uint256 => uint256) nominations; // mapping of tokenId => termNumber

  //address[] nominatedAddresses; // TODO: Could store a struct{ address, idx, pixels }[] and confirm ownership in getNextMagistrate
  //mapping(address => uint256) nominations;
  uint256 electionEntropy;

  bool waitingForEntropy = false;
  bool gotEntropy = false;
  bool nominating = true;

  uint8 constant STATE_NOMINATING = 0;
  uint8 constant STATE_WAITING_FOR_ENTROPY = 1;
  uint8 constant STATE_GOT_ENTROPY = 2;
  uint8 state = 0;

  // nominating -[term expired & startElection() calls]> waitingForEntropy -[Chainlink calls into fullfillrandomness()]> gotEntropy -[completeElection()] -> nominating

  // Chainlink values
  bytes32 private s_keyHash;
  uint256 private s_fee;

  constructor(address _ketherNFTContract, address _ketherContract, address vrfCoordinator, address link, bytes32 keyHash, uint256 fee)
  public
  VRFConsumerBase(vrfCoordinator, link) {
    s_keyHash = keyHash;
    s_fee = fee;

    ketherNFTContract = IERC721(_ketherNFTContract);
    ketherContract = IKetherHomepage(_ketherContract);
  }

  // Internal helpers:

  /**
   * @dev Only callable by Chainlink VRF, async triggered via startElection().
   */
  function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
    require(state == STATE_WAITING_FOR_ENTROPY, Errors.AlreadyExecuted);
    electionEntropy = randomness;
    state = STATE_GOT_ENTROPY;
  }

  // Views:

  function getMagistrate() public view returns (address) {
    return getAdOwner(magistrateToken);
  }

  function getAdOwner(uint256 _idx) public view returns (address) {
    return ketherNFTContract.ownerOf(_idx);
  }

  function getAdPixels(uint256 _idx) public view returns (uint256) {
    (,,,uint width,uint height,,,,,) = ketherContract.ads(_idx);
    return width * height * 10;
  }

  function isNominated(uint256 _idx) public view returns (bool) {
    return nominations[idx] > termNumber;
  }

  function getNextMagistrateToken() public view returns (uint256) {
    require(state == STATE_GOT_ENTROPY, Errors.MustHaveEntropy);
    // FIXME: Check off-by-ones

    uint256 pixelChosen = electionEntropy.mod(nominatedPixels);
    uint256 curPixel = 0;
    address nominated;

    for(uint256 i = 0; i < nominatedTokens.length; i++) {
      uint256 idx = nominatedTokens[i];
      curPixel += getAdPixels(idx);
      if (curPixel > pixelChosen) {
        return idx;
      }
    }
  }

  // External interface:

  /**
   * @dev Nominate tokens held by the sender as candidates for magistrate in the next term.
   *      Nominations of tokens are independent of their owner.
   * @return Number of nominated pixels
   */
  function nominateSelf() external returns (uint256) {
    require(state == STATE_NOMINATING, Errors.AlreadyStarted);
    address sender = _msgSender();
    require(ketherNFTContract.balanceOf(sender) > 0, Errors.MustHaveBalance);

    uint256 pixels = 0;
    for (uint256 i = 0; i < ketherNFTContract.balanceOf(sender); i++) {
      uint256 idx = ketherNFTContract.tokenOfOwnerByIndex(sender, i);
      if (!isNominated(idx)) {
        pixels += getAdPixels(idx);
        nominations[idx] = termNumber + 1;
        nominatedTokens.push(idx);
        // TODO: emit nomintated event
      }
    }

    nominatedPixels += pixels;
    return pixels;
  }

  // TODO: do we want to have a unNominateSelf()

  /**
   * @dev Stop accepting nominations, start election.
   */
  function startElection() external {
    //FIXME: check that term expired
    require(state == STATE_NOMINATING, Errors.AlreadyExecuted);
    require(termExpires <= block.timestamp, Errors.TermNotExpired);
    require(LINK.balanceOf(address(this)) >= s_fee, Errors.NotEnoughLink);

    // TODO: check if this is a re-entry vector
    state = STATE_WAITING_FOR_ENTROPY;
    requestRandomness(s_keyHash, s_fee);
  }

  /**
   * @dev Assign new magistrate and open up for nominations for next election.
   */
  function completeElection() external {
    require(state == STATE_GOT_ENTROPY, Errors.MustHaveEntropy);
    magistrateToken = getNextMagistrateToken();

    // FIXME: This is going to stagger terms, do we want to align them to
    // royalty payouts? Or maybe we could assign payouts to terms on a payment
    // receiver.
    termNumber += 1;
    termStarted = block.timestamp;
    termExpires = termStarted + TERM_DURATION;

    delete nominatedTokens;
    nominatedPixels = 0;
    state = STATE_NOMINATING;
  }

  // Only magistrate:

  function withdraw(address payable to) public {
    require(_msgSender() == getMagistrate(), Errors.OnlyMagistrate);
    // NOTE: you have exclusive rights to withdraw until the end of your term.
    // afterwards it becomes a race as someone call call an election.

    // FIXME: Would it be fun if this required having a >2 LINK balance to
    // withdraw? If we wanna be super cute, could automagically buy LINK from
    // the proceeds before transferring the remaining balance.

    to.transfer(address(this).balance);
  }

  // Only owner (admin helpers):

  // TODO: adminUpdateChainlinkValues(bytes32 keyHash, uint256 fee) external onlyOwner

  function adminDelayNextEpoch(uint256 nextEpoch) external onlyOwner {
    // XXX: Implement this.
    // TODO: Should this also allow adjusting the interval?
  }

  /**
   * @dev Withdraw remaining LINK, for rescuing once the experiment is over.
   */
  function adminWithdrawLINK(address to) external onlyOwner {
    // XXX: Add require to confirm that the contract is suspended
    LINK.transfer(to, LINK.balanceOf(this));
  }
}


finished basic tests for Creatable.sol

finished basic tests for Creatable.sol

/*
    Copyright 2017 Phillip A. Elsasser

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

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

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

pragma solidity 0.4.18;

import "truffle/Assert.sol";
import "../contracts/Creatable.sol";

/// @title TestCreatable
/// @author Phil Elsasser <phil@marketprotcol.io>
contract TestCreatable {

    function testTransferCreator() public {
        Creatable creatable = new Creatable();
        Assert.equal(
            address(this),
            creatable.creator(),
            "contract creator isn't test contract"
        );

        creatable.transferCreator(address(creatable));

        Assert.equal(
            address(creatable),
            creatable.creator(),
            "contract creator isn't itself after setting"
        );

        Assert.isFalse(
            address(creatable) == address(this),
            "Addresses of contracts are equal, test not working"
        );
    }

    function shouldThrowOnAttemptToTransferToNullAddress() private {
        Creatable creatable = new Creatable();
        creatable.transferCreator(address(0));
    }

    function testThrowOnTransferToNullAddress() public {
        bool result = this.call(bytes4(keccak256("shouldThrowOnAttemptToTransferToNullAddress()")));
        Assert.isFalse(result, "Should require address not to be null address");
    }

    function shouldThrowOnAttemptToTransferWhenNotOwner() private {
        Creatable creatable = new Creatable();
        creatable.transferCreator(address(creatable));
        creatable.transferCreator(address(this)); // should fail since we are no longer creator!
    }

    function testThrowOnTransferWhenNotCreator() public {
        bool result = this.call(bytes4(keccak256("shouldThrowOnAttemptToTransferWhenNotOwner()")));
        Assert.isFalse(result, "Able to transfer creator when not creator!");
    }
}

/*
    Copyright 2017 Phillip A. Elsasser

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

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

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

pragma solidity 0.4.18;

import "truffle/Assert.sol";
import "../contracts/Creatable.sol";

/// @title TestCreatable
/// @author Phil Elsasser <phil@marketprotcol.io>
contract TestCreatable {

    function testTransferCreator() public {
        Creatable creatable = new Creatable();
        Assert.equal(
            address(this),
            creatable.creator(),
            "contract creator isn't test contract"
        );

        creatable.transferCreator(address(creatable));

        Assert.equal(
            address(creatable),
            creatable.creator(),
            "contract creator isn't itself after setting"
        );

        Assert.isTrue(
            address(creatable) != address(this),
            "Addresses of contracts are equal, test not working"
        );
    }
}


morden testnet canary

morden testnet canary

contract SchedulerInterface {
    function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock, uint suggestedGas, uint8 gracePeriod, uint basePayment, uint baseFee) public returns (address);
    function isKnownCall(address callAddress) constant returns (bool);
}

contract CallContractAPI {
    function targetBlock() constant returns (uint);
    function cancel() public;
}

contract Canary {
    uint public aliveSince;
    uint public lastHeartbeat;
    uint public heartbeatCount;
    SchedulerInterface scheduler;
    CallContractAPI callContract;

    address public owner;

    function schedulerAddress() constant returns (address) {
        return address(scheduler);
    }

    function callContractAddress() constant returns (address) {
        return address(callContract);
    }

    function Canary(address _scheduler) {
            owner = msg.sender;
            scheduler = SchedulerInterface(_scheduler);
    }

    function() {
        if (this.balance < 2 ether) {
            owner.send(this.balance);
        }
    }

    function cancel() public {
        // not authorized
        if (msg.sender != owner) throw;
        // need to wait until the
        if (callContract.balance > 0) {
            callContract.cancel();
        }
        owner.send(address(this).balance);

    }

    function initialize() public {
        // ensure we are not already initialized.
        if (aliveSince != 0) return;

        // mark when the canary came to life.
        aliveSince = now;

        // schedule the first call
        scheduleHeartbeat();
    }

    function scheduleHeartbeat() public {
        // schedule the call (~2 hours from now)
        address call_address = scheduler.scheduleCall.value(2 ether)(address(this), 0x3defb962, block.number + 480, 2000000, 255, 1 finney, 0);
        if (call_address != 0x0) {
            callContract = CallContractAPI(call_address);
        }
    }

    function heartbeat() public {
        // Ran out of funds.
        if (this.balance < 2 ether) return;

        // Not being called by the callContract.
        if (msg.sender != address(callContract)) return;

        // The canary has died!
        if (!isAlive()) return;

        // schedule the next call.
        scheduleHeartbeat();

        // Increment the heartbeat count
        heartbeatCount += 1;
        lastHeartbeat = now;
    }

    function isAlive() constant returns (bool) {
        return (aliveSince > 0 && block.number < callContract.targetBlock() + 255);
    }
}

contract CanaryV6 is Canary {
    function CanaryV6() Canary(0xe109ecb193841af9da3110c80fdd365d1c23be2a) {
    }
}

contract CanaryTestnet is Canary {
    function CanaryTestnet() Canary(0xb8da699d7fb01289d4ef718a55c3174971092bef) {
    }
}


adds payable to citizen

adds payable to citizen

pragma solidity ^0.4.0;

import "./mortal.sol";
import "./Storage.sol";

/// @title Citizen
/// A country has citizens which can obtain passports and apply for visa.
contract Citizen is owned, mortal {

    // All data is stored centrally in a storage contract so it can be accessed
    // by all entities.
    Storage private database;

    struct Visa {
        address owner;
        uint country; // as ISO 3166-1 numeric code
        bytes32 identifier;
        uint amountPaid;
        uint price;
        uint entered; // highest block # when entering country
        uint left;    // highest block # when leaving country
    }

    function Citizen(address _database) {
        database = Storage(_database);
    }

    function setStorage(Storage _database) onlyOwner() {
        database = _database;
    }

    /**
     * Everybody can create a passport which is initially invalid
     */
    function createPassport(bytes32 hashedPass) {
        bool valid = false;
        address owner = msg.sender;
        database.updatePassport(owner, hashedPass, valid);
    }

    /**
     * Returns passport of the msg.sender
     */
    function getOwnPassport() constant returns (address owner, bytes32 hashedPass, bool valid){
        return database.passByOwner(msg.sender);
    }

    /**
     * Applies for visa of msg.sender
     * @return {[type]} [description]
     */
    function applyVisa(uint _country, uint _index) {
        var (,i,,,p,) = database.visaOfferings(_country, _index);
        bytes32 _identifier = bytes32(i);
        uint _price = uint(p);
        database.createVisa(msg.sender,_country,_identifier,_price);
    }

    function payVisa(uint _country, uint _visaId) payable {
        var (o,,,a,,e,l) = database.visaStore(msg.sender, _country, _visaId);
        address _owner = address(o);
        uint _amountPaid = uint(a);
        uint _entered = uint(e);
        uint _left = uint(l);

        _amountPaid += msg.value;

        database.updateVisa(_owner,
                            _country,
                            _visaId,
                            _amountPaid,
                            _entered,
                            _left);
    }

}

pragma solidity ^0.4.0;

import "./mortal.sol";
import "./Storage.sol";

/// @title Citizen
/// A country has citizens which can obtain passports and apply for visa.
contract Citizen is owned, mortal {

    // All data is stored centrally in a storage contract so it can be accessed
    // by all entities.
    Storage private database;

    struct Visa {
        address owner;
        uint country; // as ISO 3166-1 numeric code
        bytes32 identifier;
        uint amountPaid;
        uint price;
        uint entered; // highest block # when entering country
        uint left;    // highest block # when leaving country
    }

    function Citizen(address _database) {
        database = Storage(_database);
    }

    function setStorage(Storage _database) onlyOwner() {
        database = _database;
    }

    /**
     * Everybody can create a passport which is initially invalid
     */
    function createPassport(bytes32 hashedPass) {
        bool valid = false;
        address owner = msg.sender;
        database.updatePassport(owner, hashedPass, valid);
    }

    /**
     * Returns passport of the msg.sender
     */
    function getOwnPassport() constant returns (address owner, bytes32 hashedPass, bool valid){
        return database.passByOwner(msg.sender);
    }

    /**
     * Applies for visa of msg.sender
     * @return {[type]} [description]
     */
    function applyVisa(uint _country, uint _index) {
        var (,i,,,p,) = database.visaOfferings(_country, _index);
        bytes32 _identifier = bytes32(i);
        uint _price = uint(p);
        database.createVisa(msg.sender,_country,_identifier,_price);
    }

    function payVisa() payable {

    }

    function someFunction() {

    }
}