Contract 0x1166363D3005F96E6e2D940860BC346414E0cFB9

Contract Overview

Balance:
0 Ether
Txn Hash
Method
Block
From
To
Value
0xb6c4e40fb69d86bceeaa3fd79ef341bc32995b14115087b087b90130cfd6384cPerform Top Up111767522022-08-10 7:10:019 days 16 hrs ago0x424a05579b66d8d83d9584d1bf276e79b4eb5c1f IN  0x1166363d3005f96e6e2d940860bc346414e0cfb90 Ether0.000145082
0x8d7bd6b324261b61850b40b26c279738d090701ad03d5f4197ada8ef4759ec4bCreate Top Up111767502022-08-10 7:09:319 days 16 hrs ago0x424a05579b66d8d83d9584d1bf276e79b4eb5c1f IN  0x1166363d3005f96e6e2d940860bc346414e0cfb90 Ether0.000087422
0xb062e5a99695dfc89e7e952ecc2d87ef61c729f59d1463d27f8bec23e2ab1657Create Top Up109427082022-06-30 13:49:4850 days 10 hrs ago0x424a05579b66d8d83d9584d1bf276e79b4eb5c1f IN  0x1166363d3005f96e6e2d940860bc346414e0cfb90 Ether0.000325172
0xed2b6b44daf916fee3c94dec69d8d9a6ef5dcdb7a1fb0fce119cecfe6fc8deaaAdd Approved Str...109249472022-06-27 11:41:1353 days 12 hrs ago0x917a19e71a2811504c4f64ab33c132063b5772a5 IN  0x1166363d3005f96e6e2d940860bc346414e0cfb90 Ether0.0000719 1.50000001
0xa8334962c24686f3999a2e4a6b5e55b36dbd1228bc0df5859dc00f3549f7fb86Create Top Up109247292022-06-27 10:46:3753 days 13 hrs ago0x424a05579b66d8d83d9584d1bf276e79b4eb5c1f IN  0x1166363d3005f96e6e2d940860bc346414e0cfb90 Ether0.000068132
0x6b126441e0fe87bc1827cc2e8a119869c9acbca393c00740f39c0435e890aacaCreate Top Up109247222022-06-27 10:44:5253 days 13 hrs ago0x424a05579b66d8d83d9584d1bf276e79b4eb5c1f IN  0x1166363d3005f96e6e2d940860bc346414e0cfb90 Ether0.000057942
0x4c5014480df26102528190147ee2c2fcbc1d533ed82a4d5bcbb216c53a3858850x60a06040109126102022-06-25 8:08:4355 days 15 hrs ago0x917a19e71a2811504c4f64ab33c132063b5772a5 IN  Create: StrollManager0 Ether0.00397654 1.50000002
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xb6c4e40fb69d86bceeaa3fd79ef341bc32995b14115087b087b90130cfd6384c111767522022-08-10 7:10:019 days 16 hrs ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0xf4c5310e51f6079f601a5fb7120bc72a70b96e2a0 Ether
0xb6c4e40fb69d86bceeaa3fd79ef341bc32995b14115087b087b90130cfd6384c111767522022-08-10 7:10:019 days 16 hrs ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0xa6c537b0e5162b6a220522d0657749144d1a180e0 Ether
0xb6c4e40fb69d86bceeaa3fd79ef341bc32995b14115087b087b90130cfd6384c111767522022-08-10 7:10:019 days 16 hrs ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0x15f0ca26781c3852f8166ed2ebce5d18265cceb70 Ether
0xb6c4e40fb69d86bceeaa3fd79ef341bc32995b14115087b087b90130cfd6384c111767522022-08-10 7:10:019 days 16 hrs ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0x15f0ca26781c3852f8166ed2ebce5d18265cceb70 Ether
0xcec60fcd3773fb870248b3304ee3d988d42f56cdb6e61eb93e86643bf31867f3111692202022-08-08 23:42:5611 days 19 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0xa6c537b0e5162b6a220522d0657749144d1a180e0 Ether
0xcec60fcd3773fb870248b3304ee3d988d42f56cdb6e61eb93e86643bf31867f3111692202022-08-08 23:42:5611 days 19 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0xa6c537b0e5162b6a220522d0657749144d1a180e0 Ether
0xcec60fcd3773fb870248b3304ee3d988d42f56cdb6e61eb93e86643bf31867f3111692202022-08-08 23:42:5611 days 19 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0x745861aed1eee363b4aaa5f1994be40b1e05ff900 Ether
0xcec60fcd3773fb870248b3304ee3d988d42f56cdb6e61eb93e86643bf31867f3111692202022-08-08 23:42:5611 days 19 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0xf4c5310e51f6079f601a5fb7120bc72a70b96e2a0 Ether
0xcec60fcd3773fb870248b3304ee3d988d42f56cdb6e61eb93e86643bf31867f3111692202022-08-08 23:42:5611 days 19 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0xa6c537b0e5162b6a220522d0657749144d1a180e0 Ether
0xcec60fcd3773fb870248b3304ee3d988d42f56cdb6e61eb93e86643bf31867f3111692202022-08-08 23:42:5611 days 19 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0x15f0ca26781c3852f8166ed2ebce5d18265cceb70 Ether
0xcec60fcd3773fb870248b3304ee3d988d42f56cdb6e61eb93e86643bf31867f3111692202022-08-08 23:42:5611 days 19 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0x15f0ca26781c3852f8166ed2ebce5d18265cceb70 Ether
0xcec60fcd3773fb870248b3304ee3d988d42f56cdb6e61eb93e86643bf31867f3111692202022-08-08 23:42:5611 days 19 mins ago 0x8b0e2c6c6feb348776db4747b8124df1082facfa 0x1166363d3005f96e6e2d940860bc346414e0cfb90 Ether
0xedf85a965710f26e0d66f6b0b93e55032c03377769bb83eb2369b87b55ff4a09111441132022-08-04 14:47:4115 days 9 hrs ago 0x8f5aa163e7a5a2ba5d8f8a176b454de60b8ac862 0x1166363d3005f96e6e2d940860bc346414e0cfb90 Ether
0xfa2674f7567ce43f3d740f9b35ee27a369fec1acf4a1dfd894751c1073bd7b66111290512022-08-01 23:42:1618 days 20 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0xa6c537b0e5162b6a220522d0657749144d1a180e0 Ether
0xfa2674f7567ce43f3d740f9b35ee27a369fec1acf4a1dfd894751c1073bd7b66111290512022-08-01 23:42:1618 days 20 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0xa6c537b0e5162b6a220522d0657749144d1a180e0 Ether
0xfa2674f7567ce43f3d740f9b35ee27a369fec1acf4a1dfd894751c1073bd7b66111290512022-08-01 23:42:1618 days 20 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0x745861aed1eee363b4aaa5f1994be40b1e05ff900 Ether
0xfa2674f7567ce43f3d740f9b35ee27a369fec1acf4a1dfd894751c1073bd7b66111290512022-08-01 23:42:1618 days 20 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0xf4c5310e51f6079f601a5fb7120bc72a70b96e2a0 Ether
0xfa2674f7567ce43f3d740f9b35ee27a369fec1acf4a1dfd894751c1073bd7b66111290512022-08-01 23:42:1618 days 20 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0xa6c537b0e5162b6a220522d0657749144d1a180e0 Ether
0xfa2674f7567ce43f3d740f9b35ee27a369fec1acf4a1dfd894751c1073bd7b66111290512022-08-01 23:42:1618 days 20 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0x15f0ca26781c3852f8166ed2ebce5d18265cceb70 Ether
0xfa2674f7567ce43f3d740f9b35ee27a369fec1acf4a1dfd894751c1073bd7b66111290512022-08-01 23:42:1618 days 20 mins ago 0x1166363d3005f96e6e2d940860bc346414e0cfb9 0x15f0ca26781c3852f8166ed2ebce5d18265cceb70 Ether
0xfa2674f7567ce43f3d740f9b35ee27a369fec1acf4a1dfd894751c1073bd7b66111290512022-08-01 23:42:1618 days 20 mins ago 0x8b0e2c6c6feb348776db4747b8124df1082facfa 0x1166363d3005f96e6e2d940860bc346414e0cfb90 Ether
0x2749e4d02d2a6272a20254b4d08dfe3ab7bd8b9612d769fc5b04cd1304ce7c75111097832022-07-29 15:13:2821 days 8 hrs ago 0x7200ac6cb7c65055a4e9e4b93401b962dd9d33f3 0x1166363d3005f96e6e2d940860bc346414e0cfb90 Ether
0x8717cba2420693bacfa25626fc12bdfb85eadd1b081127a80b8e8b54f62fd6ee111046252022-07-28 17:40:4122 days 6 hrs ago 0x360a0a5faf6f280227fe06f5728b85d110aa1e86 0x1166363d3005f96e6e2d940860bc346414e0cfb90 Ether
0x8717cba2420693bacfa25626fc12bdfb85eadd1b081127a80b8e8b54f62fd6ee111046252022-07-28 17:40:4122 days 6 hrs ago 0x360a0a5faf6f280227fe06f5728b85d110aa1e86 0x1166363d3005f96e6e2d940860bc346414e0cfb90 Ether
0xb1439e0f2047a1f1820b12280f596230a6d4ce8c387f5e5c5512fd56edbf9bdb111036992022-07-28 13:48:2822 days 10 hrs ago 0x7200ac6cb7c65055a4e9e4b93401b962dd9d33f3 0x1166363d3005f96e6e2d940860bc346414e0cfb90 Ether
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
StrollManager

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 19 : StrollManager.sol
//SPDX-License-Identifier: Unlicense
pragma solidity 0.8.13;

import { IConstantFlowAgreementV1 } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/agreements/IConstantFlowAgreementV1.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./interfaces/IERC20Mod.sol";
import "./interfaces/IStrollManager.sol";


// solhint-disable not-rely-on-time
/// @title StrollManager
/// @author Harsh Prakash <[email protected]>
/// @notice StrollManager is a contract that manages top ups for the Stroll protocol.
contract StrollManager is IStrollManager, Ownable {
    IConstantFlowAgreementV1 public immutable CFA_V1;

    /// @dev IStrollManager.minLower implementation.
    uint64 public override minLower;

    /// @dev IStrollManager.minUpper implementation.
    uint64 public override minUpper;

    /// @dev IStrollManager.approvedStrategies implementation.
    mapping(address => bool) public override approvedStrategies;

    mapping(bytes32 => TopUp) private topUps; //id = sha3(user, superToken, liquidityToken)

    constructor(
        address _icfa,
        uint64 _minLower,
        uint64 _minUpper
    ) {
        if (_icfa == address(0)) revert ZeroAddress();
        if (_minLower >= _minUpper) revert WrongLimits(_minLower, _minUpper);

        CFA_V1 = IConstantFlowAgreementV1(_icfa);
        minLower = _minLower;
        minUpper = _minUpper;
    }

    /// @dev IStrollManager.createTopUp implementation.
    function createTopUp(
        address _superToken,
        address _strategy,
        address _liquidityToken,
        uint64 _expiry,
        uint64 _lowerLimit,
        uint64 _upperLimit
    ) external override {
        if (_expiry <= block.timestamp)
            revert InvalidExpirationTime(_expiry, block.timestamp);

        if (_lowerLimit < minLower)
            revert InsufficientLimits(_lowerLimit, minLower);

        if (_upperLimit < minUpper)
            revert InsufficientLimits(_upperLimit, minUpper);

        bytes32 index = getTopUpIndex(msg.sender, _superToken, _liquidityToken);

        // If index owner/user is address(0), we are creating a new top-up.
        if (topUps[index].user != msg.sender) {
            if (
                _superToken == address(0) ||
                _strategy == address(0) ||
                _liquidityToken == address(0)
            ) revert ZeroAddress();

            if (!approvedStrategies[_strategy])
                revert InvalidStrategy(_strategy);
            if (
                !IStrategy(_strategy).isSupportedSuperToken(
                    ISuperToken(_superToken)
                )
            ) revert UnsupportedSuperToken(address(_superToken));

            TopUp memory topUp = TopUp( // create new TopUp or update topup
                msg.sender,
                ISuperToken(_superToken),
                IStrategy(_strategy),
                _liquidityToken,
                _expiry,
                _lowerLimit,
                _upperLimit
            );

            topUps[index] = topUp;
        } else {
            // Else just update the limits and expiry, save gas.

            topUps[index].expiry = _expiry;
            topUps[index].lowerLimit = _lowerLimit;
            topUps[index].upperLimit = _upperLimit;
        }

        emit TopUpCreated(
            index,
            msg.sender,
            _superToken,
            _strategy,
            _liquidityToken,
            _expiry,
            _lowerLimit,
            _upperLimit
        );
    }

    /// @dev IStrollManager.performTopUp implementation.
    function performTopUp(
        address _user,
        address _superToken,
        address _liquidityToken
    ) external override {
        performTopUpByIndex(getTopUpIndex(_user, _superToken, _liquidityToken));
    }

    /// @dev IStrollManager.deleteTopUp implementation.
    function deleteTopUp(
        address _user,
        address _superToken,
        address _liquidityToken
    ) external override {
        deleteTopUpByIndex(getTopUpIndex(_user, _superToken, _liquidityToken));
    }

    /// @dev IStrollManager.deleteBatch implementation.
    function deleteBatch(bytes32[] calldata _indices) external override {
        // delete multiple top ups
        uint256 length = _indices.length;
        for (uint256 i; i < length; ++i) {
            deleteTopUpByIndex(_indices[i]);
        }
    }

    /// @dev IStrollManager.addApprovedStrategy implementation.
    function addApprovedStrategy(address _strategy)
        external
        override
        onlyOwner
    {
        if (_strategy == address(0)) revert InvalidStrategy(_strategy);
        if (!approvedStrategies[_strategy]) {
            approvedStrategies[_strategy] = true;
            emit AddedApprovedStrategy(_strategy);
        }
    }

    /// @dev IStrollManager.removeApprovedStrategy implementation.
    function removeApprovedStrategy(address _strategy) external onlyOwner {
        if (approvedStrategies[_strategy]) {
            delete approvedStrategies[_strategy];
            emit RemovedApprovedStrategy(_strategy);
        }
    }

    /// @dev IStrollManager.setLimits implementation.
    function setLimits(uint64 _lowerLimit, uint64 _upperLimit)
        external
        onlyOwner
    {
        if (_lowerLimit >= _upperLimit)
            revert WrongLimits(_lowerLimit, _upperLimit);

        minLower = _lowerLimit;
        minUpper = _upperLimit;

        emit LimitsChanged(_lowerLimit, _upperLimit);
    }

    /// @dev IStrollManager.getTopUp implementation.
    function getTopUp(
        address _user,
        address _superToken,
        address _liquidityToken
    ) external view returns (TopUp memory) {
        return
            getTopUpByIndex(getTopUpIndex(_user, _superToken, _liquidityToken));
    }

    /// @dev IStrollManager.checkTopUp implementation.
    function checkTopUp(
        address _user,
        address _superToken,
        address _liquidityToken
    ) external view override returns (uint256) {
        return
            checkTopUpByIndex(
                getTopUpIndex(_user, _superToken, _liquidityToken)
            );
    }

    /// @dev IStrollManager.performTopUpByIndex implementation.
    function performTopUpByIndex(bytes32 _index) public {
        uint256 topUpAmount = checkTopUpByIndex(_index);

        if (topUpAmount == 0) revert TopUpNotRequired(_index);

        TopUp storage topUp = topUps[_index];

        ISuperToken superToken = topUp.superToken;
        IStrategy strategy = topUp.strategy;

        if (!strategy.isSupportedSuperToken(superToken))
            revert UnsupportedSuperToken(address(superToken));

        strategy.topUp(topUp.user, superToken, topUpAmount);
        emit PerformedTopUp(_index, topUpAmount);
    }

    /// @dev IStrollManager.deleteTopUpByIndex implementation.
    function deleteTopUpByIndex(bytes32 _index) public {
        TopUp storage topUp = topUps[_index];

        address user = topUp.user;

        if (user != msg.sender && topUp.expiry >= block.timestamp)
            revert UnauthorizedCaller(msg.sender, user);

        emit TopUpDeleted(
            _index,
            topUp.user,
            address(topUp.superToken),
            address(topUp.strategy),
            topUp.liquidityToken
        );

        delete topUps[_index];
    }

    /// @dev IStrollManager.getTopUpByIndex implementation.
    function getTopUpByIndex(bytes32 _index)
        public
        view
        returns (TopUp memory)
    {
        return topUps[_index];
    }

    /// @dev IStrollManager.checkTopUpByIndex implementation.
    function checkTopUpByIndex(bytes32 _index)
        public
        view
        returns (uint256 _amount)
    {
        TopUp storage topUp = topUps[_index];

        if (
            topUp.user == address(0) || // Task exists and has a valid user
            topUp.expiry <= block.timestamp || // Task exists and current time is before task end time
            IERC20Mod(topUp.liquidityToken).allowance(
                topUp.user,
                address(topUp.strategy) // contract is allowed to spend
            ) ==
            0 ||
            IERC20Mod(topUp.liquidityToken).balanceOf(topUp.user) == 0 || // check user balance
            !IStrategy(topUp.strategy).isSupportedSuperToken(topUp.superToken) // Supertoken isn't supported anymore.
        ) return 0;

        int96 flowRate = CFA_V1.getNetFlow(topUp.superToken, topUp.user);

        if (flowRate < 0) {
            uint256 superBalance = topUp.superToken.balanceOf(topUp.user);
            uint256 positiveFlowRate = uint256(uint96(-1 * flowRate));

            // Selecting max between user defined limits and global limits.
            uint64 maxLowerLimit = (topUp.lowerLimit < minLower)? minLower: topUp.lowerLimit;
            uint64 maxUpperLimit = (topUp.upperLimit < minUpper)? minUpper: topUp.upperLimit;

            if (superBalance <= (positiveFlowRate * maxLowerLimit)) {
                return positiveFlowRate * maxUpperLimit;
            }
        }

        return 0;
    }

    /// @dev IStrollManager.getTopUpIndex implementation.
    function getTopUpIndex(
        address _user,
        address _superToken,
        address _liquidityToken
    ) public pure returns (bytes32) {
        return keccak256(abi.encode(_user, _superToken, _liquidityToken));
    }
}

