Re-arrange parameter / function order.

Re-arrange parameter / function order.

pragma solidity ^0.4.2;

import "abstract_blobstore.sol";
import "blobstore_registry.sol";

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

    byte constant FLAG_UPDATABLE = 0x01;           // True if the blob is updatable. After creation can only be disabled.
    byte constant FLAG_ENFORCE_REVISIONS = 0x02;   // True if the blob is enforcing revisions. After creation can only be enabled.
    byte constant FLAG_RETRACTABLE = 0x04;         // True if the blob can be retracted. After creation can only be disabled.
    byte constant FLAG_TRANSFERABLE = 0x08;        // True if the blob be transfered to another user or disowned. After creation can only be disabled.
    byte constant FLAG_ANONYMOUS = 0x10;           // True if the blob should not have an owner.

    /**
     * @dev Single slot structure of blob info.
     */
    struct BlobInfo {
        byte flags;                 // Packed blob settings.
        uint32 revisionCount;       // Number of revisions including revision 0.
        uint32 blockNumber;         // Block number which contains revision 0.
        address owner;              // Who owns this blob.
    }

    /**
     * @dev Mapping of blobId to blob info.
     */
    mapping (bytes32 => BlobInfo) blobInfo;

    /**
     * @dev Mapping of blobId to mapping of packed slots of eight 32-bit block numbers.
     */
    mapping (bytes32 => mapping (uint => bytes32)) packedBlockNumbers;

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

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

    /**
     * @dev A blob revision has been published.
     * @param blobId Id of the blob.
     * @param revisionId Id of the revision (the highest at time of logging).
     * @param blob Contents of the blob.
     */
    event logBlob(bytes32 indexed blobId, uint indexed revisionId, bytes blob);

    /**
     * @dev A revision has been retracted.
     * @param blobId Id of the blob.
     * @param revisionId Id of the revision.
     */
    event logRetractRevision(bytes32 indexed blobId, uint revisionId);

    /**
     * @dev An entire blob has been retracted. This cannot be undone.
     * @param blobId Id of the blob.
     */
    event logRetract(bytes32 indexed blobId);

    /**
     * @dev A blob has been transfered to a new address.
     * @param blobId Id of the blob.
     * @param recipient The address that now owns the blob.
     */
    event logTransfer(bytes32 indexed blobId, address recipient);

    /**
     * @dev A blob has been disowned. This cannot be undone.
     * @param blobId Id of the blob.
     */
    event logDisown(bytes32 indexed blobId);

    /**
     * @dev A blob has been set as not updatable. This cannot be undone.
     * @param blobId Id of the blob.
     */
    event logSetNotUpdatable(bytes32 indexed blobId);

    /**
     * @dev A blob has been set as enforcing revisions. This cannot be undone.
     * @param blobId Id of the blob.
     */
    event logSetEnforceRevisions(bytes32 indexed blobId);

    /**
     * @dev A blob has been set as not retractable. This cannot be undone.
     * @param blobId Id of the blob.
     */
    event logSetNotRetractable(bytes32 indexed blobId);

    /**
     * @dev A blob has been set as not transferable. This cannot be undone.
     * @param blobId Id of the blob.
     */
    event logSetNotTransferable(bytes32 indexed blobId);

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

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

    /**
     * @dev Throw if the blob is not updatable.
     * @param blobId Id of the blob.
     */
    modifier isUpdatable(bytes32 blobId) {
        if (blobInfo[blobId].flags & FLAG_UPDATABLE == 0) {
            throw;
        }
        _;
    }

    /**
     * @dev Throw if the blob is not enforcing revisions.
     * @param blobId Id of the blob.
     */
    modifier isNotEnforceRevisions(bytes32 blobId) {
        if (blobInfo[blobId].flags & FLAG_ENFORCE_REVISIONS != 0) {
            throw;
        }
        _;
    }

    /**
     * @dev Throw if the blob is not retractable.
     * @param blobId Id of the blob.
     */
    modifier isRetractable(bytes32 blobId) {
        if (blobInfo[blobId].flags & FLAG_RETRACTABLE == 0) {
            throw;
        }
        _;
    }

    /**
     * @dev Throw if the blob is not transferable.
     * @param blobId Id of the blob.
     */
    modifier isTransferable(bytes32 blobId) {
        if (blobInfo[blobId].flags & FLAG_TRANSFERABLE == 0) {
            throw;
        }
        _;
    }

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

    /**
     * @dev Throw if the blob only has one revision.
     * @param blobId Id of the blob.
     */
    modifier hasAdditionalRevisions(bytes32 blobId) {
        if (blobInfo[blobId].revisionCount == 1) {
            throw;
        }
        _;
    }

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

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

    /**
     * @dev Creates a new blob. It is guaranteed that each user will get a different blobId from the same nonce.
     * @param contents Contents of the blob to be stored.
     * @param nonce Any value that the user has not used previously to create a blob.
     * @param flags Packed blob settings.
     * @return blobId Id of the blob.
     */
    function create(bytes contents, bytes32 nonce, byte flags) external returns (bytes32 blobId) {
        // Determine the blobId.
        blobId = contractId | (sha3(msg.sender, nonce) & (2 ** 160 - 1));
        // Make sure this blobId has not been used before.
        if (blobInfo[blobId].blockNumber != 0) {
            throw;
        }
        // Store blob info in state.
        blobInfo[blobId] = BlobInfo({
            flags: flags,
            revisionCount: 1,
            blockNumber: uint32(block.number),
            owner: (flags & FLAG_ANONYMOUS != 0) ? 0 : msg.sender,
        });
        // Store the blob in a log in the current block.
        logBlob(blobId, 0, contents);
    }

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

    /**
     * @dev Create a new blob revision.
     * @param blobId Id of the blob.
     * @param contents Contents of the new revision.
     * @return revisionId The new revisionId.
     */
    function createNewRevision(bytes32 blobId, bytes contents) isOwner(blobId) isUpdatable(blobId) external returns (uint revisionId) {
        // Increment the number of revisions.
        revisionId = blobInfo[blobId].revisionCount++;
        // Store the block number.
        _setPackedBlockNumber(blobId, revisionId - 1);
        // Store the new blob in a log in the current block.
        logBlob(blobId, revisionId, contents);
    }

    /**
     * @dev Update a blob's latest revision.
     * @param blobId Id of the blob.
     * @param contents Contents that should replace the latest revision.
     */
    function updateLatestRevision(bytes32 blobId, bytes contents) isOwner(blobId) isUpdatable(blobId) isNotEnforceRevisions(blobId) external {
        BlobInfo info = blobInfo[blobId];
        uint revisionId = info.revisionCount - 1;
        // Update the block number.
        if (revisionId == 0) {
            info.blockNumber = uint32(block.number);
        }
        else {
            _setPackedBlockNumber(blobId, revisionId - 1);
        }
        // Store the new blob in a log in the current block.
        logBlob(blobId, revisionId, contents);
    }

    /**
     * @dev Retract a blob's latest revision. Revision 0 cannot be retracted.
     * @param blobId Id of the blob.
     */
    function retractLatestRevision(bytes32 blobId) isOwner(blobId) isUpdatable(blobId) isNotEnforceRevisions(blobId) hasAdditionalRevisions(blobId) external {
        uint revisionId = --blobInfo[blobId].revisionCount;
        // Delete the slot if it is no longer required.
        if (revisionId % 8 == 1) {
            delete packedBlockNumbers[blobId][revisionId / 8];
        }
        // Log the retraction.
        logRetractRevision(blobId, revisionId);
    }

    /**
     * @dev Delete all of a blob's packed revision block numbers.
     * @param blobId Id of the blob.
     */
    function _deleteAllPackedRevisionBlockNumbers(bytes32 blobId) internal {
        // Determine how many slots should be deleted.
        // Block number of the first revision is stored in the blob info, so the first slot only needs to be deleted if there are at least 2 revisions.
        uint slotCount = (blobInfo[blobId].revisionCount + 6) / 8;
        // Delete the slots.
        for (uint i = 0; i < slotCount; i++) {
            delete packedBlockNumbers[blobId][i];
        }
    }

    /**
     * @dev Delete all a blob's revisions and replace it with a new blob.
     * @param blobId Id of the blob.
     * @param contents Contents that should be stored.
     */
    function restart(bytes32 blobId, bytes contents) isOwner(blobId) isUpdatable(blobId) isNotEnforceRevisions(blobId) external {
        // Delete the packed revision block numbers.
        _deleteAllPackedRevisionBlockNumbers(blobId);
        // Update the blob state info.
        BlobInfo info = blobInfo[blobId];
        info.revisionCount = 1;
        info.blockNumber = uint32(block.number);
        // Store the blob in a log in the current block.
        logBlob(blobId, 0, contents);
    }

    /**
     * @dev Retract a blob.
     * @param blobId Id of the blob. This blobId can never be used again.
     */
    function retract(bytes32 blobId) isOwner(blobId) isRetractable(blobId) external {
        // Delete the packed revision block numbers.
        _deleteAllPackedRevisionBlockNumbers(blobId);
        // Mark this blob as retracted.
        blobInfo[blobId] = BlobInfo({
            flags: 0,
            revisionCount: 0,
            blockNumber: uint32(-1),
            owner: 0,
        });
        // Log that the blob has been retracted.
        logRetract(blobId);
    }

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

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

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

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

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

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

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

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

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

    /**
     * @dev Check if a blob exists.
     * @param blobId Id of the blob.
     * @return exists True if the blob exists.
     */
    function getExists(bytes32 blobId) constant external returns (bool exists) {
        BlobInfo info = blobInfo[blobId];
        exists = info.blockNumber != 0 && info.blockNumber != uint32(-1);
    }

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

    /**
     * @dev Get the block numbers for all of a blob's revisions.
     * @param blobId Id of the blob.
     * @return blockNumbers Revision block numbers.
     */
    function _getAllRevisionBlockNumbers(bytes32 blobId) internal returns (uint[] blockNumbers) {
        uint revisionCount = blobInfo[blobId].revisionCount;
        blockNumbers = new uint[](revisionCount);
        for (uint revisionId = 0; revisionId < revisionCount; revisionId++) {
            blockNumbers[revisionId] = _getRevisionBlockNumber(blobId, revisionId);
        }
    }

    /**
     * @dev Get info about a blob.
     * @param blobId Id of the blob.
     * @return flags Packed blob settings.
     * @return owner Owner of the blob.
     * @return revisionCount How many revisions the blob has.
     * @return blockNumbers The block numbers of the revisions.
     */
    function getInfo(bytes32 blobId) exists(blobId) constant external returns (byte flags, address owner, uint revisionCount, uint[] blockNumbers) {
        BlobInfo info = blobInfo[blobId];
        flags = info.flags;
        owner = info.owner;
        revisionCount = info.revisionCount;
        blockNumbers = _getAllRevisionBlockNumbers(blobId);
    }

    /**
     * @dev Get all a blob's flags.
     * @param blobId Id of the blob.
     * @return flags Packed blob settings.
     */
    function getFlags(bytes32 blobId) exists(blobId) constant external returns (byte flags) {
        flags = blobInfo[blobId].flags;
    }

    /**
     * @dev Determine if a blob is updatable.
     * @param blobId Id of the blob.
     * @return updatable True if the blob is updatable.
     */
    function getUpdatable(bytes32 blobId) exists(blobId) constant external returns (bool updatable) {
        updatable = blobInfo[blobId].flags & FLAG_UPDATABLE != 0;
    }

    /**
     * @dev Determine if a blob enforces revisions.
     * @param blobId Id of the blob.
     * @return enforceRevisions True if the blob enforces revisions.
     */
    function getEnforceRevisions(bytes32 blobId) exists(blobId) constant external returns (bool enforceRevisions) {
        enforceRevisions = blobInfo[blobId].flags & FLAG_ENFORCE_REVISIONS != 0;
    }

    /**
     * @dev Determine if a blob is retractable.
     * @param blobId Id of the blob.
     * @return retractable True if the blob is blob retractable.
     */
    function getRetractable(bytes32 blobId) exists(blobId) constant external returns (bool retractable) {
        retractable = blobInfo[blobId].flags & FLAG_RETRACTABLE != 0;
    }

    /**
     * @dev Determine if a blob is transferable.
     * @param blobId Id of the blob.
     * @return transferable True if the blob is transferable.
     */
    function getTransferable(bytes32 blobId) exists(blobId) constant external returns (bool transferable) {
        transferable = blobInfo[blobId].flags & FLAG_TRANSFERABLE != 0;
    }

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

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

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

    /**
     * @dev Get the block numbers for all of a blob's revisions.
     * @param blobId Id of the blob.
     * @return blockNumbers Revision block numbers.
     */
    function getAllRevisionBlockNumbers(bytes32 blobId) exists(blobId) constant external returns (uint[] blockNumbers) {
        blockNumbers = _getAllRevisionBlockNumbers(blobId);
    }

}

