MeterPoint and Delivery for PowerBucket reorganized in SmartContract

pragma solidity ^0.4.10;
/**
 * StromDAO Business Objects
 * ====================================================================
 * Upper level business objects required for power delivery on a public
 * energy distribution system. Defines PowerDelivery as digital asset
 * used for transaction data and entities (roles) for master data.
 *
 * @author Thorsten Zoerner <thorsten.zoerner(at)stromdao.de)
 **/

contract owned {
    address public owner;

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

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

    modifier onlyOwnerAsOriginator {
        if (tx.origin != owner) throw;
        _;
    }

    function transferOwnership(address newOwner) onlyOwner {
        owner = newOwner;
    }
}

/** Roles and Responsibility */
contract Role is owned { string  public role = 'stub'; } /**< Abstract stub for Roles */

contract RoleMPO is Role { string  public role = 'mpo'; } /**< Role Inheritance for Meter Point Operator */

contract RoleDSO is Role { string  public role = 'dso'; } /**< Role Inheritance for Grid Operators */

contract RoleProvider is Role { string  public role = 'provider'; } /**< Role Inheritance for Utilities */

contract RoleActor is Role { string public role = 'actor'; } /**< Role Inheritance for general actors (0) */

contract RoleSource is Role { string public role = 'sourceOfEnergy'; } /**< Role provides Source of Energy */
contract RoleTarget is Role { string public role = 'targetOfEnergy'; } /**< Role consume/uses Energy  */

/**
 * RoleLookup
 * ====================================================================
 * Provides entity relation model (yellowpages, who-implements-what)
 * to StromDAO Business Objects. A single consensframe must always share
 * a single RoleLookup deployment.
 */
contract RoleLookup is owned {
    mapping(uint256 => Role) public roles;
    mapping(address=>mapping(address=>address)) public relations;

    event Relation(address _from,Role _for, address _to);

    function RoleLookup() {
        roles[0]= (Role (new RoleActor())); // Generic Role as actor
        roles[1]= (Role (new RoleMPO()));
        roles[2]= (Role (new RoleDSO()));
        roles[3]= (Role (new RoleProvider()));
        roles[4]= (Role (new RoleSource()));
        roles[5]= (Role (new RoleTarget()));
    }
    function setRelation(Role _for,address _from) {
        relations[msg.sender][_for]=_from;
        Relation(_from,_for,msg.sender);
    }
    function setRelationOnBehalf(Role _for,address _from,address _to)  onlyOwnerAsOriginator {
        relations[_to][_for]=_from;
        Relation(_from,_for,msg.sender);
    }

    function deleteRelation(Role _for, address _to) onlyOwner {
        relations[_to][_for]=address(0);
        Relation(_to,_for,address(0));
    }

    function replaceRole(uint256 _role_id,Role _role) onlyOwner {
        roles[_role_id]=_role;
    }
}

/**
 * MeterPointOperator
 * ====================================================================
 * An entity that manages several meters
 */

contract MPO is RoleMPO {
    RoleLookup public roles;

    event StatusChange(address _meter_point,bool _is_approved);
    event ProcessedClearance(address _meterpoint,Clearable _clearable,uint256 power);
    event IssuedDelivery(address delivery,address _meterpoint,uint256 _roleId,uint256 fromTime,uint256 toTime,uint256 power);
    mapping(address=>uint256) public approvedMeterPoints;
    mapping(address=>reading) public readings;
    mapping(address=>reading) public processed;
    mapping(address=>Delivery) public lastDelivery;
    mapping(address=>mapping(address=>address)) public issuedDeliverables;
    struct reading {
        uint256 time;
        uint256 power;

    }
    function MPO(RoleLookup _roles) {
        roles=_roles;
    }

    function approveMP(address _meter_point,uint256 role_id) onlyOwner {
        approvedMeterPoints[_meter_point]=role_id;
        StatusChange(_meter_point,true);
    }

    function declineMP(address _meter_point) onlyOwner {
        approvedMeterPoints[_meter_point]=0;
        StatusChange(_meter_point,false);
    }

    function storeReading(uint256 _reading) {
        if((approvedMeterPoints[msg.sender]!=4)&&(approvedMeterPoints[msg.sender]!=5)) throw;
        if(readings[msg.sender].power>_reading) throw;
        if(readings[msg.sender].power<_reading) {
            Delivery delivery = new Delivery(roles,msg.sender,approvedMeterPoints[msg.sender],readings[msg.sender].time,now,_reading-readings[msg.sender].power);
            IssuedDelivery(address(delivery),msg.sender,approvedMeterPoints[msg.sender],readings[msg.sender].time,now,_reading-readings[msg.sender].power);
            issuedDeliverables[msg.sender][address(lastDelivery[msg.sender])]=address(delivery);
            lastDelivery[msg.sender]=delivery;
            delivery.transferOwnership(msg.sender);
        }
        readings[msg.sender]=reading(now,_reading);
    }

    function process(address _meterpoint,Clearable _clearable) {
        /*
        reading last_reading = readings[_meterpoint];
        reading last_processed = processed[_meterpoint];
        if(last_processed.power!=0) {
            uint256 delta_power = last_reading.power - last_processed.power;
            if(delta_power>0) {
                last_reading.power -= _clearable.doClearingGridIn(delta_power);
                ProcessedClearance(_meterpoint,_clearable,delta_power);
            }
        }
        processed[_meterpoint]=last_reading;
        */

    }
}

contract Provider is RoleProvider {
    RoleLookup public roles;

    function Provider(RoleLookup _roles) {
        roles=_roles;
    }

    function process(address _meterpoint)  {
        MPO mpo = MPO(roles.relations(_meterpoint,roles.roles(1)));
        DSO dso = DSO(roles.relations(_meterpoint,roles.roles(2)));
        mpo.process(_meterpoint,dso.clearances(_meterpoint));
    }
}

