move check for existing token into _mint

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)
        registrar.reclaim(uint256(labelhash), address(this));
        // mint a new ERC1155 token with fuses

        _checkFuses(ETH_NODE, _fuses);
        _mint(node, wrappedOwner, _fuses);

        emit NameWrapped(ETH_NODE, label, 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 node = _wrap(parentNode, label, 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));
    }

    /**
     * @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(_makeNode(ETH_NODE, label), newController);
        registrar.transferFrom(address(this), newRegistrant, uint256(label));
    }

    /**
     * @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(_makeNode(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"
        );

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

        uint96 newFuses = fuses | _fuses;
        _checkFuses(parentNode, newFuses);

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

        emit FusesBurned(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"
        );

        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, 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 {
        bytes32 labelhash = keccak256(bytes(label));
        setSubnodeRecord(parentNode, labelhash, address(this), resolver, ttl);
        _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);
    }

    /***** 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 labelHash,
        address wrappedOwner,
        uint96 _fuses
    ) internal {
        bytes32 node = _makeNode(parentNode, labelHash);
        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 parentNode,
        string calldata label,
        address wrappedOwner,
        uint96 _fuses
    ) private returns (bytes32 node) {
        require(
            parentNode != ETH_NODE,
            "NameWrapper: .eth domains need to use wrapETH2LD()"
        );
        _checkFuses(parentNode, _fuses);

        node = _makeNode(parentNode, keccak256(bytes(label)));

        _mint(node, wrappedOwner, _fuses);
        emit NameWrapped(parentNode, label, wrappedOwner, _fuses);
    }

    function _unwrap(bytes32 node, address newOwner) private {
        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);

        emit NameUnwrapped(node, newOwner);
    }

    function _checkFuses(bytes32 parentNode, uint96 _fuses) internal view {
        if (_fuses == CAN_DO_EVERYTHING) return;
        require(
            !canReplaceSubdomain(parentNode),
            "NameWrapper: Cannot burn fuses: parent name can replace subdomain"
        );
        require(
            _fuses & CANNOT_UNWRAP != 0,
            "NameWrapper: Cannot burn fuses: domain can be unwrapped"
        );
    }
}

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)
        registrar.reclaim(uint256(labelhash), address(this));
        // mint a new ERC1155 token with fuses

        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));
        }
        _checkFuses(ETH_NODE, _fuses);
        _mint(node, wrappedOwner, _fuses);

        emit NameWrapped(ETH_NODE, label, 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 node = _wrap(parentNode, label, 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));
    }

    /**
     * @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(_makeNode(ETH_NODE, label), newController);
        registrar.transferFrom(address(this), newRegistrant, uint256(label));
    }

    /**
     * @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(_makeNode(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"
        );

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

        uint96 newFuses = fuses | _fuses;
        _checkFuses(parentNode, newFuses);

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

        emit FusesBurned(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"
        );

        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, 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 {
        bytes32 labelhash = keccak256(bytes(label));
        setSubnodeRecord(parentNode, labelhash, address(this), resolver, ttl);
        _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);
    }

    /***** 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 _wrap(
        bytes32 parentNode,
        string calldata label,
        address wrappedOwner,
        uint96 _fuses
    ) private returns(bytes32 node) {
        require(
            parentNode != ETH_NODE,
            "NameWrapper: .eth domains need to use wrapETH2LD()"
        );
        _checkFuses(parentNode, _fuses);

        node = _makeNode(parentNode, keccak256(bytes(label)));

        _mint(node, wrappedOwner, _fuses);
        emit NameWrapped(parentNode, label, wrappedOwner, _fuses);
    }

    function _unwrap(
        bytes32 node,
        address newOwner
    ) private {
        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);

        emit NameUnwrapped(node, newOwner);
    }

    function _checkFuses(bytes32 parentNode, uint96 _fuses) internal view {
        if(_fuses == CAN_DO_EVERYTHING) return;
        require(
            !canReplaceSubdomain(parentNode),
            "NameWrapper: Cannot burn fuses: parent name can replace subdomain"
        );
        require(
            _fuses & CANNOT_UNWRAP != 0,
            "NameWrapper: Cannot burn fuses: domain can be unwrapped"
        );
    }
}


Update WeiControllerFactory.sol

Update WeiControllerFactory.sol

/// @title The core WeiFund configuration hook interface
/// @author Nick Dodson <thenickdodson@gmail.com>
/// @dev This contract enables campaigns to interact with other contracts, such as equity dispersal mechanisms (controllers) and registries
contract WeiFundConfig {
    /// @notice Called when a new campaign has been created
    /// @dev If a campaign specifies a configuration contract, this will be called when the new campaign is created
    /// @param _campaignID (campaign id) the campaign id
    /// @param _owner (campaign owner) the campaign owner or creator
    /// @param _fundingGoal (funding goal) the campaign funding goal
    function newCampaign(uint _campaignID, address _owner, uint _fundingGoal) {}

    /// @notice Called when a new contribution has been made
    /// @dev This will be called when a new contribution has been made to a campaign, this can be used for token generation
    /// @param _campaignID (campaign id) the campaign id
    /// @param _contributor (contributor) the account that initially made the campaign contribution
    /// @param _beneficiary (contribution beneficiary) the contribution beneficiary
    /// @param _amountContributed (amount contributed) the amount contributed by the contributor
    function contribute(uint _campaignID, address _contributor, address _beneficiary, uint _amountContributed) {}

    /// @notice Called when a new refund has been ordered
    /// @dev This will be called when a campaign has failed and a contributor is ordering a refund of their contributed ether
    /// @param _campaignID (campaign id) the campaign id
    /// @param _contributor (contributor) the campaign contributor address
    /// @param _amountRefunded the amount refunded to the contributor
    function refund(uint _campaignID, address _contributor, uint _amountRefunded) {}

    /// @notice Called when a campaign is being paid out
    /// @dev This will be called when a campaign has succeceed and the funds are being paid out to the contributor
    /// @param _campaignID (campaign id) the campaign id
    /// @param _amountPaid The amount paid out to the campaign beneficiary
    function payout(uint _campaignID, uint _amountPaid) {}
}

/// @title An Ethereum standard token interface
contract Token {
    /// @return total amount of tokens
    function totalSupply() constant returns (uint256 supply) {}

    /// @param _owner The address from which the balance will be retrieved
    /// @return The balance
    function balanceOf(address _owner) constant returns (uint256 balance) {}

    /// @notice send `_value` token to `_to` from `msg.sender`
    /// @param _to The address of the recipient
    /// @param _value The amount of token to be transferred
    /// @return Whether the transfer was successful or not
    function transfer(address _to, uint256 _value) returns (bool success) {}

    /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
    /// @param _from The address of the sender
    /// @param _to The address of the recipient
    /// @param _value The amount of token to be transferred
    /// @return Whether the transfer was successful or not
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {}

    /// @notice `msg.sender` approves `_addr` to spend `_value` tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @param _value The amount of wei to be approved for transfer
    /// @return Whether the approval was successful or not
    function approve(address _spender, uint256 _value) returns (bool success) {}

    /// @param _owner The address of the account owning tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @return Amount of remaining tokens allowed to spent
    function allowance(address _owner, address _spender) constant returns (uint256 remaining) {}

    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

/// @title The core WeiFund crowdfunding interface
/// @author Nick Dodson <thenickdodson@gmail.com>
contract WeiFund {
    /// @notice creates a new crowdfunding campaign
    /// @dev This method starts a new crowdfunding campaign and calles the campaigns configuration contract if stated
    /// @param _name (campaign name) The campaign name
    /// @param _beneficiary (beneficiary) The address of the beneficiary for this campaign
    /// @param _fundingGoal (funding goal) The funding goal of the campaign. If this goal is not met by the timelimit, all ether will be refunded to the respective contributers
    /// @param _expiry (expiry) When the campaign will expire and contributions can no longer be made
    /// @param _config (configuration address) The configuration address
    /// @return _campaignID (campaign ID) The newly created campaign ID number
    function newCampaign(string _name, address _beneficiary, uint _fundingGoal, uint _expiry, address _config) returns (uint campaignID) {}

    /// @notice contributes ether to a WeiFund campaign
    /// @dev This method will contribute an amount of ether to the campaign at ID _cid. All contribution data will be stored so that the issuance of digital assets can be made out to the contributor address
    /// @param _campaignID (campaign ID) The ID number of the crowdfunding campaign
    /// @param _beneficiary (contribute As Address) This allows a user to contribute on behalf of another address, if left empty, the from sender address is used as the primary Funder address
    /// @return _contributionID (contributor ID) The newly created contributor ID
    function contribute(uint _campaignID, address _beneficiary) returns (uint _contributionID) {}

    /// @notice refunds your accounts contribution of a failed crowdfunding campaign
    /// @dev This method will refund the amount you contributed to a WeiFund campaign, if that campaign has failed to meet it's funding goal or has expired.
    /// @param _campaignID (campaign ID) The ID number of the crowdfunding campaign to be refunded
    function refund(uint _campaignID, uint _contribution) {}

    /// @notice this will payout a successful crowdfunding campaign to the beneficiary address
    /// @dev This method will payout a successful WeiFund crowdfunding campaign to the beneficiary address specified. Any person can trigger the payout by calling this method.
    /// @param _campaignID (campaign ID) The ID number of the crowdfunding campaign
    function payout(uint _campaignID) {}

    /// @notice user Campaign ID (the address of the user, the user campaign ID); get the campaign ID of one of the users crowdfunding campaigns.
    /// @dev This method will get the campaign ID of one of the users crowdfunding campaigns, by looking up the campaign with a user campaign ID. All campaign owners and their campaigns are stored with WeiFund.
    /// @param _operator (campaign creator) The address of the campaign operator
    /// @param _campaignIndex The user campaign ID
    /// @return _campaignID (campaign ID) The campaign ID
    function operatorCampaignID(address _operator, uint _campaignIndex) constant returns (uint campaignID) {}

    /// @notice total number of campaigns created by a specific user
    /// @dev This method will get the campaign ID of one of the users crowdfunding campaigns, by looking up the campaign with a user campaign ID. All campaign owners and their campaigns are stored with WeiFund.
    /// @param _operator (campaign creator) The user's address
    /// @return _numCampaigns (number of campaigns) The number of campaigns
    function totalCampaignsBy(address _operator) constant returns (uint numCampaigns) {}

    /// @notice total number of contributions made by a contributor account to a campaign
    /// @dev This method will retunr an unsigned integer of the total number of campaigns started by a single account
    /// @param _campaignID (campaign id) The campaign id
    /// @param _contributor (campaign contributor address) The user's address
    /// @return _numCampaigns (number of campaigns) The number of campaigns
    function totalContributionsBy(uint _campaignID, address _contributor) constant returns (uint) {}

    /// @notice the total number of campaigns on WeiFund
    /// @dev This method returns the total number of campaigns on WeiFund as an unsigned integer
    /// @return _numCampaigns (number of campaigns) The number of campaigns
    function totalCampaigns() constant returns (uint numCampaigns) {}

    /// @notice retrieve campaign contribution data at specified contributor ID
    /// @dev Retrieve contributor data (tuple) of a specific contributor
    /// @param _campaignID (campaign id) The address of the campaign operator.
    /// @param _contributionID (contributor id) The user campaign ID
    /// @return contributor, beneficiary, amountContributed, refunded, created
    function contributionAt(uint _campaignID, uint _contributionID) constant returns (address contributor,
                                                                                address beneficiary,
                                                                                uint amountContributed,
                                                                                bool refunded,
                                                                                uint created) {}
    /// @notice When the campaign was created
    /// @dev For retrieving the campaign created UNIX timestamp integer
    /// @param _campaignID (campaign id) The campaign id
    /// @return unix timestamp when the campaign was created
    function createdAt(uint _campaignID) public constant returns (uint) {}

    /// @notice Retreive a contributor ID of a campaign contributor
    /// @dev The contributor ID can be used to get contributor information such as how much they contributed to a campaign
    /// @param _campaignID (campaign id) The campaign id
    /// @param _contributor (contributor address)
    /// @param _contributionIndex (contribution index)
    /// @return the contributor ID
    function contributionID(uint _campaignID, address _contributor, uint _contributionIndex) constant returns (uint) {}

    /// @notice Retreive the owner of a specific campaign
    /// @dev The campaign owner is the 20 byte address of the account that created the campaign
    /// @param _campaignID (campaign id) The campaign id
    /// @return The campaign owner's account
    function ownerOf(uint _campaignID) constant returns (address) {}

    /// @notice The beneficiary address of the campaign
    /// @dev The campaign beneficiary is the account that will receive the funds raised by the camapign
    /// @param _campaignID (campaign id) The campaign id
    /// @return The campaign beneficiary address
    function beneficiaryOf(uint _campaignID) constant returns (address) {}

    /// @notice The configuration contract address of the campaign
    /// @dev The configuration contract address allows campaigns to extend their functionality beyond the WeiFund contract
    /// @param _campaignID (campaign id) The campaign id
    /// @return The confirguation contract address
    function configOf(uint _campaignID) constant returns (address) {}

    /// @notice The amount raised by the campaign
    /// @dev The amount of ether raised by a specific campaign
    /// @param _campaignID (campaign id) The campaign id
    /// @return The campaign beneficiary address
    function amountRaisedBy(uint _campaignID) constant returns (uint) {}

    /// @notice The funding goal of a campaign
    /// @dev The amount of ether that needs to be raised in order for campaign funds to be released to the beneficiary, fund value is in wei
    /// @param _campaignID (campaign id) The campaign id
    /// @return The funding goal in wei
    function fundingGoalOf(uint _campaignID) constant returns (uint) {}

    /// @notice The campaign expiry
    /// @dev The unix timestamp at which the campaign funding goal must be reached in order for funds to be paid out
    /// @param _campaignID (campaign id) The campaign id
    /// @return The campaign expiry
    function expiryOf(uint _campaignID) constant returns (uint) {}

    /// @notice The total number of campaign contributors
    /// @dev The total number of campaign contributors returned as an integer
    /// @param _campaignID (campaign id) The campaign id
    /// @return The total number of campaign contributors
    function totalContributors(uint _campaignID) constant returns (uint) {}

    /// @notice Check to see if account is a campaign contributor
    /// @dev Determine whether a specified account address is a campaign contributor
    /// @param _campaignID (campaign id) The campaign id
    /// @param _contributor (contributor address) The contributors account address
    /// @return is address contributor or not (boolean)
    function isContributor(uint _campaignID, address _contributor) constant returns (bool) {}

    /// @notice Check to see if account is a campaign owner
    /// @dev Determine whether a specified account address is the campaign owner
    /// @param _campaignID (campaign id) The campaign id
    /// @param _owner (owner) The owner address
    /// @return is address the campaign owner or not (boolean)
    function isOwner(uint _campaignID, address _owner) constant returns (bool) {}

    /// @notice Has the campaign failed to reach its goals
    /// @dev Determine whether a campaign has failed to reach its goals
    /// @param _campaignID (campaign id) The campaign id
    /// @return has the campaign failed or not (boolean)
    function hasFailed(uint _campaignID) constant returns (bool) {}

    /// @notice Has the campaign succeeded in reaching its funding goals
    /// @dev Determine whether a campaign has succeeded to reach its goals by the campaign expiry
    /// @param _campaignID (campaign id) The campaign id
    /// @return has the campaign succeeded or not (boolean)
    function isSuccess(uint _campaignID) constant returns (bool) {}

    /// @notice Is the campaign an active campaign (i.e. hasnt failed, succeeded or been paid out)
    /// @dev Returns a boolean, is the campaign active or not
    /// @param _campaignID (campaign id) The campaign id
    /// @return is the campaign active or not (boolean)
    function isActive(uint _campaignID) constant returns (bool) {}

    /// @notice Has the campaign been paid out
    /// @dev Has the funds raised by the campaign been paid out (returns a boolean)
    /// @param _campaignID (campaign id) The campaign id
    /// @return has the campaign been paid out
    function isPaidOut(uint _campaignID) constant returns (bool) {}

    /// @notice The total amount of funds that have been refunded for a specified campaign
    /// @dev The total amount of ether that has been refunded for a specified campaign (funds are integers in the wei denomination)
    /// @param _campaignID (campaign id) The campaign id
    /// @return the total amount of funds refunded (an integer representing wei)
    function totalRefunded(uint _campaignID) constant returns (uint) {}

    /// @notice Has the campaign been completly refunded
    /// @dev Are all funds refunded from this campaign (returns a boolean)
    /// @param _campaignID (campaign id) The campaign id
    /// @return have the funds been refunded or not
    function isRefunded(uint _campaignID) constant returns (bool) {}

    event CampaignCreated(uint indexed _campaignID, address indexed _owner);
    event Contributed(uint indexed _campaignID, address indexed _contributor, uint _amountContributed);
    event Refunded(uint indexed _campaignID, address indexed _contributor, uint _amountRefunded);
    event PaidOut(uint indexed _campaignID, address indexed _beneficiary, uint _amountPaid);
}

/// @title A dispersal mechanism for WeiFund campaigns to disperse tokens
/// @author Nick Dodson <thenickdodson@gmail.com>
contract WeiController is WeiFundConfig {
    uint public campaignID;
    address public weifund;
    address public owner;
    address public token;
    uint public total_issued;
    uint public fundingGoal;
    uint public tokenValue;
    bool public autoDisperse;
	uint public version = 1;
	mapping(address => uint) public balances;

	modifier isWeiFund() {
		if(msg.sender != weifund)
			throw;
		else
			_
	}

    modifier validCampaign(uint _campaignID){
        if(campaignID != _campaignID)
            throw;
        else
            _
    }

    function WeiController (address _weifund, address _owner, address _token, uint _tokenValue, bool _autoDisperse) {
        weifund = _weifund;
        owner = _owner;
        token = _token;
        tokenValue = _tokenValue;
        autoDisperse = _autoDisperse;
    }

    function newCampaign(uint _campaignID, address _owner, uint _fundingGoal) isWeiFund {
        if(_fundingGoal <= 0)
            throw;

        campaignID = _campaignID;
        fundingGoal = _fundingGoal;
    }

    function contribute(uint _campaignID, address _contributor, address _beneficiary, uint _amountContributed) isWeiFund validCampaign(_campaignID) {
        uint tokenAmount = _amountContributed / tokenValue;

        balances[_contributor] = tokenAmount;
		total_issued += tokenAmount;

        if(autoDisperse)
            Token(token).transfer(_contributor, tokenAmount);
    }

    function claimTokens() {
        if(autoDisperse)
            throw;

        if(WeiFund(weifund).isSuccess(campaignID) && balances[msg.sender] > 0)
            Token(token).transfer(msg.sender, balances[msg.sender]);

        if(WeiFund(weifund).hasFailed(campaignID) && msg.sender == owner)
            Token(token).transfer(owner, Token(token).balanceOf(this));
    }

    function refund(uint _campaignID, address _contributor, uint _amountRefunded) isWeiFund validCampaign(_campaignID) {
    }

    function payout(uint _campaignID, uint _amountPaid) isWeiFund validCampaign(_campaignID)  {
        uint remainingBalance = Token(token).balanceOf(this);

        if(autoDisperse)
            Token(token).transfer(owner, remainingBalance);
    }
}

/// @title A simple service registry
/// @author Nick Dodson <thenickdodson@gmail.com>
contract ServiceRegistry {
    mapping(address => address) public services;
    event ServiceAdded(address indexed _service, address _sender);

    function addService(address _service) internal {
        services[_service] = msg.sender;
        ServiceAdded(_service, msg.sender);
    }

    function ownerOf(address _service) constant returns (address) {
        return services[_service];
    }

    function isService(address _service) constant returns (bool) {
        if (services[_service] != address(0))
            return true;
    }
}

/// @title This factory allows campaign operators to create safe weifund ready WeiControllers securly
/// @author Nick Dodson <thenickdodson@gmail.com>
contract WeiControllerFactory is ServiceRegistry {
    address public weifund;
	uint public version = 1;

    function WeiControllerFactory (address _weifund) {
        weifund = _weifund;
    }

    function newWeiController (address _owner, address _token, uint _tokenValue, bool _autoDisperse) returns (address newController) {
        newController = address(new WeiController(weifund, _owner, _token, _tokenValue, _autoDisperse));
        addService(newController);
    }
}

/// @title The core WeiFund configuration hook interface
/// @author Nick Dodson <thenickdodson@gmail.com>
/// @dev This contract enables campaigns to interact with other contracts, such as equity dispersal mechanisms (controllers) and registries
contract WeiFundConfig {
    /// @notice Called when a new campaign has been created
    /// @dev If a campaign specifies a configuration contract, this will be called when the new campaign is created
    /// @param _campaignID (campaign id) the campaign id
    /// @param _owner (campaign owner) the campaign owner or creator
    /// @param _fundingGoal (funding goal) the campaign funding goal
    function newCampaign(uint _campaignID, address _owner, uint _fundingGoal) {}

    /// @notice Called when a new contribution has been made
    /// @dev This will be called when a new contribution has been made to a campaign, this can be used for token generation
    /// @param _campaignID (campaign id) the campaign id
    /// @param _contributor (contributor) the account that initially made the campaign contribution
    /// @param _beneficiary (contribution beneficiary) the contribution beneficiary
    /// @param _amountContributed (amount contributed) the amount contributed by the contributor
    function contribute(uint _campaignID, address _contributor, address _beneficiary, uint _amountContributed) {}

    /// @notice Called when a new refund has been ordered
    /// @dev This will be called when a campaign has failed and a contributor is ordering a refund of their contributed ether
    /// @param _campaignID (campaign id) the campaign id
    /// @param _contributor (contributor) the campaign contributor address
    /// @param _amountRefunded the amount refunded to the contributor
    function refund(uint _campaignID, address _contributor, uint _amountRefunded) {}

    /// @notice Called when a campaign is being paid out
    /// @dev This will be called when a campaign has succeceed and the funds are being paid out to the contributor
    /// @param _campaignID (campaign id) the campaign id
    /// @param _amountPaid The amount paid out to the campaign beneficiary
    function payout(uint _campaignID, uint _amountPaid) {}
}

/// @title An Ethereum standard token interface
contract Token {
    /// @return total amount of tokens
    function totalSupply() constant returns (uint256 supply) {}

    /// @param _owner The address from which the balance will be retrieved
    /// @return The balance
    function balanceOf(address _owner) constant returns (uint256 balance) {}

    /// @notice send `_value` token to `_to` from `msg.sender`
    /// @param _to The address of the recipient
    /// @param _value The amount of token to be transferred
    /// @return Whether the transfer was successful or not
    function transfer(address _to, uint256 _value) returns (bool success) {}

    /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
    /// @param _from The address of the sender
    /// @param _to The address of the recipient
    /// @param _value The amount of token to be transferred
    /// @return Whether the transfer was successful or not
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {}

    /// @notice `msg.sender` approves `_addr` to spend `_value` tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @param _value The amount of wei to be approved for transfer
    /// @return Whether the approval was successful or not
    function approve(address _spender, uint256 _value) returns (bool success) {}

    /// @param _owner The address of the account owning tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @return Amount of remaining tokens allowed to spent
    function allowance(address _owner, address _spender) constant returns (uint256 remaining) {}

    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

/// @title The core WeiFund crowdfunding interface
/// @author Nick Dodson <thenickdodson@gmail.com>
contract WeiFund {
    /// @notice creates a new crowdfunding campaign
    /// @dev This method starts a new crowdfunding campaign and calles the campaigns configuration contract if stated
    /// @param _name (campaign name) The campaign name
    /// @param _beneficiary (beneficiary) The address of the beneficiary for this campaign
    /// @param _fundingGoal (funding goal) The funding goal of the campaign. If this goal is not met by the timelimit, all ether will be refunded to the respective contributers
    /// @param _expiry (expiry) When the campaign will expire and contributions can no longer be made
    /// @param _config (configuration address) The configuration address
    /// @return _campaignID (campaign ID) The newly created campaign ID number
    function newCampaign(string _name, address _beneficiary, uint _fundingGoal, uint _expiry, address _config) returns (uint campaignID) {}

    /// @notice contributes ether to a WeiFund campaign
    /// @dev This method will contribute an amount of ether to the campaign at ID _cid. All contribution data will be stored so that the issuance of digital assets can be made out to the contributor address
    /// @param _campaignID (campaign ID) The ID number of the crowdfunding campaign
    /// @param _beneficiary (contribute As Address) This allows a user to contribute on behalf of another address, if left empty, the from sender address is used as the primary Funder address
    /// @return _contributionID (contributor ID) The newly created contributor ID
    function contribute(uint _campaignID, address _beneficiary) returns (uint _contributionID) {}

    /// @notice refunds your accounts contribution of a failed crowdfunding campaign
    /// @dev This method will refund the amount you contributed to a WeiFund campaign, if that campaign has failed to meet it's funding goal or has expired.
    /// @param _campaignID (campaign ID) The ID number of the crowdfunding campaign to be refunded
    function refund(uint _campaignID, uint _contribution) {}

    /// @notice this will payout a successful crowdfunding campaign to the beneficiary address
    /// @dev This method will payout a successful WeiFund crowdfunding campaign to the beneficiary address specified. Any person can trigger the payout by calling this method.
    /// @param _campaignID (campaign ID) The ID number of the crowdfunding campaign
    function payout(uint _campaignID) {}

    /// @notice user Campaign ID (the address of the user, the user campaign ID); get the campaign ID of one of the users crowdfunding campaigns.
    /// @dev This method will get the campaign ID of one of the users crowdfunding campaigns, by looking up the campaign with a user campaign ID. All campaign owners and their campaigns are stored with WeiFund.
    /// @param _operator (campaign creator) The address of the campaign operator
    /// @param _campaignIndex The user campaign ID
    /// @return _campaignID (campaign ID) The campaign ID
    function operatorCampaignID(address _operator, uint _campaignIndex) constant returns (uint campaignID) {}

    /// @notice total number of campaigns created by a specific user
    /// @dev This method will get the campaign ID of one of the users crowdfunding campaigns, by looking up the campaign with a user campaign ID. All campaign owners and their campaigns are stored with WeiFund.
    /// @param _operator (campaign creator) The user's address
    /// @return _numCampaigns (number of campaigns) The number of campaigns
    function totalCampaignsBy(address _operator) constant returns (uint numCampaigns) {}

    /// @notice total number of contributions made by a contributor account to a campaign
    /// @dev This method will retunr an unsigned integer of the total number of campaigns started by a single account
    /// @param _campaignID (campaign id) The campaign id
    /// @param _contributor (campaign contributor address) The user's address
    /// @return _numCampaigns (number of campaigns) The number of campaigns
    function totalContributionsBy(uint _campaignID, address _contributor) constant returns (uint) {}

    /// @notice the total number of campaigns on WeiFund
    /// @dev This method returns the total number of campaigns on WeiFund as an unsigned integer
    /// @return _numCampaigns (number of campaigns) The number of campaigns
    function totalCampaigns() constant returns (uint numCampaigns) {}

    /// @notice retrieve campaign contribution data at specified contributor ID
    /// @dev Retrieve contributor data (tuple) of a specific contributor
    /// @param _campaignID (campaign id) The address of the campaign operator.
    /// @param _contributionID (contributor id) The user campaign ID
    /// @return contributor, beneficiary, amountContributed, refunded, created
    function contributionAt(uint _campaignID, uint _contributionID) constant returns (address contributor,
                                                                                address beneficiary,
                                                                                uint amountContributed,
                                                                                bool refunded,
                                                                                uint created) {}
    /// @notice When the campaign was created
    /// @dev For retrieving the campaign created UNIX timestamp integer
    /// @param _campaignID (campaign id) The campaign id
    /// @return unix timestamp when the campaign was created
    function createdAt(uint _campaignID) public constant returns (uint) {}

    /// @notice Retreive a contributor ID of a campaign contributor
    /// @dev The contributor ID can be used to get contributor information such as how much they contributed to a campaign
    /// @param _campaignID (campaign id) The campaign id
    /// @param _contributor (contributor address)
    /// @param _contributionIndex (contribution index)
    /// @return the contributor ID
    function contributionID(uint _campaignID, address _contributor, uint _contributionIndex) constant returns (uint) {}

    /// @notice Retreive the owner of a specific campaign
    /// @dev The campaign owner is the 20 byte address of the account that created the campaign
    /// @param _campaignID (campaign id) The campaign id
    /// @return The campaign owner's account
    function ownerOf(uint _campaignID) constant returns (address) {}

    /// @notice The beneficiary address of the campaign
    /// @dev The campaign beneficiary is the account that will receive the funds raised by the camapign
    /// @param _campaignID (campaign id) The campaign id
    /// @return The campaign beneficiary address
    function beneficiaryOf(uint _campaignID) constant returns (address) {}

    /// @notice The configuration contract address of the campaign
    /// @dev The configuration contract address allows campaigns to extend their functionality beyond the WeiFund contract
    /// @param _campaignID (campaign id) The campaign id
    /// @return The confirguation contract address
    function configOf(uint _campaignID) constant returns (address) {}

    /// @notice The amount raised by the campaign
    /// @dev The amount of ether raised by a specific campaign
    /// @param _campaignID (campaign id) The campaign id
    /// @return The campaign beneficiary address
    function amountRaisedBy(uint _campaignID) constant returns (uint) {}

    /// @notice The funding goal of a campaign
    /// @dev The amount of ether that needs to be raised in order for campaign funds to be released to the beneficiary, fund value is in wei
    /// @param _campaignID (campaign id) The campaign id
    /// @return The funding goal in wei
    function fundingGoalOf(uint _campaignID) constant returns (uint) {}

    /// @notice The campaign expiry
    /// @dev The unix timestamp at which the campaign funding goal must be reached in order for funds to be paid out
    /// @param _campaignID (campaign id) The campaign id
    /// @return The campaign expiry
    function expiryOf(uint _campaignID) constant returns (uint) {}

    /// @notice The total number of campaign contributors
    /// @dev The total number of campaign contributors returned as an integer
    /// @param _campaignID (campaign id) The campaign id
    /// @return The total number of campaign contributors
    function totalContributors(uint _campaignID) constant returns (uint) {}

    /// @notice Check to see if account is a campaign contributor
    /// @dev Determine whether a specified account address is a campaign contributor
    /// @param _campaignID (campaign id) The campaign id
    /// @param _contributor (contributor address) The contributors account address
    /// @return is address contributor or not (boolean)
    function isContributor(uint _campaignID, address _contributor) constant returns (bool) {}

    /// @notice Check to see if account is a campaign owner
    /// @dev Determine whether a specified account address is the campaign owner
    /// @param _campaignID (campaign id) The campaign id
    /// @param _owner (owner) The owner address
    /// @return is address the campaign owner or not (boolean)
    function isOwner(uint _campaignID, address _owner) constant returns (bool) {}

    /// @notice Has the campaign failed to reach its goals
    /// @dev Determine whether a campaign has failed to reach its goals
    /// @param _campaignID (campaign id) The campaign id
    /// @return has the campaign failed or not (boolean)
    function hasFailed(uint _campaignID) constant returns (bool) {}

    /// @notice Has the campaign succeeded in reaching its funding goals
    /// @dev Determine whether a campaign has succeeded to reach its goals by the campaign expiry
    /// @param _campaignID (campaign id) The campaign id
    /// @return has the campaign succeeded or not (boolean)
    function isSuccess(uint _campaignID) constant returns (bool) {}

    /// @notice Is the campaign an active campaign (i.e. hasnt failed, succeeded or been paid out)
    /// @dev Returns a boolean, is the campaign active or not
    /// @param _campaignID (campaign id) The campaign id
    /// @return is the campaign active or not (boolean)
    function isActive(uint _campaignID) constant returns (bool) {}

    /// @notice Has the campaign been paid out
    /// @dev Has the funds raised by the campaign been paid out (returns a boolean)
    /// @param _campaignID (campaign id) The campaign id
    /// @return has the campaign been paid out
    function isPaidOut(uint _campaignID) constant returns (bool) {}

    /// @notice The total amount of funds that have been refunded for a specified campaign
    /// @dev The total amount of ether that has been refunded for a specified campaign (funds are integers in the wei denomination)
    /// @param _campaignID (campaign id) The campaign id
    /// @return the total amount of funds refunded (an integer representing wei)
    function totalRefunded(uint _campaignID) constant returns (uint) {}

    /// @notice Has the campaign been completly refunded
    /// @dev Are all funds refunded from this campaign (returns a boolean)
    /// @param _campaignID (campaign id) The campaign id
    /// @return have the funds been refunded or not
    function isRefunded(uint _campaignID) constant returns (bool) {}

    event CampaignCreated(uint indexed _campaignID, address indexed _owner);
    event Contributed(uint indexed _campaignID, address indexed _contributor, uint _amountContributed);
    event Refunded(uint indexed _campaignID, address indexed _contributor, uint _amountRefunded);
    event PaidOut(uint indexed _campaignID, address indexed _beneficiary, uint _amountPaid);
}

/// @title A dispersal mechanism for WeiFund campaigns to disperse tokens
/// @author Nick Dodson <thenickdodson@gmail.com>
contract WeiController is WeiFundConfig {
    uint public campaignID;
    address public weifund;
    address public owner;
    address public token;
	address public total_issued;
    uint public fundingGoal;
    uint public tokenValue;
    bool public autoDisperse;
	uint public version = 1;
	mapping(address => uint) public balances;

	modifier isWeiFund() {
		if(msg.sender != weifund)
			throw;
		else
			_
	}

    modifier validCampaign(uint _campaignID){
        if(campaignID != _campaignID)
            throw;
        else
            _
    }

    function WeiController (address _weifund, address _owner, address _token, uint _tokenValue, bool _autoDisperse) {
        weifund = _weifund;
        owner = _owner;
        token = _token;
        tokenValue = _tokenValue;
        autoDisperse = _autoDisperse;
    }

    function newCampaign(uint _campaignID, address _owner, uint _fundingGoal) isWeiFund {
        if(_fundingGoal <= 0)
            throw;

        campaignID = _campaignID;
        fundingGoal = _fundingGoal;
    }

    function contribute(uint _campaignID, address _contributor, address _beneficiary, uint _amountContributed) isWeiFund validCampaign(_campaignID) {
        uint tokenAmount = _amountContributed / tokenValue;

        balances[_contributor] = tokenAmount;
		total_issued += tokenAmount;

        if(autoDisperse)
            Token(token).transfer(_contributor, tokenAmount);
    }

    function claimTokens() {
        if(autoDisperse)
            throw;

        if(WeiFund(weifund).isSuccess(campaignID) && balances[msg.sender] > 0)
            Token(token).transfer(msg.sender, balances[msg.sender]);

        if(WeiFund(weifund).hasFailed(campaignID) && msg.sender == owner)
            Token(token).transfer(owner, Token(token).balanceOf(this));
    }

    function refund(uint _campaignID, address _contributor, uint _amountRefunded) isWeiFund validCampaign(_campaignID) {
    }

    function payout(uint _campaignID, uint _amountPaid) isWeiFund validCampaign(_campaignID)  {
        uint remainingBalance = Token(token).balanceOf(this);

        if(autoDisperse)
            Token(token).transfer(owner, remainingBalance);
    }
}

/// @title A simple service registry
/// @author Nick Dodson <thenickdodson@gmail.com>
contract ServiceRegistry {
    mapping(address => address) public services;
    event ServiceAdded(address indexed _service, address _sender);

    function addService(address _service) internal {
        services[_service] = msg.sender;
        ServiceAdded(_service, msg.sender);
    }

    function ownerOf(address _service) constant returns (address) {
        return services[_service];
    }

    function isService(address _service) constant returns (bool) {
        if (services[_service] != address(0))
            return true;
    }
}

/// @title This factory allows campaign operators to create safe weifund ready WeiControllers securly
/// @author Nick Dodson <thenickdodson@gmail.com>
contract WeiControllerFactory is ServiceRegistry {
    address public weifund;
	uint public version = 1;

    function WeiControllerFactory (address _weifund) {
        weifund = _weifund;
    }

    function newWeiController (address _owner, address _token, uint _tokenValue, bool _autoDisperse) returns (address newController) {
        newController = address(new WeiController(weifund, _owner, _token, _tokenValue, _autoDisperse));
        addService(newController);
    }
}


Improved Math library

Improved Math library

pragma solidity ^0.4.13;

/**
 * @title Improved DSMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMathLib {

    uint constant WAD = 10 ** 18;
    uint constant RAY = 10 ** 27;

    function add(uint x, uint y) internal returns (uint z) {
        require((z = x + y) >= x);
    }

    function sub(uint x, uint y) internal returns (uint z) {
        require((z = x - y) <= x);
    }

    function mul(uint x, uint y) internal returns (uint z) {
        require(y == 0 || (z = x * y) / y == x);
    }

    function per(uint x, uint y) internal constant returns (uint z) {
        return mul((x / 100), y);
    }

    function min(uint x, uint y) internal returns (uint z) {
        return x <= y ? x : y;
    }

    function max(uint x, uint y) internal returns (uint z) {
        return x >= y ? x : y;
    }

    function imin(int x, int y) internal returns (int z) {
        return x <= y ? x : y;
    }

    function imax(int x, int y) internal returns (int z) {
        return x >= y ? x : y;
    }

    function wmul(uint x, uint y) internal returns (uint z) {
        z = add(mul(x, y), WAD / 2) / WAD;
    }

    function rmul(uint x, uint y) internal returns (uint z) {
        z = add(mul(x, y), RAY / 2) / RAY;
    }

    function wdiv(uint x, uint y) internal returns (uint z) {
        z = add(mul(x, WAD), y / 2) / y;
    }

    function rdiv(uint x, uint y) internal returns (uint z) {
        z = add(mul(x, RAY), y / 2) / y;
    }

    function wper(uint x, uint y) internal constant returns (uint z) {
        return wmul(wdiv(x, 100), y);
    }

    // This famous algorithm is called "exponentiation by squaring"
    // and calculates x^n with x as fixed-point and n as regular unsigned.
    //
    // It's O(log n), instead of O(n) for naive repeated multiplication.
    //
    // These facts are why it works:
    //
    //  If n is even, then x^n = (x^2)^(n/2).
    //  If n is odd,  then x^n = x * x^(n-1),
    //   and applying the equation for even x gives
    //    x^n = x * (x^2)^((n-1) / 2).
    //
    //  Also, EVM division is flooring and
    //    floor[(n-1) / 2] = floor[n / 2].
    //
    function rpow(uint x, uint n) internal returns (uint z) {
        z = n % 2 != 0 ? x : RAY;

        for (n /= 2; n != 0; n /= 2) {
            x = rmul(x, x);

            if (n % 2 != 0) {
                z = rmul(z, x);
            }
        }
    }

}

pragma solidity ^0.4.13;

/**
 * @title Improved SafeMath from https://github.com/OpenZeppelin/zeppelin-solidity/blob/0b9afefa9363df0f00e85057a530c83ca3b9a529/contracts/math/SafeMath.sol
 * @dev Math operations with safety checks that throw on error
 */