pragma solidity ^0.4.2;

import "abstract_blobstore.sol";
import "blobstore_registry.sol";

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

    byte constant FLAG_UPDATABLE = 0x01;           // True if the blob is updatable. After creation can only be disabled.
    byte constant FLAG_ENFORCE_REVISIONS = 0x02;   // True if the blob is enforcing revisions. After creation can only be enabled.
    byte constant FLAG_RETRACTABLE = 0x04;         // True if the blob can be retracted. After creation can only be disabled.
    byte constant FLAG_TRANSFERABLE = 0x08;        // True if the blob be transfered to another user or disowned. After creation can only be disabled.
    byte constant FLAG_ANONYMOUS = 0x10;           // True if the blob should not have an owner.

    /**
     * @dev Single slot structure of blob info.
     */
    struct BlobInfo {
        byte flags;                 // Packed boolean settings.
        uint32 revisionCount;       // Number of revisions including revision 0.
        uint32 blockNumber;         // Block number which contains revision 0.
        address owner;              // Who owns this blob.
    }

    /**
     * @dev Mapping of blobId to blob info.
     */
    mapping (bytes32 => BlobInfo) blobInfo;

    /**
     * @dev Mapping of blobId to mapping of packed slots of eight 32-bit block numbers.
     */
    mapping (bytes32 => mapping (uint => bytes32)) packedBlockNumbers;

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

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

    /**
     * @dev A blob revision has been published.
     * @param blobId Id of the blob.
     * @param revisionId Id of the revision (the highest at time of logging).
     * @param blob Contents of the blob.
     */
    event logBlob(bytes32 indexed blobId, uint indexed revisionId, bytes blob);

    /**
     * @dev A revision has been retracted.
     * @param blobId Id of the blob.
     * @param revisionId Id of the revision.
     */
    event logRetractRevision(bytes32 indexed blobId, uint revisionId);

    /**
     * @dev An entire blob has been retracted. This cannot be undone.
     * @param blobId Id of the blob.
     */
    event logRetract(bytes32 indexed blobId);

    /**
     * @dev A blob has been transfered to a new address.
     * @param blobId Id of the blob.
     * @param recipient The address that now owns the blob.
     */
    event logTransfer(bytes32 indexed blobId, address recipient);

    /**
     * @dev A blob has been disowned. This cannot be undone.
     * @param blobId Id of the blob.
     */
    event logDisown(bytes32 indexed blobId);

    /**
     * @dev A blob has been set as not updatable. This cannot be undone.
     * @param blobId Id of the blob.
     */
    event logSetNotUpdatable(bytes32 indexed blobId);

    /**
     * @dev A blob has been set as enforcing revisions. This cannot be undone.
     * @param blobId Id of the blob.
     */
    event logSetEnforceRevisions(bytes32 indexed blobId);

    /**
     * @dev A blob has been set as not retractable. This cannot be undone.
     * @param blobId Id of the blob.
     */
    event logSetNotRetractable(bytes32 indexed blobId);

    /**
     * @dev A blob has been set as not transferable. This cannot be undone.
     * @param blobId Id of the blob.
     */
    event logSetNotTransferable(bytes32 indexed blobId);

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

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

    /**
     * @dev Throw if the blob is not updatable.
     * @param blobId Id of the blob.
     */
    modifier isUpdatable(bytes32 blobId) {
        if (blobInfo[blobId].flags & FLAG_UPDATABLE == 0) {
            throw;
        }
        _;
    }

    /**
     * @dev Throw if the blob is not enforcing revisions.
     * @param blobId Id of the blob.
     */
    modifier isNotEnforceRevisions(bytes32 blobId) {
        if (blobInfo[blobId].flags & FLAG_ENFORCE_REVISIONS != 0) {
            throw;
        }
        _;
    }

    /**
     * @dev Throw if the blob is not retractable.
     * @param blobId Id of the blob.
     */
    modifier isRetractable(bytes32 blobId) {
        if (blobInfo[blobId].flags & FLAG_RETRACTABLE == 0) {
            throw;
        }
        _;
    }

    /**
     * @dev Throw if the blob is not transferable.
     * @param blobId Id of the blob.
     */
    modifier isTransferable(bytes32 blobId) {
        if (blobInfo[blobId].flags & FLAG_TRANSFERABLE == 0) {
            throw;
        }
        _;
    }

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

    /**
     * @dev Throw if the blob only has one revision.
     * @param blobId Id of the blob.
     */
    modifier hasAdditionalRevisions(bytes32 blobId) {
        if (blobInfo[blobId].revisionCount == 1) {
            throw;
        }
        _;
    }

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

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

    /**
     * @dev Creates a new blob. It is guaranteed that each user will get a different blobId from the same nonce.
     * @param contents Contents of the blob to be stored.
     * @param nonce Any value that the user has not used previously to create a blob.
     * @param flags Blob settings.
     * @return blobId Id of the blob.
     */
    function create(bytes contents, bytes32 nonce, byte flags) external returns (bytes32 blobId) {
        // Determine the blobId.
        blobId = contractId | (sha3(msg.sender, nonce) & (2 ** 160 - 1));
        // Make sure this blobId has not been used before.
        if (blobInfo[blobId].blockNumber != 0) {
            throw;
        }
        // Store blob info in state.
        blobInfo[blobId] = BlobInfo({
            flags: flags,
            revisionCount: 1,
            blockNumber: uint32(block.number),
            owner: (flags & FLAG_ANONYMOUS != 0) ? 0 : msg.sender,
        });
        // Store the blob in a log in the current block.
        logBlob(blobId, 0, contents);
    }

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

    /**
     * @dev Create a new blob revision.
     * @param blobId Id of the blob.
     * @param contents Contents of the new revision.
     * @return revisionId The new revisionId.
     */
    function createNewRevision(bytes32 blobId, bytes contents) isOwner(blobId) isUpdatable(blobId) external returns (uint revisionId) {
        // Increment the number of revisions.
        revisionId = blobInfo[blobId].revisionCount++;
        // Store the block number.
        _setPackedBlockNumber(blobId, revisionId - 1);
        // Store the new blob in a log in the current block.
        logBlob(blobId, revisionId, contents);
    }

    /**
     * @dev Update a blob's latest revision.
     * @param blobId Id of the blob.
     * @param contents Contents that should replace the latest revision.
     */
    function updateLatestRevision(bytes32 blobId, bytes contents) isOwner(blobId) isUpdatable(blobId) isNotEnforceRevisions(blobId) external {
        BlobInfo info = blobInfo[blobId];
        uint revisionId = info.revisionCount - 1;
        // Update the block number.
        if (revisionId == 0) {
            info.blockNumber = uint32(block.number);
        }
        else {
            _setPackedBlockNumber(blobId, revisionId - 1);
        }
        // Store the new blob in a log in the current block.
        logBlob(blobId, revisionId, contents);
    }

    /**
     * @dev Retract a blob's latest revision. Revision 0 cannot be retracted.
     * @param blobId Id of the blob.
     */
    function retractLatestRevision(bytes32 blobId) isOwner(blobId) isUpdatable(blobId) isNotEnforceRevisions(blobId) hasAdditionalRevisions(blobId) external {
        uint revisionId = --blobInfo[blobId].revisionCount;
        // Delete the slot if it is no longer required.
        if (revisionId % 8 == 1) {
            delete packedBlockNumbers[blobId][revisionId / 8];
        }
        // Log the retraction.
        logRetractRevision(blobId, revisionId);
    }

    /**
     * @dev Delete all of a blob's packed revision block numbers.
     * @param blobId Id of the blob.
     */
    function _deleteAllPackedRevisionBlockNumbers(bytes32 blobId) internal {
        // Determine how many slots should be deleted.
        // Block number of the first revision is stored in the blob info, so the first slot only needs to be deleted if there are at least 2 revisions.
        uint slotCount = (blobInfo[blobId].revisionCount + 6) / 8;
        // Delete the slots.
        for (uint i = 0; i < slotCount; i++) {
            delete packedBlockNumbers[blobId][i];
        }
    }

    /**
     * @dev Delete all a blob's revisions and replace it with a new blob.
     * @param blobId Id of the blob.
     * @param contents Contents that should be stored.
     */
    function restart(bytes32 blobId, bytes contents) isOwner(blobId) isUpdatable(blobId) isNotEnforceRevisions(blobId) external {
        // Delete the packed revision block numbers.
        _deleteAllPackedRevisionBlockNumbers(blobId);
        // Update the blob state info.
        BlobInfo info = blobInfo[blobId];
        info.revisionCount = 1;
        info.blockNumber = uint32(block.number);
        // Store the blob in a log in the current block.
        logBlob(blobId, 0, contents);
    }

    /**
     * @dev Retract a blob.
     * @param blobId Id of the blob. This blobId can never be used again.
     */
    function retract(bytes32 blobId) isOwner(blobId) isRetractable(blobId) external {
        // Delete the packed revision block numbers.
        _deleteAllPackedRevisionBlockNumbers(blobId);
        // Mark this blob as retracted.
        blobInfo[blobId] = BlobInfo({
            flags: 0,
            revisionCount: 0,
            blockNumber: uint32(-1),
            owner: 0,
        });
        // Log that the blob has been retracted.
        logRetract(blobId);
    }

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

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

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

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

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

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

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

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

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

    /**
     * @dev Check if a blob exists.
     * @param blobId Id of the blob.
     * @return exists True if the blob exists.
     */
    function getExists(bytes32 blobId) constant external returns (bool exists) {
        BlobInfo info = blobInfo[blobId];
        exists = info.blockNumber != 0 && info.blockNumber != uint32(-1);
    }

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

    /**
     * @dev Get the block numbers for all of a blob's revisions.
     * @param blobId Id of the blob.
     * @return blockNumbers Revision block numbers.
     */
    function _getAllRevisionBlockNumbers(bytes32 blobId) internal returns (uint[] blockNumbers) {
        uint revisionCount = blobInfo[blobId].revisionCount;
        blockNumbers = new uint[](revisionCount);
        for (uint revisionId = 0; revisionId < revisionCount; revisionId++) {
            blockNumbers[revisionId] = _getRevisionBlockNumber(blobId, revisionId);
        }
    }

    /**
     * @dev Get info about a blob.
     * @param blobId Id of the blob.
     * @return owner Owner of the blob.
     * @return revisionCount How many revisions the blob has.
     * @return blockNumbers The block numbers of the revisions.
     * @return flags
     */
    function getInfo(bytes32 blobId) exists(blobId) constant external returns (address owner, uint revisionCount, uint[] blockNumbers, byte flags) {
        BlobInfo info = blobInfo[blobId];
        owner = info.owner;
        revisionCount = info.revisionCount;
        blockNumbers = _getAllRevisionBlockNumbers(blobId);
        flags = info.flags;
    }

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

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

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

    /**
     * @dev Get the block numbers for all of a blob's revisions.
     * @param blobId Id of the blob.
     * @return blockNumbers Revision block numbers.
     */
    function getAllRevisionBlockNumbers(bytes32 blobId) exists(blobId) constant external returns (uint[] blockNumbers) {
        blockNumbers = _getAllRevisionBlockNumbers(blobId);
    }

    /**
     * @dev Get all a blob's flags.
     * @param blobId Id of the blob.
     * @return flags The blob's flags.
     */
    function getFlags(bytes32 blobId) exists(blobId) constant external returns (byte flags) {
        flags = blobInfo[blobId].flags;
    }

    /**
     * @dev Determine if a blob is updatable.
     * @param blobId Id of the blob.
     * @return updatable True if the blob is updatable.
     */
    function getUpdatable(bytes32 blobId) exists(blobId) constant external returns (bool updatable) {
        updatable = blobInfo[blobId].flags & FLAG_UPDATABLE != 0;
    }

    /**
     * @dev Determine if a blob enforces revisions.
     * @param blobId Id of the blob.
     * @return enforceRevisions True if the blob enforces revisions.
     */
    function getEnforceRevisions(bytes32 blobId) exists(blobId) constant external returns (bool enforceRevisions) {
        enforceRevisions = blobInfo[blobId].flags & FLAG_ENFORCE_REVISIONS != 0;
    }

    /**
     * @dev Determine if a blob is retractable.
     * @param blobId Id of the blob.
     * @return retractable True if the blob is blob retractable.
     */
    function getRetractable(bytes32 blobId) exists(blobId) constant external returns (bool retractable) {
        retractable = blobInfo[blobId].flags & FLAG_RETRACTABLE != 0;
    }

    /**
     * @dev Determine if a blob is transferable.
     * @param blobId Id of the blob.
     * @return transferable True if the blob is transferable.
     */
    function getTransferable(bytes32 blobId) exists(blobId) constant external returns (bool transferable) {
        transferable = blobInfo[blobId].flags & FLAG_TRANSFERABLE != 0;
    }

}


