Update link to Consensys best practices (#3597)

Co-authored-by: Francisco <4223852eec80914c4c190cdc031e06592b151a67@gmail.com>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/PullPayment.sol)

pragma solidity ^0.8.0;

import "../utils/escrow/Escrow.sol";

/**
 * @dev Simple implementation of a
 * https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/external-calls/#favor-pull-over-push-for-external-calls[pull-payment]
 * strategy, where the paying contract doesn't interact directly with the
 * receiver account, which must withdraw its payments itself.
 *
 * Pull-payments are often considered the best practice when it comes to sending
 * Ether, security-wise. It prevents recipients from blocking execution, and
 * eliminates reentrancy concerns.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 *
 * To use, derive from the `PullPayment` contract, and use {_asyncTransfer}
 * instead of Solidity's `transfer` function. Payees can query their due
 * payments with {payments}, and retrieve them with {withdrawPayments}.
 */
abstract contract PullPayment {
    Escrow private immutable _escrow;

    constructor() {
        _escrow = new Escrow();
    }

    /**
     * @dev Withdraw accumulated payments, forwarding all gas to the recipient.
     *
     * Note that _any_ account can call this function, not just the `payee`.
     * This means that contracts unaware of the `PullPayment` protocol can still
     * receive funds this way, by having a separate account call
     * {withdrawPayments}.
     *
     * WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities.
     * Make sure you trust the recipient, or are either following the
     * checks-effects-interactions pattern or using {ReentrancyGuard}.
     *
     * @param payee Whose payments will be withdrawn.
     *
     * Causes the `escrow` to emit a {Withdrawn} event.
     */
    function withdrawPayments(address payable payee) public virtual {
        _escrow.withdraw(payee);
    }

    /**
     * @dev Returns the payments owed to an address.
     * @param dest The creditor's address.
     */
    function payments(address dest) public view returns (uint256) {
        return _escrow.depositsOf(dest);
    }

    /**
     * @dev Called by the payer to store the sent amount as credit to be pulled.
     * Funds sent in this way are stored in an intermediate {Escrow} contract, so
     * there is no danger of them being spent before withdrawal.
     *
     * @param dest The destination address of the funds.
     * @param amount The amount to transfer.
     *
     * Causes the `escrow` to emit a {Deposited} event.
     */
    function _asyncTransfer(address dest, uint256 amount) internal virtual {
        _escrow.deposit{value: amount}(dest);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/PullPayment.sol)

pragma solidity ^0.8.0;

import "../utils/escrow/Escrow.sol";

/**
 * @dev Simple implementation of a
 * https://consensys.github.io/smart-contract-best-practices/recommendations/#favor-pull-over-push-for-external-calls[pull-payment]
 * strategy, where the paying contract doesn't interact directly with the
 * receiver account, which must withdraw its payments itself.
 *
 * Pull-payments are often considered the best practice when it comes to sending
 * Ether, security-wise. It prevents recipients from blocking execution, and
 * eliminates reentrancy concerns.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 *
 * To use, derive from the `PullPayment` contract, and use {_asyncTransfer}
 * instead of Solidity's `transfer` function. Payees can query their due
 * payments with {payments}, and retrieve them with {withdrawPayments}.
 */
abstract contract PullPayment {
    Escrow private immutable _escrow;

    constructor() {
        _escrow = new Escrow();
    }

    /**
     * @dev Withdraw accumulated payments, forwarding all gas to the recipient.
     *
     * Note that _any_ account can call this function, not just the `payee`.
     * This means that contracts unaware of the `PullPayment` protocol can still
     * receive funds this way, by having a separate account call
     * {withdrawPayments}.
     *
     * WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities.
     * Make sure you trust the recipient, or are either following the
     * checks-effects-interactions pattern or using {ReentrancyGuard}.
     *
     * @param payee Whose payments will be withdrawn.
     *
     * Causes the `escrow` to emit a {Withdrawn} event.
     */
    function withdrawPayments(address payable payee) public virtual {
        _escrow.withdraw(payee);
    }

    /**
     * @dev Returns the payments owed to an address.
     * @param dest The creditor's address.
     */
    function payments(address dest) public view returns (uint256) {
        return _escrow.depositsOf(dest);
    }

    /**
     * @dev Called by the payer to store the sent amount as credit to be pulled.
     * Funds sent in this way are stored in an intermediate {Escrow} contract, so
     * there is no danger of them being spent before withdrawal.
     *
     * @param dest The destination address of the funds.
     * @param amount The amount to transfer.
     *
     * Causes the `escrow` to emit a {Deposited} event.
     */
    function _asyncTransfer(address dest, uint256 amount) internal virtual {
        _escrow.deposit{value: amount}(dest);
    }
}


adding time to claim htlc invalid

adding time to claim htlc invalid

contract MicropaymentsNetwork
{

    enum ChannelStage
    {
        Empty,
        PartiallyConfirmed,
        Confirmed,
        Closing,
        Closed
    }

    struct MicropaymentsChannel
    {
        ChannelStage stage;

        address from;
        uint fromBalance;

        address to;
        uint toBalance;

        uint balanceTimestamp;
        uint closingBlockNumber;

        mapping(bytes32 => bytes32) hashesUsed;
    }

    uint public constant closingDelay = 10;

    mapping(uint => MicropaymentsChannel) channels;
    mapping(uint => bool) reserved;

    function MicropaymentsNetwork()
    {
    }

    function isAvailable(uint _cid)
        constant
        returns (bool)
    {
        return !reserved[_cid];
    }

    function assertAvailable(uint _cid)
        internal
    {
        if (!isAvailable(_cid))
        {
            throw;
        }
    }

    function assertOnlyFrom(uint _cid)
        internal
    {
        if (msg.sender != channels[_cid].from)
        {
            throw;
        }
    }

    function assertOnlyTo(uint _cid)
        internal
    {
        if (msg.sender != channels[_cid].to)
        {
            throw;
        }
    }

    function assertOnlyParticipants(uint _cid)
        internal
    {
        if ((msg.sender != channels[_cid].from) && (msg.sender != channels[_cid].to))
        {
            throw;
        }
    }

    function assertAtStage(uint _cid, ChannelStage _stage)
        internal
    {
        if (channels[_cid].stage != _stage)
        {
            throw;
        }
    }

    function assertAtOneOfStages(uint _cid, ChannelStage _stage1, ChannelStage _stage2)
    {
        if ((channels[_cid].stage != _stage1) && (channels[_cid].stage != _stage2))
        {
            throw;
        }
    }

    function assertReadyToClose(uint _cid)
    {
        if (block.number < channels[_cid].closingBlockNumber)
        {
            throw;
        }
    }

    function assertYoungerBalance(uint _cid, uint _balanceTimestamp)
        internal
    {
        if (_balanceTimestamp <= channels[_cid].balanceTimestamp)
        {
            throw;
        }
    }

    function assertMatchingBalance(uint _cid, uint _balanceTimestamp)
        internal
    {
        if (channels[_cid].balanceTimestamp < _balanceTimestamp)
        {
            throw;
        }
    }

    function assertSaneBalance(uint _cid, uint _fromBalance, uint _toBalance)
        internal
    {
        if (channels[_cid].fromBalance + channels[_cid].toBalance < _fromBalance + _toBalance)
        {
            throw;
        }
    }

    function assertStillValid(uint _timeout)
        internal
    {
        if (_timeout < now)
        {
            throw;
        }
    }

    function assertSaneHTLC(uint _cid, int _fromToDelta)
        internal
    {
        if ((int(channels[_cid].fromBalance) - _fromToDelta < 0) ||
            (int(channels[_cid].toBalance) + _fromToDelta < 0))
        {
            throw;
        }
    }

    function assertHash(bytes32 _data, bytes32 _hash)
        internal
    {
        if (getHash(_data) != _hash)
        {
            throw;
        }
    }

    function assertSignedByBoth(
        uint _cid,
        bytes32 _sigHash,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
        internal
    {
        address signer = getSigner(_sigHash, _sigV, _sigR, _sigS);
        if (!(((channels[_cid].from == msg.sender) && (channels[_cid].to == signer)) ||
              ((channels[_cid].from == signer) && (channels[_cid].to == msg.sender))))
        {
            throw;
        }
    }

    function assertNotSpent(uint _cid, int _fromToDelta, bytes32 _data, bytes32 _hash)
        internal
    {
        if (getHTLCSpendingData(_cid, _fromToDelta, _hash) == _data)
        {
            throw;
        }
    }

    function getHTLCInvalidationTimeoutExtension(uint _cid, int _fromToDelta, bytes32 _data, bytes32 _hash)
        constant
        returns (uint)
    {
        if (getHTLCSpendingData(_cid, -1 * _fromToDelta, _hash) == _data)
        {
            return 10 minutes;
        }
        return 0;
    }

    function getHTLCSpendingData(uint _cid, int _fromToDelta, bytes32 _hash)
        constant
        returns (bytes32)
    {
        return channels[_cid].hashesUsed[getHTLCSpendingHash(_fromToDelta, _hash)];
    }

    function getHTLCSpendingHash(int _fromToDelta, bytes32 _hash)
        constant
        returns (bytes32)
    {
        return sha3(_fromToDelta, _hash);
    }

    function getHash(bytes32 _data)
        constant
        returns (bytes32)
    {
        return sha3(_data);
    }

    function getUpdateHash(
        uint _cid,
        uint _balanceTimestamp,
        uint _fromBalance,
        uint _toBalance)
        constant
        returns(bytes32)
    {
        return sha3(_cid, _balanceTimestamp, _fromBalance, _toBalance);
    }

    function getHTLCHash(
        uint _cid,
        uint _balanceTimestamp,
        uint _timeout,
        bytes32 _hash,
        int _fromToDelta)
        constant
        returns(bytes32)
    {
        return sha3(_cid, _timeout, _hash, _fromToDelta);
    }

    function getSigner(
        bytes32 _sigHash,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
        constant
        returns(address)
    {
        return ecrecover(_sigHash, _sigV, _sigR, _sigS);
    }

    function getTimestampInSeconds()
        constant
        returns(uint)
    {
        return now;
    }

    function createChannel(uint _cid, address _from, address _to)
    {
        assertAvailable(_cid);

        reserved[_cid] = true;
        channels[_cid] = MicropaymentsChannel(ChannelStage.Empty, _from, 0, _to, 0, 0, 0);
    }

    function getStage(uint _cid)
        constant
        returns (uint8)
    {
        return uint8(channels[_cid].stage);
    }

    function getFrom(uint _cid)
        constant
        returns (address)
    {
        return channels[_cid].from;
    }

    function getFromBalance(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].fromBalance;
    }

    function getTo(uint _cid)
        constant
        returns (address)
    {
        return channels[_cid].to;
    }

    function getToBalance(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].toBalance;
    }

    function getBalanceTimestamp(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].balanceTimestamp;
    }

    function getClosingBlockNumber(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].closingBlockNumber;
    }

    function openChannel(uint _cid)
    {
        assertOnlyFrom(_cid);
        assertAtStage(_cid, ChannelStage.Empty);

        channels[_cid].stage = ChannelStage.PartiallyConfirmed;
        channels[_cid].fromBalance = msg.value;
    }

    function confirmChannel(uint _cid)
    {
        assertOnlyTo(_cid);
        assertAtStage(_cid, ChannelStage.PartiallyConfirmed);

        channels[_cid].stage = ChannelStage.Confirmed;
        channels[_cid].toBalance = msg.value;
    }

    function requestClosingChannel(uint _cid)
    {
        assertOnlyParticipants(_cid);
        assertAtOneOfStages(_cid, ChannelStage.PartiallyConfirmed, ChannelStage.Confirmed);

        if (channels[_cid].stage == ChannelStage.PartiallyConfirmed)
        {
            channels[_cid].stage = ChannelStage.Closed;
        }
        else
        {
            channels[_cid].stage = ChannelStage.Closing;
            channels[_cid].closingBlockNumber = block.number + closingDelay;
        }
    }

    function closeChannel(uint _cid)
    {
        assertOnlyParticipants(_cid);
        assertAtStage(_cid, ChannelStage.Closing);
        assertReadyToClose(_cid);

        channels[_cid].stage = ChannelStage.Closed;
    }

    function withdrawFrom(uint _cid)
    {
        assertOnlyFrom(_cid);
        assertAtStage(_cid, ChannelStage.Closed);

        uint balance = channels[_cid].fromBalance;
        channels[_cid].fromBalance = 0;
        channels[_cid].from.send(balance);
    }

    function withdrawTo(uint _cid)
    {
        assertOnlyTo(_cid);
        assertAtStage(_cid, ChannelStage.Closed);

        uint balance = channels[_cid].toBalance;
        channels[_cid].toBalance = 0;
        channels[_cid].to.send(balance);
    }

    function updateChannelState(
        uint _cid,
        uint _balanceTimestamp,
        uint _fromBalance,
        uint _toBalance,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
    {
        assertOnlyParticipants(_cid);
        assertAtOneOfStages(_cid, ChannelStage.Confirmed, ChannelStage.Closing);
        assertYoungerBalance(_cid, _balanceTimestamp);
        assertSaneBalance(_cid, _fromBalance, _toBalance);
        assertSignedByBoth(_cid, getUpdateHash(_cid, _balanceTimestamp, _fromBalance, _toBalance), _sigV, _sigR, _sigS);

        channels[_cid].balanceTimestamp = _balanceTimestamp;
        channels[_cid].fromBalance = _fromBalance;
        channels[_cid].toBalance = _toBalance;
    }

    function resolveHTLC(
        uint _cid,
        uint _balanceTimestamp,
        uint _timeout,
        bytes32 _hash,
        int _fromToDelta,
        bytes32 _data,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
    {
        assertOnlyParticipants(_cid);
        assertAtOneOfStages(_cid, ChannelStage.Confirmed, ChannelStage.Closing);
        assertMatchingBalance(_cid, _balanceTimestamp);
        assertStillValid(_timeout);
        assertSaneHTLC(_cid, _fromToDelta);
        assertHash(_data, _hash);
        assertNotSpent(_cid, _fromToDelta, _data, _hash);
        assertSignedByBoth(_cid, getHTLCHash(_cid, _balanceTimestamp, _timeout, _hash, _fromToDelta), _sigV, _sigR, _sigS);

        _timeout = _timeout + getHTLCInvalidationTimeoutExtension(_cid, _fromToDelta, _data, _hash);

        channels[_cid].fromBalance = uint(int(channels[_cid].fromBalance) - _fromToDelta);
        channels[_cid].toBalance = uint(int(channels[_cid].toBalance) + _fromToDelta);
        channels[_cid].hashesUsed[getHTLCSpendingHash(_fromToDelta, _hash)] = _data;
    }
}

contract MicropaymentsNetwork
{

    enum ChannelStage
    {
        Empty,
        PartiallyConfirmed,
        Confirmed,
        Closing,
        Closed
    }

    struct MicropaymentsChannel
    {
        ChannelStage stage;

        address from;
        uint fromBalance;

        address to;
        uint toBalance;

        uint balanceTimestamp;
        uint closingBlockNumber;

        mapping(bytes32 => bytes32) hashesUsed;
    }

    uint public constant closingDelay = 10;

    mapping(uint => MicropaymentsChannel) channels;
    mapping(uint => bool) reserved;

    function MicropaymentsNetwork()
    {
    }

    function isAvailable(uint _cid)
        constant
        returns (bool)
    {
        return !reserved[_cid];
    }

    function assertAvailable(uint _cid)
        internal
    {
        if (!isAvailable(_cid))
        {
            throw;
        }
    }

    function assertOnlyFrom(uint _cid)
        internal
    {
        if (msg.sender != channels[_cid].from)
        {
            throw;
        }
    }

    function assertOnlyTo(uint _cid)
        internal
    {
        if (msg.sender != channels[_cid].to)
        {
            throw;
        }
    }

    function assertOnlyParticipants(uint _cid)
        internal
    {
        if ((msg.sender != channels[_cid].from) && (msg.sender != channels[_cid].to))
        {
            throw;
        }
    }

    function assertAtStage(uint _cid, ChannelStage _stage)
        internal
    {
        if (channels[_cid].stage != _stage)
        {
            throw;
        }
    }

    function assertAtOneOfStages(uint _cid, ChannelStage _stage1, ChannelStage _stage2)
    {
        if ((channels[_cid].stage != _stage1) && (channels[_cid].stage != _stage2))
        {
            throw;
        }
    }

    function assertReadyToClose(uint _cid)
    {
        if (block.number < channels[_cid].closingBlockNumber)
        {
            throw;
        }
    }

    function assertYoungerBalance(uint _cid, uint _balanceTimestamp)
        internal
    {
        if (_balanceTimestamp <= channels[_cid].balanceTimestamp)
        {
            throw;
        }
    }

    function assertMatchingBalance(uint _cid, uint _balanceTimestamp)
        internal
    {
        if (channels[_cid].balanceTimestamp < _balanceTimestamp)
        {
            throw;
        }
    }

    function assertSaneBalance(uint _cid, uint _fromBalance, uint _toBalance)
        internal
    {
        if (channels[_cid].fromBalance + channels[_cid].toBalance < _fromBalance + _toBalance)
        {
            throw;
        }
    }

    function assertStillValid(uint _timeout)
        internal
    {
        if (_timeout < now)
        {
            throw;
        }
    }

    function assertSaneHTLC(uint _cid, int _fromToDelta)
        internal
    {
        if ((int(channels[_cid].fromBalance) - _fromToDelta < 0) ||
            (int(channels[_cid].toBalance) + _fromToDelta < 0))
        {
            throw;
        }
    }

    function assertHash(bytes32 _data, bytes32 _hash)
        internal
    {
        if (getHash(_data) != _hash)
        {
            throw;
        }
    }

    function assertNotSpent(uint _cid, int _fromToDelta, bytes32 _data, bytes32 _hash)
        internal
    {
        if (getHTLCSpendingData(_cid, _fromToDelta, _hash) == getHash(_data))
        {
            throw;
        }
    }

    function assertSignedByBoth(
        uint _cid,
        bytes32 _sigHash,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
        internal
    {
        address signer = getSigner(_sigHash, _sigV, _sigR, _sigS);
        if (!(((channels[_cid].from == msg.sender) && (channels[_cid].to == signer)) ||
              ((channels[_cid].from == signer) && (channels[_cid].to == msg.sender))))
        {
            throw;
        }
    }

    function getHTLCSpendingData(uint _cid, int _fromToDelta, bytes32 _hash)
        constant
        returns (bytes32)
    {
        return channels[_cid].hashesUsed[getHTLCSpendingHash(_fromToDelta, _hash)];
    }

    function getHTLCSpendingHash(int _fromToDelta, bytes32 _hash)
        constant
        returns (bytes32)
    {
        return sha3(_fromToDelta, _hash);
    }

    function getHash(bytes32 _data)
        constant
        returns (bytes32)
    {
        return sha3(_data);
    }

    function getUpdateHash(
        uint _cid,
        uint _balanceTimestamp,
        uint _fromBalance,
        uint _toBalance)
        constant
        returns(bytes32)
    {
        return sha3(_cid, _balanceTimestamp, _fromBalance, _toBalance);
    }

    function getHTLCHash(
        uint _cid,
        uint _balanceTimestamp,
        uint _timeout,
        bytes32 _hash,
        int _fromToDelta)
        constant
        returns(bytes32)
    {
        return sha3(_cid, _timeout, _hash, _fromToDelta);
    }

    function getSigner(
        bytes32 _sigHash,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
        constant
        returns(address)
    {
        return ecrecover(_sigHash, _sigV, _sigR, _sigS);
    }

    function getTimestampInSeconds()
        constant
        returns(uint)
    {
        return now;
    }

    function createChannel(uint _cid, address _from, address _to)
    {
        assertAvailable(_cid);

        reserved[_cid] = true;
        channels[_cid] = MicropaymentsChannel(ChannelStage.Empty, _from, 0, _to, 0, 0, 0);
    }

    function getStage(uint _cid)
        constant
        returns (uint8)
    {
        return uint8(channels[_cid].stage);
    }

    function getFrom(uint _cid)
        constant
        returns (address)
    {
        return channels[_cid].from;
    }

    function getFromBalance(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].fromBalance;
    }

    function getTo(uint _cid)
        constant
        returns (address)
    {
        return channels[_cid].to;
    }

    function getToBalance(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].toBalance;
    }

    function getBalanceTimestamp(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].balanceTimestamp;
    }

    function getClosingBlockNumber(uint _cid)
        constant
        returns (uint)
    {
        return channels[_cid].closingBlockNumber;
    }

    function openChannel(uint _cid)
    {
        assertOnlyFrom(_cid);
        assertAtStage(_cid, ChannelStage.Empty);

        channels[_cid].stage = ChannelStage.PartiallyConfirmed;
        channels[_cid].fromBalance = msg.value;
    }

    function confirmChannel(uint _cid)
    {
        assertOnlyTo(_cid);
        assertAtStage(_cid, ChannelStage.PartiallyConfirmed);

        channels[_cid].stage = ChannelStage.Confirmed;
        channels[_cid].toBalance = msg.value;
    }

    function requestClosingChannel(uint _cid)
    {
        assertOnlyParticipants(_cid);
        assertAtOneOfStages(_cid, ChannelStage.PartiallyConfirmed, ChannelStage.Confirmed);

        if (channels[_cid].stage == ChannelStage.PartiallyConfirmed)
        {
            channels[_cid].stage = ChannelStage.Closed;
        }
        else
        {
            channels[_cid].stage = ChannelStage.Closing;
            channels[_cid].closingBlockNumber = block.number + closingDelay;
        }
    }

    function closeChannel(uint _cid)
    {
        assertOnlyParticipants(_cid);
        assertAtStage(_cid, ChannelStage.Closing);
        assertReadyToClose(_cid);

        channels[_cid].stage = ChannelStage.Closed;
    }

    function withdrawFrom(uint _cid)
    {
        assertOnlyFrom(_cid);
        assertAtStage(_cid, ChannelStage.Closed);

        uint balance = channels[_cid].fromBalance;
        channels[_cid].fromBalance = 0;
        channels[_cid].from.send(balance);
    }

    function withdrawTo(uint _cid)
    {
        assertOnlyTo(_cid);
        assertAtStage(_cid, ChannelStage.Closed);

        uint balance = channels[_cid].toBalance;
        channels[_cid].toBalance = 0;
        channels[_cid].to.send(balance);
    }

    function updateChannelState(
        uint _cid,
        uint _balanceTimestamp,
        uint _fromBalance,
        uint _toBalance,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
    {
        assertOnlyParticipants(_cid);
        assertAtOneOfStages(_cid, ChannelStage.Confirmed, ChannelStage.Closing);
        assertYoungerBalance(_cid, _balanceTimestamp);
        assertSaneBalance(_cid, _fromBalance, _toBalance);
        assertSignedByBoth(_cid, getUpdateHash(_cid, _balanceTimestamp, _fromBalance, _toBalance), _sigV, _sigR, _sigS);

        channels[_cid].balanceTimestamp = _balanceTimestamp;
        channels[_cid].fromBalance = _fromBalance;
        channels[_cid].toBalance = _toBalance;
    }

    function resolveHTLC(
        uint _cid,
        uint _balanceTimestamp,
        uint _timeout,
        bytes32 _hash,
        int _fromToDelta,
        bytes32 _data,
        uint8 _sigV,
        bytes32 _sigR,
        bytes32 _sigS)
    {
        assertOnlyParticipants(_cid);
        assertAtOneOfStages(_cid, ChannelStage.Confirmed, ChannelStage.Closing);
        assertMatchingBalance(_cid, _balanceTimestamp);
        assertStillValid(_timeout);
        assertSaneHTLC(_cid, _fromToDelta);
        assertHash(_data, _hash);
        assertNotSpent(_cid, _fromToDelta, _data, _hash);
        assertSignedByBoth(_cid, getHTLCHash(_cid, _balanceTimestamp, _timeout, _hash, _fromToDelta), _sigV, _sigR, _sigS);

        channels[_cid].fromBalance = uint(int(channels[_cid].fromBalance) - _fromToDelta);
        channels[_cid].toBalance = uint(int(channels[_cid].toBalance) + _fromToDelta);
        channels[_cid].hashesUsed[getHTLCSpendingHash(_fromToDelta, _hash)] = _data;
    }
}


Update canary

Update canary

contract SchedulerInterface {
    function scheduleCall(bytes4 abiSignature,
                          uint targetBlock,
                          uint requiredGas) public returns (address);
    function isKnownCall(address callAddress) constant returns (bool);
}

contract CallContractAPI {
    function targetBlock() constant returns (uint);
    function cancel() public;
}

contract Canary {
    uint public aliveSince;
    uint public lastHeartbeat;
    uint public heartbeatCount;
    SchedulerInterface scheduler;
    CallContractAPI callContract;

    address public owner;

    function schedulerAddress() constant returns (address) {
        return address(scheduler);
    }

    function callContractAddress() constant returns (address) {
        return address(callContract);
    }

    function Canary(address _scheduler) {
            owner = msg.sender;
            scheduler = SchedulerInterface(_scheduler);
    }

    function() {
        if (this.balance < 2 ether) {
            owner.send(this.balance);
        }
    }

    function cancel() public {
        // not authorized
        if (msg.sender != owner) throw;
        // need to wait until the
        if (callContract.balance > 0) {
            callContract.cancel();
        }
        owner.send(address(this).balance);

    }

    function initialize() public {
        // ensure we are not already initialized.
        if (aliveSince != 0) return;

        // mark when the canary came to life.
        aliveSince = now;

        // schedule the first call
        scheduleHeartbeat();
    }

    function scheduleHeartbeat() public {
        // schedule the call (~2 hours from now)
        address call_address = scheduler.scheduleCall.value(2 ether)(
            0x3defb962,
            block.number + 480,
            2000000);
        if (call_address != 0x0) {
            callContract = CallContractAPI(call_address);
        }
    }

    function heartbeat() public {
        // Ran out of funds.
        if (this.balance < 2 ether) return;

        // Not being called by the callContract.
        if (msg.sender != address(callContract)) return;

        // The canary has died!
        if (!isAlive()) return;

        // schedule the next call.
        scheduleHeartbeat();

        // Increment the heartbeat count
        heartbeatCount += 1;
        lastHeartbeat = now;
    }

    function isAlive() constant returns (bool) {
        return (aliveSince > 0 && block.number < callContract.targetBlock() + 255);
    }
}

contract CanaryV7Testnet is Canary {
    function CanaryV7Testnet() Canary(0x26416b12610d26fd31d227456e9009270574038f) {
    }
}

contract SchedulerInterface {
    function scheduleCall(address contractAddress,
                          bytes4 abiSignature,
                          uint targetBlock,
                          uint requiredGas,
                          uint8 gracePeriod,
                          uint basePayment) public returns (address);
    function isKnownCall(address callAddress) constant returns (bool);
}

contract CallContractAPI {
    function targetBlock() constant returns (uint);
    function cancel() public;
}

contract Canary {
    uint public aliveSince;
    uint public lastHeartbeat;
    uint public heartbeatCount;
    SchedulerInterface scheduler;
    CallContractAPI callContract;

    address public owner;

    function schedulerAddress() constant returns (address) {
        return address(scheduler);
    }

    function callContractAddress() constant returns (address) {
        return address(callContract);
    }

    function Canary(address _scheduler) {
            owner = msg.sender;
            scheduler = SchedulerInterface(_scheduler);
    }

    function() {
        if (this.balance < 2 ether) {
            owner.send(this.balance);
        }
    }

    function cancel() public {
        // not authorized
        if (msg.sender != owner) throw;
        // need to wait until the
        if (callContract.balance > 0) {
            callContract.cancel();
        }
        owner.send(address(this).balance);

    }

    function initialize() public {
        // ensure we are not already initialized.
        if (aliveSince != 0) return;

        // mark when the canary came to life.
        aliveSince = now;

        // schedule the first call
        scheduleHeartbeat();
    }

    function scheduleHeartbeat() public {
        // schedule the call (~2 hours from now)
        address call_address = scheduler.scheduleCall.value(2 ether)(
            address(this),
            0x3defb962,
            block.number + 480,
            2000000,
            255,
            1 finney);
        if (call_address != 0x0) {
            callContract = CallContractAPI(call_address);
        }
    }

    function heartbeat() public {
        // Ran out of funds.
        if (this.balance < 2 ether) return;

        // Not being called by the callContract.
        if (msg.sender != address(callContract)) return;

        // The canary has died!
        if (!isAlive()) return;

        // schedule the next call.
        scheduleHeartbeat();

        // Increment the heartbeat count
        heartbeatCount += 1;
        lastHeartbeat = now;
    }

    function isAlive() constant returns (bool) {
        return (aliveSince > 0 && block.number < callContract.targetBlock() + 255);
    }
}

contract CanaryV6 is Canary {
    function CanaryV6() Canary(0xe109ecb193841af9da3110c80fdd365d1c23be2a) {
    }
}

contract CanaryTestnet is Canary {
    function CanaryTestnet() Canary(0xb8da699d7fb01289d4ef718a55c3174971092bef) {
    }
}


Improve Initializable docstrings (#3704)

Co-authored-by: tincho <85aed0228fd7c95a745ddea5a0f84964db8fb2b1@noreply.users.github.com>
Co-authored-by: Francisco Giordano <4223852eec80914c4c190cdc031e06592b151a67@gmail.com>
(cherry picked from commit a549ec673e29101003ece15d4e864226cdf00d84)

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0-rc.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/Address.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Internal function that returns the initialized version. Returns `_initialized`
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Internal function that returns the initialized version. Returns `_initializing`
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0-rc.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/Address.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
     * initialization step. This is essential to configure modules that are added through upgrades and that require
     * initialization.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Internal function that returns the initialized version. Returns `_initialized`
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Internal function that returns the initialized version. Returns `_initializing`
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}


Fixed Solium warnings. (#1301)

Fixed Solium warnings. (#1301)

pragma solidity ^0.4.24;

import "./IERC20.sol";

/**
 * @title ERC20Detailed token
 * @dev The decimals are only for visualization purposes.
 * All the operations are done using the smallest and indivisible token unit,
 * just as on Ethereum all the operations are done in wei.
 */
contract ERC20Detailed is IERC20 {
  string private name_;
  string private symbol_;
  uint8 private decimals_;

  constructor(string _name, string _symbol, uint8 _decimals) public {
    name_ = _name;
    symbol_ = _symbol;
    decimals_ = _decimals;
  }

  /**
   * @return the name of the token.
   */
  function name() public view returns(string) {
    return name_;
  }

  /**
   * @return the symbol of the token.
   */
  function symbol() public view returns(string) {
    return symbol_;
  }

  /**
   * @return the number of decimals of the token.
   */
  function decimals() public view returns(uint8) {
    return decimals_;
  }
}


Split up fallback function modifier

Split up fallback function modifier

pragma solidity ^0.4.8;

import "./Token.sol";
import "./SafeMath.sol";

/// @title Standard token contract with overflow protection - Used for tokens with dynamic supply.
contract StandardTokenWithOverflowProtection is Token,
                                                SafeMath
{

    /*
     *  Data structures
     */
    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint256)) allowed;
    uint256 public totalSupply;

    /*
     *  Public functions
     */
    /// @dev Transfers sender's tokens to a given address. Returns success.
    /// @param _to Address of token receiver.
    /// @param _value Number of tokens to transfer.
    /// @return Returns success of function call.
    function transfer(address _to, uint256 _value)
        public
        returns (bool)
    {
        balances[msg.sender] = safeSub(balances[msg.sender], _value);
        balances[_to] = safeAdd(balances[_to], _value);
        Transfer(msg.sender, _to, _value);
        return true;
    }

    /// @dev Allows allowed third party to transfer tokens from one address to another. Returns success.
    /// @param _from Address from where tokens are withdrawn.
    /// @param _to Address to where tokens are sent.
    /// @param _value Number of tokens to transfer.
    /// @return Returns success of function call.
    function transferFrom(address _from, address _to, uint256 _value)
        public
        returns (bool)
    {
        balances[_from] = safeSub(balances[_from], _value);
        allowed[_from][msg.sender] = safeSub(allowed[_from][msg.sender], _value);
        balances[_to] = safeAdd(balances[_to], _value);
        Transfer(_from, _to, _value);
        return true;
    }

    /// @dev Sets approved amount of tokens for spender. Returns success.
    /// @param _spender Address of allowed account.
    /// @param _value Number of approved tokens.
    /// @return Returns success of function call.
    function approve(address _spender, uint256 _value)
        public
        returns (bool)
    {
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
    }

    /*
     * Read functions
     */
    /// @dev Returns number of allowed tokens for given address.
    /// @param _owner Address of token owner.
    /// @param _spender Address of token spender.
    /// @return Returns remaining allowance for spender.
    function allowance(address _owner, address _spender)
        constant
        public
        returns (uint256)
    {
        return allowed[_owner][_spender];
    }

    /// @dev Returns number of tokens owned by given address.
    /// @param _owner Address of token owner.
    /// @return Returns balance of owner.
    function balanceOf(address _owner)
        constant
        public
        returns (uint256)
    {
        return balances[_owner];
    }
}

error: pathspec 'Contracts/Base/StandardTokenWithOverflowProtection.sol' did not match any file(s) known to git


Adds ActionEvent for linkTaskToUser

Adds ActionEvent for linkTaskToUser

import "User.sol";

contract Linker {

    // TODO extend with eventObject if possible; `bytes32[]`?
    event ActionEvent(address indexed userAddr, bytes32 actionType);
    function registerActionEvent(bytes32 actionType) {
      ActionEvent(msg.sender, actionType);
    }

    function linkTaskToUser(address taskAddr, address userAddr) returns (bool) {
        registerActionEvent('LINK TASK TO USER');
        return User(userAddr).associateWithTaskAddress(taskAddr);
    }

}

import "User.sol";

contract Linker {

    // TODO extend with eventObject if possible; `bytes32[]`?
    event ActionEvent(address indexed userAddr, bytes32 actionType);
    function registerActionEvent(bytes32 actionType) {
      ActionEvent(msg.sender, actionType);
    }

    function linkTaskToUser(address taskAddr, address userAddr) returns (bool) {
        return User(userAddr).associateWithTaskAddress(taskAddr);
    }

}


re-added token assignment.

re-added token assignment.

contract owned {
    address public owner;

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

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

    function transferOwnership(address newOwner) onlyOwner {
        owner = newOwner;
    }
}
contract tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData); }

