Reduce gas usage.

Reduce gas usage.

pragma solidity ^0.5.0;

import "./item_store_interface.sol";
import "./item_store_constants.sol";
import "./item_store_registry.sol";

/**
 * @title ItemStoreIpfsSha256
 * @author Jonathan Brown <jbrown@mix-blockchain.org>
 * @dev ItemStore implementation where each item revision is a SHA256 IPFS hash.
 */
contract ItemStoreIpfsSha256 is ItemStoreInterface, ItemStoreConstants {

    /**
     * @dev Single slot structure of item state.
     */
    struct ItemState {
        bool inUse;             // Has this itemId ever been used.
        byte flags;             // Packed item settings.
        uint32 revisionCount;   // Number of revisions including revision 0.
        uint32 timestamp;       // Timestamp of revision 0.
        address owner;          // Who owns this item.
    }

    /**
     * @dev Mapping of itemId to item state.
     */
    mapping (bytes32 => ItemState) itemState;

    /**
     * @dev Mapping of itemId to mapping of packed slots of eight 32-bit timestamps.
     */
    mapping (bytes32 => mapping (uint => bytes32)) itemPackedTimestamps;

    /**
     * @dev Mapping of itemId to mapping of revision number to IPFS hash.
     */
    mapping (bytes32 => mapping (uint => bytes32)) itemRevisionIpfsHashes;

    /**
     * @dev Mapping of itemId to mapping of transfer recipient addresses to enabled.
     */
    mapping (bytes32 => mapping (address => bool)) itemTransferEnabled;

    /**
     * @dev ItemStoreRegistry contract.
     */
    ItemStoreRegistry itemStoreRegistry;

    /**
     * @dev Id of this instance of ItemStore. Stored as bytes32 instead of bytes8 to reduce gas usage.
     */
    bytes32 contractId;

    /**
     * @dev A new item has been created.
     * @param itemId itemId of the item.
     * @param owner Address of the item owner.
     * @param flags Flags the item was created with.
     */
    event Create(bytes32 indexed itemId, address indexed owner, byte flags);

    /**
     * @dev An item revision has been published.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision (the highest at time of logging).
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    event PublishRevision(bytes32 indexed itemId, address indexed owner, uint revisionId, bytes32 ipfsHash);

    /**
     * @dev Revert if the itemId is not in use.
     * @param itemId itemId of the item.
     */
    modifier inUse(bytes32 itemId) {
        require (itemState[itemId].inUse);
        _;
    }

    /**
     * @dev Revert if the owner of the item is not the message sender.
     * @param itemId itemId of the item.
     */
    modifier isOwner(bytes32 itemId) {
        require (itemState[itemId].owner == msg.sender);
        _;
    }

    /**
     * @dev Revert if the item is not updatable.
     * @param itemId itemId of the item.
     */
    modifier isUpdatable(bytes32 itemId) {
        require (itemState[itemId].flags & UPDATABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not enforcing revisions.
     * @param itemId itemId of the item.
     */
    modifier isNotEnforceRevisions(bytes32 itemId) {
        require (itemState[itemId].flags & ENFORCE_REVISIONS == 0);
        _;
    }

    /**
     * @dev Revert if the item is not retractable.
     * @param itemId itemId of the item.
     */
    modifier isRetractable(bytes32 itemId) {
        require (itemState[itemId].flags & RETRACTABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not transferable.
     * @param itemId itemId of the item.
     */
    modifier isTransferable(bytes32 itemId) {
        require (itemState[itemId].flags & TRANSFERABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not transferable to a specific user.
     * @param itemId itemId of the item.
     * @param recipient Address of the user.
     */
    modifier isTransferEnabled(bytes32 itemId, address recipient) {
        require (itemTransferEnabled[itemId][recipient]);
        _;
    }

    /**
     * @dev Revert if the item only has one revision.
     * @param itemId itemId of the item.
     */
    modifier hasAdditionalRevisions(bytes32 itemId) {
        require (itemState[itemId].revisionCount > 1);
        _;
    }

    /**
     * @dev Revert if a specific item revision does not exist.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     */
    modifier revisionExists(bytes32 itemId, uint revisionId) {
        require (revisionId < itemState[itemId].revisionCount);
        _;
    }

    /**
     * @param _itemStoreRegistry Address of the ItemStoreRegistry contract.
     */
    constructor(ItemStoreRegistry _itemStoreRegistry) public {
        // Store the address of the ItemStoreRegistry contract.
        itemStoreRegistry = _itemStoreRegistry;
        // Register this contract.
        contractId = itemStoreRegistry.register();
    }

    /**
     * @dev Generates an itemId from owner and nonce and checks that it is unused.
     * @param owner Address that will own the item.
     * @param nonce Nonce that this owner has never used before.
     * @return itemId itemId of the item with this owner and nonce.
     */
    function getNewItemId(address owner, bytes32 nonce) public view returns (bytes32 itemId) {
        // Combine contractId with hash of sender and nonce.
        itemId = (keccak256(abi.encodePacked(address(this), owner, nonce)) & ITEM_ID_MASK) | contractId;
        // Make sure this itemId has not been used before.
        require (!itemState[itemId].inUse);
    }

    /**
     * @dev Creates an item with no parents. It is guaranteed that different users will never receive the same itemId, even before consensus has been reached. This prevents itemId sniping.
     * @param flagsNonce Nonce that this address has never passed before; first byte is creation flags.
     * @param ipfsHash Hash of the IPFS object where revision 0 is stored.
     * @return itemId itemId of the new item.
     */
    function create(bytes32 flagsNonce, bytes32 ipfsHash) external returns (bytes32 itemId) {
        // Determine the itemId.
        itemId = getNewItemId(msg.sender, flagsNonce);
        // Extract the flags.
        byte flags = byte(flagsNonce);
        // Determine the owner.
        address owner = (flags & DISOWN == 0) ? msg.sender : address(0);
        // Store item state.
        ItemState storage state = itemState[itemId];
        state.inUse = true;
        state.flags = flags;
        state.revisionCount = 1;
        state.timestamp = uint32(block.timestamp);
        state.owner = owner;
        // Store the IPFS hash.
        itemRevisionIpfsHashes[itemId][0] = ipfsHash;
        // Log item creation.
        emit Create(itemId, owner, flags);
        // Log the first revision.
        emit PublishRevision(itemId, owner, 0, ipfsHash);
    }

    /**
     * @dev Store an item revision timestamp in a packed slot.
     * @param itemId itemId of the item.
     * @param offset The offset of the timestamp that should be stored.
     */
    function _setPackedTimestamp(bytes32 itemId, uint offset) internal {
        // Get the slot.
        bytes32 slot = itemPackedTimestamps[itemId][offset / 8];
        // Calculate the shift.
        uint shift = (offset % 8) * 32;
        // Wipe the previous timestamp.
        slot &= ~(bytes32(uint256(uint32(-1))) << shift);
        // Insert the current timestamp.
        slot |= bytes32(uint256(uint32(block.timestamp))) << shift;
        // Store the slot.
        itemPackedTimestamps[itemId][offset / 8] = slot;
    }

    /**
     * @dev Create a new item revision.
     * @param itemId itemId of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     * @return revisionId The revisionId of the new revision.
     */
    function createNewRevision(bytes32 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) returns (uint revisionId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Increment the number of revisions.
        revisionId = state.revisionCount++;
        // Store the IPFS hash.
        itemRevisionIpfsHashes[itemId][revisionId] = ipfsHash;
        // Store the timestamp.
        _setPackedTimestamp(itemId, revisionId - 1);
        // Log the revision.
        emit PublishRevision(itemId, state.owner, revisionId, ipfsHash);
    }

    /**
     * @dev Update an item's latest revision.
     * @param itemId itemId of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    function updateLatestRevision(bytes32 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Determine the revisionId.
        uint revisionId = state.revisionCount - 1;
        // Update the IPFS hash.
        itemRevisionIpfsHashes[itemId][revisionId] = ipfsHash;
        // Update the timestamp.
        if (revisionId == 0) {
            state.timestamp = uint32(block.timestamp);
        }
        else {
            _setPackedTimestamp(itemId, revisionId - 1);
        }
        // Log the revision.
        emit PublishRevision(itemId, state.owner, revisionId, ipfsHash);
    }

    /**
     * @dev Retract an item's latest revision. Revision 0 cannot be retracted.
     * @param itemId itemId of the item.
     */
    function retractLatestRevision(bytes32 itemId) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) hasAdditionalRevisions(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Decrement the number of revisions.
        uint revisionId = --state.revisionCount;
        // Delete the IPFS hash.
        delete itemRevisionIpfsHashes[itemId][revisionId];
        // Delete the packed timestamp slot if it is no longer required.
        if (revisionId % 8 == 1) {
            delete itemPackedTimestamps[itemId][revisionId / 8];
        }
        // Log the revision retraction.
        emit RetractRevision(itemId, state.owner, revisionId);
    }

    /**
     * @dev Delete all of an item's packed revision timestamps.
     * @param itemId itemId of the item.
     */
    function _deleteAllPackedRevisionTimestamps(bytes32 itemId) internal {
        // Determine how many slots should be deleted.
        // Timestamp of the first revision is stored in the item state, so the first slot only needs to be deleted if there are at least 2 revisions.
        uint slotCount = (itemState[itemId].revisionCount + 6) / 8;
        // Delete the slots.
        for (uint i = 0; i < slotCount; i++) {
            delete itemPackedTimestamps[itemId][i];
        }
    }

    /**
     * @dev Delete all an item's revisions and replace it with a new item.
     * @param itemId itemId of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    function restart(bytes32 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Delete all the IPFS hashes except the first one.
        for (uint i = 1; i < state.revisionCount; i++) {
            delete itemRevisionIpfsHashes[itemId][i];
        }
        // Delete all the packed revision timestamps.
        _deleteAllPackedRevisionTimestamps(itemId);
        // Update the item state.
        state.revisionCount = 1;
        state.timestamp = uint32(block.timestamp);
        // Update the first IPFS hash.
        itemRevisionIpfsHashes[itemId][0] = ipfsHash;
        // Log the revision.
        emit PublishRevision(itemId, state.owner, 0, ipfsHash);
    }

    /**
     * @dev Retract an item.
     * @param itemId itemId of the item. This itemId can never be used again.
     */
    function retract(bytes32 itemId) external isOwner(itemId) isRetractable(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Delete all the IPFS hashes.
        for (uint i = 0; i < state.revisionCount; i++) {
            delete itemRevisionIpfsHashes[itemId][i];
        }
        // Delete all the packed revision timestamps.
        _deleteAllPackedRevisionTimestamps(itemId);
        // Log the item retraction.
        emit Retract(itemId, state.owner);
        // Mark this item as retracted.
        state.inUse = true;
        state.flags = 0;
        state.revisionCount = 0;
        state.timestamp = 0;
        state.owner = address(0);
    }

    /**
     * @dev Enable transfer of an item to the current user.
     * @param itemId itemId of the item.
     */
    function transferEnable(bytes32 itemId) external isTransferable(itemId) {
        // Record in state that the current user will accept this item.
        itemTransferEnabled[itemId][msg.sender] = true;
        // Log that transfer to this user is enabled.
        emit EnableTransfer(itemId, itemState[itemId].owner, msg.sender);
    }

    /**
     * @dev Disable transfer of an item to the current user.
     * @param itemId itemId of the item.
     */
    function transferDisable(bytes32 itemId) external isTransferEnabled(itemId, msg.sender) {
        // Record in state that the current user will not accept this item.
        itemTransferEnabled[itemId][msg.sender] = false;
        // Log that transfer to this user is disabled.
        emit DisableTransfer(itemId, itemState[itemId].owner, msg.sender);
    }

    /**
     * @dev Transfer an item to a new user.
     * @param itemId itemId of the item.
     * @param recipient Address of the user to transfer to item to.
     */
    function transfer(bytes32 itemId, address recipient) external isOwner(itemId) isTransferable(itemId) isTransferEnabled(itemId, recipient) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Log the transfer.
        emit Transfer(itemId, state.owner, recipient);
        // Update ownership of the item.
        state.owner = recipient;
        // Disable this transfer in future and free up the slot.
        itemTransferEnabled[itemId][recipient] = false;
    }

    /**
     * @dev Disown an item.
     * @param itemId itemId of the item.
     */
    function disown(bytes32 itemId) external isOwner(itemId) isTransferable(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Log that the item has been disowned.
        emit Disown(itemId, state.owner);
        // Remove the owner from the item's state.
        delete state.owner;
    }

    /**
     * @dev Set an item as not updatable.
     * @param itemId itemId of the item.
     */
    function setNotUpdatable(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that the item is not updatable.
        state.flags &= ~UPDATABLE;
        // Log that the item is not updatable.
        emit SetNotUpdatable(itemId, state.owner);
    }

    /**
     * @dev Set an item to enforce revisions.
     * @param itemId itemId of the item.
     */
    function setEnforceRevisions(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that all changes to this item must be new revisions.
        state.flags |= ENFORCE_REVISIONS;
        // Log that the item now enforces new revisions.
        emit SetEnforceRevisions(itemId, state.owner);
    }

    /**
     * @dev Set an item to not be retractable.
     * @param itemId itemId of the item.
     */
    function setNotRetractable(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that the item is not retractable.
        state.flags &= ~RETRACTABLE;
        // Log that the item is not retractable.
        emit SetNotRetractable(itemId, state.owner);
    }

    /**
     * @dev Set an item to not be transferable.
     * @param itemId itemId of the item.
     */
    function setNotTransferable(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that the item is not transferable.
        state.flags &= ~TRANSFERABLE;
        // Log that the item is not transferable.
        emit SetNotTransferable(itemId, state.owner);
    }

    /**
     * @dev Get the ABI version for this ItemStore contract.
     * @return ABI version.
     */
    function getAbiVersion() external view returns (uint) {
        return ABI_VERSION;
    }

    /**
     * @dev Get the id for this ItemStore contract.
     * @return Id of the contract.
     */
    function getContractId() external view returns (bytes8) {
        return bytes8(contractId << 192);
    }

    /**
     * @dev Check if an itemId is in use.
     * @param itemId itemId of the item.
     * @return True if the itemId is in use.
     */
    function getInUse(bytes32 itemId) external view returns (bool) {
        return itemState[itemId].inUse;
    }

    /**
     * @dev Get the IPFS hashes for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return ipfsHashes Revision IPFS hashes.
     */
    function _getAllRevisionIpfsHashes(bytes32 itemId) internal view returns (bytes32[] memory ipfsHashes) {
        uint revisionCount = itemState[itemId].revisionCount;
        ipfsHashes = new bytes32[](revisionCount);
        for (uint revisionId = 0; revisionId < revisionCount; revisionId++) {
            ipfsHashes[revisionId] = itemRevisionIpfsHashes[itemId][revisionId];
        }
    }

    /**
     * @dev Get the timestamp for a specific item revision.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     * @return timestamp Timestamp of the specified revision or 0 for unconfirmed.
     */
    function _getRevisionTimestamp(bytes32 itemId, uint revisionId) internal view returns (uint timestamp) {
        if (revisionId == 0) {
            timestamp = itemState[itemId].timestamp;
        }
        else {
            uint offset = revisionId - 1;
            timestamp = uint32(uint256(itemPackedTimestamps[itemId][offset / 8] >> ((offset % 8) * 32)));
        }
        // Check if the revision has been confirmed yet.
        if (timestamp == block.timestamp) {
            timestamp = 0;
        }
    }

    /**
     * @dev Get the timestamps for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return timestamps Revision timestamps.
     */
    function _getAllRevisionTimestamps(bytes32 itemId) internal view returns (uint[] memory timestamps) {
        uint count = itemState[itemId].revisionCount;
        timestamps = new uint[](count);
        for (uint revisionId = 0; revisionId < count; revisionId++) {
            timestamps[revisionId] = _getRevisionTimestamp(itemId, revisionId);
        }
    }

    /**
     * @dev Get an item.
     * @param itemId itemId of the item.
     * @return flags Packed item settings.
     * @return owner Owner of the item.
     * @return revisionCount How many revisions the item has.
     * @return ipfsHashes IPFS hash of each revision.
     * @return timestamps Timestamp of each revision.
     * @return parentIds itemIds of all parents.
     * @return childIds itemIds of all children.
     */
    function getItem(bytes32 itemId) external view inUse(itemId) returns (byte flags, address owner, uint revisionCount, bytes32[] memory ipfsHashes, uint[] memory timestamps) {
        ItemState storage state = itemState[itemId];
        flags = state.flags;
        owner = state.owner;
        revisionCount = state.revisionCount;
        ipfsHashes = _getAllRevisionIpfsHashes(itemId);
        timestamps = _getAllRevisionTimestamps(itemId);
    }

    /**
     * @dev Get all an item's flags.
     * @param itemId itemId of the item.
     * @return Packed item settings.
     */
    function getFlags(bytes32 itemId) external view inUse(itemId) returns (byte) {
        return itemState[itemId].flags;
    }

    /**
     * @dev Determine if an item is updatable.
     * @param itemId itemId of the item.
     * @return True if the item is updatable.
     */
    function getUpdatable(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & UPDATABLE != 0;
    }

    /**
     * @dev Determine if an item enforces revisions.
     * @param itemId itemId of the item.
     * @return True if the item enforces revisions.
     */
    function getEnforceRevisions(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & ENFORCE_REVISIONS != 0;
    }

    /**
     * @dev Determine if an item is retractable.
     * @param itemId itemId of the item.
     * @return True if the item is item retractable.
     */
    function getRetractable(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & RETRACTABLE != 0;
    }

    /**
     * @dev Determine if an item is transferable.
     * @param itemId itemId of the item.
     * @return True if the item is transferable.
     */
    function getTransferable(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & TRANSFERABLE != 0;
    }

    /**
     * @dev Get the owner of an item.
     * @param itemId itemId of the item.
     * @return Owner of the item.
     */
    function getOwner(bytes32 itemId) external view inUse(itemId) returns (address) {
        return itemState[itemId].owner;
    }

    /**
     * @dev Get the number of revisions an item has.
     * @param itemId itemId of the item.
     * @return How many revisions the item has.
     */
    function getRevisionCount(bytes32 itemId) external view inUse(itemId) returns (uint) {
        return itemState[itemId].revisionCount;
    }

   /**
    * @dev Get the IPFS hash for a specific item revision.
    * @param itemId itemId of the item.
    * @param revisionId Id of the revision.
    * @return IPFS hash of the specified revision.
    */
    function getRevisionIpfsHash(bytes32 itemId, uint revisionId) external view revisionExists(itemId, revisionId) returns (bytes32) {
        return itemRevisionIpfsHashes[itemId][revisionId];
    }

    /**
     * @dev Get the IPFS hashes for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return IPFS hashes of all revisions of the item.
     */
    function getAllRevisionIpfsHashes(bytes32 itemId) external view inUse(itemId) returns (bytes32[] memory) {
        return _getAllRevisionIpfsHashes(itemId);
    }

    /**
     * @dev Get the timestamp for a specific item revision.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     * @return Timestamp of the specified revision.
     */
    function getRevisionTimestamp(bytes32 itemId, uint revisionId) external view revisionExists(itemId, revisionId) returns (uint) {
        return _getRevisionTimestamp(itemId, revisionId);
    }

    /**
     * @dev Get the timestamps for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return Timestamps of all revisions of the item.
     */
    function getAllRevisionTimestamps(bytes32 itemId) external view inUse(itemId) returns (uint[] memory) {
        return _getAllRevisionTimestamps(itemId);
    }

}

pragma solidity ^0.5.0;

import "./item_store_interface.sol";
import "./item_store_constants.sol";
import "./item_store_registry.sol";

/**
 * @title ItemStoreIpfsSha256
 * @author Jonathan Brown <jbrown@mix-blockchain.org>
 * @dev ItemStore implementation where each item revision is a SHA256 IPFS hash.
 */
contract ItemStoreIpfsSha256 is ItemStoreInterface, ItemStoreConstants {

    /**
     * @dev Single slot structure of item state.
     */
    struct ItemState {
        bool inUse;             // Has this itemId ever been used.
        byte flags;             // Packed item settings.
        uint32 revisionCount;   // Number of revisions including revision 0.
        uint32 timestamp;       // Timestamp of revision 0.
        address owner;          // Who owns this item.
    }

    /**
     * @dev Mapping of itemId to item state.
     */
    mapping (bytes32 => ItemState) itemState;

    /**
     * @dev Mapping of itemId to mapping of packed slots of eight 32-bit timestamps.
     */
    mapping (bytes32 => mapping (uint => bytes32)) itemPackedTimestamps;

    /**
     * @dev Mapping of itemId to mapping of revision number to IPFS hash.
     */
    mapping (bytes32 => mapping (uint => bytes32)) itemRevisionIpfsHashes;

    /**
     * @dev Mapping of itemId to mapping of transfer recipient addresses to enabled.
     */
    mapping (bytes32 => mapping (address => bool)) itemTransferEnabled;

    /**
     * @dev ItemStoreRegistry contract.
     */
    ItemStoreRegistry itemStoreRegistry;

    /**
     * @dev Id of this instance of ItemStore. Stored as bytes32 instead of bytes8 to reduce gas usage.
     */
    bytes32 contractId;

    /**
     * @dev A new item has been created.
     * @param itemId itemId of the item.
     * @param owner Address of the item owner.
     * @param flags Flags the item was created with.
     */
    event Create(bytes32 indexed itemId, address indexed owner, byte flags);

    /**
     * @dev An item revision has been published.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision (the highest at time of logging).
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    event PublishRevision(bytes32 indexed itemId, address indexed owner, uint revisionId, bytes32 ipfsHash);

    /**
     * @dev Revert if the itemId is not in use.
     * @param itemId itemId of the item.
     */
    modifier inUse(bytes32 itemId) {
        require (itemState[itemId].inUse);
        _;
    }

    /**
     * @dev Revert if the owner of the item is not the message sender.
     * @param itemId itemId of the item.
     */
    modifier isOwner(bytes32 itemId) {
        require (itemState[itemId].owner == msg.sender);
        _;
    }

    /**
     * @dev Revert if the item is not updatable.
     * @param itemId itemId of the item.
     */
    modifier isUpdatable(bytes32 itemId) {
        require (itemState[itemId].flags & UPDATABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not enforcing revisions.
     * @param itemId itemId of the item.
     */
    modifier isNotEnforceRevisions(bytes32 itemId) {
        require (itemState[itemId].flags & ENFORCE_REVISIONS == 0);
        _;
    }

    /**
     * @dev Revert if the item is not retractable.
     * @param itemId itemId of the item.
     */
    modifier isRetractable(bytes32 itemId) {
        require (itemState[itemId].flags & RETRACTABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not transferable.
     * @param itemId itemId of the item.
     */
    modifier isTransferable(bytes32 itemId) {
        require (itemState[itemId].flags & TRANSFERABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not transferable to a specific user.
     * @param itemId itemId of the item.
     * @param recipient Address of the user.
     */
    modifier isTransferEnabled(bytes32 itemId, address recipient) {
        require (itemTransferEnabled[itemId][recipient]);
        _;
    }

    /**
     * @dev Revert if the item only has one revision.
     * @param itemId itemId of the item.
     */
    modifier hasAdditionalRevisions(bytes32 itemId) {
        require (itemState[itemId].revisionCount > 1);
        _;
    }

    /**
     * @dev Revert if a specific item revision does not exist.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     */
    modifier revisionExists(bytes32 itemId, uint revisionId) {
        require (revisionId < itemState[itemId].revisionCount);
        _;
    }

    /**
     * @param _itemStoreRegistry Address of the ItemStoreRegistry contract.
     */
    constructor(ItemStoreRegistry _itemStoreRegistry) public {
        // Store the address of the ItemStoreRegistry contract.
        itemStoreRegistry = _itemStoreRegistry;
        // Register this contract.
        contractId = itemStoreRegistry.register();
    }

    /**
     * @dev Generates an itemId from owner and nonce and checks that it is unused.
     * @param owner Address that will own the item.
     * @param nonce Nonce that this owner has never used before.
     * @return itemId itemId of the item with this owner and nonce.
     */
    function getNewItemId(address owner, bytes32 nonce) public view returns (bytes32 itemId) {
        // Combine contractId with hash of sender and nonce.
        itemId = (keccak256(abi.encodePacked(address(this), owner, nonce)) & ITEM_ID_MASK) | contractId;
        // Make sure this itemId has not been used before.
        require (!itemState[itemId].inUse);
    }

    /**
     * @dev Creates an item with no parents. It is guaranteed that different users will never receive the same itemId, even before consensus has been reached. This prevents itemId sniping.
     * @param flagsNonce Nonce that this address has never passed before; first byte is creation flags.
     * @param ipfsHash Hash of the IPFS object where revision 0 is stored.
     * @return itemId itemId of the new item.
     */
    function create(bytes32 flagsNonce, bytes32 ipfsHash) external returns (bytes32 itemId) {
        // Determine the itemId.
        itemId = getNewItemId(msg.sender, flagsNonce);
        // Extract the flags.
        byte flags = byte(flagsNonce);
        // Determine the owner.
        address owner = (flags & DISOWN == 0) ? msg.sender : address(0);
        // Store item state.
        itemState[itemId] = ItemState({
            inUse: true,
            flags: flags,
            revisionCount: 1,
            timestamp: uint32(block.timestamp),
            owner: owner
        });
        // Store the IPFS hash.
        itemRevisionIpfsHashes[itemId][0] = ipfsHash;
        // Log item creation.
        emit Create(itemId, owner, flags);
        // Log the first revision.
        emit PublishRevision(itemId, owner, 0, ipfsHash);
    }

    /**
     * @dev Store an item revision timestamp in a packed slot.
     * @param itemId itemId of the item.
     * @param offset The offset of the timestamp that should be stored.
     */
    function _setPackedTimestamp(bytes32 itemId, uint offset) internal {
        // Get the slot.
        bytes32 slot = itemPackedTimestamps[itemId][offset / 8];
        // Calculate the shift.
        uint shift = (offset % 8) * 32;
        // Wipe the previous timestamp.
        slot &= ~(bytes32(uint256(uint32(-1))) << shift);
        // Insert the current timestamp.
        slot |= bytes32(uint256(uint32(block.timestamp))) << shift;
        // Store the slot.
        itemPackedTimestamps[itemId][offset / 8] = slot;
    }

    /**
     * @dev Create a new item revision.
     * @param itemId itemId of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     * @return revisionId The revisionId of the new revision.
     */
    function createNewRevision(bytes32 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) returns (uint revisionId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Increment the number of revisions.
        revisionId = state.revisionCount++;
        // Store the IPFS hash.
        itemRevisionIpfsHashes[itemId][revisionId] = ipfsHash;
        // Store the timestamp.
        _setPackedTimestamp(itemId, revisionId - 1);
        // Log the revision.
        emit PublishRevision(itemId, state.owner, revisionId, ipfsHash);
    }

    /**
     * @dev Update an item's latest revision.
     * @param itemId itemId of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    function updateLatestRevision(bytes32 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Determine the revisionId.
        uint revisionId = state.revisionCount - 1;
        // Update the IPFS hash.
        itemRevisionIpfsHashes[itemId][revisionId] = ipfsHash;
        // Update the timestamp.
        if (revisionId == 0) {
            state.timestamp = uint32(block.timestamp);
        }
        else {
            _setPackedTimestamp(itemId, revisionId - 1);
        }
        // Log the revision.
        emit PublishRevision(itemId, state.owner, revisionId, ipfsHash);
    }

    /**
     * @dev Retract an item's latest revision. Revision 0 cannot be retracted.
     * @param itemId itemId of the item.
     */
    function retractLatestRevision(bytes32 itemId) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) hasAdditionalRevisions(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Decrement the number of revisions.
        uint revisionId = --state.revisionCount;
        // Delete the IPFS hash.
        delete itemRevisionIpfsHashes[itemId][revisionId];
        // Delete the packed timestamp slot if it is no longer required.
        if (revisionId % 8 == 1) {
            delete itemPackedTimestamps[itemId][revisionId / 8];
        }
        // Log the revision retraction.
        emit RetractRevision(itemId, state.owner, revisionId);
    }

    /**
     * @dev Delete all of an item's packed revision timestamps.
     * @param itemId itemId of the item.
     */
    function _deleteAllPackedRevisionTimestamps(bytes32 itemId) internal {
        // Determine how many slots should be deleted.
        // Timestamp of the first revision is stored in the item state, so the first slot only needs to be deleted if there are at least 2 revisions.
        uint slotCount = (itemState[itemId].revisionCount + 6) / 8;
        // Delete the slots.
        for (uint i = 0; i < slotCount; i++) {
            delete itemPackedTimestamps[itemId][i];
        }
    }

    /**
     * @dev Delete all an item's revisions and replace it with a new item.
     * @param itemId itemId of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    function restart(bytes32 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Delete all the IPFS hashes except the first one.
        for (uint i = 1; i < state.revisionCount; i++) {
            delete itemRevisionIpfsHashes[itemId][i];
        }
        // Delete all the packed revision timestamps.
        _deleteAllPackedRevisionTimestamps(itemId);
        // Update the item state.
        state.revisionCount = 1;
        state.timestamp = uint32(block.timestamp);
        // Update the first IPFS hash.
        itemRevisionIpfsHashes[itemId][0] = ipfsHash;
        // Log the revision.
        emit PublishRevision(itemId, state.owner, 0, ipfsHash);
    }

    /**
     * @dev Retract an item.
     * @param itemId itemId of the item. This itemId can never be used again.
     */
    function retract(bytes32 itemId) external isOwner(itemId) isRetractable(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Delete all the IPFS hashes.
        for (uint i = 0; i < state.revisionCount; i++) {
            delete itemRevisionIpfsHashes[itemId][i];
        }
        // Delete all the packed revision timestamps.
        _deleteAllPackedRevisionTimestamps(itemId);
        // Log the item retraction.
        emit Retract(itemId, state.owner);
        // Mark this item as retracted.
        itemState[itemId] = ItemState({
            inUse: true,
            flags: 0,
            revisionCount: 0,
            timestamp: 0,
            owner: address(0)
        });
    }

    /**
     * @dev Enable transfer of an item to the current user.
     * @param itemId itemId of the item.
     */
    function transferEnable(bytes32 itemId) external isTransferable(itemId) {
        // Record in state that the current user will accept this item.
        itemTransferEnabled[itemId][msg.sender] = true;
        // Log that transfer to this user is enabled.
        emit EnableTransfer(itemId, itemState[itemId].owner, msg.sender);
    }

    /**
     * @dev Disable transfer of an item to the current user.
     * @param itemId itemId of the item.
     */
    function transferDisable(bytes32 itemId) external isTransferEnabled(itemId, msg.sender) {
        // Record in state that the current user will not accept this item.
        itemTransferEnabled[itemId][msg.sender] = false;
        // Log that transfer to this user is disabled.
        emit DisableTransfer(itemId, itemState[itemId].owner, msg.sender);
    }

    /**
     * @dev Transfer an item to a new user.
     * @param itemId itemId of the item.
     * @param recipient Address of the user to transfer to item to.
     */
    function transfer(bytes32 itemId, address recipient) external isOwner(itemId) isTransferable(itemId) isTransferEnabled(itemId, recipient) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Log the transfer.
        emit Transfer(itemId, state.owner, recipient);
        // Update ownership of the item.
        state.owner = recipient;
        // Disable this transfer in future and free up the slot.
        itemTransferEnabled[itemId][recipient] = false;
    }

    /**
     * @dev Disown an item.
     * @param itemId itemId of the item.
     */
    function disown(bytes32 itemId) external isOwner(itemId) isTransferable(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Log that the item has been disowned.
        emit Disown(itemId, state.owner);
        // Remove the owner from the item's state.
        delete state.owner;
    }

    /**
     * @dev Set an item as not updatable.
     * @param itemId itemId of the item.
     */
    function setNotUpdatable(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that the item is not updatable.
        state.flags &= ~UPDATABLE;
        // Log that the item is not updatable.
        emit SetNotUpdatable(itemId, state.owner);
    }

    /**
     * @dev Set an item to enforce revisions.
     * @param itemId itemId of the item.
     */
    function setEnforceRevisions(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that all changes to this item must be new revisions.
        state.flags |= ENFORCE_REVISIONS;
        // Log that the item now enforces new revisions.
        emit SetEnforceRevisions(itemId, state.owner);
    }

    /**
     * @dev Set an item to not be retractable.
     * @param itemId itemId of the item.
     */
    function setNotRetractable(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that the item is not retractable.
        state.flags &= ~RETRACTABLE;
        // Log that the item is not retractable.
        emit SetNotRetractable(itemId, state.owner);
    }

    /**
     * @dev Set an item to not be transferable.
     * @param itemId itemId of the item.
     */
    function setNotTransferable(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that the item is not transferable.
        state.flags &= ~TRANSFERABLE;
        // Log that the item is not transferable.
        emit SetNotTransferable(itemId, state.owner);
    }

    /**
     * @dev Get the ABI version for this ItemStore contract.
     * @return ABI version.
     */
    function getAbiVersion() external view returns (uint) {
        return ABI_VERSION;
    }

    /**
     * @dev Get the id for this ItemStore contract.
     * @return Id of the contract.
     */
    function getContractId() external view returns (bytes8) {
        return bytes8(contractId << 192);
    }

    /**
     * @dev Check if an itemId is in use.
     * @param itemId itemId of the item.
     * @return True if the itemId is in use.
     */
    function getInUse(bytes32 itemId) external view returns (bool) {
        return itemState[itemId].inUse;
    }

    /**
     * @dev Get the IPFS hashes for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return ipfsHashes Revision IPFS hashes.
     */
    function _getAllRevisionIpfsHashes(bytes32 itemId) internal view returns (bytes32[] memory ipfsHashes) {
        uint revisionCount = itemState[itemId].revisionCount;
        ipfsHashes = new bytes32[](revisionCount);
        for (uint revisionId = 0; revisionId < revisionCount; revisionId++) {
            ipfsHashes[revisionId] = itemRevisionIpfsHashes[itemId][revisionId];
        }
    }

    /**
     * @dev Get the timestamp for a specific item revision.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     * @return timestamp Timestamp of the specified revision or 0 for unconfirmed.
     */
    function _getRevisionTimestamp(bytes32 itemId, uint revisionId) internal view returns (uint timestamp) {
        if (revisionId == 0) {
            timestamp = itemState[itemId].timestamp;
        }
        else {
            uint offset = revisionId - 1;
            timestamp = uint32(uint256(itemPackedTimestamps[itemId][offset / 8] >> ((offset % 8) * 32)));
        }
        // Check if the revision has been confirmed yet.
        if (timestamp == block.timestamp) {
            timestamp = 0;
        }
    }

    /**
     * @dev Get the timestamps for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return timestamps Revision timestamps.
     */
    function _getAllRevisionTimestamps(bytes32 itemId) internal view returns (uint[] memory timestamps) {
        uint count = itemState[itemId].revisionCount;
        timestamps = new uint[](count);
        for (uint revisionId = 0; revisionId < count; revisionId++) {
            timestamps[revisionId] = _getRevisionTimestamp(itemId, revisionId);
        }
    }

    /**
     * @dev Get an item.
     * @param itemId itemId of the item.
     * @return flags Packed item settings.
     * @return owner Owner of the item.
     * @return revisionCount How many revisions the item has.
     * @return ipfsHashes IPFS hash of each revision.
     * @return timestamps Timestamp of each revision.
     * @return parentIds itemIds of all parents.
     * @return childIds itemIds of all children.
     */
    function getItem(bytes32 itemId) external view inUse(itemId) returns (byte flags, address owner, uint revisionCount, bytes32[] memory ipfsHashes, uint[] memory timestamps) {
        ItemState storage state = itemState[itemId];
        flags = state.flags;
        owner = state.owner;
        revisionCount = state.revisionCount;
        ipfsHashes = _getAllRevisionIpfsHashes(itemId);
        timestamps = _getAllRevisionTimestamps(itemId);
    }

    /**
     * @dev Get all an item's flags.
     * @param itemId itemId of the item.
     * @return Packed item settings.
     */
    function getFlags(bytes32 itemId) external view inUse(itemId) returns (byte) {
        return itemState[itemId].flags;
    }

    /**
     * @dev Determine if an item is updatable.
     * @param itemId itemId of the item.
     * @return True if the item is updatable.
     */
    function getUpdatable(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & UPDATABLE != 0;
    }

    /**
     * @dev Determine if an item enforces revisions.
     * @param itemId itemId of the item.
     * @return True if the item enforces revisions.
     */
    function getEnforceRevisions(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & ENFORCE_REVISIONS != 0;
    }

    /**
     * @dev Determine if an item is retractable.
     * @param itemId itemId of the item.
     * @return True if the item is item retractable.
     */
    function getRetractable(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & RETRACTABLE != 0;
    }

    /**
     * @dev Determine if an item is transferable.
     * @param itemId itemId of the item.
     * @return True if the item is transferable.
     */
    function getTransferable(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & TRANSFERABLE != 0;
    }

    /**
     * @dev Get the owner of an item.
     * @param itemId itemId of the item.
     * @return Owner of the item.
     */
    function getOwner(bytes32 itemId) external view inUse(itemId) returns (address) {
        return itemState[itemId].owner;
    }

    /**
     * @dev Get the number of revisions an item has.
     * @param itemId itemId of the item.
     * @return How many revisions the item has.
     */
    function getRevisionCount(bytes32 itemId) external view inUse(itemId) returns (uint) {
        return itemState[itemId].revisionCount;
    }

   /**
    * @dev Get the IPFS hash for a specific item revision.
    * @param itemId itemId of the item.
    * @param revisionId Id of the revision.
    * @return IPFS hash of the specified revision.
    */
    function getRevisionIpfsHash(bytes32 itemId, uint revisionId) external view revisionExists(itemId, revisionId) returns (bytes32) {
        return itemRevisionIpfsHashes[itemId][revisionId];
    }

    /**
     * @dev Get the IPFS hashes for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return IPFS hashes of all revisions of the item.
     */
    function getAllRevisionIpfsHashes(bytes32 itemId) external view inUse(itemId) returns (bytes32[] memory) {
        return _getAllRevisionIpfsHashes(itemId);
    }

    /**
     * @dev Get the timestamp for a specific item revision.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     * @return Timestamp of the specified revision.
     */
    function getRevisionTimestamp(bytes32 itemId, uint revisionId) external view revisionExists(itemId, revisionId) returns (uint) {
        return _getRevisionTimestamp(itemId, revisionId);
    }

    /**
     * @dev Get the timestamps for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return Timestamps of all revisions of the item.
     */
    function getAllRevisionTimestamps(bytes32 itemId) external view inUse(itemId) returns (uint[] memory) {
        return _getAllRevisionTimestamps(itemId);
    }

}


tests for all of math lib created.

tests for all of math lib created.

/*
    Copyright 2017 Phillip A. Elsasser

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

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

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

pragma solidity 0.4.18;

import "truffle/Assert.sol";
import "../../contracts/libraries/MathLib.sol";

/// @title TestMathLib tests for all of our math functions
/// @author Phil Elsasser <phil@marketprotcol.io>
contract TestMathLib {

    function testSign() public {
        Assert.equal(MathLib.sign(0), 0, "Sign of 0 should be 0");
        Assert.equal(MathLib.sign(-50), -1, "Sign of a negative should be -1");
        Assert.equal(MathLib.sign(50), 1, "Sign of a positive should be 1");
    }

    function testIsSameSign() public {
        Assert.isTrue(MathLib.isSameSign(0, 0), "Sign of 0 is 0");
        Assert.isTrue(MathLib.isSameSign(-50, -120), "Sign of a negatives should be equal");
        Assert.isTrue(MathLib.isSameSign(1, 100000), "Sign of a positives should be equal");
        Assert.isTrue(!MathLib.isSameSign(1, -100000), "Sign of a positive and negative are not equal");
    }

    function testAbs() public {
        Assert.equal(MathLib.abs(0), 0, "abs of 0 should be 0");
        Assert.equal(MathLib.abs(15), 15, "abs of positive should be same");
        Assert.equal(MathLib.abs(-15), 15, "abs of negative should be positive");
    }

    function testAbsMin() public {
        Assert.equal(MathLib.absMin(0, 250), 0, "0 is always the min");
        Assert.equal(MathLib.absMin(250, 0), 0, "0 is always the min");
        Assert.equal(MathLib.absMin(-250, 0), 0, "0 is always the min");
        Assert.equal(MathLib.absMin(15, -20), 15, "15 smaller than 20");
        Assert.equal(MathLib.absMin(-15, 20), -15, "15 smaller than 20");
        Assert.equal(MathLib.absMin(-15, -20), -15, "15 smaller than 20");
    }

    function testAbsMax() public {
        Assert.equal(MathLib.absMax(0, 250), 250, "250 further than 0");
        Assert.equal(MathLib.absMax(250, 0), 250, "250 further than 0");
        Assert.equal(MathLib.absMax(-250, 0), 250, "-250 further than 0");
        Assert.equal(MathLib.absMax(15, -20), -20, "-20 further from 0 than 15");
        Assert.equal(MathLib.absMax(-15, 20), 20, "+20 further from 0 than -15");
        Assert.equal(MathLib.absMax(-15, -20), -20, "-20 further from 0 than -15");
    }

    function testCalculateNeededCollateral() public {
        uint priceFloor = 250;
        uint priceCap = 350;
        uint qtyDecimalPlaces = 100;
        uint price = 275;
        int longQty = 2;
        int shortQty = -5;
        uint neededCollateralForLongPos = MathLib.calculateNeededCollateral(
            priceFloor,
            priceCap,
            qtyDecimalPlaces,
            longQty,
            price
        );

        // for a long position we need to look at the priceFloor from the price, this represents a longs max loss
        // so 275-250 is max loss per 1 lot, 25 * longQty * qtyDecimalPlaces should equal 5000
        Assert.equal(neededCollateralForLongPos, 5000, "max loss of 25 and qty of 2 with 100 decimals should be 5000 units");

        uint neededCollateralForShortPos = MathLib.calculateNeededCollateral(
            priceFloor,
            priceCap,
            qtyDecimalPlaces,
            shortQty,
            price
        );
        // for a short position we need to look at the priceCeiling from the price, this represents a shorts max loss
        // so 350 - 275 = 125 max loss per unit * 5 units * 100 decimal places = 62500 collateral units
        Assert.equal(neededCollateralForShortPos, 62500, "max loss of 125 and qty of 5 with 100 decimals should be 62500 units");
    }
}

/*
    Copyright 2017 Phillip A. Elsasser

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

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

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

pragma solidity 0.4.18;

import "truffle/Assert.sol";
import "../../contracts/libraries/MathLib.sol";

contract TestMathLib {

    function testSign() public {
        Assert.equal(MathLib.sign(0), 0, "Sign of 0 should be 0");
        Assert.equal(MathLib.sign(-50), -1, "Sign of a negative should be -1");
        Assert.equal(MathLib.sign(50), 1, "Sign of a positive should be 1");
    }
}


fix lint stuff

fix lint stuff

pragma solidity ^0.4.4;

contract Owned {

    address public owner;

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

    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }
}

contract Randomized is Owned {

    uint public price;
    bool public disabled;

    function Randomized() {
        price = 0;
        disabled = true;
    }

    struct Key {
        uint entryBlockNumber;
        bytes32 publicKey;
    }

    mapping (address => Key[]) keys;

    function setKey(bytes32 publicKey) payable public {
        require(!disabled);
        require(msg.value >= price);
        Key[] storage senderKeys = keys[msg.sender];
        require(senderKeys.length == 0 || senderKeys[senderKeys.length-1].entryBlockNumber < block.number);
        senderKeys.push(Key(block.number, publicKey));
    }

    function validate(uint seedBlockNumber, bytes32 seed, address sender, bytes32 crypted, bytes32 result) constant public returns (bool) {
        require(!disabled);
        if (keccak256(crypted, seed) != result)
            return false;
        Key memory key = findKey(keys[sender], seedBlockNumber);
        if (key.entryBlockNumber >= seedBlockNumber)
            return false;
        return keccak256(seed) == privatized(crypted, key.publicKey);
    }

    function setPrice(uint newprice) public onlyOwner {
        require(disabled);
        price = newprice;
    }

    function disableContract() public onlyOwner {
        disabled = true;
    }

    function enableContract() public onlyOwner {
        disabled = false;
    }

    function findKey(Key[] addressKeys, uint seedBlockNumber) constant private returns (Key) {
        uint x = addressKeys.length;
        while (x > 0) {
            x -= 1;
            if (seedBlockNumber > addressKeys[x].entryBlockNumber) {
                return addressKeys[x];
            }
        }
        return Key(0, 0x0);
    }

    function privatized(bytes32 crypted, bytes32 publicKey) constant private returns (bytes32) {
        // Waiting for https://github.com/ethereum/EIPs/pull/198
        // And specifically this from geth (and same from other clients):
        // https://github.com/ethereum/go-ethereum/blob/104375f398bdfca88183010cc3693e377ea74163/core/vm/contracts.go#L56
        // For now using just a simple bitwise xor to get the bidirectional mapping for testing
        return crypted ^ publicKey;
    }

}


Fix flag docs.

Fix flag docs.

pragma solidity ^0.4.18;

import "./item_store_interface.sol";
import "./item_store_registry.sol";

/**
 * @title ItemStoreIpfsSha256
 * @author Jonathan Brown <jbrown@mix-blockchain.org>
 * @dev ItemStore implementation where each item revision is a SHA256 IPFS hash.
 */
contract ItemStoreIpfsSha256 is ItemStoreInterface {

    byte constant UPDATABLE = 0x01;           // True if the item is updatable. After creation can only be disabled.
    byte constant ENFORCE_REVISIONS = 0x02;   // True if the item is enforcing revisions. After creation can only be enabled.
    byte constant RETRACTABLE = 0x04;         // True if the item can be retracted. After creation can only be disabled.
    byte constant TRANSFERABLE = 0x08;        // True if the item can be transfered to another user or disowned. After creation can only be disabled.
    byte constant DISOWN = 0x10;              // True if the item should not have an owner at creation.

    /**
     * @dev Single slot structure of item state.
     */
    struct ItemState {
        bool inUse;             // Has this itemId ever been used.
        byte flags;             // Packed item settings.
        uint32 revisionCount;   // Number of revisions including revision 0.
        uint32 timestamp;       // Timestamp of revision 0.
        address owner;          // Who owns this item.
    }

    /**
     * @dev Mapping of itemId to item state.
     */
    mapping (bytes20 => ItemState) itemState;

    /**
     * @dev Mapping of itemId to mapping of packed slots of eight 32-bit timestamps.
     */
    mapping (bytes20 => mapping (uint => bytes32)) packedTimestamps;

    /**
     * @dev Mapping of itemId to mapping of revision number to IPFS hash.
     */
    mapping (bytes20 => mapping (uint => bytes32)) itemRevisionIpfsHashes;

    /**
     * @dev Mapping of itemId to mapping of transfer recipient addresses to enabled.
     */
    mapping (bytes20 => mapping (address => bool)) enabledTransfers;

    /**
     * @dev Id of this instance of ItemStore. Unique across all blockchains.
     */
    bytes12 contractId;

    /**
     * @dev An item revision has been published.
     * @param itemId Id of the item.
     * @param owner Address of the item owner.
     * @param flags Flags the item was created with.
     */
    event Create(bytes20 indexed itemId, address indexed owner, byte flags);

    /**
     * @dev An item revision has been published.
     * @param itemId Id of the item.
     * @param revisionId Id of the revision (the highest at time of logging).
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    event PublishRevision(bytes20 indexed itemId, uint revisionId, bytes32 ipfsHash);

    /**
     * @dev Revert if the itemId is not in use.
     * @param itemId Id of the item.
     */
    modifier inUse(bytes20 itemId) {
        require (itemState[itemId].inUse);
        _;
    }

    /**
     * @dev Revert if the owner of the item is not the message sender.
     * @param itemId Id of the item.
     */
    modifier isOwner(bytes20 itemId) {
        require (itemState[itemId].owner == msg.sender);
        _;
    }

    /**
     * @dev Revert if the item is not updatable.
     * @param itemId Id of the item.
     */
    modifier isUpdatable(bytes20 itemId) {
        require (itemState[itemId].flags & UPDATABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not enforcing revisions.
     * @param itemId Id of the item.
     */
    modifier isNotEnforceRevisions(bytes20 itemId) {
        require (itemState[itemId].flags & ENFORCE_REVISIONS == 0);
        _;
    }

    /**
     * @dev Revert if the item is not retractable.
     * @param itemId Id of the item.
     */
    modifier isRetractable(bytes20 itemId) {
        require (itemState[itemId].flags & RETRACTABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not transferable.
     * @param itemId Id of the item.
     */
    modifier isTransferable(bytes20 itemId) {
        require (itemState[itemId].flags & TRANSFERABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not transferable to a specific user.
     * @param itemId Id of the item.
     * @param recipient Address of the user.
     */
    modifier isTransferEnabled(bytes20 itemId, address recipient) {
        require (enabledTransfers[itemId][recipient]);
        _;
    }

    /**
     * @dev Revert if the item only has one revision.
     * @param itemId Id of the item.
     */
    modifier hasAdditionalRevisions(bytes20 itemId) {
        require (itemState[itemId].revisionCount > 1);
        _;
    }

    /**
     * @dev Revert if a specific item revision does not exist.
     * @param itemId Id of the item.
     * @param revisionId Id of the revision.
     */
    modifier revisionExists(bytes20 itemId, uint revisionId) {
        require (revisionId < itemState[itemId].revisionCount);
        _;
    }

    /**
     * @dev Constructor.
     * @param registry Address of ItemStoreRegistry contract to register with.
     */
    function ItemStoreIpfsSha256(ItemStoreRegistry registry) public {
        // Create id for this contract.
        contractId = bytes12(keccak256(this, block.blockhash(block.number - 1)));
        // Register this contract.
        registry.register(contractId);
    }

    /**
     * @dev Creates a new item. It is guaranteed that different users will never receive the same itemId, even before consensus has been reached. This prevents itemId sniping.
     * @param flagsNonce Nonce that this address has never passed before; first byte is creation flags.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     * @return itemId Id of the item.
     */
    function create(bytes32 flagsNonce, bytes32 ipfsHash) external returns (bytes20 itemId) {
        // Generate the itemId.
        itemId = bytes20(keccak256(msg.sender, flagsNonce));
        // Make sure this itemId has not been used before.
        require (!itemState[itemId].inUse);
        // Extract the flags.
        byte flags = byte(flagsNonce);
        // Determine the owner.
        address owner = (flags & DISOWN == 0) ? msg.sender : 0;
        // Store item state.
        itemState[itemId] = ItemState({
            inUse: true,
            flags: flags,
            revisionCount: 1,
            timestamp: uint32(block.timestamp),
            owner: owner
        });
        // Store the IPFS hash.
        itemRevisionIpfsHashes[itemId][0] = ipfsHash;
        // Log item creation.
        Create(itemId, owner, flags);
        // Log the first revision.
        PublishRevision(itemId, 0, ipfsHash);
    }

    /**
     * @dev Store an item revision timestamp in a packed slot.
     * @param itemId Id of the item.
     * @param offset The offset of the timestamp that should be stored.
     */
    function _setPackedTimestamp(bytes20 itemId, uint offset) internal {
        // Get the slot.
        bytes32 slot = packedTimestamps[itemId][offset / 8];
        // Calculate the shift.
        uint shift = (offset % 8) * 32;
        // Wipe the previous timestamp.
        slot &= ~(bytes32(uint32(-1)) << shift);
        // Insert the current timestamp.
        slot |= bytes32(uint32(block.timestamp)) << shift;
        // Store the slot.
        packedTimestamps[itemId][offset / 8] = slot;
    }

    /**
     * @dev Create a new item revision.
     * @param itemId Id of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     * @return revisionId The new revisionId.
     */
    function createNewRevision(bytes20 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) returns (uint revisionId) {
        // Increment the number of revisions.
        revisionId = itemState[itemId].revisionCount++;
        // Store the IPFS hash.
        itemRevisionIpfsHashes[itemId][revisionId] = ipfsHash;
        // Store the timestamp.
        _setPackedTimestamp(itemId, revisionId - 1);
        // Log the revision.
        PublishRevision(itemId, revisionId, ipfsHash);
    }

    /**
     * @dev Update an item's latest revision.
     * @param itemId Id of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    function updateLatestRevision(bytes20 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Determine the revisionId.
        uint revisionId = state.revisionCount - 1;
        // Update the IPFS hash.
        itemRevisionIpfsHashes[itemId][revisionId] = ipfsHash;
        // Update the timestamp.
        if (revisionId == 0) {
            state.timestamp = uint32(block.timestamp);
        }
        else {
            _setPackedTimestamp(itemId, revisionId - 1);
        }
        // Log the revision.
        PublishRevision(itemId, revisionId, ipfsHash);
    }

    /**
     * @dev Retract an item's latest revision. Revision 0 cannot be retracted.
     * @param itemId Id of the item.
     */
    function retractLatestRevision(bytes20 itemId) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) hasAdditionalRevisions(itemId) {
        // Decrement the number of revisions.
        uint revisionId = --itemState[itemId].revisionCount;
        // Delete the IPFS hash.
        delete itemRevisionIpfsHashes[itemId][revisionId];
        // Delete the packed timestamp slot if it is no longer required.
        if (revisionId % 8 == 1) {
            delete packedTimestamps[itemId][revisionId / 8];
        }
        // Log the revision retraction.
        RetractRevision(itemId, revisionId);
    }

    /**
     * @dev Delete all of an item's packed revision timestamps.
     * @param itemId Id of the item.
     */
    function _deleteAllPackedRevisionTimestamps(bytes20 itemId) internal {
        // Determine how many slots should be deleted.
        // Timestamp of the first revision is stored in the item state, so the first slot only needs to be deleted if there are at least 2 revisions.
        uint slotCount = (itemState[itemId].revisionCount + 6) / 8;
        // Delete the slots.
        for (uint i = 0; i < slotCount; i++) {
            delete packedTimestamps[itemId][i];
        }
    }

    /**
     * @dev Delete all an item's revisions and replace it with a new item.
     * @param itemId Id of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    function restart(bytes20 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) {
        // Delete all the IPFS hashes except the first one.
        for (uint i = 1; i < itemState[itemId].revisionCount; i++) {
            delete itemRevisionIpfsHashes[itemId][i];
        }
        // Delete the packed revision timestamps.
        _deleteAllPackedRevisionTimestamps(itemId);
        // Update the item state.
        itemState[itemId].revisionCount = 1;
        itemState[itemId].timestamp = uint32(block.timestamp);
        // Update the first IPFS hash.
        itemRevisionIpfsHashes[itemId][0] = ipfsHash;
        // Log the revision.
        PublishRevision(itemId, 0, ipfsHash);
    }

    /**
     * @dev Retract an item.
     * @param itemId Id of the item. This itemId can never be used again.
     */
    function retract(bytes20 itemId) external isOwner(itemId) isRetractable(itemId) {
        // Delete all the IPFS hashes.
        for (uint i = 0; i < itemState[itemId].revisionCount; i++) {
            delete itemRevisionIpfsHashes[itemId][i];
        }
        // Mark this item as retracted.
        itemState[itemId] = ItemState({
            inUse: true,
            flags: 0,
            revisionCount: 0,
            timestamp: 0,
            owner: 0
        });
        // Log the item retraction.
        Retract(itemId);
    }

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

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

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

    /**
     * @dev Disown an item.
     * @param itemId Id of the item.
     */
    function disown(bytes20 itemId) external isOwner(itemId) isTransferable(itemId) {
        // Remove the owner from the item's state.
        delete itemState[itemId].owner;
        // Log that the item has been disowned.
        Disown(itemId);
    }

    /**
     * @dev Set an item as not updatable.
     * @param itemId Id of the item.
     */
    function setNotUpdatable(bytes20 itemId) external isOwner(itemId) {
        // Record in state that the item is not updatable.
        itemState[itemId].flags &= ~UPDATABLE;
        // Log that the item is not updatable.
        SetNotUpdatable(itemId);
    }

    /**
     * @dev Set an item to enforce revisions.
     * @param itemId Id of the item.
     */
    function setEnforceRevisions(bytes20 itemId) external isOwner(itemId) {
        // Record in state that all changes to this item must be new revisions.
        itemState[itemId].flags |= ENFORCE_REVISIONS;
        // Log that the item now enforces new revisions.
        SetEnforceRevisions(itemId);
    }

    /**
     * @dev Set an item to not be retractable.
     * @param itemId Id of the item.
     */
    function setNotRetractable(bytes20 itemId) external isOwner(itemId) {
        // Record in state that the item is not retractable.
        itemState[itemId].flags &= ~RETRACTABLE;
        // Log that the item is not retractable.
        SetNotRetractable(itemId);
    }

    /**
     * @dev Set an item to not be transferable.
     * @param itemId Id of the item.
     */
    function setNotTransferable(bytes20 itemId) external isOwner(itemId) {
        // Record in state that the item is not transferable.
        itemState[itemId].flags &= ~TRANSFERABLE;
        // Log that the item is not transferable.
        SetNotTransferable(itemId);
    }

    /**
     * @dev Get the id for this ItemStore contract.
     * @return Id of the contract.
     */
    function getContractId() external view returns (bytes12) {
        return contractId;
    }

    /**
     * @dev Check if an itemId is in use.
     * @param itemId Id of the item.
     * @return True if the itemId is in use.
     */
    function getInUse(bytes20 itemId) external view returns (bool) {
        return itemState[itemId].inUse;
    }

    /**
     * @dev Get the IPFS hashes for all of an item's revisions.
     * @param itemId Id of the item.
     * @return ipfsHashes Revision IPFS hashes.
     */
    function _getAllRevisionIpfsHashes(bytes20 itemId) internal view returns (bytes32[] ipfsHashes) {
        uint revisionCount = itemState[itemId].revisionCount;
        ipfsHashes = new bytes32[](revisionCount);
        for (uint revisionId = 0; revisionId < revisionCount; revisionId++) {
            ipfsHashes[revisionId] = itemRevisionIpfsHashes[itemId][revisionId];
        }
    }

    /**
     * @dev Get the timestamp for a specific item revision.
     * @param itemId Id of the item.
     * @param revisionId Id of the revision.
     * @return timestamp Timestamp of the specified revision.
     */
    function _getRevisionTimestamp(bytes20 itemId, uint revisionId) internal view returns (uint timestamp) {
        if (revisionId == 0) {
            timestamp = itemState[itemId].timestamp;
        }
        else {
            uint offset = revisionId - 1;
            timestamp = uint32(packedTimestamps[itemId][offset / 8] >> ((offset % 8) * 32));
        }
    }

    /**
     * @dev Get the timestamps for all of an item's revisions.
     * @param itemId Id of the item.
     * @return timestamps Revision timestamps.
     */
    function _getAllRevisionTimestamps(bytes20 itemId) internal view returns (uint[] timestamps) {
        uint revisionCount = itemState[itemId].revisionCount;
        timestamps = new uint[](revisionCount);
        for (uint revisionId = 0; revisionId < revisionCount; revisionId++) {
            timestamps[revisionId] = _getRevisionTimestamp(itemId, revisionId);
        }
    }

    /**
     * @dev Get item state.
     * @param itemId Id of the item.
     * @return flags Packed item settings.
     * @return owner Owner of the item.
     * @return revisionCount How many revisions the item has.
     * @return ipfsHashes IPFS hash of each revision.
     * @return timestamps Timestamp of each revision.
     */
    function getState(bytes20 itemId) external view inUse(itemId) returns (byte flags, address owner, uint revisionCount, bytes32[] ipfsHashes, uint[] timestamps) {
        ItemState storage state = itemState[itemId];
        flags = state.flags;
        owner = state.owner;
        revisionCount = state.revisionCount;
        ipfsHashes = _getAllRevisionIpfsHashes(itemId);
        timestamps = _getAllRevisionTimestamps(itemId);
    }

    /**
     * @dev Get all an item's flags.
     * @param itemId Id of the item.
     * @return Packed item settings.
     */
    function getFlags(bytes20 itemId) external view inUse(itemId) returns (byte) {
        return itemState[itemId].flags;
    }

    /**
     * @dev Determine if an item is updatable.
     * @param itemId Id of the item.
     * @return True if the item is updatable.
     */
    function getUpdatable(bytes20 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & UPDATABLE != 0;
    }

    /**
     * @dev Determine if an item enforces revisions.
     * @param itemId Id of the item.
     * @return True if the item enforces revisions.
     */
    function getEnforceRevisions(bytes20 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & ENFORCE_REVISIONS != 0;
    }

    /**
     * @dev Determine if an item is retractable.
     * @param itemId Id of the item.
     * @return True if the item is item retractable.
     */
    function getRetractable(bytes20 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & RETRACTABLE != 0;
    }

    /**
     * @dev Determine if an item is transferable.
     * @param itemId Id of the item.
     * @return True if the item is transferable.
     */
    function getTransferable(bytes20 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & TRANSFERABLE != 0;
    }

    /**
     * @dev Get the owner of an item.
     * @param itemId Id of the item.
     * @return Owner of the item.
     */
    function getOwner(bytes20 itemId) external view inUse(itemId) returns (address) {
        return itemState[itemId].owner;
    }

    /**
     * @dev Get the number of revisions an item has.
     * @param itemId Id of the item.
     * @return How many revisions the item has.
     */
    function getRevisionCount(bytes20 itemId) external view inUse(itemId) returns (uint) {
        return itemState[itemId].revisionCount;
    }

   /**
     * @dev Get the IPFS hash for a specific item revision.
     * @param itemId Id of the item.
     * @param revisionId Id of the revision.
     * @return IPFS hash of the specified revision.
     */
    function getRevisionIpfsHash(bytes20 itemId, uint revisionId) external view revisionExists(itemId, revisionId) returns (bytes32) {
        return itemRevisionIpfsHashes[itemId][revisionId];
    }

    /**
     * @dev Get the IPFS hashes for all of an item's revisions.
     * @param itemId Id of the item.
     * @return IPFS hashes of all revisions of the item.
     */
    function getAllRevisionIpfsHashes(bytes20 itemId) external view inUse(itemId) returns (bytes32[]) {
        return _getAllRevisionIpfsHashes(itemId);
    }

   /**
     * @dev Get the timestamp for a specific item revision.
     * @param itemId Id of the item.
     * @param revisionId Id of the revision.
     * @return Timestamp of the specified revision.
     */
    function getRevisionTimestamp(bytes20 itemId, uint revisionId) external view revisionExists(itemId, revisionId) returns (uint) {
        return _getRevisionTimestamp(itemId, revisionId);
    }

    /**
     * @dev Get the timestamps for all of an item's revisions.
     * @param itemId Id of the item.
     * @return Timestamps of all revisions of the item.
     */
    function getAllRevisionTimestamps(bytes20 itemId) external view inUse(itemId) returns (uint[]) {
        return _getAllRevisionTimestamps(itemId);
    }

}

pragma solidity ^0.4.18;

import "./item_store_interface.sol";
import "./item_store_registry.sol";

/**
 * @title ItemStoreIpfsSha256
 * @author Jonathan Brown <jbrown@mix-blockchain.org>
 * @dev ItemStore implementation where each item revision is a SHA256 IPFS hash.
 */
contract ItemStoreIpfsSha256 is ItemStoreInterface {

    byte constant UPDATABLE = 0x01;           // True if the item is updatable. After creation can only be disabled.
    byte constant ENFORCE_REVISIONS = 0x02;   // True if the item is enforcing revisions. After creation can only be enabled.
    byte constant RETRACTABLE = 0x04;         // True if the item can be retracted. After creation can only be disabled.
    byte constant TRANSFERABLE = 0x08;        // True if the item be transfered to another user or disowned. After creation can only be disabled.
    byte constant DISOWN = 0x10;              // True if the item should not have an owner.

    /**
     * @dev Single slot structure of item state.
     */
    struct ItemState {
        bool inUse;             // Has this itemId ever been used.
        byte flags;             // Packed item settings.
        uint32 revisionCount;   // Number of revisions including revision 0.
        uint32 timestamp;       // Timestamp of revision 0.
        address owner;          // Who owns this item.
    }

    /**
     * @dev Mapping of itemId to item state.
     */
    mapping (bytes20 => ItemState) itemState;

    /**
     * @dev Mapping of itemId to mapping of packed slots of eight 32-bit timestamps.
     */
    mapping (bytes20 => mapping (uint => bytes32)) packedTimestamps;

    /**
     * @dev Mapping of itemId to mapping of revision number to IPFS hash.
     */
    mapping (bytes20 => mapping (uint => bytes32)) itemRevisionIpfsHashes;

    /**
     * @dev Mapping of itemId to mapping of transfer recipient addresses to enabled.
     */
    mapping (bytes20 => mapping (address => bool)) enabledTransfers;

    /**
     * @dev Id of this instance of ItemStore. Unique across all blockchains.
     */
    bytes12 contractId;

    /**
     * @dev An item revision has been published.
     * @param itemId Id of the item.
     * @param owner Address of the item owner.
     * @param flags Flags the item was created with.
     */
    event Create(bytes20 indexed itemId, address indexed owner, byte flags);

    /**
     * @dev An item revision has been published.
     * @param itemId Id of the item.
     * @param revisionId Id of the revision (the highest at time of logging).
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    event PublishRevision(bytes20 indexed itemId, uint revisionId, bytes32 ipfsHash);

    /**
     * @dev Revert if the itemId is not in use.
     * @param itemId Id of the item.
     */
    modifier inUse(bytes20 itemId) {
        require (itemState[itemId].inUse);
        _;
    }

    /**
     * @dev Revert if the owner of the item is not the message sender.
     * @param itemId Id of the item.
     */
    modifier isOwner(bytes20 itemId) {
        require (itemState[itemId].owner == msg.sender);
        _;
    }

    /**
     * @dev Revert if the item is not updatable.
     * @param itemId Id of the item.
     */
    modifier isUpdatable(bytes20 itemId) {
        require (itemState[itemId].flags & UPDATABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not enforcing revisions.
     * @param itemId Id of the item.
     */
    modifier isNotEnforceRevisions(bytes20 itemId) {
        require (itemState[itemId].flags & ENFORCE_REVISIONS == 0);
        _;
    }

    /**
     * @dev Revert if the item is not retractable.
     * @param itemId Id of the item.
     */
    modifier isRetractable(bytes20 itemId) {
        require (itemState[itemId].flags & RETRACTABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not transferable.
     * @param itemId Id of the item.
     */
    modifier isTransferable(bytes20 itemId) {
        require (itemState[itemId].flags & TRANSFERABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not transferable to a specific user.
     * @param itemId Id of the item.
     * @param recipient Address of the user.
     */
    modifier isTransferEnabled(bytes20 itemId, address recipient) {
        require (enabledTransfers[itemId][recipient]);
        _;
    }

    /**
     * @dev Revert if the item only has one revision.
     * @param itemId Id of the item.
     */
    modifier hasAdditionalRevisions(bytes20 itemId) {
        require (itemState[itemId].revisionCount > 1);
        _;
    }

    /**
     * @dev Revert if a specific item revision does not exist.
     * @param itemId Id of the item.
     * @param revisionId Id of the revision.
     */
    modifier revisionExists(bytes20 itemId, uint revisionId) {
        require (revisionId < itemState[itemId].revisionCount);
        _;
    }

    /**
     * @dev Constructor.
     * @param registry Address of ItemStoreRegistry contract to register with.
     */
    function ItemStoreIpfsSha256(ItemStoreRegistry registry) public {
        // Create id for this contract.
        contractId = bytes12(keccak256(this, block.blockhash(block.number - 1)));
        // Register this contract.
        registry.register(contractId);
    }

    /**
     * @dev Creates a new item. It is guaranteed that different users will never receive the same itemId, even before consensus has been reached. This prevents itemId sniping.
     * @param flagsNonce Nonce that this address has never passed before; first byte is creation flags.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     * @return itemId Id of the item.
     */
    function create(bytes32 flagsNonce, bytes32 ipfsHash) external returns (bytes20 itemId) {
        // Generate the itemId.
        itemId = bytes20(keccak256(msg.sender, flagsNonce));
        // Make sure this itemId has not been used before.
        require (!itemState[itemId].inUse);
        // Extract the flags.
        byte flags = byte(flagsNonce);
        // Determine the owner.
        address owner = (flags & DISOWN == 0) ? msg.sender : 0;
        // Store item state.
        itemState[itemId] = ItemState({
            inUse: true,
            flags: flags,
            revisionCount: 1,
            timestamp: uint32(block.timestamp),
            owner: owner
        });
        // Store the IPFS hash.
        itemRevisionIpfsHashes[itemId][0] = ipfsHash;
        // Log item creation.
        Create(itemId, owner, flags);
        // Log the first revision.
        PublishRevision(itemId, 0, ipfsHash);
    }

    /**
     * @dev Store an item revision timestamp in a packed slot.
     * @param itemId Id of the item.
     * @param offset The offset of the timestamp that should be stored.
     */
    function _setPackedTimestamp(bytes20 itemId, uint offset) internal {
        // Get the slot.
        bytes32 slot = packedTimestamps[itemId][offset / 8];
        // Calculate the shift.
        uint shift = (offset % 8) * 32;
        // Wipe the previous timestamp.
        slot &= ~(bytes32(uint32(-1)) << shift);
        // Insert the current timestamp.
        slot |= bytes32(uint32(block.timestamp)) << shift;
        // Store the slot.
        packedTimestamps[itemId][offset / 8] = slot;
    }

    /**
     * @dev Create a new item revision.
     * @param itemId Id of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     * @return revisionId The new revisionId.
     */
    function createNewRevision(bytes20 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) returns (uint revisionId) {
        // Increment the number of revisions.
        revisionId = itemState[itemId].revisionCount++;
        // Store the IPFS hash.
        itemRevisionIpfsHashes[itemId][revisionId] = ipfsHash;
        // Store the timestamp.
        _setPackedTimestamp(itemId, revisionId - 1);
        // Log the revision.
        PublishRevision(itemId, revisionId, ipfsHash);
    }

    /**
     * @dev Update an item's latest revision.
     * @param itemId Id of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    function updateLatestRevision(bytes20 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Determine the revisionId.
        uint revisionId = state.revisionCount - 1;
        // Update the IPFS hash.
        itemRevisionIpfsHashes[itemId][revisionId] = ipfsHash;
        // Update the timestamp.
        if (revisionId == 0) {
            state.timestamp = uint32(block.timestamp);
        }
        else {
            _setPackedTimestamp(itemId, revisionId - 1);
        }
        // Log the revision.
        PublishRevision(itemId, revisionId, ipfsHash);
    }

    /**
     * @dev Retract an item's latest revision. Revision 0 cannot be retracted.
     * @param itemId Id of the item.
     */
    function retractLatestRevision(bytes20 itemId) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) hasAdditionalRevisions(itemId) {
        // Decrement the number of revisions.
        uint revisionId = --itemState[itemId].revisionCount;
        // Delete the IPFS hash.
        delete itemRevisionIpfsHashes[itemId][revisionId];
        // Delete the packed timestamp slot if it is no longer required.
        if (revisionId % 8 == 1) {
            delete packedTimestamps[itemId][revisionId / 8];
        }
        // Log the revision retraction.
        RetractRevision(itemId, revisionId);
    }

    /**
     * @dev Delete all of an item's packed revision timestamps.
     * @param itemId Id of the item.
     */
    function _deleteAllPackedRevisionTimestamps(bytes20 itemId) internal {
        // Determine how many slots should be deleted.
        // Timestamp of the first revision is stored in the item state, so the first slot only needs to be deleted if there are at least 2 revisions.
        uint slotCount = (itemState[itemId].revisionCount + 6) / 8;
        // Delete the slots.
        for (uint i = 0; i < slotCount; i++) {
            delete packedTimestamps[itemId][i];
        }
    }

    /**
     * @dev Delete all an item's revisions and replace it with a new item.
     * @param itemId Id of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    function restart(bytes20 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) {
        // Delete all the IPFS hashes except the first one.
        for (uint i = 1; i < itemState[itemId].revisionCount; i++) {
            delete itemRevisionIpfsHashes[itemId][i];
        }
        // Delete the packed revision timestamps.
        _deleteAllPackedRevisionTimestamps(itemId);
        // Update the item state.
        itemState[itemId].revisionCount = 1;
        itemState[itemId].timestamp = uint32(block.timestamp);
        // Update the first IPFS hash.
        itemRevisionIpfsHashes[itemId][0] = ipfsHash;
        // Log the revision.
        PublishRevision(itemId, 0, ipfsHash);
    }

    /**
     * @dev Retract an item.
     * @param itemId Id of the item. This itemId can never be used again.
     */
    function retract(bytes20 itemId) external isOwner(itemId) isRetractable(itemId) {
        // Delete all the IPFS hashes.
        for (uint i = 0; i < itemState[itemId].revisionCount; i++) {
            delete itemRevisionIpfsHashes[itemId][i];
        }
        // Mark this item as retracted.
        itemState[itemId] = ItemState({
            inUse: true,
            flags: 0,
            revisionCount: 0,
            timestamp: 0,
            owner: 0
        });
        // Log the item retraction.
        Retract(itemId);
    }

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

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

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

    /**
     * @dev Disown an item.
     * @param itemId Id of the item.
     */
    function disown(bytes20 itemId) external isOwner(itemId) isTransferable(itemId) {
        // Remove the owner from the item's state.
        delete itemState[itemId].owner;
        // Log that the item has been disowned.
        Disown(itemId);
    }

    /**
     * @dev Set an item as not updatable.
     * @param itemId Id of the item.
     */
    function setNotUpdatable(bytes20 itemId) external isOwner(itemId) {
        // Record in state that the item is not updatable.
        itemState[itemId].flags &= ~UPDATABLE;
        // Log that the item is not updatable.
        SetNotUpdatable(itemId);
    }

    /**
     * @dev Set an item to enforce revisions.
     * @param itemId Id of the item.
     */
    function setEnforceRevisions(bytes20 itemId) external isOwner(itemId) {
        // Record in state that all changes to this item must be new revisions.
        itemState[itemId].flags |= ENFORCE_REVISIONS;
        // Log that the item now enforces new revisions.
        SetEnforceRevisions(itemId);
    }

    /**
     * @dev Set an item to not be retractable.
     * @param itemId Id of the item.
     */
    function setNotRetractable(bytes20 itemId) external isOwner(itemId) {
        // Record in state that the item is not retractable.
        itemState[itemId].flags &= ~RETRACTABLE;
        // Log that the item is not retractable.
        SetNotRetractable(itemId);
    }

    /**
     * @dev Set an item to not be transferable.
     * @param itemId Id of the item.
     */
    function setNotTransferable(bytes20 itemId) external isOwner(itemId) {
        // Record in state that the item is not transferable.
        itemState[itemId].flags &= ~TRANSFERABLE;
        // Log that the item is not transferable.
        SetNotTransferable(itemId);
    }

    /**
     * @dev Get the id for this ItemStore contract.
     * @return Id of the contract.
     */
    function getContractId() external view returns (bytes12) {
        return contractId;
    }

    /**
     * @dev Check if an itemId is in use.
     * @param itemId Id of the item.
     * @return True if the itemId is in use.
     */
    function getInUse(bytes20 itemId) external view returns (bool) {
        return itemState[itemId].inUse;
    }

    /**
     * @dev Get the IPFS hashes for all of an item's revisions.
     * @param itemId Id of the item.
     * @return ipfsHashes Revision IPFS hashes.
     */
    function _getAllRevisionIpfsHashes(bytes20 itemId) internal view returns (bytes32[] ipfsHashes) {
        uint revisionCount = itemState[itemId].revisionCount;
        ipfsHashes = new bytes32[](revisionCount);
        for (uint revisionId = 0; revisionId < revisionCount; revisionId++) {
            ipfsHashes[revisionId] = itemRevisionIpfsHashes[itemId][revisionId];
        }
    }

    /**
     * @dev Get the timestamp for a specific item revision.
     * @param itemId Id of the item.
     * @param revisionId Id of the revision.
     * @return timestamp Timestamp of the specified revision.
     */
    function _getRevisionTimestamp(bytes20 itemId, uint revisionId) internal view returns (uint timestamp) {
        if (revisionId == 0) {
            timestamp = itemState[itemId].timestamp;
        }
        else {
            uint offset = revisionId - 1;
            timestamp = uint32(packedTimestamps[itemId][offset / 8] >> ((offset % 8) * 32));
        }
    }

    /**
     * @dev Get the timestamps for all of an item's revisions.
     * @param itemId Id of the item.
     * @return timestamps Revision timestamps.
     */
    function _getAllRevisionTimestamps(bytes20 itemId) internal view returns (uint[] timestamps) {
        uint revisionCount = itemState[itemId].revisionCount;
        timestamps = new uint[](revisionCount);
        for (uint revisionId = 0; revisionId < revisionCount; revisionId++) {
            timestamps[revisionId] = _getRevisionTimestamp(itemId, revisionId);
        }
    }

    /**
     * @dev Get item state.
     * @param itemId Id of the item.
     * @return flags Packed item settings.
     * @return owner Owner of the item.
     * @return revisionCount How many revisions the item has.
     * @return ipfsHashes IPFS hash of each revision.
     * @return timestamps Timestamp of each revision.
     */
    function getState(bytes20 itemId) external view inUse(itemId) returns (byte flags, address owner, uint revisionCount, bytes32[] ipfsHashes, uint[] timestamps) {
        ItemState storage state = itemState[itemId];
        flags = state.flags;
        owner = state.owner;
        revisionCount = state.revisionCount;
        ipfsHashes = _getAllRevisionIpfsHashes(itemId);
        timestamps = _getAllRevisionTimestamps(itemId);
    }

    /**
     * @dev Get all an item's flags.
     * @param itemId Id of the item.
     * @return Packed item settings.
     */
    function getFlags(bytes20 itemId) external view inUse(itemId) returns (byte) {
        return itemState[itemId].flags;
    }

    /**
     * @dev Determine if an item is updatable.
     * @param itemId Id of the item.
     * @return True if the item is updatable.
     */
    function getUpdatable(bytes20 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & UPDATABLE != 0;
    }

    /**
     * @dev Determine if an item enforces revisions.
     * @param itemId Id of the item.
     * @return True if the item enforces revisions.
     */
    function getEnforceRevisions(bytes20 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & ENFORCE_REVISIONS != 0;
    }

    /**
     * @dev Determine if an item is retractable.
     * @param itemId Id of the item.
     * @return True if the item is item retractable.
     */
    function getRetractable(bytes20 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & RETRACTABLE != 0;
    }

    /**
     * @dev Determine if an item is transferable.
     * @param itemId Id of the item.
     * @return True if the item is transferable.
     */
    function getTransferable(bytes20 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & TRANSFERABLE != 0;
    }

    /**
     * @dev Get the owner of an item.
     * @param itemId Id of the item.
     * @return Owner of the item.
     */
    function getOwner(bytes20 itemId) external view inUse(itemId) returns (address) {
        return itemState[itemId].owner;
    }

    /**
     * @dev Get the number of revisions an item has.
     * @param itemId Id of the item.
     * @return How many revisions the item has.
     */
    function getRevisionCount(bytes20 itemId) external view inUse(itemId) returns (uint) {
        return itemState[itemId].revisionCount;
    }

   /**
     * @dev Get the IPFS hash for a specific item revision.
     * @param itemId Id of the item.
     * @param revisionId Id of the revision.
     * @return IPFS hash of the specified revision.
     */
    function getRevisionIpfsHash(bytes20 itemId, uint revisionId) external view revisionExists(itemId, revisionId) returns (bytes32) {
        return itemRevisionIpfsHashes[itemId][revisionId];
    }

    /**
     * @dev Get the IPFS hashes for all of an item's revisions.
     * @param itemId Id of the item.
     * @return IPFS hashes of all revisions of the item.
     */
    function getAllRevisionIpfsHashes(bytes20 itemId) external view inUse(itemId) returns (bytes32[]) {
        return _getAllRevisionIpfsHashes(itemId);
    }

   /**
     * @dev Get the timestamp for a specific item revision.
     * @param itemId Id of the item.
     * @param revisionId Id of the revision.
     * @return Timestamp of the specified revision.
     */
    function getRevisionTimestamp(bytes20 itemId, uint revisionId) external view revisionExists(itemId, revisionId) returns (uint) {
        return _getRevisionTimestamp(itemId, revisionId);
    }

    /**
     * @dev Get the timestamps for all of an item's revisions.
     * @param itemId Id of the item.
     * @return Timestamps of all revisions of the item.
     */
    function getAllRevisionTimestamps(bytes20 itemId) external view inUse(itemId) returns (uint[]) {
        return _getAllRevisionTimestamps(itemId);
    }

}