library SafeMathLib {

    function mul(uint256 a, uint256 b) internal constant returns (uint256) {
        uint256 c = a * b;
        assert(a == 0 || c / a == b);
        return c;
    }

    function div(uint256 a, uint256 b) internal constant returns (uint256) {
        // assert(b > 0); // Solidity automatically throws when dividing by 0
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return c;
    }

    function sub(uint256 a, uint256 b) internal constant returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    function add(uint256 a, uint256 b) internal constant returns (uint256) {
        uint256 c = a + b;
        assert(c >= a);
        return c;
    }

    function per(uint256 a, uint256 b) internal constant returns (uint256) {
        return mul(div(a, 100), b);
    }
}


Underflow guards

Underflow guards

// Implements standard token interface
// From: https://github.com/slockit/DAO/blob/f640568e694a057aaeb64a0f1049fae27efe818b/Token.sol
// See also https://github.com/ethereum/wiki/wiki/Standardized_Contract_APIs

contract TokenInterface {
    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint256)) allowed;

    /// Total amount of tokens
    uint256 public totalSupply;

    /// @param _owner The address from which the balance will be retrieved
    /// @return The balance
    function balanceOf(address _owner) constant returns (uint256 balance);

    /// @notice Send `_amount` tokens to `_to` from `msg.sender`
    /// @param _to The address of the recipient
    /// @param _amount The amount of tokens to be transferred
    /// @return Whether the transfer was successful or not
    function transfer(address _to, uint256 _amount) returns (bool success);

    /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
    /// is approved by `_from`
    /// @param _from The address of the origin of the transfer
    /// @param _to The address of the recipient
    /// @param _amount The amount of tokens to be transferred
    /// @return Whether the transfer was successful or not
    function transferFrom(address _from, address _to, uint256 _amount) returns (bool success);

    /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
    /// its behalf
    /// @param _spender The address of the account able to transfer the tokens
    /// @param _amount The amount of tokens to be approved for transfer
    /// @return Whether the approval was successful or not
    function approve(address _spender, uint256 _amount) returns (bool success);

    /// @param _owner The address of the account owning tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @return Amount of remaining tokens of _owner that _spender is allowed
    /// to spend
    function allowance(
        address _owner,
        address _spender
    ) constant returns (uint256 remaining);

    event Transfer(address indexed _from, address indexed _to, uint256 _amount);
    event Approval(
        address indexed _owner,
        address indexed _spender,
        uint256 _amount
    );
}