File 2 of 19 : IConstantFlowAgreementV1.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.7.0;

import { ISuperAgreement } from "../superfluid/ISuperAgreement.sol";
import { ISuperfluidToken } from "../superfluid/ISuperfluidToken.sol";


/**
 * @dev Superfluid's constant flow agreement interface
 *
 * @author Superfluid
 */
abstract contract IConstantFlowAgreementV1 is ISuperAgreement {

    /// @dev ISuperAgreement.agreementType implementation
    function agreementType() external override pure returns (bytes32) {
        return keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1");
    }

    /**
     * @dev Get the maximum flow rate allowed with the deposit
     * @param deposit Deposit amount used for creating the flow
     */
    function getMaximumFlowRateFromDeposit(
        ISuperfluidToken token,
        uint256 deposit)
        external view virtual
        returns (int96 flowRate);

    /**
     * @dev Get the deposit required for creating the flow
     * @param flowRate Flow rate to be tested
     * 
     * NOTE: 
     * - if calculated deposit (flowRate * liquidationPeriod) is less
     *   than the minimum deposit, we use the minimum deposit otherwise
     *   we use the calculated deposit
     */
    function getDepositRequiredForFlowRate(
        ISuperfluidToken token,
        int96 flowRate)
        external view virtual
        returns (uint256 deposit);

    /**
     * @dev Create a flow betwen sender and receiver.
     * @param token Super token address.
     * @param receiver Flow receiver address.
     * @param flowRate New flow rate in amount per second.
     *
     * # App callbacks
     *
     * - AgreementCreated
     *   - agreementId - can be used in getFlowByID
     *   - agreementData - abi.encode(address flowSender, address flowReceiver)
     *
     * NOTE:
     * - A deposit is taken as safety margin for the solvency agents.
     * - A extra gas fee may be taken to pay for solvency agent liquidations.
     */
    function createFlow(
        ISuperfluidToken token,
        address receiver,
        int96 flowRate,
        bytes calldata ctx
    )
        external virtual
        returns(bytes memory newCtx);

    /**
     * @dev Update the flow rate between sender and receiver.
     * @param token Super token address.
     * @param receiver Flow receiver address.
     * @param flowRate New flow rate in amount per second.
     *
     * # App callbacks
     *
     * - AgreementUpdated
     *   - agreementId - can be used in getFlowByID
     *   - agreementData - abi.encode(address flowSender, address flowReceiver)
     *
     * NOTE:
     * - Only the flow sender may update the flow rate.
     * - Even if the flow rate is zero, the flow is not deleted
     * from the system.
     * - Deposit amount will be adjusted accordingly.
     * - No new gas fee is charged.
     */
    function updateFlow(
        ISuperfluidToken token,
        address receiver,
        int96 flowRate,
        bytes calldata ctx
    )
        external virtual
        returns(bytes memory newCtx);


    /**
     * @dev Get the flow data between `sender` and `receiver`.
     * @param token Super token address.
     * @param sender Flow receiver.
     * @param receiver Flow sender.
     * @return timestamp Timestamp of when the flow is updated.
     * @return flowRate The flow rate.
     * @return deposit The amount of deposit the flow.
     * @return owedDeposit The amount of owed deposit of the flow.
     */
    function getFlow(
        ISuperfluidToken token,
        address sender,
        address receiver
    )
        external view virtual
        returns (
            uint256 timestamp,
            int96 flowRate,
            uint256 deposit,
            uint256 owedDeposit
        );

    /**
     * @dev Get flow data using agreement ID
     * @param token Super token address.
     * @param agreementId The agreement ID.
     * @return timestamp Timestamp of when the flow is updated.
     * @return flowRate The flow rate.
     * @return deposit The amount of deposit the flow.
     * @return owedDeposit The amount of owed deposit of the flow.
     */
    function getFlowByID(
       ISuperfluidToken token,
       bytes32 agreementId
    )
        external view virtual
        returns (
            uint256 timestamp,
            int96 flowRate,
            uint256 deposit,
            uint256 owedDeposit
        );

    /**
     * @dev Get the aggregated flow info of the account
     * @param token Super token address.
    * @param account Account for the query.
    */
    function getAccountFlowInfo(
        ISuperfluidToken token,
        address account
    )
        external view virtual
        returns (
            uint256 timestamp,
            int96 flowRate,
            uint256 deposit,
            uint256 owedDeposit);

    /**
     * @dev Get the net flow rate of the account
     * @param token Super token address.
     * @param account Account for the query.
     * @return flowRate Flow rate.
     */
    function getNetFlow(
        ISuperfluidToken token,
        address account
    )
        external view virtual
        returns (int96 flowRate);

    /**
     * @dev Delete the flow between sender and receiver
     * @param token Super token address.
     * @param ctx Context bytes.
     * @param receiver Flow receiver address.
     *
     * # App callbacks
     *
     * - AgreementTerminated
     *   - agreementId - can be used in getFlowByID
     *   - agreementData - abi.encode(address flowSender, address flowReceiver)
     *
     * NOTE:
     * - Both flow sender and receiver may delete the flow.
     * - If Sender account is insolvent or in critical state, a solvency agent may
     *   also terminate the agreement.
     * - Gas fee may be returned to the sender.
     */
    function deleteFlow(
        ISuperfluidToken token,
        address sender,
        address receiver,
        bytes calldata ctx
    )
        external virtual
        returns(bytes memory newCtx);

     /**
      * @dev Flow updated event.
      * @param token Super token address.
      * @param sender Flow sender address.
      * @param receiver Flow recipient address.
      * @param flowRate Flow rate in amount per second for this flow.
      * @param flowRate Total flow rate in amount per second for the sender.
      * @param flowRate Total flow rate in amount per second for the receiver.
      * @param userData The user provided data.
      */
     event FlowUpdated(
         ISuperfluidToken indexed token,
         address indexed sender,
         address indexed receiver,
         int96 flowRate,
         int256 totalSenderFlowRate,
         int256 totalReceiverFlowRate,
         bytes userData
     );

}

File 3 of 19 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 4 of 19 : IERC20Mod.sol
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.8.13;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IERC20Mod is IERC20 {
    function decimals() external view returns (uint8);
}

File 5 of 19 : IStrollManager.sol
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.13;

import { ISuperToken } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol";
import "../interfaces/IStrategy.sol";

interface IStrollManager {
    event TopUpCreated(
        bytes32 indexed id,
        address indexed user,
        address indexed superToken,
        address strategy,
        address liquidityToken,
        uint256 expiry,
        uint256 lowerLimit,
        uint256 upperLimit
    );
    event TopUpDeleted(
        bytes32 indexed id,
        address indexed user,
        address indexed superToken,
        address strategy,
        address liquidityToken
    );
    event PerformedTopUp(bytes32 indexed id, uint256 topUpAmount);
    event AddedApprovedStrategy(address indexed strategy);
    event RemovedApprovedStrategy(address indexed strategy);
    event LimitsChanged(uint64 lowerLimit, uint64 upperLimit);

    /// Custom error to indicate that null address has been passed.
    error ZeroAddress();

    /// Custom error to indicate addition/usage of invalid strategy.
    /// @param strategy Address of the strategy contract.
    error InvalidStrategy(address strategy);

    /// Custom error to indicate top up is not required and the index id associated with that top-up.
    /// @param index Index id associated with the top up request.
    error TopUpNotRequired(bytes32 index);

    /// Custom error to indicate that supertoken provided isn't supported.
    /// @param superToken Address of the supertoken which isn't supported.
    error UnsupportedSuperToken(address superToken);

    /// Custom error to indicate caller of a function is unauthorized.
    /// @param caller Address of the caller of the function.
    /// @param expectedCaller Address of the expected caller.
    error UnauthorizedCaller(address caller, address expectedCaller);

    /// Custom error to indicate expiration time given is invalid.
    /// @param expirationTimeGiven Time given as expiration time by a user.
    /// @param timeNow Current time (block.timestamp).
    error InvalidExpirationTime(uint64 expirationTimeGiven, uint256 timeNow);

    /// Custom error to indicate the limits given by a user are insufficient.
    /// @param limitGiven Limit (upper/lower) given by the user.
    /// @param minLimit Minimum limit (upper/lower) expected.
    error InsufficientLimits(uint64 limitGiven, uint64 minLimit);

    /// Custom error to indicate that the limits are wrong (lower limit >= upper limit).
    /// @param lowerLimit Limit (upper/lower) given by the user.
    /// @param upperLimit Minimum limit (upper/lower) expected.
    error WrongLimits(uint64 lowerLimit, uint64 upperLimit);

    /**
     * @notice Struct representing a top-up.
     * @param user Address of the user who created the top-up.
     * @param superToken Supertoken which needs to be topped up for the user.
     * @param strategy Address of the strategy contract to be used for top-up.
     * @param liquidityToken Address of the token to be liquidated/used for conversion to supertoken and topping-up.
     * @param expiry Expiration time of the top-up request.
     * @param lowerLimit Minimum time necessary in order to trigger a top-up.
     * @param upperLimit Determines the amount of supertokens required in terms of time (ex: 1 week's worth, 2 days worth etc).
     */
    struct TopUp {
        address user;
        ISuperToken superToken;
        IStrategy strategy;
        address liquidityToken;
        uint64 expiry;
        uint64 lowerLimit;
        uint64 upperLimit;
    }

    /**
     * @notice Adds a strategy to the list of approved strategies.
     * @param _strategy The address of strategy contract to add.
     */
    function addApprovedStrategy(address _strategy) external;

    /**
     * @notice Removes a strategy from the list of approved strategies.
     * @param _strategy The address of strategy contract to remove.
     */
    function removeApprovedStrategy(address _strategy) external;

