pass through owner to reverseRegistrar

pass through owner to reverseRegistrar

pragma solidity >=0.8.4;

import "./BaseRegistrarImplementation.sol";
import "./StringUtils.sol";
import "../resolvers/Resolver.sol";
import "../registry/ReverseRegistrar.sol";
import "../dnssec-oracle/BytesUtils.sol";
import "./IETHRegistrarController.sol";

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../wrapper/INameWrapper.sol";

/**
 * @dev A registrar controller for registering and renewing names at fixed cost.
 */
contract ETHRegistrarController is Ownable, IETHRegistrarController {
    using StringUtils for *;
    using BytesUtils for bytes;

    uint256 public constant MIN_REGISTRATION_DURATION = 28 days;
    bytes32 private constant ETH_NODE =
        0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae;

    BaseRegistrarImplementation immutable base;
    PriceOracle public prices;
    uint256 public immutable minCommitmentAge;
    uint256 public immutable maxCommitmentAge;
    ReverseRegistrar public immutable reverseRegistrar;
    INameWrapper public immutable nameWrapper;

    mapping(bytes32 => uint256) public commitments;

    event NameRegistered(
        string name,
        bytes32 indexed label,
        address indexed owner,
        uint256 baseCost,
        uint256 premium,
        uint256 expires
    );
    event NameRenewed(
        string name,
        bytes32 indexed label,
        uint256 cost,
        uint256 expires
    );
    event NewPriceOracle(address indexed oracle);

    constructor(
        BaseRegistrarImplementation _base,
        PriceOracle _prices,
        uint256 _minCommitmentAge,
        uint256 _maxCommitmentAge,
        ReverseRegistrar _reverseRegistrar,
        INameWrapper _nameWrapper
    ) {
        require(_maxCommitmentAge > _minCommitmentAge);

        base = _base;
        prices = _prices;
        minCommitmentAge = _minCommitmentAge;
        maxCommitmentAge = _maxCommitmentAge;
        reverseRegistrar = _reverseRegistrar;
        nameWrapper = _nameWrapper;
    }

    function rentPrice(string memory name, uint256 duration)
        public
        view
        override
        returns (uint256 basePrice, uint256 premiumPrice)
    {
        bytes32 hash = keccak256(bytes(name));
        (basePrice, premiumPrice) = prices.price(
            name,
            base.nameExpires(uint256(hash)),
            duration
        );
    }

    function rentDuration(string memory name, uint256 cost)
        public
        view
        override
        returns (uint256 duration, uint256 premiumPrice)
    {
        bytes32 hash = keccak256(bytes(name));
        (duration, premiumPrice) = prices.duration(
            name,
            base.nameExpires(uint256(hash)),
            cost
        );
    }

    function valid(string memory name) public pure returns (bool) {
        return name.strlen() >= 3;
    }

    function available(string memory name) public view override returns (bool) {
        bytes32 label = keccak256(bytes(name));
        return valid(name) && base.available(uint256(label));
    }

    function makeCommitment(
        string memory name,
        address owner,
        bytes32 secret,
        address resolver,
        bytes[] calldata data,
        bool reverseRecord,
        uint96 fuses
    ) public pure override returns (bytes32) {
        bytes32 label = keccak256(bytes(name));
        if (data.length > 0) {
            require(
                resolver != address(0),
                "ETHRegistrarController: resolver is required when data is supplied"
            );
        }
        return
            keccak256(
                abi.encode(
                    label,
                    owner,
                    resolver,
                    data,
                    secret,
                    reverseRecord,
                    fuses
                )
            );
    }

    function commit(bytes32 commitment) public override {
        require(commitments[commitment] + maxCommitmentAge < block.timestamp);
        commitments[commitment] = block.timestamp;
    }

    function register(
        string calldata name,
        address owner,
        bytes32 secret,
        address resolver,
        bytes[] calldata data,
        bool reverseRecord,
        uint96 fuses
    ) public payable override {
        bytes32 label = keccak256(bytes(name));
        (uint256 duration, uint256 premiumCost) = prices.duration(
            name,
            base.nameExpires(uint256(label)),
            msg.value
        );
        _consumeCommitment(
            name,
            duration,
            makeCommitment(
                name,
                owner,
                secret,
                resolver,
                data,
                reverseRecord,
                fuses
            )
        );

        uint256 expires = nameWrapper.registerAndWrapETH2LD(
            name,
            owner,
            duration,
            resolver,
            fuses
        );

        _setRecords(resolver, label, data);

        if (reverseRecord) {
            _setReverseRecord(name, resolver, msg.sender);
        }

        emit NameRegistered(
            name,
            label,
            owner,
            msg.value - premiumCost,
            premiumCost,
            expires
        );
    }

    function renew(string calldata name) external payable override {
        bytes32 label = keccak256(bytes(name));
        (uint256 duration, ) = prices.duration(
            name,
            base.nameExpires(uint256(label)),
            msg.value
        );

        uint256 expires = base.renew(uint256(label), duration);

        emit NameRenewed(name, label, msg.value, expires);
    }

    function setPriceOracle(PriceOracle _prices) public onlyOwner {
        prices = _prices;
        emit NewPriceOracle(address(prices));
    }

    function withdraw() public {
        payable(owner()).transfer(address(this).balance);
    }

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

    /* Internal functions */

    function _consumeCommitment(
        string memory name,
        uint256 duration,
        bytes32 commitment
    ) internal {
        // Require a valid commitment
        require(commitments[commitment] + minCommitmentAge <= block.timestamp);

        // If the commitment is too old, or the name is registered, stop
        require(commitments[commitment] + maxCommitmentAge > block.timestamp);
        require(available(name));

        delete (commitments[commitment]);

        require(duration >= MIN_REGISTRATION_DURATION);
    }

    function _setRecords(
        address resolver,
        bytes32 label,
        bytes[] calldata data
    ) internal {
        // use hardcoded .eth namehash
        bytes32 nodehash = keccak256(abi.encodePacked(ETH_NODE, label));
        for (uint256 i = 0; i < data.length; i++) {
            // check first few bytes are namehash
            bytes32 txNamehash = data[i].readBytes32(4);
            require(
                txNamehash == nodehash,
                "ETHRegistrarController: Namehash on record do not match the name being registered"
            );
            (bool success, ) = address(resolver).call(data[i]);
            require(success, "ETHRegistrarController: Failed to set Record");
        }
    }

    function _setReverseRecord(
        string calldata name,
        address resolver,
        address owner
    ) internal {
        reverseRegistrar.setNameForAddr(
            msg.sender,
            owner,
            resolver,
            string(abi.encodePacked(name, ".eth"))
        );
    }
}

pragma solidity >=0.8.4;

import "./BaseRegistrarImplementation.sol";
import "./StringUtils.sol";
import "../resolvers/Resolver.sol";
import "../registry/ReverseRegistrar.sol";
import "../dnssec-oracle/BytesUtils.sol";
import "./IETHRegistrarController.sol";

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../wrapper/INameWrapper.sol";

/**
 * @dev A registrar controller for registering and renewing names at fixed cost.
 */
contract ETHRegistrarController is Ownable, IETHRegistrarController {
    using StringUtils for *;
    using BytesUtils for bytes;

    uint256 public constant MIN_REGISTRATION_DURATION = 28 days;
    bytes32 private constant ETH_NODE =
        0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae;

    BaseRegistrarImplementation immutable base;
    PriceOracle public prices;
    uint256 public immutable minCommitmentAge;
    uint256 public immutable maxCommitmentAge;
    ReverseRegistrar public immutable reverseRegistrar;
    INameWrapper public immutable nameWrapper;

    mapping(bytes32 => uint256) public commitments;

    event NameRegistered(
        string name,
        bytes32 indexed label,
        address indexed owner,
        uint256 baseCost,
        uint256 premium,
        uint256 expires
    );
    event NameRenewed(
        string name,
        bytes32 indexed label,
        uint256 cost,
        uint256 expires
    );
    event NewPriceOracle(address indexed oracle);

    constructor(
        BaseRegistrarImplementation _base,
        PriceOracle _prices,
        uint256 _minCommitmentAge,
        uint256 _maxCommitmentAge,
        ReverseRegistrar _reverseRegistrar,
        INameWrapper _nameWrapper
    ) {
        require(_maxCommitmentAge > _minCommitmentAge);

        base = _base;
        prices = _prices;
        minCommitmentAge = _minCommitmentAge;
        maxCommitmentAge = _maxCommitmentAge;
        reverseRegistrar = _reverseRegistrar;
        nameWrapper = _nameWrapper;
    }

    function rentPrice(string memory name, uint256 duration)
        public
        view
        override
        returns (uint256 basePrice, uint256 premiumPrice)
    {
        bytes32 hash = keccak256(bytes(name));
        (basePrice, premiumPrice) = prices.price(
            name,
            base.nameExpires(uint256(hash)),
            duration
        );
    }

    function rentDuration(string memory name, uint256 cost)
        public
        view
        override
        returns (uint256 duration, uint256 premiumPrice)
    {
        bytes32 hash = keccak256(bytes(name));
        (duration, premiumPrice) = prices.duration(
            name,
            base.nameExpires(uint256(hash)),
            cost
        );
    }

    function valid(string memory name) public pure returns (bool) {
        return name.strlen() >= 3;
    }

    function available(string memory name) public view override returns (bool) {
        bytes32 label = keccak256(bytes(name));
        return valid(name) && base.available(uint256(label));
    }

    function makeCommitment(
        string memory name,
        address owner,
        bytes32 secret,
        address resolver,
        bytes[] calldata data,
        bool reverseRecord,
        uint96 fuses
    ) public pure override returns (bytes32) {
        bytes32 label = keccak256(bytes(name));
        if (data.length > 0) {
            require(
                resolver != address(0),
                "ETHRegistrarController: resolver is required when data is supplied"
            );
        }
        return
            keccak256(
                abi.encode(
                    label,
                    owner,
                    resolver,
                    data,
                    secret,
                    reverseRecord,
                    fuses
                )
            );
    }

    function commit(bytes32 commitment) public override {
        require(commitments[commitment] + maxCommitmentAge < block.timestamp);
        commitments[commitment] = block.timestamp;
    }

    function register(
        string calldata name,
        address owner,
        bytes32 secret,
        address resolver,
        bytes[] calldata data,
        bool reverseRecord,
        uint96 fuses
    ) public payable override {
        bytes32 label = keccak256(bytes(name));
        (uint256 duration, uint256 premiumCost) = prices.duration(
            name,
            base.nameExpires(uint256(label)),
            msg.value
        );
        _consumeCommitment(
            name,
            duration,
            makeCommitment(
                name,
                owner,
                secret,
                resolver,
                data,
                reverseRecord,
                fuses
            )
        );

        uint256 expires = nameWrapper.registerAndWrapETH2LD(
            name,
            owner,
            duration,
            resolver,
            fuses
        );

        _setRecords(resolver, label, data);

        if (reverseRecord) {
            _setReverseRecord(name, resolver, msg.sender);
        }

        emit NameRegistered(
            name,
            label,
            owner,
            msg.value - premiumCost,
            premiumCost,
            expires
        );
    }

    function renew(string calldata name) external payable override {
        bytes32 label = keccak256(bytes(name));
        (uint256 duration, ) = prices.duration(
            name,
            base.nameExpires(uint256(label)),
            msg.value
        );

        uint256 expires = base.renew(uint256(label), duration);

        emit NameRenewed(name, label, msg.value, expires);
    }

    function setPriceOracle(PriceOracle _prices) public onlyOwner {
        prices = _prices;
        emit NewPriceOracle(address(prices));
    }

    function withdraw() public {
        payable(owner()).transfer(address(this).balance);
    }

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

    /* Internal functions */

    function _consumeCommitment(
        string memory name,
        uint256 duration,
        bytes32 commitment
    ) internal {
        // Require a valid commitment
        require(commitments[commitment] + minCommitmentAge <= block.timestamp);

        // If the commitment is too old, or the name is registered, stop
        require(commitments[commitment] + maxCommitmentAge > block.timestamp);
        require(available(name));

        delete (commitments[commitment]);

        require(duration >= MIN_REGISTRATION_DURATION);
    }

    function _setRecords(
        address resolver,
        bytes32 label,
        bytes[] calldata data
    ) internal {
        // use hardcoded .eth namehash
        bytes32 nodehash = keccak256(abi.encodePacked(ETH_NODE, label));
        for (uint256 i = 0; i < data.length; i++) {
            // check first few bytes are namehash
            bytes32 txNamehash = data[i].readBytes32(4);
            require(
                txNamehash == nodehash,
                "ETHRegistrarController: Namehash on record do not match the name being registered"
            );
            (bool success, ) = address(resolver).call(data[i]);
            require(success, "ETHRegistrarController: Failed to set Record");
        }
    }

    function _setReverseRecord(
        string calldata name,
        address resolver,
        address owner
    ) internal {
        reverseRegistrar.setNameForAddr(
            msg.sender,
            msg.sender,
            resolver,
            string(abi.encodePacked(name, ".eth"))
        );
    }
}