contract DynamicToken is TokenInterface {
  address public contractOwner;
  address[] public accounts;
  mapping (address => bool) public accountExists;
  string[] public proofIds;
  mapping (string => bool) proofIdExists;
  uint256 public maxSupply;
  bool public closed;
  address public upgradedContract;

  event TransferFrom(address indexed _from, address indexed _to,  address indexed _spender, uint256 _amount);
  event Issue(address _from, address _to, uint256 _amount, string _proofId);
  event Burn(address _burnFrom, uint256 _amount, address _burner);
  event Close(address _closedBy);
  event Upgrade(address _upgradedContract);

  function DynamicToken() {
    contractOwner = msg.sender;     // contract owner is contract creator
    closed = false;
    maxSupply = 10**7;
    totalSupply = 0;
  }

  // restrict usage to only the owner
  modifier onlyContractOwner {
    if (msg.sender != contractOwner) throw;
    _
  }

  // check if the contract has been closed
  modifier notClosed {
    if (closed) throw;
    _
  }

  // no ether should be transfered to this contract
  modifier noEther() {if (msg.value > 0) throw; _}

  // accessors

  function getAccounts() noEther constant returns (address[] _accounts) {
    return accounts;
  }

  function balanceOf(address _owner) noEther constant returns(uint256 balance) {
    return balances[_owner];
  }

  function allowance(address _owner, address _spender) noEther constant returns (uint256 remaining) {
    return allowed[_owner][_spender];
  }

  // mutators

  // tokens are only issued in exchange for a unique proof of contribution
  function issue(address _to, uint256 _amount, string _proofId) notClosed onlyContractOwner noEther returns (bool success) {
    if (balances[_to] + _amount < balances[_to]) throw; // Guard against overflow
    if (totalSupply + _amount < totalSupply) throw;     // Guard against overflow  (this should never happen)

    if (proofIdExists[_proofId]) return false;
    if (totalSupply + _amount > maxSupply) return false;

    balances[_to] += _amount;
    totalSupply += _amount;
    _indexAccount(_to);
    _indexProofId(_proofId);
    Issue(msg.sender, _to, _amount, _proofId);
    return true;
  }

  function setMaxSupply(uint256 _maxSupply) notClosed onlyContractOwner noEther returns (bool success) {
    if (_maxSupply < totalSupply) throw;

    maxSupply = _maxSupply;
    return true;
  }

  function transferContractOwnership(address _newOwner) notClosed onlyContractOwner noEther returns (bool success) {
    contractOwner = _newOwner;
    return true;
  }

  function transfer(address _to, uint256 _amount) notClosed noEther returns (bool success) {
    return _transfer(msg.sender, _to, _amount);
  }

  function approve(address _spender, uint256 _amount) notClosed noEther returns (bool success) {
    allowed[msg.sender][_spender] = _amount;
    Approval(msg.sender, _spender, _amount);
    return true;
  }

  function transferFrom(address _from, address _to, uint256 _amount) notClosed noEther returns (bool success) {
    if (_amount > allowed[_from][msg.sender]) return false;

    if (allowed[_from][msg.sender] - _amount > allowed[_from][msg.sender]) throw;  // Guard against underflow

    if (_transfer(_from, _to, _amount)) {
      allowed[_from][msg.sender] -= _amount;
      TransferFrom(_from, _to, msg.sender, _amount);
      return true;
    } else {
      return false;
    }
  }

  function burn(address _burnFrom, uint256 _amount) notClosed noEther returns (bool success) {
    if (_amount > balances[_burnFrom]) return false;

    if (_amount > totalSupply) throw;
    if (!(msg.sender == _burnFrom || msg.sender == contractOwner)) throw;
    if (balances[_burnFrom] - _amount > balances[_burnFrom]) throw;     // Guard against underflow
    if (totalSupply - _amount > totalSupply) throw;                     // Guard against underflow

    balances[_burnFrom] -= _amount;
    totalSupply -= _amount;
    Burn(_burnFrom, _amount, msg.sender);
    return true;
  }

  function upgrade(address _upgradedContract) notClosed onlyContractOwner noEther returns (bool success) {
    upgradedContract = _upgradedContract;
    close();
    Upgrade(_upgradedContract);
    return true;
  }

  function close() notClosed onlyContractOwner noEther returns (bool success) {
    closed = true;
    Close(msg.sender);
    return true;
  }

  function destroyContract() onlyContractOwner noEther {
    selfdestruct(contractOwner);
  }

  // private mutators

  function _transfer(address _from, address _to, uint256 _amount) notClosed private returns (bool success) {
    if (balances[_to] + _amount < balances[_to]) throw;      // Guard against overflow
    if (balances[_from] - _amount > balances[_from]) throw;  // Guard against underflow
    if (_amount > balances[_from]) return false;

    balances[_to] += _amount;
    balances[_from] -= _amount;
    _indexAccount(_to);
    Transfer(_from, _to, _amount);
    return true;
  }

  function _indexAccount(address _account) notClosed private {
    if (accountExists[_account]) return;
    accountExists[_account] = true;
    accounts.push(_account);
  }

  function _indexProofId(string _proofId) notClosed private {
    if (proofIdExists[_proofId]) return;
    proofIdExists[_proofId] = true;
    proofIds.push(_proofId);
  }

  // throw on malformed calls
  function () {
    throw;
  }
}

