Contract 0xE7d4BD74f8698F2F28F52d3e9F6d2885B59eb714 1

Contract Overview

Balance:
0 Ether
Txn Hash
Method
Block
From
To
Value
0xac9b4655b104058a3310b7d26caf216f98fe677d5c95519b6531b824b5b6f4e20x61010060108639722022-06-16 20:19:43163 days 21 hrs ago0xd15d5d0f5b1b56a4daef75cfe108cb825e97d015 IN  Create: Superfluid0 Ether0.01189038 2.50000001
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xa209d5e7aef7caa5a6a67fe6ada5db85c050b559ed288fcdc1236e4e3337bf68114340132022-09-24 3:29:1764 days 14 hrs ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xa209d5e7aef7caa5a6a67fe6ada5db85c050b559ed288fcdc1236e4e3337bf68114340132022-09-24 3:29:1764 days 14 hrs ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xa209d5e7aef7caa5a6a67fe6ada5db85c050b559ed288fcdc1236e4e3337bf68114340132022-09-24 3:29:1764 days 14 hrs ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xa209d5e7aef7caa5a6a67fe6ada5db85c050b559ed288fcdc1236e4e3337bf68114340132022-09-24 3:29:1764 days 14 hrs ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0x3a229f96406eb661dda378e45a4de271e56cc29958280e945ad648be5f9074d6113939832022-09-17 3:29:4171 days 14 hrs ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0x3a229f96406eb661dda378e45a4de271e56cc29958280e945ad648be5f9074d6113939832022-09-17 3:29:4171 days 14 hrs ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0x3a229f96406eb661dda378e45a4de271e56cc29958280e945ad648be5f9074d6113939832022-09-17 3:29:4171 days 14 hrs ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0x3a229f96406eb661dda378e45a4de271e56cc29958280e945ad648be5f9074d6113939832022-09-17 3:29:4171 days 14 hrs ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xaf9315064168164c88bda2657df8c481436d3aba0a4f4512d9acd4411d713749113537242022-09-10 3:29:2778 days 14 hrs ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xaf9315064168164c88bda2657df8c481436d3aba0a4f4512d9acd4411d713749113537242022-09-10 3:29:2778 days 14 hrs ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xaf9315064168164c88bda2657df8c481436d3aba0a4f4512d9acd4411d713749113537242022-09-10 3:29:2778 days 14 hrs ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xaf9315064168164c88bda2657df8c481436d3aba0a4f4512d9acd4411d713749113537242022-09-10 3:29:2778 days 14 hrs ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xda2976074463bf3e26c510929109aca54bf5f28400fb9c58f6beb19289ceab77113452472022-09-08 15:54:5580 days 1 hr ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xda2976074463bf3e26c510929109aca54bf5f28400fb9c58f6beb19289ceab77113452472022-09-08 15:54:5580 days 1 hr ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xda2976074463bf3e26c510929109aca54bf5f28400fb9c58f6beb19289ceab77113452472022-09-08 15:54:5580 days 1 hr ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xda2976074463bf3e26c510929109aca54bf5f28400fb9c58f6beb19289ceab77113452472022-09-08 15:54:5580 days 1 hr ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xda2976074463bf3e26c510929109aca54bf5f28400fb9c58f6beb19289ceab77113452472022-09-08 15:54:5580 days 1 hr ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xda2976074463bf3e26c510929109aca54bf5f28400fb9c58f6beb19289ceab77113452472022-09-08 15:54:5580 days 1 hr ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xda2976074463bf3e26c510929109aca54bf5f28400fb9c58f6beb19289ceab77113452472022-09-08 15:54:5580 days 1 hr ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xda2976074463bf3e26c510929109aca54bf5f28400fb9c58f6beb19289ceab77113452472022-09-08 15:54:5580 days 1 hr ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0xda2976074463bf3e26c510929109aca54bf5f28400fb9c58f6beb19289ceab77113452472022-09-08 15:54:5580 days 1 hr ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0x6cabbd2f78274120e4cbadf7e84008822b89011d2caa75a55fc202e81629b06a113452332022-09-08 15:51:2580 days 1 hr ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0x6cabbd2f78274120e4cbadf7e84008822b89011d2caa75a55fc202e81629b06a113452332022-09-08 15:51:2580 days 1 hr ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0x6cabbd2f78274120e4cbadf7e84008822b89011d2caa75a55fc202e81629b06a113452332022-09-08 15:51:2580 days 1 hr ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
0x6cabbd2f78274120e4cbadf7e84008822b89011d2caa75a55fc202e81629b06a113452332022-09-08 15:51:2580 days 1 hr ago 0xed5b5b32110c3ded02a07c8b8e97513fafb883b6 0xe7d4bd74f8698f2f28f52d3e9f6d2885b59eb7140 Ether
[ Download CSV Export 
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
Superfluid

Compiler Version
v0.8.14+commit.80d49f37

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 23 : Superfluid.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.14;

import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";

import { UUPSProxiable } from "../upgradability/UUPSProxiable.sol";
import { UUPSProxy } from "../upgradability/UUPSProxy.sol";

import {
    ISuperfluid,
    ISuperfluidGovernance,
    ISuperAgreement,
    ISuperApp,
    SuperAppDefinitions,
    ContextDefinitions,
    BatchOperation,
    SuperfluidGovernanceConfigs,
    ISuperfluidToken,
    ISuperToken,
    ISuperTokenFactory,
    IERC20
} from "../interfaces/superfluid/ISuperfluid.sol";

import { CallUtils } from "../libs/CallUtils.sol";
import { BaseRelayRecipient } from "../libs/BaseRelayRecipient.sol";


/// FIXME Lots of reverts in here - can put custom errors

/**
 * @dev The Superfluid host implementation.
 *
 * NOTE:
 * - Please read ISuperfluid for implementation notes.
 * - For some deeper technical notes, please visit protocol-monorepo wiki area.
 *
 * @author Superfluid
 */
contract Superfluid is
    UUPSProxiable,
    ISuperfluid,
    BaseRelayRecipient
{

    using SafeCast for uint256;

    struct AppManifest {
        uint256 configWord;
    }

    // solhint-disable-next-line var-name-mixedcase
    bool immutable public NON_UPGRADABLE_DEPLOYMENT;

    // solhint-disable-next-line var-name-mixedcase
    bool immutable public APP_WHITE_LISTING_ENABLED;

    /**
     * @dev Maximum number of level of apps can be composed together
     *
     * NOTE:
     * - TODO Composite app feature is currently disabled. Hence app cannot
     *   will not be able to call other app.
     */
    // solhint-disable-next-line var-name-mixedcase
    uint immutable public MAX_APP_LEVEL = 1;

    // solhint-disable-next-line var-name-mixedcase
    uint64 immutable public CALLBACK_GAS_LIMIT = 3000000;

    /* WARNING: NEVER RE-ORDER VARIABLES! Always double-check that new
       variables are added APPEND-ONLY. Re-ordering variables can
       permanently BREAK the deployed proxy contract. */

    /// @dev Governance contract
    ISuperfluidGovernance internal _gov;

    /// @dev Agreement list indexed by agreement index minus one
    ISuperAgreement[] internal _agreementClasses;
    /// @dev Mapping between agreement type to agreement index (starting from 1)
    mapping (bytes32 => uint) internal _agreementClassIndices;

    /// @dev Super token
    ISuperTokenFactory internal _superTokenFactory;

    /// @dev App manifests
    mapping(ISuperApp => AppManifest) internal _appManifests;
    /// @dev Composite app white-listing: source app => (target app => isAllowed)
    mapping(ISuperApp => mapping(ISuperApp => bool)) internal _compositeApps;
    /// @dev Ctx stamp of the current transaction, it should always be cleared to
    ///      zero before transaction finishes
    bytes32 internal _ctxStamp;
    /// @dev if app whitelisting is enabled, this is to make sure the keys are used only once
    mapping(bytes32 => bool) internal _appKeysUsedDeprecated;

    constructor(bool nonUpgradable, bool appWhiteListingEnabled) {
        NON_UPGRADABLE_DEPLOYMENT = nonUpgradable;
        APP_WHITE_LISTING_ENABLED = appWhiteListingEnabled;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // UUPSProxiable
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    function initialize(
        ISuperfluidGovernance gov
    )
        external
        initializer // OpenZeppelin Initializable
    {
        _gov = gov;
    }

    function proxiableUUID() public pure override returns (bytes32) {
        return keccak256("org.superfluid-finance.contracts.Superfluid.implementation");
    }

    function updateCode(address newAddress) external override onlyGovernance {
        require(!NON_UPGRADABLE_DEPLOYMENT, "SF: non upgradable");
        require(!Superfluid(newAddress).NON_UPGRADABLE_DEPLOYMENT(), "SF: cannot downgrade to non upgradable");
        _updateCodeAddress(newAddress);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Time
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    function getNow() public view  returns (uint256) {
        // solhint-disable-next-line not-rely-on-time
        return block.timestamp;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Governance
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    function getGovernance() external view override returns (ISuperfluidGovernance) {
        return _gov;
    }

    function replaceGovernance(ISuperfluidGovernance newGov) external override onlyGovernance {
        emit GovernanceReplaced(_gov, newGov);
        _gov = newGov;
    }

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

    function registerAgreementClass(ISuperAgreement agreementClassLogic) external onlyGovernance override {
        bytes32 agreementType = agreementClassLogic.agreementType();
        require(_agreementClassIndices[agreementType] == 0,
            "SF: agreement class already registered");
        require(_agreementClasses.length < 256,
            "SF: support up to 256 agreement classes");
        ISuperAgreement agreementClass;
        if (!NON_UPGRADABLE_DEPLOYMENT) {
            // initialize the proxy
            UUPSProxy proxy = new UUPSProxy();
            proxy.initializeProxy(address(agreementClassLogic));
            agreementClass = ISuperAgreement(address(proxy));
        } else {
            agreementClass = ISuperAgreement(address(agreementClassLogic));
        }
        // register the agreement proxy
        _agreementClasses.push((agreementClass));
        _agreementClassIndices[agreementType] = _agreementClasses.length;
        emit AgreementClassRegistered(agreementType, address(agreementClassLogic));
    }

    function updateAgreementClass(ISuperAgreement agreementClassLogic) external onlyGovernance override {
        require(!NON_UPGRADABLE_DEPLOYMENT, "SF: non upgradable");
        bytes32 agreementType = agreementClassLogic.agreementType();
        uint idx = _agreementClassIndices[agreementType];
        require(idx != 0, "SF: agreement class not registered");
        UUPSProxiable proxiable = UUPSProxiable(address(_agreementClasses[idx - 1]));
        proxiable.updateCode(address(agreementClassLogic));
        emit AgreementClassUpdated(agreementType, address(agreementClassLogic));
    }

    function isAgreementTypeListed(bytes32 agreementType)
        external view override
        returns (bool yes)
    {
        uint idx = _agreementClassIndices[agreementType];
        return idx != 0;
    }

    function isAgreementClassListed(ISuperAgreement agreementClass)
        public view override
        returns (bool yes)
    {
        bytes32 agreementType = agreementClass.agreementType();
        uint idx = _agreementClassIndices[agreementType];
        // it should also be the same agreement class proxy address
        return idx != 0 && _agreementClasses[idx - 1] == agreementClass;
    }

    function getAgreementClass(bytes32 agreementType)
        external view override
        returns(ISuperAgreement agreementClass)
    {
        uint idx = _agreementClassIndices[agreementType];
        require(idx != 0, "SF: agreement class not registered");
        return ISuperAgreement(_agreementClasses[idx - 1]);
    }

    function mapAgreementClasses(uint256 bitmap)
        external view override
        returns (ISuperAgreement[] memory agreementClasses) {
        uint i;
        uint n;
        // create memory output using the counted size
        agreementClasses = new ISuperAgreement[](_agreementClasses.length);
        // add to the output
        n = 0;
        for (i = 0; i < _agreementClasses.length; ++i) {
            if ((bitmap & (1 << i)) > 0) {
                agreementClasses[n++] = _agreementClasses[i];
            }
        }
        // resize memory arrays
        assembly { mstore(agreementClasses, n) }
    }

    function addToAgreementClassesBitmap(uint256 bitmap, bytes32 agreementType)
        external view override
        returns (uint256 newBitmap)
    {
        uint idx = _agreementClassIndices[agreementType];
        require(idx != 0, "SF: agreement class not registered");
        return bitmap | (1 << (idx - 1));
    }

    function removeFromAgreementClassesBitmap(uint256 bitmap, bytes32 agreementType)
        external view override
        returns (uint256 newBitmap)
    {
        uint idx = _agreementClassIndices[agreementType];
        require(idx != 0, "SF: agreement class not registered");
        return bitmap & ~(1 << (idx - 1));
    }

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

    function getSuperTokenFactory()
        external view override
        returns (ISuperTokenFactory factory)
    {
        return _superTokenFactory;
    }

    function getSuperTokenFactoryLogic()
        external view override
        returns (address logic)
    {
        assert(address(_superTokenFactory) != address(0));
        if (NON_UPGRADABLE_DEPLOYMENT) return address(_superTokenFactory);
        else return UUPSProxiable(address(_superTokenFactory)).getCodeAddress();
    }

    function updateSuperTokenFactory(ISuperTokenFactory newFactory)
        external override
        onlyGovernance
    {
        if (address(_superTokenFactory) == address(0)) {
            if (!NON_UPGRADABLE_DEPLOYMENT) {
                // initialize the proxy
                UUPSProxy proxy = new UUPSProxy();
                proxy.initializeProxy(address(newFactory));
                _superTokenFactory = ISuperTokenFactory(address(proxy));
            } else {
                _superTokenFactory = newFactory;
            }
            _superTokenFactory.initialize();
        } else {
            require(!NON_UPGRADABLE_DEPLOYMENT, "SF: non upgradable");
            UUPSProxiable(address(_superTokenFactory)).updateCode(address(newFactory));
        }
        emit SuperTokenFactoryUpdated(_superTokenFactory);
    }

    function updateSuperTokenLogic(ISuperToken token)
        external override
        onlyGovernance
    {
        address code = address(_superTokenFactory.getSuperTokenLogic());
        // assuming it's uups proxiable
        UUPSProxiable(address(token)).updateCode(code);
        emit SuperTokenLogicUpdated(token, code);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // App Registry
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    function registerApp(
        uint256 configWord
    )
        external override
    {
        // check if whitelisting required
        if (APP_WHITE_LISTING_ENABLED) {
            revert("SF: app registration requires permission");
        }
        _registerApp(configWord, ISuperApp(msg.sender), true);
    }

    function registerAppWithKey(uint256 configWord, string calldata registrationKey)
        external override
    {
        bytes32 configKey = SuperfluidGovernanceConfigs.getAppRegistrationConfigKey(
            // solhint-disable-next-line avoid-tx-origin
            tx.origin,
            registrationKey
        );
        if (APP_WHITE_LISTING_ENABLED) {
            // check if the key is valid and not expired
            require(
                _gov.getConfigAsUint256(
                    this,
                    ISuperfluidToken(address(0)),
                    configKey
                // solhint-disable-next-line not-rely-on-time
                ) >= block.timestamp,
                "SF: invalid or expired registration key"
            );
        }
        _registerApp(configWord, ISuperApp(msg.sender), true);
    }

    function registerAppByFactory(
        ISuperApp app,
        uint256 configWord
    )
        external override
    {
        // msg sender must be a contract
        {
            uint256 cs;
            // solhint-disable-next-line no-inline-assembly
            assembly { cs := extcodesize(caller()) }
            require(cs > 0, "SF: factory must be a contract");
        }

        if (APP_WHITE_LISTING_ENABLED) {
            // check if msg sender is authorized to register
            bytes32 configKey = SuperfluidGovernanceConfigs.getAppFactoryConfigKey(msg.sender);
            bool isAuthorizedAppFactory = _gov.getConfigAsUint256(
                this,
                ISuperfluidToken(address(0)),
                configKey) == 1;

            require(isAuthorizedAppFactory, "SF: authorized factory required");
        }
        _registerApp(configWord, app, false);
    }

    function _registerApp(uint256 configWord, ISuperApp app, bool checkIfInAppConstructor) private
    {
        // solhint-disable-next-line avoid-tx-origin
        require(msg.sender != tx.origin, "SF: APP_RULE_NO_REGISTRATION_FOR_EOA");

        if (checkIfInAppConstructor) {
            uint256 cs;
            // solhint-disable-next-line no-inline-assembly
            assembly { cs := extcodesize(app) }
            require(cs == 0, "SF: APP_RULE_REGISTRATION_ONLY_IN_CONSTRUCTOR");
        }
        require(
            SuperAppDefinitions.isConfigWordClean(configWord) &&
            SuperAppDefinitions.getAppLevel(configWord) > 0 &&
            (configWord & SuperAppDefinitions.APP_JAIL_BIT) == 0,
            "SF: invalid config word");
        require(_appManifests[ISuperApp(app)].configWord == 0 , "SF: app already registered");
        _appManifests[ISuperApp(app)] = AppManifest(configWord);
        emit AppRegistered(app);
    }

    function isApp(ISuperApp app) public view override returns(bool) {
        return _appManifests[app].configWord > 0;
    }

    function getAppLevel(ISuperApp appAddr) public override view returns(uint8) {
        return SuperAppDefinitions.getAppLevel(_appManifests[appAddr].configWord);
    }

    function getAppManifest(
        ISuperApp app
    )
        external view override
        returns (
            bool isSuperApp,
            bool isJailed,
            uint256 noopMask
        )
    {
        AppManifest memory manifest = _appManifests[app];
        isSuperApp = (manifest.configWord > 0);
        if (isSuperApp) {
            isJailed = SuperAppDefinitions.isAppJailed(manifest.configWord);
            noopMask = manifest.configWord & SuperAppDefinitions.AGREEMENT_CALLBACK_NOOP_BITMASKS;
        }
    }

    function isAppJailed(
        ISuperApp app
    )
        public view override
        returns(bool)
    {
        return SuperAppDefinitions.isAppJailed(_appManifests[app].configWord);
    }

    function allowCompositeApp(
        ISuperApp targetApp
    )
        external override
    {
        ISuperApp sourceApp = ISuperApp(msg.sender);
        require(isApp(sourceApp), "SF: sender is not an app");
        require(isApp(targetApp), "SF: target is not an app");
        require(getAppLevel(sourceApp) > getAppLevel(targetApp), "SF: source app should have higher app level");
        _compositeApps[ISuperApp(msg.sender)][targetApp] = true;
    }

    function isCompositeAppAllowed(
        ISuperApp app,
        ISuperApp targetApp
    )
        external view override
        returns (bool)
    {
        return _compositeApps[app][targetApp];
    }

    /**************************************************************************
     * Agreement Framework
     *************************************************************************/

    function callAppBeforeCallback(
        ISuperApp app,
        bytes calldata callData,
        bool isTermination,
        bytes calldata ctx
    )
        external override
        onlyAgreement
        assertValidCtx(ctx)
        returns(bytes memory cbdata)
    {
        (bool success, bytes memory returnedData) = _callCallback(app, true, isTermination, callData, ctx);
        if (success) {
            if (CallUtils.isValidAbiEncodedBytes(returnedData)) {
                cbdata = abi.decode(returnedData, (bytes));
            } else {
                if (!isTermination) {
                    revert("SF: APP_RULE_CTX_IS_MALFORMATED");
                } else {
                    _jailApp(app, SuperAppDefinitions.APP_RULE_CTX_IS_MALFORMATED);
                }
            }
        }
    }

    function callAppAfterCallback(
        ISuperApp app,
        bytes calldata callData,
        bool isTermination,
        bytes calldata ctx
    )
        external override
        onlyAgreement
        assertValidCtx(ctx)
        returns(bytes memory newCtx)
    {
        (bool success, bytes memory returnedData) = _callCallback(app, false, isTermination, callData, ctx);
        if (success) {
            // the non static callback should not return empty ctx
            if (CallUtils.isValidAbiEncodedBytes(returnedData)) {
                newCtx = abi.decode(returnedData, (bytes));
                if (!_isCtxValid(newCtx)) {
                    if (!isTermination) {
                        revert("SF: APP_RULE_CTX_IS_READONLY");
                    } else {
                        newCtx = ctx;
                        _jailApp(app, SuperAppDefinitions.APP_RULE_CTX_IS_READONLY);
                    }
                }
            } else {
                if (!isTermination) {
                    revert("SF: APP_RULE_CTX_IS_MALFORMATED");
                } else {
                    newCtx = ctx;
                    _jailApp(app, SuperAppDefinitions.APP_RULE_CTX_IS_MALFORMATED);
                }
            }
        } else {
            newCtx = ctx;
        }
    }

    function appCallbackPush(
        bytes calldata ctx,
        ISuperApp app,
        uint256 appAllowanceGranted,
        int256 appAllowanceUsed,
        ISuperfluidToken appAllowanceToken
    )
        external override
        onlyAgreement
        assertValidCtx(ctx)
        returns (bytes memory appCtx)
    {
        Context memory context = decodeCtx(ctx);
        if (isApp(ISuperApp(context.msgSender))) {
            require(_compositeApps[ISuperApp(context.msgSender)][app],
                "SF: APP_RULE_COMPOSITE_APP_IS_NOT_WHITELISTED");
        }
        context.appLevel++;
        context.callType = ContextDefinitions.CALL_INFO_CALL_TYPE_APP_CALLBACK;
        context.appAllowanceGranted = appAllowanceGranted;
        context.appAllowanceWanted = 0;
        context.appAllowanceUsed = appAllowanceUsed;
        context.appAddress = address(app);
        context.appAllowanceToken = appAllowanceToken;
        appCtx = _updateContext(context);
    }

    function appCallbackPop(
        bytes calldata ctx,
        int256 appAllowanceUsedDelta
    )
        external override
        onlyAgreement
        returns (bytes memory newCtx)
    {
        Context memory context = decodeCtx(ctx);
        context.appAllowanceUsed = context.appAllowanceUsed + appAllowanceUsedDelta;
        newCtx = _updateContext(context);
    }

    function ctxUseAllowance(
        bytes calldata ctx,
        uint256 appAllowanceWantedMore,
        int256 appAllowanceUsedDelta
    )
        external override
        onlyAgreement
        assertValidCtx(ctx)
        returns (bytes memory newCtx)
    {
        Context memory context = decodeCtx(ctx);

        context.appAllowanceWanted = context.appAllowanceWanted + appAllowanceWantedMore;
        context.appAllowanceUsed = context.appAllowanceUsed + appAllowanceUsedDelta;

        newCtx = _updateContext(context);
    }

    function jailApp(
        bytes calldata ctx,
        ISuperApp app,
        uint256 reason
    )
        external override
        onlyAgreement
        assertValidCtx(ctx)
        returns (bytes memory newCtx)
    {
        _jailApp(app, reason);
        return ctx;
    }

    /**************************************************************************
    * Contextless Call Proxies
    *************************************************************************/

    function _callAgreement(
        address msgSender,
        ISuperAgreement agreementClass,
        bytes memory callData,
        bytes memory userData
    )
        internal
        cleanCtx
        isAgreement(agreementClass)
        returns(bytes memory returnedData)
    {
        // beaware of the endiness
        bytes4 agreementSelector = CallUtils.parseSelector(callData);

        //Build context data
        bytes memory  ctx = _updateContext(Context({
            appLevel: isApp(ISuperApp(msgSender)) ? 1 : 0,
            callType: ContextDefinitions.CALL_INFO_CALL_TYPE_AGREEMENT,
            timestamp: getNow(),
            msgSender: msgSender,
            agreementSelector: agreementSelector,
            userData: userData,
            appAllowanceGranted: 0,
            appAllowanceWanted: 0,
            appAllowanceUsed: 0,
            appAddress: address(0),
            appAllowanceToken: ISuperfluidToken(address(0))
        }));
        bool success;
        (success, returnedData) = _callExternalWithReplacedCtx(address(agreementClass), callData, ctx);
        if (!success) {
            CallUtils.revertFromReturnedData(returnedData);
        }
        // clear the stamp
        _ctxStamp = 0;
    }

    function callAgreement(
        ISuperAgreement agreementClass,
        bytes memory callData,
        bytes memory userData
    )
        external override
        returns(bytes memory returnedData)
    {
        return _callAgreement(msg.sender, agreementClass, callData, userData);
    }

    function _callAppAction(
        address msgSender,
        ISuperApp app,
        bytes memory callData
    )
        internal
        cleanCtx
        isAppActive(app)
        isValidAppAction(callData)
        returns(bytes memory returnedData)
    {
        //Build context data
        bytes memory ctx = _updateContext(Context({
            appLevel: isApp(ISuperApp(msgSender)) ? 1 : 0,
            callType: ContextDefinitions.CALL_INFO_CALL_TYPE_APP_ACTION,
            timestamp: getNow(),
            msgSender: msgSender,
            agreementSelector: 0,
            userData: "",
            appAllowanceGranted: 0,
            appAllowanceWanted: 0,
            appAllowanceUsed: 0,
            appAddress: address(app),
            appAllowanceToken: ISuperfluidToken(address(0))
        }));
        bool success;
        (success, returnedData) = _callExternalWithReplacedCtx(address(app), callData, ctx);
        if (success) {
            ctx = abi.decode(returnedData, (bytes));
            require(_isCtxValid(ctx), "SF: APP_RULE_CTX_IS_READONLY");
        } else {
            CallUtils.revertFromReturnedData(returnedData);
        }
        // clear the stamp
        _ctxStamp = 0;
    }

    function callAppAction(
        ISuperApp app,
        bytes memory callData
    )
        external override // NOTE: modifiers are called in _callAppAction
        returns(bytes memory returnedData)
    {
        return _callAppAction(msg.sender, app, callData);
    }

    /**************************************************************************
     * Contextual Call Proxies
     *************************************************************************/

    function callAgreementWithContext(
        ISuperAgreement agreementClass,
        bytes calldata callData,
        bytes calldata userData,
        bytes calldata ctx
    )
        external override
        requireValidCtx(ctx)
        isAgreement(agreementClass)
        returns (bytes memory newCtx, bytes memory returnedData)
    {
        Context memory context = decodeCtx(ctx);
        require(context.appAddress == msg.sender,  "SF: callAgreementWithContext from wrong address");

        address oldSender = context.msgSender;
        context.msgSender = msg.sender;
        //context.agreementSelector =;
        context.userData = userData;
        newCtx = _updateContext(context);

        bool success;
        (success, returnedData) = _callExternalWithReplacedCtx(address(agreementClass), callData, newCtx);
        if (success) {
            (newCtx) = abi.decode(returnedData, (bytes));
            assert(_isCtxValid(newCtx));
            // back to old msg.sender
            context = decodeCtx(newCtx);
            context.msgSender = oldSender;
            newCtx = _updateContext(context);
        } else {
            CallUtils.revertFromReturnedData(returnedData);
        }
    }

    function callAppActionWithContext(
        ISuperApp app,
        bytes calldata callData,
        bytes calldata ctx
    )
        external override
        requireValidCtx(ctx)
        isAppActive(app)
        isValidAppAction(callData)
        returns(bytes memory newCtx)
    {
        Context memory context = decodeCtx(ctx);
        require(context.appAddress == msg.sender,  "SF: callAppActionWithContext from wrong address");

        address oldSender = context.msgSender;
        context.msgSender = msg.sender;
        newCtx = _updateContext(context);

        (bool success, bytes memory returnedData) = _callExternalWithReplacedCtx(address(app), callData, newCtx);
        if (success) {
            (newCtx) = abi.decode(returnedData, (bytes));
            require(_isCtxValid(newCtx), "SF: APP_RULE_CTX_IS_READONLY");
            // back to old msg.sender
            context = decodeCtx(newCtx);
            context.msgSender = oldSender;
            newCtx = _updateContext(context);
        } else {
            CallUtils.revertFromReturnedData(returnedData);
        }
    }

    function decodeCtx(bytes memory ctx)
        public pure override
        returns (Context memory context)
    {
        return _decodeCtx(ctx);
    }

    function isCtxValid(bytes calldata ctx)
        external view override
        returns (bool)
    {
        return _isCtxValid(ctx);
    }

    /**************************************************************************
    * Batch call
    **************************************************************************/

    function _batchCall(
        address msgSender,
        Operation[] memory operations
    )
       internal
    {
        for(uint256 i = 0; i < operations.length; i++) {
            uint32 operationType = operations[i].operationType;
            if (operationType == BatchOperation.OPERATION_TYPE_ERC20_APPROVE) {
                (address spender, uint256 amount) =
                    abi.decode(operations[i].data, (address, uint256));
                ISuperToken(operations[i].target).operationApprove(
                    msgSender,
                    spender,
                    amount);
            } else if (operationType == BatchOperation.OPERATION_TYPE_ERC20_TRANSFER_FROM) {
                (address sender, address receiver, uint256 amount) =
                    abi.decode(operations[i].data, (address, address, uint256));
                ISuperToken(operations[i].target).operationTransferFrom(
                    msgSender,
                    sender,
                    receiver,
                    amount);
            } else if (operationType == BatchOperation.OPERATION_TYPE_SUPERTOKEN_UPGRADE) {
                ISuperToken(operations[i].target).operationUpgrade(
                    msgSender,
                    abi.decode(operations[i].data, (uint256)));
            } else if (operationType == BatchOperation.OPERATION_TYPE_SUPERTOKEN_DOWNGRADE) {
                ISuperToken(operations[i].target).operationDowngrade(
                    msgSender,
                    abi.decode(operations[i].data, (uint256)));
            } else if (operationType == BatchOperation.OPERATION_TYPE_SUPERFLUID_CALL_AGREEMENT) {
                (bytes memory callData, bytes memory userData) = abi.decode(operations[i].data, (bytes, bytes));
                _callAgreement(
                    msgSender,
                    ISuperAgreement(operations[i].target),
                    callData,
                    userData);
            } else if (operationType == BatchOperation.OPERATION_TYPE_SUPERFLUID_CALL_APP_ACTION) {
                _callAppAction(
                    msgSender,
                    ISuperApp(operations[i].target),
                    operations[i].data);
            } else {
               revert("SF: unknown batch call operation type");
            }
        }
    }

    /// @dev ISuperfluid.batchCall implementation
    function batchCall(
       Operation[] memory operations
    )
       external override
    {
        _batchCall(msg.sender, operations);
    }

    /// @dev ISuperfluid.forwardBatchCall implementation
    function forwardBatchCall(Operation[] memory operations)
        external override
    {
        _batchCall(_getTransactionSigner(), operations);
    }

    /// @dev BaseRelayRecipient.isTrustedForwarder implementation
    function isTrustedForwarder(address forwarder)
        public view override
        returns(bool)
    {
        return _gov.getConfigAsUint256(
            this,
            ISuperfluidToken(address(0)),
            SuperfluidGovernanceConfigs.getTrustedForwarderConfigKey(forwarder)
        ) != 0;
    }

    /// @dev IRelayRecipient.isTrustedForwarder implementation
    function versionRecipient()
        external override pure
        returns (string memory)
    {
        return "v1";
    }

    /**************************************************************************
    * Internal
    **************************************************************************/

    function _jailApp(ISuperApp app, uint256 reason)
        internal
    {
        if ((_appManifests[app].configWord & SuperAppDefinitions.APP_JAIL_BIT) == 0) {
            _appManifests[app].configWord |= SuperAppDefinitions.APP_JAIL_BIT;
            emit Jail(app, reason);
        }
    }

    function _updateContext(Context memory context)
        private
        returns (bytes memory ctx)
    {
        require(context.appLevel <= MAX_APP_LEVEL, "SF: APP_RULE_MAX_APP_LEVEL_REACHED");
        uint256 callInfo = ContextDefinitions.encodeCallInfo(context.appLevel, context.callType);
        uint256 allowanceIO =
            context.appAllowanceGranted.toUint128() |
            (uint256(context.appAllowanceWanted.toUint128()) << 128);
        // NOTE: nested encoding done due to stack too deep error when decoding in _decodeCtx
        ctx = abi.encode(
            abi.encode(
                callInfo,
                context.timestamp,
                context.msgSender,
                context.agreementSelector,
                context.userData
            ),
            abi.encode(
                allowanceIO,
                context.appAllowanceUsed,
                context.appAddress,
                context.appAllowanceToken
            )
        );
        _ctxStamp = keccak256(ctx);
    }

    function _decodeCtx(bytes memory ctx)
        private pure
        returns (Context memory context)
    {
        bytes memory ctx1;
        bytes memory ctx2;
        (ctx1, ctx2) = abi.decode(ctx, (bytes, bytes));
        {
            uint256 callInfo;
            (
                callInfo,
                context.timestamp,
                context.msgSender,
                context.agreementSelector,
                context.userData
            ) = abi.decode(ctx1, (
                uint256,
                uint256,
                address,
                bytes4,
                bytes));
            (context.appLevel, context.callType) = ContextDefinitions.decodeCallInfo(callInfo);
        }
        {
            uint256 allowanceIO;
            (
                allowanceIO,
                context.appAllowanceUsed,
                context.appAddress,
                context.appAllowanceToken
            ) = abi.decode(ctx2, (
                uint256,
                int256,
                address,
                ISuperfluidToken));
            context.appAllowanceGranted = allowanceIO & type(uint128).max;
            context.appAllowanceWanted = allowanceIO >> 128;
        }
    }

    function _isCtxValid(bytes memory ctx) private view returns (bool) {
        return ctx.length != 0 && keccak256(ctx) == _ctxStamp;
    }

    function _callExternalWithReplacedCtx(
        address target,
        bytes memory callData,
        bytes memory ctx
    )
        private
        returns(bool success, bytes memory returnedData)
    {
        assert(target != address(0));

        // STEP 1 : replace placeholder ctx with actual ctx
        callData = _replacePlaceholderCtx(callData, ctx);

        // STEP 2: Call external with replaced context
        // FIXME make sure existence of target due to EVM rule
        /* solhint-disable-next-line avoid-low-level-calls */
        (success, returnedData) = target.call(callData);

        if (success) {
            require(returnedData.length > 0, "SF: APP_RULE_CTX_IS_EMPTY");
        }
    }

    function _callCallback(
        ISuperApp app,
        bool isStaticall,
        bool isTermination,
        bytes memory callData,
        bytes memory ctx
    )
        private
        returns(bool success, bytes memory returnedData)
    {
        assert(address(app) != address(0));

        callData = _replacePlaceholderCtx(callData, ctx);

        uint256 gasLeftBefore = gasleft();
        if (isStaticall) {
            /* solhint-disable-next-line avoid-low-level-calls*/
            (success, returnedData) = address(app).staticcall{ gas: CALLBACK_GAS_LIMIT }(callData);
        } else {
            /* solhint-disable-next-line avoid-low-level-calls*/
            (success, returnedData) = address(app).call{ gas: CALLBACK_GAS_LIMIT }(callData);
        }

        if (!success) {
            // "/ 63" is a magic to avoid out of gas attack. See https://ronan.eth.link/blog/ethereum-gas-dangers/.
            // A callback may use this to block the APP_RULE_NO_REVERT_ON_TERMINATION_CALLBACK jail rule.
            if (gasleft() > gasLeftBefore / 63) {
                if (!isTermination) {
                    CallUtils.revertFromReturnedData(returnedData);
                } else {
                    _jailApp(app, SuperAppDefinitions.APP_RULE_NO_REVERT_ON_TERMINATION_CALLBACK);
                }
            } else {
                // For legit out of gas issue, the call may still fail if more gas is provied
                // and this is okay, because there can be incentive to jail the app by providing
                // more gas.
                revert("SF: need more gas");
            }
        }
    }

    /**
     * @dev Replace the placeholder ctx with the actual ctx
     */
    function _replacePlaceholderCtx(bytes memory data, bytes memory ctx)
        internal pure
        returns (bytes memory dataWithCtx)
    {
        // 1.a ctx needs to be padded to align with 32 bytes boundary
        uint256 dataLen = data.length;

        // Double check if the ctx is a placeholder ctx
        //
        // NOTE: This can't check all cases - user can still put nonzero length of zero data
        // developer experience check. So this is more like a sanity check for clumsy app developers.
        //
        // So, agreements MUST NOT TRUST the ctx passed to it, and always use the isCtxValid first.
        {
            uint256 placeHolderCtxLength;
            // NOTE: len(data) is data.length + 32 https://docs.soliditylang.org/en/latest/abi-spec.html
            // solhint-disable-next-line no-inline-assembly
            assembly { placeHolderCtxLength := mload(add(data, dataLen)) }
            require(placeHolderCtxLength == 0, "SF: placerholder ctx should have zero length");
        }

        // 1.b remove the placeholder ctx
        // solhint-disable-next-line no-inline-assembly
        assembly { mstore(data, sub(dataLen, 0x20)) }

        // 1.c pack data with the replacement ctx
        return abi.encodePacked(
            data,
            // bytes with padded length
            uint256(ctx.length),
            ctx, new bytes(CallUtils.padLength32(ctx.length) - ctx.length) // ctx padding
        );
        // NOTE: the alternative placeholderCtx is passing extra calldata to the agreements
        // agreements would use assembly code to read the ctx
        // Because selector is part of calldata, we do the padding internally, instead of
        // outside
    }

    modifier requireValidCtx(bytes memory ctx) {
        require(_isCtxValid(ctx), "SF: APP_RULE_CTX_IS_NOT_VALID");
        _;
    }

    modifier assertValidCtx(bytes memory ctx) {
        assert(_isCtxValid(ctx));
        _;
    }

    modifier cleanCtx() {
        require(_ctxStamp == 0, "SF: APP_RULE_CTX_IS_NOT_CLEAN");
        _;
    }

    modifier isAgreement(ISuperAgreement agreementClass) {
        require(isAgreementClassListed(agreementClass), "SF: only listed agreeement allowed");
        _;
    }

    modifier onlyGovernance() {
        require(msg.sender == address(_gov), "SF: only governance allowed");
        _;
    }

    modifier onlyAgreement() {
        require(isAgreementClassListed(ISuperAgreement(msg.sender)), "SF: sender is not listed agreeement");
        _;
    }

    modifier isAppActive(ISuperApp app) {
        uint256 w = _appManifests[app].configWord;
        require(w > 0, "SF: not a super app");
        require(!SuperAppDefinitions.isAppJailed(w), "SF: app is jailed");
        _;
    }

    modifier isValidAppAction(bytes memory callData) {
        bytes4 actionSelector = CallUtils.parseSelector(callData);
        if (actionSelector == ISuperApp.beforeAgreementCreated.selector ||
            actionSelector == ISuperApp.afterAgreementCreated.selector ||
            actionSelector == ISuperApp.beforeAgreementUpdated.selector ||
            actionSelector == ISuperApp.afterAgreementUpdated.selector ||
            actionSelector == ISuperApp.beforeAgreementTerminated.selector ||
            actionSelector == ISuperApp.afterAgreementTerminated.selector) {
            revert("SF: agreement callback is not action");
        }
        _;
    }
}

File 2 of 23 : UUPSUtils.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.14;

/**
 * @title UUPS (Universal Upgradeable Proxy Standard) Shared Library
 */
library UUPSUtils {

    /**
     * @dev Implementation slot constant.
     * Using https://eips.ethereum.org/EIPS/eip-1967 standard
     * Storage slot 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
     * (obtained as bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)).
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /// @dev Get implementation address.
    function implementation() internal view returns (address impl) {
        assembly { // solium-disable-line
            impl := sload(_IMPLEMENTATION_SLOT)
        }
    }

    /// @dev Set new implementation address.
    function setImplementation(address codeAddress) internal {
        assembly {
            // solium-disable-line
            sstore(
                _IMPLEMENTATION_SLOT,
                codeAddress
            )
        }
    }

}

File 3 of 23 : UUPSProxy.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.14;

import { UUPSUtils } from "./UUPSUtils.sol";
import { Proxy } from "@openzeppelin/contracts/proxy/Proxy.sol";


/**
 * @title UUPS (Universal Upgradeable Proxy Standard) Proxy
 *
 * NOTE:
 * - Compliant with [Universal Upgradeable Proxy Standard](https://eips.ethereum.org/EIPS/eip-1822)
 * - Compiiant with [Standard Proxy Storage Slots](https://eips.ethereum.org/EIPS/eip-1967)
 * - Implements delegation of calls to other contracts, with proper forwarding of
 *   return values and bubbling of failures.
 * - It defines a fallback function that delegates all calls to the implementation.
 */
contract UUPSProxy is Proxy {

    /**
     * @dev Proxy initialization function.
     *      This should only be called once and it is permission-less.
     * @param initialAddress Initial logic contract code address to be used.
     */
    function initializeProxy(address initialAddress) external {
        require(initialAddress != address(0), "UUPSProxy: zero address");
        require(UUPSUtils.implementation() == address(0), "UUPSProxy: already initialized");
        UUPSUtils.setImplementation(initialAddress);
    }

    /// @dev Proxy._implementation implementation
    function _implementation() internal virtual override view returns (address)
    {
        return UUPSUtils.implementation();
    }

}

File 4 of 23 : UUPSProxiable.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.14;

import { UUPSUtils } from "./UUPSUtils.sol";
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";

/**
 * @title UUPS (Universal Upgradeable Proxy Standard) Proxiable contract.
 */
abstract contract UUPSProxiable is Initializable {

    /**
     * @dev Get current implementation code address.
     */
    function getCodeAddress() public view returns (address codeAddress)
    {
        return UUPSUtils.implementation();
    }

    function updateCode(address newAddress) external virtual;

    /**
     * @dev Proxiable UUID marker function, this would help to avoid wrong logic
     *      contract to be used for upgrading.
     *
     * NOTE: The semantics of the UUID deviates from the actual UUPS standard,
     *       where it is equivalent of _IMPLEMENTATION_SLOT.
     */
    function proxiableUUID() public view virtual returns (bytes32);

    /**
     * @dev Update code address function.
     *      It is internal, so the derived contract could setup its own permission logic.
     */
    function _updateCodeAddress(address newAddress) internal
    {
        // require UUPSProxy.initializeProxy first
        require(UUPSUtils.implementation() != address(0), "UUPSProxiable: not upgradable");
        require(
            proxiableUUID() == UUPSProxiable(newAddress).proxiableUUID(),
            "UUPSProxiable: not compatible logic"
        );
        require(
            address(this) != newAddress,
            "UUPSProxiable: proxy loop"
        );
        UUPSUtils.setImplementation(newAddress);
        emit CodeUpdated(proxiableUUID(), newAddress);
    }

    event CodeUpdated(bytes32 uuid, address codeAddress);

}

File 5 of 23 : CallUtils.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.14;

/**
 * @title Call utilities library that is absent from the OpenZeppelin
 * @author Superfluid
 */
library CallUtils {

    /// @dev Bubble up the revert from the returnedData (supports Panic, Error & Custom Errors)
    /// @notice This is needed in order to provide some human-readable revert message from a call
    /// @param returnedData Response of the call
    function revertFromReturnedData(bytes memory returnedData) internal pure {
        if (returnedData.length < 4) {
            // case 1: catch all
            revert("CallUtils: target revert()");
        } else {
            bytes4 errorSelector;
            assembly {
                errorSelector := mload(add(returnedData, 0x20))
            }
            if (errorSelector == bytes4(0x4e487b71) /* `seth sig "Panic(uint256)"` */) {
                // case 2: Panic(uint256) (Defined since 0.8.0)
                // solhint-disable-next-line max-line-length
                // ref: https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require)
                string memory reason = "CallUtils: target panicked: 0x__";
                uint errorCode;
                assembly {
                    errorCode := mload(add(returnedData, 0x24))
                    let reasonWord := mload(add(reason, 0x20))
                    // [0..9] is converted to ['0'..'9']
                    // [0xa..0xf] is not correctly converted to ['a'..'f']
                    // but since panic code doesn't have those cases, we will ignore them for now!
                    let e1 := add(and(errorCode, 0xf), 0x30)
                    let e2 := shl(8, add(shr(4, and(errorCode, 0xf0)), 0x30))
                    reasonWord := or(
                        and(reasonWord, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000),
                        or(e2, e1))
                    mstore(add(reason, 0x20), reasonWord)
                }
                revert(reason);
            } else {
                // case 3: Error(string) (Defined at least since 0.7.0)
                // case 4: Custom errors (Defined since 0.8.0)
                uint len = returnedData.length;
                assembly {
                    revert(add(returnedData, 32), len)
                }
            }
        }
    }

    /**
    * @dev Helper method to parse data and extract the method signature (selector).
    *
    * Copied from: https://github.com/argentlabs/argent-contracts/
    * blob/master/contracts/modules/common/Utils.sol#L54-L60
    */
    function parseSelector(bytes memory callData) internal pure returns (bytes4 selector) {
        require(callData.length >= 4, "CallUtils: invalid callData");
        // solhint-disable-next-line no-inline-assembly
        assembly {
            selector := mload(add(callData, 0x20))
        }
    }

    /**
     * @dev Pad length to 32 bytes word boundary
     */
    function padLength32(uint256 len) internal pure returns (uint256 paddedLen) {
        return ((len / 32) +  (((len & 31) > 0) /* rounding? */ ? 1 : 0)) * 32;
    }

    /**
     * @dev Validate if the data is encoded correctly with abi.encode(bytesData)
     *
     * Expected ABI Encode Layout:
     * | word 1      | word 2           | word 3           | the rest...
     * | data length | bytesData offset | bytesData length | bytesData + padLength32 zeros |
     */
    function isValidAbiEncodedBytes(bytes memory data) internal pure returns (bool) {
        if (data.length < 64) return false;
        uint bytesOffset;
        uint bytesLen;
        // bytes offset is always expected to be 32
        assembly { bytesOffset := mload(add(data, 32)) }
        if (bytesOffset != 32) return false;
        assembly { bytesLen := mload(add(data, 64)) }
        // the data length should be bytesData.length + 64 + padded bytes length
        return data.length == 64 + padLength32(bytesLen);
    }

}

File 6 of 23 : BaseRelayRecipient.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.14;

import "../interfaces/utils/IRelayRecipient.sol";


/**
 * @title Base relay recipient contract
 * @author Superfluid
 * @dev A base contract to be inherited by any contract that want to receive relayed transactions
 *      A subclass must use "_msgSender()" instead of "msg.sender"
 *      MODIFIED FROM: https://github.com/opengsn/forwarder/blob/master/contracts/BaseRelayRecipient.sol
 */
abstract contract BaseRelayRecipient is IRelayRecipient {

    /**
     * @dev Check if the forwarder is trusted
     */
    function isTrustedForwarder(address forwarder) public view virtual override returns(bool);

    /**
     * @dev Return the transaction signer of this call
     *
     * if the call came through our trusted forwarder, return the original sender.
     * otherwise, return `msg.sender`.
     * should be used in the contract anywhere instead of msg.sender
     */
    function _getTransactionSigner() internal virtual view returns (address payable ret) {
        require(msg.data.length >= 24 && isTrustedForwarder(msg.sender), "Not trusted forwarder");
        // At this point we know that the sender is a trusted forwarder,
        // so we trust that the last bytes of msg.data are the verified sender address.
        // extract sender address from the end of msg.data
        assembly {
            ret := shr(96,calldataload(sub(calldatasize(),20)))
        }
    }

}

File 7 of 23 : IRelayRecipient.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.8.0;

// MODIFIED FROM: https://github.com/opengsn/forwarder/blob/master/contracts/interfaces/IRelayRecipient.sol

/**
 * @title Relay recipient interface
 * @author Superfluid
 * @dev A contract must implement this interface in order to support relayed transactions
 * @dev It is better to inherit the BaseRelayRecipient as its implementation
 */
interface IRelayRecipient {

    /**
     * @notice Returns if the forwarder is trusted to forward relayed transactions to us.
     * @dev the forwarder is required to verify the sender's signature, and verify
     *      the call is not a replay.
     */
    function isTrustedForwarder(address forwarder) external view returns(bool);

    /**
     * @dev EIP 2771 version
     *
     * NOTE:
     * - It is not clear if it is actually from the EIP 2771....
     * - https://docs.biconomy.io/guides/enable-gasless-transactions/eip-2771
     */
    function versionRecipient() external view returns (string memory);
}

File 8 of 23 : TokenInfo.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.8.0;

/**
 * @title ERC20 token info interface
 * @author Superfluid
 * @dev 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 9 of 23 : ERC20WithTokenInfo.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.8.0;

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

/**
 * @title ERC20 token with token info interface
 * @author Superfluid
 * @dev 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 {}

File 10 of 23 : ISuperfluidToken.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.8.0;

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


/**
 * @title Superfluid 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
     *
     * @custom: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);

    /**
     * @notice Calculate the realtime balance given the current host.getNow() value
     * @dev realtimeBalanceOf with timestamp equals to block timestamp
     * @param account for the query
     * @return availableBalance Real-time balance
     * @return deposit Account deposit
     * @return owedDeposit Account owed Deposit
     */
    function realtimeBalanceOfNow(
       address account
    )
        external view
        returns (
            int256 availableBalance,
            uint256 deposit,
            uint256 owedDeposit,
            uint256 timestamp);

    /**
    * @notice Check if account is critical
    * @dev A critical account is when availableBalance < 0
    * @param account The account to check
    * @param timestamp The time we'd like to check if the account is critical (should use future)
    * @return isCritical Whether the account is critical
    */
    function isAccountCritical(
        address account,
        uint256 timestamp
    )
        external view
        returns(bool isCritical);

    /**
    * @notice Check if account is critical now (current host.getNow())
    * @dev A critical account is when availableBalance < 0
    * @param account The account to check
    * @return isCritical Whether the account is critical
    */
    function isAccountCriticalNow(
        address account
    )
        external view
        returns(bool isCritical);

    /**
     * @notice Check if account is solvent
     * @dev An account is insolvent when the sum of deposits for a token can't cover the negative availableBalance
     * @param account The account to check
     * @param timestamp The time we'd like to check if the account is solvent (should use future)
     * @return isSolvent True if the account is solvent, false otherwise
     */
    function isAccountSolvent(
        address account,
        uint256 timestamp
    )
        external view
        returns(bool isSolvent);

    /**
     * @notice Check if account is solvent now
     * @dev An account is insolvent when the sum of deposits for a token can't cover the negative availableBalance
     * @param account The account to check
     * @return isSolvent True if the account is solvent, false otherwise
     */
    function isAccountSolventNow(
        address account
    )
        external view
        returns(bool isSolvent);

    /**
    * @notice 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 created 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 updated 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 terminated 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
     *
     * @custom: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 an 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);

    /**
     * @notice Settle balance from an account by the agreement
     * @dev 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
     *
     * @custom:modifiers 
     *  - onlyAgreement
     */
    function settleBalance(
        address account,
        int256 delta
    )
        external;

    /**
     * @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 to be liquidated
     * @param rewardAmount The amount the rewarded account will receive
     * @param targetAccountBalanceDelta The delta amount the target account balance should change by
     *
     * @custom:note 
     * - 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
     *
     * @custom:modifiers 
     *  - onlyAgreement
     */
    function makeLiquidationPayoutsV2
    (
        bytes32 id,
        bytes memory liquidationTypeData,
        address liquidatorAccount,
        bool useDefaultRewardAccount,
        address targetAccount,
        uint256 rewardAmount,
        int256 targetAccountBalanceDelta
    ) 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 rewardAmountReceiver 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)
     *
     * @custom:note 
     * Reward account rule:
     * - if the agreement is liquidated during the PIC period
     *   - the rewardAmountReceiver 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 rewardAmountReceiver 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 default reward account (governance) 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 rewardAmountReceiver,
        uint256 rewardAmount,
        int256 targetAccountBalanceDelta,
        bytes liquidationTypeData
    );

    /**************************************************************************
     * 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;

    /**************************************************************************
     * DEPRECATED
     *************************************************************************/

    /**
     * @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
     *
     * @custom:deprecated Use AgreementLiquidatedV2 instead
     */
    event AgreementLiquidated(
        address indexed agreementClass,
        bytes32 id,
        address indexed penaltyAccount,
        address indexed rewardAccount,
        uint256 rewardAmount
    );

    /**
     * @dev System bailout occurred (DEPRECATED BY AgreementLiquidatedBy)
     * @param bailoutAccount Account that bailout the penalty account
     * @param bailoutAmount Amount of account bailout
     *
     * @custom:deprecated Use AgreementLiquidatedV2 instead
     */
    event Bailout(
        address indexed bailoutAccount,
        uint256 bailoutAmount
    );

    /**
     * @dev Agreement liquidation event (DEPRECATED BY AgreementLiquidatedV2)
     * @param liquidatorAccount Account of the agent that performed the liquidation.
     * @param agreementClass Contract address of the agreement
     * @param id Agreement ID
     * @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
     *
     * @custom:deprecated Use AgreementLiquidatedV2 instead
     *
     * @custom: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
    );
}

File 11 of 23 : ISuperfluidGovernance.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.8.0;

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


/**
 * @title Superfluid 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
     *
     * @custom: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 Set configuration as address value
     */
    function setConfig(
        ISuperfluid host,
        ISuperfluidToken superToken,
        bytes32 key,
        address value
    ) external;
    
    /**
     * @dev Set configuration as uint256 value
     */
    function setConfig(
        ISuperfluid host,
        ISuperfluidToken superToken,
        bytes32 key,
        uint256 value
    ) external;

    /**
     * @dev Clear configuration
     */
    function clearConfig(
        ISuperfluid host,
        ISuperfluidToken superToken,
        bytes32 key
    ) 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 12 of 23 : ISuperfluid.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.8.2;

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 {
    BatchOperation,
    ContextDefinitions,
    FlowOperatorDefinitions,
    SuperAppDefinitions,
    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";

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

    /**************************************************************************
     * Time
     *
     * > The Oracle: You have the sight now, Neo. You are looking at the world without time.
     * > Neo: Then why can't I see what happens to her?
     * > The Oracle: We can never see past the choices we don't understand.
     * >       - The Oracle and Neo conversing about the future of Trinity and the effects of Neo's choices
     *************************************************************************/

    function getNow() external view returns (uint256);

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

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

    /**
     * @dev Replace the current governance with a new one
     */
    function replaceGovernance(ISuperfluidGovernance newGov) external;
    /**
     * @dev Governance replaced event
     * @param oldGov Address of the old governance contract
     * @param newGov Address of the new governance contract
     */
    event GovernanceReplaced(ISuperfluidGovernance oldGov, ISuperfluidGovernance newGov);

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

    /**
     * @dev Register a new agreement class to the system
     * @param agreementClassLogic Initial agreement class code
     *
     * @custom:modifiers 
     * - onlyGovernance
     */
    function registerAgreementClass(ISuperAgreement agreementClassLogic) external;
    /**
     * @notice Agreement class registered event
     * @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
     * @param agreementType The agreement type registered
     * @param code Address of the new agreement
     */
    event AgreementClassRegistered(bytes32 agreementType, address code);

    /**
    * @dev Update code of an agreement class
    * @param agreementClassLogic New code for the agreement class
    *
    * @custom:modifiers 
    *  - onlyGovernance
    */
    function updateAgreementClass(ISuperAgreement agreementClassLogic) external;
    /**
     * @notice Agreement class updated event
     * @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
     * @param agreementType The agreement type updated
     * @param code Address of the new agreement
     */
    event AgreementClassUpdated(bytes32 agreementType, address code);

    /**
    * @notice Check if the agreement type is whitelisted
    * @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
    */
    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);

    /**
    * @notice Get agreement class
    * @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
    */
    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);

    /**
    * @notice Create a new bitmask by adding a agreement class to it
    * @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
    * @param bitmap Agreement class bitmap
    */
    function addToAgreementClassesBitmap(uint256 bitmap, bytes32 agreementType)
        external view
        returns (uint256 newBitmap);

    /**
    * @notice Create a new bitmask by removing a agreement class from it
    * @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
    * @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);

    /**
     * @dev Update super token factory
     * @param newFactory New factory logic
     */
    function updateSuperTokenFactory(ISuperTokenFactory newFactory) external;
    /**
     * @dev SuperToken factory updated event
     * @param newFactory Address of the new factory
     */
    event SuperTokenFactoryUpdated(ISuperTokenFactory newFactory);

    /**
     * @notice Update the super token logic to the latest
     * @dev Refer to ISuperTokenFactory.Upgradability for expected behaviours
     */
    function updateSuperTokenLogic(ISuperToken token) external;
    /**
     * @dev SuperToken logic updated event
     * @param code Address of the new SuperToken logic
     */
    event SuperTokenLogicUpdated(ISuperToken indexed token, address code);

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

    /**
     * @dev Message sender (must be a contract) declares itself as a super app.
     * @custom:deprecated you should use `registerAppWithKey` or `registerAppByFactory` instead,
     * because app registration is currently governance permissioned on mainnets.
     * @param configWord The super app manifest configuration, flags are defined in
     * `SuperAppDefinitions`
     */
    function registerApp(uint256 configWord) external;
    /**
     * @dev App registered event
     * @param app Address of jailed app
     */
    event AppRegistered(ISuperApp indexed app);

    /**
     * @dev Message sender declares itself as a super app.
     * @param configWord The super app manifest configuration, flags are defined in `SuperAppDefinitions`
     * @param registrationKey The registration key issued by the governance, needed to register on a mainnet.
     * @notice See https://github.com/superfluid-finance/protocol-monorepo/wiki/Super-App-White-listing-Guide
     * On testnets or in dev environment, a placeholder (e.g. empty string) can be used.
     * While the message sender must be the super app itself, the transaction sender (tx.origin)
     * must be the deployer account the registration key was issued for.
     */
    function registerAppWithKey(uint256 configWord, string calldata registrationKey) external;

    /**
     * @dev Message sender (must be a contract) declares app as a super app
     * @param configWord The super app manifest configuration, flags are defined in `SuperAppDefinitions`
     * @notice On mainnet deployments, only factory contracts pre-authorized by governance can use this.
     * See https://github.com/superfluid-finance/protocol-monorepo/wiki/Super-App-White-listing-Guide
     */
    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 Whitelist the target app for app composition for the source app (msg.sender)
     * @param targetApp The target 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 target 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.
     *************************************************************************/

    /**
     * @dev (For agreements) StaticCall the app before callback
     * @param  app               The super app.
     * @param  callData          The call data sending to the super app.
     * @param  isTermination     Is it a termination callback?
     * @param  ctx               Current ctx, it will be validated.
     * @return cbdata            Data returned from the callback.
     */
    function callAppBeforeCallback(
        ISuperApp app,
        bytes calldata callData,
        bool isTermination,
        bytes calldata ctx
    )
        external
        // onlyAgreement
        // assertValidCtx(ctx)
        returns(bytes memory cbdata);

    /**
     * @dev (For agreements) Call the app after callback
     * @param  app               The super app.
     * @param  callData          The call data sending to the super app.
     * @param  isTermination     Is it a termination callback?
     * @param  ctx               Current ctx, it will be validated.
     * @return newCtx            The current context of the transaction.
     */
    function callAppAfterCallback(
        ISuperApp app,
        bytes calldata callData,
        bool isTermination,
        bytes calldata ctx
    )
        external
        // onlyAgreement
        // assertValidCtx(ctx)
        returns(bytes memory newCtx);

    /**
     * @dev (For agreements) Create a new callback stack
     * @param  ctx                     The current ctx, it will be validated.
     * @param  app                     The super app.
     * @param  appAllowanceGranted     App allowance granted so far.
     * @param  appAllowanceUsed        App allowance used so far.
     * @return newCtx                  The current context of the transaction.
     */
    function appCallbackPush(
        bytes calldata ctx,
        ISuperApp app,
        uint256 appAllowanceGranted,
        int256 appAllowanceUsed,
        ISuperfluidToken appAllowanceToken
    )
        external
        // onlyAgreement
        // assertValidCtx(ctx)
        returns (bytes memory newCtx);

    /**
     * @dev (For agreements) Pop from the current app callback stack
     * @param  ctx                     The ctx that was pushed before the callback stack.
     * @param  appAllowanceUsedDelta   App allowance used by the app.
     * @return newCtx                  The current context of the transaction.
     *
     * @custom:security 
     * - Here we cannot do assertValidCtx(ctx), since we do not really save the stack in memory.
     * - Hence there is still implicit trust that the agreement handles the callback push/pop pair correctly.
     */
    function appCallbackPop(
        bytes calldata ctx,
        int256 appAllowanceUsedDelta
    )
        external
        // onlyAgreement
        returns (bytes memory newCtx);

    /**
     * @dev (For agreements) Use app allowance.
     * @param  ctx                      The current ctx, it will be validated.
     * @param  appAllowanceWantedMore   See app allowance for more details.
     * @param  appAllowanceUsedDelta    See app allowance for more details.
     * @return newCtx                   The current context of the transaction.
     */
    function ctxUseAllowance(
        bytes calldata ctx,
        uint256 appAllowanceWantedMore,
        int256 appAllowanceUsedDelta
    )
        external
        // onlyAgreement
        // assertValidCtx(ctx)
        returns (bytes memory newCtx);

    /**
     * @dev (For agreements) Jail the app.
     * @param  app                     The super app.
     * @param  reason                  Jail reason code.
     * @return newCtx                  The current context of the transaction.
     */
    function jailApp(
        bytes calldata ctx,
        ISuperApp app,
        uint256 reason
    )
        external
        // onlyAgreement
        // assertValidCtx(ctx)
        returns (bytes memory newCtx);

    /**
     * @dev Jail event for the app
     * @param app Address of jailed app
     * @param reason Reason the app is jailed (see Definitions.sol for the full list)
     */
    event Jail(ISuperApp indexed app, uint256 reason);

    /**************************************************************************
     * 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 agreementClass The agreement address you are calling
      * @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
        //isAgreement(agreementClass)
        returns(bytes memory returnedData);

    /**
     * @notice Call app action
     * @dev Main use case is calling app action in a batch call via the host
     * @param callData The contextual call data
     *
     * @custom:note See "Contextless Call Proxies" above for more about contextual call data.
     */
    function callAppAction(
        ISuperApp app,
        bytes calldata callData
    )
        external
        //cleanCtx
        //isAppActive(app)
        //isValidAppAction(callData)
        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 Context Struct
     *
     * @custom: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 timestamp
        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
        // requireValidCtx(ctx)
        // onlyAgreement(agreementClass)
        returns (bytes memory newCtx, bytes memory returnedData);

    function callAppActionWithContext(
        ISuperApp app,
        bytes calldata callData,
        bytes calldata ctx
    )
        external
        // requireValidCtx(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 type. 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 doesn't like it
     *************************************************************************/

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

     /// @dev Require the ctx being valid.
     modifier requireValidCtx(bytes memory ctx) virtual;

     /// @dev Assert the ctx being valid.
     modifier assertValidCtx(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 13 of 23 : ISuperTokenFactory.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.8.0;

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

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

/**
 * @title Super token factory interface
 * @author Superfluid
 */
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;

    /**
      * @dev Super token logic created event
      * @param tokenLogic Token logic address
      */
    event SuperTokenLogicCreated(ISuperToken indexed tokenLogic);

    /**
      * @dev Super token created event
      * @param token Newly created super token address
      */
    event SuperTokenCreated(ISuperToken indexed token);

    /**
      * @dev Custom super token created event
      * @param token Newly created custom super token address
      */
    event CustomSuperTokenCreated(ISuperToken indexed token);

}

File 14 of 23 : ISuperToken.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.8.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 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.
     *
     * @custom:note SuperToken always uses 18 decimals.
     *
     * 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`.
     *
     * @return Returns Success a boolean value indicating whether the operation succeeded.
     *
     * @custom: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.
     *
     * @notice 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.
     *
     * @return Returns Success a boolean value indicating whether the operation succeeded.
     *
     * @custom:note 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
     *
     * @custom: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.
     *
     * @return Returns Success a boolean value indicating whether the operation succeeded.
     *
     * @custom: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}.
     *
     * @custom:emits an {Approval} event indicating the updated allowance.
     *
     * @custom: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}.
     *
     * @custom:emits an {Approval} event indicating the updated allowance.
     *
     * @custom: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.
     *
     * @custom:note For super token contracts, this value is always 1
     */
    function granularity() external view override(IERC777) returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * @dev 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}.
     *
     * @custom:emits a {Sent} event.
     *
     * @custom: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}.
     *
     * @custom:emits a {Burned} event.
     *
     * @custom: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}.
     *
     * @custom:emits an {AuthorizedOperator} event.
     *
     * @custom: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}.
     *
     * @custom:emits a {RevokedOperator} event.
     *
     * @custom: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}.
     *
     * @custom:emits a {Sent} event.
     *
     * @custom: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}.
     *
     * @custom:emits a {Burned} event.
     *
     * @custom: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
     *
     * @custom:modifiers 
     *  - onlySelf
     */
    function selfMint(
        address account,
        uint256 amount,
        bytes memory userData
    ) external;

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

   /**
    * @dev Transfer `amount` tokens from the `sender` to `recipient`.
    * If `spender` isn't the same as `sender`, checks if `spender` has allowance to
    * spend tokens of `sender`.
    *
    * @custom:modifiers 
    *  - onlySelf
    */
   function selfTransferFrom(
        address sender,
        address spender,
        address recipient,
        uint256 amount
   ) external;

   /**
    * @dev Give `spender`, `amount` allowance to spend the tokens of
    * `account`.
    *
    * @custom:modifiers 
    *  - onlySelf
    */
   function selfApproveFor(
        address account,
        address spender,
        uint256 amount
   ) 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)
     *
     * @custom: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
     *
     * @custom: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.
    *
    * @custom: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.
    *
    * @custom: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)
    *
    * @custom: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)
    *
    * @custom: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 15 of 23 : ISuperApp.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.8.0;

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

/**
 * @title SuperApp interface
 * @author Superfluid
 * @dev Be aware of the app being jailed, when the word permitted is used.
 */
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.
     *
     * @custom: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.
     *
     * @custom: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.
     *
     * @custom: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.
    *
    * @custom: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.
    *
    * @custom: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.
    *
    * @custom: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 23 : ISuperAgreement.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.8.0;

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

/**
 * @title Super agreement interface
 * @author Superfluid
 */
interface ISuperAgreement {

    /**
     * @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 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 17 of 23 : Definitions.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity >= 0.8.0;

/**
 * @title Super app definitions library
 * @author Superfluid
 */
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;

    // Validate configWord cleaness for future compatibility, or else may introduce undefined future behavior
    function isConfigWordClean(uint256 configWord) internal pure returns (bool) {
        return (configWord & ~(APP_LEVEL_MASK | APP_JAIL_BIT | AGREEMENT_CALLBACK_NOOP_BITMASKS)) == uint256(0);
    }
}

/**
 * @title Context definitions library
 * @author Superfluid
 */
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);
    }

}

/**
 * @title Flow Operator definitions library
  * @author Superfluid
 */
 library FlowOperatorDefinitions {
    uint8 constant internal AUTHORIZE_FLOW_OPERATOR_CREATE = uint8(1) << 0;
    uint8 constant internal AUTHORIZE_FLOW_OPERATOR_UPDATE = uint8(1) << 1;
    uint8 constant internal AUTHORIZE_FLOW_OPERATOR_DELETE = uint8(1) << 2;
    uint8 constant internal AUTHORIZE_FULL_CONTROL =
        AUTHORIZE_FLOW_OPERATOR_CREATE | AUTHORIZE_FLOW_OPERATOR_UPDATE | AUTHORIZE_FLOW_OPERATOR_DELETE;
    uint8 constant internal REVOKE_FLOW_OPERATOR_CREATE = ~(uint8(1) << 0);
    uint8 constant internal REVOKE_FLOW_OPERATOR_UPDATE = ~(uint8(1) << 1);
    uint8 constant internal REVOKE_FLOW_OPERATOR_DELETE = ~(uint8(1) << 2);

    function isPermissionsClean(uint8 permissions) internal pure returns (bool) {
        return (
            permissions & ~(AUTHORIZE_FLOW_OPERATOR_CREATE
                | AUTHORIZE_FLOW_OPERATOR_UPDATE
                | AUTHORIZE_FLOW_OPERATOR_DELETE)
            ) == uint8(0);
    }
 }

/**
 * @title Batch operation library
 * @author Superfluid
 */
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;
}

/**
 * @title Superfluid governance configs library
 * @author Superfluid
 */
library SuperfluidGovernanceConfigs {

    bytes32 constant internal SUPERFLUID_REWARD_ADDRESS_CONFIG_KEY =
        keccak256("org.superfluid-finance.superfluid.rewardAddress");
    bytes32 constant internal CFAV1_PPP_CONFIG_KEY =
        keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1.PPPConfiguration");
    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));
    }

    function decodePPPConfig(uint256 pppConfig) internal pure returns (uint256 liquidationPeriod, uint256 patricianPeriod) {
        liquidationPeriod = (pppConfig >> 32) & type(uint32).max;
        patricianPeriod = pppConfig & type(uint32).max;
    }
}

File 18 of 23 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)

pragma solidity ^0.8.0;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {
    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

File 19 of 23 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 20 of 23 : 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 21 of 23 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (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 `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, 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 `from` to `to` 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 from,
        address to,
        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 22 of 23 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
 * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() initializer {}
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

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

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        // If the contract is initializing we ignore whether _initialized is set in order to support multiple
        // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
        // contract may have been reentered.
        require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }

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

    function _isConstructor() private view returns (bool) {
        return !Address.isContract(address(this));
    }
}

File 23 of 23 : Proxy.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/Proxy.sol)