fixed the code

fixed the code

pragma solidity ^0.4.4;
import '../PullPayment.sol';

// mock class using PullPayment
contract PullPaymentMock is PullPayment {

  function PullPaymentMock() payable { }

  // test helper function to call asyncSend
  function callSend(address dest, uint amount) {
    asyncSend(dest, amount);
  }

}

pragma solidity ^0.4.4;
import '../PullPayment.sol';

// mock class using PullPayment
contract PullPaymentMock is PullPayment {

  function PullPaymentMock() payable { }

  // test helper function to call asyncSend

  function PullPaymentMock() payable { }

  function callSend(address dest, uint amount) {
    asyncSend(dest, amount);
  }

}


clean contracts/HealthDRS.sol: Cleaning up smart contracts

pragma solidity ^0.5.0;

import '../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol';
import '../node_modules/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol';

/**
* Health Decentralized Record Service (DRS)
* This contract enables creation of services and keys which can
* be managed, shared, traded, and sold using Health Cash (HLTH).
*
* These keys enable gatekeeper services and
* cryptographically secure data exchanges.
*/

contract HealthDRS is Ownable {

   address public latestContract = address(this);
   uint8 public version = 1;
   uint256 public balance = address(this).balance;

   struct Service {
       string url;
       address owner;
   }

   struct Key {
       address owner;
       bool canShare;
       bool canTrade;
       bool canSell;
       bytes32 service;
   }

   struct SalesOffer {
       address buyer;
       uint price;
       bool canSell;
   }

   mapping (bytes32 => Service) public services;
   bytes32[] public serviceList;

   mapping(bytes32 => Key) keys;
   bytes32[] public keyList;

   mapping(bytes32 => address[]) public owners;
   mapping(bytes32 => bytes32) public keyData;
   mapping(bytes32 => SalesOffer) public salesOffers;
   mapping(bytes32 => bytes32) public tradeOffers;

   event ServiceCreated(address indexed _owner, bytes32 indexed _service);
   event KeyCreated(address indexed _owner, bytes32 indexed _key);
   event KeySold(bytes32 _key, address indexed _seller, address indexed _buyer, uint _price);
   event KeysTraded(bytes32 indexed _key1, bytes32 indexed _key2);
   event Access(address indexed _owner, bytes32 indexed _from, bytes32 indexed _to, uint _time, string _data);
   event Message(address indexed _owner, bytes32 indexed _from, bytes32 indexed _to, uint _time, string _category, string _data);
   event Log(address indexed _owner, bytes32 indexed _from, uint _time, string _data);

   modifier validKey(bytes32 key) {
     require(keys[key].owner != address(0), "validKey() error");
     _;
   }

   modifier validService(bytes32 service) {
     require(services[service].owner != address(0), "validService() error");
     _;
   }

   modifier ownsKey(bytes32 key) {
       require(isKeyOwner(key, msg.sender), "ownsKey() error");
       _;
   }
   modifier ownsService(bytes32 service) {
       require(isServiceOwner(service, msg.sender), "ownsService() error");
       _;
   }

   modifier canSell(bytes32 key) {
     require(keys[key].canSell, "canSell() key can't be sold error");
     require(owners[key].length == 0, "canSell() key does not exist error");
     _;
   }

   modifier canTrade(bytes32 key) {
     require(keys[key].canTrade, "canTrade() keys[key].canTrade error");
     require(owners[key].length == 0, "canTrade() owners[key].length error");
     _;
   }

   modifier canShare(bytes32 key) {
     require(keys[key].canShare, "canShare() error");
     _;
   }

   //prevent accidentally sending/trapping ether
   function() external {
       revert("function() line 104 error");
   }

   function isKeyOwner(bytes32 key, address account)
       public
       view
       validKey(key)
       returns (bool)
   {
       if (keys[key].owner == account) {
           return true;
       } else {
           if (keys[key].canShare) {
               for (uint i = 0; i < owners[key].length; i++) {
                   if (owners[key][i] == account) {
                       return true;
                   }
               }
           }
       }
       return false;
   }

   function isServiceOwner(bytes32 service, address account)
       public
       view
       validService(service)
       returns (bool)
   {
       if (services[service].owner == account) {
           return true;
       } else {
           for (uint i = 0; i < owners[service].length; i++) {
               if (owners[service][i] == account) {
                   return true;
               }
          }
       }
       return false;
   }

   function getUrl(bytes32 service)
       public
       view
       validService(service)
       returns (string memory)
   {
      return services[service].url;
   }

   function getUrlFromKey(bytes32 key)
       public
       view
       validKey(key)
       returns (string memory)
   {
       return services[keys[key].service].url;
   }

   function updateUrl(bytes32 service, string memory url)
       public
       ownsService(service)
   {
      services[service].url = url;
   }

   function getOwnersLength(bytes32 key)
       public
       view
       returns (uint256)
    {
        return owners[key].length;
    }

    //allow owner access to tokens erroneously transferred to this contract
   function recoverTokens(address payable _token, uint amount) public onlyOwner {
       _token.transfer(amount);
   }

   function setLatestContract(address _contract) public onlyOwner {
       latestContract = _contract;
   }

  /**
  * Create Services & Keys
  * Keys can also be issued to accounts
  */
   function createService(string memory url)
        public
   {
       bytes32 id = keccak256(abi.encode(msg.sender, url));
       require(services[id].owner == address(0), "createService() error"); //prevent overwriting
       services[id].owner = msg.sender;
       services[id].url = url;
       serviceList.push(id);
       emit ServiceCreated(msg.sender, id);
   }

   function createKey(bytes32 service)
       public
       ownsService(service)
   {
       issueKey(service, msg.sender);
   }

   function issueKey(bytes32 service, address issueTo)
       public
       ownsService(service)
   {
       bytes32 id = keccak256(abi.encode(service, issueTo, now));
       require(keys[id].owner == address(0), "issueKey() error");
       keys[id].owner = issueTo;
       keys[id].service = service;
       keyList.push(id);
       emit KeyCreated(issueTo, id);
   }

  /**
  * Share Services and Keys
  * allow owners to authorize other accounts
  * a service can disable sharing for their keys.
  * Can also unshare.
  */
   function shareKey(bytes32 key, address account)
       public
       ownsKey(key)
       canShare(key)
   {
       if (isKeyOwner(key, account) == false) {
           owners[key].push(account);
       }
   }

   function shareService(bytes32 service, address account)
       public
       ownsService(service)
   {
       if (isServiceOwner(service, account) == false) {
           owners[service].push(account);
       }
   }

   function unshareKey(bytes32 key, address account)
       public
       ownsKey(key)
   {
       for (uint i = 0; i < owners[key].length; i++) {
           if (owners[key][i] == account) {
               if (i != owners[key].length - 1) {
                   owners[key][i] = owners[key][owners[key].length - 1];
               }
               owners[key].length--;
               break;
           }
       }
   }

   function unshareService(bytes32 service, address account)
       public
       ownsService(service)
   {
       for (uint i = 0; i < owners[service].length; i++) {
           if (owners[service][i] == account) {
               if (i != owners[service].length - 1) {
                   owners[service][i] = owners[service][owners[service].length - 1];
               }
               owners[service].length--;
               break;
           }
       }
   }

   /**
   * Sell Keys
   * Services have to authorize keys for sale.
   * Key owners can disable key selling at time
   * of sale to prevent re-selling.
   */
   function createSalesOffer(bytes32 key, address buyer, uint price, bool _canSell)
       public
       ownsKey(key)
       canSell(key)
   {
       //cancel trade offer & create sales offer
       cancelTradeOffer(key);
       salesOffers[key].buyer = buyer;
       salesOffers[key].price = price;
       salesOffers[key].canSell = _canSell;
   }

   function cancelSalesOffer(bytes32 key)
       public
       ownsKey(key)
   {
       salesOffers[key].buyer = address(0);
       salesOffers[key].price = 0;
       salesOffers[key].canSell = false;
   }

   function purchaseKey(bytes32 key)
       public
       canSell(key)
   {

      //require explicit authority to spend tokens on the purchasers behalf
      require(salesOffers[key].price <= balance, "purchaseKey() salesOffers[key].price error");
      require(salesOffers[key].buyer == msg.sender, "purchaseKey() salesOffers[key].buyer error");

      /**
      * Price in HLTH tokens is transferred from the purchaser
      * to the primary owner of the key.
      */
    //   assert(balance.transfer(msg.sender, keys[key].owner, salesOffers[key].price));

      emit KeySold(key, keys[key].owner, msg.sender, salesOffers[key].price);
      keys[key].owner = msg.sender;

      //set canSell - allows for non-resellable keys
      keys[key].canSell = salesOffers[key].canSell;

      //remove sales offer
      cancelSalesOffer(key);
   }

   /**
   * Trade keys
   * both keys have to be authorized
   * to trade by their respective services.
   */
    function createTradeOffer(bytes32 have, bytes32 want)
        public
        ownsKey(have)
        validKey(want)
        canTrade(have)
        canTrade(want)
    {
        //cancel sales offer & create a trade offer
        cancelSalesOffer(have);
        tradeOffers[have] = want;
    }

   function cancelTradeOffer(bytes32 key)
       public
       ownsKey(key)
   {
       tradeOffers[key] = bytes32(0); //remove the tradeOffer
   }

    function tradeKey(bytes32 have, bytes32 want)
        public
        ownsKey(have)
        validKey(want)
        canTrade(have)
        canTrade(want)
    {
        require(tradeOffers[want] == have, "tradeKey() error");

        emit KeysTraded(want, have);
        //complete the trade
        keys[have].owner = keys[want].owner;
        keys[want].owner = msg.sender;

        //remove trade offer
        cancelTradeOffer(want);
    }

   /**
   * Manage Keys
   * Service owner can set key permissions
   * disabling sharing, trading, or selling
   * removes shared owners, active trade
   * offers, and active sales offers respectively
   *
   * Should also be able to get a key and service,
   * get a count of keys and services, and get
   * a key and service key from the respective
   * lists.
   */
   //service owner can set permissions
   function setKeyPermissions(
       bytes32 key,
       bool canShare_,
       bool canTrade_,
       bool canSell_)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       keys[key].canShare = canShare_;
       if (canShare_ == false) {
           owners[key].length = 0;
       }

       keys[key].canTrade = canTrade_;
       if (canTrade_ == false) {
           tradeOffers[key] = bytes32(0);
       }

       keys[key].canSell = canSell_;
       if (canSell_ == false) {
           salesOffers[key].buyer = address(0);
           salesOffers[key].price = 0;
           salesOffers[key].canSell = false;
       }

   }

   function getServiceCount() public view returns (uint) {
       return serviceList.length;
   }

   function getKeyCount() public view returns (uint) {
       return keyList.length;
   }

   function getService(bytes32 service)
       public
       view
       validService(service)
       returns(string memory, address)
   {
      return (services[service].url, services[service].owner);
   }

   function getKey(bytes32 key)
       public
       view
       validKey(key)
       returns(address, bool, bool, bool, bytes32)
   {
      return (keys[key].owner,
              keys[key].canShare,
              keys[key].canTrade,
              keys[key].canSell,
              keys[key].service);
   }

   /**
   * Key Data
   * A service can store public data for its keys.
   */
   function setKeyData(bytes32 key, bytes32 dataKey, bytes32 dataValue)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       keyData[keccak256(abi.encodePacked(key,dataKey))] = dataValue;
   }

   function getKeyData(bytes32 key, bytes32 dataKey)
       public
       view
       validKey(key)
       returns (bytes32)
   {
       return keyData[keccak256(abi.encodePacked(key,dataKey))];
   }

   /**
   * ecrecover passthrough
   */
   function recoverAddress(
       bytes32 msgHash,
       uint8 v,
       bytes32 r,
       bytes32 s)
       public
       pure
       returns (address)
   {
     return ecrecover(msgHash, v, r, s);
   }

   /**
   * Logging & Messaging
   * functions for creating an auditable record of activity.
   * A service can log access from any of its keys.
   */
   function logAccess(bytes32 key, string memory data)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       emit Access(msg.sender, keys[key].service, key, now, data);
   }

   //services and keys can log messages to each other
   function message(bytes32 from, bytes32 to, string memory category, string memory data)
       public
   {
       require((keys[from].owner != address(0) && isKeyOwner(from, msg.sender)) ||
               isServiceOwner(from, msg.sender), "message() error 1");
       require(keys[to].owner != address(0) || services[to].owner != address(0), "message() error 2");

       emit Message(msg.sender, from, to, now, category, data);
   }

   //any key or service can log
   function log(bytes32 from, string memory data)
       public
   {
       require((keys[from].owner != address(0) && isKeyOwner(from, msg.sender)) ||
                isServiceOwner(from, msg.sender), "log() error");

       emit Log(msg.sender, from, now, data);
   }

}