    /**
     * @notice Sets the global limits for top-ups.
     * @param _lowerLimit Triggers top up if stream can't be continued for this amount of seconds.
     * @param _upperLimit Increase supertoken balance to continue stream for this amount of seconds.
     * @dev If the previous top-ups don't adhere to the current global limits, the global limits will be enforced.
     * i.e., max(global limit, user defined limit) is always taken.
     */
    function setLimits(uint64 _lowerLimit, uint64 _upperLimit) external;

    /**
     *  @notice Creates a new top up task.
     *  @param _superToken The supertoken to monitor/top up.
     *  @param _strategy The strategy to use for top up.
     *  @param _liquidityToken The token used to convert to _superToken.
     *  @param _expiry Timestamp after which the top up is considered invalid.
     *  @param _lowerLimit Triggers top up if stream can't be continued for this amount of seconds.
     *  @param _upperLimit Increase supertoken balance to continue stream for this amount of seconds.
     */
    function createTopUp(
        address _superToken,
        address _strategy,
        address _liquidityToken,
        uint64 _expiry,
        uint64 _lowerLimit,
        uint64 _upperLimit
    ) external;

    /**
     * @notice Gets the index of a top up.
     * @param _user The creator of top up.
     * @param _superToken The supertoken which is being monitored/top up.
     * @param _liquidityToken The token used to convert to _superToken.
     * @return The index of the top up.
     */
    function getTopUpIndex(
        address _user,
        address _superToken,
        address _liquidityToken
    ) external pure returns (bytes32);

    /**
     * @notice Gets a top up by index.
     * @param _index Index of top up.
     * @return The top up.
     */
    function getTopUpByIndex(bytes32 _index)
        external
        view
        returns (TopUp memory);

    /**
     * @notice Gets a top up by index.
     * @param _user The creator of top up.
     * @param _superToken The supertoken which is being monitored/top up.
     * @param _liquidityToken The token used to convert to _superToken.
     * @return The top up.
     */
    function getTopUp(
        address _user,
        address _superToken,
        address _liquidityToken
    ) external view returns (TopUp memory);

    /**
     * @notice Checks if a top up is required by index.
     * @param _index Index of top up.
     * @return _amount The amount of supertoken to top up.
     */
    function checkTopUpByIndex(bytes32 _index)
        external
        view
        returns (uint256 _amount);

    /**
     * @notice Checks if a top up is required.
     * @param _user The creator of top up.
     * @param _superToken The supertoken which is being monitored/top up.
     * @param _liquidityToken The token used to convert to _superToken.
     * @return _amount The amount of supertoken to top up.
     */
    function checkTopUp(
        address _user,
        address _superToken,
        address _liquidityToken
    ) external view returns (uint256);

    /**
     * @notice Performs a top up by index.
     * @param _index Index of top up.
     */
    function performTopUpByIndex(bytes32 _index) external;

    /**
     * @notice Performs a top up.
     * @param _user The user to top up.
     * @param _superToken The supertoken to monitor/top up.
     * @param _liquidityToken The token used to convert to _superToken.
     */
    function performTopUp(
        address _user,
        address _superToken,
        address _liquidityToken
    ) external;

    /**
     * @notice Deletes a top up by index.
     * @param _index Index of top up.
     */
    function deleteTopUpByIndex(bytes32 _index) external;

    /** @dev IStrollManager.deleteTopUp implementation.
     * @notice Deletes a top up.
     * @param _user The creator of top up.
     * @param _superToken The supertoken which is being monitored/top up.
     * @param _liquidityToken The token used to convert to _superToken.
     */
    function deleteTopUp(
        address _user,
        address _superToken,
        address _liquidityToken
    ) external;

    /**  @dev IStrollManager.deleteBatch implementation.
     * @notice Deletes a batch of top ups.
     * @param _indices Array of indices of top ups to delete.
     */
    function deleteBatch(bytes32[] calldata _indices) external;

    /**
     * @notice Gets the minimum time for _lowerLimit
     */
    function minLower() external view returns (uint64);

    /**
     * @notice Gets the minimum time for _upperLimit
     */
    function minUpper() external view returns (uint64);

    /**
     * @notice Gets the list of approved strategies.
     */
    function approvedStrategies(address _strategy) external view returns (bool);
}

File 6 of 19 : ISuperAgreement.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.7.0;

import { ISuperfluidToken } from "./ISuperfluidToken.sol";

/**
 * @title Superfluid's agreement interface.
 *
 * @author Superfluid
 */
interface ISuperAgreement {

    /**
     * @dev Initialize the agreement contract
     */
    function initialize() external;

    /**
     * @dev Get the type of the agreement class.
     */
    function agreementType() external view returns (bytes32);

    /**
     * @dev Calculate the real-time balance for the account of this agreement class.
     * @param account Account the state belongs to
     * @param time Future time used for the calculation.
     * @return dynamicBalance Dynamic balance portion of real-time balance of this agreement.
     * @return deposit Account deposit amount of this agreement.
     * @return owedDeposit Account owed deposit amount of this agreement.
     */
    function realtimeBalanceOf(
        ISuperfluidToken token,
        address account,
        uint256 time
    )
        external
        view
        returns (
            int256 dynamicBalance,
            uint256 deposit,
            uint256 owedDeposit
        );

}

File 7 of 19 : ISuperfluidToken.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.7.0;

import { ISuperAgreement } from "./ISuperAgreement.sol";


/**
 * @title Superfluid's token interface.
 *
 * @author Superfluid
 */
interface ISuperfluidToken {

    /**************************************************************************
     * Basic information
     *************************************************************************/

    /**
     * @dev Get superfluid host contract address
     */
    function getHost() external view returns(address host);

    /**
     * @dev Encoded liquidation type data mainly used for handling stack to deep errors
     * 
     * Note:
     * - version: 1 
     * - liquidationType key:
     *    - 0 = reward account receives reward (PIC period)
     *    - 1 = liquidator account receives reward (Pleb period)
     *    - 2 = liquidator account receives reward (Pirate period/bailout)
     */
    struct LiquidationTypeData {
        uint256 version;
        uint8 liquidationType;
    }

    /**************************************************************************
     * Real-time balance functions
     *************************************************************************/

    /**
    * @dev Calculate the real balance of a user, taking in consideration all agreements of the account
    * @param account for the query
    * @param timestamp Time of balance
    * @return availableBalance Real-time balance
    * @return deposit Account deposit
    * @return owedDeposit Account owed Deposit
    */
    function realtimeBalanceOf(
       address account,
       uint256 timestamp
    )
        external view
        returns (
            int256 availableBalance,
            uint256 deposit,
            uint256 owedDeposit);

    /// @dev realtimeBalanceOf with timestamp equals to block timestamp
    function realtimeBalanceOfNow(
       address account
    )
        external view
        returns (
            int256 availableBalance,
            uint256 deposit,
            uint256 owedDeposit,
            uint256 timestamp);

    /**
    * @dev Check if one account is critical
    * @param account Account check if is critical by a future time
    * @param timestamp Time of balance
    * @return isCritical
    */
    function isAccountCritical(
        address account,
        uint256 timestamp
    )
        external view
        returns(bool isCritical);

    /**
    * @dev Check if one account is critical now
    * @param account Account check if is critical by a future time
    * @return isCritical
    */
    function isAccountCriticalNow(
        address account
    )
        external view
        returns(bool isCritical);

    /**
     * @dev Check if one account is solvent
     * @param account Account check if is solvent by a future time
     * @param timestamp Time of balance
     * @return isSolvent
     */
    function isAccountSolvent(
        address account,
        uint256 timestamp
    )
        external view
        returns(bool isSolvent);

    /**
     * @dev Check if one account is solvent now
     * @param account Account check if is solvent now
     * @return isSolvent
     */
    function isAccountSolventNow(
        address account
    )
        external view
        returns(bool isSolvent);

    /**
    * @dev Get a list of agreements that is active for the account
    * @dev An active agreement is one that has state for the account
    * @param account Account to query
    * @return activeAgreements List of accounts that have non-zero states for the account
    */
    function getAccountActiveAgreements(address account)
       external view
       returns(ISuperAgreement[] memory activeAgreements);


   /**************************************************************************
    * Super Agreement hosting functions
    *************************************************************************/

    /**
     * @dev Create a new agreement
     * @param id Agreement ID
     * @param data Agreement data
     */
    function createAgreement(
        bytes32 id,
        bytes32[] calldata data
    )
        external;

    /**
     * @dev Agreement creation event
     * @param agreementClass Contract address of the agreement
     * @param id Agreement ID
     * @param data Agreement data
     */
    event AgreementCreated(
        address indexed agreementClass,
        bytes32 id,
        bytes32[] data
    );

    /**
     * @dev Get data of the agreement
     * @param agreementClass Contract address of the agreement
     * @param id Agreement ID
     * @return data Data of the agreement
     */
    function getAgreementData(
        address agreementClass,
        bytes32 id,
        uint dataLength
    )
        external view
        returns(bytes32[] memory data);

    /**
     * @dev Create a new agreement
     * @param id Agreement ID
     * @param data Agreement data
     */
    function updateAgreementData(
        bytes32 id,
        bytes32[] calldata data
    )
        external;

    /**
     * @dev Agreement creation event
     * @param agreementClass Contract address of the agreement
     * @param id Agreement ID
     * @param data Agreement data
     */
    event AgreementUpdated(
        address indexed agreementClass,
        bytes32 id,
        bytes32[] data
    );

    /**
     * @dev Close the agreement
     * @param id Agreement ID
     */
    function terminateAgreement(
        bytes32 id,
        uint dataLength
    )
        external;

    /**
     * @dev Agreement termination event
     * @param agreementClass Contract address of the agreement
     * @param id Agreement ID
     */
    event AgreementTerminated(
        address indexed agreementClass,
        bytes32 id
    );

    /**
     * @dev Update agreement state slot
     * @param account Account to be updated
     *
     * NOTE
     * - To clear the storage out, provide zero-ed array of intended length
     */
    function updateAgreementStateSlot(
        address account,
        uint256 slotId,
        bytes32[] calldata slotData
    )
        external;

    /**
     * @dev Agreement account state updated event
     * @param agreementClass Contract address of the agreement
     * @param account Account updated
     * @param slotId slot id of the agreement state
     */
    event AgreementStateUpdated(
        address indexed agreementClass,
        address indexed account,
        uint256 slotId
    );

    /**
     * @dev Get data of the slot of the state of a agreement
     * @param agreementClass Contract address of the agreement
     * @param account Account to query
     * @param slotId slot id of the state
     * @param dataLength length of the state data
     */
    function getAgreementStateSlot(
        address agreementClass,
        address account,
        uint256 slotId,
        uint dataLength
    )
        external view
        returns (bytes32[] memory slotData);

    /**
     * @dev Settle balance from an account by the agreement.
     *      The agreement needs to make sure that the balance delta is balanced afterwards
     * @param account Account to query.
     * @param delta Amount of balance delta to be settled
     *
     * Modifiers:
     *  - onlyAgreement
     */
    function settleBalance(
        address account,
        int256 delta
    )
        external;

    /**
     * @dev Agreement liquidation event (DEPRECATED BY AgreementLiquidatedBy)
     * @param agreementClass Contract address of the agreement
     * @param id Agreement ID
     * @param penaltyAccount Account of the agreement to be penalized
     * @param rewardAccount Account that collect the reward
     * @param rewardAmount Amount of liquidation reward
     */
    event AgreementLiquidated(
        address indexed agreementClass,
        bytes32 id,
        address indexed penaltyAccount,
        address indexed rewardAccount,
        uint256 rewardAmount
    );

    /**
     * @dev System bailout occurred (DEPRECATIED BY AgreementLiquidatedBy)
     * @param bailoutAccount Account that bailout the penalty account
     * @param bailoutAmount Amount of account bailout
     */
    event Bailout(
        address indexed bailoutAccount,
        uint256 bailoutAmount
    );

    /**
     * @dev Agreement liquidation event (including agent account)
     * @param agreementClass Contract address of the agreement
     * @param id Agreement ID
     * @param liquidatorAccount Account of the agent that performed the liquidation.
     * @param penaltyAccount Account of the agreement to be penalized
     * @param bondAccount Account that collect the reward or bailout accounts
     * @param rewardAmount Amount of liquidation reward
     * @param bailoutAmount Amount of liquidation bailouot
     *
     * NOTE:
     * Reward account rule:
     * - if bailout is equal to 0, then
     *   - the bondAccount will get the rewardAmount,
     *   - the penaltyAccount will pay for the rewardAmount.
     * - if bailout is larger than 0, then
     *   - the liquidatorAccount will get the rewardAmouont,
     *   - the bondAccount will pay for both the rewardAmount and bailoutAmount,
     *   - the penaltyAccount will pay for the rewardAmount while get the bailoutAmount.
     */
    event AgreementLiquidatedBy(
        address liquidatorAccount,
        address indexed agreementClass,
        bytes32 id,
        address indexed penaltyAccount,
        address indexed bondAccount,
        uint256 rewardAmount,
        uint256 bailoutAmount
    );

    /**
     * @dev Make liquidation payouts
     * @param id Agreement ID
     * @param liquidator Address of the executer of liquidation
     * @param penaltyAccount Account of the agreement to be penalized
     * @param rewardAmount Amount of liquidation reward
     * @param bailoutAmount Amount of account bailout needed
     *
     * NOTE:
     * Liquidation rules:
     *  - If a bailout is required (bailoutAmount > 0)
     *     - the actual reward goes to the liquidator,
     *     - while the reward account becomes the bailout account
     *     - total bailout include: bailout amount + reward amount
     *
     * Modifiers:
     *  - onlyAgreement
     */
    function makeLiquidationPayouts
    (
        bytes32 id,
        address liquidator,
        address penaltyAccount,
        uint256 rewardAmount,
        uint256 bailoutAmount
    )
        external;