pragma solidity ^0.8.0;

/**
 * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
 * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
 * be specified by overriding the virtual {_implementation} function.
 *
 * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
 * different contract through the {_delegate} function.
 *
 * The success and return data of the delegated call will be returned back to the caller of the proxy.
 */
abstract contract Proxy {
    /**
     * @dev Delegates the current call to `implementation`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _delegate(address implementation) internal virtual {
        assembly {
            // Copy msg.data. We take full control of memory in this inline assembly
            // block because it will not return to Solidity code. We overwrite the
            // Solidity scratch pad at memory position 0.
            calldatacopy(0, 0, calldatasize())

            // Call the implementation.
            // out and outsize are 0 because we don't know the size yet.
            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

            // Copy the returned data.
            returndatacopy(0, 0, returndatasize())

            switch result
            // delegatecall returns 0 on error.
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }

    /**
     * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
     * and {_fallback} should delegate.
     */
    function _implementation() internal view virtual returns (address);

    /**
     * @dev Delegates the current call to the address returned by `_implementation()`.
     *
     * This function does not return to its internall call site, it will return directly to the external caller.
     */
    function _fallback() internal virtual {
        _beforeFallback();
        _delegate(_implementation());
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
     * function in the contract matches the call data.
     */
    fallback() external payable virtual {
        _fallback();
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
     * is empty.
     */
    receive() external payable virtual {
        _fallback();
    }

    /**
     * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
     * call, or as part of the Solidity `fallback` or `receive` functions.
     *
     * If overriden should call `super._beforeFallback()`.
     */
    function _beforeFallback() internal virtual {}
}

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

Contract ABI

[{"inputs":[{"internalType":"bool","name":"nonUpgradable","type":"bool"},{"internalType":"bool","name":"appWhiteListingEnabled","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"agreementType","type":"bytes32"},{"indexed":false,"internalType":"address","name":"code","type":"address"}],"name":"AgreementClassRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"agreementType","type":"bytes32"},{"indexed":false,"internalType":"address","name":"code","type":"address"}],"name":"AgreementClassUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperApp","name":"app","type":"address"}],"name":"AppRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"uuid","type":"bytes32"},{"indexed":false,"internalType":"address","name":"codeAddress","type":"address"}],"name":"CodeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ISuperfluidGovernance","name":"oldGov","type":"address"},{"indexed":false,"internalType":"contract ISuperfluidGovernance","name":"newGov","type":"address"}],"name":"GovernanceReplaced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperApp","name":"app","type":"address"},{"indexed":false,"internalType":"uint256","name":"reason","type":"uint256"}],"name":"Jail","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ISuperTokenFactory","name":"newFactory","type":"address"}],"name":"SuperTokenFactoryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperToken","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"code","type":"address"}],"name":"SuperTokenLogicUpdated","type":"event"},{"inputs":[],"name":"APP_WHITE_LISTING_ENABLED","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CALLBACK_GAS_LIMIT","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_APP_LEVEL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NON_UPGRADABLE_DEPLOYMENT","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bitmap","type":"uint256"},{"internalType":"bytes32","name":"agreementType","type":"bytes32"}],"name":"addToAgreementClassesBitmap","outputs":[{"internalType":"uint256","name":"newBitmap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"targetApp","type":"address"}],"name":"allowCompositeApp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"ctx","type":"bytes"},{"internalType":"int256","name":"appAllowanceUsedDelta","type":"int256"}],"name":"appCallbackPop","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"ctx","type":"bytes"},{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"uint256","name":"appAllowanceGranted","type":"uint256"},{"internalType":"int256","name":"appAllowanceUsed","type":"int256"},{"internalType":"contract ISuperfluidToken","name":"appAllowanceToken","type":"address"}],"name":"appCallbackPush","outputs":[{"internalType":"bytes","name":"appCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"operationType","type":"uint32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ISuperfluid.Operation[]","name":"operations","type":"tuple[]"}],"name":"batchCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperAgreement","name":"agreementClass","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"callAgreement","outputs":[{"internalType":"bytes","name":"returnedData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperAgreement","name":"agreementClass","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"userData","type":"bytes"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"callAgreementWithContext","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"},{"internalType":"bytes","name":"returnedData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"callAppAction","outputs":[{"internalType":"bytes","name":"returnedData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"callAppActionWithContext","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bool","name":"isTermination","type":"bool"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"callAppAfterCallback","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bool","name":"isTermination","type":"bool"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"callAppBeforeCallback","outputs":[{"internalType":"bytes","name":"cbdata","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"ctx","type":"bytes"},{"internalType":"uint256","name":"appAllowanceWantedMore","type":"uint256"},{"internalType":"int256","name":"appAllowanceUsedDelta","type":"int256"}],"name":"ctxUseAllowance","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"decodeCtx","outputs":[{"components":[{"internalType":"uint8","name":"appLevel","type":"uint8"},{"internalType":"uint8","name":"callType","type":"uint8"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"address","name":"msgSender","type":"address"},{"internalType":"bytes4","name":"agreementSelector","type":"bytes4"},{"internalType":"bytes","name":"userData","type":"bytes"},{"internalType":"uint256","name":"appAllowanceGranted","type":"uint256"},{"internalType":"uint256","name":"appAllowanceWanted","type":"uint256"},{"internalType":"int256","name":"appAllowanceUsed","type":"int256"},{"internalType":"address","name":"appAddress","type":"address"},{"internalType":"contract ISuperfluidToken","name":"appAllowanceToken","type":"address"}],"internalType":"struct ISuperfluid.Context","name":"context","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"operationType","type":"uint32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ISuperfluid.Operation[]","name":"operations","type":"tuple[]"}],"name":"forwardBatchCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"agreementType","type":"bytes32"}],"name":"getAgreementClass","outputs":[{"internalType":"contract ISuperAgreement","name":"agreementClass","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"appAddr","type":"address"}],"name":"getAppLevel","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"}],"name":"getAppManifest","outputs":[{"internalType":"bool","name":"isSuperApp","type":"bool"},{"internalType":"bool","name":"isJailed","type":"bool"},{"internalType":"uint256","name":"noopMask","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCodeAddress","outputs":[{"internalType":"address","name":"codeAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGovernance","outputs":[{"internalType":"contract ISuperfluidGovernance","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSuperTokenFactory","outputs":[{"internalType":"contract ISuperTokenFactory","name":"factory","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSuperTokenFactoryLogic","outputs":[{"internalType":"address","name":"logic","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidGovernance","name":"gov","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperAgreement","name":"agreementClass","type":"address"}],"name":"isAgreementClassListed","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"agreementType","type":"bytes32"}],"name":"isAgreementTypeListed","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"}],"name":"isApp","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"}],"name":"isAppJailed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"contract ISuperApp","name":"targetApp","type":"address"}],"name":"isCompositeAppAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"isCtxValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"ctx","type":"bytes"},{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"uint256","name":"reason","type":"uint256"}],"name":"jailApp","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bitmap","type":"uint256"}],"name":"mapAgreementClasses","outputs":[{"internalType":"contract ISuperAgreement[]","name":"agreementClasses","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"contract ISuperAgreement","name":"agreementClassLogic","type":"address"}],"name":"registerAgreementClass","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"configWord","type":"uint256"}],"name":"registerApp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"uint256","name":"configWord","type":"uint256"}],"name":"registerAppByFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"configWord","type":"uint256"},{"internalType":"string","name":"registrationKey","type":"string"}],"name":"registerAppWithKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bitmap","type":"uint256"},{"internalType":"bytes32","name":"agreementType","type":"bytes32"}],"name":"removeFromAgreementClassesBitmap","outputs":[{"internalType":"uint256","name":"newBitmap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidGovernance","name":"newGov","type":"address"}],"name":"replaceGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperAgreement","name":"agreementClassLogic","type":"address"}],"name":"updateAgreementClass","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"updateCode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperTokenFactory","name":"newFactory","type":"address"}],"name":"updateSuperTokenFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"token","type":"address"}],"name":"updateSuperTokenLogic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"versionRecipient","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]