contract token is owned{
    /* Public variables of the token */
    string public standard = 'Token 0.1';
    string public name;
    string public symbol;
    uint8 public decimals;
    uint256 public totalSupply;
    uint public equityMarker;
    uint public supplyIncreaseRate;
    address public CEOaddress;

    /* This creates an array with all balances */
    mapping (address => uint256) public balanceOf;
    mapping (address => mapping (address => uint256)) public allowance;

    mapping(uint => address) public indexes;
    uint public currentIndex;
    mapping (address => uint) etherBalanceOf;

    /* This generates a public event on the blockchain that will notify clients */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /* Initializes contract with initial supply tokens to the creator of the contract */
    function token(
        uint256 initialSupply,
        string tokenName,
        uint8 decimalUnits,
        string tokenSymbol,
        address ceoAddress,
        uint256 equityGoal
        ) {
        balanceOf[msg.sender] = initialSupply;              // Give the creator all initial tokens
        totalSupply = initialSupply;                        // Update total supply
        name = tokenName;                                   // Set the name for display purposes
        symbol = tokenSymbol;                               // Set the symbol for display purposes
        decimals = decimalUnits;                            // Amount of decimals for display purposes
        CEOaddress = ceoAddress;                            // Set the address of the Ceo.
        supplyIncreaseRate = equityGoal;                    // Equity goal to distribute a token to CEO
        msg.sender.send(msg.value);
        currentIndex = 0;
        indexes[currentIndex] = msg.sender;
        currentIndex = 1;
        indexes[currentIndex] = ceoAddress;

        }

    /* Send coins */
    function transfer(address _to, uint256 _value) {
        if (balanceOf[msg.sender] < _value) throw;           // Check if the sender has enough
        if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows
        balanceOf[msg.sender] -= _value;                     // Subtract from the sender
        balanceOf[_to] += _value;                            // Add the same to the recipient
        if(balanceOf[_to] == 0){
            currentIndex ++;
            indexes[currentIndex] = _to;
        }
        Transfer(msg.sender, _to, _value);                   // Notify anyone listening that this transfer took place
    }

    /* Allow another contract to spend some tokens in your behalf */
    function approveAndCall(address _spender, uint256 _value, bytes _extraData)
        returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        tokenRecipient spender = tokenRecipient(_spender);
        spender.receiveApproval(msg.sender, _value, this, _extraData);
        return true;
    }

    /* A contract attempts to get the coins */
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        if (balanceOf[_from] < _value) throw;                 // Check if the sender has enough
        if (balanceOf[_to] + _value < balanceOf[_to]) throw;  // Check for overflows
        if (_value > allowance[_from][msg.sender]) throw;   // Check allowance
        balanceOf[_from] -= _value;                          // Subtract from the sender
        balanceOf[_to] += _value;                            // Add the same to the recipient
        allowance[_from][msg.sender] -= _value;
        if(balanceOf[_to] == 0){
            currentIndex ++;
            indexes[currentIndex] = _to;
        }
        Transfer(_from, _to, _value);
        return true;
    }

    /*withdraw funds*/
   function withDraw(){
        if(etherBalanceOf[msg.sender]>0){
          uint value = etherBalanceOf[msg.sender];
          etherBalanceOf[msg.sender] = 0;
          msg.sender.send(value);
        }
    }

    /* This unnamed function is called whenever someone tries to send ether to it */
    function () {
        equityMarker += msg.value;
        for(var i = 0; i < currentIndex + 1; i++){
            etherBalanceOf[indexes[i]] += balanceOf[indexes[i]]/totalSupply*msg.value;
        }
        //gives a token to the CEO everytime equity increases.
        if(equityMarker >= supplyIncreaseRate){
            equityMarker -= supplyIncreaseRate;
            balanceOf[CEOaddress] += 1;
        }
        //throw;
    }
}