    /**
     * @dev Agreement liquidation event v2 (including agent account)
     * @param agreementClass Contract address of the agreement
     * @param id Agreement ID
     * @param liquidatorAccount Address of the executor of the liquidation
     * @param targetAccount Account of the stream sender
     * @param rewardAccount Account that collects the reward or bails out insolvent accounts
     * @param rewardAmount The amount the reward recipient account balance should change by
     * @param targetAccountBalanceDelta The amount the sender account balance should change by
     * @param liquidationTypeData The encoded liquidation type data including the version (how to decode)
     *
     * NOTE:
     * Reward account rule:
     * - if the agreement is liquidated during the PIC period
     *   - the rewardAccount will get the rewardAmount (remaining deposit), regardless of the liquidatorAccount
     *   - the targetAccount will pay for the rewardAmount
     * - if the agreement is liquidated after the PIC period AND the targetAccount is solvent
     *   - the liquidatorAccount will get the rewardAmount (remaining deposit)
     *   - the targetAccount will pay for the rewardAmount
     * - if the targetAccount is insolvent
     *   - the liquidatorAccount will get the rewardAmount (single deposit)
     *   - the rewardAccount will pay for both the rewardAmount and bailoutAmount
     *   - the targetAccount will receive the bailoutAmount
     */
    event AgreementLiquidatedV2(
        address indexed agreementClass,
        bytes32 id,
        address indexed liquidatorAccount,
        address indexed targetAccount,
        address rewardAccount,
        uint256 rewardAmount,
        int256 targetAccountBalanceDelta,
        bytes liquidationTypeData
    );

    /**
     * @dev Make liquidation payouts (v2)
     * @param id Agreement ID
     * @param liquidationTypeData Data regarding the version of the liquidation schema and the type
     * @param liquidatorAccount Address of the executor of the liquidation
     * @param useDefaultRewardAccount Whether or not the default reward account receives the rewardAmount
     * @param targetAccount Account of the stream sender
     * @param rewardAmount The amount the reward recepient account will receive
     * @param targetAccountBalanceDelta The amount the sender account balance should change by
     *
     * - If a bailout is required (bailoutAmount > 0)
     *   - the actual reward (single deposit) goes to the executor,
     *   - while the reward account becomes the bailout account
     *   - total bailout include: bailout amount + reward amount
     *   - the targetAccount will be bailed out
     * - If a bailout is not required
     *   - the targetAccount will pay the rewardAmount
     *   - the liquidator (reward account in PIC period) will receive the rewardAmount
     *
     * Modifiers:
     *  - onlyAgreement
     */
    function makeLiquidationPayoutsV2
    (
        bytes32 id,
        bytes memory liquidationTypeData,
        address liquidatorAccount,
        bool useDefaultRewardAccount,
        address targetAccount,
        uint256 rewardAmount,
        int256 targetAccountBalanceDelta
    ) external;

    /**************************************************************************
     * Function modifiers for access control and parameter validations
     *
     * While they cannot be explicitly stated in function definitions, they are
     * listed in function definition comments instead for clarity.
     *
     * NOTE: solidity-coverage not supporting it
     *************************************************************************/

     /// @dev The msg.sender must be host contract
     //modifier onlyHost() virtual;

    /// @dev The msg.sender must be a listed agreement.
    //modifier onlyAgreement() virtual;

}

File 8 of 19 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 9 of 19 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 10 of 19 : ISuperfluid.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.7.0;
// This is required by the batchCall and decodeCtx
pragma experimental ABIEncoderV2;

import { ISuperfluidGovernance } from "./ISuperfluidGovernance.sol";
import { ISuperfluidToken } from "./ISuperfluidToken.sol";
import { ISuperToken } from "./ISuperToken.sol";
import { ISuperTokenFactory } from "./ISuperTokenFactory.sol";
import { ISuperAgreement } from "./ISuperAgreement.sol";
import { ISuperApp } from "./ISuperApp.sol";
import {
    SuperAppDefinitions,
    ContextDefinitions,
    BatchOperation,
    SuperfluidGovernanceConfigs
} from "./Definitions.sol";
import { TokenInfo } from "../tokens/TokenInfo.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC777 } from "@openzeppelin/contracts/token/ERC777/IERC777.sol";


/**
 * @dev Superfluid host interface.

 * It is the central contract of the system where super agreement, super app
 * and super token features are connected together.
 *
 * The superfluid host contract is also the entry point for the protocol users,
 * where batch call and meta transaction are provided for UX improvements.
 *
 * @author Superfluid
 */
interface ISuperfluid {

    /**************************************************************************
     * Governance
     *************************************************************************/

    /**
     * @dev Get the current governace of the Superfluid host
     */
    function getGovernance() external view returns(ISuperfluidGovernance governance);

    event GovernanceReplaced(ISuperfluidGovernance oldGov, ISuperfluidGovernance newGov);
    /**
     * @dev Replace the current governance with a new one
     */
    function replaceGovernance(ISuperfluidGovernance newGov) external;

    /**************************************************************************
     * Agreement Whitelisting
     *************************************************************************/

    event AgreementClassRegistered(bytes32 agreementType, address code);
    /**
     * @dev Register a new agreement class to the system
     * @param agreementClassLogic INitial agreement class code
     *
     * Modifiers:
     *  - onlyGovernance
     */
    function registerAgreementClass(ISuperAgreement agreementClassLogic) external;

    event AgreementClassUpdated(bytes32 agreementType, address code);
    /**
    * @dev Update code of an agreement class
    * @param agreementClassLogic New code for the agreement class
    *
    * Modifiers:
    *  - onlyGovernance
    */
    function updateAgreementClass(ISuperAgreement agreementClassLogic) external;

    /**
    * @dev Check if the agreement class is whitelisted
    */
    function isAgreementTypeListed(bytes32 agreementType) external view returns(bool yes);

    /**
    * @dev Check if the agreement class is whitelisted
    */
    function isAgreementClassListed(ISuperAgreement agreementClass) external view returns(bool yes);

    /**
    * @dev Get agreement class
    */
    function getAgreementClass(bytes32 agreementType) external view returns(ISuperAgreement agreementClass);

    /**
    * @dev Map list of the agreement classes using a bitmap
    * @param bitmap Agreement class bitmap
    */
    function mapAgreementClasses(uint256 bitmap)
        external view
        returns (ISuperAgreement[] memory agreementClasses);

    /**
    * @dev Create a new bitmask by adding a agreement class to it.
    * @param bitmap Agreement class bitmap
    */
    function addToAgreementClassesBitmap(uint256 bitmap, bytes32 agreementType)
        external view
        returns (uint256 newBitmap);

    /**
    * @dev Create a new bitmask by removing a agreement class from it.
    * @param bitmap Agreement class bitmap
    */
    function removeFromAgreementClassesBitmap(uint256 bitmap, bytes32 agreementType)
        external view
        returns (uint256 newBitmap);

    /**************************************************************************
    * Super Token Factory
    **************************************************************************/

    /**
     * @dev Get the super token factory
     * @return factory The factory
     */
    function getSuperTokenFactory() external view returns (ISuperTokenFactory factory);

    /**
     * @dev Get the super token factory logic (applicable to upgradable deployment)
     * @return logic The factory logic
     */
    function getSuperTokenFactoryLogic() external view returns (address logic);

    event SuperTokenFactoryUpdated(ISuperTokenFactory newFactory);
    /**
     * @dev Update super token factory
     * @param newFactory New factory logic
     */
    function updateSuperTokenFactory(ISuperTokenFactory newFactory) external;

    event SuperTokenLogicUpdated(ISuperToken indexed token, address code);
    /**
     * @dev Update the super token logic to the latest
     *
     * NOTE:
     * - Refer toISuperTokenFactory.Upgradability for expected behaviours.
     */
    function updateSuperTokenLogic(ISuperToken token) external;

    /**************************************************************************
     * App Registry
     *************************************************************************/

    /**
     * @dev App registered event
     */
    event AppRegistered(ISuperApp indexed app);

    /**
     * @dev Jail event for the app
     */
    event Jail(ISuperApp indexed app, uint256 reason);

    /**
     * @dev Message sender declares it as a super app
     * @param configWord The super app manifest configuration, flags are defined in
     *                   `SuperAppDefinitions`
     */
    function registerApp(uint256 configWord) external;

    /**
     * @dev Message sender declares it as a super app, using a registration key
     * @param configWord The super app manifest configuration, flags are defined in
     *                   `SuperAppDefinitions`
     * @param registrationKey The registration key issued by the governance
     */
    function registerAppWithKey(uint256 configWord, string calldata registrationKey) external;

    /**
     * @dev Message sender declares app as a super app
     * @param configWord The super app manifest configuration, flags are defined in
     *                   `SuperAppDefinitions`
     * NOTE: only factory contracts authorized by governance can register super apps
     */
    function registerAppByFactory(ISuperApp app, uint256 configWord) external;

    /**
     * @dev Query if the app is registered
     * @param app Super app address
     */
    function isApp(ISuperApp app) external view returns(bool);

    /**
     * @dev Query app level
     * @param app Super app address
     */
    function getAppLevel(ISuperApp app) external view returns(uint8 appLevel);

    /**
     * @dev Get the manifest of the super app
     * @param app Super app address
     */
    function getAppManifest(
        ISuperApp app
    )
        external view
        returns (
            bool isSuperApp,
            bool isJailed,
            uint256 noopMask
        );

    /**
     * @dev Query if the app has been jailed
     * @param app Super app address
     */
    function isAppJailed(ISuperApp app) external view returns (bool isJail);

    /**
     * @dev White-list the target app for app composition for the source app (msg.sender)
     * @param targetApp The taget super app address
     */
    function allowCompositeApp(ISuperApp targetApp) external;

    /**
     * @dev Query if source app  is allowed to call the target app as downstream app.
     * @param app Super app address
     * @param targetApp The taget super app address
     */
    function isCompositeAppAllowed(
        ISuperApp app,
        ISuperApp targetApp
    )
        external view
        returns (bool isAppAllowed);

    /**************************************************************************
     * Agreement Framework
     *
     * Agreements use these function to trigger super app callbacks, updates
     * app allowance and charge gas fees.
     *
     * These functions can only be called by registered agreements.
     *************************************************************************/

    function callAppBeforeCallback(
        ISuperApp app,
        bytes calldata callData,
        bool isTermination,
        bytes calldata ctx
    )
        external
        // onlyAgreement
        // isAppActive(app)
        returns(bytes memory cbdata);

    function callAppAfterCallback(
        ISuperApp app,
        bytes calldata callData,
        bool isTermination,
        bytes calldata ctx
    )
        external
        // onlyAgreement
        // isAppActive(app)
        returns(bytes memory appCtx);

    function appCallbackPush(
        bytes calldata ctx,
        ISuperApp app,
        uint256 appAllowanceGranted,
        int256 appAllowanceUsed,
        ISuperfluidToken appAllowanceToken
    )
        external
        // onlyAgreement
        returns (bytes memory appCtx);

    function appCallbackPop(
        bytes calldata ctx,
        int256 appAllowanceUsedDelta
    )
        external
        // onlyAgreement
        returns (bytes memory newCtx);

    function ctxUseAllowance(
        bytes calldata ctx,
        uint256 appAllowanceWantedMore,
        int256 appAllowanceUsedDelta
    )
        external
        // onlyAgreement
        returns (bytes memory newCtx);

    function jailApp(
        bytes calldata ctx,
        ISuperApp app,
        uint256 reason
    )
        external
        // onlyAgreement
        returns (bytes memory newCtx);

    /**************************************************************************
     * Contextless Call Proxies
     *
     * NOTE: For EOAs or non-app contracts, they are the entry points for interacting
     * with agreements or apps.
     *
     * NOTE: The contextual call data should be generated using
     * abi.encodeWithSelector. The context parameter should be set to "0x",
     * an empty bytes array as a placeholder to be replaced by the host
     * contract.
     *************************************************************************/

     /**
      * @dev Call agreement function
      * @param callData The contextual call data with placeholder ctx
      * @param userData Extra user data being sent to the super app callbacks
      */
     function callAgreement(
         ISuperAgreement agreementClass,
         bytes calldata callData,
         bytes calldata userData
     )
        external
        //cleanCtx
        returns(bytes memory returnedData);

    /**
     * @dev Call app action
     * @param callData The contextual call data.
     *
     * NOTE: See callAgreement about contextual call data.
     */
    function callAppAction(
        ISuperApp app,
        bytes calldata callData
    )
        external
        //cleanCtx
        //isAppActive(app)
        returns(bytes memory returnedData);

    /**************************************************************************
     * Contextual Call Proxies and Context Utilities
     *
     * For apps, they must use context they receive to interact with
     * agreements or apps.
     *
     * The context changes must be saved and returned by the apps in their
     * callbacks always, any modification to the context will be detected and
     * the violating app will be jailed.
     *************************************************************************/

    /**
     * @dev ABIv2 Encoded memory data of context
     *
     * NOTE on backward compatibility:
     * - Non-dynamic fields are padded to 32bytes and packed
     * - Dynamic fields are referenced through a 32bytes offset to their "parents" field (or root)
     * - The order of the fields hence should not be rearranged in order to be backward compatible:
     *    - non-dynamic fields will be parsed at the same memory location,
     *    - and dynamic fields will simply have a greater offset than it was.
     */
    struct Context {
        //
        // Call context
        //
        // callback level
        uint8 appLevel;
        // type of call
        uint8 callType;
        // the system timestsamp
        uint256 timestamp;
        // The intended message sender for the call
        address msgSender;

        //
        // Callback context
        //
        // For callbacks it is used to know which agreement function selector is called
        bytes4 agreementSelector;
        // User provided data for app callbacks
        bytes userData;

        //
        // App context
        //
        // app allowance granted
        uint256 appAllowanceGranted;
        // app allowance wanted by the app callback
        uint256 appAllowanceWanted;
        // app allowance used, allowing negative values over a callback session
        int256 appAllowanceUsed;
        // app address
        address appAddress;
        // app allowance in super token
        ISuperfluidToken appAllowanceToken;
    }

    function callAgreementWithContext(
        ISuperAgreement agreementClass,
        bytes calldata callData,
        bytes calldata userData,
        bytes calldata ctx
    )
        external
        // validCtx(ctx)
        // onlyAgreement(agreementClass)
        returns (bytes memory newCtx, bytes memory returnedData);

    function callAppActionWithContext(
        ISuperApp app,
        bytes calldata callData,
        bytes calldata ctx
    )
        external
        // validCtx(ctx)
        // isAppActive(app)
        returns (bytes memory newCtx);