pragma solidity ^0.5.0;

import '../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol';
import '../node_modules/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol';

/**
* Health Decentralized Record Service (DRS)
* This contract enables creation of services and keys which can
* be managed, shared, traded, and sold using Health Cash (HLTH).
*
* These keys enable gatekeeper services and
* cryptographically secure data exchanges.
*/

contract HealthDRS is Ownable {

   address public latestContract = address(this);
   uint8 public version = 1;
   uint public minimumHold = 0;  //TODO remove with all references
   uint256 public balance = address(this).balance;

   struct Service {
       string url;
       address owner;
   }

   struct Key {
       address owner;
       bool canShare;
       bool canTrade;
       bool canSell;
       bytes32 service;
   }

   struct SalesOffer {
       address buyer;
       uint price;
       bool canSell;
   }

   mapping (bytes32 => Service) public services;
   bytes32[] public serviceList;

   mapping(bytes32 => Key) keys;
   bytes32[] public keyList;

   mapping(bytes32 => address[]) public owners;
   mapping(bytes32 => bytes32) public keyData;
   mapping(bytes32 => SalesOffer) public salesOffers;
   mapping(bytes32 => bytes32) public tradeOffers;

   event ServiceCreated(address indexed _owner, bytes32 indexed _service);
   event KeyCreated(address indexed _owner, bytes32 indexed _key);
   event KeySold(bytes32 _key, address indexed _seller, address indexed _buyer, uint _price);
   event KeysTraded(bytes32 indexed _key1, bytes32 indexed _key2);
   event Access(address indexed _owner, bytes32 indexed _from, bytes32 indexed _to, uint _time, string _data);
   event Message(address indexed _owner, bytes32 indexed _from, bytes32 indexed _to, uint _time, string _category, string _data);
   event Log(address indexed _owner, bytes32 indexed _from, uint _time, string _data);

   modifier validKey(bytes32 key) {
     require(keys[key].owner != address(0), "validKey() error");
     _;
   }

   modifier validService(bytes32 service) {
     require(services[service].owner != address(0), "validService() error");
     _;
   }

   modifier ownsKey(bytes32 key) {
       require(isKeyOwner(key, msg.sender), "ownsKey() error");
       _;
   }
   modifier ownsService(bytes32 service) {
       require(isServiceOwner(service, msg.sender), "ownsService() error");
       _;
   }

   modifier canSell(bytes32 key) {
     require(keys[key].canSell, "canSell() key can't be sold error");
     require(owners[key].length == 0, "canSell() key does not exist error");
     _;
   }

   modifier canTrade(bytes32 key) {
     require(keys[key].canTrade, "canTrade() keys[key].canTrade error");
     require(owners[key].length == 0, "canTrade() owners[key].length error");
     _;
   }

   modifier canShare(bytes32 key) {
     require(keys[key].canShare, "canShare() error");
     _;
   }

    // ensure account has currency
    // TODO Remove and remove all references
    modifier holdingCurrency(){
        require(address(this).balance >= minimumHold, "holdingCurrency() error");
        _;
    }

   //prevent accidentally sending/trapping ether
   function() external {
       revert("function() line 104 error");
   }

//   //require token specified at deployment
//   constructor(ERC20 _token) public {
//       token = _token;
//   }

   function isKeyOwner(bytes32 key, address account)
       public
       view
       validKey(key)
       returns (bool)
   {
       if (keys[key].owner == account) {
           return true;
       } else {
           if (keys[key].canShare) {
               for (uint i = 0; i < owners[key].length; i++) {
                   if (owners[key][i] == account) {
                       return true;
                   }
               }
           }
       }
       return false;
   }

   function isServiceOwner(bytes32 service, address account)
       public
       view
       validService(service)
       returns (bool)
   {
       if (services[service].owner == account) {
           return true;
       } else {
           for (uint i = 0; i < owners[service].length; i++) {
               if (owners[service][i] == account) {
                   return true;
               }
          }
       }
       return false;
   }

   function getUrl(bytes32 service)
       public
       view
       validService(service)
       returns (string memory)
   {
      return services[service].url;
   }

   function getUrlFromKey(bytes32 key)
       public
       view
       validKey(key)
       returns (string memory)
   {
       return services[keys[key].service].url;
   }

   function updateUrl(bytes32 service, string memory url)
       public
       ownsService(service)
   {
      services[service].url = url;
   }

   function getOwnersLength(bytes32 key)
       public
       view
       returns (uint256)
    {
        return owners[key].length;
    }

   //user must authorize this contract to spend Health Cash (HLTH)
   function authorizedToSpend() public view returns (uint) {
    //    return token.allowance(msg.sender, address(this));
   }

    //allow owner access to tokens erroneously transferred to this contract
   function recoverTokens(address payable _token, uint amount) public onlyOwner {
       _token.transfer(amount);
   }

//    function setHealthCashToken(ERC20 _token) public onlyOwner {
//        token = _token;
//    }

   function setLatestContract(address _contract) public onlyOwner {
       latestContract = _contract;
   }

//    function setMinimumHold(uint _minimumHold) public onlyOwner {
//        minimumHold = _minimumHold;
//    }

  /**
  * Create Services & Keys
  * Keys can also be issued to accounts
  */
   function createService(string memory url)
        public
        holdingCurrency()
   {
       bytes32 id = keccak256(abi.encode(msg.sender, url));
       require(services[id].owner == address(0), "createService() error"); //prevent overwriting
       services[id].owner = msg.sender;
       services[id].url = url;
       serviceList.push(id);
       emit ServiceCreated(msg.sender, id);
   }

   function createKey(bytes32 service)
       public
       ownsService(service)
       holdingCurrency()
   {
       issueKey(service, msg.sender);
   }

   function issueKey(bytes32 service, address issueTo)
       public
       ownsService(service)
       holdingCurrency()
   {
       bytes32 id = keccak256(abi.encode(service, issueTo, now));
       require(keys[id].owner == address(0), "issueKey() error");
       keys[id].owner = issueTo;
       keys[id].service = service;
       keyList.push(id);
       emit KeyCreated(issueTo, id);
   }

  /**
  * Share Services and Keys
  * allow owners to authorize other accounts
  * a service can disable sharing for their keys.
  * Can also unshare.
  */
   function shareKey(bytes32 key, address account)
       public
       ownsKey(key)
       canShare(key)
       holdingCurrency()
   {
       if (isKeyOwner(key, account) == false) {
           owners[key].push(account);
       }
   }

   function shareService(bytes32 service, address account)
       public
       ownsService(service)
   {
       if (isServiceOwner(service, account) == false) {
           owners[service].push(account);
       }
   }

   function unshareKey(bytes32 key, address account)
       public
       ownsKey(key)
       holdingCurrency()
   {
       for (uint i = 0; i < owners[key].length; i++) {
           if (owners[key][i] == account) {
               if (i != owners[key].length - 1) {
                   owners[key][i] = owners[key][owners[key].length - 1];
               }
               owners[key].length--;
               break;
           }
       }
   }

   function unshareService(bytes32 service, address account)
       public
       ownsService(service)
   {
       for (uint i = 0; i < owners[service].length; i++) {
           if (owners[service][i] == account) {
               if (i != owners[service].length - 1) {
                   owners[service][i] = owners[service][owners[service].length - 1];
               }
               owners[service].length--;
               break;
           }
       }
   }

   /**
   * Sell Keys
   * Services have to authorize keys for sale.
   * Key owners can disable key selling at time
   * of sale to prevent re-selling.
   */
   function createSalesOffer(bytes32 key, address buyer, uint price, bool _canSell)
       public
       ownsKey(key)
       canSell(key)
   {
       //cancel trade offer & create sales offer
       cancelTradeOffer(key);
       salesOffers[key].buyer = buyer;
       salesOffers[key].price = price;
       salesOffers[key].canSell = _canSell;
   }

   function cancelSalesOffer(bytes32 key)
       public
       ownsKey(key)
   {
       salesOffers[key].buyer = address(0);
       salesOffers[key].price = 0;
       salesOffers[key].canSell = false;
   }

   function purchaseKey(bytes32 key)
       public
       canSell(key)
   {

      //require explicit authority to spend tokens on the purchasers behalf
      require(salesOffers[key].price <= balance, "purchaseKey() salesOffers[key].price error");
      require(salesOffers[key].buyer == msg.sender, "purchaseKey() salesOffers[key].buyer error");

      /**
      * Price in HLTH tokens is transferred from the purchaser
      * to the primary owner of the key.
      */
    //   assert(balance.transfer(msg.sender, keys[key].owner, salesOffers[key].price));

      emit KeySold(key, keys[key].owner, msg.sender, salesOffers[key].price);
      keys[key].owner = msg.sender;

      //set canSell - allows for non-resellable keys
      keys[key].canSell = salesOffers[key].canSell;

      //remove sales offer
      cancelSalesOffer(key);
   }

   /**
   * Trade keys
   * both keys have to be authorized
   * to trade by their respective services.
   */
    function createTradeOffer(bytes32 have, bytes32 want)
        public
        ownsKey(have)
        validKey(want)
        canTrade(have)
        canTrade(want)
    {
        //cancel sales offer & create a trade offer
        cancelSalesOffer(have);
        tradeOffers[have] = want;
    }

   function cancelTradeOffer(bytes32 key)
       public
       ownsKey(key)
   {
       tradeOffers[key] = bytes32(0); //remove the tradeOffer
   }

    function tradeKey(bytes32 have, bytes32 want)
        public
        ownsKey(have)
        validKey(want)
        canTrade(have)
        canTrade(want)
    {
        require(tradeOffers[want] == have, "tradeKey() error");

        emit KeysTraded(want, have);
        //complete the trade
        keys[have].owner = keys[want].owner;
        keys[want].owner = msg.sender;

        //remove trade offer
        cancelTradeOffer(want);
    }

   /**
   * Manage Keys
   * Service owner can set key permissions
   * disabling sharing, trading, or selling
   * removes shared owners, active trade
   * offers, and active sales offers respectively
   *
   * Should also be able to get a key and service,
   * get a count of keys and services, and get
   * a key and service key from the respective
   * lists.
   */
   //service owner can set permissions
   function setKeyPermissions(
       bytes32 key,
       bool canShare_,
       bool canTrade_,
       bool canSell_)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       keys[key].canShare = canShare_;
       if (canShare_ == false) {
           owners[key].length = 0;
       }

       keys[key].canTrade = canTrade_;
       if (canTrade_ == false) {
           tradeOffers[key] = bytes32(0);
       }

       keys[key].canSell = canSell_;
       if (canSell_ == false) {
           salesOffers[key].buyer = address(0);
           salesOffers[key].price = 0;
           salesOffers[key].canSell = false;
       }

   }

   function getServiceCount() public view returns (uint) {
       return serviceList.length;
   }

   function getKeyCount() public view returns (uint) {
       return keyList.length;
   }

   function getService(bytes32 service)
       public
       view
       validService(service)
       returns(string memory, address)
   {
      return (services[service].url, services[service].owner);
   }

   function getKey(bytes32 key)
       public
       view
       validKey(key)
       returns(address, bool, bool, bool, bytes32)
   {
      return (keys[key].owner,
              keys[key].canShare,
              keys[key].canTrade,
              keys[key].canSell,
              keys[key].service);
   }

   /**
   * Key Data
   * A service can store public data for its keys.
   */
   function setKeyData(bytes32 key, bytes32 dataKey, bytes32 dataValue)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       keyData[keccak256(abi.encodePacked(key,dataKey))] = dataValue;
   }

   function getKeyData(bytes32 key, bytes32 dataKey)
       public
       view
       validKey(key)
       returns (bytes32)
   {
       return keyData[keccak256(abi.encodePacked(key,dataKey))];
   }

   /**
   * ecrecover passthrough
   */
   function recoverAddress(
       bytes32 msgHash,
       uint8 v,
       bytes32 r,
       bytes32 s)
       public
       pure
       returns (address)
   {
     return ecrecover(msgHash, v, r, s);
   }

   /**
   * Logging & Messaging
   * functions for creating an auditable record of activity.
   * A service can log access from any of its keys.
   */
   function logAccess(bytes32 key, string memory data)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       emit Access(msg.sender, keys[key].service, key, now, data);
   }

   //services and keys can log messages to each other
   function message(bytes32 from, bytes32 to, string memory category, string memory data)
       public
   {
       require((keys[from].owner != address(0) && isKeyOwner(from, msg.sender)) ||
               isServiceOwner(from, msg.sender), "message() error 1");
       require(keys[to].owner != address(0) || services[to].owner != address(0), "message() error 2");

       emit Message(msg.sender, from, to, now, category, data);
   }

   //any key or service can log
   function log(bytes32 from, string memory data)
       public
   {
       require((keys[from].owner != address(0) && isKeyOwner(from, msg.sender)) ||
                isServiceOwner(from, msg.sender), "log() error");

       emit Log(msg.sender, from, now, data);
   }

}