fixed purchase and added event

fixed purchase and added event

pragma solidity 0.4.11;

import "../ERC20.sol";
import "../ownership/Ownable.sol";
import "../controller/ControllerInterface.sol";
import "../ERC223ReceivingContract.sol";
import "../PullPayInterface.sol";

/**
 * Nutz implements a price floor and a price ceiling on the token being
 * sold. It is based of the zeppelin token contract.
 */
contract Nutz is Ownable, ERC20 {

  event Sell(address indexed seller, uint256 value);

  string public name = "Acebusters Nutz";
  // acebusters units:
  // 10^12 - Nutz   (NTZ)
  // 10^9 - Jonyz
  // 10^6 - Helcz
  // 10^3 - Pascalz
  // 10^0 - Babz
  string public symbol = "NTZ";
  uint256 public decimals = 12;

  // returns balances of active holders
  function balanceOf(address _owner) constant returns (uint) {
    return ControllerInterface(owner).babzBalanceOf(_owner);
  }

  function totalSupply() constant returns (uint256) {
    return ControllerInterface(owner).totalSupply();
  }

  function activeSupply() constant returns (uint256) {
    return ControllerInterface(owner).activeSupply();
  }

  // return remaining allowance
  // if calling return allowed[address(this)][_spender];
  // returns balance of ether parked to be withdrawn
  function allowance(address _owner, address _spender) constant returns (uint256) {
    return ControllerInterface(owner).allowance(_owner, _spender);
  }

  // returns either the salePrice, or if reserve does not suffice
  // for active supply, returns maxFloor
  function floor() constant returns (uint256) {
    return ControllerInterface(owner).floor();
  }

  // returns either the salePrice, or if reserve does not suffice
  // for active supply, returns maxFloor
  function ceiling() constant returns (uint256) {
    return ControllerInterface(owner).ceiling();
  }

  function powerPool() constant returns (uint256) {
    return ControllerInterface(owner).powerPool();
  }

  function _checkDestination(address _from, address _to, uint256 _value, bytes _data) internal {
    // erc223: Retrieve the size of the code on target address, this needs assembly .
    uint256 codeLength;
    assembly {
      codeLength := extcodesize(_to)
    }
    if(codeLength>0) {
      ERC223ReceivingContract untrustedReceiver = ERC223ReceivingContract(_to);
      // untrusted contract call
      untrustedReceiver.tokenFallback(_from, _value, _data);
    }
  }

  // ############################################
  // ########### ADMIN FUNCTIONS ################
  // ############################################

  function powerDown(address powerAddr, address _holder, uint256 _amountBabz) public onlyOwner {
    bytes memory empty;
    _checkDestination(powerAddr, _holder, _amountBabz, empty);
    // NTZ transfered from power pool to user's balance
    Transfer(powerAddr, _holder, _amountBabz);
  }

  function asyncSend(address _pullAddr, address _dest, uint256 _amountWei) public onlyOwner {
    assert(_amountWei <= this.balance);
    PullPayInterface(_pullAddr).asyncSend.value(_amountWei)(_dest);
  }

  // ############################################
  // ########### PUBLIC FUNCTIONS ###############
  // ############################################

  function approve(address _spender, uint256 _amountBabz) public {
    ControllerInterface(owner).approve(msg.sender, _spender, _amountBabz);
    Approval(msg.sender, _spender, _amountBabz);
  }

  function transfer(address _to, uint256 _amountBabz, bytes _data) public returns (bool) {
    ControllerInterface(owner).transfer(msg.sender, _to, _amountBabz, _data);
    Transfer(msg.sender, _to, _amountBabz);
    _checkDestination(msg.sender, _to, _amountBabz, _data);
    return true;
  }

  function transfer(address _to, uint256 _amountBabz) public returns (bool) {
    bytes memory empty;
    return transfer(_to, _amountBabz, empty);
  }

  function transData(address _to, uint256 _amountBabz, bytes _data) public returns (bool) {
    return transfer(_to, _amountBabz, _data);
  }

  function transferFrom(address _from, address _to, uint256 _amountBabz, bytes _data) public returns (bool) {
    ControllerInterface(owner).transferFrom(msg.sender, _from, _to, _amountBabz, _data);
    Transfer(_from, _to, _amountBabz);
    _checkDestination(_from, _to, _amountBabz, _data);
    return true;
  }

  function transferFrom(address _from, address _to, uint256 _amountBabz) public returns (bool) {
    bytes memory empty;
    return transferFrom(_from, _to, _amountBabz, empty);
  }

  function () public payable {
    uint256 price = ControllerInterface(owner).ceiling();
    purchase(price);
    require(msg.value > 0);
  }

  function purchase(uint256 _price) public payable {
    require(msg.value > 0);
    uint256 amountBabz = ControllerInterface(owner).purchase(msg.sender, msg.value, _price);
    Transfer(owner, msg.sender, amountBabz);
    bytes memory empty;
    _checkDestination(address(this), msg.sender, amountBabz, empty);
  }

  function sell(uint256 _price, uint256 _amountBabz) public {
    require(_amountBabz != 0);
    ControllerInterface(owner).sell(msg.sender, _price, _amountBabz);
    Sell(msg.sender, _amountBabz);
  }

  function powerUp(uint256 _amountBabz) public {
    Transfer(msg.sender, owner, _amountBabz);
    ControllerInterface(owner).powerUp(msg.sender, msg.sender, _amountBabz);
  }

}