    function decodeCtx(bytes calldata ctx)
        external pure
        returns (Context memory context);

    function isCtxValid(bytes calldata ctx) external view returns (bool);

    /**************************************************************************
    * Batch call
    **************************************************************************/
    /**
     * @dev Batch operation data
     */
    struct Operation {
        // Operation. Defined in BatchOperation (Definitions.sol)
        uint32 operationType;
        // Operation target
        address target;
        // Data specific to the operation
        bytes data;
    }

    /**
     * @dev Batch call function
     * @param operations Array of batch operations.
     */
    function batchCall(Operation[] memory operations) external;

    /**
     * @dev Batch call function for trusted forwarders (EIP-2771)
     * @param operations Array of batch operations.
     */
    function forwardBatchCall(Operation[] memory operations) external;

    /**************************************************************************
     * Function modifiers for access control and parameter validations
     *
     * While they cannot be explicitly stated in function definitions, they are
     * listed in function definition comments instead for clarity.
     *
     * TODO: turning these off because solidity-coverage don't like it
     *************************************************************************/

     /* /// @dev The current superfluid context is clean.
     modifier cleanCtx() virtual;

     /// @dev The superfluid context is valid.
     modifier validCtx(bytes memory ctx) virtual;

     /// @dev The agreement is a listed agreement.
     modifier isAgreement(ISuperAgreement agreementClass) virtual;

     // onlyGovernance

     /// @dev The msg.sender must be a listed agreement.
     modifier onlyAgreement() virtual;

     /// @dev The app is registered and not jailed.
     modifier isAppActive(ISuperApp app) virtual; */
}

File 11 of 19 : IStrategy.sol
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.13;

import { ISuperToken } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol";

interface IStrategy {
    event TopUp(
        address indexed user,
        address indexed superToken,
        uint256 superTokenAmount
    );
    event StrollManagerChanged(
        address indexed oldStrollManager,
        address indexed strollManager
    );
    event EmergencyWithdrawInitiated(
        address indexed receiver,
        address indexed token,
        uint256 amount
    );

    /// Custom error to indicate that null address has been passed.
    error ZeroAddress();

    /// Custom error to indicate that supertoken provided isn't supported.
    /// @param superToken Address of the supertoken which isn't supported.
    error UnsupportedSuperToken(address superToken);

    /// Custom error to indicate that the caller is unauthorized to call a function.
    /// @param caller Address of the caller of the function.
    /// @param expectedCaller Address of the expected caller of the function.
    error UnauthorizedCaller(address caller, address expectedCaller);

    /// Function to get the current StrollManager contract which interacts with the-
    /// strategy contract.
    /// @return StrollManager contract address.
    function strollManager() external returns (address);

    /// Function to top-up an account based on certain conditions pre-defined in the StrollManager contract.
    /// @param _user Address of the user whose account needs to be topped-up.
    /// @param _superToken Supertoken which needs to be replenished.
    /// @param _superTokenAmount Amount of supertoken to be replenished.
    /// @dev This function assumes whatever given by StrollManager is correct. Therefore, all the necessary-
    /// checks such as if a top-up is required and if so how much amount needs to be topped up, do we have-
    /// enough allowance to perform a top-up and so on must be performed in StrollManager only.
    function topUp(
        address _user,
        ISuperToken _superToken,
        uint256 _superTokenAmount
    ) external;

    /// Function to check whether a supertoken is supported by a strategy or not.
    /// @dev More specifically, this function checks whether the underlying token of the supertoken-
    /// is supported or not.
    /// @param _superToken Supertoken which needs to be checked for support.
    /// @return Boolean indicating the support of the supertoken.
    function isSupportedSuperToken(ISuperToken _superToken)
        external
        view
        returns (bool);

    /// Function to change the StrollManager contract that a strategy interacts with.
    /// This function can only be called by the owner of the strategy contract.
    /// @param _newStrollManager Address of the new StrollManager contract the strategy should interact with.
    function changeStrollManager(address _newStrollManager) external;

    /// Function to withdraw any token locked in the contract in case of an emergency.
    /// Ideally, no tokens should ever be sent directly to the contract but in case it happens,
    /// this function can be used by the owner of the strategy contract to transfer all the locked tokens-
    /// to their address.
    /// @param _token Address of the locked token which is to be transferred to the owner address.
    function emergencyWithdraw(address _token) external;
}

File 12 of 19 : ISuperfluidGovernance.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.7.0;

import { ISuperAgreement } from "./ISuperAgreement.sol";
import { ISuperToken } from "./ISuperToken.sol";
import { ISuperfluidToken  } from "./ISuperfluidToken.sol";
import { ISuperfluid } from "./ISuperfluid.sol";


/**
 * @dev Superfluid's Governance interface
 *
 * @author Superfluid
 */
interface ISuperfluidGovernance {

    /**
     * @dev Replace the current governance with a new governance
     */
    function replaceGovernance(
        ISuperfluid host,
        address newGov) external;

    /**
     * @dev Register a new agreement class
     */
    function registerAgreementClass(
        ISuperfluid host,
        address agreementClass) external;

    /**
     * @dev Update logics of the contracts
     *
     * NOTE:
     * - Because they might have inter-dependencies, it is good to have one single function to update them all
     */
    function updateContracts(
        ISuperfluid host,
        address hostNewLogic,
        address[] calldata agreementClassNewLogics,
        address superTokenFactoryNewLogic
    ) external;

    /**
     * @dev Update supertoken logic contract to the latest that is managed by the super token factory
     */
    function batchUpdateSuperTokenLogic(
        ISuperfluid host,
        ISuperToken[] calldata tokens) external;

    /// @dev Get configuration as address value
    function getConfigAsAddress(
        ISuperfluid host,
        ISuperfluidToken superToken,
        bytes32 key) external view returns (address value);

    /// @dev Get configuration as uint256 value
    function getConfigAsUint256(
        ISuperfluid host,
        ISuperfluidToken superToken,
        bytes32 key) external view returns (uint256 value);

}

File 13 of 19 : ISuperToken.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.7.0;

import { ISuperfluid } from "./ISuperfluid.sol";
import { ISuperfluidToken } from "./ISuperfluidToken.sol";
import { TokenInfo } from "../tokens/TokenInfo.sol";
import { IERC777 } from "@openzeppelin/contracts/token/ERC777/IERC777.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title Superfluid's super token (Superfluid Token + ERC20 + ERC777) interface
 *
 * @author Superfluid
 */
interface ISuperToken is ISuperfluidToken, TokenInfo, IERC20, IERC777 {

    /// @dev Initialize the contract
    function initialize(
        IERC20 underlyingToken,
        uint8 underlyingDecimals,
        string calldata n,
        string calldata s
    ) external;

    /**************************************************************************
    * TokenInfo & ERC777
    *************************************************************************/

    /**
     * @dev Returns the name of the token.
     */
    function name() external view override(IERC777, TokenInfo) returns (string memory);

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() external view override(IERC777, TokenInfo) returns (string memory);

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
     * called.
     *
     * NOTE: SuperToken always uses 18 decimals.
     *
     * Note: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() external view override(TokenInfo) returns (uint8);

    /**************************************************************************
    * ERC20 & ERC777
    *************************************************************************/

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() external view override(IERC777, IERC20) returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by an account (`owner`).
     */
    function balanceOf(address account) external view override(IERC777, IERC20) returns(uint256 balance);

    /**************************************************************************
    * ERC20
    *************************************************************************/

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external override(IERC20) returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external override(IERC20) view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external override(IERC20) returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external override(IERC20) returns (bool);

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
     function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);

    /**************************************************************************
    * ERC777
    *************************************************************************/

    /**
     * @dev Returns the smallest part of the token that is not divisible. This
     * means all token operations (creation, movement and destruction) must have
     * amounts that are a multiple of this number.
     *
     * For super token contracts, this value is 1 always
     */
    function granularity() external view override(IERC777) returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * If send or receive hooks are registered for the caller and `recipient`,
     * the corresponding functions will be called with `data` and empty
     * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
     *
     * Emits a {Sent} event.
     *
     * Requirements
     *
     * - the caller must have at least `amount` tokens.
     * - `recipient` cannot be the zero address.
     * - if `recipient` is a contract, it must implement the {IERC777Recipient}
     * interface.
     */
    function send(address recipient, uint256 amount, bytes calldata data) external override(IERC777);

    /**
     * @dev Destroys `amount` tokens from the caller's account, reducing the
     * total supply.
     *
     * If a send hook is registered for the caller, the corresponding function
     * will be called with `data` and empty `operatorData`. See {IERC777Sender}.
     *
     * Emits a {Burned} event.
     *
     * Requirements
     *
     * - the caller must have at least `amount` tokens.
     */
    function burn(uint256 amount, bytes calldata data) external override(IERC777);

    /**
     * @dev Returns true if an account is an operator of `tokenHolder`.
     * Operators can send and burn tokens on behalf of their owners. All
     * accounts are their own operator.
     *
     * See {operatorSend} and {operatorBurn}.
     */
    function isOperatorFor(address operator, address tokenHolder) external override(IERC777) view returns (bool);

    /**
     * @dev Make an account an operator of the caller.
     *
     * See {isOperatorFor}.
     *
     * Emits an {AuthorizedOperator} event.
     *
     * Requirements
     *
     * - `operator` cannot be calling address.
     */
    function authorizeOperator(address operator) external override(IERC777);

    /**
     * @dev Revoke an account's operator status for the caller.
     *
     * See {isOperatorFor} and {defaultOperators}.
     *
     * Emits a {RevokedOperator} event.
     *
     * Requirements
     *
     * - `operator` cannot be calling address.
     */
    function revokeOperator(address operator) external override(IERC777);

    /**
     * @dev Returns the list of default operators. These accounts are operators
     * for all token holders, even if {authorizeOperator} was never called on
     * them.
     *
     * This list is immutable, but individual holders may revoke these via
     * {revokeOperator}, in which case {isOperatorFor} will return false.
     */
    function defaultOperators() external override(IERC777) view returns (address[] memory);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must
     * be an operator of `sender`.
     *
     * If send or receive hooks are registered for `sender` and `recipient`,
     * the corresponding functions will be called with `data` and
     * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
     *
     * Emits a {Sent} event.
     *
     * Requirements
     *
     * - `sender` cannot be the zero address.
     * - `sender` must have at least `amount` tokens.
     * - the caller must be an operator for `sender`.
     * - `recipient` cannot be the zero address.
     * - if `recipient` is a contract, it must implement the {IERC777Recipient}
     * interface.
     */
    function operatorSend(
        address sender,
        address recipient,
        uint256 amount,
        bytes calldata data,
        bytes calldata operatorData
    ) external override(IERC777);

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the total supply.
     * The caller must be an operator of `account`.
     *
     * If a send hook is registered for `account`, the corresponding function
     * will be called with `data` and `operatorData`. See {IERC777Sender}.
     *
     * Emits a {Burned} event.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     * - the caller must be an operator for `account`.
     */
    function operatorBurn(
        address account,
        uint256 amount,
        bytes calldata data,
        bytes calldata operatorData
    ) external override(IERC777);

    /**************************************************************************
     * SuperToken custom token functions
     *************************************************************************/

    /**
     * @dev Mint new tokens for the account
     *
     * Modifiers:
     *  - onlySelf
     */
    function selfMint(
        address account,
        uint256 amount,
        bytes memory userData
    ) external;

   /**
    * @dev Burn existing tokens for the account
    *
    * Modifiers:
    *  - onlySelf
    */
   function selfBurn(
       address account,
       uint256 amount,
       bytes memory userData
   ) external;

    /**************************************************************************
     * SuperToken extra functions
     *************************************************************************/

    /**
     * @dev Transfer all available balance from `msg.sender` to `recipient`
     */
    function transferAll(address recipient) external;

    /**************************************************************************
     * ERC20 wrapping
     *************************************************************************/

    /**
     * @dev Return the underlying token contract
     * @return tokenAddr Underlying token address
     */
    function getUnderlyingToken() external view returns(address tokenAddr);

    /**
     * @dev Upgrade ERC20 to SuperToken.
     * @param amount Number of tokens to be upgraded (in 18 decimals)
     *
     * NOTE: It will use ´transferFrom´ to get tokens. Before calling this
     * function you should ´approve´ this contract
     */
    function upgrade(uint256 amount) external;

    /**
     * @dev Upgrade ERC20 to SuperToken and transfer immediately
     * @param to The account to received upgraded tokens
     * @param amount Number of tokens to be upgraded (in 18 decimals)
     * @param data User data for the TokensRecipient callback
     *
     * NOTE: It will use ´transferFrom´ to get tokens. Before calling this
     * function you should ´approve´ this contract
     */
    function upgradeTo(address to, uint256 amount, bytes calldata data) external;

    /**
     * @dev Token upgrade event
     * @param account Account where tokens are upgraded to
     * @param amount Amount of tokens upgraded (in 18 decimals)
     */
    event TokenUpgraded(
        address indexed account,
        uint256 amount
    );

    /**
     * @dev Downgrade SuperToken to ERC20.
     * @dev It will call transfer to send tokens
     * @param amount Number of tokens to be downgraded
     */
    function downgrade(uint256 amount) external;

    /**
     * @dev Token downgrade event
     * @param account Account whose tokens are upgraded
     * @param amount Amount of tokens downgraded
     */
    event TokenDowngraded(
        address indexed account,
        uint256 amount
    );

    /**************************************************************************
    * Batch Operations
    *************************************************************************/

    /**
    * @dev Perform ERC20 approve by host contract.
    * @param account The account owner to be approved.
    * @param spender The spender of account owner's funds.
    * @param amount Number of tokens to be approved.
    *
    * Modifiers:
    *  - onlyHost
    */
    function operationApprove(
        address account,
        address spender,
        uint256 amount
    ) external;

    /**
    * @dev Perform ERC20 transfer from by host contract.
    * @param account The account to spend sender's funds.
    * @param spender  The account where the funds is sent from.
    * @param recipient The recipient of thefunds.
    * @param amount Number of tokens to be transferred.
    *
    * Modifiers:
    *  - onlyHost
    */
    function operationTransferFrom(
        address account,
        address spender,
        address recipient,
        uint256 amount
    ) external;

    /**
    * @dev Upgrade ERC20 to SuperToken by host contract.
    * @param account The account to be changed.
    * @param amount Number of tokens to be upgraded (in 18 decimals)
    *
    * Modifiers:
    *  - onlyHost
    */
    function operationUpgrade(address account, uint256 amount) external;

    /**
    * @dev Downgrade ERC20 to SuperToken by host contract.
    * @param account The account to be changed.
    * @param amount Number of tokens to be downgraded (in 18 decimals)
    *
    * Modifiers:
    *  - onlyHost
    */
    function operationDowngrade(address account, uint256 amount) external;


    /**************************************************************************
    * Function modifiers for access control and parameter validations
    *
    * While they cannot be explicitly stated in function definitions, they are
    * listed in function definition comments instead for clarity.
    *
    * NOTE: solidity-coverage not supporting it
    *************************************************************************/

    /// @dev The msg.sender must be the contract itself
    //modifier onlySelf() virtual

}