contract DSO is RoleDSO {
    RoleLookup public roles;
    ClearablesLink public cl;
    Clearable public last_clearable_from;
    mapping(address=>Clearable) public clearances;
    mapping(address=>bool) public approvedProvider;
    function DSO(RoleLookup _roles) {
        roles=_roles;
    }

    function approveConnection(address _address,uint256 _base_from_time,uint256 _base_to_time,uint256 _base_powerIn,uint256 _base_powerOut) onlyOwner {
        Clearable base_clearance = clearances[_address];
        if(address(base_clearance)!=0) {
            _base_from_time=base_clearance.valid_untilTime();
        }
        if(_base_from_time==0) _base_from_time=now;
        if(_base_to_time==0) _base_to_time= _base_from_time+86400;
        base_clearance = new Clearable();
        base_clearance.setFromTime(_base_from_time);
        base_clearance.setUntilTime(_base_to_time);
        base_clearance.setPowerOut(_base_powerIn);
        base_clearance.setPowerIn(_base_powerOut);
        clearances[_address]=base_clearance;
        // roles.setRelationOnBehalf(roles.roles(2),this,tx.origin); ! Needs to be set by Account itself !
    }

    function addClearableFrom(address from,Clearable _clearable) {
        Clearable clearable_from = clearances[from];
        clearable_from.setChild(_clearable);
    }

    function addClearableTo(address to,Clearable _clearable) {
        Clearable clearable_to = clearances[to];
        clearable_to.setChild(_clearable);
    }
    /*
    function addClearableTo(ClearablesLink _clearableLink) {
        // if(clearances[msg.sender].valid_untilTime()<now) throw; // if we do not have a valid base clearable (approve Connection required). ! Not possible to throw !
        // TODO: Should check approved Provider
        cl=_clearableLink;

        //clearances[msg.sender].setChild(_clearable);
        address to = roles.relations(_clearableLink,roles.roles(5));

        if(address(roles.relations(to,roles.roles(2)))==address(this)) {
            Clearable clearable_to = clearances[to];
            clearable_to.setChild(_clearableLink.clearable_to());
        }

    }
    */
    function providerAllowance(address dso,bool allow) onlyOwner {
        approvedProvider[dso]=allow;
    }
}

contract Clearable is owned {

    uint256 public valid_fromTime;          /**< unit: seconds since 1.1.1970 (Unix-Time) */
    uint256 public valid_untilTime;         /**< unit: seconds since 1.1.1970 (Unix-Time) */
    uint256 public valid_powerIn;             /**< unit: Watt-hours (Wh) */
    uint256 public valid_powerOut;             /**< unit: Watt-hours (Wh) */

    uint256 public buffersize;               /**< unit: Watt (W) */
    uint256 public bufferload;              /**< unit: Watt (W) */
    uint256 public cleared_power;

    Clearable public child;
    event ClearedDelivery(uint256 _power,uint256 valid_power,uint256 cleared_power);

    function setFromTime(uint256 _from) onlyOwner { valid_fromTime = _from; }
    function setUntilTime(uint256 _until) onlyOwner { valid_untilTime = _until; }
    function setPowerIn(uint256 _power) onlyOwner { valid_powerIn = _power; }
    function setPowerOut(uint256 _power) onlyOwner { valid_powerOut = _power; }
    function setChild(Clearable _child) {
        if(address(child)==address(0)) {
            child = _child;
        } else {
            child.setChild(_child);
        }

    }    //TODO Add onlyOwner again
    function setBuffer(uint256 _buffersize) onlyOwner { buffersize = _buffersize; }

    /** doClearing(uint256 _power)
     * @param _power Amount of Wh that is clearable
     * returns Remaining (uncleared) power
     */
    function doClearingGridIn(uint256 _power) returns(uint256) {
        // Check if valid timeframe
        if(valid_fromTime>now) return(0);
        if(valid_untilTime<now) return(0);

        // First delegate clearing to childs
        if(address(child)!=address(0)) {
            _power=child.doClearingGridIn(_power);
        }
        _power=buffer(_power);
        // Than substract our clearance.
        if(_power>0) {
            if(valid_powerIn<_power) { _power=valid_powerIn;  cleared_power+=valid_powerIn;  } else { valid_powerIn-=_power; cleared_power+=_power; _power=0;}
            ClearedDelivery(_power,valid_powerIn,cleared_power);
        }

        //Return remaining to clear.
        return _power;
    }
     function doClearingGridOut(uint256 _power) returns(uint256) {
        // Check if valid timeframe
        if(valid_fromTime>now) return(0);
        if(valid_untilTime<now) return(0);

        // First delegate clearing to childs
        if(address(child)!=address(0)) {
            _power=child.doClearingGridOut(_power);
        }
        _power=buffer(_power);
        // Than substract our clearance.
        if(_power>0) {
            if(valid_powerOut<_power) { _power=valid_powerOut;  cleared_power+=valid_powerOut;  } else { valid_powerOut-=_power; cleared_power+=_power; _power=0;}
            ClearedDelivery(_power,valid_powerOut,cleared_power);
        }

        //Return remaining to clear.
        return _power;
    }

    function buffer(uint256 _power) private returns(uint256) {
        if(_power>0) {
            var possible_load = buffersize-bufferload;
            if(possible_load>0) {
                if(possible_load>_power) { bufferload+=_power; _power=0;} else { bufferload+=possible_load; _power-=possible_load; }
            }

        } else {
            // unload buffer...
            _power=bufferload;
            bufferload=0;

        }
        return _power;
    }
}

/**
 * ClearablesLink
 * ====================================================================
 * Connects two clearables for Peer-2-Peer "flow" of energy delivery
 * introduces a buffer to limit speed of flow.
 */
contract ClearablesLink is owned {

    RoleLookup public roles;
    address public from;                    /* Energy Source */
    address public to;                      /* Energy To */

    Clearable public clearable_from;
    Clearable public clearable_to;

    function ClearablesLink(RoleLookup _roles,uint256 _validFrom,uint256 _validUntil,uint256 _quantity,uint256 _buffer,address _from, address _to)  {
        roles=_roles;

        clearable_from = new Clearable();
        clearable_from.setFromTime(_validFrom);
        clearable_from.setUntilTime(_validUntil);
        clearable_from.setPowerIn(_quantity);
        from=_from;
        roles.setRelation(roles.roles(4),from);

        clearable_to = new Clearable();
        clearable_to.setFromTime(_validFrom);
        clearable_to.setUntilTime(_validUntil);
        clearable_to.setPowerOut(_quantity);
        to=_to;
        roles.setRelation(roles.roles(5),to);

        DSO dso_from = DSO(roles.relations(_from,roles.roles(2)));
        DSO dso_to = DSO(roles.relations(_to,roles.roles(2)));

        dso_from.addClearableFrom(from,clearable_from);
        dso_to.addClearableTo(to,clearable_to);
        //if(address(dso_from)!= address(dso_to)) { dso_to.addClearableLink(this); }

    }
}

/**
 * PowerDelivery
 * ====================================================================
 * Asset that is megotiated and controlled by consens. Covering
 * a power delivery between two parties.
 */
