Token ready

Token ready

contract token {
    address public creator;
    string public symbol;
    string public name;
    uint public baseUnit;
    uint totalSupply;
    mapping (address => uint) balanceOf;
    mapping (address => mapping(address => bool)) approveOf;
    mapping (address => mapping(address => bool)) approveOnceOf;
    mapping (address => mapping(address => uint)) approveOnceValueOf;

    modifier creatorCheck { if (msg.sender == creator) _ }

    /* Events */
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event AddressApproval(address indexed _address, address indexed _proxy, bool _result);
    event AddressApprovalOnce(address indexed _address, address indexed _proxy, uint256 _value);

    /*Initial */
    function token() {
        creator = msg.sender;
    }

    /* Creator functions */
    function setSymbol(string _s) creatorCheck returns(bool result) {
        symbol = _s;
        return true;
    }
    function setName(string _n) creatorCheck returns(bool result) {
        name = _n;
        return true;
    }

    function setBaseUnit(uint _unit) creatorCheck returns(bool result) {
        baseUnit = _unit;
        return true;
    }

    function getTotalSupply()  creatorCheck returns (uint supply) {
        return totalSupply;
    }

    /* Agent function */

    function myBalance() returns (uint256 balance) {
        balance = balanceOf[msg.sender];
        return balance;
    }

    function transfer(address _to, uint256 _value) returns (bool result) {
        if (balanceOf[msg.sender] < _value) {return false;}
        if (balanceOf[msg.sender] + _value < balanceOf[msg.sender]) {return false;}
        balanceOf[msg.sender] -= _value;
        balanceOf[_to] += _value;
        Transfer(msg.sender, _to, _value);
        return true;
    }

    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        if(approveOf[_from][msg.sender])
        {
            if (balanceOf[_from] < _value) {return false;}
            if (balanceOf[_from] + _value < balanceOf[_from]) {return false;}
            balanceOf[_from] -= _value;
            balanceOf[_to] += _value;
            Transfer(_from, _to, _value);
            return true;
        } else if(approveOnceOf[_from][msg.sender] && approveOnceValueOf[_from][msg.sender]<=_value) {
            if (balanceOf[_from] < _value) {return false;}
            if (balanceOf[_from] + _value < balanceOf[_from]) {return false;}
            balanceOf[_from] -= _value;
            balanceOf[_to] += _value;
            Transfer(_from, _to, _value);
            return true;
        }

    }

    function approve(address _address) returns (bool result) {
        approveOf[msg.sender][_address] = true;
        AddressApproval(_address, msg.sender, true);
        return true;
    }

    function unapprove(address _address) returns (bool success) {
        approveOf[msg.sender][_address] = false;
        return true;
    }

    function approveOnce(address _address, uint256 _maxValue) returns (bool success) {
        approveOnceOf[msg.sender][_address] = true;
        approveOnceValueOf[msg.sender][_address] = _maxValue;
        AddressApprovalOnce(_address, msg.sender, _maxValue);
        return true;
    }

    function unapproveOnce(address _address) returns (bool success) {
        approveOnceOf[msg.sender][_address] = false;
        approveOnceValueOf[msg.sender][_address] = 0;
        return true;
    }

    function isApprovedOnceFor(address _target, address _proxy) returns (uint256 maxValue) {
        maxValue = approveOnceValueOf[_target][_proxy];
        return maxValue;
    }

    function isApprovedFor(address _target, address _proxy) constant returns (bool success) {
        success = approveOnceOf[_target][_proxy];
        return success;
    }
}