pragma solidity 0.4.11;

import "../ERC20.sol";
import "../ownership/Ownable.sol";
import "../controller/ControllerInterface.sol";
import "../ERC223ReceivingContract.sol";
import "../PullPayInterface.sol";

/**
 * Nutz implements a price floor and a price ceiling on the token being
 * sold. It is based of the zeppelin token contract.
 */
contract Nutz is Ownable, ERC20 {

  event Sell(address indexed seller, uint256 value);

  string public name = "Acebusters Nutz";
  // acebusters units:
  // 10^12 - Nutz   (NTZ)
  // 10^9 - Jonyz
  // 10^6 - Helcz
  // 10^3 - Pascalz
  // 10^0 - Babz
  string public symbol = "NTZ";
  uint256 public decimals = 12;

  // returns balances of active holders
  function balanceOf(address _owner) constant returns (uint) {
    return ControllerInterface(owner).babzBalanceOf(_owner);
  }

  function totalSupply() constant returns (uint256) {
    return ControllerInterface(owner).totalSupply();
  }

  function activeSupply() constant returns (uint256) {
    return ControllerInterface(owner).activeSupply();
  }

  // return remaining allowance
  // if calling return allowed[address(this)][_spender];
  // returns balance of ether parked to be withdrawn
  function allowance(address _owner, address _spender) constant returns (uint256) {
    return ControllerInterface(owner).allowance(_owner, _spender);
  }

  // returns either the salePrice, or if reserve does not suffice
  // for active supply, returns maxFloor
  function floor() constant returns (uint256) {
    return ControllerInterface(owner).floor();
  }

  // returns either the salePrice, or if reserve does not suffice
  // for active supply, returns maxFloor
  function ceiling() constant returns (uint256) {
    return ControllerInterface(owner).ceiling();
  }

  function powerPool() constant returns (uint256) {
    return ControllerInterface(owner).powerPool();
  }

  function _checkDestination(address _from, address _to, uint256 _value, bytes _data) internal {
    // erc223: Retrieve the size of the code on target address, this needs assembly .
    uint256 codeLength;
    assembly {
      codeLength := extcodesize(_to)
    }
    if(codeLength>0) {
      ERC223ReceivingContract untrustedReceiver = ERC223ReceivingContract(_to);
      // untrusted contract call
      untrustedReceiver.tokenFallback(_from, _value, _data);
    }
  }

  // ############################################
  // ########### ADMIN FUNCTIONS ################
  // ############################################

  function powerDown(address powerAddr, address _holder, uint256 _amountBabz) public onlyOwner {
    bytes memory empty;
    _checkDestination(powerAddr, _holder, _amountBabz, empty);
    // NTZ transfered from power pool to user's balance
    Transfer(powerAddr, _holder, _amountBabz);
  }

  function asyncSend(address _pullAddr, address _dest, uint256 _amountWei) public onlyOwner {
    assert(_amountWei <= this.balance);
    PullPayInterface(_pullAddr).asyncSend.value(_amountWei)(_dest);
  }

  // ############################################
  // ########### PUBLIC FUNCTIONS ###############
  // ############################################

  function approve(address _spender, uint256 _amountBabz) public {
    ControllerInterface(owner).approve(msg.sender, _spender, _amountBabz);
    Approval(msg.sender, _spender, _amountBabz);
  }

  function transfer(address _to, uint256 _amountBabz, bytes _data) public returns (bool) {
    ControllerInterface(owner).transfer(msg.sender, _to, _amountBabz, _data);
    Transfer(msg.sender, _to, _amountBabz);
    _checkDestination(msg.sender, _to, _amountBabz, _data);
    return true;
  }

  function transfer(address _to, uint256 _amountBabz) public returns (bool) {
    bytes memory empty;
    return transfer(_to, _amountBabz, empty);
  }

  function transData(address _to, uint256 _amountBabz, bytes _data) public returns (bool) {
    return transfer(_to, _amountBabz, _data);
  }

  function transferFrom(address _from, address _to, uint256 _amountBabz, bytes _data) public returns (bool) {
    ControllerInterface(owner).transferFrom(msg.sender, _from, _to, _amountBabz, _data);
    Transfer(_from, _to, _amountBabz);
    _checkDestination(_from, _to, _amountBabz, _data);
    return true;
  }

  function transferFrom(address _from, address _to, uint256 _amountBabz) public returns (bool) {
    bytes memory empty;
    return transferFrom(_from, _to, _amountBabz, empty);
  }

  function () public payable {
    require(msg.value > 0);
    uint256 price = ControllerInterface(owner).ceiling();
    uint256 amountBabz = ControllerInterface(owner).purchase(msg.sender, msg.value, price);
    Transfer(owner, msg.sender, amountBabz);
    bytes memory empty;
    _checkDestination(address(this), msg.sender, amountBabz, empty);
  }

  function purchase(uint256 _price) public payable {
    require(msg.value > 0);
    uint256 amountBabz = ControllerInterface(owner).purchase(msg.sender, msg.value, _price);
    Transfer(owner, msg.sender, amountBabz);
    bytes memory empty;
    _checkDestination(address(this), msg.sender, amountBabz, empty);
  }

  function sell(uint256 _price, uint256 _amountBabz) public {
    require(_amountBabz != 0);
    ControllerInterface(owner).sell(msg.sender, _price, _amountBabz);
    Sell(msg.sender, _amountBabz);
  }

  function powerUp(uint256 _amountBabz) public {
    ControllerInterface(owner).powerUp(msg.sender, msg.sender, _amountBabz);
  }

}