contract PowerDelivery {

    address public owner;
    RoleLookup public roles;

    address public from;                /** Energy From **/
    address public to;                  /** Energy To **/

    uint256 public start;               /**< unit: seconds since 1.1.1970 (Unix-Time) */
    uint256 public duration;            /**< unit: seconds */

    uint256 public quantity;            /**< unit: Watt-Hour (Wh) */
    uint256 public price;               /**< unit: 1/1000 Euro-Cent */
    uint256 public buffer;              /**< unit: Watt-Hour (Wh) - of inbalance buffer */
    ClearablesLink public clearabalelink;

    function PowerDelivery(RoleLookup _roles,uint256 _start,uint256 _duration, uint256 _quantity, uint256 _price,uint256 _buffer) {
        if(_start == 0 ) _start=now;
        start = _start;
        duration= _duration;
        quantity = _quantity;
        price = _price;
        roles=_roles;
        buffer = _buffer;
        owner = msg.sender;
    }

    /** Helper to validate if there is a consense that entity (address) becomes actor in a PowerDelivery-Contract */
    function validateConnectivity(address _address)  {
         if(roles.relations(_address,roles.roles(1))==address(0)) throw; // No MeterPointOperator available
         address mpo_adr = roles.relations(_address,roles.roles(1));
         MPO mpo = MPO(mpo_adr);
         if(mpo.approvedMeterPoints(_address)==0) throw; // MPO refuses to have actor

          if(roles.relations(_address,roles.roles(2))==address(0)) throw; // No DSO available
         address dso_adr = roles.relations(_address,roles.roles(2));
         DSO dso = DSO(dso_adr);

         if(dso.clearances(_address).valid_untilTime()<start) throw;

         // Check if provider is allowed to push clearance
         address provider_adr = roles.relations(_address,roles.roles(3));
         // TODO Check (traps at the moment!): if(!dso.approvedProvider(provider_adr)) throw;

         // We do not need to Return something, as we throw on execpetion
    }

    function hasParties() {
        if((address(from)!=0)&&(address(to)!=0)) {
            // Clearables may be commited now
           clearabalelink = new ClearablesLink(roles,start,start+duration,quantity,buffer,from,to);
        }

    }

    /** Managing entity relations - Role "From" for SmartContract */
    function becomeFrom() {
        if(address(from)!=0) throw;
        // Only allow "from" if consens about MPO
        validateConnectivity(msg.sender);
        from=msg.sender;
        //hasParties(); //TODO Reenable
    }

    /** Managing entity relations - Role "To" for SmartContract */
    function becomeTo() {
        if(address(to)!=0) throw;
        // Only allow "from" if consens about MPO
        validateConnectivity(msg.sender);
        to=msg.sender;
        //hasParties(); //TODO Reenable
    }

}

contract Delivery is owned{
    RoleLookup public roles;
    address public dso;
    uint256 public role;

    struct Deliverable {
        uint256 startTime;
        uint256 endTime;
        uint256 power;
        address resolution;
    }

    Deliverable public deliverable;

    function getDeliverableStartTime() returns(uint256) { return(deliverable.startTime);}
    function getDeliverableEndTime() returns(uint256) { return(deliverable.endTime);}
    function getDeliverablePower() returns(uint256) { return(deliverable.power);}
    function getDeliverableResolution() returns(address) { return(deliverable.resolution);}

    function Delivery(RoleLookup _roles,address _meterpoint,uint256 _mprole,uint256 _startTime,uint256 _endTime, uint256 _power)  {
        roles=_roles;
        role=_mprole;
        deliverable=Deliverable(_startTime,_endTime,_power,address(0));
        // check sender is MPO for MP
        if(msg.sender!=roles.relations(_meterpoint,roles.roles(1))) throw;
        dso=roles.relations(_meterpoint,roles.roles(2));
        if(address(0)==dso) throw;

    }

    function includeDelivery(Delivery _delivery) onlyOwner {
        if(_delivery.owner()!=address(this)) throw; // Operation only allowed if not owned by this Delivery

         Deliverable memory _deliverable = Deliverable(_delivery.getDeliverableStartTime(),_delivery.getDeliverableEndTime(),_delivery.getDeliverablePower(),_delivery.getDeliverableResolution());

        if(deliverable.startTime>_deliverable.startTime) deliverable.startTime=_deliverable.startTime;
        if(deliverable.endTime<_deliverable.endTime) deliverable.endTime=_deliverable.endTime;
        if(_delivery.role()==role) {
            // add
            deliverable.power+=_deliverable.power;
        } else {
            // substract (Need to change Role, if lt 0)
            if(_deliverable.power>deliverable.power) throw; // Not a include!
            deliverable.power-=_deliverable.power;
        }
        _delivery.destructWith(this);
    }

    function destructWith(Delivery _delivery) onlyOwner {
        if(address(deliverable.resolution)!=0) throw;
        deliverable.power=0;
        deliverable.resolution=address(_delivery);

    }
}
contract IT_Connectivity is owned {
    RoleLookup public roles;
    DSO public dso;

    function IT_Connectivity(RoleLookup _roles) {
        roles=_roles;
        dso = new DSO(roles);
        dso.approveConnection(this,now,now+3600,1000,1000);
        dso.approveConnection(msg.sender,now,now+3600,1000,1000);
    }

    function becomeInstanceOwner() onlyOwner {
        dso.transferOwnership(msg.sender);
    }
}

/**
 * Integration Test Provider
 * ====================================================================
 * Integration testing for consens of Business Object Model (Framework)
 *
 */
contract IT_Provider is owned {
    RoleLookup public roles;
    Provider public provider;

    function IT_Provider(RoleLookup _roles) {
        roles = _roles;
        provider=new Provider(_roles);
    }

    function becomeInstanceOwner() onlyOwner {
        provider.transferOwnership(msg.sender);
    }
}

pragma solidity ^0.4.10;
/**
 * StromDAO Business Objects
 * ====================================================================
 * Upper level business objects required for power delivery on a public
 * energy distribution system. Defines PowerDelivery as digital asset
 * used for transaction data and entities (roles) for master data.
 *
 * @author Thorsten Zoerner <thorsten.zoerner(at)stromdao.de)
 **/

contract owned {
    address public owner;

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

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

    modifier onlyOwnerAsOriginator {
        if (tx.origin != owner) throw;
        _;
    }

    function transferOwnership(address newOwner) onlyOwner {
        owner = newOwner;
    }
}

/** Roles and Responsibility */
contract Role is owned { string  public role = 'stub'; } /**< Abstract stub for Roles */

contract RoleMPO is Role { string  public role = 'mpo'; } /**< Role Inheritance for Meter Point Operator */

contract RoleDSO is Role { string  public role = 'dso'; } /**< Role Inheritance for Grid Operators */

contract RoleProvider is Role { string  public role = 'provider'; } /**< Role Inheritance for Utilities */

contract RoleActor is Role { string public role = 'actor'; } /**< Role Inheritance for general actors (0) */

contract RoleSource is Role { string public role = 'sourceOfEnergy'; } /**< Role provides Source of Energy */
contract RoleTarget is Role { string public role = 'targetOfEnergy'; } /**< Role consume/uses Energy  */

/**
 * RoleLookup
 * ====================================================================
 * Provides entity relation model (yellowpages, who-implements-what)
 * to StromDAO Business Objects. A single consensframe must always share
 * a single RoleLookup deployment.
 */