contract DAO {
    address public daoFounder;
    address public daoFounderContr;
    address public daoMarketContr;
    address public daoGovermentContr;
    bool public initialization;
    uint public creditAmount;
    uint public sharesAmount;
    uint public creditTurn;
    uint public numAgents;

    token public daoShares;
    token public daoCredits;

    /* Assets data */
    Asset[] public assetsList;
    mapping (address => uint) public assetDataOf;
    mapping (address => bool) public assetExistOf;
    struct Asset {
        address assetAddr;
    }

    /* Agents data */
    Agent[] public agentsList;
    mapping (address => uint) public agentDataOf;
    mapping (address => bool) public agentActiveOf;
    struct Agent {
        address agentContrAddr;
        uint joinData;
    }

    function DAO(token _shares, token _credits, market _daoMarketContr, goverment _daoGovermentContr) {
        daoFounder = msg.sender;
        daoShares = token(_shares);
        daoCredits = token(_credits);
        daoMarketContr = _daoMarketContr;
        daoGovermentContr = _daoGovermentContr;
    }

    function initializationDaoBalances(uint _founderSharesAmount, uint _founderCreditsAmount) returns (bool result) {
        if(!initialization) {
        daoShares.emission(msg.sender, _founderSharesAmount);
        sharesAmount = _founderSharesAmount;
        daoCredits.emission(msg.sender, _founderCreditsAmount);
        creditAmount = _founderCreditsAmount;
        return true;
        }
    }

    function daoEfficiency() returns (uint daoEfficiency) {
        daoEfficiency = creditTurn*100/creditAmount;
    }

    function daoShareCost() returns (uint shareCost) {
        shareCost = creditTurn/sharesAmount;
    }

    function daoCreditPower() returns (uint creditPower) {
        creditPower = sharesAmount*100/creditTurn;
    }

    function daoShareSale(uint _shareAmount) returns (uint creditReward) {
        if(daoShares.tokenBalanceOf(msg.sender)>=_shareAmount) {
            creditReward = daoShareCost()*_shareAmount;
            daoCredits.emission(msg.sender, creditReward);
            daoShares.burn(msg.sender, _shareAmount);
        }
    }

    function daoShareBuy(uint _creditAmount) returns (uint shares) {
        if(daoCredits.tokenBalanceOf(msg.sender)>=_creditAmount) {
            shares = daoCreditPower()*_creditAmount;
            daoShares.emission(msg.sender, shares);
            daoCredits.burn(msg.sender, _creditAmount);
        }
    }

    function daoSharesEmission(address _agentContrAddr, uint _sharesAmount) {
        daoShares.emission(_agentContrAddr, _sharesAmount);
    }

    function daoCreditEmission(uint _creditsAMount) {
        daoCredits.emission(msg.sender, _creditsAMount);
    }

    function setAgent(address _agentContAddr) returns(uint agentID) {
        if(daoShares.tokenBalanceOf(msg.sender)>0) {
            agentID = agentsList.length++;
            Agent a = agentsList[agentID];
            a.agentContrAddr = _agentContAddr;
            a.joinData = now;
            uint newAgentSharesAmount;
            newAgentSharesAmount = sharesAmount/numAgents;
            daoShares.emission(_agentContAddr, newAgentSharesAmount);
            numAgents = agentID;
            agentDataOf[_agentContAddr] = agentID;
            agentActiveOf[_agentContAddr] = true;
            return agentID;
        }
    }

    function setAssets(address _assetAddr) returns(uint assetID) {
        if (msg.sender == daoMarketContr) {
            assetID = assetsList.length++;
            Asset a = assetsList[assetID];
            a.assetAddr = _assetAddr;
            assetDataOf[_assetAddr] = assetID;
            assetExistOf[_assetAddr] = true;
            return assetID;
        }
    }
}

contract agent {
    address agentAddr;
    address controlAddr;
    address daoAddr;
    DAO public dao;

    /* Agents contract list*/

    AgentContract[] public agentContracts;
    struct AgentContract {
        address agentContractAddr;
        string abi;
    }

    modifier controlCheck { if (msg.sender == controlAddr) _ }

    function agent(address _daoAddr) {
        agentAddr = msg.sender;
        controlAddr = msg.sender;
        daoAddr = _daoAddr;
    }

    function setControlAddr(address _controlAddr) returns(bool result) {
        if(msg.sender == agentAddr) {
            controlAddr = _controlAddr;
        }
    }

    function setNewAgent(address _agentAddr) controlCheck returns(bool result) {
        dao.setAgent(_agentAddr);
        return true;
    }
}