fixed token

fixed token

pragma solidity ^0.4.10;

//the very seventh example
contract Example7 {

    address owner;
    mapping (address => uint) accounts;

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

    function mint(address recipient, uint value) {
        if(msg.sender == owner) {
            accounts[recipient] = value;
        }
    }

    function transfer(address to, uint value) {
        if(accounts[msg.sender] >= value) {
            accounts[msg.sender] -= value;
            accounts[to] += value;
        }
    }

    function balance(address addr) constant returns (uint) {
        return accounts[addr];
    }
}

pragma solidity ^0.4.10;

//the very seventh example
contract Example7 {

    address owner;
    mapping (address => uint) accounts;

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

    function mint(address recipient, uint value) {
        if(msg.sender == owner) {
            accounts[recipient] = value;
        }
    }

    function transfer(address to, uint value) {
        if(accounts[msg.sender] >= value) {
            accounts[msg.sender] -= value;
            accounts[to] += value;
        }
    }

    function balance() constant returns (uint) {
        return accounts[msg.sender];
    }
}


todo about verifying msg.sender

todo about verifying msg.sender

contract BitcoinProcessor {
    uint256 public lastTxHash;

    function processTransaction(bytes txn, uint256 txHash) returns (int256) {
        log0("processTransaction called");

        // TODO this is a sample and there should be a check here that msg.sender
        // is the btcrelay contract

        log0(bytes32(txHash));
        lastTxHash = txHash;
        // parse & do whatever with txn
        return 1;
    }
}

contract BitcoinProcessor {
    uint256 public lastTxHash;

    function processTransaction(bytes txn, uint256 txHash) returns (int256) {
        log0("processTransaction called");
        log0(bytes32(txHash));
        lastTxHash = txHash;
        // parse & do whatever with txn
        return 1;
    }
}


add Receiptor.sol

add Receiptor.sol

//! Receipting contract. Just records who sent what.
//! By Parity Technologies, 2017.
//! Released under the Apache Licence 2.

pragma solidity ^0.4.7;

/// Will accept Ether "contributions" and record each both as a log and in a
/// queryable record.
contract Receipter {
	/// Constructor. `_admin` has the ability to pause the
	/// contribution period and, eventually, kill this contract. `_treasury`
	/// receives all funds. `_beginBlock` and `_endBlock` define the begin and
	/// end of the period.
    function Receipter(address _admin, address _treasury, uint _beginBlock, uint _endBlock) {
        admin = _admin;
        treasury = _treasury;
        beginBlock = _beginBlock;
        endBlock = _endBlock;
    }

	// Can only be called by _admin.
    modifier only_admin { if (msg.sender != admin) throw; _; }
	// Can only be called by prior to the period.
    modifier only_before_period { if (block.number >= beginBlock) throw; _; }
	// Can only be called during the period when not halted.
    modifier only_during_period { if (block.number < beginBlock || block.number >= endBlock || isHalted) throw; _; }
	// Can only be called during the period when halted.
    modifier only_during_halted_period { if (block.number < beginBlock || block.number >= endBlock || !isHalted) throw; _; }
	// Can only be called after the period.
    modifier only_after_period { if (block.number < endBlock || isHalted) throw; _; }
	// The value of the message must be sufficiently large to not be considered dust.
    modifier is_not_dust { if (msg.value < dust) throw; _; }

	/// Some contribution `amount` received from `recipient`.
    event Received(address indexed recipient, uint amount);
	/// Period halted abnormally.
    event Halted();
	/// Period restarted after abnormal halt.
    event Unhalted();

	/// Fallback function: receive a contribution from sender.
    function() payable {
        receiveFrom(msg.sender);
    }

	/// Receive a contribution from `_recipient`.
    function receiveFrom(address _recipient) payable only_during_period is_not_dust {
        if (!treasury.call.value(msg.value)()) throw;
        record[_recipient] += msg.value;
        total += msg.value;
        Received(_recipient, msg.value);
    }

	/// Halt the contribution period. Any attempt at contributing will fail.
    function halt() only_admin only_during_period {
        isHalted = true;
        Halted();
    }

	/// Unhalt the contribution period.
    function unhalt() only_admin only_during_halted_period {
        isHalted = false;
        Unhalted();
    }

	/// Kill this contract.
    function kill() only_admin only_after_period {
        suicide(treasury);
    }

	// How much is enough?
    uint public constant dust = 100 finney;

	// Who can halt/unhalt/kill?
    address public admin;
	// Who gets the stash?
    address public treasury;
	// When does the contribution period begin?
    uint public beginBlock;
	// When does the period end?
    uint public endBlock;

	// Are contributions abnormally halted?
    bool public isHalted = false;

    mapping (address => uint) public record;
    uint public total = 0;
}