Add interval retrieval testing

Add interval retrieval testing

pragma solidity ^0.4.15;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";

import "../contracts/IntervalTree.sol";

contract TestIntervalTree {
  function testIntervals() {
    IntervalTree tree = IntervalTree(DeployedAddresses.IntervalTree());

    tree.addInterval(1, 9, 0xDEADBEEF);
    Assert.equal(tree.numIntervals(), 1, "There should be 1 interval");

    Assert.equal(tree.intervalsAt(5), 1, "Point search should find 1 interval");
    Assert.equal(tree.intervalsAt(0), 0, "Strictly below interval should find 0 intervals");
    Assert.equal(tree.intervalsAt(9), 0, "Upper boundary exact match should find 0 intervals");

    tree.addInterval(3, 4, 0xF00DF00D);
    Assert.equal(tree.numIntervals(), 2, "There should be 2 intervals");

    Assert.equal(tree.intervalsAt(5), 1, "Point search should find 1 interval");
    Assert.equal(tree.intervalsAt(3), 2, "Common point should find 2 intervals");
    Assert.equal(tree.intervalsAt(4), 1, "Upper-bound on only 1 should find 1 match");

    uint begin1;
    uint end1;
    bytes32 data1;

    uint begin2;
    uint end2;
    bytes32 data2;

    (begin1, end1, data1) = tree.intervalAt(3, 0);
    (begin2, end2, data2) = tree.intervalAt(3, 1);

    Assert.equal(
      begin1 == 1 && end1 == 9 && data1 == 0xDEADBEEF ||
      begin2 == 1 && end2 == 9 && data2 == 0xDEADBEEF,
      true,
      "Should find first interval"
    );
    Assert.equal(
      begin1 == 3 && end1 == 4 && data1 == 0xF00DF00D ||
      begin2 == 3 && end2 == 4 && data2 == 0xF00DF00D,
      true,
      "Should find second interval"
    );
  }
}

pragma solidity ^0.4.15;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";

import "../contracts/IntervalTree.sol";

contract TestIntervalTree {
  function testAddInterval() {
    IntervalTree tree = IntervalTree(DeployedAddresses.IntervalTree());

    tree.addInterval(1, 9, 0xDEADBEEF);
    Assert.equal(tree.numIntervals(), 1, "There should be 1 interval");

    Assert.equal(tree.intervalsAt(5), 1, "Point search should find 1 interval");
    Assert.equal(tree.intervalsAt(0), 0, "Strictly below interval should find 0 intervals");
    Assert.equal(tree.intervalsAt(9), 0, "Upper boundary exact match should find 0 intervals");

    tree.addInterval(3, 4, 0xF00DF00D);
    Assert.equal(tree.numIntervals(), 2, "There should be 2 intervals");

    Assert.equal(tree.intervalsAt(5), 1, "Point search should find 1 interval");
    Assert.equal(tree.intervalsAt(3), 2, "Common point should find 2 intervals");
    Assert.equal(tree.intervalsAt(4), 1, "Upper-bound on only 1 should find 1 match");

  }
}


Fix compiler warning