File 14 of 19 : ISuperTokenFactory.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.7.0;

import { ISuperToken } from "./ISuperToken.sol";

import {
    IERC20,
    ERC20WithTokenInfo
} from "../tokens/ERC20WithTokenInfo.sol";


interface ISuperTokenFactory {

    /**
     * @dev Get superfluid host contract address
     */
    function getHost() external view returns(address host);

    /// @dev Initialize the contract
    function initialize() external;

    /**
     * @dev Get the current super token logic used by the factory
     */
    function getSuperTokenLogic() external view returns (ISuperToken superToken);

    /**
     * @dev Upgradability modes
     */
    enum Upgradability {
        /// Non upgradable super token, `host.updateSuperTokenLogic` will revert
        NON_UPGRADABLE,
        /// Upgradable through `host.updateSuperTokenLogic` operation
        SEMI_UPGRADABLE,
        /// Always using the latest super token logic
        FULL_UPGRADABE
    }

    /**
     * @dev Create new super token wrapper for the underlying ERC20 token
     * @param underlyingToken Underlying ERC20 token
     * @param underlyingDecimals Underlying token decimals
     * @param upgradability Upgradability mode
     * @param name Super token name
     * @param symbol Super token symbol
     */
    function createERC20Wrapper(
        IERC20 underlyingToken,
        uint8 underlyingDecimals,
        Upgradability upgradability,
        string calldata name,
        string calldata symbol
    )
        external
        returns (ISuperToken superToken);

    /**
     * @dev Create new super token wrapper for the underlying ERC20 token with extra token info
     * @param underlyingToken Underlying ERC20 token
     * @param upgradability Upgradability mode
     * @param name Super token name
     * @param symbol Super token symbol
     *
     * NOTE:
     * - It assumes token provide the .decimals() function
     */
    function createERC20Wrapper(
        ERC20WithTokenInfo underlyingToken,
        Upgradability upgradability,
        string calldata name,
        string calldata symbol
    )
        external
        returns (ISuperToken superToken);

    function initializeCustomSuperToken(
        address customSuperTokenProxy
    )
        external;

    event SuperTokenLogicCreated(ISuperToken indexed tokenLogic);

    event SuperTokenCreated(ISuperToken indexed token);

    event CustomSuperTokenCreated(ISuperToken indexed token);

}

File 15 of 19 : ISuperApp.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.7.0;

import { ISuperToken } from "./ISuperToken.sol";


/**
 * @title Superfluid's app interface.
 *
 * NOTE:
 * - Be fearful of the app jail, when the word permitted is used.
 *
 * @author Superfluid
 */
interface ISuperApp {

    /**
     * @dev Callback before a new agreement is created.
     * @param superToken The super token used for the agreement.
     * @param agreementClass The agreement class address.
     * @param agreementId The agreementId
     * @param agreementData The agreement data (non-compressed)
     * @param ctx The context data.
     * @return cbdata A free format in memory data the app can use to pass
     *          arbitary information to the after-hook callback.
     *
     * NOTE:
     * - It will be invoked with `staticcall`, no state changes are permitted.
     * - Only revert with a "reason" is permitted.
     */
    function beforeAgreementCreated(
        ISuperToken superToken,
        address agreementClass,
        bytes32 agreementId,
        bytes calldata agreementData,
        bytes calldata ctx
    )
        external
        view
        returns (bytes memory cbdata);

    /**
     * @dev Callback after a new agreement is created.
     * @param superToken The super token used for the agreement.
     * @param agreementClass The agreement class address.
     * @param agreementId The agreementId
     * @param agreementData The agreement data (non-compressed)
     * @param cbdata The data returned from the before-hook callback.
     * @param ctx The context data.
     * @return newCtx The current context of the transaction.
     *
     * NOTE:
     * - State changes is permitted.
     * - Only revert with a "reason" is permitted.
     */
    function afterAgreementCreated(
        ISuperToken superToken,
        address agreementClass,
        bytes32 agreementId,
        bytes calldata agreementData,
        bytes calldata cbdata,
        bytes calldata ctx
    )
        external
        returns (bytes memory newCtx);

    /**
     * @dev Callback before a new agreement is updated.
     * @param superToken The super token used for the agreement.
     * @param agreementClass The agreement class address.
     * @param agreementId The agreementId
     * @param agreementData The agreement data (non-compressed)
     * @param ctx The context data.
     * @return cbdata A free format in memory data the app can use to pass
     *          arbitary information to the after-hook callback.
     *
     * NOTE:
     * - It will be invoked with `staticcall`, no state changes are permitted.
     * - Only revert with a "reason" is permitted.
     */
    function beforeAgreementUpdated(
        ISuperToken superToken,
        address agreementClass,
        bytes32 agreementId,
        bytes calldata agreementData,
        bytes calldata ctx
    )
        external
        view
        returns (bytes memory cbdata);


    /**
    * @dev Callback after a new agreement is updated.
    * @param superToken The super token used for the agreement.
    * @param agreementClass The agreement class address.
    * @param agreementId The agreementId
    * @param agreementData The agreement data (non-compressed)
    * @param cbdata The data returned from the before-hook callback.
    * @param ctx The context data.
    * @return newCtx The current context of the transaction.
    *
    * NOTE:
    * - State changes is permitted.
    * - Only revert with a "reason" is permitted.
    */
    function afterAgreementUpdated(
        ISuperToken superToken,
        address agreementClass,
        bytes32 agreementId,
        bytes calldata agreementData,
        bytes calldata cbdata,
        bytes calldata ctx
    )
        external
        returns (bytes memory newCtx);

    /**
    * @dev Callback before a new agreement is terminated.
    * @param superToken The super token used for the agreement.
    * @param agreementClass The agreement class address.
    * @param agreementId The agreementId
    * @param agreementData The agreement data (non-compressed)
    * @param ctx The context data.
    * @return cbdata A free format in memory data the app can use to pass
    *          arbitary information to the after-hook callback.
    *
    * NOTE:
    * - It will be invoked with `staticcall`, no state changes are permitted.
    * - Revert is not permitted.
    */
    function beforeAgreementTerminated(
        ISuperToken superToken,
        address agreementClass,
        bytes32 agreementId,
        bytes calldata agreementData,
        bytes calldata ctx
    )
        external
        view
        returns (bytes memory cbdata);

    /**
    * @dev Callback after a new agreement is terminated.
    * @param superToken The super token used for the agreement.
    * @param agreementClass The agreement class address.
    * @param agreementId The agreementId
    * @param agreementData The agreement data (non-compressed)
    * @param cbdata The data returned from the before-hook callback.
    * @param ctx The context data.
    * @return newCtx The current context of the transaction.
    *
    * NOTE:
    * - State changes is permitted.
    * - Revert is not permitted.
    */
    function afterAgreementTerminated(
        ISuperToken superToken,
        address agreementClass,
        bytes32 agreementId,
        bytes calldata agreementData,
        bytes calldata cbdata,
        bytes calldata ctx
    )
        external
        returns (bytes memory newCtx);
}

File 16 of 19 : Definitions.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.7.0;

/**
 * @dev Super app definitions library
 */
library SuperAppDefinitions {

    /**************************************************************************
    / App manifest config word
    /**************************************************************************/

    /*
     * App level is a way to allow the app to whitelist what other app it can
     * interact with (aka. composite app feature).
     *
     * For more details, refer to the technical paper of superfluid protocol.
     */
    uint256 constant internal APP_LEVEL_MASK = 0xFF;

    // The app is at the final level, hence it doesn't want to interact with any other app
    uint256 constant internal APP_LEVEL_FINAL = 1 << 0;

    // The app is at the second level, it may interact with other final level apps if whitelisted
    uint256 constant internal APP_LEVEL_SECOND = 1 << 1;

    function getAppLevel(uint256 configWord) internal pure returns (uint8) {
        return uint8(configWord & APP_LEVEL_MASK);
    }

    uint256 constant internal APP_JAIL_BIT = 1 << 15;
    function isAppJailed(uint256 configWord) internal pure returns (bool) {
        return (configWord & SuperAppDefinitions.APP_JAIL_BIT) > 0;
    }

    /**************************************************************************
    / Callback implementation bit masks
    /**************************************************************************/
    uint256 constant internal AGREEMENT_CALLBACK_NOOP_BITMASKS = 0xFF << 32;
    uint256 constant internal BEFORE_AGREEMENT_CREATED_NOOP = 1 << (32 + 0);
    uint256 constant internal AFTER_AGREEMENT_CREATED_NOOP = 1 << (32 + 1);
    uint256 constant internal BEFORE_AGREEMENT_UPDATED_NOOP = 1 << (32 + 2);
    uint256 constant internal AFTER_AGREEMENT_UPDATED_NOOP = 1 << (32 + 3);
    uint256 constant internal BEFORE_AGREEMENT_TERMINATED_NOOP = 1 << (32 + 4);
    uint256 constant internal AFTER_AGREEMENT_TERMINATED_NOOP = 1 << (32 + 5);

    /**************************************************************************
    / App Jail Reasons
    /**************************************************************************/

    uint256 constant internal APP_RULE_REGISTRATION_ONLY_IN_CONSTRUCTOR = 1;
    uint256 constant internal APP_RULE_NO_REGISTRATION_FOR_EOA = 2;
    uint256 constant internal APP_RULE_NO_REVERT_ON_TERMINATION_CALLBACK = 10;
    uint256 constant internal APP_RULE_NO_CRITICAL_SENDER_ACCOUNT = 11;
    uint256 constant internal APP_RULE_NO_CRITICAL_RECEIVER_ACCOUNT = 12;
    uint256 constant internal APP_RULE_CTX_IS_READONLY = 20;
    uint256 constant internal APP_RULE_CTX_IS_NOT_CLEAN = 21;
    uint256 constant internal APP_RULE_CTX_IS_MALFORMATED = 22;
    uint256 constant internal APP_RULE_COMPOSITE_APP_IS_NOT_WHITELISTED = 30;
    uint256 constant internal APP_RULE_COMPOSITE_APP_IS_JAILED = 31;
    uint256 constant internal APP_RULE_MAX_APP_LEVEL_REACHED = 40;
}

/**
 * @dev Context definitions library
 */
library ContextDefinitions {

    /**************************************************************************
    / Call info
    /**************************************************************************/

    // app level
    uint256 constant internal CALL_INFO_APP_LEVEL_MASK = 0xFF;

    // call type
    uint256 constant internal CALL_INFO_CALL_TYPE_SHIFT = 32;
    uint256 constant internal CALL_INFO_CALL_TYPE_MASK = 0xF << CALL_INFO_CALL_TYPE_SHIFT;
    uint8 constant internal CALL_INFO_CALL_TYPE_AGREEMENT = 1;
    uint8 constant internal CALL_INFO_CALL_TYPE_APP_ACTION = 2;
    uint8 constant internal CALL_INFO_CALL_TYPE_APP_CALLBACK = 3;

    function decodeCallInfo(uint256 callInfo)
        internal pure
        returns (uint8 appLevel, uint8 callType)
    {
        appLevel = uint8(callInfo & CALL_INFO_APP_LEVEL_MASK);
        callType = uint8((callInfo & CALL_INFO_CALL_TYPE_MASK) >> CALL_INFO_CALL_TYPE_SHIFT);
    }

    function encodeCallInfo(uint8 appLevel, uint8 callType)
        internal pure
        returns (uint256 callInfo)
    {
        return uint256(appLevel) | (uint256(callType) << CALL_INFO_CALL_TYPE_SHIFT);
    }

}

/**
 * @dev Batch operation library
 */
library BatchOperation {
    /**
     * @dev ERC20.approve batch operation type
     *
     * Call spec:
     * ISuperToken(target).operationApprove(
     *     abi.decode(data, (address spender, uint256 amount))
     * )
     */
    uint32 constant internal OPERATION_TYPE_ERC20_APPROVE = 1;
    /**
     * @dev ERC20.transferFrom batch operation type
     *
     * Call spec:
     * ISuperToken(target).operationTransferFrom(
     *     abi.decode(data, (address sender, address recipient, uint256 amount)
     * )
     */
    uint32 constant internal OPERATION_TYPE_ERC20_TRANSFER_FROM = 2;
    /**
     * @dev SuperToken.upgrade batch operation type
     *
     * Call spec:
     * ISuperToken(target).operationUpgrade(
     *     abi.decode(data, (uint256 amount)
     * )
     */
    uint32 constant internal OPERATION_TYPE_SUPERTOKEN_UPGRADE = 1 + 100;
    /**
     * @dev SuperToken.downgrade batch operation type
     *
     * Call spec:
     * ISuperToken(target).operationDowngrade(
     *     abi.decode(data, (uint256 amount)
     * )
     */
    uint32 constant internal OPERATION_TYPE_SUPERTOKEN_DOWNGRADE = 2 + 100;
    /**
     * @dev Superfluid.callAgreement batch operation type
     *
     * Call spec:
     * callAgreement(
     *     ISuperAgreement(target)),
     *     abi.decode(data, (bytes calldata, bytes userdata)
     * )
     */
    uint32 constant internal OPERATION_TYPE_SUPERFLUID_CALL_AGREEMENT = 1 + 200;
    /**
     * @dev Superfluid.callAppAction batch operation type
     *
     * Call spec:
     * callAppAction(
     *     ISuperApp(target)),
     *     data
     * )
     */
    uint32 constant internal OPERATION_TYPE_SUPERFLUID_CALL_APP_ACTION = 2 + 200;
}