contract market {
    address daoAddr;
    DAO public dao;

    struct Order {
        uint orderID;
        address owner;
        uint amount;
        uint price;
    }

    struct OrderList {
        address assetAddr;
        Order[] orders;
    }

    OrderList[] public sellList;
    Order[] public sellOrders;
    mapping (address => bool) sellExistOf;
    mapping (address => uint) sellDataOf;

    OrderList[] public buyList;
    Order[] public buyOrders;
    mapping (address => bool) buyExistOf;
    mapping (address => uint) buyDataOf;

    function getSellList(address _assetAddr) returns(uint assetID) {
        return 0;
    }

    function getBuyList(address _assetAddr) returns(uint assetID) {
        return 0;
    }

    function addSell(address _assetAddr, uint _amount, uint _price) returns(uint sellID) {
        if (dao.agentActiveOf(msg.sender) && dao.assetExistOf(_assetAddr)) {
            if(sellExistOf[_assetAddr]) {
                uint assetID;
                assetID = sellDataOf[_assetAddr];
                OrderList[] assetOrders = sellList[assetID];
                sellID = sellOrders.sellOrders.length++;
                sellOrders.orders[sellID] = Order({orderID: sellID, owner: msg.sender, amount: _amount, price: _price});
                return assetID;
            }

        }
    }

    function addBuy(address _assetAddr, uint _amount, uint _price) returns(uint buyID) {
        if (dao.agentActiveOf(msg.sender) && dao.assetExistOf(_assetAddr)) {
            if(buyExistOf[_assetAddr]) {
                uint assetID;
                assetID = buyDataOf[_assetAddr];
                OrderList[] buyOrders = buyList[assetID];
                buyID = buyOrders.orders.length++;
                buyOrders.orders[buyID] = Order({orderID: buyID, owner: msg.sender, amount: _amount, price: _price});
                return assetID;
            }

        }
    }

    function BuyDeal(address _assetAddr, uint _buyID) {
        uint profit = msg.value*dao.daoEfficiency()/100;
        dao.daoCredits.emission(daoAddr, profit);
        return true;
    }

    function SellDeal(address _assetAddr, uint sellID) returns(bool result) {
        return true;
    }

}

contract goverment {
    address daoAddr;
    DAO public dao;

}

contract token {
    address public creator;
    string public symbol;
    string public name;
    uint public baseUnit;
    uint totalSupply;
    mapping (address => uint) balanceOf;

    modifier creatorCheck { if (msg.sender == creator) _ }

    /*Initial */
    function token() {
        creator = msg.sender;
    }

    /* Basic functions */
    function setSymbol(string _s) creatorCheck returns(bool result) {
        symbol = _s;
        return true;
    }
    function setName(string _n) creatorCheck returns(bool result) {
        name = _n;
        return true;
    }

    function setBaseUnit(uint _unit) creatorCheck returns(bool result) {
        baseUnit = _unit;
        return true;
    }

    function totalSupply() constant returns (uint256 supply)
    function balanceOf(address _address) constant returns (uint256 balance)
    function transfer(address _to, uint256 _value) returns (bool _success)
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success)
    function approve(address _address) returns (bool success)
    function unapprove(address _address) returns (bool success)
    function isApprovedFor(address _target, address _proxy) constant returns (bool success)
    function approveOnce(address _address, uint256 _maxValue) returns (bool success)
    function isApprovedOnceFor(address _target, address _proxy) returns (uint256 maxValue)

    /* Events */
    event Transfer(address indexed _from, address indexed _to, uint256 _value)
    event AddressApproval(address indexed _address, address indexed _proxy, bool _result)
    event AddressApprovalOnce(address indexed _address, address indexed _proxy, uint256 _value)

    /* Agent function */

    function getBalance() returns(uint _balance) {
        return tokenBalanceOf[msg.sender];
    }

    function sendToken(address receiver, uint amount) returns(bool result) {
        if (tokenBalanceOf[msg.sender] < amount) {return false;}
        tokenBalanceOf[msg.sender] -= amount;
        tokenBalanceOf[receiver] += amount;
        return true;
    }
}