contract owned {
    address public owner;

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

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

    function transferOwnership(address newOwner) onlyOwner {
        owner = newOwner;
    }
}
contract tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData); }

contract token is owned{
    /* Public variables of the token */
    string public standard = 'Token 0.1';
    string public name;
    string public symbol;
    uint8 public decimals;
    uint256 public totalSupply;
    uint256 public totalEquityEarned;

    /* This creates an array with all balances */
    mapping (address => uint256) public balanceOf;
    mapping (address => mapping (address => uint256)) public allowance;

    mapping(uint => address) public indexes;
    uint public currentIndex;
    mapping (address => uint) etherBalanceOf;

    /* This generates a public event on the blockchain that will notify clients */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /* Initializes contract with initial supply tokens to the creator of the contract */
    function token(
        uint256 initialSupply,
        string tokenName,
        uint8 decimalUnits,
        string tokenSymbol
        ) {
        balanceOf[msg.sender] = initialSupply;              // Give the creator all initial tokens
        totalSupply = initialSupply;                        // Update total supply
        name = tokenName;                                   // Set the name for display purposes
        symbol = tokenSymbol;                               // Set the symbol for display purposes
        decimals = decimalUnits;                            // Amount of decimals for display purposes
        msg.sender.send(msg.value);
        currentIndex = 0;
        indexes[currentIndex] = msg.sender;

        }

    /* Send coins */
    function transfer(address _to, uint256 _value) {
        if (balanceOf[msg.sender] < _value) throw;           // Check if the sender has enough
        if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows
        balanceOf[msg.sender] -= _value;                     // Subtract from the sender
        balanceOf[_to] += _value;                            // Add the same to the recipient
        if(balanceOf[_to] == 0){
            currentIndex ++;
            indexes[currentIndex] = _to;
        }
        Transfer(msg.sender, _to, _value);                   // Notify anyone listening that this transfer took place
    }

    /* Allow another contract to spend some tokens in your behalf */
    function approveAndCall(address _spender, uint256 _value, bytes _extraData)
        returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        tokenRecipient spender = tokenRecipient(_spender);
        spender.receiveApproval(msg.sender, _value, this, _extraData);
        return true;
    }

    /* A contract attempts to get the coins */
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        if (balanceOf[_from] < _value) throw;                 // Check if the sender has enough
        if (balanceOf[_to] + _value < balanceOf[_to]) throw;  // Check for overflows
        if (_value > allowance[_from][msg.sender]) throw;   // Check allowance
        balanceOf[_from] -= _value;                          // Subtract from the sender
        balanceOf[_to] += _value;                            // Add the same to the recipient
        allowance[_from][msg.sender] -= _value;
        if(balanceOf[_to] == 0){
            currentIndex ++;
            indexes[currentIndex] = _to;
        }
        Transfer(_from, _to, _value);
        return true;
    }

    /*withdraw funds*/
   function withDraw(){
        if(etherBalanceOf[msg.sender]>0){
          uint value = etherBalanceOf[msg.sender];
          etherBalanceOf[msg.sender] = 0;
          msg.sender.send(value);
        }
    }

    /* This unnamed function is called whenever someone tries to send ether to it */
    function () {
       for(var i = 0; i < currentIndex + 1; i++){
          etherBalanceOf[indexes[i]] += balanceOf[indexes[i]]/totalSupply*msg.value;
        }
        //throw;
    }
}