Fix compiler warning

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract ERC165MaliciousData {
    function supportsInterface(bytes4) public pure returns (bool) {
        assembly {
            mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
            return(0, 32)
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract ERC165MaliciousData {
    function supportsInterface(bytes4) public view returns (bool) {
        assembly {
            mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
            return(0, 32)
        }
    }
}


Change bug logic to success only if there are less actual balance

import './Conference.sol';
import './zeppelin/PullPaymentCapable.sol';

/*
 * Bounty
 * This bounty will pay out if you can cause a Conference's balance
 * to be different from its totalBalance, which would mean that it doesn't
 * have sufficient ether for everyone to withdraw.
 */
contract Bounty is PullPaymentCapable {
  uint public totalBounty;
  bool public claimed;
  mapping(address => address) public researchers;
  event TargetCreation(address createdAddress);
  event Error(string message);

  function contribute() {
    totalBounty = msg.value;
    if (claimed) throw;
  }

  function createTarget() returns(Conference) {
    Conference target = new Conference();
    researchers[target] = msg.sender;
    TargetCreation(target);
    return target;
  }

  modifier hasResearcher(Conference target) {
    address researcher = researchers[target];
    if (researcher != 0){
      _
    }else{
      Error('there are no researcher');
    }
  }

  modifier hasBug(Conference target) {
    if (target.totalBalance() > target.balance){
      _
    }else{
      Error('No security breach');
    }
  }

  function claim(Conference target) hasResearcher(target) hasBug(target){
    address researcher = researchers[target];
    asyncSend(researcher, this.balance);
    totalBounty = 0;
    claimed = true;
  }
}

import './Conference.sol';
import './zeppelin/PullPaymentCapable.sol';

/*
 * Bounty
 * This bounty will pay out if you can cause a Conference's balance
 * to be different from its totalBalance, which would mean that it doesn't
 * have sufficient ether for everyone to withdraw.
 */
contract Bounty is PullPaymentCapable {
  uint public totalBounty;
  bool public claimed;
  mapping(address => address) public researchers;
  event TargetCreation(address createdAddress);
  event Error(string message);
  function contribute() {
    totalBounty = msg.value;
    if (claimed) throw;
  }

  function createTarget() returns(Conference) {
    Conference target = new Conference();
    researchers[target] = msg.sender;
    TargetCreation(target);
    return target;
  }

  modifier hasResearcher(Conference target) {
    address researcher = researchers[target];
    if (researcher != 0){
      _
    }else{
      Error('there are no researcher');
    }
  }

  modifier hasBug(Conference target) {
    if (target.totalBalance() != target.balance){
      _
    }else{
      Error('No security breach');
    }
  }

  function claim(Conference target) hasResearcher(target) hasBug(target){
    address researcher = researchers[target];
    asyncSend(researcher, this.balance);
    totalBounty = 0;
    claimed = true;
  }
}


update function order

update function order

/*
    Copyright 2017-2018 Phillip A. Elsasser

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

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

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

pragma solidity ^0.4.24;

import "./libraries/MathLib.sol";
import "./MarketContract.sol";
import "./tokens/PositionToken.sol";

import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";

/// @title MarketCollateralPool
/// @notice This collateral pool houses all of the collateral for all market contracts currently in circulation.
/// This pool facilitates locking of collateral and minting / redemption of position tokens for that collateral.
/// @author Phil Elsasser <phil@marketprotocol.io>
contract MarketCollateralPool is Ownable {
    using MathLib for uint;
    using MathLib for int;
    using SafeERC20 for ERC20;

    mapping(address => uint) public contractAddressToCollateralPoolBalance;                 // current balance of all collateral committed
    enum MarketSide { Long, Short, Both}

    event TokensMinted(address indexed marketContract, uint qtyMinted, uint collateralLocked);
    event TokensRedeemed(address indexed marketContract, uint qtyRedeemed, uint collateralUnlocked, uint8 marketSide);
    event FactoryAddressRemoved(address indexed factoryAddress);

    constructor() public { }

    /*
    // EXTERNAL METHODS
    */

    /// @notice Called by a user that would like to mint a new set of long and short token for a specified
    /// market contract.  This will transfer and lock the correct amount of collateral into the pool
    /// and issue them the requested qty of long and short tokens
    /// @param marketContractAddress            address of the market contract to redeem tokens for
    /// @param qtyToMint                      quantity of long / short tokens to mint.
    function mintPositionTokens(address marketContractAddress, uint qtyToMint) external {
        MarketContract marketContract = MarketContract(marketContractAddress);
        require(!marketContract.isSettled(), "Contract is already settled");

        uint neededCollateral = MathLib.multiply(qtyToMint, marketContract.COLLATERAL_PER_UNIT());

        // EXTERNAL CALL - transferring ERC20 tokens from sender to this contract.  User must have called
        // ERC20.approve in order for this call to succeed.
        ERC20(marketContract.COLLATERAL_TOKEN_ADDRESS()).safeTransferFrom(msg.sender, this, neededCollateral);

        // Update the collateral pool locked balance.
        contractAddressToCollateralPoolBalance[marketContractAddress] = contractAddressToCollateralPoolBalance[
            marketContractAddress
        ].add(neededCollateral);

        // mint and distribute short and long position tokens to our caller
        PositionToken(marketContract.LONG_POSITION_TOKEN()).mintAndSendToken(qtyToMint, msg.sender);
        PositionToken(marketContract.SHORT_POSITION_TOKEN()).mintAndSendToken(qtyToMint, msg.sender);

        emit TokensMinted(marketContractAddress, qtyToMint, neededCollateral);
    }

    /// @notice Called by a user that currently holds both short and long position tokens and would like to redeem them
    /// for their collateral.
    /// @param marketContractAddress            address of the market contract to redeem tokens for
    /// @param qtyToRedeem                      quantity of long / short tokens to redeem.
    function redeemPositionTokens(address marketContractAddress, uint qtyToRedeem) external {
        MarketContract marketContract = MarketContract(marketContractAddress);

        // Redeem positions tokens by burning them.
        PositionToken(marketContract.LONG_POSITION_TOKEN()).redeemToken(qtyToRedeem, msg.sender);
        PositionToken(marketContract.SHORT_POSITION_TOKEN()).redeemToken(qtyToRedeem, msg.sender);

        // calculate collateral to return and update pool balance
        uint collateralToReturn = MathLib.multiply(qtyToRedeem, marketContract.COLLATERAL_PER_UNIT());
        contractAddressToCollateralPoolBalance[marketContractAddress] = contractAddressToCollateralPoolBalance[
            marketContractAddress
        ].subtract(collateralToReturn);

        // transfer collateral back to user
        ERC20(marketContract.COLLATERAL_TOKEN_ADDRESS()).safeTransfer(msg.sender, collateralToReturn);

        emit TokensRedeemed(
            marketContractAddress,
            qtyToRedeem,
            collateralToReturn,
            uint8(MarketSide.Both)
        );
    }

    // @notice called by a user after settlement has occurred.  This function will finalize all accounting around any
    // outstanding positions and return all remaining collateral to the caller. This should only be called after
    // settlement has occurred.
    /// @param marketContractAddress address of the MARKET Contract being traded.
    /// @param qtyToRedeem signed qtyToRedeem, positive (+) for long tokens, negative(-) for short tokens
    function settleAndClose(address marketContractAddress, int qtyToRedeem) external {
        MarketContract marketContract = MarketContract(marketContractAddress);
        require(marketContract.isSettled(), "Contract is not settled");

        // burn tokens being redeemed.
        MarketSide marketSide;
        uint absQtyToRedeem = qtyToRedeem.abs(); // convert to a uint for non signed functions
        if (qtyToRedeem > 0) {
            PositionToken(marketContract.LONG_POSITION_TOKEN()).redeemToken(absQtyToRedeem, msg.sender);
            marketSide = MarketSide.Long;
        } else {
            PositionToken(marketContract.SHORT_POSITION_TOKEN()).redeemToken(absQtyToRedeem, msg.sender);
            marketSide = MarketSide.Short;
        }

        // calculate amount of collateral to return and update pool balances
        uint collateralToReturn = MathLib.calculateNeededCollateral(
            marketContract.PRICE_FLOOR(),
            marketContract.PRICE_CAP(),
            marketContract.QTY_MULTIPLIER(),
            qtyToRedeem,
            marketContract.settlementPrice()
        );
        contractAddressToCollateralPoolBalance[marketContract] = contractAddressToCollateralPoolBalance[
        marketContract
        ].subtract(collateralToReturn);

        // return collateral tokens
        ERC20(marketContract.COLLATERAL_TOKEN_ADDRESS()).safeTransfer(msg.sender, collateralToReturn);

        emit TokensRedeemed(
            marketContractAddress,
            absQtyToRedeem,
            collateralToReturn,
            uint8(marketSide)
        );
    }

}

/*
    Copyright 2017-2018 Phillip A. Elsasser

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

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

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

pragma solidity ^0.4.24;

import "./libraries/MathLib.sol";
import "./MarketContract.sol";
import "./tokens/PositionToken.sol";

import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";

/// @title MarketCollateralPool
/// @notice This collateral pool houses all of the collateral for all market contracts currently in circulation.
/// This pool facilitates locking of collateral and minting / redemption of position tokens for that collateral.
/// @author Phil Elsasser <phil@marketprotocol.io>
contract MarketCollateralPool is Ownable {
    using MathLib for uint;
    using MathLib for int;
    using SafeERC20 for ERC20;

    mapping(address => uint) public contractAddressToCollateralPoolBalance;                 // current balance of all collateral committed
    enum MarketSide { Long, Short, Both}

    event TokensMinted(address indexed marketContract, uint qtyMinted, uint collateralLocked);
    event TokensRedeemed(address indexed marketContract, uint qtyRedeemed, uint collateralUnlocked, uint8 marketSide);
    event FactoryAddressRemoved(address indexed factoryAddress);

    constructor() public { }

    /*
    // EXTERNAL METHODS
    */

    // @notice called by a user after settlement has occurred.  This function will finalize all accounting around any
    // outstanding positions and return all remaining collateral to the caller. This should only be called after
    // settlement has occurred.
    /// @param marketContractAddress address of the MARKET Contract being traded.
    /// @param qtyToRedeem signed qtyToRedeem, positive (+) for long tokens, negative(-) for short tokens
    function settleAndClose(address marketContractAddress, int qtyToRedeem) external {
        MarketContract marketContract = MarketContract(marketContractAddress);
        require(marketContract.isSettled(), "Contract is not settled");

        // burn tokens being redeemed.
        MarketSide marketSide;
        uint absQtyToRedeem = qtyToRedeem.abs(); // convert to a uint for non signed functions
        if (qtyToRedeem > 0) {
            PositionToken(marketContract.LONG_POSITION_TOKEN()).redeemToken(absQtyToRedeem, msg.sender);
            marketSide = MarketSide.Long;
        } else {
            PositionToken(marketContract.SHORT_POSITION_TOKEN()).redeemToken(absQtyToRedeem, msg.sender);
            marketSide = MarketSide.Short;
        }

        // calculate amount of collateral to return and update pool balances
        uint collateralToReturn = MathLib.calculateNeededCollateral(
            marketContract.PRICE_FLOOR(),
            marketContract.PRICE_CAP(),
            marketContract.QTY_MULTIPLIER(),
            qtyToRedeem,
            marketContract.settlementPrice()
        );
        contractAddressToCollateralPoolBalance[marketContract] = contractAddressToCollateralPoolBalance[
            marketContract
        ].subtract(collateralToReturn);

        // return collateral tokens
        ERC20(marketContract.COLLATERAL_TOKEN_ADDRESS()).safeTransfer(msg.sender, collateralToReturn);

        emit TokensRedeemed(
            marketContractAddress,
            absQtyToRedeem,
            collateralToReturn,
            uint8(marketSide)
        );
    }

    /// @notice Called by a user that would like to mint a new set of long and short token for a specified
    /// market contract.  This will transfer and lock the correct amount of collateral into the pool
    /// and issue them the requested qty of long and short tokens
    /// @param marketContractAddress            address of the market contract to redeem tokens for
    /// @param qtyToMint                      quantity of long / short tokens to mint.
    function mintPositionTokens(address marketContractAddress, uint qtyToMint) external {
        MarketContract marketContract = MarketContract(marketContractAddress);
        require(!marketContract.isSettled(), "Contract is already settled");

        uint neededCollateral = MathLib.multiply(qtyToMint, marketContract.COLLATERAL_PER_UNIT());

        // EXTERNAL CALL - transferring ERC20 tokens from sender to this contract.  User must have called
        // ERC20.approve in order for this call to succeed.
        ERC20(marketContract.COLLATERAL_TOKEN_ADDRESS()).safeTransferFrom(msg.sender, this, neededCollateral);

        // Update the collateral pool locked balance.
        contractAddressToCollateralPoolBalance[marketContractAddress] = contractAddressToCollateralPoolBalance[
            marketContractAddress
        ].add(neededCollateral);

        // mint and distribute short and long position tokens to our caller
        PositionToken(marketContract.LONG_POSITION_TOKEN()).mintAndSendToken(qtyToMint, msg.sender);
        PositionToken(marketContract.SHORT_POSITION_TOKEN()).mintAndSendToken(qtyToMint, msg.sender);

        emit TokensMinted(marketContractAddress, qtyToMint, neededCollateral);
    }

    /// @notice Called by a user that currently holds both short and long position tokens and would like to redeem them
    /// for their collateral.
    /// @param marketContractAddress            address of the market contract to redeem tokens for
    /// @param qtyToRedeem                      quantity of long / short tokens to redeem.
    function redeemPositionTokens(address marketContractAddress, uint qtyToRedeem) external {
        MarketContract marketContract = MarketContract(marketContractAddress);

        // Redeem positions tokens by burning them.
        PositionToken(marketContract.LONG_POSITION_TOKEN()).redeemToken(qtyToRedeem, msg.sender);
        PositionToken(marketContract.SHORT_POSITION_TOKEN()).redeemToken(qtyToRedeem, msg.sender);

        // calculate collateral to return and update pool balance
        uint collateralToReturn = MathLib.multiply(qtyToRedeem, marketContract.COLLATERAL_PER_UNIT());
        contractAddressToCollateralPoolBalance[marketContractAddress] = contractAddressToCollateralPoolBalance[
            marketContractAddress
        ].subtract(collateralToReturn);

        // transfer collateral back to user
        ERC20(marketContract.COLLATERAL_TOKEN_ADDRESS()).safeTransfer(msg.sender, collateralToReturn);

        emit TokensRedeemed(
            marketContractAddress,
            qtyToRedeem,
            collateralToReturn,
            uint8(MarketSide.Both)
        );
    }
}


Commented TicTacToeRules.sol

Commented TicTacToeRules.sol

import "Rules.sol";
import "TicTacToeAdjudicator.sol";

/* Board state values are as follows:
 *  0 | 1 | 2
 *  ---------
 *  3 | 4 | 5
 *  ---------
 *  6 | 7 | 8
 *
 * 9: 4 if last player was O, 1 if the last player was X
 */
contract TicTacToeRules is Rules {

    uint constant BLANK = 0;
    uint constant X = 1;
    uint constant O = 4;

    address addressX;
    address addressO;
    uint timeout;

    /**
     * Creates a new TicTacToeRules
     * _addressX: the address of X
     * _addressO: the address of O
     * _timeout: the timeout before state can be closed
     */
    function TicTacToeRules(address _addressX, address _addressO, uint _timeout) {
        addressX = _addressX;
        addressO = _addressO;
        timeout = _timeout;
    }

    function createAdjudicator() internal returns (Adjudicator newAdjudicator) {
        newAdjudicator = new TicTacToeAdjudicator(addressX, addressO, timeout);
        delete timeout;
    }

    // Converts a grid coordinate to an index value
    function gridToIndex(uint x, uint y) constant internal returns (uint) {
        return x + 3*y;
    }

    /**
     * Send a state directly to the underlying state channel.
     * Allows for transactions to be closed without any adjudication fees.
     *
     * state: the state that will be sent
     * nonce: the nonce that will be sent
     * the rest are signature values for X and O, respectively
     * returns: true if state sent sucessfully, otherwise false
     */
    function sendState(
        bytes state,
        uint nonce,
        uint8 vX,
        bytes32 rX,
        bytes32 sX,
        uint8 vO,
        bytes32 rO,
        bytes32 sO
    ) external returns (bool) {
        uint8[] memory v = new uint8[](2);
        bytes32[] memory r = new bytes32[](2);
        bytes32[] memory s = new bytes32[](2);

        v[0] = vX;
        v[1] = vO;
        r[0] = rX;
        r[1] = rO;
        s[0] = sX;
        s[1] = sO;

        return adjudicator.close(2, state, nonce, v, r, s);
    }

    /**
     * Sends a unilateral ruling (0 signatures required) to underlying adjudicator.
     *
     * uintState: the state which will be sent
     * nonce: the nonce which will be sent
     * returns: true if the state was sent successfully, otherwise false
     */
    function unilateralRuling(uint8 uintState, uint nonce) internal returns (bool) {
        bytes memory state = new bytes(1);
        state[0] = byte(uintState);
        adjudicator.close(0, state, nonce, new uint8[](1), new bytes32[](1), new bytes32[](1));
    }

    /**
     * Sends a board to be adjudicated upon.
     *
     * board: the board to be adjudicated upon
     * nonce: the nonce that will be used
     * v, r, s: X's signature if last player was X, O's signature if last player was O
     * returns: true if adjudication was sucessful, otherwise false
     */
    function sendBoard(
        bytes10 board,
        uint nonce,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (bool) {
        uint x;
        uint y;
        uint i;
        uint8 uintState = uint(board[9]) == X ? 0x28 : 0x14;// by default, the person who didn't play will lose all deposits

        if (
            !((uint(board[9]) == X && addressX == ecrecover(sha3(board, nonce), v, r, s))
            || (uint(board[9]) == O && addressO == ecrecover(sha3(board, nonce), v, r, s)))
        ) {
            return false;
        }

        // do something about what happens if you send old boards???

        // checking wins
        // checking |
        for (x = 0; x < 3; x++) {
            i = 0;
            for (y = 0; y < 3; y++) {
                i += uint(board[gridToIndex(x, y)]);
            }
            if (i == X * 3) {
                return unilateralRuling(uintState | 0x01 , nonce);// give X the bet winnings
            } else if (i == O * 3) {
                return unilateralRuling(uintState | 0x02, nonce);// give O the bet winnings
            }
        }

        // checking -
        for (y = 0; y < 3; y++) {
            i = 0;
            for (x = 0; x < 3; x++) {
                i += uint(board[gridToIndex(x, y)]);
            }
            if (i == X * 3) {
                return unilateralRuling(uintState | 0x01, nonce);
            } else if (i == O * 3) {
                return unilateralRuling(uintState | 0x02, nonce);
            }
        }

        // checking \
        i = 0;
        for (x = 0; x < 3; x++) {
            i += uint(board[gridToIndex(x, x)]);
        }
        if (i == X * 3) {
            return unilateralRuling(uintState | 0x01, nonce);
        } else if (i == O * 3) {
            return unilateralRuling(uintState | 0x02, nonce);
        }

        // checking /
        i = 0;
        for (x = 0; x < 3; x++) {
            i += uint(board[gridToIndex(x, 2 - x)]);
        }
        if (i == X * 3) {
            return unilateralRuling(uintState | 0x01, nonce);
        } else if (i == O * 3) {
            return unilateralRuling(uintState | 0x02, nonce);
        }

        // check if tie
        for (i = 0; i < 9; i++) {
            if (uint(board[i]) == BLANK) {
                // last player wins
                return unilateralRuling(uintState | uint(board[9]) == X ? 0x01 : 0x02, nonce);// bets sent to last player
            }
        }
        // it is a tie
        return unilateralRuling(uintState, nonce);// if tie, bets returned
    }

    /**
     * Punishes a sender for sending an errornous board.
     *
     * oldBoard: the old board to be compared against
     * oldNonce: the old nonce to verify the old board
     * oldV, oldR, oldS: the signature for oldBoard, from the last player
     * newBoard: the new board which has an error
     * newNonce: the new nonce of newBoard
     * newV, newR, newS: the signatures for newBoard, from the last player
     */
    function badBoardSent(
        bytes10 oldBoard,
        uint oldNonce,
        uint8 oldV,
        bytes32 oldR,
        bytes32 oldS,
        bytes10 newBoard,
        uint newNonce,
        uint8 newV,
        bytes32 newR,
        bytes32 newS
    ) external returns (bool) {
        // verify the integrity of oldBoard
        if (
            !((uint(oldBoard[9]) == X && addressX == ecrecover(sha3(oldBoard, oldNonce), oldV, oldR, oldS))
            || (uint(oldBoard[9]) == O && addressO == ecrecover(sha3(oldBoard, oldNonce), oldV, oldR, oldS)))
        ) {
            return false;
        }

        // verify the integrity of newBoard
        if (
            !((uint(newBoard[9]) == X && addressX == ecrecover(sha3(newBoard, newNonce), newV, newR, newS))
            || (uint(newBoard[9]) == O && addressO == ecrecover(sha3(newBoard, newNonce), newV, newR, newS)))
        ) {
            return false;
        }

        bool notChanged = true;
        for (uint i = 0; i < 9; i++) {
            if (oldBoard[i] == newBoard[i]) {
                break;
            }
            if ((uint(newBoard[i]) == X || uint(newBoard[i]) == O) && (uint(oldBoard[i]) == BLANK) && notChanged && (newBoard[i] == newBoard[9])) {
                notChanged = false;
                break;
            }
            // shenanigans
            return unilateralRuling(uint(newBoard[9]) == X ? 0x56 : 0x69, newNonce);
        }
        if (notChanged) {
            // shenanigans
            return unilateralRuling(uint(newBoard[9]) == X ? 0x56 : 0x69, newNonce);
        } else {
            // nothing fishy
            return false;
        }
    }

    /**
     * Lets the contract know that you have not disconnected.
     * Will modify the state such that the disconnect deposits will be
     * refunded and both party's adjudication deposits will be lost.
     *
     * returns: true if sucessful, otherwise false
     */
    function checkIn() external returns (bool) {
        uint8 uintState = uint8(adjudicator.getStateAt(0));
        if (uintState & 0x40 != 0x00 || uintState & 0x0C != 0x00) {
            return false;
        }
        return unilateralRuling(uintState & 0xCF | 0x0C, adjudicator.getNonce());
    }
}

import "Rules.sol";
import "TicTacToeAdjudicator.sol";

/* Grid is as follows:
 *  0 | 1 | 2
 *  ---------
 *  3 | 4 | 5
 *  ---------
 *  6 | 7 | 8
 *
 * 9: 4 if last player was O, 1 if the last player was X
 */
contract TicTacToeRules is Rules {

    uint constant BLANK = 0;
    uint constant X = 1;
    uint constant O = 4;

    address addressX;
    address addressO;
    uint timeout;

    function TicTacToeRules(address _addressX, address _addressO, uint _timeout) {
        addressX = _addressX;
        addressO = _addressO;
        timeout = _timeout;
    }

    function createAdjudicator() internal returns (Adjudicator newAdjudicator) {
        newAdjudicator = new TicTacToeAdjudicator(addressX, addressO, timeout);
        delete timeout;
    }

    function gridToIndex(uint x, uint y) constant internal returns (uint) {
        return x + 3*y;
    }

    function sendState(
        bytes state,
        uint nonce,
        uint8 vX,
        bytes32 rX,
        bytes32 sX,
        uint8 vO,
        bytes32 rO,
        bytes32 sO
    ) external returns (bool) {
        uint8[] memory v = new uint8[](2);
        bytes32[] memory r = new bytes32[](2);
        bytes32[] memory s = new bytes32[](2);

        v[0] = vX;
        v[1] = vO;
        r[0] = rX;
        r[1] = rO;
        s[0] = sX;
        s[1] = sO;

        return adjudicator.close(2, state, nonce, v, r, s);
    }

    function unilateralRuling(uint8 uintState, uint nonce) internal returns (bool) {
        bytes memory state = new bytes(1);
        state[0] = byte(uintState);
        adjudicator.close(0, state, nonce, new uint8[](1), new bytes32[](1), new bytes32[](1));
    }

    function sendBoard(
        bytes10 board,
        uint nonce,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (bool) {
        uint x;
        uint y;
        uint i;
        uint8 uintState = uint(board[9]) == X ? 0x28 : 0x14;

        if (
            !((uint(board[9]) == X && addressX == ecrecover(sha3(board, nonce), v, r, s))
            || (uint(board[9]) == O && addressO == ecrecover(sha3(board, nonce), v, r, s)))
        ) {
            return false;
        }

        // do something about what happens if you send old boards???

        // checking wins
        // checking |
        for (x = 0; x < 3; x++) {
            i = 0;
            for (y = 0; y < 3; y++) {
                i += uint(board[gridToIndex(x, y)]);
            }
            if (i == X * 3) {
                return unilateralRuling(uintState | 0x01 , nonce);
            } else if (i == O * 3) {
                return unilateralRuling(uintState | 0x02, nonce);
            }
        }

        // checking -
        for (y = 0; y < 3; y++) {
            i = 0;
            for (x = 0; x < 3; x++) {
                i += uint(board[gridToIndex(x, y)]);
            }
            if (i == X * 3) {
                return unilateralRuling(uintState | 0x01, nonce);
            } else if (i == O * 3) {
                return unilateralRuling(uintState | 0x02, nonce);
            }
        }

        // checking \
        i = 0;
        for (x = 0; x < 3; x++) {
            i += uint(board[gridToIndex(x, x)]);
        }
        if (i == X * 3) {
            return unilateralRuling(uintState | 0x01, nonce);
        } else if (i == O * 3) {
            return unilateralRuling(uintState | 0x02, nonce);
        }

        // checking /
        i = 0;
        for (x = 0; x < 3; x++) {
            i += uint(board[gridToIndex(x, 2 - x)]);
        }
        if (i == X * 3) {
            return unilateralRuling(uintState | 0x01, nonce);
        } else if (i == O * 3) {
            return unilateralRuling(uintState | 0x02, nonce);
        }

        // check if tie
        for (i = 0; i < 9; i++) {
            if (uint(board[i]) == BLANK) {
                // last player wins
                return unilateralRuling(uintState | uint(board[9]) == X ? 0x01 : 0x02, nonce);
            }
        }
        // it is a tie
        return unilateralRuling(uintState, nonce);
    }

    function badBoardSent(
        bytes10 oldBoard,
        uint oldNonce,
        uint8 oldV,
        bytes32 oldR,
        bytes32 oldS,
        bytes10 newBoard,
        uint newNonce,
        uint8 newV,
        bytes32 newR,
        bytes32 newS
    ) external returns (bool) {
        if (
            !((uint(oldBoard[9]) == X && addressX == ecrecover(sha3(oldBoard, oldNonce), oldV, oldR, oldS))
            || (uint(oldBoard[9]) == O && addressO == ecrecover(sha3(oldBoard, oldNonce), oldV, oldR, oldS)))
        ) {
            return false;
        }

        if (
            !((uint(newBoard[9]) == X && addressX == ecrecover(sha3(newBoard, newNonce), newV, newR, newS))
            || (uint(newBoard[9]) == O && addressO == ecrecover(sha3(newBoard, newNonce), newV, newR, newS)))
        ) {
            return false;
        }

        bool notChanged = true;
        for (uint i = 0; i < 9; i++) {
            if (oldBoard[i] == newBoard[i]) {
                break;
            }
            if ((uint(newBoard[i]) == X || uint(newBoard[i]) == O) && (oldBoard[i] != newBoard[i]) && (uint(oldBoard[i]) == BLANK) && (notChanged && newBoard[i] == newBoard[9])) {
                notChanged = false;
                break;
            }
            // shenanigans
            return unilateralRuling(uint(newBoard[9]) == X ? 0x56 : 0x69, newNonce);
        }
        if (notChanged) {
            // shenanigans
            return unilateralRuling(uint(newBoard[9]) == X ? 0x56 : 0x69, newNonce);
        } else {
            // nothing fishy
            return false;
        }
    }

    function checkIn() external returns (bool) {
        uint8 uintState = uint8(adjudicator.getStateAt(0));
        if (uintState & 0x40 != 0x00 || uintState & 0x0C != 0x00) {
            return false;
        }
        return unilateralRuling(uintState & 0xCF | 0x0C, adjudicator.getNonce());
    }
}