contract DAO {
    address public daoFounder;
    address public daoFounderContr;
    address public daoMarketContr;
    address public daoGovermentContr;
    bool public initialization;
    uint public creditAmount;
    uint public sharesAmount;
    uint public creditTurn;
    uint public numAgents;

    token public daoShares;
    token public daoCredits;

    /* Assets data */
    Asset[] public assetsList;
    mapping (address => uint) public assetDataOf;
    mapping (address => bool) public assetExistOf;
    struct Asset {
        address assetAddr;
    }

    /* Agents data */
    Agent[] public agentsList;
    mapping (address => uint) public agentDataOf;
    mapping (address => bool) public agentActiveOf;
    struct Agent {
        address agentContrAddr;
        uint joinData;
    }

    function DAO(token _shares, token _credits, market _daoMarketContr, goverment _daoGovermentContr) {
        daoFounder = msg.sender;
        daoShares = token(_shares);
        daoCredits = token(_credits);
        daoMarketContr = _daoMarketContr;
        daoGovermentContr = _daoGovermentContr;
    }

    function initializationDaoBalances(uint _founderSharesAmount, uint _founderCreditsAmount) returns (bool result) {
        if(!initialization) {
        daoShares.emission(msg.sender, _founderSharesAmount);
        sharesAmount = _founderSharesAmount;
        daoCredits.emission(msg.sender, _founderCreditsAmount);
        creditAmount = _founderCreditsAmount;
        return true;
        }
    }

    function daoEfficiency() returns (uint daoEfficiency) {
        daoEfficiency = creditTurn*100/creditAmount;
    }

    function daoShareCost() returns (uint shareCost) {
        shareCost = creditTurn/sharesAmount;
    }

    function daoCreditPower() returns (uint creditPower) {
        creditPower = sharesAmount*100/creditTurn;
    }

    function daoShareSale(uint _shareAmount) returns (uint creditReward) {
        if(daoShares.tokenBalanceOf(msg.sender)>=_shareAmount) {
            creditReward = daoShareCost()*_shareAmount;
            daoCredits.emission(msg.sender, creditReward);
            daoShares.burn(msg.sender, _shareAmount);
        }
    }

    function daoShareBuy(uint _creditAmount) returns (uint shares) {
        if(daoCredits.tokenBalanceOf(msg.sender)>=_creditAmount) {
            shares = daoCreditPower()*_creditAmount;
            daoShares.emission(msg.sender, shares);
            daoCredits.burn(msg.sender, _creditAmount);
        }
    }

    function daoSharesEmission(address _agentContrAddr, uint _sharesAmount) {
        daoShares.emission(_agentContrAddr, _sharesAmount);
    }

    function daoCreditEmission(uint _creditsAMount) {
        daoCredits.emission(msg.sender, _creditsAMount);
    }

    function setAgent(address _agentContAddr) returns(uint agentID) {
        if(daoShares.tokenBalanceOf(msg.sender)>0) {
            agentID = agentsList.length++;
            Agent a = agentsList[agentID];
            a.agentContrAddr = _agentContAddr;
            a.joinData = now;
            uint newAgentSharesAmount;
            newAgentSharesAmount = sharesAmount/numAgents;
            daoShares.emission(_agentContAddr, newAgentSharesAmount);
            numAgents = agentID;
            agentDataOf[_agentContAddr] = agentID;
            agentActiveOf[_agentContAddr] = true;
            return agentID;
        }
    }

    function setAssets(address _assetAddr) returns(uint assetID) {
        if (msg.sender == daoMarketContr) {
            assetID = assetsList.length++;
            Asset a = assetsList[assetID];
            a.assetAddr = _assetAddr;
            assetDataOf[_assetAddr] = assetID;
            assetExistOf[_assetAddr] = true;
            return assetID;
        }
    }
}

contract agent {
    address agentAddr;
    address controlAddr;
    address daoAddr;
    DAO public dao;

    /* Agents contract list*/

    AgentContract[] public agentContracts;
    struct AgentContract {
        address agentContractAddr;
        string abi;
    }

    modifier controlCheck { if (msg.sender == controlAddr) _ }

    function agent(address _daoAddr) {
        agentAddr = msg.sender;
        controlAddr = msg.sender;
        daoAddr = _daoAddr;
    }

    function setControlAddr(address _controlAddr) returns(bool result) {
        if(msg.sender == agentAddr) {
            controlAddr = _controlAddr;
        }
    }

    function setNewAgent(address _agentAddr) controlCheck returns(bool result) {
        dao.setAgent(_agentAddr);
        return true;
    }
}

contract market {
    address daoAddr;
    DAO public dao;

    struct Order {
        uint orderID;
        address owner;
        uint amount;
        uint price;
    }

    struct OrderList {
        address assetAddr;
        Order[] orders;
    }

    OrderList[] public sellList;
    Order[] public sellOrders;
    mapping (address => bool) sellExistOf;
    mapping (address => uint) sellDataOf;

    OrderList[] public buyList;
    Order[] public buyOrders;
    mapping (address => bool) buyExistOf;
    mapping (address => uint) buyDataOf;

    function getSellList(address _assetAddr) returns(uint assetID) {
        return 0;
    }

    function getBuyList(address _assetAddr) returns(uint assetID) {
        return 0;
    }

    function addSell(address _assetAddr, uint _amount, uint _price) returns(uint sellID) {
        if (dao.agentActiveOf(msg.sender) && dao.assetExistOf(_assetAddr)) {
            if(sellExistOf[_assetAddr]) {
                uint assetID;
                assetID = sellDataOf[_assetAddr];
                OrderList[] assetOrders = sellList[assetID];
                sellID = sellOrders.sellOrders.length++;
                sellOrders.orders[sellID] = Order({orderID: sellID, owner: msg.sender, amount: _amount, price: _price});
                return assetID;
            }

        }
    }

    function addBuy(address _assetAddr, uint _amount, uint _price) returns(uint buyID) {
        if (dao.agentActiveOf(msg.sender) && dao.assetExistOf(_assetAddr)) {
            if(buyExistOf[_assetAddr]) {
                uint assetID;
                assetID = buyDataOf[_assetAddr];
                OrderList[] buyOrders = buyList[assetID];
                buyID = buyOrders.orders.length++;
                buyOrders.orders[buyID] = Order({orderID: buyID, owner: msg.sender, amount: _amount, price: _price});
                return assetID;
            }

        }
    }

    function BuyDeal(address _assetAddr, uint _buyID) {
        uint profit = msg.value*dao.daoEfficiency()/100;
        dao.daoCredits.emission(daoAddr, profit);
        return true;
    }

    function SellDeal(address _assetAddr, uint sellID) returns(bool result) {
        return true;
    }

}