contract SignedReceipter is Receipter {
    function Receipter(address _admin, address _treasury, uint _beginBlock, uint _endBlock, bytes32 _sigHash) {
        admin = _admin;
        treasury = _treasury;
        beginBlock = _beginBlock;
        endBlock = _endBlock;
        sigHash = _sigHash;
    }

    modifier when_signed(address who, uint8 v, bytes32 r, bytes32 s) { if (ecrecover(sigHash, v, r, s) != who) throw; _; }

    function() payable { throw; }

    /// Fallback function: receive a contribution from sender.
    function receive(uint8 v, bytes32 r, bytes32 s) payable {
        receiveFrom(msg.sender, v, r, s);
    }

	/// Receive a contribution from `_recipient`.
    function receiveFrom(address _source, uint8 v, bytes32 r, bytes32 s) payable only_during_period is_not_dust when_signed(_source, v, r, s) {
        if (!treasury.call.value(msg.value)()) throw;
        record[_source] += msg.value;
        total += msg.value;
        Received(_source, msg.value);
    }

    bytes32 sigHash;
}

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


Commented LockedStateWithFunds.sol

Commented LockedStateWithFunds.sol

import "LockedState.sol";

/**
 * LockedStateWithFunds
 *
 * LockedState which implements the tracking of funds sent to it.
 */
contract LockedStateWithFunds is LockedState {

    // Event triggered whenever funds have been added
    event FundsAdded(address from, address to, uint amount);

    mapping (address => uint) balances;

    /**
     * Gets the balance of the address passed in.
     *
     * toCheck: the address to check the balance for
     * returns: the balance
     */
    function getBalance(address toCheck) constant returns (uint) {
        return balances[toCheck];
    }

    function addFunds(address recipient) {
        balances[recipient] += msg.value;
    }

    function () {
        addFunds(msg.sender);
    }
}

import "LockedState.sol";

contract LockedStateWithFunds is LockedState {

    event FundsAdded(address from, address to, uint amount);

    mapping (address => uint) balances;

    function getBalance(address toCheck) constant returns (uint) {
        return balances[toCheck];
    }

    function addFunds(address recipient) {
        balances[recipient] += msg.value;
    }

    function () {
        addFunds(msg.sender);
    }
}