// Implements standard token interface
// From: https://github.com/slockit/DAO/blob/f640568e694a057aaeb64a0f1049fae27efe818b/Token.sol
// See also https://github.com/ethereum/wiki/wiki/Standardized_Contract_APIs

contract TokenInterface {
    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint256)) allowed;

    /// Total amount of tokens
    uint256 public totalSupply;

    /// @param _owner The address from which the balance will be retrieved
    /// @return The balance
    function balanceOf(address _owner) constant returns (uint256 balance);

    /// @notice Send `_amount` tokens to `_to` from `msg.sender`
    /// @param _to The address of the recipient
    /// @param _amount The amount of tokens to be transferred
    /// @return Whether the transfer was successful or not
    function transfer(address _to, uint256 _amount) returns (bool success);

    /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
    /// is approved by `_from`
    /// @param _from The address of the origin of the transfer
    /// @param _to The address of the recipient
    /// @param _amount The amount of tokens to be transferred
    /// @return Whether the transfer was successful or not
    function transferFrom(address _from, address _to, uint256 _amount) returns (bool success);

    /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
    /// its behalf
    /// @param _spender The address of the account able to transfer the tokens
    /// @param _amount The amount of tokens to be approved for transfer
    /// @return Whether the approval was successful or not
    function approve(address _spender, uint256 _amount) returns (bool success);

    /// @param _owner The address of the account owning tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @return Amount of remaining tokens of _owner that _spender is allowed
    /// to spend
    function allowance(
        address _owner,
        address _spender
    ) constant returns (uint256 remaining);

    event Transfer(address indexed _from, address indexed _to, uint256 _amount);
    event Approval(
        address indexed _owner,
        address indexed _spender,
        uint256 _amount
    );
}