contract RoleLookup is owned {
    mapping(uint256 => Role) public roles;
    mapping(address=>mapping(address=>address)) public relations;

    event Relation(address _from,Role _for, address _to);

    function RoleLookup() {
        roles[0]= (Role (new RoleActor())); // Generic Role as actor
        roles[1]= (Role (new RoleMPO()));
        roles[2]= (Role (new RoleDSO()));
        roles[3]= (Role (new RoleProvider()));
        roles[4]= (Role (new RoleSource()));
        roles[5]= (Role (new RoleTarget()));
    }
    function setRelation(Role _for,address _from) {
        relations[msg.sender][_for]=_from;
        Relation(_from,_for,msg.sender);
    }
    function setRelationOnBehalf(Role _for,address _from,address _to)  onlyOwnerAsOriginator {
        relations[_to][_for]=_from;
        Relation(_from,_for,msg.sender);
    }

    function deleteRelation(Role _for, address _to) onlyOwner {
        relations[_to][_for]=address(0);
        Relation(_to,_for,address(0));
    }

    function replaceRole(uint256 _role_id,Role _role) onlyOwner {
        roles[_role_id]=_role;
    }
}

/**
 * MeterPointOperator
 * ====================================================================
 * An entity that manages several meters
 */

contract MPO is RoleMPO {
    RoleLookup public roles;

    event StatusChange(address _meter_point,bool _is_approved);
    event ProcessedClearance(address _meterpoint,Clearable _clearable,uint256 power);
    event IssuedDelivery(address delivery,address _meterpoint,uint256 fromTime,uint256 toTime,uint256 power);
    mapping(address=>bool) public approvedMeterPoints;
    mapping(address=>reading) public readings;
    mapping(address=>reading) public processed;
    mapping(address=>Delivery) public lastDelivery;

    struct reading {
        uint256 time;
        uint256 power;

    }
    function MPO(RoleLookup _roles) {
        roles=_roles;
    }

    function approveMP(address _meter_point) onlyOwner {
        approvedMeterPoints[_meter_point]=true;
        StatusChange(_meter_point,true);
    }

    function declineMP(address _meter_point) onlyOwner {
        approvedMeterPoints[_meter_point]=false;
        StatusChange(_meter_point,false);
    }

    function storeReading(uint256 _reading) {
        if(approvedMeterPoints[msg.sender]==false) throw;
        if(readings[msg.sender].power<_reading) {
            Delivery delivery = new Delivery(roles,msg.sender,readings[msg.sender].time,now,_reading-readings[msg.sender].power);
            IssuedDelivery(address(delivery),msg.sender,readings[msg.sender].time,now,_reading-readings[msg.sender].power);
            lastDelivery[msg.sender]=delivery;
            delivery.transferOwnership(msg.sender);
        }
        readings[msg.sender]=reading(now,_reading);
    }

    function process(address _meterpoint,Clearable _clearable) {
        reading last_reading = readings[_meterpoint];
        reading last_processed = processed[_meterpoint];
        if(last_processed.power!=0) {
            uint256 delta_power = last_reading.power - last_processed.power;
            if(delta_power>0) {
                last_reading.power -= _clearable.doClearingGridIn(delta_power);
                ProcessedClearance(_meterpoint,_clearable,delta_power);
            }
        }
        processed[_meterpoint]=last_reading;

    }
}

contract Provider is RoleProvider {
    RoleLookup public roles;

    function Provider(RoleLookup _roles) {
        roles=_roles;
    }

    function process(address _meterpoint)  {
        MPO mpo = MPO(roles.relations(_meterpoint,roles.roles(1)));
        DSO dso = DSO(roles.relations(_meterpoint,roles.roles(2)));
        mpo.process(_meterpoint,dso.clearances(_meterpoint));
    }
}

contract DSO is RoleDSO {
    RoleLookup public roles;
    ClearablesLink public cl;
    Clearable public last_clearable_from;
    mapping(address=>Clearable) public clearances;
    mapping(address=>bool) public approvedProvider;
    function DSO(RoleLookup _roles) {
        roles=_roles;
    }

    function approveConnection(address _address,uint256 _base_from_time,uint256 _base_to_time,uint256 _base_powerIn,uint256 _base_powerOut) onlyOwner {
        Clearable base_clearance = clearances[_address];
        if(address(base_clearance)!=0) {
            _base_from_time=base_clearance.valid_untilTime();
        }
        if(_base_from_time==0) _base_from_time=now;
        if(_base_to_time==0) _base_to_time= _base_from_time+86400;
        base_clearance = new Clearable();
        base_clearance.setFromTime(_base_from_time);
        base_clearance.setUntilTime(_base_to_time);
        base_clearance.setPowerOut(_base_powerIn);
        base_clearance.setPowerIn(_base_powerOut);
        clearances[_address]=base_clearance;
        // roles.setRelationOnBehalf(roles.roles(2),this,tx.origin); ! Needs to be set by Account itself !
    }

    function addClearableFrom(address from,Clearable _clearable) {
        Clearable clearable_from = clearances[from];
        clearable_from.setChild(_clearable);
    }

    function addClearableTo(address to,Clearable _clearable) {
        Clearable clearable_to = clearances[to];
        clearable_to.setChild(_clearable);
    }
    /*
    function addClearableTo(ClearablesLink _clearableLink) {
        // if(clearances[msg.sender].valid_untilTime()<now) throw; // if we do not have a valid base clearable (approve Connection required). ! Not possible to throw !
        // TODO: Should check approved Provider
        cl=_clearableLink;

        //clearances[msg.sender].setChild(_clearable);
        address to = roles.relations(_clearableLink,roles.roles(5));

        if(address(roles.relations(to,roles.roles(2)))==address(this)) {
            Clearable clearable_to = clearances[to];
            clearable_to.setChild(_clearableLink.clearable_to());
        }

    }
    */
    function providerAllowance(address dso,bool allow) onlyOwner {
        approvedProvider[dso]=allow;
    }
}