library SuperfluidGovernanceConfigs {

    bytes32 constant internal SUPERFLUID_REWARD_ADDRESS_CONFIG_KEY =
        keccak256("org.superfluid-finance.superfluid.rewardAddress");

    bytes32 constant internal CFAv1_LIQUIDATION_PERIOD_CONFIG_KEY =
        keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1.liquidationPeriod");

    bytes32 constant internal SUPERTOKEN_MINIMUM_DEPOSIT_KEY = 
        keccak256("org.superfluid-finance.superfluid.superTokenMinimumDeposit");

    function getTrustedForwarderConfigKey(address forwarder) internal pure returns (bytes32) {
        return keccak256(abi.encode(
            "org.superfluid-finance.superfluid.trustedForwarder",
            forwarder));
    }

    function getAppRegistrationConfigKey(address deployer, string memory registrationKey) internal pure returns (bytes32) {
        return keccak256(abi.encode(
            "org.superfluid-finance.superfluid.appWhiteListing.registrationKey",
            deployer,
            registrationKey));
    }

    function getAppFactoryConfigKey(address factory) internal pure returns (bytes32) {
        return keccak256(abi.encode(
            "org.superfluid-finance.superfluid.appWhiteListing.factory",
            factory));
    }
}

File 17 of 19 : TokenInfo.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.5.0;

/**
 * @dev ERC20 token info interface
 *
 * NOTE: ERC20 standard interface does not specify these functions, but
 * often the token implementations have them.
 *
 */
interface TokenInfo {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
     * called.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() external view returns (uint8);
}

File 18 of 19 : IERC777.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC777/IERC777.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC777Token standard as defined in the EIP.
 *
 * This contract uses the
 * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let
 * token holders and recipients react to token movements by using setting implementers
 * for the associated interfaces in said registry. See {IERC1820Registry} and
 * {ERC1820Implementer}.
 */
interface IERC777 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the smallest part of the token that is not divisible. This
     * means all token operations (creation, movement and destruction) must have
     * amounts that are a multiple of this number.
     *
     * For most token contracts, this value will equal 1.
     */
    function granularity() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by an account (`owner`).
     */
    function balanceOf(address owner) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * If send or receive hooks are registered for the caller and `recipient`,
     * the corresponding functions will be called with `data` and empty
     * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
     *
     * Emits a {Sent} event.
     *
     * Requirements
     *
     * - the caller must have at least `amount` tokens.
     * - `recipient` cannot be the zero address.
     * - if `recipient` is a contract, it must implement the {IERC777Recipient}
     * interface.
     */
    function send(
        address recipient,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev Destroys `amount` tokens from the caller's account, reducing the
     * total supply.
     *
     * If a send hook is registered for the caller, the corresponding function
     * will be called with `data` and empty `operatorData`. See {IERC777Sender}.
     *
     * Emits a {Burned} event.
     *
     * Requirements
     *
     * - the caller must have at least `amount` tokens.
     */
    function burn(uint256 amount, bytes calldata data) external;

    /**
     * @dev Returns true if an account is an operator of `tokenHolder`.
     * Operators can send and burn tokens on behalf of their owners. All
     * accounts are their own operator.
     *
     * See {operatorSend} and {operatorBurn}.
     */
    function isOperatorFor(address operator, address tokenHolder) external view returns (bool);

    /**
     * @dev Make an account an operator of the caller.
     *
     * See {isOperatorFor}.
     *
     * Emits an {AuthorizedOperator} event.
     *
     * Requirements
     *
     * - `operator` cannot be calling address.
     */
    function authorizeOperator(address operator) external;

    /**
     * @dev Revoke an account's operator status for the caller.
     *
     * See {isOperatorFor} and {defaultOperators}.
     *
     * Emits a {RevokedOperator} event.
     *
     * Requirements
     *
     * - `operator` cannot be calling address.
     */
    function revokeOperator(address operator) external;

    /**
     * @dev Returns the list of default operators. These accounts are operators
     * for all token holders, even if {authorizeOperator} was never called on
     * them.
     *
     * This list is immutable, but individual holders may revoke these via
     * {revokeOperator}, in which case {isOperatorFor} will return false.
     */
    function defaultOperators() external view returns (address[] memory);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must
     * be an operator of `sender`.
     *
     * If send or receive hooks are registered for `sender` and `recipient`,
     * the corresponding functions will be called with `data` and
     * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
     *
     * Emits a {Sent} event.
     *
     * Requirements
     *
     * - `sender` cannot be the zero address.
     * - `sender` must have at least `amount` tokens.
     * - the caller must be an operator for `sender`.
     * - `recipient` cannot be the zero address.
     * - if `recipient` is a contract, it must implement the {IERC777Recipient}
     * interface.
     */
    function operatorSend(
        address sender,
        address recipient,
        uint256 amount,
        bytes calldata data,
        bytes calldata operatorData
    ) external;

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the total supply.
     * The caller must be an operator of `account`.
     *
     * If a send hook is registered for `account`, the corresponding function
     * will be called with `data` and `operatorData`. See {IERC777Sender}.
     *
     * Emits a {Burned} event.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     * - the caller must be an operator for `account`.
     */
    function operatorBurn(
        address account,
        uint256 amount,
        bytes calldata data,
        bytes calldata operatorData
    ) external;

    event Sent(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 amount,
        bytes data,
        bytes operatorData
    );

    event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);

    event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);

    event AuthorizedOperator(address indexed operator, address indexed tokenHolder);

    event RevokedOperator(address indexed operator, address indexed tokenHolder);
}

File 19 of 19 : ERC20WithTokenInfo.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.5.0;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { TokenInfo } from "./TokenInfo.sol";


/**
 *
 * @dev Interface for ERC20 token with token info
 *
 * NOTE: Using abstract contract instead of interfaces because old solidity
 * does not support interface inheriting other interfaces
 * solhint-disable-next-line no-empty-blocks
 *
 */
// solhint-disable-next-line no-empty-blocks
abstract contract ERC20WithTokenInfo is IERC20, TokenInfo {}