contract goverment {
    address daoAddr;
    DAO public dao;

}


Make itemStoreRegistry public.

Make itemStoreRegistry public.

pragma solidity ^0.5.2;

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 public 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.2;

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);
    }

}


removes unused dependency (#2603)

removes unused dependency (#2603)

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping (uint256 => address) private _owners;

    // Mapping owner address to token count
    mapping (address => uint256) private _balances;

    // Mapping from token ID to approved address
    mapping (uint256 => address) private _tokenApprovals;

    // Mapping from owner to operator approvals
    mapping (address => mapping (address => bool)) private _operatorApprovals;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor (string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IERC721).interfaceId
            || interfaceId == type(IERC721Metadata).interfaceId
            || super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");
        return owner;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0
            ? string(abi.encodePacked(baseURI, tokenId.toString()))
            : '';
    }

    /**
     * @dev Base URI for computing {tokenURI}. Empty by default, can be overriden
     * in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ERC721.ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        require(operator != _msgSender(), "ERC721: approve to caller");

        _operatorApprovals[_msgSender()][operator] = approved;
        emit ApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(address from, address to, uint256 tokenId) public virtual override {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransfer(from, to, tokenId, _data);
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * `_data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
        _transfer(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return _owners[tokenId] != address(0);
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
        _mint(to, tokenId);
        require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId);

        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(address(0), to, tokenId);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ERC721.ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId);

        // Clear approvals
        _approve(address(0), tokenId);

        _balances[owner] -= 1;
        delete _owners[tokenId];

        emit Transfer(owner, address(0), tokenId);
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(address from, address to, uint256 tokenId) internal virtual {
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
        private returns (bool)
    {
        if (to.isContract()) {
            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
                return retval == IERC721Receiver(to).onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("ERC721: transfer to non ERC721Receiver implementer");
                } else {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, ``from``'s `tokenId` will be burned.
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "./extensions/IERC721Enumerable.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping (uint256 => address) private _owners;

    // Mapping owner address to token count
    mapping (address => uint256) private _balances;

    // Mapping from token ID to approved address
    mapping (uint256 => address) private _tokenApprovals;

    // Mapping from owner to operator approvals
    mapping (address => mapping (address => bool)) private _operatorApprovals;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor (string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IERC721).interfaceId
            || interfaceId == type(IERC721Metadata).interfaceId
            || super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");
        return owner;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0
            ? string(abi.encodePacked(baseURI, tokenId.toString()))
            : '';
    }

    /**
     * @dev Base URI for computing {tokenURI}. Empty by default, can be overriden
     * in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ERC721.ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        require(operator != _msgSender(), "ERC721: approve to caller");

        _operatorApprovals[_msgSender()][operator] = approved;
        emit ApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(address from, address to, uint256 tokenId) public virtual override {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransfer(from, to, tokenId, _data);
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * `_data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
        _transfer(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return _owners[tokenId] != address(0);
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
        _mint(to, tokenId);
        require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId);

        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(address(0), to, tokenId);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ERC721.ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId);

        // Clear approvals
        _approve(address(0), tokenId);

        _balances[owner] -= 1;
        delete _owners[tokenId];

        emit Transfer(owner, address(0), tokenId);
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(address from, address to, uint256 tokenId) internal virtual {
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
        private returns (bool)
    {
        if (to.isContract()) {
            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
                return retval == IERC721Receiver(to).onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("ERC721: transfer to non ERC721Receiver implementer");
                } else {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, ``from``'s `tokenId` will be burned.
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { }
}