contract Clearable is owned {

    uint256 public valid_fromTime;          /**< unit: seconds since 1.1.1970 (Unix-Time) */
    uint256 public valid_untilTime;         /**< unit: seconds since 1.1.1970 (Unix-Time) */
    uint256 public valid_powerIn;             /**< unit: Watt-hours (Wh) */
    uint256 public valid_powerOut;             /**< unit: Watt-hours (Wh) */

    uint256 public buffersize;               /**< unit: Watt (W) */
    uint256 public bufferload;              /**< unit: Watt (W) */
    uint256 public cleared_power;

    Clearable public child;
    event ClearedDelivery(uint256 _power,uint256 valid_power,uint256 cleared_power);

    function setFromTime(uint256 _from) onlyOwner { valid_fromTime = _from; }
    function setUntilTime(uint256 _until) onlyOwner { valid_untilTime = _until; }
    function setPowerIn(uint256 _power) onlyOwner { valid_powerIn = _power; }
    function setPowerOut(uint256 _power) onlyOwner { valid_powerOut = _power; }
    function setChild(Clearable _child) {
        if(address(child)==address(0)) {
            child = _child;
        } else {
            child.setChild(_child);
        }

    }    //TODO Add onlyOwner again
    function setBuffer(uint256 _buffersize) onlyOwner { buffersize = _buffersize; }

    /** doClearing(uint256 _power)
     * @param _power Amount of Wh that is clearable
     * returns Remaining (uncleared) power
     */
    function doClearingGridIn(uint256 _power) returns(uint256) {
        // Check if valid timeframe
        if(valid_fromTime>now) return(0);
        if(valid_untilTime<now) return(0);

        // First delegate clearing to childs
        if(address(child)!=address(0)) {
            _power=child.doClearingGridIn(_power);
        }
        _power=buffer(_power);
        // Than substract our clearance.
        if(_power>0) {
            if(valid_powerIn<_power) { _power=valid_powerIn;  cleared_power+=valid_powerIn;  } else { valid_powerIn-=_power; cleared_power+=_power; _power=0;}
            ClearedDelivery(_power,valid_powerIn,cleared_power);
        }

        //Return remaining to clear.
        return _power;
    }
     function doClearingGridOut(uint256 _power) returns(uint256) {
        // Check if valid timeframe
        if(valid_fromTime>now) return(0);
        if(valid_untilTime<now) return(0);

        // First delegate clearing to childs
        if(address(child)!=address(0)) {
            _power=child.doClearingGridOut(_power);
        }
        _power=buffer(_power);
        // Than substract our clearance.
        if(_power>0) {
            if(valid_powerOut<_power) { _power=valid_powerOut;  cleared_power+=valid_powerOut;  } else { valid_powerOut-=_power; cleared_power+=_power; _power=0;}
            ClearedDelivery(_power,valid_powerOut,cleared_power);
        }

        //Return remaining to clear.
        return _power;
    }

    function buffer(uint256 _power) private returns(uint256) {
        if(_power>0) {
            var possible_load = buffersize-bufferload;
            if(possible_load>0) {
                if(possible_load>_power) { bufferload+=_power; _power=0;} else { bufferload+=possible_load; _power-=possible_load; }
            }

        } else {
            // unload buffer...
            _power=bufferload;
            bufferload=0;

        }
        return _power;
    }
}

/**
 * ClearablesLink
 * ====================================================================
 * Connects two clearables for Peer-2-Peer "flow" of energy delivery
 * introduces a buffer to limit speed of flow.
 */
contract ClearablesLink is owned {

    RoleLookup public roles;
    address public from;                    /* Energy Source */
    address public to;                      /* Energy To */

    Clearable public clearable_from;
    Clearable public clearable_to;

    function ClearablesLink(RoleLookup _roles,uint256 _validFrom,uint256 _validUntil,uint256 _quantity,uint256 _buffer,address _from, address _to)  {
        roles=_roles;

        clearable_from = new Clearable();
        clearable_from.setFromTime(_validFrom);
        clearable_from.setUntilTime(_validUntil);
        clearable_from.setPowerIn(_quantity);
        from=_from;
        roles.setRelation(roles.roles(4),from);

        clearable_to = new Clearable();
        clearable_to.setFromTime(_validFrom);
        clearable_to.setUntilTime(_validUntil);
        clearable_to.setPowerOut(_quantity);
        to=_to;
        roles.setRelation(roles.roles(5),to);

        DSO dso_from = DSO(roles.relations(_from,roles.roles(2)));
        DSO dso_to = DSO(roles.relations(_to,roles.roles(2)));

        dso_from.addClearableFrom(from,clearable_from);
        dso_to.addClearableTo(to,clearable_to);
        //if(address(dso_from)!= address(dso_to)) { dso_to.addClearableLink(this); }

    }
}

/**
 * PowerDelivery
 * ====================================================================
 * Asset that is megotiated and controlled by consens. Covering
 * a power delivery between two parties.
 */
contract PowerDelivery {

    address public owner;
    RoleLookup public roles;

    address public from;                /** Energy From **/
    address public to;                  /** Energy To **/

    uint256 public start;               /**< unit: seconds since 1.1.1970 (Unix-Time) */
    uint256 public duration;            /**< unit: seconds */

    uint256 public quantity;            /**< unit: Watt-Hour (Wh) */
    uint256 public price;               /**< unit: 1/1000 Euro-Cent */
    uint256 public buffer;              /**< unit: Watt-Hour (Wh) - of inbalance buffer */
    ClearablesLink public clearabalelink;

    function PowerDelivery(RoleLookup _roles,uint256 _start,uint256 _duration, uint256 _quantity, uint256 _price,uint256 _buffer) {
        if(_start == 0 ) _start=now;
        start = _start;
        duration= _duration;
        quantity = _quantity;
        price = _price;
        roles=_roles;
        buffer = _buffer;
        owner = msg.sender;
    }

    /** Helper to validate if there is a consense that entity (address) becomes actor in a PowerDelivery-Contract */
    function validateConnectivity(address _address)  {
         if(roles.relations(_address,roles.roles(1))==address(0)) throw; // No MeterPointOperator available
         address mpo_adr = roles.relations(_address,roles.roles(1));
         MPO mpo = MPO(mpo_adr);
         if(!mpo.approvedMeterPoints(_address)) throw; // MPO refuses to have actor

          if(roles.relations(_address,roles.roles(2))==address(0)) throw; // No DSO available
         address dso_adr = roles.relations(_address,roles.roles(2));
         DSO dso = DSO(dso_adr);

         if(dso.clearances(_address).valid_untilTime()<start) throw;

         // Check if provider is allowed to push clearance
         address provider_adr = roles.relations(_address,roles.roles(3));
         // TODO Check (traps at the moment!): if(!dso.approvedProvider(provider_adr)) throw;

         // We do not need to Return something, as we throw on execpetion
    }

    function hasParties() {
        if((address(from)!=0)&&(address(to)!=0)) {
            // Clearables may be commited now
           clearabalelink = new ClearablesLink(roles,start,start+duration,quantity,buffer,from,to);
        }

    }

    /** Managing entity relations - Role "From" for SmartContract */
    function becomeFrom() {
        if(address(from)!=0) throw;
        // Only allow "from" if consens about MPO
        validateConnectivity(msg.sender);
        from=msg.sender;
        //hasParties(); //TODO Reenable
    }

    /** Managing entity relations - Role "To" for SmartContract */
    function becomeTo() {
        if(address(to)!=0) throw;
        // Only allow "from" if consens about MPO
        validateConnectivity(msg.sender);
        to=msg.sender;
        //hasParties(); //TODO Reenable
    }

}