610100604052600160c052622dc6c060e0523480156200001e57600080fd5b506040516200564a3803806200564a833981016040819052620000419162000068565b901515608052151560a052620000a0565b805180151581146200006357600080fd5b919050565b600080604083850312156200007c57600080fd5b620000878362000052565b9150620000976020840162000052565b90509250929050565b60805160a05160c05160e05161551c6200012e6000396000818161037101528181612cb80152612d460152600081816107020152612af501526000818161058501528181611f390152818161254201526129720152600081816106b9015281816107aa01528181610bd0015281816112a60152818161141d0152818161157c0152612875015261551c6000f3fe608060405234801561001057600080fd5b50600436106102a05760003560e01c806374041e0211610167578063bbe4fd50116100ce578063cd312ec411610087578063cd312ec4146106b4578063e8dccb7d146106db578063f213bb02146106fd578063f2e55caf14610724578063f37330521461072c578063f9f522f41461073f57600080fd5b8063bbe4fd5014610642578063bced3ddc14610648578063bd1c448b1461065b578063bf4287341461066e578063c4d66de814610681578063c56a069d1461069457600080fd5b8063a5dbbbcd11610120578063a5dbbbcd146105a7578063ad3915c8146105ba578063b6d200de146105cd578063b724211e146105e0578063ba48b5f8146105f3578063bb84cfa11461060657600080fd5b806374041e0214610521578063768fabb014610534578063787afde7146105475780638ca484841461055a578063989b0c3e1461056d5780639d297e301461058057600080fd5b8063469519541161020b578063572b6c05116101c4578063572b6c05146104b1578063670e77e3146104c45780636ad3ca7d146104d75780636b4f3335146104ea5780637283100c146104fd578063731aed6e1461051057600080fd5b80634695195414610422578063486ff0cd1461043557806350d75d251461045357806352d1902d1461045b57806354fbc4931461048b57806357121e0c1461049e57600080fd5b8063289b3c0d1161025d578063289b3c0d1461034157806333d608f11461036c57806339255d5b146103ab5780633ca3ad4e146103be5780633f6c923a146103e15780634329d2931461040157600080fd5b806306cecba8146102a55780630792f20a146102ba57806313349046146102e357806315a024e1146103085780631e6d0a841461031b5780631e855cf31461032e575b600080fd5b6102b86102b3366004614283565b61076f565b005b6102cd6102c83660046142e8565b61094c565b6040516102da9190614390565b60405180910390f35b6102f66102f1366004614283565b610a44565b60405160ff90911681526020016102da565b6102b8610316366004614283565b610a67565b6102cd6103293660046143b1565b610d33565b6102cd61033c366004614532565b610fa1565b6000546201000090046001600160a01b03165b6040516001600160a01b0390911681526020016102da565b6103937f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160401b0390911681526020016102da565b6102cd6103b9366004614581565b610fb5565b6103d16103cc366004614283565b610fcb565b60405190151581526020016102da565b6103f46103ef3660046145f6565b610fe8565b6040516102da919061462a565b61041461040f36600461470b565b610ff9565b6040516102da9291906147b7565b6102b8610430366004614283565b611274565b604080518082019091526002815261763160f01b60208201526102cd565b6103546113ac565b7fcd355cae2c435f8c5e0c626c4691d22fd85aa7422a424c6f0bced6e64c7aba745b6040519081526020016102da565b6102b8610499366004614283565b6113db565b6102b86104ac366004614283565b61165c565b6103d16104bf366004614283565b6117b2565b6102b86104d23660046147dc565b61183c565b6102b86104e53660046147dc565b61184d565b6103d16104f8366004614283565b611857565b6102b861050b366004614283565b61187b565b6003546001600160a01b0316610354565b6102cd61052f3660046143b1565b611922565b6102cd6105423660046148f5565b611a9c565b6102b8610555366004614283565b611c54565b6103d1610568366004614283565b611d96565b6102cd61057b366004614970565b611e5b565b6103d17f000000000000000000000000000000000000000000000000000000000000000081565b61047d6105b53660046149bb565b611eee565b6102b86105c83660046149dd565b611f37565b6103546105db3660046149dd565b611fc2565b6102cd6105ee3660046149f6565b612028565b6102cd610601366004614a52565b6120e8565b6103d1610614366004614ad4565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b4261047d565b61047d6106563660046149bb565b6124b4565b6102b8610669366004614b0d565b6124fc565b6103d161067c366004614b58565b612651565b6102b861068f366004614283565b612692565b6106a76106a23660046149dd565b61276e565b6040516102da9190614b99565b6103d17f000000000000000000000000000000000000000000000000000000000000000081565b6103d16106e93660046149dd565b600090815260026020526040902054151590565b61047d7f000000000000000000000000000000000000000000000000000000000000000081565b610354612858565b6102b861073a366004614be6565b612920565b61075261074d366004614283565b612a82565b6040805193151584529115156020840152908201526060016102da565b6000546201000090046001600160a01b031633146107a85760405162461bcd60e51b815260040161079f90614c12565b60405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000156107e65760405162461bcd60e51b815260040161079f90614c49565b6000816001600160a01b0316637730599e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610826573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084a9190614c75565b60008181526002602052604081205491925081900361087b5760405162461bcd60e51b815260040161079f90614c8e565b600060016108898184614ce6565b8154811061089957610899614cfd565b6000918252602090912001546040516311a5465560e21b81526001600160a01b03868116600483015290911691508190634695195490602401600060405180830381600087803b1580156108ec57600080fd5b505af1158015610900573d6000803e3d6000fd5b5050604080518681526001600160a01b03881660208201527f9279aa773f2b588996032d8de89911555039f28b13a11a7c17074330bc082d9a935001905060405180910390a150505050565b606061095733611d96565b6109735760405162461bcd60e51b815260040161079f90614d13565b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506109b59250839150612ad19050565b6109c1576109c1614d56565b6000610a0287878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fe892505050565b9050848160e00151610a149190614d6c565b60e0820152610100810151610a2a908590614d84565b610100820152610a3981612af1565b979650505050505050565b6001600160a01b03811660009081526004602052604081205460ff165b92915050565b6000546201000090046001600160a01b03163314610a975760405162461bcd60e51b815260040161079f90614c12565b6000816001600160a01b0316637730599e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ad7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610afb9190614c75565b60008181526002602052604090205490915015610b695760405162461bcd60e51b815260206004820152602660248201527f53463a2061677265656d656e7420636c61737320616c726561647920726567696044820152651cdd195c995960d21b606482015260840161079f565b60015461010011610bcc5760405162461bcd60e51b815260206004820152602760248201527f53463a20737570706f727420757020746f203235362061677265656d656e7420604482015266636c617373657360c81b606482015260840161079f565b60007f0000000000000000000000000000000000000000000000000000000000000000610c86576000604051610c0190614206565b604051809103906000f080158015610c1d573d6000803e3d6000fd5b50604051634a0687ef60e01b81526001600160a01b03868116600483015291925090821690634a0687ef90602401600060405180830381600087803b158015610c6557600080fd5b505af1158015610c79573d6000803e3d6000fd5b5050505080915050610c89565b50815b6001805480820182557fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b0384166001600160a01b0319909116179055546000838152600260205260409081902091909155517f878135063a6cfb3bc333e534b1fdc83f4f12221cad6705c31c0567048a8bd3d190610d2690849086909182526001600160a01b0316602082015260400190565b60405180910390a1505050565b6060610d3e33611d96565b610d5a5760405162461bcd60e51b815260040161079f90614d13565b82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610d9c9250839150612ad19050565b610da857610da8614d56565b600080610e228a6000898c8c8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c9081908401838280828437600092019190915250612c7b92505050565b915091508115610f5a57610e3581612e42565b15610ec65780806020019051810190610e4e9190614e0a565b9350610e5984612ad1565b610ec15786610e7a5760405162461bcd60e51b815260040161079f90614e3e565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929650610ec192508c915060149050612e96565b610f94565b86610f135760405162461bcd60e51b815260206004820152601f60248201527f53463a204150505f52554c455f4354585f49535f4d414c464f524d4154454400604482015260640161079f565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929650610ec192508c915060169050612e96565b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509296505050505b5050509695505050505050565b6060610fae338484612f0b565b9392505050565b6060610fc3338585856131e9565b949350505050565b6001600160a01b0316600090815260046020526040902054151590565b610ff0614213565b610a618261333c565b60608083838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061103e9250839150612ad19050565b61108a5760405162461bcd60e51b815260206004820152601d60248201527f53463a204150505f52554c455f4354585f49535f4e4f545f56414c4944000000604482015260640161079f565b8961109481611d96565b6110b05760405162461bcd60e51b815260040161079f90614e75565b60006110f187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fe892505050565b6101208101519091506001600160a01b031633146111695760405162461bcd60e51b815260206004820152602f60248201527f53463a2063616c6c41677265656d656e7457697468436f6e746578742066726f60448201526e6d2077726f6e67206164647265737360881b606482015260840161079f565b60608101805133909152604080516020601f8c018190048102820181019092528a8152908b908b908190840183828082843760009201919091525050505060a08301526111b582612af1565b955060006111fb8e8e8e8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c9250613407915050565b96509050801561125a57858060200190518101906112199190614e0a565b965061122487612ad1565b61123057611230614d56565b61123987610fe8565b6001600160a01b0383166060820152925061125383612af1565b9650611263565b611263866134ec565b505050505097509795505050505050565b6000546201000090046001600160a01b031633146112a45760405162461bcd60e51b815260040161079f90614c12565b7f0000000000000000000000000000000000000000000000000000000000000000156112e25760405162461bcd60e51b815260040161079f90614c49565b806001600160a01b031663cd312ec46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611320573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113449190614eb7565b156113a05760405162461bcd60e51b815260206004820152602660248201527f53463a2063616e6e6f7420646f776e677261646520746f206e6f6e2075706772604482015265616461626c6560d01b606482015260840161079f565b6113a9816135f7565b50565b60006113d67f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b905090565b6000546201000090046001600160a01b0316331461140b5760405162461bcd60e51b815260040161079f90614c12565b6003546001600160a01b031661157a577f00000000000000000000000000000000000000000000000000000000000000006114f157600060405161144e90614206565b604051809103906000f08015801561146a573d6000803e3d6000fd5b50604051634a0687ef60e01b81526001600160a01b03848116600483015291925090821690634a0687ef90602401600060405180830381600087803b1580156114b257600080fd5b505af11580156114c6573d6000803e3d6000fd5b5050600380546001600160a01b0319166001600160a01b0394909416939093179092555061150d9050565b600380546001600160a01b0319166001600160a01b0383161790555b600360009054906101000a90046001600160a01b03166001600160a01b0316638129fc1c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561155d57600080fd5b505af1158015611571573d6000803e3d6000fd5b50505050611618565b7f0000000000000000000000000000000000000000000000000000000000000000156115b85760405162461bcd60e51b815260040161079f90614c49565b6003546040516311a5465560e21b81526001600160a01b03838116600483015290911690634695195490602401600060405180830381600087803b1580156115ff57600080fd5b505af1158015611613573d6000803e3d6000fd5b505050505b6003546040516001600160a01b0390911681527fce13a9895a1719ad4493b2ac1a9bfb36070566161abab408e7ecbe586da8d499906020015b60405180910390a150565b3361166681610fcb565b6116b25760405162461bcd60e51b815260206004820152601860248201527f53463a2073656e646572206973206e6f7420616e206170700000000000000000604482015260640161079f565b6116bb82610fcb565b6117075760405162461bcd60e51b815260206004820152601860248201527f53463a20746172676574206973206e6f7420616e206170700000000000000000604482015260640161079f565b61171082610a44565b60ff1661171c82610a44565b60ff16116117805760405162461bcd60e51b815260206004820152602b60248201527f53463a20736f75726365206170702073686f756c64206861766520686967686560448201526a1c88185c1c081b195d995b60aa1b606482015260840161079f565b503360009081526005602090815260408083206001600160a01b0394909416835292905220805460ff19166001179055565b600080546201000090046001600160a01b03166380f70cba30836117d586613831565b6040518463ffffffff1660e01b81526004016117f393929190614ed4565b602060405180830381865afa158015611810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118349190614c75565b151592915050565b6113a96118476138b9565b82613921565b6113a93382613921565b6001600160a01b038116600090815260046020526040812054618000161515610a61565b6000546201000090046001600160a01b031633146118ab5760405162461bcd60e51b815260040161079f90614c12565b600054604080516001600160a01b03620100009093048316815291831660208301527f13abda02e63c790d0e2818b251282cfe5cbe0a8abd69c54bf5d2260c0907bd2e910160405180910390a1600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b606061192d33611d96565b6119495760405162461bcd60e51b815260040161079f90614d13565b82828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061198b9250839150612ad19050565b61199757611997614d56565b600080611a118a6001898c8c8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c9081908401838280828437600092019190915250612c7b92505050565b915091508115610f9457611a2481612e42565b15611a445780806020019051810190611a3d9190614e0a565b9350610f94565b86611a915760405162461bcd60e51b815260206004820152601f60248201527f53463a204150505f52554c455f4354585f49535f4d414c464f524d4154454400604482015260640161079f565b610f948a6016612e96565b6060611aa733611d96565b611ac35760405162461bcd60e51b815260040161079f90614d13565b86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b059250839150612ad19050565b611b1157611b11614d56565b6000611b5289898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fe892505050565b9050611b618160600151610fcb565b15611bf65760608101516001600160a01b039081166000908152600560209081526040808320938b168352929052205460ff16611bf65760405162461bcd60e51b815260206004820152602d60248201527f53463a204150505f52554c455f434f4d504f534954455f4150505f49535f4e4f60448201526c1517d5d2125511531254d51151609a1b606482015260840161079f565b805181611c0282614ef8565b60ff169052506003602082015260c08101869052600060e082015261010081018590526001600160a01b038088166101208301528416610140820152611c4781612af1565b9998505050505050505050565b6000546201000090046001600160a01b03163314611c845760405162461bcd60e51b815260040161079f90614c12565b60035460408051634a3852d960e11b815290516000926001600160a01b031691639470a5b29160048083019260209291908290030181865afa158015611cce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf29190614f17565b6040516311a5465560e21b81526001600160a01b03808316600483015291925090831690634695195490602401600060405180830381600087803b158015611d3957600080fd5b505af1158015611d4d573d6000803e3d6000fd5b50506040516001600160a01b038481168252851692507f840acbd291b38534819f47f875839277e502f40e1c7bfea2c5fc2c8017442cd391506020015b60405180910390a25050565b600080826001600160a01b0316637730599e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dfb9190614c75565b6000818152600260205260409020549091508015801590610fc357506001600160a01b0384166001611e2d8184614ce6565b81548110611e3d57611e3d614cfd565b6000918252602090912001546001600160a01b031614949350505050565b6060611e6633611d96565b611e825760405162461bcd60e51b815260040161079f90614d13565b6000611ec385858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fe892505050565b905082816101000151611ed69190614d84565b610100820152611ee581612af1565b95945050505050565b600081815260026020526040812054808203611f1c5760405162461bcd60e51b815260040161079f90614c8e565b611f27600182614ce6565b6001901b19841691505092915050565b7f000000000000000000000000000000000000000000000000000000000000000015611fb65760405162461bcd60e51b815260206004820152602860248201527f53463a2061707020726567697374726174696f6e2072657175697265732070656044820152673936b4b9b9b4b7b760c11b606482015260840161079f565b6113a981336001613d65565b600081815260026020526040812054808203611ff05760405162461bcd60e51b815260040161079f90614c8e565b6001611ffc8183614ce6565b8154811061200c5761200c614cfd565b6000918252602090912001546001600160a01b03169392505050565b606061203333611d96565b61204f5760405162461bcd60e51b815260040161079f90614d13565b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506120919250839150612ad19050565b61209d5761209d614d56565b6120a78484612e96565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929998505050505050505050565b606082828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061212c9250839150612ad19050565b6121785760405162461bcd60e51b815260206004820152601d60248201527f53463a204150505f52554c455f4354585f49535f4e4f545f56414c4944000000604482015260640161079f565b6001600160a01b0387166000908152600460205260409020548790806121d65760405162461bcd60e51b8152602060048201526013602482015272053463a206e6f7420612073757065722061707606c1b604482015260640161079f565b61800081161561221c5760405162461bcd60e51b815260206004820152601160248201527014d18e88185c1c081a5cc81a985a5b1959607a1b604482015260640161079f565b87878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250925061225d9150839050613f5c565b90506001600160e01b031981166330d9c91560e01b148061228e57506001600160e01b0319811663d86ed3e560e01b145b806122a957506001600160e01b03198116630221347d60e61b145b806122c457506001600160e01b0319811663230dbd2960e01b145b806122df57506001600160e01b03198116635f9e7d7760e01b145b806122fa57506001600160e01b031981166353c11f9960e01b145b156123175760405162461bcd60e51b815260040161079f90614f34565b600061235889898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fe892505050565b6101208101519091506001600160a01b031633146123d05760405162461bcd60e51b815260206004820152602f60248201527f53463a2063616c6c417070416374696f6e57697468436f6e746578742066726f60448201526e6d2077726f6e67206164647265737360881b606482015260840161079f565b606081018051339091526123e382612af1565b975060008061242a8f8f8f8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508f9250613407915050565b91509150811561249957808060200190518101906124489190614e0a565b99506124538a612ad1565b61246f5760405162461bcd60e51b815260040161079f90614e3e565b6124788a610fe8565b6001600160a01b0384166060820152935061249284612af1565b99506124a2565b6124a2816134ec565b50505050505050505095945050505050565b6000818152600260205260408120548082036124e25760405162461bcd60e51b815260040161079f90614c8e565b6124ed600182614ce6565b6001901b841791505092915050565b600061253e3284848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613fb892505050565b90507f00000000000000000000000000000000000000000000000000000000000000001561263f576000805460405163407b865d60e11b81524292620100009092046001600160a01b0316916380f70cba916125a09130918790600401614ed4565b602060405180830381865afa1580156125bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125e19190614c75565b101561263f5760405162461bcd60e51b815260206004820152602760248201527f53463a20696e76616c6964206f72206578706972656420726567697374726174604482015266696f6e206b657960c81b606482015260840161079f565b61264b84336001613d65565b50505050565b6000610fae83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612ad192505050565b600054610100900460ff166126ad5760005460ff16156126b1565b303b155b6127145760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161079f565b600054610100900460ff16158015612736576000805461ffff19166101011790555b6000805462010000600160b01b031916620100006001600160a01b03851602179055801561276a576000805461ff00191690555b5050565b60606000806001805490506001600160401b0381111561279057612790614447565b6040519080825280602002602001820160405280156127b9578160200160208202803683370190505b50925060009050600091505b600154821015612850576001821b84161561284057600182815481106127ed576127ed614cfd565b6000918252602090912001546001600160a01b0316838261280d81614f78565b93508151811061281f5761281f614cfd565b60200260200101906001600160a01b031690816001600160a01b0316815250505b61284982614f78565b91506127c5565b825250919050565b6003546000906001600160a01b031661287357612873614d56565b7f0000000000000000000000000000000000000000000000000000000000000000156128a957506003546001600160a01b031690565b600360009054906101000a90046001600160a01b03166001600160a01b03166350d75d256040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d69190614f17565b333b8061296f5760405162461bcd60e51b815260206004820152601e60248201527f53463a20666163746f7279206d757374206265206120636f6e74726163740000604482015260640161079f565b507f000000000000000000000000000000000000000000000000000000000000000015612a765760006129a133613feb565b6000805460405163407b865d60e11b81529293509091620100009091046001600160a01b0316906380f70cba906129e090309085908790600401614ed4565b602060405180830381865afa1580156129fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a219190614c75565b600114905080612a735760405162461bcd60e51b815260206004820152601f60248201527f53463a20617574686f72697a656420666163746f727920726571756972656400604482015260640161079f565b50505b61276a81836000613d65565b6001600160a01b038116600090815260046020908152604080832081519283019091525480825215801592918291612ac957805161800081161515935064ff000000001691505b509193909250565b60008151600014158015610a615750600654825160208401201492915050565b60607f0000000000000000000000000000000000000000000000000000000000000000826000015160ff161115612b755760405162461bcd60e51b815260206004820152602260248201527f53463a204150505f52554c455f4d41585f4150505f4c4556454c5f5245414348604482015261115160f21b606482015260840161079f565b815160208084015160009260ff1664ff000000009190921b1617905060006080612ba28560e00151614065565b6001600160801b0316901b612bba8560c00151614065565b6001600160801b0316179050818460400151856060015186608001518760a00151604051602001612bef959493929190614f91565b60408051601f1981840301815282825261010087015161012088015161014089015160208601879052938501919091526001600160a01b03908116606085015290911660808301529060a00160408051601f1981840301815290829052612c5992916020016147b7565b60408051601f1981840301815291905280516020820120600655949350505050565b600060606001600160a01b038716612c9557612c95614d56565b612c9f84846140d2565b935060005a90508615612d3a57876001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160401b031686604051612cee9190614fd2565b6000604051808303818686fa925050503d8060008114612d2a576040519150601f19603f3d011682016040523d82523d6000602084013e612d2f565b606091505b509093509150612dc6565b876001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160401b031686604051612d7c9190614fd2565b60006040518083038160008787f1925050503d8060008114612dba576040519150601f19603f3d011682016040523d82523d6000602084013e612dbf565b606091505b5090935091505b82612e3757612dd6603f82614fee565b5a1115612dfb5785612df057612deb826134ec565b612e37565b612deb88600a612e96565b60405162461bcd60e51b815260206004820152601160248201527053463a206e656564206d6f72652067617360781b604482015260640161079f565b509550959350505050565b6000604082511015612e5657506000919050565b602082810151906000908214612e70575060009392505050565b506040830151612e7f816141cd565b612e8a906040614d6c565b84511492505050919050565b6001600160a01b03821660009081526004602052604081205461800016900361276a576001600160a01b038216600081815260046020526040908190208054618000179055517fbe3aa33bd245135e4e26b223d79d14ea479a47bff09f2b03c53838af1edbb14b90611d8a9084815260200190565b60065460609015612f5e5760405162461bcd60e51b815260206004820152601d60248201527f53463a204150505f52554c455f4354585f49535f4e4f545f434c45414e000000604482015260640161079f565b6001600160a01b038316600090815260046020526040902054839080612fbc5760405162461bcd60e51b8152602060048201526013602482015272053463a206e6f7420612073757065722061707606c1b604482015260640161079f565b6180008116156130025760405162461bcd60e51b815260206004820152601160248201527014d18e88185c1c081a5cc81a985a5b1959607a1b604482015260640161079f565b83600061300e82613f5c565b90506001600160e01b031981166330d9c91560e01b148061303f57506001600160e01b0319811663d86ed3e560e01b145b8061305a57506001600160e01b03198116630221347d60e61b145b8061307557506001600160e01b0319811663230dbd2960e01b145b8061309057506001600160e01b03198116635f9e7d7760e01b145b806130ab57506001600160e01b031981166353c11f9960e01b145b156130c85760405162461bcd60e51b815260040161079f90614f34565b60006131746040518061016001604052806130e28c610fcb565b6130ed5760006130f0565b60015b60ff168152600260208201526040014281526020018b6001600160a01b03168152602001600060e01b6001600160e01b03191681526020016040518060200160405280600081525081526020016000815260200160008152602001600081526020018a6001600160a01b0316815260200160006001600160a01b0316815250612af1565b90506000613183898984613407565b9750905080156131cd57868060200190518101906131a19190614e0a565b91506131ac82612ad1565b6131c85760405162461bcd60e51b815260040161079f90614e3e565b6131d6565b6131d6876134ec565b5050600060065550929695505050505050565b6006546060901561323c5760405162461bcd60e51b815260206004820152601d60248201527f53463a204150505f52554c455f4354585f49535f4e4f545f434c45414e000000604482015260640161079f565b8361324681611d96565b6132625760405162461bcd60e51b815260040161079f90614e75565b600061326d85613f5c565b905060006133096040518061016001604052806132898b610fcb565b613294576000613297565b60015b60ff168152600160208201526040014281526020018a6001600160a01b03168152602001846001600160e01b031916815260200187815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815250612af1565b90506000613318888884613407565b955090508061332a5761332a856134ec565b50506000600655509095945050505050565b613344614213565b6060808380602001905181019061335b9190615010565b815191935091506000906133789084016020908101908501615069565b60a08901526001600160e01b03191660808801526001600160a01b031660608701526040860152602081811c600f168187015260ff90911685528251600092506133c99190840181019084016150ed565b6001600160a01b03908116610140890152166101208701526101008601526001600160801b03811660c086015260801c60e085015250919392505050565b600060606001600160a01b03851661342157613421614d56565b61342b84846140d2565b9350846001600160a01b0316846040516134459190614fd2565b6000604051808303816000865af19150503d8060008114613482576040519150601f19603f3d011682016040523d82523d6000602084013e613487565b606091505b50909250905081156134e45760008151116134e45760405162461bcd60e51b815260206004820152601960248201527f53463a204150505f52554c455f4354585f49535f454d50545900000000000000604482015260640161079f565b935093915050565b60048151101561353e5760405162461bcd60e51b815260206004820152601a60248201527f43616c6c5574696c733a20746172676574207265766572742829000000000000604482015260640161079f565b602081015163b1b7848f60e01b6001600160e01b03198216016135ee5760408051808201825260208082527f43616c6c5574696c733a207461726765742070616e69636b65643a2030785f5f90820190815260248501517f43616c6c5574696c733a207461726765742070616e69636b65643a2030780000600482811c600f908116603090810160081b918516011791909117909252925162461bcd60e51b815291929161079f91849101614390565b81518060208401fd5b60006136217f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6001600160a01b0316036136775760405162461bcd60e51b815260206004820152601d60248201527f5555505350726f786961626c653a206e6f742075706772616461626c65000000604482015260640161079f565b806001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156136b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136d99190614c75565b7fcd355cae2c435f8c5e0c626c4691d22fd85aa7422a424c6f0bced6e64c7aba74146137535760405162461bcd60e51b815260206004820152602360248201527f5555505350726f786961626c653a206e6f7420636f6d70617469626c65206c6f60448201526267696360e81b606482015260840161079f565b6001600160a01b03811630036137ab5760405162461bcd60e51b815260206004820152601960248201527f5555505350726f786961626c653a2070726f7879206c6f6f7000000000000000604482015260640161079f565b6137d3817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b7fe011bc04c286c344a8fcbb8de77f953da762c3e25d8cdea984147fc4168a5dcc7fcd355cae2c435f8c5e0c626c4691d22fd85aa7422a424c6f0bced6e64c7aba74604080519182526001600160a01b038416602083015201611651565b6040805160208101829052603260608201527f6f72672e7375706572666c7569642d66696e616e63652e7375706572666c756960808201527132173a393ab9ba32b22337b93bb0b93232b960711b60a08201526001600160a01b0383169181019190915260009060c0015b604051602081830303815290604052805190602001209050919050565b6000601836108015906138d057506138d0336117b2565b6139145760405162461bcd60e51b81526020600482015260156024820152742737ba103a393ab9ba32b2103337b93bb0b93232b960591b604482015260640161079f565b5060131936013560601c90565b60005b8151811015613d6057600082828151811061394157613941614cfd565b6020026020010151600001519050600163ffffffff168163ffffffff1603613a215760008084848151811061397857613978614cfd565b6020026020010151604001518060200190518101906139979190615138565b915091508484815181106139ad576139ad614cfd565b6020026020010151602001516001600160a01b03166362aa52878784846040518463ffffffff1660e01b81526004016139e893929190614ed4565b600060405180830381600087803b158015613a0257600080fd5b505af1158015613a16573d6000803e3d6000fd5b505050505050613d4d565b60011963ffffffff821601613b07576000806000858581518110613a4757613a47614cfd565b602002602001015160400151806020019051810190613a669190615166565b925092509250858581518110613a7e57613a7e614cfd565b6020908102919091018101510151604051630b682aeb60e11b81526001600160a01b0389811660048301528581166024830152848116604483015260648201849052909116906316d055d690608401600060405180830381600087803b158015613ae757600080fd5b505af1158015613afb573d6000803e3d6000fd5b50505050505050613d4d565b60641963ffffffff821601613bd757828281518110613b2857613b28614cfd565b6020026020010151602001516001600160a01b031663ca78946485858581518110613b5557613b55614cfd565b602002602001015160400151806020019051810190613b749190614c75565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015613bba57600080fd5b505af1158015613bce573d6000803e3d6000fd5b50505050613d4d565b60651963ffffffff821601613c2557828281518110613bf857613bf8614cfd565b6020026020010151602001516001600160a01b031663245887fc85858581518110613b5557613b55614cfd565b60c81963ffffffff821601613c9d57600080848481518110613c4957613c49614cfd565b602002602001015160400151806020019051810190613c689190615010565b91509150613c9586868681518110613c8257613c82614cfd565b60200260200101516020015184846131e9565b505050613d4d565b60c91963ffffffff821601613cf757613cf184848481518110613cc257613cc2614cfd565b602002602001015160200151858581518110613ce057613ce0614cfd565b602002602001015160400151612f0b565b50613d4d565b60405162461bcd60e51b815260206004820152602560248201527f53463a20756e6b6e6f776e2062617463682063616c6c206f7065726174696f6e604482015264207479706560d81b606482015260840161079f565b5080613d5881614f78565b915050613924565b505050565b323303613dc05760405162461bcd60e51b8152602060048201526024808201527f53463a204150505f52554c455f4e4f5f524547495354524154494f4e5f464f526044820152635f454f4160e01b606482015260840161079f565b8015613e2e57813b8015613e2c5760405162461bcd60e51b815260206004820152602d60248201527f53463a204150505f52554c455f524547495354524154494f4e5f4f4e4c595f4960448201526c272fa1a7a729aa292aa1aa27a960991b606482015260840161079f565b505b64ff000080ff198316158015613e46575060ff831615155b8015613e5457506180008316155b613ea05760405162461bcd60e51b815260206004820152601760248201527f53463a20696e76616c696420636f6e66696720776f7264000000000000000000604482015260640161079f565b6001600160a01b03821660009081526004602052604090205415613f065760405162461bcd60e51b815260206004820152601a60248201527f53463a2061707020616c72656164792072656769737465726564000000000000604482015260640161079f565b60408051602080820183528582526001600160a01b038516600081815260049092528382209251909255915190917f0d540ad8f39e07d19909687352b9fa017405d93c91a6760981fbae9cf28bfef791a2505050565b6000600482511015613fb05760405162461bcd60e51b815260206004820152601b60248201527f43616c6c5574696c733a20696e76616c69642063616c6c446174610000000000604482015260640161079f565b506020015190565b60008282604051602001613fcd9291906151a9565b60405160208183030381529060405280519060200120905092915050565b6040805160208101829052603960608201527f6f72672e7375706572666c7569642d66696e616e63652e7375706572666c756960808201527f642e61707057686974654c697374696e672e666163746f72790000000000000060a08201526001600160a01b0383169181019190915260009060c00161389c565b60006001600160801b038211156140ce5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b606482015260840161079f565b5090565b81518083015160609190801561413f5760405162461bcd60e51b815260206004820152602c60248201527f53463a20706c61636572686f6c646572206374782073686f756c64206861766560448201526b040f4cae4de40d8cadccee8d60a31b606482015260840161079f565b50601f1981018452825184908481614156816141cd565b6141609190614ce6565b6001600160401b0381111561417757614177614447565b6040519080825280601f01601f1916602001820160405280156141a1576020820181803683370190505b506040516020016141b5949392919061522e565b60405160208183030381529060405291505092915050565b60008082601f16116141e05760006141e3565b60015b60ff166141f1602084614fee565b6141fb9190614d6c565b610a6190602061527d565b61024a8061529d83390190565b604080516101608101825260008082526020820181905291810182905260608082018390526080820183905260a082015260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b6001600160a01b03811681146113a957600080fd5b60006020828403121561429557600080fd5b8135610fae8161426e565b60008083601f8401126142b257600080fd5b5081356001600160401b038111156142c957600080fd5b6020830191508360208285010111156142e157600080fd5b9250929050565b600080600080606085870312156142fe57600080fd5b84356001600160401b0381111561431457600080fd5b614320878288016142a0565b90989097506020870135966040013595509350505050565b60005b8381101561435357818101518382015260200161433b565b8381111561264b5750506000910152565b6000815180845261437c816020860160208601614338565b601f01601f19169290920160200192915050565b602081526000610fae6020830184614364565b80151581146113a957600080fd5b600080600080600080608087890312156143ca57600080fd5b86356143d58161426e565b955060208701356001600160401b03808211156143f157600080fd5b6143fd8a838b016142a0565b909750955060408901359150614412826143a3565b9093506060880135908082111561442857600080fd5b5061443589828a016142a0565b979a9699509497509295939492505050565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b038111828210171561447f5761447f614447565b60405290565b604051601f8201601f191681016001600160401b03811182821017156144ad576144ad614447565b604052919050565b60006001600160401b038211156144ce576144ce614447565b50601f01601f191660200190565b600082601f8301126144ed57600080fd5b81356145006144fb826144b5565b614485565b81815284602083860101111561451557600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561454557600080fd5b82356145508161426e565b915060208301356001600160401b0381111561456b57600080fd5b614577858286016144dc565b9150509250929050565b60008060006060848603121561459657600080fd5b83356145a18161426e565b925060208401356001600160401b03808211156145bd57600080fd5b6145c9878388016144dc565b935060408601359150808211156145df57600080fd5b506145ec868287016144dc565b9150509250925092565b60006020828403121561460857600080fd5b81356001600160401b0381111561461e57600080fd5b610fc3848285016144dc565b6020815261463e60208201835160ff169052565b60006020830151614654604084018260ff169052565b5060408301516060830152606083015161467960808401826001600160a01b03169052565b5060808301516001600160e01b0319811660a08401525060a08301516101608060c08501526146ac610180850183614364565b915060c085015160e085015260e08501516101008181870152808701519150506101208181870152808701519150506101406146f2818701836001600160a01b03169052565b909501516001600160a01b031693019290925250919050565b60008060008060008060006080888a03121561472657600080fd5b87356147318161426e565b965060208801356001600160401b038082111561474d57600080fd5b6147598b838c016142a0565b909850965060408a013591508082111561477257600080fd5b61477e8b838c016142a0565b909650945060608a013591508082111561479757600080fd5b506147a48a828b016142a0565b989b979a50959850939692959293505050565b6040815260006147ca6040830185614364565b8281036020840152611ee58185614364565b600060208083850312156147ef57600080fd5b82356001600160401b038082111561480657600080fd5b818501915085601f83011261481a57600080fd5b81358181111561482c5761482c614447565b8060051b61483b858201614485565b918252838101850191858101908984111561485557600080fd5b86860192505b83831015611c47578235858111156148735760008081fd5b86016060818c03601f190181131561488b5760008081fd5b61489361445d565b8983013563ffffffff811681146148aa5760008081fd5b81526040838101356148bb8161426e565b828c01529183013591888311156148d25760008081fd5b6148e08e8c858701016144dc565b9082015284525050918601919086019061485b565b60008060008060008060a0878903121561490e57600080fd5b86356001600160401b0381111561492457600080fd5b61493089828a016142a0565b90975095505060208701356149448161426e565b9350604087013592506060870135915060808701356149628161426e565b809150509295509295509295565b60008060006040848603121561498557600080fd5b83356001600160401b0381111561499b57600080fd5b6149a7868287016142a0565b909790965060209590950135949350505050565b600080604083850312156149ce57600080fd5b50508035926020909101359150565b6000602082840312156149ef57600080fd5b5035919050565b60008060008060608587031215614a0c57600080fd5b84356001600160401b03811115614a2257600080fd5b614a2e878288016142a0565b9095509350506020850135614a428161426e565b9396929550929360400135925050565b600080600080600060608688031215614a6a57600080fd5b8535614a758161426e565b945060208601356001600160401b0380821115614a9157600080fd5b614a9d89838a016142a0565b90965094506040880135915080821115614ab657600080fd5b50614ac3888289016142a0565b969995985093965092949392505050565b60008060408385031215614ae757600080fd5b8235614af28161426e565b91506020830135614b028161426e565b809150509250929050565b600080600060408486031215614b2257600080fd5b8335925060208401356001600160401b03811115614b3f57600080fd5b614b4b868287016142a0565b9497909650939450505050565b60008060208385031215614b6b57600080fd5b82356001600160401b03811115614b8157600080fd5b614b8d858286016142a0565b90969095509350505050565b6020808252825182820181905260009190848201906040850190845b81811015614bda5783516001600160a01b031683529284019291840191600101614bb5565b50909695505050505050565b60008060408385031215614bf957600080fd5b8235614c048161426e565b946020939093013593505050565b6020808252601b908201527f53463a206f6e6c7920676f7665726e616e636520616c6c6f7765640000000000604082015260600190565b60208082526012908201527153463a206e6f6e2075706772616461626c6560701b604082015260600190565b600060208284031215614c8757600080fd5b5051919050565b60208082526022908201527f53463a2061677265656d656e7420636c617373206e6f74207265676973746572604082015261195960f21b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b600082821015614cf857614cf8614cd0565b500390565b634e487b7160e01b600052603260045260246000fd5b60208082526023908201527f53463a2073656e646572206973206e6f74206c6973746564206167726565656d604082015262195b9d60ea1b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b60008219821115614d7f57614d7f614cd0565b500190565b600080821280156001600160ff1b0384900385131615614da657614da6614cd0565b600160ff1b8390038412811615614dbf57614dbf614cd0565b50500190565b600082601f830112614dd657600080fd5b8151614de46144fb826144b5565b818152846020838601011115614df957600080fd5b610fc3826020830160208701614338565b600060208284031215614e1c57600080fd5b81516001600160401b03811115614e3257600080fd5b610fc384828501614dc5565b6020808252601c908201527f53463a204150505f52554c455f4354585f49535f524541444f4e4c5900000000604082015260600190565b60208082526022908201527f53463a206f6e6c79206c6973746564206167726565656d656e7420616c6c6f77604082015261195960f21b606082015260800190565b600060208284031215614ec957600080fd5b8151610fae816143a3565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600060ff821660ff8103614f0e57614f0e614cd0565b60010192915050565b600060208284031215614f2957600080fd5b8151610fae8161426e565b60208082526024908201527f53463a2061677265656d656e742063616c6c6261636b206973206e6f742061636040820152633a34b7b760e11b606082015260800190565b600060018201614f8a57614f8a614cd0565b5060010190565b858152602081018590526001600160a01b03841660408201526001600160e01b03198316606082015260a060808201819052600090610a3990830184614364565b60008251614fe4818460208701614338565b9190910192915050565b60008261500b57634e487b7160e01b600052601260045260246000fd5b500490565b6000806040838503121561502357600080fd5b82516001600160401b038082111561503a57600080fd5b61504686838701614dc5565b9350602085015191508082111561505c57600080fd5b5061457785828601614dc5565b600080600080600060a0868803121561508157600080fd5b8551945060208601519350604086015161509a8161426e565b60608701519093506001600160e01b0319811681146150b857600080fd5b60808701519092506001600160401b038111156150d457600080fd5b6150e088828901614dc5565b9150509295509295909350565b6000806000806080858703121561510357600080fd5b8451935060208501519250604085015161511c8161426e565b606086015190925061512d8161426e565b939692955090935050565b6000806040838503121561514b57600080fd5b82516151568161426e565b6020939093015192949293505050565b60008060006060848603121561517b57600080fd5b83516151868161426e565b60208501519093506151978161426e565b80925050604084015190509250925092565b60608152604160608201527f6f72672e7375706572666c7569642d66696e616e63652e7375706572666c756960808201527f642e61707057686974654c697374696e672e726567697374726174696f6e4b6560a0820152607960f81b60c082015260018060a01b038316602082015260e060408201526000610fc360e0830184614364565b6000855160206152418285838b01614338565b8184019150868252855161525a81838501848a01614338565b855192019161526e81838501848901614338565b91909101019695505050505050565b600081600019048311821515161561529757615297614cd0565b50029056fe608060405234801561001057600080fd5b5061022a806100206000396000f3fe6080604052600436106100225760003560e01c80634a0687ef1461003957610031565b366100315761002f610059565b005b61002f610059565b34801561004557600080fd5b5061002f6100543660046101c4565b61006b565b610069610064610171565b6101a0565b565b6001600160a01b0381166100c65760405162461bcd60e51b815260206004820152601760248201527f5555505350726f78793a207a65726f206164647265737300000000000000000060448201526064015b60405180910390fd5b60006100f07f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6001600160a01b0316146101465760405162461bcd60e51b815260206004820152601e60248201527f5555505350726f78793a20616c726561647920696e697469616c697a6564000060448201526064016100bd565b61016e817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b50565b600061019b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b905090565b3660008037600080366000845af43d6000803e8080156101bf573d6000f35b3d6000fd5b6000602082840312156101d657600080fd5b81356001600160a01b03811681146101ed57600080fd5b939250505056fea264697066735822122086b1fc3a42d3af20b0ab5b46a7113da519907b8dce59f9a2b801e27095423bbc64736f6c634300080e0033a264697066735822122059f0a0071f959a271ecaab63758663dabcce218faad3dfcafb6e9201f3c9760664736f6c634300080e003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

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

00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : nonUpgradable (bool): False
Arg [1] : appWhiteListingEnabled (bool): False

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000


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.