Make VestingWallet token event argument indexed (#2988)

(cherry picked from commit 0859c70936e648a7f275e301b497b06bc4c71b12)

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0-rc.1 (finance/VestingWallet.sol)
pragma solidity ^0.8.0;

import "../token/ERC20/utils/SafeERC20.sol";
import "../utils/Address.sol";
import "../utils/Context.sol";
import "../utils/math/Math.sol";

/**
 * @title VestingWallet
 * @dev This contract handles the vesting of Eth and ERC20 tokens for a given beneficiary. Custody of multiple tokens
 * can be given to this contract, which will release the token to the beneficiary following a given vesting schedule.
 * The vesting schedule is customizable through the {vestedAmount} function.
 *
 * Any token transferred to this contract will follow the vesting schedule as if they were locked from the beginning.
 * Consequently, if the vesting has already started, any amount of tokens sent to this contract will (at least partly)
 * be immediately releasable.
 */
contract VestingWallet is Context {
    event EtherReleased(uint256 amount);
    event ERC20Released(address indexed token, uint256 amount);

    uint256 private _released;
    mapping(address => uint256) private _erc20Released;
    address private immutable _beneficiary;
    uint64 private immutable _start;
    uint64 private immutable _duration;

    /**
     * @dev Set the beneficiary, start timestamp and vesting duration of the vesting wallet.
     */
    constructor(
        address beneficiaryAddress,
        uint64 startTimestamp,
        uint64 durationSeconds
    ) {
        require(beneficiaryAddress != address(0), "VestingWallet: beneficiary is zero address");
        _beneficiary = beneficiaryAddress;
        _start = startTimestamp;
        _duration = durationSeconds;
    }

    /**
     * @dev The contract should be able to receive Eth.
     */
    receive() external payable virtual {}

    /**
     * @dev Getter for the beneficiary address.
     */
    function beneficiary() public view virtual returns (address) {
        return _beneficiary;
    }

    /**
     * @dev Getter for the start timestamp.
     */
    function start() public view virtual returns (uint256) {
        return _start;
    }

    /**
     * @dev Getter for the vesting duration.
     */
    function duration() public view virtual returns (uint256) {
        return _duration;
    }

    /**
     * @dev Amount of eth already released
     */
    function released() public view virtual returns (uint256) {
        return _released;
    }

    /**
     * @dev Amount of token already released
     */
    function released(address token) public view virtual returns (uint256) {
        return _erc20Released[token];
    }

    /**
     * @dev Release the native token (ether) that have already vested.
     *
     * Emits a {TokensReleased} event.
     */
    function release() public virtual {
        uint256 releasable = vestedAmount(uint64(block.timestamp)) - released();
        _released += releasable;
        emit EtherReleased(releasable);
        Address.sendValue(payable(beneficiary()), releasable);
    }

    /**
     * @dev Release the tokens that have already vested.
     *
     * Emits a {TokensReleased} event.
     */
    function release(address token) public virtual {
        uint256 releasable = vestedAmount(token, uint64(block.timestamp)) - released(token);
        _erc20Released[token] += releasable;
        emit ERC20Released(token, releasable);
        SafeERC20.safeTransfer(IERC20(token), beneficiary(), releasable);
    }

    /**
     * @dev Calculates the amount of ether that has already vested. Default implementation is a linear vesting curve.
     */
    function vestedAmount(uint64 timestamp) public view virtual returns (uint256) {
        return _vestingSchedule(address(this).balance + released(), timestamp);
    }

    /**
     * @dev Calculates the amount of tokens that has already vested. Default implementation is a linear vesting curve.
     */
    function vestedAmount(address token, uint64 timestamp) public view virtual returns (uint256) {
        return _vestingSchedule(IERC20(token).balanceOf(address(this)) + released(token), timestamp);
    }

    /**
     * @dev Virtual implementation of the vesting formula. This returns the amout vested, as a function of time, for
     * an asset given its total historical allocation.
     */
    function _vestingSchedule(uint256 totalAllocation, uint64 timestamp) internal view virtual returns (uint256) {
        if (timestamp < start()) {
            return 0;
        } else if (timestamp > start() + duration()) {
            return totalAllocation;
        } else {
            return (totalAllocation * (timestamp - start())) / duration();
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0-rc.1 (finance/VestingWallet.sol)
pragma solidity ^0.8.0;

import "../token/ERC20/utils/SafeERC20.sol";
import "../utils/Address.sol";
import "../utils/Context.sol";
import "../utils/math/Math.sol";

/**
 * @title VestingWallet
 * @dev This contract handles the vesting of Eth and ERC20 tokens for a given beneficiary. Custody of multiple tokens
 * can be given to this contract, which will release the token to the beneficiary following a given vesting schedule.
 * The vesting schedule is customizable through the {vestedAmount} function.
 *
 * Any token transferred to this contract will follow the vesting schedule as if they were locked from the beginning.
 * Consequently, if the vesting has already started, any amount of tokens sent to this contract will (at least partly)
 * be immediately releasable.
 */
contract VestingWallet is Context {
    event EtherReleased(uint256 amount);
    event ERC20Released(address token, uint256 amount);

    uint256 private _released;
    mapping(address => uint256) private _erc20Released;
    address private immutable _beneficiary;
    uint64 private immutable _start;
    uint64 private immutable _duration;

    /**
     * @dev Set the beneficiary, start timestamp and vesting duration of the vesting wallet.
     */
    constructor(
        address beneficiaryAddress,
        uint64 startTimestamp,
        uint64 durationSeconds
    ) {
        require(beneficiaryAddress != address(0), "VestingWallet: beneficiary is zero address");
        _beneficiary = beneficiaryAddress;
        _start = startTimestamp;
        _duration = durationSeconds;
    }

    /**
     * @dev The contract should be able to receive Eth.
     */
    receive() external payable virtual {}

    /**
     * @dev Getter for the beneficiary address.
     */
    function beneficiary() public view virtual returns (address) {
        return _beneficiary;
    }

    /**
     * @dev Getter for the start timestamp.
     */
    function start() public view virtual returns (uint256) {
        return _start;
    }

    /**
     * @dev Getter for the vesting duration.
     */
    function duration() public view virtual returns (uint256) {
        return _duration;
    }

    /**
     * @dev Amount of eth already released
     */
    function released() public view virtual returns (uint256) {
        return _released;
    }

    /**
     * @dev Amount of token already released
     */
    function released(address token) public view virtual returns (uint256) {
        return _erc20Released[token];
    }

    /**
     * @dev Release the native token (ether) that have already vested.
     *
     * Emits a {TokensReleased} event.
     */
    function release() public virtual {
        uint256 releasable = vestedAmount(uint64(block.timestamp)) - released();
        _released += releasable;
        emit EtherReleased(releasable);
        Address.sendValue(payable(beneficiary()), releasable);
    }

    /**
     * @dev Release the tokens that have already vested.
     *
     * Emits a {TokensReleased} event.
     */
    function release(address token) public virtual {
        uint256 releasable = vestedAmount(token, uint64(block.timestamp)) - released(token);
        _erc20Released[token] += releasable;
        emit ERC20Released(token, releasable);
        SafeERC20.safeTransfer(IERC20(token), beneficiary(), releasable);
    }

    /**
     * @dev Calculates the amount of ether that has already vested. Default implementation is a linear vesting curve.
     */
    function vestedAmount(uint64 timestamp) public view virtual returns (uint256) {
        return _vestingSchedule(address(this).balance + released(), timestamp);
    }

    /**
     * @dev Calculates the amount of tokens that has already vested. Default implementation is a linear vesting curve.
     */
    function vestedAmount(address token, uint64 timestamp) public view virtual returns (uint256) {
        return _vestingSchedule(IERC20(token).balanceOf(address(this)) + released(token), timestamp);
    }

    /**
     * @dev Virtual implementation of the vesting formula. This returns the amout vested, as a function of time, for
     * an asset given its total historical allocation.
     */
    function _vestingSchedule(uint256 totalAllocation, uint64 timestamp) internal view virtual returns (uint256) {
        if (timestamp < start()) {
            return 0;
        } else if (timestamp > start() + duration()) {
            return totalAllocation;
        } else {
            return (totalAllocation * (timestamp - start())) / duration();
        }
    }
}


Default agent.sol from Mira

Default agent.sol from Mira

import "pie";

contract agent {

    address public creator;

    uint public typeAgent;

    function agent() {
		creator = msg.sender;
    }

    function getBalance(address _token) returns (uint256 balance) {
        return pie(_token).getBalance(creator);
    }

    function transfer(address _asset, address _to, uint256 _value) returns (bool) {
		return false;
    }
}

error: pathspec 'dao_nodes/agent.sol' did not match any file(s) known to git


ID => id.

ID => id.

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

    struct BlobInfo {               // Single slot.
        bool updatable;             // Can the blob be updated? Can be disabled.
        bool enforceRevisions;      // When updating, always make a new revision. Can be enabled.
        bool retractable;           // Can the blob be retracted? Can be disabled.
        bool transferable;          // Can the blob be transfered to another user or disowned? Can be disabled.
        uint32 blockNumber;         // Which block has revision 0 of this blob.
        uint32 numRevisions;        // Number of additional revisions.
        address owner;              // Who owns this blob.
    }

    mapping (bytes32 => BlobInfo) blobInfo;
    mapping (bytes32 => mapping (uint => bytes32)) packedRevisionBlockNumbers;
    mapping (bytes32 => mapping (address => bool)) enabledTransfers;

    event logBlob(bytes32 indexed id, uint indexed revisionId, bytes blob);     // Greatest revisionId for the blob at time of logging.
    event logRetractRevision(bytes32 indexed id, uint revisionId);
    event logRetract(bytes32 indexed id);
    event logTransfer(bytes32 indexed id, address recipient);
    event logDisown(bytes32 indexed id);
    event logSetNotUpdatable(bytes32 indexed id);
    event logSetEnforceRevisions(bytes32 indexed id);
    event logSetNotRetractable(bytes32 indexed id);
    event logSetNotTransferable(bytes32 indexed id);

    // Create a 96-bit id for this contract. This is unique across all blockchains.
    // Wait a few minutes after deploying for this id to settle.
    bytes12 constant contractId = bytes12(sha3(this, block.blockhash(block.number - 1)));

    /**
     * @dev Throw if the current message is sending a payment.
     */
    modifier noValue() {
        if (msg.value > 0) {
            throw;      // Do not maintain a balance.
        }
        _
    }

    /**
     * @dev Throw if the blob has not been used before or it has been retracted.
     * @param id Id of the blob.
     */
    modifier exists(bytes32 id) {
        if (blobInfo[id].blockNumber == 0 || blobInfo[id].blockNumber == uint32(-1)) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the owner of the blob is not the message sender.
     * @param id Id of the blob.
     */
    modifier isOwner(bytes32 id) {
        if (blobInfo[id].owner != msg.sender) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not updatable.
     * @param id Id of the blob.
     */
    modifier isUpdatable(bytes32 id) {
        if (!blobInfo[id].updatable) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not enforcing revisions.
     * @param id Id of the blob.
     */
    modifier isNotEnforceRevisions(bytes32 id) {
        if (blobInfo[id].enforceRevisions) {
            throw;
        }
        _
    }

    /**
     * @dev Throw is the blob is not retractable.
     * @param id Id of the blob.
     */
    modifier isRetractable(bytes32 id) {
        if (!blobInfo[id].retractable) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not transferable.
     * @param id Id of the blob.
     */
    modifier isTransferable(bytes32 id) {
        if (!blobInfo[id].transferable) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not transferable to a specific user.
     * @param id Id of the blob.
     * @param recipient Address of the user.
     */
    modifier isTransferEnabled(bytes32 id, address recipient) {
        if (!enabledTransfers[id][recipient]) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob does not have revisions.
     * @param id Id of the blob.
     */
    modifier hasRevisions(bytes32 id) {
        if (blobInfo[id].numRevisions == 0) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if a specific blob revision does not exist.
     * @param id Id of the blob.
     * @param revisionId Id of the revision.
     */
    modifier revisionExists(bytes32 id, uint revisionId) {
        if (revisionId > blobInfo[id].numRevisions) {
            throw;
        }
        _
    }

    /**
     * @dev Stores new blob in the transaction log. It is guaranteed that each user will get a different id from the same nonce.
     * @param blob Blob that should be stored.
     * @param nonce Any value that the user has not used previously to create a blob.
     * @param updatable Should the blob be updatable?
     * @param enforceRevisions Should the blob enforce revisions when updating?
     * @param retractable Should the blob be retractable?
     * @param transferable Should the blob be transferable?
     * @param anon Should the blob be anonymous?
     * @return id Id of the blob.
     */
    function create(bytes blob, bytes32 nonce, bool updatable, bool enforceRevisions, bool retractable, bool transferable, bool anon) noValue external returns (bytes32 id) {
        // Determine the id.
        id = contractId | (sha3(msg.sender, nonce) & (2 ** 160 - 1));
        // Make sure this id has not been used before.
        if (blobInfo[id].blockNumber != 0) {
            throw;
        }
        // Store blob info in state.
        blobInfo[id] = BlobInfo({
            updatable: updatable,
            enforceRevisions: enforceRevisions,
            retractable: retractable,
            transferable: transferable,
            numRevisions: 0,
            blockNumber: uint32(block.number),
            owner: anon ? 0 : msg.sender,
        });
        // Store the blob in a log in the current block.
        logBlob(id, 0, blob);
    }

    /**
     * @dev Store a blob revision block number in a packed slot.
     * @param id Id of the blob.
     * @param offset The offset of the block number should be retreived.
     */
    function _setPackedRevisionBlockNumber(bytes32 id, uint offset) internal {
        // Get the slot.
        bytes32 slot = packedRevisionBlockNumbers[id][offset / 8];
        // Wipe the previous block number.
        slot &= ~bytes32(uint32(-1) * 2 ** ((offset % 8) * 32));
        // Insert the current block number.
        slot |= bytes32(uint32(block.number) * 2 ** ((offset % 8) * 32));
        // Store the slot.
        packedRevisionBlockNumbers[id][offset / 8] = slot;
    }

    /**
     * @dev Create a new blob revision.
     * @param id Id of the blob.
     * @param blob Blob that should be stored as the new revision.
     * @return revisionId The new revisionId.
     */
    function createNewRevision(bytes32 id, bytes blob) noValue isOwner(id) isUpdatable(id) external returns (uint revisionId) {
        // Increment the number of revisions.
        revisionId = ++blobInfo[id].numRevisions;
        // Store the block number.
        _setPackedRevisionBlockNumber(id, revisionId - 1);
        // Store the new blob in a log in the current block.
        logBlob(id, revisionId, blob);
    }

    /**
     * @dev Update a blob's latest revsion.
     * @param id Id of the blob.
     * @param blob Blob that should be stored as the latest revision.
     */
    function updateLatestRevision(bytes32 id,  bytes blob) noValue isOwner(id) isUpdatable(id) isNotEnforceRevisions(id) external {
        if (blobInfo[id].numRevisions == 0) {
            blobInfo[id].blockNumber = uint32(block.number);
        }
        else {
            _setPackedRevisionBlockNumber(id, blobInfo[id].numRevisions - 1);
        }
        // Store the new blob in a log in the current block.
        logBlob(id, blobInfo[id].numRevisions, blob);
    }

    /**
     * @dev Retract a blob's latest revision.
     * @param id Id of the blob.
     */
    function retractLatestRevision(bytes32 id) noValue isOwner(id) isUpdatable(id) isNotEnforceRevisions(id) hasRevisions(id) external {
        // Delete slot if empty
        if (blobInfo[id].numRevisions % 8 == 1) {
            delete packedRevisionBlockNumbers[id][blobInfo[id].numRevisions / 8];
        }
        // Log the retraction.
        logRetractRevision(id, blobInfo[id].numRevisions--);
    }

    /**
     * @dev Delete all of a blob's packed revision block numbers.
     * @param id Id of the blob.
     */
    function _deleteAllRevisionBlockNumbers(bytes32 id) internal {
        uint numSlots = (blobInfo[id].numRevisions + 7) / 8;
        for (uint i = 0; i < numSlots; i++) {
            delete packedRevisionBlockNumbers[id][i];
        }
    }

    /**
     * @dev Delete all a blob's revisions and replace it with a new blob.
     * @param id Id of the blob.
     * @param blob Blob that should be stored.
     */
    function restart(bytes32 id, bytes blob) noValue isOwner(id) isUpdatable(id) isNotEnforceRevisions(id) external {
        // Try to get some gas refunds.
        _deleteAllRevisionBlockNumbers(id);
        // Update the blob state info.
        blobInfo[id].blockNumber = uint32(block.number);
        blobInfo[id].numRevisions = 0;
        // Store the blob in a log in the current block.
        logBlob(id, 0, blob);
    }

    /**
     * @dev Retract a blob.
     * @param id Id of the blob.
     */
    function retract(bytes32 id) noValue isOwner(id) isRetractable(id) external {
        // Delete the packed revision block numbers.
        _deleteAllRevisionBlockNumbers(id);
        // Mark this blob as retracted.
        blobInfo[id] = BlobInfo({
            updatable: false,
            enforceRevisions: false,
            retractable: false,
            transferable: false,
            numRevisions: 0,
            blockNumber: uint32(-1),
            owner: 0,
        });
        // Log that the blob has been retracted.
        logRetract(id);
    }

    /**
     * @dev Enable transfer of the blob to the current user.
     * @param id Id of the blob.
     */
    function transferEnable(bytes32 id) noValue isTransferable(id) external {
        // Record in state that the current user will accept this blob.
        enabledTransfers[id][msg.sender] = true;
    }

    /**
     * @dev Disable transfer of the blob to the current user.
     * @param id Id of the blob.
     */
    function transferDisable(bytes32 id) noValue isTransferEnabled(id, msg.sender) external {
        // Record in state that the current user will not accept this blob.
        enabledTransfers[id][msg.sender] = false;
    }

    /**
     * @dev Transfer a blob to a new user.
     * @param id Id of the blob.
     * @param recipient Address of the user to transfer to blob to.
     */
    function transfer(bytes32 id, address recipient) noValue isOwner(id) isTransferable(id) isTransferEnabled(id, recipient) external {
        // Update ownership of the blob.
        blobInfo[id].owner = recipient;
        // Disable this transfer in future and free up the slot.
        enabledTransfers[id][recipient] = false;
        // Log the transfer.
        logTransfer(id, recipient);
    }

    /**
     * @dev Disown a blob.
     * @param id Id of the blob.
     */
    function disown(bytes32 id) noValue isOwner(id) isTransferable(id) external {
        // Remove the owner from the blob's state.
        delete blobInfo[id].owner;
        // Log as blob as disowned.
        logDisown(id);
    }

    /**
     * @dev Set a blob as not updatable.
     * @param id Id of the blob.
     */
    function setNotUpdatable(bytes32 id) noValue isOwner(id) external {
        // Record in state that the blob is not updatable.
        blobInfo[id].updatable = false;
        // Log that the blob is not updatable.
        logSetNotUpdatable(id);
    }

    /**
     * @dev Set a blob to enforce revisions.
     * @param id Id of the blob.
     */
    function setEnforceRevisions(bytes32 id) noValue isOwner(id) external {
        // Record in state that all changes to this blob must be new revisions.
        blobInfo[id].enforceRevisions = true;
        // Log that the blob now forces new revisions.
        logSetEnforceRevisions(id);
    }

    /**
     * @dev Set a blob to not be retractable.
     * @param id Id of the blob.
     */
    function setNotRetractable(bytes32 id) noValue isOwner(id) external {
        // Record in state that the blob is not retractable.
        blobInfo[id].retractable = false;
        // Log that the blob is not retractable.
        logSetNotRetractable(id);
    }

    /**
     * @dev Set a blob to not be transferable.
     * @param id Id of the blob.
     */
    function setNotTransferable(bytes32 id) noValue isOwner(id) external {
        // Record in state that the blob is not transferable.
        blobInfo[id].transferable = false;
        // Log that the blob is not transferable.
        logSetNotTransferable(id);
    }

    /**
     * @dev Get the id for this BlobStore contract.
     * @return _contractId Id of the contract.
     */
    function getContractId() noValue constant external returns (bytes12 _contractId) {
        _contractId = contractId;
    }

    /**
     * @dev Get the block number for a specific blob revision.
     * @param id Id of the blob.
     * @param revisionId Id of the revision.
     * @return blockNumber Block number of the specified revision.
     */
    function _getRevisionBlockNumber(bytes32 id, uint revisionId) internal returns (uint blockNumber) {
        if (revisionId == 0) {
            blockNumber = blobInfo[id].blockNumber;
        }
        else {
            bytes32 slot = packedRevisionBlockNumbers[id][(revisionId - 1) / 8];
            blockNumber = uint32(uint256(slot) / 2 ** (((revisionId - 1) % 8) * 32));
        }
    }

    /**
     * @dev Get info about a blob.
     * @param id Id of the blob.
     * @return owner Owner of the blob.
     * @return numRevisions How many revisions the blob has.
     * @return latestBlockNumber The block number of the latest revision.
     * @return updatable Is the blob updatable?
     * @return enforceRevisions Does the blob enforce revisions?
     * @return retractable Is the blob retractable?
     * @return transferable Is the blob transferable?
     */
    function getInfo(bytes32 id) noValue exists(id) constant external returns (address owner, uint numRevisions, uint latestBlockNumber, bool updatable, bool enforceRevisions, bool retractable, bool transferable) {
        owner = blobInfo[id].owner;
        numRevisions = blobInfo[id].numRevisions;
        latestBlockNumber = _getRevisionBlockNumber(id, numRevisions);
        updatable = blobInfo[id].updatable;
        enforceRevisions = blobInfo[id].enforceRevisions;
        retractable = blobInfo[id].retractable;
        transferable = blobInfo[id].transferable;
    }

    /**
     * @dev Get the owner of a blob.
     * @param id Id of the blob.
     * @return owner Owner of the blob.
     */
    function getOwner(bytes32 id) noValue exists(id) constant external returns (address owner) {
        owner = blobInfo[id].owner;
    }

    /**
     * @dev Is a blob updatable?
     * @param id Id of the blob.
     * @return updatable Is the blob updatable?
     */
    function getUpdatable(bytes32 id) noValue exists(id) constant external returns (bool updatable) {
        updatable = blobInfo[id].updatable;
    }

    /**
     * @dev Does a blob enforce revisions?
     * @param id Id of the blob.
     * @return enforceRevisions Does the blob enforce revisions?
     */
    function getEnforceRevisions(bytes32 id) noValue exists(id) constant external returns (bool enforceRevisions) {
        enforceRevisions = blobInfo[id].enforceRevisions;
    }

    /**
     * @dev Is a blob retractable?
     * @param id Id of the blob.
     * @return retractable Is the blob retractable?
     */
    function getRetractable(bytes32 id) noValue exists(id) constant external returns (bool retractable) {
        retractable = blobInfo[id].retractable;
    }

    /**
     * @dev Is a blob transferable.
     * @param id Id of the blob.
     * @return transferable Is the blob transferable?
     */
    function getTransferable(bytes32 id) noValue exists(id) constant external returns (bool transferable) {
        transferable = blobInfo[id].transferable;
    }

    /**
     * @dev Get the number of revisions a blob has.
     * @param id Id of the blob.
     * @return numRevisions How many revisions the blob has.
     */
    function getNumRevisions(bytes32 id) noValue exists(id) constant external returns (uint numRevisions) {
        numRevisions = blobInfo[id].numRevisions;
    }

    /**
     * @dev Get the block number for a specific blob revision.
     * @param id Id of the blob.
     * @param revisionId Id of the revision.
     * @return blockNumber Block number of the specified revision.
     */
    function getRevisionBlockNumber(bytes32 id, uint revisionId) noValue exists(id) revisionExists(id, revisionId) constant returns (uint blockNumber) {
        blockNumber = _getRevisionBlockNumber(id, revisionId);
    }

    /**
     * @dev Default function.
     */
    function() {
        throw;      // Do not maintain a balance.
    }

}

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

    struct BlobInfo {               // Single slot.
        bool updatable;             // Can the blob be updated? Can be disabled.
        bool enforceRevisions;      // When updating, always make a new revision. Can be enabled.
        bool retractable;           // Can the blob be retracted? Can be disabled.
        bool transferable;          // Can the blob be transfered to another user or disowned? Can be disabled.
        uint32 blockNumber;         // Which block has revision 0 of this blob.
        uint32 numRevisions;        // Number of additional revisions.
        address owner;              // Who owns this blob.
    }

    mapping (bytes32 => BlobInfo) blobInfo;
    mapping (bytes32 => mapping (uint => bytes32)) packedRevisionBlockNumbers;
    mapping (bytes32 => mapping (address => bool)) enabledTransfers;

    event logBlob(bytes32 indexed id, uint indexed revisionId, bytes blob);     // Greatest revisionId for the blob at time of logging.
    event logRetractRevision(bytes32 indexed id, uint revisionId);
    event logRetract(bytes32 indexed id);
    event logTransfer(bytes32 indexed id, address recipient);
    event logDisown(bytes32 indexed id);
    event logSetNotUpdatable(bytes32 indexed id);
    event logSetEnforceRevisions(bytes32 indexed id);
    event logSetNotRetractable(bytes32 indexed id);
    event logSetNotTransferable(bytes32 indexed id);

    // Create a 96-bit id for this contract. This is unique across all blockchains.
    // Wait a few minutes after deploying for this id to settle.
    bytes12 constant contractId = bytes12(sha3(this, block.blockhash(block.number - 1)));

    /**
     * @dev Throw if the current message is sending a payment.
     */
    modifier noValue() {
        if (msg.value > 0) {
            throw;      // Do not maintain a balance.
        }
        _
    }

    /**
     * @dev Throw if the blob has not been used before or it has been retracted.
     * @param id Id of the blob.
     */
    modifier exists(bytes32 id) {
        if (blobInfo[id].blockNumber == 0 || blobInfo[id].blockNumber == uint32(-1)) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the owner of the blob is not the message sender.
     * @param id Id of the blob.
     */
    modifier isOwner(bytes32 id) {
        if (blobInfo[id].owner != msg.sender) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not updatable.
     * @param id Id of the blob.
     */
    modifier isUpdatable(bytes32 id) {
        if (!blobInfo[id].updatable) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not enforcing revisions.
     * @param id Id of the blob.
     */
    modifier isNotEnforceRevisions(bytes32 id) {
        if (blobInfo[id].enforceRevisions) {
            throw;
        }
        _
    }

    /**
     * @dev Throw is the blob is not retractable.
     * @param id Id of the blob.
     */
    modifier isRetractable(bytes32 id) {
        if (!blobInfo[id].retractable) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not transferable.
     * @param id Id of the blob.
     */
    modifier isTransferable(bytes32 id) {
        if (!blobInfo[id].transferable) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not transferable to a specific user.
     * @param id Id of the blob.
     * @param recipient Address of the user.
     */
    modifier isTransferEnabled(bytes32 id, address recipient) {
        if (!enabledTransfers[id][recipient]) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob does not have revisions.
     * @param id Id of the blob.
     */
    modifier hasRevisions(bytes32 id) {
        if (blobInfo[id].numRevisions == 0) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if a specific blob revision does not exist.
     * @param id Id of the blob.
     * @param revisionId Id of the revision.
     */
    modifier revisionExists(bytes32 id, uint revisionId) {
        if (revisionId > blobInfo[id].numRevisions) {
            throw;
        }
        _
    }

    /**
     * @dev Stores new blob in the transaction log. It is guaranteed that each user will get a different id from the same nonce.
     * @param blob Blob that should be stored.
     * @param nonce Any value that the user has not used previously to create a blob.
     * @param updatable Should the blob be updatable?
     * @param enforceRevisions Should the blob enforce revisions when updating?
     * @param retractable Should the blob be retractable?
     * @param transferable Should the blob be transferable?
     * @param anon Should the blob be anonymous?
     * @return id Id of the blob.
     */
    function create(bytes blob, bytes32 nonce, bool updatable, bool enforceRevisions, bool retractable, bool transferable, bool anon) noValue external returns (bytes32 id) {
        // Determine the id.
        id = contractId | (sha3(msg.sender, nonce) & (2 ** 160 - 1));
        // Make sure this id has not been used before.
        if (blobInfo[id].blockNumber != 0) {
            throw;
        }
        // Store blob info in state.
        blobInfo[id] = BlobInfo({
            updatable: updatable,
            enforceRevisions: enforceRevisions,
            retractable: retractable,
            transferable: transferable,
            numRevisions: 0,
            blockNumber: uint32(block.number),
            owner: anon ? 0 : msg.sender,
        });
        // Store the blob in a log in the current block.
        logBlob(id, 0, blob);
    }

    /**
     * @dev Store a blob revision block number in a packed slot.
     * @param id Id of the blob.
     * @param offset The offset of the block number should be retreived.
     */
    function _setPackedRevisionBlockNumber(bytes32 id, uint offset) internal {
        // Get the slot.
        bytes32 slot = packedRevisionBlockNumbers[id][offset / 8];
        // Wipe the previous block number.
        slot &= ~bytes32(uint32(-1) * 2 ** ((offset % 8) * 32));
        // Insert the current block number.
        slot |= bytes32(uint32(block.number) * 2 ** ((offset % 8) * 32));
        // Store the slot.
        packedRevisionBlockNumbers[id][offset / 8] = slot;
    }

    /**
     * @dev Create a new blob revision.
     * @param id Id of the blob.
     * @param blob Blob that should be stored as the new revision.
     * @return revisionId The new revisionId.
     */
    function createNewRevision(bytes32 id, bytes blob) noValue isOwner(id) isUpdatable(id) external returns (uint revisionId) {
        // Increment the number of revisions.
        revisionId = ++blobInfo[id].numRevisions;
        // Store the block number.
        _setPackedRevisionBlockNumber(id, revisionId - 1);
        // Store the new blob in a log in the current block.
        logBlob(id, revisionId, blob);
    }

    /**
     * @dev Update a blob's latest revsion.
     * @param id Id of the blob.
     * @param blob Blob that should be stored as the latest revision.
     */
    function updateLatestRevision(bytes32 id,  bytes blob) noValue isOwner(id) isUpdatable(id) isNotEnforceRevisions(id) external {
        if (blobInfo[id].numRevisions == 0) {
            blobInfo[id].blockNumber = uint32(block.number);
        }
        else {
            _setPackedRevisionBlockNumber(id, blobInfo[id].numRevisions - 1);
        }
        // Store the new blob in a log in the current block.
        logBlob(id, blobInfo[id].numRevisions, blob);
    }

    /**
     * @dev Retract a blob's latest revision.
     * @param id Id of the blob.
     */
    function retractLatestRevision(bytes32 id) noValue isOwner(id) isUpdatable(id) isNotEnforceRevisions(id) hasRevisions(id) external {
        // Delete slot if empty
        if (blobInfo[id].numRevisions % 8 == 1) {
            delete packedRevisionBlockNumbers[id][blobInfo[id].numRevisions / 8];
        }
        // Log the retraction.
        logRetractRevision(id, blobInfo[id].numRevisions--);
    }

    /**
     * @dev Delete all of a blob's packed revision block numbers.
     * @param id Id of the blob.
     */
    function _deleteAllRevisionBlockNumbers(bytes32 id) internal {
        uint numSlots = (blobInfo[id].numRevisions + 7) / 8;
        for (uint i = 0; i < numSlots; i++) {
            delete packedRevisionBlockNumbers[id][i];
        }
    }

    /**
     * @dev Delete all a blob's revisions and replace it with a new blob.
     * @param id Id of the blob.
     * @param blob Blob that should be stored.
     */
    function restart(bytes32 id, bytes blob) noValue isOwner(id) isUpdatable(id) isNotEnforceRevisions(id) external {
        // Try to get some gas refunds.
        _deleteAllRevisionBlockNumbers(id);
        // Update the blob state info.
        blobInfo[id].blockNumber = uint32(block.number);
        blobInfo[id].numRevisions = 0;
        // Store the blob in a log in the current block.
        logBlob(id, 0, blob);
    }

    /**
     * @dev Retract a blob.
     * @param id Id of the blob.
     */
    function retract(bytes32 id) noValue isOwner(id) isRetractable(id) external {
        // Delete the packed revision block numbers.
        _deleteAllRevisionBlockNumbers(id);
        // Mark this blob as retracted.
        blobInfo[id] = BlobInfo({
            updatable: false,
            enforceRevisions: false,
            retractable: false,
            transferable: false,
            numRevisions: 0,
            blockNumber: uint32(-1),
            owner: 0,
        });
        // Log that the blob has been retracted.
        logRetract(id);
    }

    /**
     * @dev Enable transfer of the blob to the current user.
     * @param id Id of the blob.
     */
    function transferEnable(bytes32 id) noValue isTransferable(id) external {
        // Record in state that the current user will accept this blob.
        enabledTransfers[id][msg.sender] = true;
    }

    /**
     * @dev Disable transfer of the blob to the current user.
     * @param id Id of the blob.
     */
    function transferDisable(bytes32 id) noValue isTransferEnabled(id, msg.sender) external {
        // Record in state that the current user will not accept this blob.
        enabledTransfers[id][msg.sender] = false;
    }

    /**
     * @dev Transfer a blob to a new user.
     * @param id Id of the blob.
     * @param recipient Address of the user to transfer to blob to.
     */
    function transfer(bytes32 id, address recipient) noValue isOwner(id) isTransferable(id) isTransferEnabled(id, recipient) external {
        // Update ownership of the blob.
        blobInfo[id].owner = recipient;
        // Disable this transfer in future and free up the slot.
        enabledTransfers[id][recipient] = false;
        // Log the transfer.
        logTransfer(id, recipient);
    }

    /**
     * @dev Disown a blob.
     * @param id Id of the blob.
     */
    function disown(bytes32 id) noValue isOwner(id) isTransferable(id) external {
        // Remove the owner from the blob's state.
        delete blobInfo[id].owner;
        // Log as blob as disowned.
        logDisown(id);
    }

    /**
     * @dev Set a blob as not updatable.
     * @param id Id of the blob.
     */
    function setNotUpdatable(bytes32 id) noValue isOwner(id) external {
        // Record in state that the blob is not updatable.
        blobInfo[id].updatable = false;
        // Log that the blob is not updatable.
        logSetNotUpdatable(id);
    }

    /**
     * @dev Set a blob to enforce revisions.
     * @param id Id of the blob.
     */
    function setEnforceRevisions(bytes32 id) noValue isOwner(id) external {
        // Record in state that all changes to this blob must be new revisions.
        blobInfo[id].enforceRevisions = true;
        // Log that the blob now forces new revisions.
        logSetEnforceRevisions(id);
    }

    /**
     * @dev Set a blob to not be retractable.
     * @param id Id of the blob.
     */
    function setNotRetractable(bytes32 id) noValue isOwner(id) external {
        // Record in state that the blob is not retractable.
        blobInfo[id].retractable = false;
        // Log that the blob is not retractable.
        logSetNotRetractable(id);
    }

    /**
     * @dev Set a blob to not be transferable.
     * @param id Id of the blob.
     */
    function setNotTransferable(bytes32 id) noValue isOwner(id) external {
        // Record in state that the blob is not transferable.
        blobInfo[id].transferable = false;
        // Log that the blob is not transferable.
        logSetNotTransferable(id);
    }

    /**
     * @dev Get the ID for this BlobStore contract.
     * @return _contractId ID of the contract.
     */
    function getContractId() noValue constant external returns (bytes12 _contractId) {
        _contractId = contractId;
    }

    /**
     * @dev Get the block number for a specific blob revision.
     * @param id Id of the blob.
     * @param revisionId Id of the revision.
     * @return blockNumber Block number of the specified revision.
     */
    function _getRevisionBlockNumber(bytes32 id, uint revisionId) internal returns (uint blockNumber) {
        if (revisionId == 0) {
            blockNumber = blobInfo[id].blockNumber;
        }
        else {
            bytes32 slot = packedRevisionBlockNumbers[id][(revisionId - 1) / 8];
            blockNumber = uint32(uint256(slot) / 2 ** (((revisionId - 1) % 8) * 32));
        }
    }

    /**
     * @dev Get info about a blob.
     * @param id Id of the blob.
     * @return owner Owner of the blob.
     * @return numRevisions How many revisions the blob has.
     * @return latestBlockNumber The block number of the latest revision.
     * @return updatable Is the blob updatable?
     * @return enforceRevisions Does the blob enforce revisions?
     * @return retractable Is the blob retractable?
     * @return transferable Is the blob transferable?
     */
    function getInfo(bytes32 id) noValue exists(id) constant external returns (address owner, uint numRevisions, uint latestBlockNumber, bool updatable, bool enforceRevisions, bool retractable, bool transferable) {
        owner = blobInfo[id].owner;
        numRevisions = blobInfo[id].numRevisions;
        latestBlockNumber = _getRevisionBlockNumber(id, numRevisions);
        updatable = blobInfo[id].updatable;
        enforceRevisions = blobInfo[id].enforceRevisions;
        retractable = blobInfo[id].retractable;
        transferable = blobInfo[id].transferable;
    }

    /**
     * @dev Get the owner of a blob.
     * @param id Id of the blob.
     * @return owner Owner of the blob.
     */
    function getOwner(bytes32 id) noValue exists(id) constant external returns (address owner) {
        owner = blobInfo[id].owner;
    }

    /**
     * @dev Is a blob updatable?
     * @param id Id of the blob.
     * @return updatable Is the blob updatable?
     */
    function getUpdatable(bytes32 id) noValue exists(id) constant external returns (bool updatable) {
        updatable = blobInfo[id].updatable;
    }

    /**
     * @dev Does a blob enforce revisions?
     * @param id Id of the blob.
     * @return enforceRevisions Does the blob enforce revisions?
     */
    function getEnforceRevisions(bytes32 id) noValue exists(id) constant external returns (bool enforceRevisions) {
        enforceRevisions = blobInfo[id].enforceRevisions;
    }

    /**
     * @dev Is a blob retractable?
     * @param id Id of the blob.
     * @return retractable Is the blob retractable?
     */
    function getRetractable(bytes32 id) noValue exists(id) constant external returns (bool retractable) {
        retractable = blobInfo[id].retractable;
    }

    /**
     * @dev Is a blob transferable.
     * @param id Id of the blob.
     * @return transferable Is the blob transferable?
     */
    function getTransferable(bytes32 id) noValue exists(id) constant external returns (bool transferable) {
        transferable = blobInfo[id].transferable;
    }

    /**
     * @dev Get the number of revisions a blob has.
     * @param id Id of the blob.
     * @return numRevisions How many revisions the blob has.
     */
    function getNumRevisions(bytes32 id) noValue exists(id) constant external returns (uint numRevisions) {
        numRevisions = blobInfo[id].numRevisions;
    }

    /**
     * @dev Get the block number for a specific blob revision.
     * @param id Id of the blob.
     * @param revisionId Id of the revision.
     * @return blockNumber Block number of the specified revision.
     */
    function getRevisionBlockNumber(bytes32 id, uint revisionId) noValue exists(id) revisionExists(id, revisionId) constant returns (uint blockNumber) {
        blockNumber = _getRevisionBlockNumber(id, revisionId);
    }

    /**
     * @dev Default function.
     */
    function() {
        throw;      // Do not maintain a balance.
    }

}