contract Delivery is owned{
    RoleLookup public roles;
    address public dso;

    struct Deliverable {
        uint256 startTime;
        uint256 endTime;
        uint256 power;
    }

    Deliverable public deliverable;

    function Delivery(RoleLookup _roles,address _meterpoint,uint256 _startTime,uint256 _endTime, uint256 _power)  {
        roles=_roles;
        deliverable=Deliverable(_startTime,_endTime,_power);
        // check sender is MPO for MP
        if(msg.sender!=roles.relations(_meterpoint,roles.roles(1))) throw;
        dso=roles.relations(_meterpoint,roles.roles(2));
        if(address(0)==dso) throw;

    }

    function includeDelivery(Delivery _delivery) onlyOwner {
        deliverable.power+=_delivery.excludeDelivery(this);
    }

    function excludeDelivery(Delivery _delivery) returns(uint256) { return 1;}
}
contract IT_Connectivity is owned {
    RoleLookup public roles;
    DSO public dso;

    function IT_Connectivity(RoleLookup _roles) {
        roles=_roles;
        dso = new DSO(roles);
        dso.approveConnection(this,now,now+3600,1000,1000);
        dso.approveConnection(msg.sender,now,now+3600,1000,1000);
    }

    function becomeInstanceOwner() onlyOwner {
        dso.transferOwnership(msg.sender);
    }
}

/**
 * Integration Test Provider
 * ====================================================================
 * Integration testing for consens of Business Object Model (Framework)
 *
 */
contract IT_Provider is owned {
    RoleLookup public roles;
    Provider public provider;

    function IT_Provider(RoleLookup _roles) {
        roles = _roles;
        provider=new Provider(_roles);
    }

    function becomeInstanceOwner() onlyOwner {
        provider.transferOwnership(msg.sender);
    }
}

/**
 * Integration Test PowerDelivery
 * ====================================================================
 * Integration testing for consens of Business Object Model (Framework)
 *
 * - Creates a Meter Point Operator and assigns to TX Sender and Self
 * - Creates a Powerdelivery:
 *     - from Self to Self
 *     - from Msg.sender to Msg.sender
 *     - from Self to Msg.sender
 *     - from Msg.sender to Self
 */
contract IT_PowerDelivery is owned {
    RoleLookup public roles;
    MPO public mpo;
    PowerDelivery public powerdelivery;

    function IT_PowerDelivery(RoleLookup _roles) {
        roles = _roles;

        mpo = new MPO(roles);
        mpo.approveMP(msg.sender);
        mpo.approveMP(this);

        roles.setRelationOnBehalf(roles.roles(1),address(mpo),msg.sender);
        roles.setRelationOnBehalf(roles.roles(1),address(mpo),this);
    /*
        powerdelivery = new PowerDelivery(roles,now,3600,10,10);

        powerdelivery.becomeFrom();

        powerdelivery.becomeTo();
*/
        // Removed to avoid Gas-Limit issues in quick test szenario
        /*
        powerdelivery = new PowerDelivery(roles,now,3600,10,10);
        powerdelivery.setFrom(msg.sender);
        powerdelivery.setTo(msg.sender);

        powerdelivery = new PowerDelivery(roles,now,3600,10,10);
        powerdelivery.setFrom(this);
        powerdelivery.setTo(msg.sender);

        powerdelivery = new PowerDelivery(roles,now,3600,10,10);
        powerdelivery.setFrom(msg.sender);
        powerdelivery.setTo(this);
        */

    }
    function becomeInstanceOwner() onlyOwner {
        mpo.transferOwnership(msg.sender);
        //powerdelivery.transferOwnership(msg.sender);
    }
}