Commented modifiers

Commented modifiers


Now setting the finalized flag before doing finalization to prevent possbile reentrancy issues. (#1447)

(cherry picked from commit 5bb865218f02a01d0521c9d9a947cdf4bd32e74c)

pragma solidity ^0.4.24;

import "../../math/SafeMath.sol";
import "../validation/TimedCrowdsale.sol";

/**
 * @title FinalizableCrowdsale
 * @dev Extension of Crowdsale with a one-off finalization action, where one
 * can do extra work after finishing.
 */
contract FinalizableCrowdsale is TimedCrowdsale {
  using SafeMath for uint256;

  bool private _finalized;

  event CrowdsaleFinalized();

  constructor() internal {
    _finalized = false;
  }

  /**
   * @return true if the crowdsale is finalized, false otherwise.
   */
  function finalized() public view returns (bool) {
    return _finalized;
  }

  /**
   * @dev Must be called after crowdsale ends, to do some extra finalization
   * work. Calls the contract's finalization function.
   */
  function finalize() public {
    require(!_finalized);
    require(hasClosed());

    _finalized = true;

    _finalization();
    emit CrowdsaleFinalized();
  }

  /**
   * @dev Can be overridden to add finalization logic. The overriding function
   * should call super._finalization() to ensure the chain of finalization is
   * executed entirely.
   */
  function _finalization() internal {
  }
}

pragma solidity ^0.4.24;

import "../../math/SafeMath.sol";
import "../validation/TimedCrowdsale.sol";

/**
 * @title FinalizableCrowdsale
 * @dev Extension of Crowdsale with a one-off finalization action, where one
 * can do extra work after finishing.
 */
contract FinalizableCrowdsale is TimedCrowdsale {
  using SafeMath for uint256;

  bool private _finalized;

  event CrowdsaleFinalized();

  constructor() internal {
    _finalized = false;
  }

  /**
   * @return true if the crowdsale is finalized, false otherwise.
   */
  function finalized() public view returns (bool) {
    return _finalized;
  }

  /**
   * @dev Must be called after crowdsale ends, to do some extra finalization
   * work. Calls the contract's finalization function.
   */
  function finalize() public {
    require(!_finalized);
    require(hasClosed());

    _finalization();
    emit CrowdsaleFinalized();

    _finalized = true;
  }

  /**
   * @dev Can be overridden to add finalization logic. The overriding function
   * should call super._finalization() to ensure the chain of finalization is
   * executed entirely.
   */
  function _finalization() internal {
  }

}


working towards better documentation

working towards better documentation


Test blob ownership.

Test blob ownership.

pragma solidity ^0.4.4;

import "dapple/test.sol";
import "./blobstore.sol";
import "./blobstore_flags.sol";
import "./blobstore_proxy.sol";

/**
 * @title BlobStoreTest
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStoreTest is Test, BlobStoreFlags {

    BlobStoreRegistry blobStoreRegistry;
    BlobStore blobStore;
    BlobStoreProxy blobStoreProxy;

    function setUp() {
        blobStoreRegistry = new BlobStoreRegistry();
        blobStore = new BlobStore(blobStoreRegistry);
        blobStoreProxy = new BlobStoreProxy(blobStore);
    }

    function testThrowRegisterContractAgain() {
        blobStoreRegistry.register(blobStore.getContractId());
    }

    function testThrowBlobStoreNotRegistered() {
        blobStoreRegistry.getBlobStore(0);
    }

    function testBlobStoreRegistered() {
        assertEq(blobStoreRegistry.getBlobStore(blobStore.getContractId()), blobStore);
    }

    function testCreate() {
        bytes20 blobId0 = blobStore.create(0, hex"00");
        assertTrue(blobStore.getExists(blobId0));
        assertEq(blobStore.getOwner(blobId0), this);
        assertEq(blobStore.getRevisionCount(blobId0), 1);
        assertFalse(blobStore.getUpdatable(blobId0));
        assertFalse(blobStore.getEnforceRevisions(blobId0));
        assertFalse(blobStore.getRetractable(blobId0));
        assertFalse(blobStore.getTransferable(blobId0));

        bytes20 blobId1 = blobStore.create(UPDATABLE | ENFORCE_REVISIONS | RETRACTABLE | TRANSFERABLE | ANONYMOUS, hex"00");
        assertTrue(blobStore.getExists(blobId1));
        assertEq(blobStore.getOwner(blobId1), 0);
        assertEq(blobStore.getRevisionCount(blobId1), 1);
        assertTrue(blobStore.getUpdatable(blobId1));
        assertTrue(blobStore.getEnforceRevisions(blobId1));
        assertTrue(blobStore.getRetractable(blobId1));
        assertTrue(blobStore.getTransferable(blobId1));

        assertFalse(blobId0 == blobId1);
    }

    function testThrowCreateWithNonceExistingNonce() {
        blobStore.createWithNonce(0, hex"00");
        blobStore.createWithNonce(0, hex"00");
    }

    function testCreateWithNonce() {
        bytes20 blobId0 = blobStore.createWithNonce(0, hex"00");
        assertTrue(blobStore.getExists(blobId0));
        assertEq(blobStore.getOwner(blobId0), this);
        assertEq(blobStore.getRevisionCount(blobId0), 1);
        assertFalse(blobStore.getUpdatable(blobId0));
        assertFalse(blobStore.getEnforceRevisions(blobId0));
        assertFalse(blobStore.getRetractable(blobId0));
        assertFalse(blobStore.getTransferable(blobId0));

        bytes20 blobId1 = blobStoreProxy.createWithNonce(0, hex"00");

        assertTrue(blobStore.getExists(blobId1));
        assertEq(blobStore.getOwner(blobId1), blobStoreProxy);
        assertEq(blobStore.getRevisionCount(blobId1), 1);
        assertFalse(blobStore.getUpdatable(blobId1));
        assertFalse(blobStore.getEnforceRevisions(blobId1));
        assertFalse(blobStore.getRetractable(blobId1));
        assertFalse(blobStore.getTransferable(blobId1));
        assertFalse(blobId0 == blobId1);

        blobId1 = blobStore.createWithNonce(UPDATABLE | ENFORCE_REVISIONS | RETRACTABLE | TRANSFERABLE | ANONYMOUS, hex"00");
        assertTrue(blobStore.getExists(blobId1));
        assertEq(blobStore.getOwner(blobId1), 0);
        assertEq(blobStore.getRevisionCount(blobId1), 1);
        assertTrue(blobStore.getUpdatable(blobId1));
        assertTrue(blobStore.getEnforceRevisions(blobId1));
        assertTrue(blobStore.getRetractable(blobId1));
        assertTrue(blobStore.getTransferable(blobId1));
        assertFalse(blobId0 == blobId1);
    }

    function testThrowCreateWithNonceRetracted() {
        bytes20 blobId = blobStore.createWithNonce(RETRACTABLE, hex"00");
        blobStore.retract(blobId);
        blobStore.createWithNonce(RETRACTABLE, hex"00");
    }

    function testThrowsCreateNewRevisionNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStoreProxy.createNewRevision(blobId, hex"00");
    }

    function testThrowsCreateNewRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
    }

    function testCreateNewRevision() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        uint revisionId = blobStore.createNewRevision(blobId, hex"00");
        assertEq(revisionId, 1);
        assertEq(blobStore.getRevisionCount(blobId), 2);
    }

    function testThrowsUpdateLatestRevisionNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStoreProxy.updateLatestRevision(blobId, hex"00");
    }

    function testThrowsUpdateLatestRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
    }

    function testThrowsUpdateLatestRevisionEnforceRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE | ENFORCE_REVISIONS, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
    }

    function testUpdateLatestRevision() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 1);
    }

    function testThrowsRetractLatestRevisionNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStoreProxy.retractLatestRevision(blobId);
    }

    function testThrowsRetractLatestRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.setNotUpdatable(blobId);
        blobStore.retractLatestRevision(blobId);
    }

    function testThrowsRetractLatestRevisionEnforceRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE | ENFORCE_REVISIONS, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.retractLatestRevision(blobId);
    }

    function testThrowsRetractLatestRevisionDoesntHaveAdditionalRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.retractLatestRevision(blobId);
    }

    function testRetractLatestRevision() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 3);
        blobStore.retractLatestRevision(blobId);
        assertEq(blobStore.getRevisionCount(blobId), 2);
    }

    function testThrowsRestartNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStoreProxy.restart(blobId, hex"00");
    }

    function testThrowsRestartNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.restart(blobId, hex"00");
    }

    function testThrowsRestartEnforceRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE | ENFORCE_REVISIONS, hex"00");
        blobStore.restart(blobId, hex"00");
    }

    function testRestart() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 3);
        blobStore.restart(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 1);
    }

    function testThrowsRetractNotOwner() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        blobStoreProxy.retract(blobId);
    }

    function testThrowsRetractNotRetractable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.retract(blobId);
    }

    function testRetract() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        blobStore.retract(blobId);
        assertEq(blobStore.getExists(blobId), false);
    }

    function testThrowsDisownNotOwner() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStoreProxy.disown(blobId);
    }

    function testThrowsDisownNotTransferable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.disown(blobId);
    }

    function testDisown() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        assertEq(blobStore.getOwner(blobId), this);
        blobStore.disown(blobId);
        assertEq(blobStore.getOwner(blobId), 0);
    }

    function testThrowsSetNotUpdatableNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStoreProxy.setNotUpdatable(blobId);
    }

    function testSetNotUpdatable() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        assertTrue(blobStore.getUpdatable(blobId));
        blobStore.setNotUpdatable(blobId);
        assertEq(blobStore.getUpdatable(blobId), false);
    }

    function testThrowsSetEnforceRevisionsNotOwner() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStoreProxy.setEnforceRevisions(blobId);
    }

    function testSetEnforceRevisions() {
        bytes20 blobId = blobStore.create(0, hex"00");
        assertEq(blobStore.getEnforceRevisions(blobId), false);
        blobStore.setEnforceRevisions(blobId);
        assertTrue(blobStore.getEnforceRevisions(blobId));
    }

    function testThrowsSetNotRetractableNotOwner() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        blobStoreProxy.setNotRetractable(blobId);
    }

    function testSetNotRetractable() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        assertTrue(blobStore.getRetractable(blobId));
        blobStore.setNotRetractable(blobId);
        assertEq(blobStore.getRetractable(blobId), false);
    }

    function testThrowsSetNotTransferableNotOwner() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStoreProxy.setNotTransferable(blobId);
    }

    function testSetNotTransferable() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        assertTrue(blobStore.getTransferable(blobId));
        blobStore.setNotTransferable(blobId);
        assertEq(blobStore.getTransferable(blobId), false);
    }

}

pragma solidity ^0.4.4;

import "dapple/test.sol";
import "./blobstore.sol";
import "./blobstore_flags.sol";
import "./blobstore_proxy.sol";

/**
 * @title BlobStoreTest
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStoreTest is Test, BlobStoreFlags {

    BlobStoreRegistry blobStoreRegistry;
    BlobStore blobStore;

    function setUp() {
        blobStoreRegistry = new BlobStoreRegistry();
        blobStore = new BlobStore(blobStoreRegistry);
    }

    function testThrowRegisterContractAgain() {
        blobStoreRegistry.register(blobStore.getContractId());
    }

    function testThrowBlobStoreNotRegistered() {
        blobStoreRegistry.getBlobStore(0);
    }

    function testBlobStoreRegistered() {
        assertEq(blobStoreRegistry.getBlobStore(blobStore.getContractId()), blobStore);
    }

    function testCreate() {
        bytes20 blobId0 = blobStore.create(0, hex"00");
        assertTrue(blobStore.getExists(blobId0));
        assertEq(blobStore.getOwner(blobId0), this);
        assertEq(blobStore.getRevisionCount(blobId0), 1);
        assertFalse(blobStore.getUpdatable(blobId0));
        assertFalse(blobStore.getEnforceRevisions(blobId0));
        assertFalse(blobStore.getRetractable(blobId0));
        assertFalse(blobStore.getTransferable(blobId0));

        bytes20 blobId1 = blobStore.create(UPDATABLE | ENFORCE_REVISIONS | RETRACTABLE | TRANSFERABLE | ANONYMOUS, hex"00");
        assertTrue(blobStore.getExists(blobId1));
        assertEq(blobStore.getOwner(blobId1), 0);
        assertEq(blobStore.getRevisionCount(blobId1), 1);
        assertTrue(blobStore.getUpdatable(blobId1));
        assertTrue(blobStore.getEnforceRevisions(blobId1));
        assertTrue(blobStore.getRetractable(blobId1));
        assertTrue(blobStore.getTransferable(blobId1));

        assertFalse(blobId0 == blobId1);
    }

    function testThrowCreateWithNonceExistingNonce() {
        blobStore.createWithNonce(0, hex"00");
        blobStore.createWithNonce(0, hex"00");
    }

    function testCreateWithNonce() {
        bytes20 blobId0 = blobStore.createWithNonce(0, hex"00");
        assertTrue(blobStore.getExists(blobId0));
        assertEq(blobStore.getOwner(blobId0), this);
        assertEq(blobStore.getRevisionCount(blobId0), 1);
        assertFalse(blobStore.getUpdatable(blobId0));
        assertFalse(blobStore.getEnforceRevisions(blobId0));
        assertFalse(blobStore.getRetractable(blobId0));
        assertFalse(blobStore.getTransferable(blobId0));

        bytes20 blobId1 = blobStore.createWithNonce(UPDATABLE | ENFORCE_REVISIONS | RETRACTABLE | TRANSFERABLE | ANONYMOUS, hex"00");
        assertTrue(blobStore.getExists(blobId1));
        assertEq(blobStore.getOwner(blobId1), 0);
        assertEq(blobStore.getRevisionCount(blobId1), 1);
        assertTrue(blobStore.getUpdatable(blobId1));
        assertTrue(blobStore.getEnforceRevisions(blobId1));
        assertTrue(blobStore.getRetractable(blobId1));
        assertTrue(blobStore.getTransferable(blobId1));

        assertFalse(blobId0 == blobId1);
    }

    function testThrowCreateWithNonceRetracted() {
        bytes20 blobId = blobStore.createWithNonce(RETRACTABLE, hex"00");
        blobStore.retract(blobId);
        blobStore.createWithNonce(RETRACTABLE, hex"00");
    }

    function testThrowsCreateNewRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
    }

    function testCreateNewRevision() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        uint revisionId = blobStore.createNewRevision(blobId, hex"00");
        assertEq(revisionId, 1);
        assertEq(blobStore.getRevisionCount(blobId), 2);
    }

    function testThrowsUpdateLatestRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
    }

    function testThrowsUpdateLatestRevisionEnforceRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE | ENFORCE_REVISIONS, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
    }

    function testUpdateLatestRevision() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 1);
    }

    function testThrowsRetractLatestRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.setNotUpdatable(blobId);
        blobStore.retractLatestRevision(blobId);
    }

    function testThrowsRetractLatestRevisionEnforceRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE | ENFORCE_REVISIONS, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.retractLatestRevision(blobId);
    }

    function testThrowsRetractLatestRevisionDoesntHaveAdditionalRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.retractLatestRevision(blobId);
    }

    function testRetractLatestRevision() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 3);
        blobStore.retractLatestRevision(blobId);
        assertEq(blobStore.getRevisionCount(blobId), 2);
    }

    function testThrowsRestartNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.restart(blobId, hex"00");
    }

    function testThrowsRestartEnforceRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE | ENFORCE_REVISIONS, hex"00");
        blobStore.restart(blobId, hex"00");
    }

    function testRestart() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 3);
        blobStore.restart(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 1);
    }

    function testThrowsRetractNotRetractable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.retract(blobId);
    }

    function testRetract() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        blobStore.retract(blobId);
        assertEq(blobStore.getExists(blobId), false);
    }

    function testThrowsDisownNotTransferable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.disown(blobId);
    }

    function testDisown() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        assertEq(blobStore.getOwner(blobId), this);
        blobStore.disown(blobId);
        assertEq(blobStore.getOwner(blobId), 0);
    }

    function testSetNotUpdatable() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        assertTrue(blobStore.getUpdatable(blobId));
        blobStore.setNotUpdatable(blobId);
        assertEq(blobStore.getUpdatable(blobId), false);
    }

    function testSetEnforceRevisions() {
        bytes20 blobId = blobStore.create(0, hex"00");
        assertEq(blobStore.getEnforceRevisions(blobId), false);
        blobStore.setEnforceRevisions(blobId);
        assertTrue(blobStore.getEnforceRevisions(blobId));
    }

    function testSetNotRetractable() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        assertTrue(blobStore.getRetractable(blobId));
        blobStore.setNotRetractable(blobId);
        assertEq(blobStore.getRetractable(blobId), false);
    }

    function testSetNotTransferable() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        assertTrue(blobStore.getTransferable(blobId));
        blobStore.setNotTransferable(blobId);
        assertEq(blobStore.getTransferable(blobId), false);
    }

}