Settings
{
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_icfa","type":"address"},{"internalType":"uint64","name":"_minLower","type":"uint64"},{"internalType":"uint64","name":"_minUpper","type":"uint64"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint64","name":"limitGiven","type":"uint64"},{"internalType":"uint64","name":"minLimit","type":"uint64"}],"name":"InsufficientLimits","type":"error"},{"inputs":[{"internalType":"uint64","name":"expirationTimeGiven","type":"uint64"},{"internalType":"uint256","name":"timeNow","type":"uint256"}],"name":"InvalidExpirationTime","type":"error"},{"inputs":[{"internalType":"address","name":"strategy","type":"address"}],"name":"InvalidStrategy","type":"error"},{"inputs":[{"internalType":"bytes32","name":"index","type":"bytes32"}],"name":"TopUpNotRequired","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"expectedCaller","type":"address"}],"name":"UnauthorizedCaller","type":"error"},{"inputs":[{"internalType":"address","name":"superToken","type":"address"}],"name":"UnsupportedSuperToken","type":"error"},{"inputs":[{"internalType":"uint64","name":"lowerLimit","type":"uint64"},{"internalType":"uint64","name":"upperLimit","type":"uint64"}],"name":"WrongLimits","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"AddedApprovedStrategy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"lowerLimit","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"upperLimit","type":"uint64"}],"name":"LimitsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"topUpAmount","type":"uint256"}],"name":"PerformedTopUp","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"RemovedApprovedStrategy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"superToken","type":"address"},{"indexed":false,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"address","name":"liquidityToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lowerLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"upperLimit","type":"uint256"}],"name":"TopUpCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"superToken","type":"address"},{"indexed":false,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"address","name":"liquidityToken","type":"address"}],"name":"TopUpDeleted","type":"event"},{"inputs":[],"name":"CFA_V1","outputs":[{"internalType":"contract IConstantFlowAgreementV1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"addApprovedStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approvedStrategies","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_superToken","type":"address"},{"internalType":"address","name":"_liquidityToken","type":"address"}],"name":"checkTopUp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_index","type":"bytes32"}],"name":"checkTopUpByIndex","outputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_superToken","type":"address"},{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"address","name":"_liquidityToken","type":"address"},{"internalType":"uint64","name":"_expiry","type":"uint64"},{"internalType":"uint64","name":"_lowerLimit","type":"uint64"},{"internalType":"uint64","name":"_upperLimit","type":"uint64"}],"name":"createTopUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_indices","type":"bytes32[]"}],"name":"deleteBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_superToken","type":"address"},{"internalType":"address","name":"_liquidityToken","type":"address"}],"name":"deleteTopUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_index","type":"bytes32"}],"name":"deleteTopUpByIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_superToken","type":"address"},{"internalType":"address","name":"_liquidityToken","type":"address"}],"name":"getTopUp","outputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"address","name":"liquidityToken","type":"address"},{"internalType":"uint64","name":"expiry","type":"uint64"},{"internalType":"uint64","name":"lowerLimit","type":"uint64"},{"internalType":"uint64","name":"upperLimit","type":"uint64"}],"internalType":"struct IStrollManager.TopUp","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_index","type":"bytes32"}],"name":"getTopUpByIndex","outputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"address","name":"liquidityToken","type":"address"},{"internalType":"uint64","name":"expiry","type":"uint64"},{"internalType":"uint64","name":"lowerLimit","type":"uint64"},{"internalType":"uint64","name":"upperLimit","type":"uint64"}],"internalType":"struct IStrollManager.TopUp","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_superToken","type":"address"},{"internalType":"address","name":"_liquidityToken","type":"address"}],"name":"getTopUpIndex","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"minLower","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minUpper","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_superToken","type":"address"},{"internalType":"address","name":"_liquidityToken","type":"address"}],"name":"performTopUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_index","type":"bytes32"}],"name":"performTopUpByIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"removeApprovedStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_lowerLimit","type":"uint64"},{"internalType":"uint64","name":"_upperLimit","type":"uint64"}],"name":"setLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a06040523480156200001157600080fd5b50604051620031ea380380620031ea833981810160405281019062000037919062000325565b620000576200004b620001aa60201b60201c565b620001b260201b60201c565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603620000be576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff168267ffffffffffffffff16106200011b5781816040517fe52779850000000000000000000000000000000000000000000000000000000081526004016200011292919062000392565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff168152505081600060146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555080600160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505050620003bf565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620002a8826200027b565b9050919050565b620002ba816200029b565b8114620002c657600080fd5b50565b600081519050620002da81620002af565b92915050565b600067ffffffffffffffff82169050919050565b620002ff81620002e0565b81146200030b57600080fd5b50565b6000815190506200031f81620002f4565b92915050565b60008060006060848603121562000341576200034062000276565b5b60006200035186828701620002c9565b935050602062000364868287016200030e565b925050604062000377868287016200030e565b9150509250925092565b6200038c81620002e0565b82525050565b6000604082019050620003a9600083018562000381565b620003b8602083018462000381565b9392505050565b608051612e08620003e260003960008181610b8e015261157a0152612e086000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c80638b80f351116100b8578063a7052e6b1161007c578063a7052e6b14610324578063c613aec014610342578063f11665c914610372578063f2556da9146103a2578063f29730cf146103be578063f2fde38b146103da57610137565b80638b80f3511461026e5780638bc6a9411461029e5780638da5cb5b146102ba578063947dd645146102d85780639aed5c51146102f457610137565b806359b830be116100ff57806359b830be146101ca578063715018a6146101e857806377a80e47146101f2578063854ba6d01461022257806388882af21461023e57610137565b80633aa4e5901461013c5780633db29ed8146101585780633f34c5141461017657806347cda691146101925780634e0e623d146101ae575b600080fd5b6101566004803603810190610151919061232f565b6103f6565b005b610160610b8c565b60405161016d919061241b565b60405180910390f35b610190600480360381019061018b9190612436565b610bb0565b005b6101ac60048036038101906101a791906124db565b610d15565b005b6101c860048036038101906101c39190612528565b610d61565b005b6101d2610f3e565b6040516101df9190612564565b60405180910390f35b6101f0610f58565b005b61020c6004803603810190610207919061257f565b610fe0565b60405161021991906125eb565b60405180910390f35b61023c6004803603810190610237919061263c565b610ffe565b005b6102586004803603810190610253919061263c565b611246565b60405161026591906125eb565b60405180910390f35b6102886004803603810190610283919061257f565b6118c3565b6040516102959190612757565b60405180910390f35b6102b860048036038101906102b39190612528565b6118e7565b005b6102c2611a4b565b6040516102cf9190612781565b60405180910390f35b6102f260048036038101906102ed919061263c565b611a74565b005b61030e6004803603810190610309919061263c565b611d56565b60405161031b9190612757565b60405180910390f35b61032c611f71565b6040516103399190612564565b60405180910390f35b61035c60048036038101906103579190612528565b611f8b565b60405161036991906127b7565b60405180910390f35b61038c6004803603810190610387919061257f565b611fab565b60405161039991906127e1565b60405180910390f35b6103bc60048036038101906103b7919061257f565b611fe1565b005b6103d860048036038101906103d3919061257f565b611ff9565b005b6103f460048036038101906103ef9190612528565b612011565b005b428367ffffffffffffffff16116104465782426040517fa81e80eb00000000000000000000000000000000000000000000000000000000815260040161043d9291906127fc565b60405180910390fd5b600060149054906101000a900467ffffffffffffffff1667ffffffffffffffff168267ffffffffffffffff1610156104cd5781600060149054906101000a900467ffffffffffffffff166040517f367e59f90000000000000000000000000000000000000000000000000000000081526004016104c4929190612825565b60405180910390fd5b600160009054906101000a900467ffffffffffffffff1667ffffffffffffffff168167ffffffffffffffff1610156105545780600160009054906101000a900467ffffffffffffffff166040517f367e59f900000000000000000000000000000000000000000000000000000000815260040161054b929190612825565b60405180910390fd5b6000610561338887611fab565b90503373ffffffffffffffffffffffffffffffffffffffff166003600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610a5d57600073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614806106335750600073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16145b8061066a5750600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16145b156106a1576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661072f57856040517feb894b340000000000000000000000000000000000000000000000000000000081526004016107269190612781565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff1663fc888cb0886040518263ffffffff1660e01b8152600401610768919061285d565b602060405180830381865afa158015610785573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a991906128a4565b6107ea57866040517f1d5f93fb0000000000000000000000000000000000000000000000000000000081526004016107e19190612781565b60405180910390fd5b60006040518060e001604052803373ffffffffffffffffffffffffffffffffffffffff1681526020018973ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018667ffffffffffffffff1681526020018567ffffffffffffffff1681526020018467ffffffffffffffff168152509050806003600084815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060808201518160030160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060a08201518160040160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060c08201518160040160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555090505050610b15565b836003600083815260200190815260200160002060030160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550826003600083815260200190815260200160002060040160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550816003600083815260200190815260200160002060040160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b8673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16827f160bcdb242b6b3400162d90511ed5912a4a4f906a00a80e523c1bb10867e428a8989898989604051610b7b959493929190612902565b60405180910390a450505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b610bb8612108565b73ffffffffffffffffffffffffffffffffffffffff16610bd6611a4b565b73ffffffffffffffffffffffffffffffffffffffff1614610c2c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c23906129b2565b60405180910390fd5b8067ffffffffffffffff168267ffffffffffffffff1610610c865781816040517fe5277985000000000000000000000000000000000000000000000000000000008152600401610c7d929190612825565b60405180910390fd5b81600060146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555080600160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055507fcdbc762ccbd384cdee07c2d0ac57883fa6bb2cd308895ed4417a0526c6baea0c8282604051610d09929190612825565b60405180910390a15050565b600082829050905060005b81811015610d5b57610d4a848483818110610d3e57610d3d6129d2565b5b90506020020135611a74565b80610d5490612a30565b9050610d20565b50505050565b610d69612108565b73ffffffffffffffffffffffffffffffffffffffff16610d87611a4b565b73ffffffffffffffffffffffffffffffffffffffff1614610ddd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dd4906129b2565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610e4e57806040517feb894b34000000000000000000000000000000000000000000000000000000008152600401610e459190612781565b60405180910390fd5b600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610f3b576001600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508073ffffffffffffffffffffffffffffffffffffffff167f3edff2b723512b7e98f0fb394d84a670f3a40eb2f2c51e9c00c58a3f04e1e4dd60405160405180910390a25b50565b600160009054906101000a900467ffffffffffffffff1681565b610f60612108565b73ffffffffffffffffffffffffffffffffffffffff16610f7e611a4b565b73ffffffffffffffffffffffffffffffffffffffff1614610fd4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fcb906129b2565b60405180910390fd5b610fde6000612110565b565b6000610ff5610ff0858585611fab565b611246565b90509392505050565b600061100982611246565b90506000810361105057816040517fc160da3f00000000000000000000000000000000000000000000000000000000815260040161104791906127e1565b60405180910390fd5b600060036000848152602001908152602001600020905060008160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008260020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663fc888cb0836040518263ffffffff1660e01b81526004016110f2919061285d565b602060405180830381865afa15801561110f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113391906128a4565b61117457816040517f1d5f93fb00000000000000000000000000000000000000000000000000000000815260040161116b9190612781565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663699018588460000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684876040518463ffffffff1660e01b81526004016111d593929190612a78565b600060405180830381600087803b1580156111ef57600080fd5b505af1158015611203573d6000803e3d6000fd5b50505050847fd9ed57b29272093f04d5d1de3484d5ef3819413dcccbfe2d364ead6ab58d4df68560405161123791906125eb565b60405180910390a25050505050565b600080600360008481526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614806112df5750428160030160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1611155b806113d1575060008160030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8360000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168460020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518363ffffffff1660e01b815260040161138e929190612aaf565b602060405180830381865afa1580156113ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113cf9190612b04565b145b8061149d575060008160030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a082318360000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b815260040161145a9190612781565b602060405180830381865afa158015611477573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149b9190612b04565b145b8061156757508060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fc888cb08260010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401611524919061285d565b602060405180830381865afa158015611541573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156591906128a4565b155b156115765760009150506118be565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e8e7e2d18360010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168460000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518363ffffffff1660e01b815260040161161b929190612b31565b602060405180830381865afa158015611638573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165c9190612b93565b9050600081600b0b12156118b75760008260010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a082318460000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b81526004016116ed9190612781565b602060405180830381865afa15801561170a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172e9190612b04565b90506000827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61175e9190612bc0565b6bffffffffffffffffffffffff16905060008060149054906101000a900467ffffffffffffffff1667ffffffffffffffff168560040160009054906101000a900467ffffffffffffffff1667ffffffffffffffff16106117d6578460040160009054906101000a900467ffffffffffffffff166117ee565b600060149054906101000a900467ffffffffffffffff165b90506000600160009054906101000a900467ffffffffffffffff1667ffffffffffffffff168660040160089054906101000a900467ffffffffffffffff1667ffffffffffffffff1610611859578560040160089054906101000a900467ffffffffffffffff16611871565b600160009054906101000a900467ffffffffffffffff165b90508167ffffffffffffffff16836118899190612caf565b84116118b2578067ffffffffffffffff16836118a59190612caf565b96505050505050506118be565b505050505b6000925050505b919050565b6118cb6121d4565b6118de6118d9858585611fab565b611d56565b90509392505050565b6118ef612108565b73ffffffffffffffffffffffffffffffffffffffff1661190d611a4b565b73ffffffffffffffffffffffffffffffffffffffff1614611963576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195a906129b2565b60405180910390fd5b600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611a4857600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81549060ff02191690558073ffffffffffffffffffffffffffffffffffffffff167fcccfdaf06e384e4afcea4acf18f915e4cf10ccbebf3bd41dbdbf360388fa613860405160405180910390a25b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600060036000838152602001908152602001600020905060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015611b125750428260030160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1610155b15611b565733816040517f536dd9ef000000000000000000000000000000000000000000000000000000008152600401611b4d929190612aaf565b60405180910390fd5b8160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16847f435d6aa02bc57be393afe57c6498e59391018bbf9f6be723d2f94a0e0328ae4b8560020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168660030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16604051611c46929190612aaf565b60405180910390a460036000848152602001908152602001600020600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556003820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556003820160146101000a81549067ffffffffffffffff02191690556004820160006101000a81549067ffffffffffffffff02191690556004820160086101000a81549067ffffffffffffffff02191690555050505050565b611d5e6121d4565b600360008381526020019081526020016000206040518060e00160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016003820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016003820160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020016004820160009054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020016004820160089054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff16815250509050919050565b600060149054906101000a900467ffffffffffffffff1681565b60026020528060005260406000206000915054906101000a900460ff1681565b6000838383604051602001611fc293929190612d09565b6040516020818303038152906040528051906020012090509392505050565b611ff4611fef848484611fab565b611a74565b505050565b61200c612007848484611fab565b610ffe565b505050565b612019612108565b73ffffffffffffffffffffffffffffffffffffffff16612037611a4b565b73ffffffffffffffffffffffffffffffffffffffff161461208d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612084906129b2565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036120fc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120f390612db2565b60405180910390fd5b61210581612110565b50565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6040518060e00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff1681525090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006122bc82612291565b9050919050565b6122cc816122b1565b81146122d757600080fd5b50565b6000813590506122e9816122c3565b92915050565b600067ffffffffffffffff82169050919050565b61230c816122ef565b811461231757600080fd5b50565b60008135905061232981612303565b92915050565b60008060008060008060c0878903121561234c5761234b612287565b5b600061235a89828a016122da565b965050602061236b89828a016122da565b955050604061237c89828a016122da565b945050606061238d89828a0161231a565b935050608061239e89828a0161231a565b92505060a06123af89828a0161231a565b9150509295509295509295565b6000819050919050565b60006123e16123dc6123d784612291565b6123bc565b612291565b9050919050565b60006123f3826123c6565b9050919050565b6000612405826123e8565b9050919050565b612415816123fa565b82525050565b6000602082019050612430600083018461240c565b92915050565b6000806040838503121561244d5761244c612287565b5b600061245b8582860161231a565b925050602061246c8582860161231a565b9150509250929050565b600080fd5b600080fd5b600080fd5b60008083601f84011261249b5761249a612476565b5b8235905067ffffffffffffffff8111156124b8576124b761247b565b5b6020830191508360208202830111156124d4576124d3612480565b5b9250929050565b600080602083850312156124f2576124f1612287565b5b600083013567ffffffffffffffff8111156125105761250f61228c565b5b61251c85828601612485565b92509250509250929050565b60006020828403121561253e5761253d612287565b5b600061254c848285016122da565b91505092915050565b61255e816122ef565b82525050565b60006020820190506125796000830184612555565b92915050565b60008060006060848603121561259857612597612287565b5b60006125a6868287016122da565b93505060206125b7868287016122da565b92505060406125c8868287016122da565b9150509250925092565b6000819050919050565b6125e5816125d2565b82525050565b600060208201905061260060008301846125dc565b92915050565b6000819050919050565b61261981612606565b811461262457600080fd5b50565b60008135905061263681612610565b92915050565b60006020828403121561265257612651612287565b5b600061266084828501612627565b91505092915050565b612672816122b1565b82525050565b6000612683826123e8565b9050919050565b61269381612678565b82525050565b60006126a4826123e8565b9050919050565b6126b481612699565b82525050565b6126c3816122ef565b82525050565b60e0820160008201516126df6000850182612669565b5060208201516126f2602085018261268a565b50604082015161270560408501826126ab565b5060608201516127186060850182612669565b50608082015161272b60808501826126ba565b5060a082015161273e60a08501826126ba565b5060c082015161275160c08501826126ba565b50505050565b600060e08201905061276c60008301846126c9565b92915050565b61277b816122b1565b82525050565b60006020820190506127966000830184612772565b92915050565b60008115159050919050565b6127b18161279c565b82525050565b60006020820190506127cc60008301846127a8565b92915050565b6127db81612606565b82525050565b60006020820190506127f660008301846127d2565b92915050565b60006040820190506128116000830185612555565b61281e60208301846125dc565b9392505050565b600060408201905061283a6000830185612555565b6128476020830184612555565b9392505050565b61285781612678565b82525050565b6000602082019050612872600083018461284e565b92915050565b6128818161279c565b811461288c57600080fd5b50565b60008151905061289e81612878565b92915050565b6000602082840312156128ba576128b9612287565b5b60006128c88482850161288f565b91505092915050565b60006128ec6128e76128e2846122ef565b6123bc565b6125d2565b9050919050565b6128fc816128d1565b82525050565b600060a0820190506129176000830188612772565b6129246020830187612772565b61293160408301866128f3565b61293e60608301856128f3565b61294b60808301846128f3565b9695505050505050565b600082825260208201905092915050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b600061299c602083612955565b91506129a782612966565b602082019050919050565b600060208201905081810360008301526129cb8161298f565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612a3b826125d2565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612a6d57612a6c612a01565b5b600182019050919050565b6000606082019050612a8d6000830186612772565b612a9a602083018561284e565b612aa760408301846125dc565b949350505050565b6000604082019050612ac46000830185612772565b612ad16020830184612772565b9392505050565b612ae1816125d2565b8114612aec57600080fd5b50565b600081519050612afe81612ad8565b92915050565b600060208284031215612b1a57612b19612287565b5b6000612b2884828501612aef565b91505092915050565b6000604082019050612b46600083018561284e565b612b536020830184612772565b9392505050565b600081600b0b9050919050565b612b7081612b5a565b8114612b7b57600080fd5b50565b600081519050612b8d81612b67565b92915050565b600060208284031215612ba957612ba8612287565b5b6000612bb784828501612b7e565b91505092915050565b6000612bcb82612b5a565b9150612bd683612b5a565b9250826b7fffffffffffffffffffffff0482116000841360008413161615612c0157612c00612a01565b5b817fffffffffffffffffffffffffffffffffffffffff8000000000000000000000000583126000841260008413161615612c3e57612c3d612a01565b5b827fffffffffffffffffffffffffffffffffffffffff8000000000000000000000000582126000841360008412161615612c7b57612c7a612a01565b5b826b7fffffffffffffffffffffff0582126000841260008412161615612ca457612ca3612a01565b5b828202905092915050565b6000612cba826125d2565b9150612cc5836125d2565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612cfe57612cfd612a01565b5b828202905092915050565b6000606082019050612d1e6000830186612772565b612d2b6020830185612772565b612d386040830184612772565b949350505050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000612d9c602683612955565b9150612da782612d40565b604082019050919050565b60006020820190508181036000830152612dcb81612d8f565b905091905056fea264697066735822122069eff5baf3d151e17f8d11225e8b854b39047c6225b908e57f59a95acd1df93b64736f6c634300080d0033000000000000000000000000f4c5310e51f6079f601a5fb7120bc72a70b96e2a000000000000000000000000000000000000000000000000000000000002a3000000000000000000000000000000000000000000000000000000000000093a80

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000f4c5310e51f6079f601a5fb7120bc72a70b96e2a000000000000000000000000000000000000000000000000000000000002a3000000000000000000000000000000000000000000000000000000000000093a80

-----Decoded View---------------
Arg [0] : _icfa (address): 0xf4c5310e51f6079f601a5fb7120bc72a70b96e2a
Arg [1] : _minLower (uint64): 172800
Arg [2] : _minUpper (uint64): 604800

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000f4c5310e51f6079f601a5fb7120bc72a70b96e2a
Arg [1] : 000000000000000000000000000000000000000000000000000000000002a300
Arg [2] : 0000000000000000000000000000000000000000000000000000000000093a80


Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.