Move local authorisation checks up since they're cheaper

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 ||
                isApprovedForAll(owner, msg.sender) ||
                registrar.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 ||
                isApprovedForAll(owner, msg.sender) ||
                ens.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 node,
        address wrappedOwner,
        uint96 _fuses
    ) internal override {
        address oldWrappedOwner = ownerOf(uint256(node));
        if (oldWrappedOwner != address(0)) {
            // burn and unwrap old token of old owner
            _burn(uint256(node));
            emit NameUnwrapped(node, address(0));
        }
        super._mint(node, wrappedOwner, _fuses);
    }

    function _wrap(
        bytes32 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

        _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 node,
        address wrappedOwner,
        uint96 _fuses
    ) internal override {
        address oldWrappedOwner = ownerOf(uint256(node));
        if (oldWrappedOwner != address(0)) {
            // burn and unwrap old token of old owner
            _burn(uint256(node));
            emit NameUnwrapped(node, address(0));
        }
        super._mint(node, wrappedOwner, _fuses);
    }

    function _wrap(
        bytes32 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 CrowdFundrrConfig.sol

Update CrowdFundrrConfig.sol

// WeiFund System
// Start, donate, payout and refund crowdfunding campaigns
// @authors:
// Nick Dodson <thenickdodson@gmail.com>
// If goal is not reached and campaign is expired, contributers can get their donation refunded individually
// If goal is reached by alloted time, contributions can still be made

// With config.
// The config will allow the CrowdFundrr contract to morph
// This allows the campaign owners to connect anything from token systems
// to shares or what ever contract they want.
contract WeiFundConfig
{
    function onContribute(uint cid, address addr, uint amount){}
    function onRefund(uint cid, address addr, uint amount){}
    function onPayout(uint cid, uint amount){}
}

contract WeiFund
{
    struct User
    {
        uint numCampaigns;
        mapping(uint => uint) campaigns;
    }

    struct Funder
    {
        address addr;
        uint amount;
    }

    struct Campaign
    {
        bytes32 name;
        bytes32 website;
        address owner;
        address beneficiary;
        address config; // ADDRESS TO CONFIG
        uint timelimit;
        uint fundingGoal;
        uint amount;
        uint category;
        uint status;
        uint numFunders;
        mapping (uint => Funder) funders;
        mapping (address => uint) toFunder;
    }

    uint public numCampaigns;
    mapping (uint => Campaign) public campaigns;
    mapping (address => User) public users;

    modifier hasValue { if(msg.value > 0) _ }

    function newCampaign(bytes32 name, bytes32 website
    , address beneficiary, uint goal, uint timelimit, uint category, address config)
    {
        if(goal > 0 && timelimit > block.timestamp){
            uint cid = numCampaigns++; // campaignID is return variable
            Campaign c = campaigns[cid];  // assigns reference
            c.name = name;
            c.owner = msg.sender;
            c.website = website;
            c.beneficiary = beneficiary;
            c.fundingGoal = goal;
            c.timelimit = timelimit;
            c.category = category;
            c.config = config; // config address setting

            User u = users[msg.sender];
            uint u_cid = u.numCampaigns++;
            u.campaigns[u_cid] = cid;
        }
    }

    function contribute(uint cid) hasValue
    {
        Campaign c = campaigns[cid]; // Cannot be expired.
        if(c.timelimit >= block.timestamp){
            uint fid = c.numFunders++;
            Funder f = c.funders[fid];
            f.addr = msg.sender;
            f.amount = msg.value;
            c.amount += f.amount;
            c.toFunder[msg.sender] = fid;

            // A certain amount could be taken as a fee if config is set for
            // sending the transaction.
            // Call custom contract set by campaign owner
            if(c.config != 0) // if config address exists
                WeiFundConfig(c.config).onContribute(cid, msg.sender, msg.value);
        }
    }

    function refund(uint cid)
    {
        Campaign c = campaigns[cid];
        if (block.timestamp > c.timelimit
        && c.amount < c.fundingGoal && c.amount > 0){
            Funder f = c.funders[c.toFunder[msg.sender]];
            if(f.amount > 0){
                f.addr.send(f.amount);
                c.amount -= f.amount;
                f.amount = 0;
                if(c.config != 0) // if config address exists
                    WeiFundConfig(c.config).onRefund(cid, f.addr, f.amount);
            }
        }
    }

    function payout(uint cid)
    {
        Campaign c = campaigns[cid];
        if (c.amount >= c.fundingGoal){
            c.beneficiary.send(c.amount);
            c.amount = 0;
            c.status = 1;
            if(c.config != 0) // if config address exists
                WeiFundConfig(c.config).onPayout(cid, c.amount);
        }
    }

    function userCampaigns(address addr, uint u_cid) returns (uint _cid)
    {
        User u = users[addr];
        _cid = u.campaigns[u_cid];
    }
}

/*
// Solidity Interface
contract WeiFund{function campaigns(uint256 )constant returns(string32 name,string32 website,address owner,address beneficiary,uint256 timelimit,uint256 fundingGoal,uint256 amount,uint256 category,uint256 status,uint256 numFunders){}function userCampaigns(address addr,uint256 u_cid)returns(uint256 _cid){}function refund(uint256 cid){}function numCampaigns()constant returns(uint256 ){}function newCampaign(string32 name,string32 website,address beneficiary,uint256 goal,uint256 timelimit,uint256 category){}function users(address )constant returns(uint256 numCampaigns){}function contribute(uint256 cid){}function payout(uint256 cid){}}

// JS Hex (Compiled in AlethZero)
var WeiFundHex = "6104b98061000e6000396000f30060003560e060020a90048063141961bc1461006357806319ac74bd146100b1578063278ecde1146100c95780632c0f7b6f146100da5780639aac25c6146100ec578063a87430ba1461010c578063c1cbbca714610121578063e11523431461013257005b61006e600435610370565b896000528860205287600160a060020a031660405286600160a060020a0316606052856080528460a0528360c0528260e052816101005280610120526101406000f35b6100bf6004356024356103ba565b8060005260206000f35b6100d460043561022e565b60006000f35b6100e2610159565b8060005260206000f35b61010660043560243560443560643560843560a43561015f565b60006000f35b610117600435610144565b8060005260206000f35b61012c6004356103fb565b60006000f35b61013d600435610305565b60006000f35b5b600052600260205260406000208054905081565b5b60005481565b600060006000600060008711801561017657504286115b61017f57610222565b600080549081600101905593506001600085815260200190815260200160002092508983819055503383600201819055508883600101819055508783600301819055508683600501819055508583600401819055508483600701819055506002600033600160a060020a03168152602001908152602001600020915081805490816001019055905083826001016000838152602001908152602001600020819055505b50505050505050505050565b60006000600160008481526020019081526020016000209150816004015442118015610261575081600501548260060154105b8015610271575060008260060154115b61027a57610300565b81600a01600083600b01600033600160a060020a03168152602001908152602001600020548152602001908152602001600020905060008160010154116102c0576102ff565b8054600160a060020a0316600082600101546000600060006000848787f150505050806001015482600601908154039081905550600081600101819055505b5b505050565b60006001600083815260200190815260200160002090508060050154816006015410156103315761036b565b8060030154600160a060020a0316600082600601546000600060006000848787f15050505060008160060181905550600181600801819055505b5050565b5b60005260016020526040600020805490806001015490806002015490806003015490806004015490806005015490806006015490806007015490806008015490806009015490508a565b600060006002600085600160a060020a0316815260200190815260200160002090508060010160008481526020019081526020016000205491505092915050565b6000600060006000341161040e576104b3565b60016000858152602001908152602001600020925042836004015410158061043e57508260050154836006015410155b610447576104b2565b82600901805490816001019055915082600a01600083815260200190815260200160002090503381819055503481600101819055508060010154836006019081540190819055508183600b01600033600160a060020a03168152602001908152602001600020819055505b5b5050505056";

// JS ABI (Generated in AlethZero)
var WeiFundABI = web3.eth.contractFromAbi([{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"campaigns","outputs":[{"name":"name","type":"string32"},{"name":"website","type":"string32"},{"name":"owner","type":"address"},{"name":"beneficiary","type":"address"},{"name":"timelimit","type":"uint256"},{"name":"fundingGoal","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"category","type":"uint256"},{"name":"status","type":"uint256"},{"name":"numFunders","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"},{"name":"u_cid","type":"uint256"}],"name":"userCampaigns","outputs":[{"name":"_cid","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"cid","type":"uint256"}],"name":"refund","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"numCampaigns","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string32"},{"name":"website","type":"string32"},{"name":"beneficiary","type":"address"},{"name":"goal","type":"uint256"},{"name":"timelimit","type":"uint256"},{"name":"category","type":"uint256"}],"name":"newCampaign","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"users","outputs":[{"name":"numCampaigns","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"cid","type":"uint256"}],"name":"contribute","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"cid","type":"uint256"}],"name":"payout","outputs":[],"type":"function"}]);

*/

// Crowdfunding System
// Start, donate, payout and refund crowdfunding campaigns
// @authors:
// Nick Dodson <thenickdodson@gmail.com>
// If goal is not reached and campaign is expired, contributers can get their donation refunded individually
// If goal is reached by alloted time, contributions can still be made

// With config.
// The config will allow the CrowdFundrr contract to morph
// This allows the campaign owners to connect anything from token systems
// to shares or what ever contract they want.
contract CrowdFundrrConfig
{
    function onContribute(uint cid, address addr, uint amount){}
    function onRefund(uint cid, address addr, uint amount){}
    function onPayout(uint cid, uint amount){}
}

contract CrowdFundrr
{
    struct User
    {
        uint numCampaigns;
        mapping(uint => uint) campaigns;
    }

    struct Funder
    {
        address addr;
        uint amount;
    }

    struct Campaign
    {
        bytes32 name;
        bytes32 website;
        address owner;
        address beneficiary;
        address config; // ADDRESS TO CONFIG
        uint timelimit;
        uint fundingGoal;
        uint amount;
        uint category;
        uint status;
        uint numFunders;
        mapping (uint => Funder) funders;
        mapping (address => uint) toFunder;
    }

    uint public numCampaigns;
    mapping (uint => Campaign) public campaigns;
    mapping (address => User) public users;

    modifier hasValue { if(msg.value > 0) _ }

    function newCampaign(bytes32 name, bytes32 website
    , address beneficiary, uint goal, uint timelimit, uint category, address config)
    {
        if(goal > 0 && timelimit > block.timestamp){
            uint cid = numCampaigns++; // campaignID is return variable
            Campaign c = campaigns[cid];  // assigns reference
            c.name = name;
            c.owner = msg.sender;
            c.website = website;
            c.beneficiary = beneficiary;
            c.fundingGoal = goal;
            c.timelimit = timelimit;
            c.category = category;
            c.config = config; // config address setting

            User u = users[msg.sender];
            uint u_cid = u.numCampaigns++;
            u.campaigns[u_cid] = cid;
        }
    }

    function contribute(uint cid) hasValue
    {
        Campaign c = campaigns[cid]; // Cannot be expired.
        if(c.timelimit >= block.timestamp){
            uint fid = c.numFunders++;
            Funder f = c.funders[fid];
            f.addr = msg.sender;
            f.amount = msg.value;
            c.amount += f.amount;
            c.toFunder[msg.sender] = fid;

            // A certain amount could be taken as a fee if config is set for
            // sending the transaction.
            // Call custom contract set by campaign owner
            if(c.config != 0) // if config address exists
                CrowdFundrrConfig(c.config).onContribute(cid, msg.sender, msg.value);
        }
    }

    function refund(uint cid)
    {
        Campaign c = campaigns[cid];
        if (block.timestamp > c.timelimit
        && c.amount < c.fundingGoal && c.amount > 0){
            Funder f = c.funders[c.toFunder[msg.sender]];
            if(f.amount > 0){
                f.addr.send(f.amount);
                c.amount -= f.amount;
                f.amount = 0;
                if(c.config != 0) // if config address exists
                    CrowdFundrrConfig(c.config).onRefund(cid, f.addr, f.amount);
            }
        }
    }

    function payout(uint cid)
    {
        Campaign c = campaigns[cid];
        if (c.amount >= c.fundingGoal){
            c.beneficiary.send(c.amount);
            c.amount = 0;
            c.status = 1;
            if(c.config != 0) // if config address exists
                CrowdFundrrConfig(c.config).onPayout(cid, c.amount);
        }
    }

    function userCampaigns(address addr, uint u_cid) returns (uint _cid)
    {
        User u = users[addr];
        _cid = u.campaigns[u_cid];
    }
}

/*
// Solidity Interface
contract CrowdFundrr{function campaigns(uint256 )constant returns(string32 name,string32 website,address owner,address beneficiary,uint256 timelimit,uint256 fundingGoal,uint256 amount,uint256 category,uint256 status,uint256 numFunders){}function userCampaigns(address addr,uint256 u_cid)returns(uint256 _cid){}function refund(uint256 cid){}function numCampaigns()constant returns(uint256 ){}function newCampaign(string32 name,string32 website,address beneficiary,uint256 goal,uint256 timelimit,uint256 category){}function users(address )constant returns(uint256 numCampaigns){}function contribute(uint256 cid){}function payout(uint256 cid){}}

// JS Hex (Compiled in AlethZero)
var CrowdFundrrHex = "6104b98061000e6000396000f30060003560e060020a90048063141961bc1461006357806319ac74bd146100b1578063278ecde1146100c95780632c0f7b6f146100da5780639aac25c6146100ec578063a87430ba1461010c578063c1cbbca714610121578063e11523431461013257005b61006e600435610370565b896000528860205287600160a060020a031660405286600160a060020a0316606052856080528460a0528360c0528260e052816101005280610120526101406000f35b6100bf6004356024356103ba565b8060005260206000f35b6100d460043561022e565b60006000f35b6100e2610159565b8060005260206000f35b61010660043560243560443560643560843560a43561015f565b60006000f35b610117600435610144565b8060005260206000f35b61012c6004356103fb565b60006000f35b61013d600435610305565b60006000f35b5b600052600260205260406000208054905081565b5b60005481565b600060006000600060008711801561017657504286115b61017f57610222565b600080549081600101905593506001600085815260200190815260200160002092508983819055503383600201819055508883600101819055508783600301819055508683600501819055508583600401819055508483600701819055506002600033600160a060020a03168152602001908152602001600020915081805490816001019055905083826001016000838152602001908152602001600020819055505b50505050505050505050565b60006000600160008481526020019081526020016000209150816004015442118015610261575081600501548260060154105b8015610271575060008260060154115b61027a57610300565b81600a01600083600b01600033600160a060020a03168152602001908152602001600020548152602001908152602001600020905060008160010154116102c0576102ff565b8054600160a060020a0316600082600101546000600060006000848787f150505050806001015482600601908154039081905550600081600101819055505b5b505050565b60006001600083815260200190815260200160002090508060050154816006015410156103315761036b565b8060030154600160a060020a0316600082600601546000600060006000848787f15050505060008160060181905550600181600801819055505b5050565b5b60005260016020526040600020805490806001015490806002015490806003015490806004015490806005015490806006015490806007015490806008015490806009015490508a565b600060006002600085600160a060020a0316815260200190815260200160002090508060010160008481526020019081526020016000205491505092915050565b6000600060006000341161040e576104b3565b60016000858152602001908152602001600020925042836004015410158061043e57508260050154836006015410155b610447576104b2565b82600901805490816001019055915082600a01600083815260200190815260200160002090503381819055503481600101819055508060010154836006019081540190819055508183600b01600033600160a060020a03168152602001908152602001600020819055505b5b5050505056";

// JS ABI (Generated in AlethZero)
var CrowdFundrrABI = web3.eth.contractFromAbi([{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"campaigns","outputs":[{"name":"name","type":"string32"},{"name":"website","type":"string32"},{"name":"owner","type":"address"},{"name":"beneficiary","type":"address"},{"name":"timelimit","type":"uint256"},{"name":"fundingGoal","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"category","type":"uint256"},{"name":"status","type":"uint256"},{"name":"numFunders","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"},{"name":"u_cid","type":"uint256"}],"name":"userCampaigns","outputs":[{"name":"_cid","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"cid","type":"uint256"}],"name":"refund","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"numCampaigns","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string32"},{"name":"website","type":"string32"},{"name":"beneficiary","type":"address"},{"name":"goal","type":"uint256"},{"name":"timelimit","type":"uint256"},{"name":"category","type":"uint256"}],"name":"newCampaign","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"users","outputs":[{"name":"numCampaigns","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"cid","type":"uint256"}],"name":"contribute","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"cid","type":"uint256"}],"name":"payout","outputs":[],"type":"function"}]);

*/