contract DynamicToken is TokenInterface {
  address public contractOwner;
  address[] public accounts;
  mapping (address => bool) public accountExists;
  string[] public proofIds;
  mapping (string => bool) proofIdExists;
  uint256 public maxSupply;
  bool public closed;
  address public upgradedContract;

  event TransferFrom(address indexed _from, address indexed _to,  address indexed _spender, uint256 _amount);
  event Issue(address _from, address _to, uint256 _amount, string _proofId);
  event Burn(address _burnFrom, uint256 _amount, address _burner);
  event Close(address _closedBy);
  event Upgrade(address _upgradedContract);

  function DynamicToken() {
    contractOwner = msg.sender;     // contract owner is contract creator
    closed = false;
    maxSupply = 10**7;
    totalSupply = 0;
  }

  // restrict usage to only the owner
  modifier onlyContractOwner {
    if (msg.sender != contractOwner) throw;
    _
  }

  // check if the contract has been closed
  modifier notClosed {
    if (closed) throw;
    _
  }

  // no ether should be transfered to this contract
  modifier noEther() {if (msg.value > 0) throw; _}

  // accessors

  function getAccounts() noEther constant returns (address[] _accounts) {
    return accounts;
  }

  function balanceOf(address _owner) noEther constant returns(uint256 balance) {
    return balances[_owner];
  }

  function allowance(address _owner, address _spender) noEther constant returns (uint256 remaining) {
    return allowed[_owner][_spender];
  }

  // mutators

  // tokens are only issued in exchange for a unique proof of contribution
  function issue(address _to, uint256 _amount, string _proofId) notClosed onlyContractOwner noEther returns (bool success) {
    if (balances[_to] + _amount < balances[_to]) throw; // Check for overflow
    if (totalSupply + _amount < totalSupply) throw;     // Check for overflow  (this should never happen)

    if (proofIdExists[_proofId]) return false;
    if (totalSupply + _amount > maxSupply) return false;

    balances[_to] += _amount;
    totalSupply += _amount;
    _indexAccount(_to);
    _indexProofId(_proofId);
    Issue(msg.sender, _to, _amount, _proofId);
    return true;
  }

  function setMaxSupply(uint256 _maxSupply) notClosed onlyContractOwner noEther returns (bool success) {
    if (_maxSupply < totalSupply) throw;

    maxSupply = _maxSupply;
    return true;
  }

  function transferContractOwnership(address _newOwner) notClosed onlyContractOwner noEther returns (bool success) {
    contractOwner = _newOwner;
    return true;
  }

  function transfer(address _to, uint256 _amount) notClosed noEther returns (bool success) {
    return _transfer(msg.sender, _to, _amount);
  }

  function approve(address _spender, uint256 _amount) notClosed noEther returns (bool success) {
    allowed[msg.sender][_spender] = _amount;
    Approval(msg.sender, _spender, _amount);
    return true;
  }

  function transferFrom(address _from, address _to, uint256 _amount) notClosed noEther returns (bool success) {
    if (_amount > allowed[_from][msg.sender]) return false;

    if (_transfer(_from, _to, _amount)) {
      allowed[_from][msg.sender] -= _amount;
      TransferFrom(_from, _to, msg.sender, _amount);
      return true;
    } else {
      return false;
    }
  }

  function burn(address _burnFrom, uint256 _amount) notClosed noEther returns (bool success) {
    if( !(msg.sender == _burnFrom || msg.sender == contractOwner) ) throw;

    if (_amount > balances[_burnFrom]) return false;
    if (_amount > totalSupply) return false;          // should never happen

    balances[_burnFrom] -= _amount;
    totalSupply -= _amount;
    Burn(_burnFrom, _amount, msg.sender);
    return true;
  }

  function upgrade(address _upgradedContract) notClosed onlyContractOwner noEther returns (bool success) {
    upgradedContract = _upgradedContract;
    close();
    Upgrade(_upgradedContract);
    return true;
  }

  function close() notClosed onlyContractOwner noEther returns (bool success) {
    closed = true;
    Close(msg.sender);
    return true;
  }

  function destroyContract() onlyContractOwner noEther {
    selfdestruct(contractOwner);
  }

  // private mutators

  function _transfer(address _from, address _to, uint256 _amount) notClosed private returns (bool success) {
    if (balances[_to] + _amount < balances[_to]) throw;  // Check for overflow
    if (_amount > balances[_from]) return false;

    balances[_to] += _amount;
    balances[_from] -= _amount;
    _indexAccount(_to);
    Transfer(_from, _to, _amount);
    return true;
  }

  function _indexAccount(address _account) notClosed private {
    if (accountExists[_account]) return;
    accountExists[_account] = true;
    accounts.push(_account);
  }

  function _indexProofId(string _proofId) notClosed private {
    if (proofIdExists[_proofId]) return;
    proofIdExists[_proofId] = true;
    proofIds.push(_proofId);
  }

  // throw on malformed calls
  function () {
    throw;
  }
}