Address Details
contract

0x9B46349877486d724FC7f1F8CAcAf8715f78469a

Contract Name
SuperGoodDollar
Creator
0x5128e3–22e4bb at 0x2042e6–45870c
Balance
0 CELO ( )
Locked CELO Balance
0.00 CELO
Voting CELO Balance
0.00 CELO
Pending Unlocked Gold
0.00 CELO
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
28614308
This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
SuperGoodDollar




Optimization enabled
true
Compiler version
v0.8.19+commit.7dd6d404




Optimization runs
0
EVM Version
paris




Verified at
2024-03-22T16:46:45.773516Z

contracts/token/superfluid/SuperGoodDollar.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.8;

import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import { ERC777Helper } from "@superfluid-finance/ethereum-contracts/contracts/libs/ERC777Helper.sol";
import { FixedSizeData } from "@superfluid-finance/ethereum-contracts/contracts/libs/FixedSizeData.sol";

import { IGoodDollarCustom } from "./ISuperGoodDollar.sol";
import { SuperToken } from "./SuperToken.sol";
import "../ERC677.sol";
import "../IFeesFormula.sol";
import "../../Interfaces.sol";
import "./ERC20Permit.sol";

// import "hardhat/console.sol";

// IMPORTANT: The order of base contracts with storage MUST REMAIN AS IS after the initial deployment.
// Changing order can result in storage corruption when upgrading.
contract SuperGoodDollar is
	SuperToken, // includes 32 storage slots padding for SuperToken
	AccessControlEnumerableUpgradeable, // with storage
	PausableUpgradeable,
	ERC20Permit,
	ERC677, // without storage
	IGoodDollarCustom // without storage
{
	error SUPER_GOODDOLLAR_PAUSED();

	// IMPORTANT! Never change the type (storage size) or order of state variables.
	// If a variable isn't needed anymore, leave it as padding (renaming is ok).
	address public feeRecipient;
	IFeesFormula public formula;
	IIdentity public identity;
	uint256 public cap;
	bool public disableHostOperations;
	address public getUnderlyingToken;
	// Append additional state variables here!

	// ============== constants and immutables ==============

	bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
	bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

	event TransferFee(
		address from,
		address to,
		uint256 amount,
		uint256 fee,
		bool senderPays
	);

	// ========================================================================================
	// ============== Functionality to be executed on the proxy via delegateCall ==============
	// ========================================================================================

	/// initializes state specific to the GoodDollar token
	/// When upgrading to a new logic contract,
	function initialize(
		string calldata n,
		string calldata s,
		uint256 _cap,
		IFeesFormula _formula,
		IIdentity _identity,
		address _feeRecipient,
		address _owner,
		IConstantOutflowNFT _outflowNFT,
		IConstantInflowNFT _inflowNFT
	) public initializer {
		initialize(IERC20(address(0)), 18, n, s);
		__AccessControl_init_unchained();
		__Pausable_init_unchained();
		__ERC20Permit_init(n);
		_setupRole(DEFAULT_ADMIN_ROLE, _owner);
		_setupRole(MINTER_ROLE, _owner);
		_setupRole(PAUSER_ROLE, _owner);
		feeRecipient = _feeRecipient;
		identity = _identity;
		formula = _formula;
		cap = _cap;
		_setNFTProxyContracts(
			_outflowNFT,
			_inflowNFT,
			IPoolAdminNFT(address(0)),
			IPoolMemberNFT(address(0))
		);
	}

	// ============ SuperFluid ============

	constructor(ISuperfluid _host) SuperToken(_host) {}

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

	function updateCode(address newAddress) external override {
		_onlyOwner();
		UUPSProxiable._updateCodeAddress(newAddress);
	}

	/// override Superfluid agreement function in order to make it pausable
	/// that is, no new streams can be started when the contract is paused
	function createAgreement(
		bytes32 id,
		bytes32[] calldata data
	) public override(ISuperfluidToken, SuperfluidToken) {
		_onlyNotPaused();
		// otherwise the wrapper of SuperToken.createAgreement does the actual job
		super.createAgreement(id, data);
	}

	/// failsafe in case we don't want to trust superfluid host for batch operations
	function allowHostOperations()
		internal
		view
		virtual
		override
		returns (bool hostEnabled)
	{
		return !disableHostOperations;
	}

	function enableHostOperations(bool enabled) external {
		_onlyOwner();
		disableHostOperations = !enabled;
	}

	// ============ IGoodDollarCustom ============

	function owner() external view override returns (address) {
		return getRoleMember(DEFAULT_ADMIN_ROLE, 0);
	}

	function setFormula(IFeesFormula _formula) external override {
		_onlyOwner();
		formula = _formula;
	}

	function setIdentity(IIdentityV2 _identity) external override {
		_onlyOwner();
		identity = _identity;
	}

	function transferOwnership(address _owner) public override {
		_onlyOwner();
		grantRole(DEFAULT_ADMIN_ROLE, _owner);
		renounceRole(DEFAULT_ADMIN_ROLE, _msgSender());
	}

	function isMinter(address _minter) external view override returns (bool) {
		return hasRole(MINTER_ROLE, _minter);
	}

	function addMinter(address _minter) external override {
		grantRole(MINTER_ROLE, _minter); // enforces permissions
	}

	function renounceMinter() external override {
		renounceRole(MINTER_ROLE, _msgSender()); // enforces permissions
	}

	function isPauser(address _pauser) external view override returns (bool) {
		return hasRole(PAUSER_ROLE, _pauser);
	}

	function addPauser(address _pauser) external override {
		grantRole(PAUSER_ROLE, _pauser); // enforces permissions
	}

	function pause() public override {
		_onlyPauser();
		_pause();
	}

	function unpause() public override {
		_onlyPauser();
		_unpause();
	}

	/**
	 * @dev Processes transfer fees and calls ERC677Token transferAndCall function
	 * @param to address to transfer to
	 * @param amount the amount to transfer
	 * @param data The data to pass to transferAndCall
	 * @return a bool indicating if transfer function succeeded
	 */
	function transferAndCall(
		address to,
		uint256 amount,
		bytes calldata data
	) external override returns (bool) {
		//duplicated code from _transferAndCall so we can get the amount after fees correctly for transferAndCall event + callback
		_onlyNotPaused();
		uint256 netAmount = _processFees(msg.sender, to, amount);
		// handing over to the wrapper of SuperToken.transferFrom skipping this _transferFrom which also collects fees
		bool res = super._transferFrom(msg.sender, msg.sender, to, netAmount);
		emit ERC677.Transfer(msg.sender, to, netAmount, data);
		if (isContract(to)) {
			require(
				contractFallback(to, netAmount, data),
				"Contract fallback failed"
			);
		}
		return res;
	}

	function transfer(
		address to,
		uint256 amount
	) public virtual override(ERC677, SuperToken) returns (bool) {
		return _transferFrom(msg.sender, msg.sender, to, amount);
	}

	/// make sure supertoken erc20 methods include fees and pausable
	function _transferFrom(
		address spender,
		address holder,
		address recipient,
		uint256 amount
	) internal virtual override returns (bool) {
		_onlyNotPaused();
		uint256 bruttoValue = _processFees(holder, recipient, amount);
		// handing over to the wrapper of SuperToken.transferFrom
		super._transferFrom(spender, holder, recipient, bruttoValue);
		return true;
	}

	/// make sure supertoken erc777 methods include fees and pausable
	function _send(
		address operator,
		address from,
		address to,
		uint256 amount,
		bytes memory userData,
		bytes memory operatorData,
		bool requireReceptionAck
	) internal virtual override {
		_onlyNotPaused();
		uint256 bruttoValue = _processFees(from, to, amount);
		// handing over to the wrapper of SuperToken.transferFrom
		super._send(
			operator,
			from,
			to,
			bruttoValue,
			userData,
			operatorData,
			requireReceptionAck
		);
	}

	/// make sure supertoken erc777 methods include pausable
	function _burn(
		address operator,
		address from,
		uint256 amount,
		bytes memory userData,
		bytes memory operatorData
	) internal virtual override {
		_onlyNotPaused();
		// handing over to the wrapper of SuperToken.transferFrom
		super._burn(operator, from, amount, userData, operatorData);
	}

	/**
	 * @dev Minting function
	 * @param to the address that will receive the minted tokens
	 * @param amount the amount of tokens to mint
	 */
	function mint(
		address to,
		uint256 amount
	) public override(IGoodDollarCustom) onlyMinter returns (bool) {
		_onlyNotPaused();

		if (cap > 0) {
			require(
				totalSupply() + amount <= cap,
				"Cannot increase supply beyond cap"
			);
		}
		_mint(
			msg.sender,
			to,
			amount,
			false /* requireReceptionAck */,
			new bytes(0),
			new bytes(0)
		);

		return true;
	}

	function burnFrom(address account, uint256 amount) public {
		uint256 currentAllowance = allowance(account, _msgSender());
		require(currentAllowance >= amount, "ERC20: burn amount exceeds allowance");
		unchecked {
			_approve(account, _msgSender(), currentAllowance - amount);
		}
		_burn(msg.sender, account, amount, new bytes(0), new bytes(0));
	}

	function burn(uint256 amount) external override {
		_burn(msg.sender, msg.sender, amount, new bytes(0), new bytes(0));
	}

	/**
	 * @dev Gets the current transaction fees
	 * @return fee senderPays  that represents the current transaction fees and bool true if sender pays the fee or receiver
	 */
	function getFees(
		uint256 amount
	) public view returns (uint256 fee, bool senderPays) {
		return formula.getTxFees(amount, address(0), address(0));
	}

	/**
	 * @dev Gets the current transaction fees
	 * @return fee senderPays  that represents the current transaction fees and bool true if sender pays the fee or receiver
	 */
	function getFees(
		uint256 amount,
		address sender,
		address recipient
	) public view returns (uint256 fee, bool senderPays) {
		return formula.getTxFees(amount, sender, recipient);
	}

	/**
	 * @dev Sets the address that receives the transactional fees.
	 * can only be called by owner
	 * @param _feeRecipient The new address to receive transactional fees
	 */
	function setFeeRecipient(address _feeRecipient) public {
		_onlyOwner();
		feeRecipient = _feeRecipient;
	}

	// internal functions

	/**
	 * @dev Sends transactional fees to feeRecipient address from given address
	 * @param account The account that sends the fees
	 * @param amount The amount to subtract fees from
	 * @return an uint256 that represents the given amount minus the transactional fees
	 */
	function _processFees(
		address account,
		address recipient,
		uint256 amount
	) internal returns (uint256) {
		(uint256 txFees, bool senderPays) = getFees(amount, account, recipient);
		if (txFees > 0 && !identity.isDAOContract(msg.sender)) {
			require(
				senderPays == false || amount + txFees <= balanceOf(account),
				"Not enough balance to pay TX fee"
			);
			super._transferFrom(account, account, feeRecipient, txFees);
			emit TransferFee(account, recipient, amount, txFees, senderPays);
			return senderPays ? amount : amount - txFees;
		}
		return amount;
	}

	/**************************************************************************
	 * ERC20x-specific Functions
	 *************************************************************************/

	function setNFTProxyContracts(
		IConstantOutflowNFT _constantOutflowNFT,
		IConstantInflowNFT _constantInflowNFT,
		IPoolAdminNFT _poolAdminNFT,
		IPoolMemberNFT _poolMemberNFT
	) public {
		_onlyOwner();
		_setNFTProxyContracts(
			_constantOutflowNFT,
			_constantInflowNFT,
			_poolAdminNFT,
			_poolMemberNFT
		);
	}

	function _setNFTProxyContracts(
		IConstantOutflowNFT _constantOutflowNFT,
		IConstantInflowNFT _constantInflowNFT,
		IPoolAdminNFT _poolAdminNFT,
		IPoolMemberNFT _poolMemberNFT
	) internal {
		CONSTANT_OUTFLOW_NFT = _constantOutflowNFT;
		CONSTANT_INFLOW_NFT = _constantInflowNFT;
		poolAdminNFT = _poolAdminNFT;
		poolMemberNFT = _poolMemberNFT;

		// emit NFT proxy creation events
		emit ConstantOutflowNFTCreated(CONSTANT_OUTFLOW_NFT);
		emit ConstantInflowNFTCreated(CONSTANT_INFLOW_NFT);
	}

	function recover(IERC20 token) public {
		token.transfer(
			getRoleMember(DEFAULT_ADMIN_ROLE, 0),
			token.balanceOf(address(this))
		);
	}

	/**************************************************************************
	 * Modifiers
	 *************************************************************************/

	function _onlyOwner() internal view {
		require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "not owner");
	}

	function _onlyPauser() internal view {
		require(hasRole(PAUSER_ROLE, msg.sender), "not pauser");
	}

	function _onlyNotPaused() internal view {
		if (paused()) revert SUPER_GOODDOLLAR_PAUSED();
	}

	modifier onlyMinter() {
		require(hasRole(MINTER_ROLE, msg.sender), "not minter");
		_;
	}
}
        

/contracts/utils/DataTypes.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

library DataTypes {
	// refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties.
	struct ReserveData {
		//stores the reserve configuration
		ReserveConfigurationMap configuration;
		//the liquidity index. Expressed in ray
		uint128 liquidityIndex;
		//variable borrow index. Expressed in ray
		uint128 variableBorrowIndex;
		//the current supply rate. Expressed in ray
		uint128 currentLiquidityRate;
		//the current variable borrow rate. Expressed in ray
		uint128 currentVariableBorrowRate;
		//the current stable borrow rate. Expressed in ray
		uint128 currentStableBorrowRate;
		uint40 lastUpdateTimestamp;
		//tokens addresses
		address aTokenAddress;
		address stableDebtTokenAddress;
		address variableDebtTokenAddress;
		//address of the interest rate strategy
		address interestRateStrategyAddress;
		//the id of the reserve. Represents the position in the list of the active reserves
		uint8 id;
	}

	struct ReserveConfigurationMap {
		//bit 0-15: LTV
		//bit 16-31: Liq. threshold
		//bit 32-47: Liq. bonus
		//bit 48-55: Decimals
		//bit 56: Reserve is active
		//bit 57: reserve is frozen
		//bit 58: borrowing is enabled
		//bit 59: stable rate borrowing enabled
		//bit 60-63: reserved
		//bit 64-79: reserve factor
		uint256 data;
	}
	enum InterestRateMode { NONE, STABLE, VARIABLE }
}
          

/contracts/token/superfluid/UUPSProxiable.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.8;

import { UUPSUtils } from "@superfluid-finance/ethereum-contracts/contracts/upgradability/UUPSUtils.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

/**
 * @title UUPS (Universal Upgradeable Proxy Standard) Proxiable contract.
 * @dev Modified for SuperGoodDollar
 * 1. use upgradeable Initializable for compatability with usage of other openzep upgradeablaes contracts
 */
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;

	// allows to mark logic contracts as initialized in order to reduce the attack surface
	// solhint-disable-next-line no-empty-blocks
	function castrate() external initializer {}

	/**
	 * @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);
}
          

/contracts/token/superfluid/SuperfluidToken.sol

// SPDX-License-Identifier: AGPLv3
pragma solidity >=0.8;

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

import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { EventsEmitter } from "@superfluid-finance/ethereum-contracts/contracts/libs/EventsEmitter.sol";
import { FixedSizeData } from "@superfluid-finance/ethereum-contracts/contracts/libs/FixedSizeData.sol";

/**
 * @title Superfluid's token implementation
 *
 * @author Superfluid
 * @dev Modified for SuperGoodDollar
 * 1. made createAgreement public and virtual
 * 2. added allowHostOperations to disable host actions by G$ governance in case of security issues
 */
abstract contract SuperfluidToken is ISuperfluidToken {
	bytes32 private constant _REWARD_ADDRESS_CONFIG_KEY =
		keccak256("org.superfluid-finance.superfluid.rewardAddress");

	using SafeCast for uint256;
	using SafeCast for int256;

	/// @dev Superfluid contract
	ISuperfluid internal immutable _host;

	/// @dev Active agreement bitmap
	mapping(address => uint256) internal _inactiveAgreementBitmap;

	/// @dev Shared Settled balance for the account
	mapping(address => int256) internal _sharedSettledBalances;

	/// @dev Total supply
	uint256 internal _totalSupply;

	// NOTE: for future compatibility, these are reserved solidity slots
	// The sub-class of SuperfluidToken solidity slot will start after _reserve13
	uint256 internal _reserve4;
	uint256 private _reserve5;
	uint256 private _reserve6;
	uint256 private _reserve7;
	uint256 private _reserve8;
	uint256 private _reserve9;
	uint256 private _reserve10;
	uint256 private _reserve11;
	uint256 private _reserve12;
	uint256 internal _reserve13;

	constructor(ISuperfluid host) {
		_host = host;
	}

	/// @dev ISuperfluidToken.getHost implementation
	function getHost()
		external
		view
		override(ISuperfluidToken)
		returns (address host)
	{
		return address(_host);
	}

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

	/// @dev ISuperfluidToken.realtimeBalanceOf implementation
	function realtimeBalanceOf(address account, uint256 timestamp)
		public
		view
		override
		returns (
			int256 availableBalance,
			uint256 deposit,
			uint256 owedDeposit
		)
	{
		availableBalance = _sharedSettledBalances[account];
		ISuperAgreement[] memory activeAgreements = getAccountActiveAgreements(
			account
		);
		for (uint256 i = 0; i < activeAgreements.length; ++i) {
			(
				int256 agreementDynamicBalance,
				uint256 agreementDeposit,
				uint256 agreementOwedDeposit
			) = activeAgreements[i].realtimeBalanceOf(this, account, timestamp);
			deposit = deposit + agreementDeposit;
			owedDeposit = owedDeposit + agreementOwedDeposit;
			// 1. Available Balance = Dynamic Balance - Max(0, Deposit - OwedDeposit)
			// 2. Deposit should not be shared between agreements
			availableBalance =
				availableBalance +
				agreementDynamicBalance -
				(
					agreementDeposit > agreementOwedDeposit
						? (agreementDeposit - agreementOwedDeposit)
						: 0
				).toInt256();
		}
	}

	/// @dev ISuperfluidToken.realtimeBalanceOfNow implementation
	function realtimeBalanceOfNow(address account)
		public
		view
		override
		returns (
			int256 availableBalance,
			uint256 deposit,
			uint256 owedDeposit,
			uint256 timestamp
		)
	{
		timestamp = _host.getNow();
		(availableBalance, deposit, owedDeposit) = realtimeBalanceOf(
			account,
			timestamp
		);
	}

	function isAccountCritical(address account, uint256 timestamp)
		public
		view
		override
		returns (bool isCritical)
	{
		(int256 availableBalance, , ) = realtimeBalanceOf(account, timestamp);
		return availableBalance < 0;
	}

	function isAccountCriticalNow(address account)
		external
		view
		override
		returns (bool isCritical)
	{
		return isAccountCritical(account, _host.getNow());
	}

	function isAccountSolvent(address account, uint256 timestamp)
		public
		view
		override
		returns (bool isSolvent)
	{
		(
			int256 availableBalance,
			uint256 deposit,
			uint256 owedDeposit
		) = realtimeBalanceOf(account, timestamp);
		// Available Balance = Realtime Balance - Max(0, Deposit - OwedDeposit)
		int256 realtimeBalance = availableBalance +
			(deposit > owedDeposit ? (deposit - owedDeposit) : 0).toInt256();
		return realtimeBalance >= 0;
	}

	function isAccountSolventNow(address account)
		external
		view
		override
		returns (bool isSolvent)
	{
		return isAccountSolvent(account, _host.getNow());
	}

	/// @dev ISuperfluidToken.getAccountActiveAgreements implementation
	function getAccountActiveAgreements(address account)
		public
		view
		override
		returns (ISuperAgreement[] memory)
	{
		return _host.mapAgreementClasses(~_inactiveAgreementBitmap[account]);
	}

	/**************************************************************************
	 * Token implementation helpers
	 *************************************************************************/

	function _mint(address account, uint256 amount) internal {
		_sharedSettledBalances[account] =
			_sharedSettledBalances[account] +
			amount.toInt256();
		_totalSupply = _totalSupply + amount;
	}

	function _burn(address account, uint256 amount) internal {
		(int256 availableBalance, , ) = realtimeBalanceOf(account, _host.getNow());
		if (availableBalance < amount.toInt256()) {
			revert SF_TOKEN_BURN_INSUFFICIENT_BALANCE();
		}
		_sharedSettledBalances[account] =
			_sharedSettledBalances[account] -
			amount.toInt256();
		_totalSupply = _totalSupply - amount;
	}

	function _move(
		address from,
		address to,
		int256 amount
	) internal {
		(int256 availableBalance, , ) = realtimeBalanceOf(from, _host.getNow());
		if (availableBalance < amount) {
			revert SF_TOKEN_MOVE_INSUFFICIENT_BALANCE();
		}
		_sharedSettledBalances[from] = _sharedSettledBalances[from] - amount;
		_sharedSettledBalances[to] = _sharedSettledBalances[to] + amount;
	}

	function _getRewardAccount() internal view returns (address rewardAccount) {
		ISuperfluidGovernance gov = _host.getGovernance();
		rewardAccount = gov.getConfigAsAddress(
			_host,
			this,
			_REWARD_ADDRESS_CONFIG_KEY
		);
	}

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

	/// @dev ISuperfluidToken.createAgreement implementation
	function createAgreement(bytes32 id, bytes32[] calldata data)
		public
		virtual
		override
	{
		address agreementClass = msg.sender;
		bytes32 slot = keccak256(abi.encode("AgreementData", agreementClass, id));
		if (FixedSizeData.hasData(slot, data.length)) {
			revert SF_TOKEN_AGREEMENT_ALREADY_EXISTS();
		}
		FixedSizeData.storeData(slot, data);
		emit AgreementCreated(agreementClass, id, data);
	}

	/// @dev ISuperfluidToken.getAgreementData implementation
	function getAgreementData(
		address agreementClass,
		bytes32 id,
		uint256 dataLength
	) external view override returns (bytes32[] memory data) {
		bytes32 slot = keccak256(abi.encode("AgreementData", agreementClass, id));
		data = FixedSizeData.loadData(slot, dataLength);
	}

	/// @dev ISuperfluidToken.updateAgreementData implementation
	function updateAgreementData(bytes32 id, bytes32[] calldata data)
		external
		override
	{
		address agreementClass = msg.sender;
		bytes32 slot = keccak256(abi.encode("AgreementData", agreementClass, id));
		FixedSizeData.storeData(slot, data);
		emit AgreementUpdated(msg.sender, id, data);
	}

	/// @dev ISuperfluidToken.terminateAgreement implementation
	function terminateAgreement(bytes32 id, uint256 dataLength)
		external
		override
	{
		address agreementClass = msg.sender;
		bytes32 slot = keccak256(abi.encode("AgreementData", agreementClass, id));
		if (!FixedSizeData.hasData(slot, dataLength)) {
			revert SF_TOKEN_AGREEMENT_DOES_NOT_EXIST();
		}
		FixedSizeData.eraseData(slot, dataLength);
		emit AgreementTerminated(msg.sender, id);
	}

	/// @dev ISuperfluidToken.updateAgreementState implementation
	function updateAgreementStateSlot(
		address account,
		uint256 slotId,
		bytes32[] calldata slotData
	) external override {
		bytes32 slot = keccak256(
			abi.encode("AgreementState", msg.sender, account, slotId)
		);
		FixedSizeData.storeData(slot, slotData);
		emit AgreementStateUpdated(msg.sender, account, slotId);
	}

	/// @dev ISuperfluidToken.getAgreementState implementation
	function getAgreementStateSlot(
		address agreementClass,
		address account,
		uint256 slotId,
		uint256 dataLength
	) external view override returns (bytes32[] memory slotData) {
		bytes32 slot = keccak256(
			abi.encode("AgreementState", agreementClass, account, slotId)
		);
		slotData = FixedSizeData.loadData(slot, dataLength);
	}

	/// @dev ISuperfluidToken.settleBalance implementation
	function settleBalance(address account, int256 delta)
		external
		override
		onlyAgreement
	{
		_sharedSettledBalances[account] = _sharedSettledBalances[account] + delta;
	}

	/// @dev ISuperfluidToken.makeLiquidationPayoutsV2 implementation
	function makeLiquidationPayoutsV2(
		bytes32 id,
		bytes memory liquidationTypeData,
		address liquidatorAccount, // the address executing the liquidation
		bool useDefaultRewardAccount, // Whether or not the default reward account receives the rewardAmount
		address targetAccount, // Account to be liquidated
		uint256 rewardAmount, // The amount the rewarded account will receive
		int256 targetAccountBalanceDelta // The delta amount the target account balance should change by
	) external override onlyAgreement {
		address rewardAccount = _getRewardAccount();

		// we set the rewardAccount to the user who executed the liquidation if
		// no rewardAccount is set (aka. ANARCHY MODE - should not occur in reality, for testing purposes)
		if (rewardAccount == address(0)) {
			rewardAccount = liquidatorAccount;
		}

		address rewardAmountReceiver = useDefaultRewardAccount
			? rewardAccount
			: liquidatorAccount;

		if (targetAccountBalanceDelta <= 0) {
			// LIKELY BRANCH: target account pays penalty to rewarded account
			assert(rewardAmount.toInt256() == -targetAccountBalanceDelta);

			_sharedSettledBalances[rewardAmountReceiver] += rewardAmount.toInt256();
			_sharedSettledBalances[targetAccount] += targetAccountBalanceDelta;
			EventsEmitter.emitTransfer(
				targetAccount,
				rewardAmountReceiver,
				rewardAmount
			);
		} else {
			// LESS LIKELY BRANCH: target account is bailed out
			// NOTE: useDefaultRewardAccount being true is undefined behavior
			// because the default reward account isn't receiving the rewardAmount by default
			assert(!useDefaultRewardAccount);
			_sharedSettledBalances[rewardAccount] -= (rewardAmount.toInt256() +
				targetAccountBalanceDelta);
			_sharedSettledBalances[liquidatorAccount] += rewardAmount.toInt256();
			_sharedSettledBalances[targetAccount] += targetAccountBalanceDelta;
			EventsEmitter.emitTransfer(
				rewardAccount,
				liquidatorAccount,
				rewardAmount
			);
			EventsEmitter.emitTransfer(
				rewardAccount,
				targetAccount,
				uint256(targetAccountBalanceDelta)
			);
		}

		emit AgreementLiquidatedV2(
			msg.sender,
			id,
			liquidatorAccount,
			targetAccount,
			rewardAmountReceiver,
			rewardAmount,
			targetAccountBalanceDelta,
			liquidationTypeData
		);
	}

	function allowHostOperations()
		internal
		view
		virtual
		returns (bool hostEnabled);

	/**************************************************************************
	 * Modifiers
	 *************************************************************************/

	modifier onlyAgreement() {
		if (!_host.isAgreementClassListed(ISuperAgreement(msg.sender))) {
			revert SF_TOKEN_ONLY_LISTED_AGREEMENT();
		}
		_;
	}

	modifier onlyHost() {
		if (address(_host) != msg.sender || allowHostOperations() == false) {
			revert SF_TOKEN_ONLY_HOST();
		}
		_;
	}
}
          

/contracts/token/superfluid/SuperToken.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.8;

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

import { ISuperfluid, ISuperfluidGovernance, ISuperToken as ISuperTokenOriginal, ISuperAgreement, IERC20, IERC777, TokenInfo } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol";
import { ISuperfluidToken } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol";
import { ERC777Helper } from "@superfluid-finance/ethereum-contracts/contracts/libs/ERC777Helper.sol";
import { IConstantOutflowNFT } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/IConstantOutflowNFT.sol";
import { IConstantInflowNFT } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/IConstantInflowNFT.sol";
import { IPoolAdminNFT } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/IPoolAdminNFT.sol";
import { IPoolMemberNFT } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/IPoolMemberNFT.sol";

import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { IERC777Recipient } from "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol";
import { IERC777Sender } from "@openzeppelin/contracts/token/ERC777/IERC777Sender.sol";
import { AddressUpgradeable as Address } from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";

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

/**
 * @title Superfluid's super token implementation
 *
 * @author Superfluid
 * @dev Modified for SuperGoodDollar
 * 1. made virtual - transfer,_transferFrom,_send,_burn, proxiableuuid, initialize, updateCode
 * 2. removed upgrade/downgrade internal methods, all external/public using _upgrade/_downgrade will revert
 * 3. use modified UUPSProxy with openzep upgradeable Initializable instead of openzep regular Initializable used by superfluid
 * 4. fixed erc777 burn and operator burn to work for puresupertokens
 * 5. removed unused "self" functions
 */
contract SuperToken is UUPSProxiable, SuperfluidToken, ISuperToken {
	using SafeMath for uint256;
	using SafeCast for uint256;
	using Address for address;
	using ERC777Helper for ERC777Helper.Operators;
	using SafeERC20 for IERC20;

	uint8 private constant _STANDARD_DECIMALS = 18;

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

	/// @dev The underlying ERC20 token
	IERC20 internal _underlyingToken;

	/// @dev Decimals of the underlying token
	uint8 internal _underlyingDecimals;

	/// @dev TokenInfo Name property
	string internal _name;

	/// @dev TokenInfo Symbol property
	string internal _symbol;

	/// @dev ERC20 Allowances Storage
	mapping(address => mapping(address => uint256)) internal _allowances;

	/// @dev ERC777 operators support data
	ERC777Helper.Operators internal _operators;

	/// @notice Constant Outflow NFT proxy address
	IConstantOutflowNFT public CONSTANT_OUTFLOW_NFT;

	/// @notice Constant Inflow NFT proxy address
	IConstantInflowNFT public CONSTANT_INFLOW_NFT;

	/// @notice Pool Admin NFT proxy address
	IPoolAdminNFT public poolAdminNFT;

	/// @notice Pool Member NFT proxy address
	IPoolMemberNFT public poolMemberNFT;

	// NOTE: for future compatibility, these are reserved solidity slots
	// The sub-class of SuperToken solidity slot will start after _reserve26

	// NOTE: Whenever modifying the storage layout here it is important to update the validateStorageLayout
	// function in its respective mock contract to ensure that it doesn't break anything or lead to unexpected
	// behaviors/layout when upgrading

	uint256 internal _reserve26;
	uint256 private _reserve27;
	uint256 private _reserve28;
	uint256 private _reserve29;
	uint256 private _reserve30;
	uint256 internal _reserve31;

	constructor(
		ISuperfluid host
	)
		SuperfluidToken(host) // solhint-disable-next-line no-empty-blocks
	{}

	/// @dev Initialize the Super Token proxy
	function initialize(
		IERC20 underlyingToken,
		uint8 underlyingDecimals,
		string calldata n,
		string calldata s
	) public virtual override onlyInitializing {
		_underlyingToken = underlyingToken;
		_underlyingDecimals = underlyingDecimals;

		_name = n;
		_symbol = s;

		// register interfaces
		ERC777Helper.register(address(this));

		// help tools like explorers detect the token contract
		emit Transfer(address(0), address(0), 0);
	}

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

	function updateCode(address newAddress) external virtual override {
		if (msg.sender != address(_host)) revert SUPER_TOKEN_ONLY_HOST();
		UUPSProxiable._updateCodeAddress(newAddress);
	}

	/**************************************************************************
	 * ERC20 Token Info
	 *************************************************************************/

	function name() external view override returns (string memory) {
		return _name;
	}

	function symbol() external view override returns (string memory) {
		return _symbol;
	}

	function decimals() external pure override returns (uint8) {
		return _STANDARD_DECIMALS;
	}

	/**************************************************************************
	 * (private) Token Logics
	 *************************************************************************/

	/**
	 * @notice in the original openzeppelin implementation, transfer() and transferFrom()
	 * did invoke the send and receive hooks, as required by ERC777.
	 * This hooks were removed from super tokens for ERC20 transfers in order to protect
	 * interfacing contracts which don't expect invocations of ERC20 transfers to potentially reenter.
	 * Interactions relying on ERC777 hooks need to use the ERC777 interface.
	 * For more context, see https://github.com/superfluid-finance/protocol-monorepo/wiki/About-ERC-777
	 */
	function _transferFrom(
		address spender,
		address holder,
		address recipient,
		uint256 amount
	) internal virtual returns (bool) {
		if (holder == address(0)) {
			revert SUPER_TOKEN_TRANSFER_FROM_ZERO_ADDRESS();
		}
		if (recipient == address(0)) {
			revert SUPER_TOKEN_TRANSFER_TO_ZERO_ADDRESS();
		}

		if (recipient == address(this)) {
			revert SUPER_TOKEN_TRANSFER_TO_TOKEN_ADDRESS();
		}

		address operator = msg.sender;

		_move(operator, holder, recipient, amount, "", "");

		if (spender != holder) {
			_approve(
				holder,
				spender,
				_allowances[holder][spender].sub(
					amount,
					"SuperToken: transfer amount exceeds allowance"
				)
			);
		}

		return true;
	}

	/**
	 * @dev Send tokens
	 * @param operator address operator address
	 * @param from address token holder address
	 * @param to address recipient address
	 * @param amount uint256 amount of tokens to transfer
	 * @param userData bytes extra information provided by the token holder (if any)
	 * @param operatorData bytes extra information provided by the operator (if any)
	 * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient
	 * @notice this is overridden in supergooddollar to enforce fees
	 */
	function _send(
		address operator,
		address from,
		address to,
		uint256 amount,
		bytes memory userData,
		bytes memory operatorData,
		bool requireReceptionAck
	) internal virtual {
		if (from == address(0)) {
			revert SUPER_TOKEN_TRANSFER_FROM_ZERO_ADDRESS();
		}
		if (to == address(0)) {
			revert SUPER_TOKEN_TRANSFER_TO_ZERO_ADDRESS();
		}
		if (to == address(this)) {
			revert SUPER_TOKEN_TRANSFER_TO_TOKEN_ADDRESS();
		}

		_callTokensToSend(operator, from, to, amount, userData, operatorData);

		_move(operator, from, to, amount, userData, operatorData);

		_callTokensReceived(
			operator,
			from,
			to,
			amount,
			userData,
			operatorData,
			requireReceptionAck
		);
	}

	function _move(
		address operator,
		address from,
		address to,
		uint256 amount,
		bytes memory userData,
		bytes memory operatorData
	) private {
		SuperfluidToken._move(from, to, amount.toInt256());

		emit Sent(operator, from, to, amount, userData, operatorData);
		emit Transfer(from, to, amount);
	}

	/**
	 * @dev Creates `amount` tokens and assigns them to `account`, increasing
	 * the total supply.
	 *
	 * If a send hook is registered for `account`, the corresponding function
	 * will be called with `operator`, `data` and `operatorData`.
	 *
	 * See {IERC777Sender} and {IERC777Recipient}.
	 *
	 * Emits {Minted} and {IERC20-Transfer} events.
	 *
	 * Requirements
	 *
	 * - `account` cannot be the zero address.
	 * - if `account` is a contract, it must implement the {IERC777Recipient}
	 * interface.
	 */
	function _mint(
		address operator,
		address account,
		uint256 amount,
		bool requireReceptionAck,
		bytes memory userData,
		bytes memory operatorData
	) internal {
		if (account == address(0)) {
			revert SUPER_TOKEN_MINT_TO_ZERO_ADDRESS();
		}

		SuperfluidToken._mint(account, amount);

		_callTokensReceived(
			operator,
			address(0),
			account,
			amount,
			userData,
			operatorData,
			requireReceptionAck
		);

		emit Minted(operator, account, amount, userData, operatorData);
		emit Transfer(address(0), account, amount);
	}

	/**
	 * @dev Burn tokens
	 * @param from address token holder address
	 * @param amount uint256 amount of tokens to burn
	 * @param userData bytes extra information provided by the token holder
	 * @param operatorData bytes extra information provided by the operator (if any)
	 */
	function _burn(
		address operator,
		address from,
		uint256 amount,
		bytes memory userData,
		bytes memory operatorData
	) internal virtual {
		if (from == address(0)) {
			revert SUPER_TOKEN_BURN_FROM_ZERO_ADDRESS();
		}

		_callTokensToSend(
			operator,
			from,
			address(0),
			amount,
			userData,
			operatorData
		);

		SuperfluidToken._burn(from, amount);

		emit Burned(operator, from, amount, userData, operatorData);
		emit Transfer(from, address(0), amount);
	}

	/**
	 * @notice Sets `amount` as the allowance of `spender` over the `account`s tokens.
	 *
	 * This is internal function is equivalent to `approve`, and can be used to
	 * e.g. set automatic allowances for certain subsystems, etc.
	 *
	 * Emits an {Approval} event.
	 *
	 * Requirements:
	 *
	 * - `account` cannot be the zero address.
	 * - `spender` cannot be the zero address.
	 */
	function _approve(address account, address spender, uint256 amount) internal {
		if (account == address(0)) {
			revert SUPER_TOKEN_APPROVE_FROM_ZERO_ADDRESS();
		}
		if (spender == address(0)) {
			revert SUPER_TOKEN_APPROVE_TO_ZERO_ADDRESS();
		}

		_allowances[account][spender] = amount;
		emit Approval(account, spender, amount);
	}

	/**
	 * @dev Call from.tokensToSend() if the interface is registered
	 * @param operator address operator requesting the transfer
	 * @param from address token holder address
	 * @param to address recipient address
	 * @param amount uint256 amount of tokens to transfer
	 * @param userData bytes extra information provided by the token holder (if any)
	 * @param operatorData bytes extra information provided by the operator (if any)
	 */
	function _callTokensToSend(
		address operator,
		address from,
		address to,
		uint256 amount,
		bytes memory userData,
		bytes memory operatorData
	) private {
		address implementer = ERC777Helper
			._ERC1820_REGISTRY
			.getInterfaceImplementer(
				from,
				ERC777Helper._TOKENS_SENDER_INTERFACE_HASH
			);
		if (implementer != address(0)) {
			IERC777Sender(implementer).tokensToSend(
				operator,
				from,
				to,
				amount,
				userData,
				operatorData
			);
		}
	}

	/**
	 * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but
	 * tokensReceived() was not registered for the recipient
	 * @param operator address operator requesting the transfer
	 * @param from address token holder address
	 * @param to address recipient address
	 * @param amount uint256 amount of tokens to transfer
	 * @param userData bytes extra information provided by the token holder (if any)
	 * @param operatorData bytes extra information provided by the operator (if any)
	 * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient
	 */
	function _callTokensReceived(
		address operator,
		address from,
		address to,
		uint256 amount,
		bytes memory userData,
		bytes memory operatorData,
		bool requireReceptionAck
	) private {
		address implementer = ERC777Helper
			._ERC1820_REGISTRY
			.getInterfaceImplementer(
				to,
				ERC777Helper._TOKENS_RECIPIENT_INTERFACE_HASH
			);
		if (implementer != address(0)) {
			IERC777Recipient(implementer).tokensReceived(
				operator,
				from,
				to,
				amount,
				userData,
				operatorData
			);
		} else if (requireReceptionAck) {
			if (to.isContract()) revert SUPER_TOKEN_NOT_ERC777_TOKENS_RECIPIENT();
		}
	}

	/**************************************************************************
	 * ERC20 Implementations
	 *************************************************************************/

	function totalSupply() public view override returns (uint256) {
		return _totalSupply;
	}

	function balanceOf(
		address account
	) public view override returns (uint256 balance) {
		// solhint-disable-next-line not-rely-on-time
		(int256 availableBalance, , , ) = super.realtimeBalanceOfNow(account);
		return availableBalance < 0 ? 0 : uint256(availableBalance);
	}

	function transfer(
		address recipient,
		uint256 amount
	) public virtual override returns (bool) {
		return _transferFrom(msg.sender, msg.sender, recipient, amount);
	}

	function allowance(
		address account,
		address spender
	) public view override returns (uint256) {
		return _allowances[account][spender];
	}

	function approve(
		address spender,
		uint256 amount
	) public override returns (bool) {
		_approve(msg.sender, spender, amount);
		return true;
	}

	function transferFrom(
		address holder,
		address recipient,
		uint256 amount
	) public override returns (bool) {
		return _transferFrom(msg.sender, holder, recipient, amount);
	}

	function increaseAllowance(
		address spender,
		uint256 addedValue
	) public override returns (bool) {
		_approve(
			msg.sender,
			spender,
			_allowances[msg.sender][spender] + addedValue
		);
		return true;
	}

	function decreaseAllowance(
		address spender,
		uint256 subtractedValue
	) public override returns (bool) {
		_approve(
			msg.sender,
			spender,
			_allowances[msg.sender][spender].sub(
				subtractedValue,
				"SuperToken: decreased allowance below zero"
			)
		);
		return true;
	}

	/**************************************************************************
	 * ERC-777 functions
	 *************************************************************************/

	function granularity() external pure override returns (uint256) {
		return 1;
	}

	function send(
		address recipient,
		uint256 amount,
		bytes calldata data
	) external override {
		_send(msg.sender, msg.sender, recipient, amount, data, "", true);
	}

	function burn(uint256 amount, bytes calldata data) external virtual override {
		_burn(msg.sender, msg.sender, amount, data, new bytes(0));
	}

	function isOperatorFor(
		address operator,
		address tokenHolder
	) external view override returns (bool) {
		return _operators.isOperatorFor(operator, tokenHolder);
	}

	function authorizeOperator(address operator) external override {
		address holder = msg.sender;
		_operators.authorizeOperator(holder, operator);
		emit AuthorizedOperator(operator, holder);
	}

	function revokeOperator(address operator) external override {
		address holder = msg.sender;
		_operators.revokeOperator(holder, operator);
		emit RevokedOperator(operator, holder);
	}

	function defaultOperators()
		external
		view
		override
		returns (address[] memory)
	{
		return ERC777Helper.defaultOperators(_operators);
	}

	function operatorSend(
		address sender,
		address recipient,
		uint256 amount,
		bytes calldata data,
		bytes calldata operatorData
	) external override {
		address operator = msg.sender;
		if (!_operators.isOperatorFor(operator, sender))
			revert SUPER_TOKEN_CALLER_IS_NOT_OPERATOR_FOR_HOLDER();
		_send(operator, sender, recipient, amount, data, operatorData, true);
	}

	function operatorBurn(
		address account,
		uint256 amount,
		bytes calldata data,
		bytes calldata operatorData
	) external override {
		address operator = msg.sender;
		if (!_operators.isOperatorFor(operator, account))
			revert SUPER_TOKEN_CALLER_IS_NOT_OPERATOR_FOR_HOLDER();
		_burn(operator, account, amount, data, operatorData);
	}

	function _setupDefaultOperators(address[] memory operators) internal {
		_operators.setupDefaultOperators(operators);
	}

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

	/// still used by erc20permit
	function selfApproveFor(
		address account,
		address spender,
		uint256 amount
	) external override onlySelf {
		_approve(account, spender, amount);
	}

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

	function allowHostOperations()
		internal
		view
		virtual
		override
		returns (bool hostEnabled)
	{
		return true;
	}

	function operationApprove(
		address account,
		address spender,
		uint256 amount
	) external override onlyHost {
		_approve(account, spender, amount);
	}

	function operationTransferFrom(
		address account,
		address spender,
		address recipient,
		uint256 amount
	) external override onlyHost {
		_transferFrom(account, spender, recipient, amount);
	}

	function operationSend(
		address spender,
		address recipient,
		uint256 amount,
		bytes memory userData
	) external override onlyHost {
		_send(msg.sender, spender, recipient, amount, userData, "", true);
	}

	function operationIncreaseAllowance(
		address account,
		address spender,
		uint256 addedValue
	) external override onlyHost {
		_approve(account, spender, _allowances[account][spender] + addedValue);
	}

	function operationDecreaseAllowance(
		address account,
		address spender,
		uint256 subtractedValue
	) external override onlyHost {
		_approve(
			account,
			spender,
			_allowances[account][spender].sub(
				subtractedValue,
				"SuperToken: decreased allowance below zero"
			)
		);
	}

	/**************************************************************************
	 * Celo gas token functions
	 *************************************************************************/

	/**
	 * @notice Reserve balance for making payments for gas in this StableToken currency.
	 * @param from The account to reserve balance from
	 * @param value The amount of balance to reserve
	 * @dev Note that this function is called by the protocol when paying for tx fees in this
	 * currency. After the tx is executed, gas is refunded to the sender and credited to the
	 * various tx fee recipients via a call to `creditGasFees`. Note too that the events emitted
	 * by `creditGasFees` reflect the *net* gas fee payments for the transaction.
	 */
	function debitGasFees(address from, uint256 value) external {
		require(msg.sender == address(0), "Only VM can call");
		SuperfluidToken._burn(from, value);
	}

	/**
	 * @notice Alternative function to credit balance after making payments
	 * for gas in this StableToken currency.
	 * @param from The account to debit balance from
	 * @param feeRecipient Coinbase address
	 * @param gatewayFeeRecipient Gateway address
	 * @param baseFeeRecipient baseFee recipient address
	 * @param tipTxFee Coinbase fee
	 * @param baseTxFee base fee
	 * @param gatewayFee Gateway fee
	 * @dev Note that this function is called by the protocol when paying for tx fees in this
	 * currency. Before the tx is executed, gas is debited from the sender via a call to
	 * `debitGasFees`. Note too that the events emitted by `creditGasFees` reflect the *net* gas fee
	 * payments for the transaction.
	 */
	function creditGasFees(
		address from,
		address feeRecipient,
		address gatewayFeeRecipient,
		address baseFeeRecipient,
		uint256 refund,
		uint256 tipTxFee,
		uint256 gatewayFee,
		uint256 baseTxFee
	) external {
		require(msg.sender == address(0), "Only VM can call");
		SuperfluidToken._mint(from, refund);

		_creditGas(from, feeRecipient, tipTxFee);
		_creditGas(from, baseFeeRecipient, baseTxFee);
		_creditGas(from, gatewayFeeRecipient, gatewayFee);
	}

	function _creditGas(address from, address to, uint256 value) internal {
		if (to == address(0)) {
			return;
		}
		SuperfluidToken._mint(to, value);
		emit Transfer(from, to, value);
	}

	/**************************************************************************
	 * Modifiers
	 *************************************************************************/

	modifier onlySelf() {
		if (msg.sender != address(this)) revert SUPER_TOKEN_ONLY_SELF();
		_;
	}
}
          

/contracts/token/superfluid/ISuperToken.sol

// SPDX-License-Identifier: AGPLv3
pragma solidity >=0.8.4;

import { IERC20, IERC777, TokenInfo } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol";
import { ISuperfluidToken } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol";
import { IConstantOutflowNFT } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/IConstantOutflowNFT.sol";
import { IConstantInflowNFT } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/IConstantInflowNFT.sol";
import { IPoolAdminNFT } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/IPoolAdminNFT.sol";
import { IPoolMemberNFT } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/IPoolMemberNFT.sol";

/**
 * @title Super token (Superfluid Token + ERC20 + ERC777) interface
 * @author Superfluid
 */
interface ISuperToken is ISuperfluidToken, TokenInfo, IERC20, IERC777 {
	/**************************************************************************
	 * Errors
	 *************************************************************************/
	error SUPER_TOKEN_CALLER_IS_NOT_OPERATOR_FOR_HOLDER(); // 0xf7f02227
	error SUPER_TOKEN_NOT_ERC777_TOKENS_RECIPIENT(); // 0xfe737d05
	error SUPER_TOKEN_INFLATIONARY_DEFLATIONARY_NOT_SUPPORTED(); // 0xe3e13698
	error SUPER_TOKEN_NO_UNDERLYING_TOKEN(); // 0xf79cf656
	error SUPER_TOKEN_ONLY_SELF(); // 0x7ffa6648
	error SUPER_TOKEN_ONLY_HOST(); // 0x98f73704
	error SUPER_TOKEN_ONLY_GOV_OWNER(); // 0xd9c7ed08
	error SUPER_TOKEN_APPROVE_FROM_ZERO_ADDRESS(); // 0x81638627
	error SUPER_TOKEN_APPROVE_TO_ZERO_ADDRESS(); // 0xdf070274
	error SUPER_TOKEN_BURN_FROM_ZERO_ADDRESS(); // 0xba2ab184
	error SUPER_TOKEN_MINT_TO_ZERO_ADDRESS(); // 0x0d243157
	error SUPER_TOKEN_TRANSFER_FROM_ZERO_ADDRESS(); // 0xeecd6c9b
	error SUPER_TOKEN_TRANSFER_TO_ZERO_ADDRESS(); // 0xe219bd39
	error SUPER_TOKEN_TRANSFER_TO_TOKEN_ADDRESS();
	error SUPER_TOKEN_NFT_PROXY_ALREADY_SET(); // 0x6bef249d

	/**
	 * @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 view override(IERC20) 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 and transfers the underlying token to the caller's account.
	 *
	 * 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 view override(IERC777) 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
		view
		override(IERC777)
		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 Give `spender`, `amount` allowance to spend the tokens of
	 * `account`.
	 *
	 * @custom:modifiers
	 *  - onlySelf
	 */
	function selfApproveFor(
		address account,
		address spender,
		uint256 amount
	) external;

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

	function operationIncreaseAllowance(
		address account,
		address spender,
		uint256 addedValue
	) external;

	function operationDecreaseAllowance(
		address account,
		address spender,
		uint256 subtractedValue
	) external;

	/**
	 * @dev Perform ERC20 transferFrom 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 the funds.
	 * @param amount Number of tokens to be transferred.
	 *
	 * @custom:modifiers
	 *  - onlyHost
	 */
	function operationTransferFrom(
		address account,
		address spender,
		address recipient,
		uint256 amount
	) external;

	/**
	 * @dev Perform ERC777 send by host contract.
	 * @param spender The account where the funds is sent from.
	 * @param recipient The recipient of the funds.
	 * @param amount Number of tokens to be transferred.
	 * @param data Arbitrary user inputted data
	 *
	 * @custom:modifiers
	 *  - onlyHost
	 */
	function operationSend(
		address spender,
		address recipient,
		uint256 amount,
		bytes memory data
	) external;

	/**************************************************************************
	 * ERC20x-specific Functions
	 *************************************************************************/

	function CONSTANT_OUTFLOW_NFT() external view returns (IConstantOutflowNFT);

	function CONSTANT_INFLOW_NFT() external view returns (IConstantInflowNFT);

	function poolAdminNFT() external view returns (IPoolAdminNFT);

	function poolMemberNFT() external view returns (IPoolMemberNFT);

	/**
	 * @dev Constant Outflow NFT proxy created event
	 * @param constantOutflowNFT constant outflow nft address
	 */
	event ConstantOutflowNFTCreated(
		IConstantOutflowNFT indexed constantOutflowNFT
	);

	/**
	 * @dev Constant Inflow NFT proxy created event
	 * @param constantInflowNFT constant inflow nft address
	 */
	event ConstantInflowNFTCreated(IConstantInflowNFT indexed constantInflowNFT);

	/**************************************************************************
	 * 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 it\
	//modifier onlySelf() virtual
}
          

/@superfluid-finance/ethereum-contracts/contracts/libs/EventsEmitter.sol

// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.19;

/**
 * @title Events Emitter Library
 * @author Superfluid
 * @dev A library used for emitting missing and unaccessable events.
 *
 */
library EventsEmitter {
    event Transfer(address indexed from, address indexed to, uint256 value);

    function emitTransfer(address from, address to, uint256 value) internal {
        emit Transfer(from, to, value);
    }
}
          

/contracts/token/superfluid/ISuperGoodDollar.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.8;

import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";
import { ISuperToken } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/CustomSuperTokenBase.sol";
import "../IFeesFormula.sol";
import "../../Interfaces.sol";

// GoodDollar specific functions
interface IGoodDollarCustom {
	// view functions
	function feeRecipient() external view returns (address);

	function getFees(
		uint256 value
	) external view returns (uint256 fee, bool senderPays);

	function getFees(
		uint256 value,
		address sender,
		address recipient
	) external view returns (uint256 fee, bool senderPays);

	function formula() external view returns (IFeesFormula);

	function identity() external view returns (IIdentity);

	function cap() external view returns (uint256);

	function isMinter(address _minter) external view returns (bool);

	function isPauser(address _pauser) external view returns (bool);

	function owner() external view returns (address);

	// state changing functions
	function setFeeRecipient(address _feeRecipient) external;

	function setFormula(IFeesFormula _formula) external;

	function setIdentity(IIdentityV2 _identity) external;

	function transferOwnership(address _owner) external;

	function transferAndCall(
		address to,
		uint256 value,
		bytes calldata data
	) external returns (bool);

	function mint(address to, uint256 amount) external returns (bool);

	function burn(uint256 amount) external;

	function burnFrom(address account, uint256 amount) external;

	function addMinter(address _minter) external;

	function renounceMinter() external;

	function addPauser(address _pauser) external;

	function pause() external;

	function unpause() external;
}

interface ISuperGoodDollar is
	IGoodDollarCustom,
	ISuperToken,
	IERC20PermitUpgradeable
{
	function initialize(
		string calldata name,
		string calldata symbol,
		uint256 _cap,
		IFeesFormula _formula,
		IIdentity _identity,
		address _feeRecipient,
		address _owner
	) external;
}
          

/contracts/token/superfluid/ERC20Permit.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.8;

import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

import "./SuperToken.sol";

interface SelfApprove {
	function selfApproveFor(
		address account,
		address spender,
		uint256 amount
	) external;
}

abstract contract ERC20Permit is IERC20PermitUpgradeable, EIP712Upgradeable {
	mapping(address => uint256) private _nonces;

	// solhint-disable-next-line var-name-mixedcase
	bytes32 private _PERMIT_TYPEHASH;

	/**
	 * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
	 *
	 * It's a good idea to use the same `name` that is defined as the ERC20 token name.
	 */
	function __ERC20Permit_init(string memory name) internal onlyInitializing {
		__EIP712_init_unchained(name, "1");
		__ERC20Permit_init_unchained(name);
	}

	function __ERC20Permit_init_unchained(string memory name)
		internal
		onlyInitializing
	{
		_PERMIT_TYPEHASH = keccak256(
			"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
		);
	}

	/**
	 * @dev See {IERC20Permit-permit}.
	 */
	function permit(
		address owner,
		address spender,
		uint256 value,
		uint256 deadline,
		uint8 v,
		bytes32 r,
		bytes32 s
	) public virtual {
		require(block.timestamp <= deadline, "ERC20Permit: expired deadline");

		bytes32 structHash = keccak256(
			abi.encode(
				_PERMIT_TYPEHASH,
				owner,
				spender,
				value,
				_useNonce(owner),
				deadline
			)
		);

		bytes32 hash = _hashTypedDataV4(structHash);

		address signer = ECDSAUpgradeable.recover(hash, v, r, s);
		require(signer == owner, "ERC20Permit: invalid signature");

		SelfApprove(address(this)).selfApproveFor(owner, spender, value);
	}

	/**
	 * @dev See {IERC20Permit-nonces}.
	 */
	function nonces(address owner) public view virtual returns (uint256) {
		return _nonces[owner];
	}

	/**
	 * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
	 */
	// solhint-disable-next-line func-name-mixedcase
	function DOMAIN_SEPARATOR() external view returns (bytes32) {
		return _domainSeparatorV4();
	}

	/**
	 * @dev "Consume a nonce": return the current value and increment.
	 *
	 * _Available since v4.1._
	 */

	function _useNonce(address owner) internal virtual returns (uint256 current) {
		current = _nonces[owner];
		_nonces[owner]++;
	}
}
          

/contracts/token/IFeesFormula.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.8;

interface IFeesFormula {
	function getTxFees(
		uint256 value,
		address sender,
		address recipient
	) external view returns (uint256 fee, bool senderPays);
}
          

/contracts/token/ERC677.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.8;

/* @title ERC677Receiver interface
 */
interface ERC677Receiver {
	function onTokenTransfer(
		address _from,
		uint256 _value,
		bytes calldata _data
	) external returns (bool);
}

abstract contract ERC677 {
	event Transfer(
		address indexed from,
		address indexed to,
		uint256 value,
		bytes data
	);

	function transfer(address to, uint256 value) public virtual returns (bool);

	/**
	 * @dev transfer token to a contract address with additional data if the recipient is a contact.
	 * @param _to The address to transfer to.
	 * @param _value The amount to be transferred.
	 * @param _data The extra data to be passed to the receiving contract.
	 * @return true if transfer is successful
	 */
	function _transferAndCall(
		address _to,
		uint256 _value,
		bytes memory _data
	) internal returns (bool) {
		bool res = transfer(_to, _value);
		emit Transfer(msg.sender, _to, _value, _data);

		if (isContract(_to)) {
			require(contractFallback(_to, _value, _data), "Contract fallback failed");
		}
		return res;
	}

	/* @dev Contract fallback function. Is called if transferAndCall is called
	 * to a contract
	 */
	function contractFallback(
		address _to,
		uint256 _value,
		bytes memory _data
	) internal virtual returns (bool) {
		ERC677Receiver receiver = ERC677Receiver(_to);
		require(
			receiver.onTokenTransfer(msg.sender, _value, _data),
			"Contract Fallback failed"
		);
		return true;
	}

	/* @dev Function to check if given address is a contract
	 * @param _addr Address to check
	 * @return true if given address is a contract
	 */

	function isContract(address _addr) internal view returns (bool) {
		uint256 length;
		assembly {
			length := extcodesize(_addr)
		}
		return length > 0;
	}
}
          

/contracts/Interfaces.sol

// SPDX-License-Identifier: MIT
import { DataTypes } from "./utils/DataTypes.sol";
pragma solidity >=0.8.0;

pragma experimental ABIEncoderV2;

interface ERC20 {
	function balanceOf(address addr) external view returns (uint256);

	function transfer(address to, uint256 amount) external returns (bool);

	function approve(address spender, uint256 amount) external returns (bool);

	function decimals() external view returns (uint8);

	function mint(address to, uint256 mintAmount) external returns (uint256);

	function burn(uint256 amount) external;

	function totalSupply() external view returns (uint256);

	function allowance(
		address owner,
		address spender
	) external view returns (uint256);

	function transferFrom(
		address sender,
		address recipient,
		uint256 amount
	) external returns (bool);

	function name() external view returns (string memory);

	function symbol() external view returns (string memory);

	event Transfer(address indexed from, address indexed to, uint256 amount);
	event Transfer(
		address indexed from,
		address indexed to,
		uint256 amount,
		bytes data
	);
}

interface cERC20 is ERC20 {
	function mint(uint256 mintAmount) external returns (uint256);

	function redeemUnderlying(uint256 mintAmount) external returns (uint256);

	function redeem(uint256 mintAmount) external returns (uint256);

	function exchangeRateCurrent() external returns (uint256);

	function exchangeRateStored() external view returns (uint256);

	function underlying() external returns (address);
}

interface IGoodDollar is ERC20 {
	// view functions
	function feeRecipient() external view returns (address);

	function getFees(
		uint256 value,
		address sender,
		address recipient
	) external view returns (uint256 fee, bool senderPays);

	function cap() external view returns (uint256);

	function isPauser(address _pauser) external view returns (bool);

	function getFees(uint256 value) external view returns (uint256, bool);

	function isMinter(address minter) external view returns (bool);

	function formula() external view returns (address);

	function identity() external view returns (address);

	function owner() external view returns (address);

	// state changing functions
	function setFeeRecipient(address _feeRecipient) external;

	function setFormula(address _formula) external;

	function transferOwnership(address _owner) external;

	function addPauser(address _pauser) external;

	function pause() external;

	function unpause() external;

	function burn(uint256 amount) external;

	function burnFrom(address account, uint256 amount) external;

	function renounceMinter() external;

	function addMinter(address minter) external;

	function transferAndCall(
		address to,
		uint256 value,
		bytes calldata data
	) external returns (bool);

	function setIdentity(address identity) external;
}

interface IERC2917 is ERC20 {
	/// @dev This emit when interests amount per block is changed by the owner of the contract.
	/// It emits with the old interests amount and the new interests amount.
	event InterestRatePerBlockChanged(uint256 oldValue, uint256 newValue);

	/// @dev This emit when a users' productivity has changed
	/// It emits with the user's address and the the value after the change.
	event ProductivityIncreased(address indexed user, uint256 value);

	/// @dev This emit when a users' productivity has changed
	/// It emits with the user's address and the the value after the change.
	event ProductivityDecreased(address indexed user, uint256 value);

	/// @dev Return the current contract's interests rate per block.
	/// @return The amount of interests currently producing per each block.
	function interestsPerBlock() external view returns (uint256);

	/// @notice Change the current contract's interests rate.
	/// @dev Note the best practice will be restrict the gross product provider's contract address to call this.
	/// @return The true/fase to notice that the value has successfully changed or not, when it succeed, it will emite the InterestRatePerBlockChanged event.
	function changeInterestRatePerBlock(uint256 value) external returns (bool);

	/// @notice It will get the productivity of given user.
	/// @dev it will return 0 if user has no productivity proved in the contract.
	/// @return user's productivity and overall productivity.
	function getProductivity(
		address user
	) external view returns (uint256, uint256);

	/// @notice increase a user's productivity.
	/// @dev Note the best practice will be restrict the callee to prove of productivity's contract address.
	/// @return true to confirm that the productivity added success.
	function increaseProductivity(
		address user,
		uint256 value
	) external returns (bool);

	/// @notice decrease a user's productivity.
	/// @dev Note the best practice will be restrict the callee to prove of productivity's contract address.
	/// @return true to confirm that the productivity removed success.
	function decreaseProductivity(
		address user,
		uint256 value
	) external returns (bool);

	/// @notice take() will return the interests that callee will get at current block height.
	/// @dev it will always calculated by block.number, so it will change when block height changes.
	/// @return amount of the interests that user are able to mint() at current block height.
	function take() external view returns (uint256);

	/// @notice similar to take(), but with the block height joined to calculate return.
	/// @dev for instance, it returns (_amount, _block), which means at block height _block, the callee has accumulated _amount of interests.
	/// @return amount of interests and the block height.
	function takeWithBlock() external view returns (uint256, uint256);

	/// @notice mint the avaiable interests to callee.
	/// @dev once it mint, the amount of interests will transfer to callee's address.
	/// @return the amount of interests minted.
	function mint() external returns (uint256);
}

interface Staking {
	struct Staker {
		// The staked DAI amount
		uint256 stakedDAI;
		// The latest block number which the
		// staker has staked tokens
		uint256 lastStake;
	}

	function stakeDAI(uint256 amount) external;

	function withdrawStake() external;

	function stakers(address staker) external view returns (Staker memory);
}

interface Uniswap {
	function swapExactETHForTokens(
		uint256 amountOutMin,
		address[] calldata path,
		address to,
		uint256 deadline
	) external payable returns (uint256[] memory amounts);

	function swapExactTokensForETH(
		uint256 amountIn,
		uint256 amountOutMin,
		address[] calldata path,
		address to,
		uint256 deadline
	) external returns (uint256[] memory amounts);

	function swapExactTokensForTokens(
		uint256 amountIn,
		uint256 amountOutMin,
		address[] calldata path,
		address to,
		uint256 deadline
	) external returns (uint256[] memory amounts);

	function WETH() external pure returns (address);

	function factory() external pure returns (address);

	function quote(
		uint256 amountA,
		uint256 reserveA,
		uint256 reserveB
	) external pure returns (uint256 amountB);

	function getAmountIn(
		uint256 amountOut,
		uint256 reserveIn,
		uint256 reserveOut
	) external pure returns (uint256 amountIn);

	function getAmountOut(
		uint256 amountI,
		uint256 reserveIn,
		uint256 reserveOut
	) external pure returns (uint256 amountOut);

	function getAmountsOut(
		uint256 amountIn,
		address[] memory path
	) external pure returns (uint256[] memory amounts);
}

interface UniswapFactory {
	function getPair(
		address tokenA,
		address tokenB
	) external view returns (address);
}

interface UniswapPair {
	function getReserves()
		external
		view
		returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);

	function kLast() external view returns (uint256);

	function token0() external view returns (address);

	function token1() external view returns (address);

	function totalSupply() external view returns (uint256);

	function balanceOf(address owner) external view returns (uint256);
}

interface Reserve {
	function buy(
		address _buyWith,
		uint256 _tokenAmount,
		uint256 _minReturn
	) external returns (uint256);
}

interface IIdentity {
	function isWhitelisted(address user) external view returns (bool);

	function addWhitelistedWithDID(address account, string memory did) external;

	function removeWhitelisted(address account) external;

	function addBlacklisted(address account) external;

	function removeBlacklisted(address account) external;

	function isBlacklisted(address user) external view returns (bool);

	function addIdentityAdmin(address account) external returns (bool);

	function setAvatar(address _avatar) external;

	function isIdentityAdmin(address account) external view returns (bool);

	function owner() external view returns (address);

	function removeContract(address account) external;

	function isDAOContract(address account) external view returns (bool);

	function addrToDID(address account) external view returns (string memory);

	function didHashToAddress(bytes32 hash) external view returns (address);

	function lastAuthenticated(address account) external view returns (uint256);

	event WhitelistedAdded(address user);
}

interface IIdentityV2 is IIdentity {
	function addWhitelistedWithDIDAndChain(
		address account,
		string memory did,
		uint256 orgChainId,
		uint256 dateAuthenticated
	) external;

	function getWhitelistedRoot(
		address account
	) external view returns (address root);
}

interface IUBIScheme {
	function currentDay() external view returns (uint256);

	function periodStart() external view returns (uint256);

	function hasClaimed(address claimer) external view returns (bool);
}

interface IFirstClaimPool {
	function awardUser(address user) external returns (uint256);

	function claimAmount() external view returns (uint256);

	function end() external;
}

interface ProxyAdmin {
	function getProxyImplementation(
		address proxy
	) external view returns (address);

	function getProxyAdmin(address proxy) external view returns (address);

	function upgrade(address proxy, address implementation) external;

	function owner() external view returns (address);

	function transferOwnership(address newOwner) external;

	function upgradeAndCall(
		address proxy,
		address implementation,
		bytes memory data
	) external;
}

/**
 * @dev Interface for chainlink oracles to obtain price datas
 */
interface AggregatorV3Interface {
	function decimals() external view returns (uint8);

	function description() external view returns (string memory);

	function version() external view returns (uint256);

	// getRoundData and latestRoundData should both raise "No data present"
	// if they do not have data to report, instead of returning unset values
	// which could be misinterpreted as actual reported values.
	function getRoundData(
		uint80 _roundId
	)
		external
		view
		returns (
			uint80 roundId,
			int256 answer,
			uint256 startedAt,
			uint256 updatedAt,
			uint80 answeredInRound
		);

	function latestAnswer() external view returns (int256);
}

/**
	@dev interface for AAVE lending Pool
 */
interface ILendingPool {
	/**
	 * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
	 * - E.g. User deposits 100 USDC and gets in return 100 aUSDC
	 * @param asset The address of the underlying asset to deposit
	 * @param amount The amount to be deposited
	 * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
	 *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
	 *   is a different wallet
	 * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
	 *   0 if the action is executed directly by the user, without any middle-man
	 **/
	function deposit(
		address asset,
		uint256 amount,
		address onBehalfOf,
		uint16 referralCode
	) external;

	/**
	 * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
	 * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
	 * @param asset The address of the underlying asset to withdraw
	 * @param amount The underlying amount to be withdrawn
	 *   - Send the value type(uint256).max in order to withdraw the whole aToken balance
	 * @param to Address that will receive the underlying, same as msg.sender if the user
	 *   wants to receive it on his own wallet, or a different address if the beneficiary is a
	 *   different wallet
	 * @return The final amount withdrawn
	 **/
	function withdraw(
		address asset,
		uint256 amount,
		address to
	) external returns (uint256);

	/**
	 * @dev Returns the state and configuration of the reserve
	 * @param asset The address of the underlying asset of the reserve
	 * @return The state of the reserve
	 **/
	function getReserveData(
		address asset
	) external view returns (DataTypes.ReserveData memory);
}

interface IDonationStaking {
	function stakeDonations() external payable;
}

interface INameService {
	function getAddress(string memory _name) external view returns (address);
}

interface IAaveIncentivesController {
	/**
	 * @dev Claims reward for an user, on all the assets of the lending pool, accumulating the pending rewards
	 * @param amount Amount of rewards to claim
	 * @param to Address that will be receiving the rewards
	 * @return Rewards claimed
	 **/
	function claimRewards(
		address[] calldata assets,
		uint256 amount,
		address to
	) external returns (uint256);

	/**
	 * @dev Returns the total of rewards of an user, already accrued + not yet accrued
	 * @param user The address of the user
	 * @return The rewards
	 **/
	function getRewardsBalance(
		address[] calldata assets,
		address user
	) external view returns (uint256);
}

interface IGoodStaking {
	function collectUBIInterest(
		address recipient
	) external returns (uint256, uint256, uint256);

	function iToken() external view returns (address);

	function currentGains(
		bool _returnTokenBalanceInUSD,
		bool _returnTokenGainsInUSD
	) external view returns (uint256, uint256, uint256, uint256, uint256);

	function getRewardEarned(address user) external view returns (uint256);

	function getGasCostForInterestTransfer() external view returns (uint256);

	function rewardsMinted(
		address user,
		uint256 rewardsPerBlock,
		uint256 blockStart,
		uint256 blockEnd
	) external returns (uint256);
}

interface IHasRouter {
	function getRouter() external view returns (Uniswap);
}

interface IAdminWallet {
	function addAdmins(address payable[] memory _admins) external;

	function removeAdmins(address[] memory _admins) external;

	function owner() external view returns (address);

	function transferOwnership(address _owner) external;
}

interface IMultichainRouter {
	// Swaps `amount` `token` from this chain to `toChainID` chain with recipient `to`
	function anySwapOut(
		address token,
		address to,
		uint256 amount,
		uint256 toChainID
	) external;

	// Swaps `amount` `token` from this chain to `toChainID` chain with recipient `to`
	function anySwapOutUnderlying(
		address token,
		address to,
		uint256 amount,
		uint256 toChainID
	) external;
}
          

/@superfluid-finance/ethereum-contracts/contracts/upgradability/UUPSUtils.sol

// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.19;

/**
 * @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
            )
        }
    }

}
          

/@superfluid-finance/ethereum-contracts/contracts/libs/FixedSizeData.sol

// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.19;

/**
 * @title Utilities for fixed size data in storage
 * @author Superfluid
 *
 * When using solidity dynamic array, first word is used to store the length
 * of the array. For use cases that the length doesn't change, it is better
 * to use a fixed size data premitive.
 *
 * To use this library:
 * - The pointer to the storage is `slot`, the user could use `keccak256(abi.encode(...))`
 *   scheme to create collision-free slot ID for locating the data.
 * - To load data, or erase data and get all gas refund, data length is always required.
 */
library FixedSizeData {

    /**
     * @dev Store data to the slot at `slot`
     */
    function storeData(bytes32 slot, bytes32[] memory data) internal {
        for (uint j = 0; j < data.length; ++j) {
            bytes32 d = data[j];
            assembly { sstore(add(slot, j), d) }
        }
    }

    function hasData(bytes32 slot, uint dataLength) internal view returns (bool) {
        for (uint j = 0; j < dataLength; ++j) {
            bytes32 d;
            assembly { d := sload(add(slot, j)) }
            if (uint256(d) > 0) return true;
        }
        return false;
    }

    /**
     * @dev Load data of size `dataLength` from the slot at `slot`
     */
    function loadData(bytes32 slot, uint dataLength) internal view returns (bytes32[] memory data) {
        data = new bytes32[](dataLength);
        for (uint j = 0; j < dataLength; ++j) {
            bytes32 d;
            assembly { d := sload(add(slot, j)) }
            data[j] = d;
        }
    }

    /**
     * @dev Erase data of size `dataLength` from the slot at `slot`
     */
    function eraseData(bytes32 slot, uint dataLength) internal {
        for (uint j = 0; j < dataLength; ++j) {
            assembly { sstore(add(slot, j), 0) }
        }
    }

}
          

/@superfluid-finance/ethereum-contracts/contracts/libs/ERC777Helper.sol

// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.19;

import { IERC1820Registry } from "@openzeppelin/contracts/utils/introspection/IERC1820Registry.sol";

/**
 * @title ERC777 helper library
 * @author Superfluid
 */
library ERC777Helper {

    IERC1820Registry constant internal _ERC1820_REGISTRY =
        IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);

    bytes32 constant internal _TOKENS_SENDER_INTERFACE_HASH = keccak256("ERC777TokensSender");
    bytes32 constant internal _TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient");


    /// @dev ERC777 operators support self structure
    struct Operators {
        address[] defaultOperatorsArray;
        mapping(address => bool) defaultOperators;
        mapping(address => mapping(address => bool)) operators;
        mapping(address => mapping(address => bool)) revokedDefaultOperators;
    }

    function register(address token) internal {
        _ERC1820_REGISTRY.setInterfaceImplementer(token, keccak256("ERC777Token"), address(this));
        _ERC1820_REGISTRY.setInterfaceImplementer(token, keccak256("ERC20Token"), address(this));
    }

    function isOperatorFor(Operators storage self, address operator, address tokenHolder) internal view returns (bool) {
        return operator == tokenHolder ||
            (
                self.defaultOperators[operator] &&
                !self.revokedDefaultOperators[tokenHolder][operator]
            ) ||
            self.operators[tokenHolder][operator];
    }

    function authorizeOperator(Operators storage self, address holder, address operator) internal {
        require(holder != operator, "ERC777Operators: authorizing self as operator");

        if (self.defaultOperators[operator]) {
            delete self.revokedDefaultOperators[holder][operator];
        } else {
            self.operators[holder][operator] = true;
        }
    }

    function revokeOperator(Operators storage self, address holder, address operator) internal {
        require(operator != msg.sender, "ERC777Operators: revoking self as operator");
        if (self.defaultOperators[operator]) {
            self.revokedDefaultOperators[holder][operator] = true;
        } else {
            delete self.operators[holder][operator];
        }
    }

    function defaultOperators(Operators storage self) internal view returns (address[] memory) {
        return self.defaultOperatorsArray;
    }

    function setupDefaultOperators(Operators storage self, address[] memory operators) internal {
        // According to 777 spec: default operators should only be setup once
        assert(self.defaultOperatorsArray.length == 0);
        self.defaultOperatorsArray = operators;
        for (uint i = 0; i < operators.length; ++i) {
            self.defaultOperators[operators[i]] = true;
        }
    }

}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/tokens/TokenInfo.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

/**
 * @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);
}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/tokens/ISETH.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

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


/**
 * @title Super ETH (SETH) custom token interface
 * @author Superfluid
 */
interface ISETHCustom {
    // using native token
    function upgradeByETH() external payable;
    function upgradeByETHTo(address to) external payable;
    function downgradeToETH(uint wad) external;
}

/**
 * @title Super ETH (SETH) full interface
 * @author Superfluid
 */
// solhint-disable-next-line no-empty-blocks
interface ISETH is ISETHCustom, ISuperToken {}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/tokens/ERC20WithTokenInfo.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

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 {}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

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

/**
 * @title Superfluid token interface
 * @author Superfluid
 */
interface ISuperfluidToken {

    /**************************************************************************
     * Errors
     *************************************************************************/
    error SF_TOKEN_AGREEMENT_ALREADY_EXISTS();  // 0xf05521f6
    error SF_TOKEN_AGREEMENT_DOES_NOT_EXIST();  // 0xdae18809
    error SF_TOKEN_BURN_INSUFFICIENT_BALANCE(); // 0x10ecdf44
    error SF_TOKEN_MOVE_INSUFFICIENT_BALANCE(); // 0x2f4cb941
    error SF_TOKEN_ONLY_LISTED_AGREEMENT();     // 0xc9ff6644
    error SF_TOKEN_ONLY_HOST();                 // 0xc51efddd

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

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidGovernance.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

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

/**
 * @title Superfluid governance interface
 * @author Superfluid
 */
interface ISuperfluidGovernance {

    /**************************************************************************
     * Errors
     *************************************************************************/
    error SF_GOV_INVALID_LIQUIDATION_OR_PATRICIAN_PERIOD(); // 0xe171980a
    error SF_GOV_MUST_BE_CONTRACT();                        // 0x80dddd73

    /**
     * @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 Update supertoken logic contract to the provided logic contracts.
     *      Note that this is an overloaded version taking an additional argument `tokenLogics`
     */
    function batchUpdateSuperTokenLogic(
        ISuperfluid host,
        ISuperToken[] calldata tokens,
        address[] calldata tokenLogics) 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);

}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

// ISuperfluid.sol can also be used as an umbrella-import for everything Superfluid, hence we should have these unused
// import.
//
// solhint-disable no-unused-import

/// Global definitions
import {
    SuperAppDefinitions,
    ContextDefinitions,
    FlowOperatorDefinitions,
    BatchOperation,
    SuperfluidGovernanceConfigs
} from "./Definitions.sol";
/// Super token related interfaces:
/// Note: CustomSuperTokenBase is not included for people building CustomSuperToken.
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC777 } from "@openzeppelin/contracts/token/ERC777/IERC777.sol";
import { TokenInfo, ERC20WithTokenInfo } from "../tokens/ERC20WithTokenInfo.sol";
import { ISuperfluidToken } from "./ISuperfluidToken.sol";
import { ISuperToken } from "./ISuperToken.sol";
import { ISuperTokenFactory } from "./ISuperTokenFactory.sol";
import { ISETH } from "../tokens/ISETH.sol";
/// Superfluid/ERC20x NFTs
import { IFlowNFTBase } from "./IFlowNFTBase.sol";
import { IConstantOutflowNFT } from "./IConstantOutflowNFT.sol";
import { IConstantInflowNFT } from "./IConstantInflowNFT.sol";
import { IPoolAdminNFT } from "./IPoolAdminNFT.sol";
import { IPoolMemberNFT } from "./IPoolMemberNFT.sol";
/// Superfluid agreement interfaces:
import { ISuperAgreement } from "./ISuperAgreement.sol";
import { IConstantFlowAgreementV1 } from "../agreements/IConstantFlowAgreementV1.sol";
import { IInstantDistributionAgreementV1 } from "../agreements/IInstantDistributionAgreementV1.sol";
/// Superfluid App interfaces:
import { ISuperApp } from "./ISuperApp.sol";
/// Superfluid governance
import { ISuperfluidGovernance } from "./ISuperfluidGovernance.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 {

    /**************************************************************************
     * Errors
     *************************************************************************/
    // Superfluid Custom Errors
    error HOST_AGREEMENT_CALLBACK_IS_NOT_ACTION();              // 0xef4295f6
    error HOST_CANNOT_DOWNGRADE_TO_NON_UPGRADEABLE();           // 0x474e7641
    error HOST_CALL_AGREEMENT_WITH_CTX_FROM_WRONG_ADDRESS();    // 0x0cd0ebc2
    error HOST_CALL_APP_ACTION_WITH_CTX_FROM_WRONG_ADDRESS();   // 0x473f7bd4
    error HOST_INVALID_CONFIG_WORD();                           // 0xf4c802a4
    error HOST_MAX_256_AGREEMENTS();                            // 0x7c281a78
    error HOST_NON_UPGRADEABLE();                               // 0x14f72c9f
    error HOST_NON_ZERO_LENGTH_PLACEHOLDER_CTX();               // 0x67e9985b
    error HOST_ONLY_GOVERNANCE();                               // 0xc5d22a4e
    error HOST_UNKNOWN_BATCH_CALL_OPERATION_TYPE();             // 0xb4770115
    error HOST_AGREEMENT_ALREADY_REGISTERED();                  // 0xdc9ddba8
    error HOST_AGREEMENT_IS_NOT_REGISTERED();                   // 0x1c9e9bea
    error HOST_MUST_BE_CONTRACT();                              // 0xd4f6b30c
    error HOST_ONLY_LISTED_AGREEMENT();                         // 0x619c5359
    error HOST_NEED_MORE_GAS();                                 // 0xd4f5d496

    // App Related Custom Errors
    // uses SuperAppDefinitions' App Jail Reasons as _code
    error APP_RULE(uint256 _code);                              // 0xa85ba64f

    error HOST_INVALID_OR_EXPIRED_SUPER_APP_REGISTRATION_KEY(); // 0x19ab84d1
    error HOST_NOT_A_SUPER_APP();                               // 0x163cbe43
    error HOST_NO_APP_REGISTRATION_PERMISSIONS();               // 0x5b93ebf0
    error HOST_RECEIVER_IS_NOT_SUPER_APP();                     // 0x96aa315e
    error HOST_SENDER_IS_NOT_SUPER_APP();                       // 0xbacfdc40
    error HOST_SOURCE_APP_NEEDS_HIGHER_APP_LEVEL();             // 0x44725270
    error HOST_SUPER_APP_IS_JAILED();                           // 0x02384b64
    error HOST_SUPER_APP_ALREADY_REGISTERED();                  // 0x01b0a935
    error HOST_UNAUTHORIZED_SUPER_APP_FACTORY();                // 0x289533c5

    /**************************************************************************
     * 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 (canonical) implementation
     * if `newLogicOverride` is zero, or to `newLogicOverride` otherwise.
     * or to the provided implementation `.
     * @dev Refer to ISuperTokenFactory.Upgradability for expected behaviours
     */
    function updateSuperTokenLogic(ISuperToken token, address newLogicOverride) external;
    /**
     * @notice Update the super token logic to the provided one
     * @dev newLogic must implement UUPSProxiable with matching proxiableUUID
     */
    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 callbacklevel
     * @param app Super app address
     */
    function getAppCallbackLevel(ISuperApp app) external view returns(uint8 appCallbackLevel);

    /**
     * @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 credit 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  appCreditGranted        App credit granted so far.
     * @param  appCreditUsed           App credit used so far.
     * @return newCtx                  The current context of the transaction.
     */
    function appCallbackPush(
        bytes calldata ctx,
        ISuperApp app,
        uint256 appCreditGranted,
        int256 appCreditUsed,
        ISuperfluidToken appCreditToken
    )
        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  appCreditUsedDelta      App credit 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 appCreditUsedDelta
    )
        external
        // onlyAgreement
        returns (bytes memory newCtx);

    /**
     * @dev (For agreements) Use app credit.
     * @param  ctx                      The current ctx, it will be validated.
     * @param  appCreditUsedMore        See app credit for more details.
     * @return newCtx                   The current context of the transaction.
     */
    function ctxUseCredit(
        bytes calldata ctx,
        int256 appCreditUsedMore
    )
        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.
     * - We cannot change the structure of the Context struct because of ABI compatibility requirements
     */
    struct Context {
        //
        // Call context
        //
        // app callback level
        uint8 appCallbackLevel;
        // 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 credit granted
        uint256 appCreditGranted;
        // app credit wanted by the app callback
        uint256 appCreditWantedDeprecated;
        // app credit used, allowing negative values over a callback session
        // the appCreditUsed value over a callback sessions is calculated with:
        // existing flow data owed deposit + sum of the callback agreements
        // deposit deltas
        // the final value used to modify the state is determined by the
        // _adjustNewAppCreditUsed function (in AgreementLibrary.sol) which takes
        // the appCreditUsed value reached in the callback session and the app
        // credit granted
        int256 appCreditUsed;
        // app address
        address appAddress;
        // app credit in super token
        ISuperfluidToken appCreditToken;
    }

    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 memory 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[] calldata operations) external;

    /**
     * @dev Batch call function for trusted forwarders (EIP-2771)
     * @param operations Array of batch operations
     */
    function forwardBatchCall(Operation[] calldata 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; */
}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperTokenFactory.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

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

/**
 * @title Super token factory interface
 * @author Superfluid
 */
interface ISuperTokenFactory {

    /**************************************************************************
     * Errors
     *************************************************************************/
    error SUPER_TOKEN_FACTORY_ALREADY_EXISTS();                 // 0x91d67972
    error SUPER_TOKEN_FACTORY_DOES_NOT_EXIST();                 // 0x872cac48
    error SUPER_TOKEN_FACTORY_UNINITIALIZED();                  // 0x1b39b9b4
    error SUPER_TOKEN_FACTORY_ONLY_HOST();                      // 0x478b8e83
    error SUPER_TOKEN_FACTORY_NON_UPGRADEABLE_IS_DEPRECATED();  // 0xc4901a43
    error SUPER_TOKEN_FACTORY_ZERO_ADDRESS();                   // 0x305c9e82

    /**************************************************************************
    * Immutable Variables
    **************************************************************************/

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

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

    /**
     * @notice Get the canonical super token logic.
     */
    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_UPGRADABLE
    }

    /**
     * @notice 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
     * @return superToken The deployed and initialized wrapper super token
     */
    function createERC20Wrapper(
        IERC20 underlyingToken,
        uint8 underlyingDecimals,
        Upgradability upgradability,
        string calldata name,
        string calldata symbol
    )
        external
        returns (ISuperToken superToken);

    /**
     * @notice 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
     * @return superToken The deployed and initialized wrapper super token
     * NOTE:
     * - It assumes token provide the .decimals() function
     */
    function createERC20Wrapper(
        ERC20WithTokenInfo underlyingToken,
        Upgradability upgradability,
        string calldata name,
        string calldata symbol
    )
        external
        returns (ISuperToken superToken);

    /**
     * @notice Creates a wrapper super token AND sets it in the canonical list OR reverts if it already exists
     * @dev salt for create2 is the keccak256 hash of abi.encode(address(_underlyingToken))
     * @param _underlyingToken Underlying ERC20 token
     * @return ISuperToken the created supertoken
     */
    function createCanonicalERC20Wrapper(ERC20WithTokenInfo _underlyingToken)
        external
        returns (ISuperToken);

    /**
     * @notice Computes/Retrieves wrapper super token address given the underlying token address
     * @dev We return from our canonical list if it already exists, otherwise we compute it
     * @dev note that this function only computes addresses for SEMI_UPGRADABLE SuperTokens
     * @param _underlyingToken Underlying ERC20 token address
     * @return superTokenAddress Super token address
     * @return isDeployed whether the super token is deployed AND set in the canonical mapping
     */
    function computeCanonicalERC20WrapperAddress(address _underlyingToken)
        external
        view
        returns (address superTokenAddress, bool isDeployed);

    /**
     * @notice Gets the canonical ERC20 wrapper super token address given the underlying token address
     * @dev We return the address if it exists and the zero address otherwise
     * @param _underlyingTokenAddress Underlying ERC20 token address
     * @return superTokenAddress Super token address
     */
    function getCanonicalERC20Wrapper(address _underlyingTokenAddress)
        external
        view
        returns (address superTokenAddress);

    /**
     * @dev Creates a new custom super token
     * @param customSuperTokenProxy address of the custom supertoken proxy
     */
    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);

}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperToken.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

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";
import { IConstantOutflowNFT } from "./IConstantOutflowNFT.sol";
import { IConstantInflowNFT } from "./IConstantInflowNFT.sol";

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

    /**************************************************************************
     * Errors
     *************************************************************************/
    error SUPER_TOKEN_CALLER_IS_NOT_OPERATOR_FOR_HOLDER();       // 0xf7f02227
    error SUPER_TOKEN_NOT_ERC777_TOKENS_RECIPIENT();             // 0xfe737d05
    error SUPER_TOKEN_INFLATIONARY_DEFLATIONARY_NOT_SUPPORTED(); // 0xe3e13698
    error SUPER_TOKEN_NO_UNDERLYING_TOKEN();                     // 0xf79cf656
    error SUPER_TOKEN_ONLY_SELF();                               // 0x7ffa6648
    error SUPER_TOKEN_ONLY_HOST();                               // 0x98f73704
    error SUPER_TOKEN_ONLY_GOV_OWNER();                          // 0xd9c7ed08
    error SUPER_TOKEN_APPROVE_FROM_ZERO_ADDRESS();               // 0x81638627
    error SUPER_TOKEN_APPROVE_TO_ZERO_ADDRESS();                 // 0xdf070274
    error SUPER_TOKEN_BURN_FROM_ZERO_ADDRESS();                  // 0xba2ab184
    error SUPER_TOKEN_MINT_TO_ZERO_ADDRESS();                    // 0x0d243157
    error SUPER_TOKEN_TRANSFER_FROM_ZERO_ADDRESS();              // 0xeecd6c9b
    error SUPER_TOKEN_TRANSFER_TO_ZERO_ADDRESS();                // 0xe219bd39
    error SUPER_TOKEN_NFT_PROXY_ADDRESS_CHANGED();               // 0x6bef249d

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

    /**************************************************************************
    * Immutable variables
    *************************************************************************/

    // solhint-disable-next-line func-name-mixedcase
    function CONSTANT_OUTFLOW_NFT() external view returns (IConstantOutflowNFT);
    // solhint-disable-next-line func-name-mixedcase
    function CONSTANT_INFLOW_NFT() external view returns (IConstantInflowNFT);

    /**************************************************************************
    * 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 `userData` 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 userData) external override(IERC777);

    /**
     * @dev Destroys `amount` tokens from the caller's account, reducing the
     * total supply and transfers the underlying token to the caller's account.
     *
     * If a send hook is registered for the caller, the corresponding function
     * will be called with `userData` 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 userData) 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 `userData` 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 userData,
        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 `userData` 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 userData,
        bytes calldata operatorData
    ) external override(IERC777);

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

    /**
     * @dev Mint new tokens for the account
     * If `userData` is not empty, the `tokensReceived` hook is invoked according to ERC777 semantics.
     *
     * @custom:modifiers
     *  - onlySelf
     */
    function selfMint(
        address account,
        uint256 amount,
        bytes memory userData
    ) external;

   /**
    * @dev Burn existing tokens for the account
    * If `userData` is not empty, the `tokensToSend` hook is invoked according to ERC777 semantics.
    *
    * @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 receive upgraded tokens
     * @param amount Number of tokens to be upgraded (in 18 decimals)
     * @param userData User data for the TokensRecipient callback
     *
     * @custom:note It will use `transferFrom` to get tokens. Before calling this
     * function you should `approve` this contract
     *
     * @custom:warning
     * - there is potential of reentrancy IF the "to" account is a registered ERC777 recipient.
     * @custom:requirements
     * - if `userData` is NOT empty AND `to` is a contract, it MUST be a registered ERC777 recipient
     *   otherwise it reverts.
     */
    function upgradeTo(address to, uint256 amount, bytes calldata userData) 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 Downgrade SuperToken to ERC20 and transfer immediately
     * @param to The account to receive downgraded tokens
     * @param amount Number of tokens to be downgraded (in 18 decimals)
     */
    function downgradeTo(address to, uint256 amount) external;

    /**
     * @dev Token downgrade event
     * @param account Account whose tokens are downgraded
     * @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;

    function operationIncreaseAllowance(
        address account,
        address spender,
        uint256 addedValue
    ) external;

    function operationDecreaseAllowance(
        address account,
        address spender,
        uint256 subtractedValue
    ) external;

    /**
    * @dev Perform ERC20 transferFrom 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 the funds.
    * @param amount Number of tokens to be transferred.
    *
    * @custom:modifiers
    *  - onlyHost
    */
    function operationTransferFrom(
        address account,
        address spender,
        address recipient,
        uint256 amount
    ) external;

    /**
    * @dev Perform ERC777 send by host contract.
    * @param spender The account where the funds is sent from.
    * @param recipient The recipient of the funds.
    * @param amount Number of tokens to be transferred.
    * @param userData Arbitrary user inputted data
    *
    * @custom:modifiers
    *  - onlyHost
    */
    function operationSend(
        address spender,
        address recipient,
        uint256 amount,
        bytes memory userData
    ) 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;

    // Flow NFT events
    /**
     * @dev Constant Outflow NFT proxy created event
     * @param constantOutflowNFT constant outflow nft address
     */
    event ConstantOutflowNFTCreated(
        IConstantOutflowNFT indexed constantOutflowNFT
    );

    /**
     * @dev Constant Inflow NFT proxy created event
     * @param constantInflowNFT constant inflow nft address
     */
    event ConstantInflowNFTCreated(
        IConstantInflowNFT indexed constantInflowNFT
    );

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

}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperApp.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

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

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperAgreement.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

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

}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/IPoolMemberNFT.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;

// TODO
// solhint-disable-next-line no-empty-blocks
interface IPoolMemberNFT {}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/IPoolAdminNFT.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;

// TODO
// solhint-disable-next-line no-empty-blocks
interface IPoolAdminNFT {}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/IFlowNFTBase.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;

import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";

interface IFlowNFTBase is IERC721Metadata {
    // FlowNFTData struct storage packing:
    // b = bits
    // WORD 1: | superToken      | FREE
    //         | 160b            | 96b
    // WORD 2: | flowSender      | FREE
    //         | 160b            | 96b
    // WORD 3: | flowReceiver    | flowStartDate | FREE
    //         | 160b            | 32b           | 64b
    struct FlowNFTData {
        address superToken;
        address flowSender;
        address flowReceiver;
        uint32 flowStartDate;
    }

    /**************************************************************************
     * Custom Errors
     *************************************************************************/

    error CFA_NFT_APPROVE_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL();   // 0xa3352582
    error CFA_NFT_APPROVE_TO_CALLER();                              // 0xd3c77329
    error CFA_NFT_APPROVE_TO_CURRENT_OWNER();                       // 0xe4790b25
    error CFA_NFT_INVALID_TOKEN_ID();                               // 0xeab95e3b
    error CFA_NFT_ONLY_SUPER_TOKEN_FACTORY();                       // 0xebb7505b
    error CFA_NFT_TRANSFER_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL();  // 0x2551d606
    error CFA_NFT_TRANSFER_FROM_INCORRECT_OWNER();                  // 0x5a26c744
    error CFA_NFT_TRANSFER_IS_NOT_ALLOWED();                        // 0xaa747eca
    error CFA_NFT_TRANSFER_TO_ZERO_ADDRESS();                       // 0xde06d21e

    /**************************************************************************
     * Events
     *************************************************************************/

    /// @notice Informs third-party platforms that NFT metadata should be updated
    /// @dev This event comes from https://eips.ethereum.org/EIPS/eip-4906
    /// @param tokenId the id of the token that should have its metadata updated
    event MetadataUpdate(uint256 tokenId);

    /**************************************************************************
     * View
     *************************************************************************/

    /// @notice An external function for querying flow data by `tokenId``
    /// @param tokenId the token id
    /// @return flowData the flow data associated with `tokenId`
    function flowDataByTokenId(
        uint256 tokenId
    ) external view returns (FlowNFTData memory flowData);

    /// @notice An external function for computing the deterministic tokenId
    /// @dev tokenId = uint256(keccak256(abi.encode(block.chainId, superToken, flowSender, flowReceiver)))
    /// @param superToken the super token
    /// @param flowSender the flow sender
    /// @param flowReceiver the flow receiver
    /// @return tokenId the tokenId
    function getTokenId(
        address superToken,
        address flowSender,
        address flowReceiver
    ) external view returns (uint256);

    /**************************************************************************
     * Write
     *************************************************************************/

    function initialize(
        string memory nftName,
        string memory nftSymbol
    ) external; // initializer;

    function triggerMetadataUpdate(uint256 tokenId) external;
}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/IConstantOutflowNFT.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;

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

interface IConstantOutflowNFT is IFlowNFTBase {
    /**************************************************************************
     * Custom Errors
     *************************************************************************/

    error COF_NFT_INVALID_SUPER_TOKEN();            // 0x6de98774
    error COF_NFT_MINT_TO_AND_FLOW_RECEIVER_SAME(); // 0x0d1d1161
    error COF_NFT_MINT_TO_ZERO_ADDRESS();           // 0x43d05e51
    error COF_NFT_ONLY_CONSTANT_INFLOW();           // 0xa495a718
    error COF_NFT_ONLY_FLOW_AGREEMENTS();           // 0xd367b64f
    error COF_NFT_TOKEN_ALREADY_EXISTS();           // 0xe2480183


    /**************************************************************************
     * Write Functions
     *************************************************************************/

    /// @notice The onCreate function is called when a new flow is created.
    /// @param token the super token passed from the CFA (flowVars)
    /// @param flowSender the flow sender
    /// @param flowReceiver the flow receiver
    function onCreate(ISuperfluidToken token, address flowSender, address flowReceiver) external;

    /// @notice The onUpdate function is called when a flow is updated.
    /// @param token the super token passed from the CFA (flowVars)
    /// @param flowSender the flow sender
    /// @param flowReceiver the flow receiver
    function onUpdate(ISuperfluidToken token, address flowSender, address flowReceiver) external;

    /// @notice The onDelete function is called when a flow is deleted.
    /// @param token the super token passed from the CFA (flowVars)
    /// @param flowSender the flow sender
    /// @param flowReceiver the flow receiver
    function onDelete(ISuperfluidToken token, address flowSender, address flowReceiver) external;
}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/IConstantInflowNFT.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;

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

interface IConstantInflowNFT is IFlowNFTBase {
    /**************************************************************************
     * Custom Errors
     *************************************************************************/
    error CIF_NFT_ONLY_CONSTANT_OUTFLOW(); // 0xe81ef57a

    /**************************************************************************
     * Write Functions
     *************************************************************************/

    /// @notice The mint function emits the "mint" `Transfer` event.
    /// @dev We don't modify storage as this is handled in ConstantOutflowNFT.sol and this function's sole purpose
    /// is to inform clients that search for events.
    /// @param to the flow receiver (inflow NFT receiver)
    /// @param newTokenId the new token id
    function mint(address to, uint256 newTokenId) external;

    /// @notice This burn function emits the "burn" `Transfer` event.
    /// @dev We don't modify storage as this is handled in ConstantOutflowNFT.sol and this function's sole purpose
    /// is to inform clients that search for events.
    /// @param tokenId desired token id to burn
    function burn(uint256 tokenId) external;
}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/Definitions.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

/**
 * @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 getAppCallbackLevel(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 appCallbackLevel, uint8 callType)
    {
        appCallbackLevel = uint8(callInfo & CALL_INFO_APP_LEVEL_MASK);
        callType = uint8((callInfo & CALL_INFO_CALL_TYPE_MASK) >> CALL_INFO_CALL_TYPE_SHIFT);
    }

    function encodeCallInfo(uint8 appCallbackLevel, uint8 callType)
        internal pure
        returns (uint256 callInfo)
    {
        return uint256(appCallbackLevel) | (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 ERC777.send batch operation type
     *
     * Call spec:
     * ISuperToken(target).operationSend(
     *     abi.decode(data, (address recipient, uint256 amount, bytes userData)
     * )
     */
    uint32 constant internal OPERATION_TYPE_ERC777_SEND = 3;
    /**
     * @dev ERC20.increaseAllowance batch operation type
     *
     * Call spec:
     * ISuperToken(target).operationIncreaseAllowance(
     *     abi.decode(data, (address account, address spender, uint256 addedValue))
     * )
     */
    uint32 constant internal OPERATION_TYPE_ERC20_INCREASE_ALLOWANCE = 4;
    /**
     * @dev ERC20.decreaseAllowance batch operation type
     *
     * Call spec:
     * ISuperToken(target).operationDecreaseAllowance(
     *     abi.decode(data, (address account, address spender, uint256 subtractedValue))
     * )
     */
    uint32 constant internal OPERATION_TYPE_ERC20_DECREASE_ALLOWANCE = 5;
    /**
     * @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;
    }
}
          

/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/CustomSuperTokenBase.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

// We export this too because it seems reasonable for a custom super token.
// solhint-disable-next-line no-unused-import
import { ISuperToken } from "../../interfaces/superfluid/ISuperToken.sol";

/**
 * @title Custom super token base contract
 * @author Superfluid
 * NOTE:
 * - Because of how solidity lays out its storage variables and how custom
 *   super tokens inherit the SuperToken standard implementation, it is
 *   required that the custom token proxy pads its implementation
 *   with reserved storage used by the Super Token implementation.
 * - You will need to append your own proxy implementation after the base
 *   - Refer to SETH.sol for an example how it is used.
 */
abstract contract CustomSuperTokenBase {
    // This (32) is the hard-coded number of storage slots used by the super token
    uint256[32] internal _storagePaddings;
}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/agreements/IInstantDistributionAgreementV1.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

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

/**
 * @title Instant Distribution Agreement interface
 * @author Superfluid
 *
 * @notice 
 *   - A publisher can create as many as indices as possibly identifiable with `indexId`.
 *     - `indexId` is deliberately limited to 32 bits, to avoid the chance for sha-3 collision.
 *       Despite knowing sha-3 collision is only theoretical.
 *   - A publisher can create a subscription to an index for any subscriber.
 *   - A subscription consists of:
 *     - The index it subscribes to.
 *     - Number of units subscribed.
 *   - An index consists of:
 *     - Current value as `uint128 indexValue`.
 *     - Total units of the approved subscriptions as `uint128 totalUnitsApproved`.
 *     - Total units of the non approved subscription as `uint128 totalUnitsPending`.
 *   - A publisher can update an index with a new value that doesn't decrease.
 *   - A publisher can update a subscription with any number of units.
 *   - A publisher or a subscriber can delete a subscription and reset its units to zero.
 *   - A subscriber must approve the index in order to receive distributions from the publisher
 *     each time the index is updated.
 *     - The amount distributed is $$\Delta{index} * units$$
 *   - Distributions to a non approved subscription stays in the publisher's deposit until:
 *     - the subscriber approves the subscription (side effect),
 *     - the publisher updates the subscription (side effect),
 *     - the subscriber deletes the subscription even if it is never approved (side effect),
 *     - or the subscriber can explicitly claim them.
 */
abstract contract IInstantDistributionAgreementV1 is ISuperAgreement {

    /**************************************************************************
     * Errors
     *************************************************************************/
    error IDA_INDEX_SHOULD_GROW();             // 0xcfdca725
    error IDA_OPERATION_NOT_ALLOWED();         // 0x92da6d17
    error IDA_INDEX_ALREADY_EXISTS();          // 0x5c02a517
    error IDA_INDEX_DOES_NOT_EXIST();          // 0xedeaa63b
    error IDA_SUBSCRIPTION_DOES_NOT_EXIST();   // 0xb6c8c980
    error IDA_SUBSCRIPTION_ALREADY_APPROVED(); // 0x3eb2f849
    error IDA_SUBSCRIPTION_IS_NOT_APPROVED();  // 0x37412573
    error IDA_INSUFFICIENT_BALANCE();          // 0x16e759bb
    error IDA_ZERO_ADDRESS_SUBSCRIBER();       // 0xc90a4674

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

    /**************************************************************************
     * Index operations
     *************************************************************************/

    /**
     * @dev Create a new index for the publisher
     * @param token Super token address
     * @param indexId Id of the index
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     *
     * @custom:callbacks 
     * None
     */
    function createIndex(
        ISuperfluidToken token,
        uint32 indexId,
        bytes calldata ctx)
            external
            virtual
            returns(bytes memory newCtx);
    /**
    * @dev Index created event
    * @param token Super token address
    * @param publisher Index creator and publisher
    * @param indexId The specified indexId of the newly created index
    * @param userData The user provided data
    */
    event IndexCreated(
        ISuperfluidToken indexed token,
        address indexed publisher,
        uint32 indexed indexId,
        bytes userData);

    /**
     * @dev Query the data of a index
     * @param token Super token address
     * @param publisher The publisher of the index
     * @param indexId Id of the index
     * @return exist Does the index exist
     * @return indexValue Value of the current index
     * @return totalUnitsApproved Total units approved for the index
     * @return totalUnitsPending Total units pending approval for the index
     */
    function getIndex(
        ISuperfluidToken token,
        address publisher,
        uint32 indexId)
            external
            view
            virtual
            returns(
                bool exist,
                uint128 indexValue,
                uint128 totalUnitsApproved,
                uint128 totalUnitsPending);

    /**
     * @dev Calculate actual distribution amount
     * @param token Super token address
     * @param publisher The publisher of the index
     * @param indexId Id of the index
     * @param amount The amount of tokens desired to be distributed
     * @return actualAmount The amount to be distributed after ensuring no rounding errors
     * @return newIndexValue The index value given the desired amount of tokens to be distributed
     */
    function calculateDistribution(
       ISuperfluidToken token,
       address publisher,
       uint32 indexId,
       uint256 amount)
           external view
           virtual
           returns(
               uint256 actualAmount,
               uint128 newIndexValue);

    /**
     * @dev Update index value of an index
     * @param token Super token address
     * @param indexId Id of the index
     * @param indexValue Value of the index
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     *
     * @custom:callbacks 
     * None
     */
    function updateIndex(
        ISuperfluidToken token,
        uint32 indexId,
        uint128 indexValue,
        bytes calldata ctx)
            external
            virtual
            returns(bytes memory newCtx);
    /**
      * @dev Index updated event
      * @param token Super token address
      * @param publisher Index updater and publisher
      * @param indexId The specified indexId of the updated index
      * @param oldIndexValue The previous index value
      * @param newIndexValue The updated index value
      * @param totalUnitsPending The total units pending when the indexValue was updated
      * @param totalUnitsApproved The total units approved when the indexValue was updated
      * @param userData The user provided data
      */
    event IndexUpdated(
        ISuperfluidToken indexed token,
        address indexed publisher,
        uint32 indexed indexId,
        uint128 oldIndexValue,
        uint128 newIndexValue,
        uint128 totalUnitsPending,
        uint128 totalUnitsApproved,
        bytes userData);

    /**
     * @dev Distribute tokens through the index
     * @param token Super token address
     * @param indexId Id of the index
     * @param amount The amount of tokens desired to be distributed
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     *
     * @custom:note 
     * - This is a convenient version of updateIndex. It adds to the index
     *   a delta that equals to `amount / totalUnits`
     * - The actual amount distributed could be obtained via
     *   `calculateDistribution`. This is due to precision error with index
     *   value and units data range
     *
     * @custom:callbacks 
     * None
     */
    function distribute(
        ISuperfluidToken token,
        uint32 indexId,
        uint256 amount,
        bytes calldata ctx)
            external
            virtual
            returns(bytes memory newCtx);


    /**************************************************************************
     * Subscription operations
     *************************************************************************/

    /**
     * @dev Approve the subscription of an index
     * @param token Super token address
     * @param publisher The publisher of the index
     * @param indexId Id of the index
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     *
     * @custom:callbacks 
     * - if subscription exist
     *   - AgreementCreated callback to the publisher:
     *      - agreementId is for the subscription
     * - if subscription does not exist
     *   - AgreementUpdated callback to the publisher:
     *      - agreementId is for the subscription
     */
    function approveSubscription(
        ISuperfluidToken token,
        address publisher,
        uint32 indexId,
        bytes calldata ctx)
            external
            virtual
            returns(bytes memory newCtx);
    /**
      * @dev Index subscribed event
      * @param token Super token address
      * @param publisher Index publisher
      * @param indexId The specified indexId
      * @param subscriber The approved subscriber
      * @param userData The user provided data
      */
    event IndexSubscribed(
        ISuperfluidToken indexed token,
        address indexed publisher,
        uint32 indexed indexId,
        address subscriber,
        bytes userData);

    /**
      * @dev Subscription approved event
      * @param token Super token address
      * @param subscriber The approved subscriber
      * @param publisher Index publisher
      * @param indexId The specified indexId
      * @param userData The user provided data
      */
    event SubscriptionApproved(
        ISuperfluidToken indexed token,
        address indexed subscriber,
        address publisher,
        uint32 indexId,
        bytes userData);

    /**
    * @notice Revoke the subscription of an index
    * @dev "Unapproves" the subscription and moves approved units to pending
    * @param token Super token address
    * @param publisher The publisher of the index
    * @param indexId Id of the index
    * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
    *
    * @custom:callbacks 
    * - AgreementUpdated callback to the publisher:
    *    - agreementId is for the subscription
    */
    function revokeSubscription(
        ISuperfluidToken token,
        address publisher,
        uint32 indexId,
        bytes calldata ctx)
         external
         virtual
         returns(bytes memory newCtx);
    /**
      * @dev Index unsubscribed event
      * @param token Super token address
      * @param publisher Index publisher
      * @param indexId The specified indexId
      * @param subscriber The unsubscribed subscriber
      * @param userData The user provided data
      */
    event IndexUnsubscribed(
        ISuperfluidToken indexed token,
        address indexed publisher,
        uint32 indexed indexId,
        address subscriber,
        bytes userData);
    
    /**
      * @dev Subscription approved event
      * @param token Super token address
      * @param subscriber The approved subscriber
      * @param publisher Index publisher
      * @param indexId The specified indexId
      * @param userData The user provided data
      */
    event SubscriptionRevoked(
        ISuperfluidToken indexed token,
        address indexed subscriber,
        address publisher,
        uint32 indexId,
        bytes userData);

    /**
     * @dev Update the nuber of units of a subscription
     * @param token Super token address
     * @param indexId Id of the index
     * @param subscriber The subscriber of the index
     * @param units Number of units of the subscription
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     *
     * @custom:callbacks 
     * - if subscription exist
     *   - AgreementCreated callback to the subscriber:
     *      - agreementId is for the subscription
     * - if subscription does not exist
     *   - AgreementUpdated callback to the subscriber:
     *      - agreementId is for the subscription
     */
    function updateSubscription(
        ISuperfluidToken token,
        uint32 indexId,
        address subscriber,
        uint128 units,
        bytes calldata ctx)
            external
            virtual
            returns(bytes memory newCtx);

    /**
      * @dev Index units updated event
      * @param token Super token address
      * @param publisher Index publisher
      * @param indexId The specified indexId
      * @param subscriber The subscriber units updated
      * @param units The new units amount
      * @param userData The user provided data
      */
    event IndexUnitsUpdated(
        ISuperfluidToken indexed token,
        address indexed publisher,
        uint32 indexed indexId,
        address subscriber,
        uint128 units,
        bytes userData);
    
    /**
      * @dev Subscription units updated event
      * @param token Super token address
      * @param subscriber The subscriber units updated
      * @param indexId The specified indexId
      * @param publisher Index publisher
      * @param units The new units amount
      * @param userData The user provided data
      */
    event SubscriptionUnitsUpdated(
        ISuperfluidToken indexed token,
        address indexed subscriber,
        address publisher,
        uint32 indexId,
        uint128 units,
        bytes userData);

    /**
     * @dev Get data of a subscription
     * @param token Super token address
     * @param publisher The publisher of the index
     * @param indexId Id of the index
     * @param subscriber The subscriber of the index
     * @return exist Does the subscription exist?
     * @return approved Is the subscription approved?
     * @return units Units of the suscription
     * @return pendingDistribution Pending amount of tokens to be distributed for unapproved subscription
     */
    function getSubscription(
        ISuperfluidToken token,
        address publisher,
        uint32 indexId,
        address subscriber)
            external
            view
            virtual
            returns(
                bool exist,
                bool approved,
                uint128 units,
                uint256 pendingDistribution
            );

    /**
     * @notice Get data of a subscription by agreement ID
     * @dev indexId (agreementId) is the keccak256 hash of encodePacked("publisher", publisher, indexId)
     * @param token Super token address
     * @param agreementId The agreement ID
     * @return publisher The publisher of the index
     * @return indexId Id of the index
     * @return approved Is the subscription approved?
     * @return units Units of the suscription
     * @return pendingDistribution Pending amount of tokens to be distributed for unapproved subscription
     */
    function getSubscriptionByID(
        ISuperfluidToken token,
        bytes32 agreementId)
            external
            view
            virtual
            returns(
                address publisher,
                uint32 indexId,
                bool approved,
                uint128 units,
                uint256 pendingDistribution
            );

    /**
     * @dev List subscriptions of an user
     * @param token Super token address
     * @param subscriber The subscriber's address
     * @return publishers Publishers of the subcriptions
     * @return indexIds Indexes of the subscriptions
     * @return unitsList Units of the subscriptions
     */
    function listSubscriptions(
        ISuperfluidToken token,
        address subscriber)
            external
            view
            virtual
            returns(
                address[] memory publishers,
                uint32[] memory indexIds,
                uint128[] memory unitsList);

    /**
     * @dev Delete the subscription of an user
     * @param token Super token address
     * @param publisher The publisher of the index
     * @param indexId Id of the index
     * @param subscriber The subscriber's address
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     *
     * @custom:callbacks 
     * - if the subscriber called it
     *   - AgreementTerminated callback to the publsiher:
     *      - agreementId is for the subscription
     * - if the publisher called it
     *   - AgreementTerminated callback to the subscriber:
     *      - agreementId is for the subscription
     */
    function deleteSubscription(
        ISuperfluidToken token,
        address publisher,
        uint32 indexId,
        address subscriber,
        bytes calldata ctx)
            external
            virtual
            returns(bytes memory newCtx);

    /**
    * @dev Claim pending distributions
    * @param token Super token address
    * @param publisher The publisher of the index
    * @param indexId Id of the index
    * @param subscriber The subscriber's address
    * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
    *
    * @custom:note The subscription should not be approved yet
    *
    * @custom:callbacks 
    * - AgreementUpdated callback to the publisher:
    *    - agreementId is for the subscription
    */
    function claim(
        ISuperfluidToken token,
        address publisher,
        uint32 indexId,
        address subscriber,
        bytes calldata ctx)
        external
        virtual
        returns(bytes memory newCtx);
    
    /**
      * @dev Index distribution claimed event
      * @param token Super token address
      * @param publisher Index publisher
      * @param indexId The specified indexId
      * @param subscriber The subscriber units updated
      * @param amount The pending amount claimed
      */
    event IndexDistributionClaimed(
        ISuperfluidToken indexed token,
        address indexed publisher,
        uint32 indexed indexId,
        address subscriber,
        uint256 amount);
    
    /**
      * @dev Subscription distribution claimed event
      * @param token Super token address
      * @param subscriber The subscriber units updated
      * @param publisher Index publisher
      * @param indexId The specified indexId
      * @param amount The pending amount claimed
      */
    event SubscriptionDistributionClaimed(
        ISuperfluidToken indexed token,
        address indexed subscriber,
        address publisher,
        uint32 indexId,
        uint256 amount);

}
          

/@superfluid-finance/ethereum-contracts/contracts/interfaces/agreements/IConstantFlowAgreementV1.sol

// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;

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

/**
 * @title Constant Flow Agreement interface
 * @author Superfluid
 */
abstract contract IConstantFlowAgreementV1 is ISuperAgreement {

    /**************************************************************************
     * Errors
     *************************************************************************/
    error CFA_ACL_NO_SENDER_CREATE();               // 0x4b993136
    error CFA_ACL_NO_SENDER_UPDATE();               // 0xedfa0d3b
    error CFA_ACL_OPERATOR_NO_CREATE_PERMISSIONS(); // 0xa3eab6ac
    error CFA_ACL_OPERATOR_NO_UPDATE_PERMISSIONS(); // 0xac434b5f
    error CFA_ACL_OPERATOR_NO_DELETE_PERMISSIONS(); // 0xe30f1bff
    error CFA_ACL_FLOW_RATE_ALLOWANCE_EXCEEDED();   // 0xa0645c1f
    error CFA_ACL_UNCLEAN_PERMISSIONS();            // 0x7939d66c
    error CFA_ACL_NO_SENDER_FLOW_OPERATOR();        // 0xb0ed394d
    error CFA_ACL_NO_NEGATIVE_ALLOWANCE();          // 0x86e0377d
    error CFA_FLOW_ALREADY_EXISTS();                // 0x801b6863
    error CFA_FLOW_DOES_NOT_EXIST();                // 0x5a32bf24
    error CFA_INSUFFICIENT_BALANCE();               // 0xea76c9b3
    error CFA_ZERO_ADDRESS_SENDER();                // 0x1ce9b067
    error CFA_ZERO_ADDRESS_RECEIVER();              // 0x78e02b2a
    error CFA_HOOK_OUT_OF_GAS();                    // 0x9f76430b
    error CFA_DEPOSIT_TOO_BIG();                    // 0x752c2b9c
    error CFA_FLOW_RATE_TOO_BIG();                  // 0x0c9c55c1
    error CFA_NON_CRITICAL_SENDER();                // 0xce11b5d1
    error CFA_INVALID_FLOW_RATE();                  // 0x91acad16
    error CFA_NO_SELF_FLOW();                       // 0xa47338ef

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

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

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

    /**
     * @dev Returns whether it is the patrician period based on host.getNow()
     * @param account The account we are interested in
     * @return isCurrentlyPatricianPeriod Whether it is currently the patrician period dictated by governance
     * @return timestamp The value of host.getNow()
     */
    function isPatricianPeriodNow(
        ISuperfluidToken token,
        address account)
        external view virtual
        returns (bool isCurrentlyPatricianPeriod, uint256 timestamp);

    /**
     * @dev Returns whether it is the patrician period based on timestamp
     * @param account The account we are interested in
     * @param timestamp The timestamp we are interested in observing the result of isPatricianPeriod
     * @return bool Whether it is currently the patrician period dictated by governance
     */
    function isPatricianPeriod(
        ISuperfluidToken token,
        address account,
        uint256 timestamp
    )
        public view virtual
        returns (bool);

    /**
     * @dev msgSender from `ctx` updates permissions for the `flowOperator` with `flowRateAllowance`
     * @param token Super token address
     * @param flowOperator The permission grantee address
     * @param permissions A bitmask representation of the granted permissions
     * @param flowRateAllowance The flow rate allowance the `flowOperator` is granted (only goes down)
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     */
    function updateFlowOperatorPermissions(
        ISuperfluidToken token,
        address flowOperator,
        uint8 permissions,
        int96 flowRateAllowance,
        bytes calldata ctx
    )
        external virtual
        returns(bytes memory newCtx);

    /**
     * @notice msgSender from `ctx` increases flow rate allowance for the `flowOperator` by `addedFlowRateAllowance`
     * @dev if `addedFlowRateAllowance` is negative, we revert with CFA_ACL_NO_NEGATIVE_ALLOWANCE
     * @param token Super token address
     * @param flowOperator The permission grantee address
     * @param addedFlowRateAllowance The flow rate allowance delta
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     * @return newCtx The new context bytes
     */
    function increaseFlowRateAllowance(
        ISuperfluidToken token,
        address flowOperator,
        int96 addedFlowRateAllowance,
        bytes calldata ctx
    ) external virtual returns(bytes memory newCtx);

    /**
     * @dev msgSender from `ctx` decreases flow rate allowance for the `flowOperator` by `subtractedFlowRateAllowance`
     * @dev if `subtractedFlowRateAllowance` is negative, we revert with CFA_ACL_NO_NEGATIVE_ALLOWANCE
     * @param token Super token address
     * @param flowOperator The permission grantee address
     * @param subtractedFlowRateAllowance The flow rate allowance delta
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     * @return newCtx The new context bytes
     */
    function decreaseFlowRateAllowance(
        ISuperfluidToken token,
        address flowOperator,
        int96 subtractedFlowRateAllowance,
        bytes calldata ctx
    ) external virtual returns(bytes memory newCtx);

    /**
     * @dev msgSender from `ctx` increases flow rate allowance for the `flowOperator` by `addedFlowRateAllowance`
     * @dev if `addedFlowRateAllowance` is negative, we revert with CFA_ACL_NO_NEGATIVE_ALLOWANCE
     * @param token Super token address
     * @param flowOperator The permission grantee address
     * @param permissionsToAdd A bitmask representation of the granted permissions to add as a delta
     * @param addedFlowRateAllowance The flow rate allowance delta
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     * @return newCtx The new context bytes
     */
    function increaseFlowRateAllowanceWithPermissions(
        ISuperfluidToken token,
        address flowOperator,
        uint8 permissionsToAdd,
        int96 addedFlowRateAllowance,
        bytes calldata ctx
    ) external virtual returns(bytes memory newCtx);

    /**
     * @dev msgSender from `ctx` decreases flow rate allowance for the `flowOperator` by `subtractedFlowRateAllowance`
     * @dev if `subtractedFlowRateAllowance` is negative, we revert with CFA_ACL_NO_NEGATIVE_ALLOWANCE
     * @param token Super token address
     * @param flowOperator The permission grantee address
     * @param permissionsToRemove A bitmask representation of the granted permissions to remove as a delta
     * @param subtractedFlowRateAllowance The flow rate allowance delta
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     * @return newCtx The new context bytes
     */
    function decreaseFlowRateAllowanceWithPermissions(
        ISuperfluidToken token,
        address flowOperator,
        uint8 permissionsToRemove,
        int96 subtractedFlowRateAllowance,
        bytes calldata ctx
    ) external virtual returns(bytes memory newCtx);

    /**
     * @dev msgSender from `ctx` grants `flowOperator` all permissions with flowRateAllowance as type(int96).max
     * @param token Super token address
     * @param flowOperator The permission grantee address
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     */
    function authorizeFlowOperatorWithFullControl(
        ISuperfluidToken token,
        address flowOperator,
        bytes calldata ctx
    )
        external virtual
        returns(bytes memory newCtx);

     /**
     * @notice msgSender from `ctx` revokes `flowOperator` create/update/delete permissions
     * @dev `permissions` and `flowRateAllowance` will both be set to 0
     * @param token Super token address
     * @param flowOperator The permission grantee address
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     */
    function revokeFlowOperatorWithFullControl(
        ISuperfluidToken token,
        address flowOperator,
        bytes calldata ctx
    )
        external virtual
        returns(bytes memory newCtx);

    /**
     * @notice Get the permissions of a flow operator between `sender` and `flowOperator` for `token`
     * @param token Super token address
     * @param sender The permission granter address
     * @param flowOperator The permission grantee address
     * @return flowOperatorId The keccak256 hash of encoded string "flowOperator", sender and flowOperator
     * @return permissions A bitmask representation of the granted permissions
     * @return flowRateAllowance The flow rate allowance the `flowOperator` is granted (only goes down)
     */
    function getFlowOperatorData(
       ISuperfluidToken token,
       address sender,
       address flowOperator
    )
        public view virtual
        returns (
            bytes32 flowOperatorId,
            uint8 permissions,
            int96 flowRateAllowance
        );

    /**
     * @notice Get flow operator using flowOperatorId
     * @param token Super token address
     * @param flowOperatorId The keccak256 hash of encoded string "flowOperator", sender and flowOperator
     * @return permissions A bitmask representation of the granted permissions
     * @return flowRateAllowance The flow rate allowance the `flowOperator` is granted (only goes down)
     */
    function getFlowOperatorDataByID(
       ISuperfluidToken token,
       bytes32 flowOperatorId
    )
        external view virtual
        returns (
            uint8 permissions,
            int96 flowRateAllowance
        );

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

    /**
    * @notice Create a flow between sender and receiver
    * @dev A flow created by an approved flow operator (see above for details on callbacks)
    * @param token Super token address
    * @param sender Flow sender address (has granted permissions)
    * @param receiver Flow receiver address
    * @param flowRate New flow rate in amount per second
    * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
    */
    function createFlowByOperator(
        ISuperfluidToken token,
        address sender,
        address receiver,
        int96 flowRate,
        bytes calldata ctx
    )
        external virtual
        returns(bytes memory newCtx);

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

    /**
    * @notice Update a flow between sender and receiver
    * @dev A flow updated by an approved flow operator (see above for details on callbacks)
    * @param token Super token address
    * @param sender Flow sender address (has granted permissions)
    * @param receiver Flow receiver address
    * @param flowRate New flow rate in amount per second
    * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
    */
    function updateFlowByOperator(
        ISuperfluidToken token,
        address sender,
        address receiver,
        int96 flowRate,
        bytes calldata ctx
    )
        external virtual
        returns(bytes memory newCtx);

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

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

    /**
     * @dev Get the aggregated flow info of the account
     * @param token Super token address
     * @param account Account for the query
     * @return timestamp Timestamp of when a flow was last updated for account
     * @return flowRate The net flow rate of token for account
     * @return deposit The sum of all deposits for account's flows
     * @return owedDeposit The sum of all owed deposits for account's flows
     */
    function getAccountFlowInfo(
        ISuperfluidToken token,
        address account
    )
        external view virtual
        returns (
            uint256 timestamp,
            int96 flowRate,
            uint256 deposit,
            uint256 owedDeposit);

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

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

    /**
     * @notice Delete the flow between sender and receiver
     * @dev A flow deleted by an approved flow operator (see above for details on callbacks)
     * @param token Super token address
     * @param ctx Context bytes (see ISuperfluid.sol for Context struct)
     * @param receiver Flow receiver address
     */
    function deleteFlowByOperator(
        ISuperfluidToken token,
        address sender,
        address receiver,
        bytes calldata ctx
    )
        external virtual
        returns(bytes memory newCtx);

    /**
     * @dev Flow operator updated event
     * @param token Super token address
     * @param sender Flow sender address
     * @param flowOperator Flow operator address
     * @param permissions Octo bitmask representation of permissions
     * @param flowRateAllowance The flow rate allowance the `flowOperator` is granted (only goes down)
     */
    event FlowOperatorUpdated(
        ISuperfluidToken indexed token,
        address indexed sender,
        address indexed flowOperator,
        uint8 permissions,
        int96 flowRateAllowance
    );

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

    /**
     * @dev Flow updated extension event
     * @param flowOperator Flow operator address - the Context.msgSender
     * @param deposit The deposit amount for the stream
     */
    event FlowUpdatedExtension(
        address indexed flowOperator,
        uint256 deposit
    );
}
          

/@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSetUpgradeable {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}
          

/@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library MathUpgradeable {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10**64) {
                value /= 10**64;
                result += 64;
            }
            if (value >= 10**32) {
                value /= 10**32;
                result += 32;
            }
            if (value >= 10**16) {
                value /= 10**16;
                result += 16;
            }
            if (value >= 10**8) {
                value /= 10**8;
                result += 8;
            }
            if (value >= 10**4) {
                value /= 10**4;
                result += 4;
            }
            if (value >= 10**2) {
                value /= 10**2;
                result += 2;
            }
            if (value >= 10**1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
        }
    }
}
          

/@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165Upgradeable {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
          

/@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
    function __ERC165_init() internal onlyInitializing {
    }

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165Upgradeable).interfaceId;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}
          

/@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/draft-EIP712.sol)

pragma solidity ^0.8.0;

// EIP-712 is Final as of 2022-08-11. This file is deprecated.

import "./EIP712Upgradeable.sol";
          

/@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)

pragma solidity ^0.8.0;

import "./ECDSAUpgradeable.sol";
import "../../proxy/utils/Initializable.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
 * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
 * they need in their contracts using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * _Available since v3.4._
 *
 * @custom:storage-size 52
 */
abstract contract EIP712Upgradeable is Initializable {
    /* solhint-disable var-name-mixedcase */
    bytes32 private _HASHED_NAME;
    bytes32 private _HASHED_VERSION;
    bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    /* solhint-enable var-name-mixedcase */

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    function __EIP712_init(string memory name, string memory version) internal onlyInitializing {
        __EIP712_init_unchained(name, version);
    }

    function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {
        bytes32 hashedName = keccak256(bytes(name));
        bytes32 hashedVersion = keccak256(bytes(version));
        _HASHED_NAME = hashedName;
        _HASHED_VERSION = hashedVersion;
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        return _buildDomainSeparator(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash());
    }

    function _buildDomainSeparator(
        bytes32 typeHash,
        bytes32 nameHash,
        bytes32 versionHash
    ) private view returns (bytes32) {
        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash);
    }

    /**
     * @dev The hash of the name parameter for the EIP712 domain.
     *
     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
     * are a concern.
     */
    function _EIP712NameHash() internal virtual view returns (bytes32) {
        return _HASHED_NAME;
    }

    /**
     * @dev The hash of the version parameter for the EIP712 domain.
     *
     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
     * are a concern.
     */
    function _EIP712VersionHash() internal virtual view returns (bytes32) {
        return _HASHED_VERSION;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}
          

/@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../StringsUpgradeable.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSAUpgradeable {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}
          

/@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/MathUpgradeable.sol";

/**
 * @dev String operations.
 */
library StringsUpgradeable {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = MathUpgradeable.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, MathUpgradeable.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}
          

/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol

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

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

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

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}
          

/@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @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 functionCallWithValue(target, data, 0, "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");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or 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 {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // 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
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}
          

/@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20PermitUpgradeable {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
          

/@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol

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

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    function __Pausable_init() internal onlyInitializing {
        __Pausable_init_unchained();
    }

    function __Pausable_init_unchained() internal onlyInitializing {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}
          

/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol

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

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

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

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

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

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

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

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

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

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

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

/@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControlUpgradeable {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}
          

/@openzeppelin/contracts-upgradeable/access/IAccessControlEnumerableUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)

pragma solidity ^0.8.0;

import "./IAccessControlUpgradeable.sol";

/**
 * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
 */
interface IAccessControlEnumerableUpgradeable is IAccessControlUpgradeable {
    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) external view returns (address);

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) external view returns (uint256);
}
          

/@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControlUpgradeable.sol";
import "../utils/ContextUpgradeable.sol";
import "../utils/StringsUpgradeable.sol";
import "../utils/introspection/ERC165Upgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
    function __AccessControl_init() internal onlyInitializing {
    }

    function __AccessControl_init_unchained() internal onlyInitializing {
    }
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

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

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        StringsUpgradeable.toHexString(account),
                        " is missing role ",
                        StringsUpgradeable.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}
          

/@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)

pragma solidity ^0.8.0;

import "./IAccessControlEnumerableUpgradeable.sol";
import "./AccessControlUpgradeable.sol";
import "../utils/structs/EnumerableSetUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Extension of {AccessControl} that allows enumerating the members of each role.
 */
abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerableUpgradeable, AccessControlUpgradeable {
    function __AccessControlEnumerable_init() internal onlyInitializing {
    }

    function __AccessControlEnumerable_init_unchained() internal onlyInitializing {
    }
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;

    mapping(bytes32 => EnumerableSetUpgradeable.AddressSet) private _roleMembers;

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

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {
        return _roleMembers[role].at(index);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {
        return _roleMembers[role].length();
    }

    /**
     * @dev Overload {_grantRole} to track enumerable memberships
     */
    function _grantRole(bytes32 role, address account) internal virtual override {
        super._grantRole(role, account);
        _roleMembers[role].add(account);
    }

    /**
     * @dev Overload {_revokeRole} to track enumerable memberships
     */
    function _revokeRole(bytes32 role, address account) internal virtual override {
        super._revokeRole(role, account);
        _roleMembers[role].remove(account);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}
          

/@openzeppelin/contracts/utils/math/SafeMath.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}
          

/@openzeppelin/contracts/utils/math/SafeCast.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

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 uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     *
     * _Available since v4.7._
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
        return uint248(value);
    }

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

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

    /**
     * @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
     *
     * _Available since v4.2._
     */
    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 uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     *
     * _Available since v4.7._
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
        return uint216(value);
    }

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

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

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

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

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

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

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

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

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

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     *
     * _Available since v4.7._
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
        return uint136(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
     *
     * _Available since v2.5._
     */
    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 uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     *
     * _Available since v4.7._
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
        return uint120(value);
    }

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

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     *
     * _Available since v4.7._
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
        return uint104(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
     *
     * _Available since v4.2._
     */
    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 uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     *
     * _Available since v4.7._
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
        return uint88(value);
    }

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

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     *
     * _Available since v4.7._
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
        return uint72(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
     *
     * _Available since v2.5._
     */
    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 uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     *
     * _Available since v4.7._
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
        return uint56(value);
    }

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

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     *
     * _Available since v4.7._
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
        return uint40(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
     *
     * _Available since v2.5._
     */
    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 uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     *
     * _Available since v4.7._
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
        return uint24(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
     *
     * _Available since v2.5._
     */
    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
     *
     * _Available since v2.5._
     */
    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.
     *
     * _Available since v3.0._
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     *
     * _Available since v4.7._
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     *
     * _Available since v4.7._
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     *
     * _Available since v4.7._
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     *
     * _Available since v4.7._
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     *
     * _Available since v4.7._
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     *
     * _Available since v4.7._
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     *
     * _Available since v4.7._
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     *
     * _Available since v4.7._
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     *
     * _Available since v4.7._
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     *
     * _Available since v4.7._
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     *
     * _Available since v4.7._
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     *
     * _Available since v4.7._
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     *
     * _Available since v4.7._
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     *
     * _Available since v4.7._
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     *
     * _Available since v4.7._
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
    }

    /**
     * @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 downcasted) {
        downcasted = int128(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     *
     * _Available since v4.7._
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     *
     * _Available since v4.7._
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     *
     * _Available since v4.7._
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     *
     * _Available since v4.7._
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     *
     * _Available since v4.7._
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     *
     * _Available since v4.7._
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     *
     * _Available since v4.7._
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
    }

    /**
     * @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 downcasted) {
        downcasted = int64(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     *
     * _Available since v4.7._
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     *
     * _Available since v4.7._
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     *
     * _Available since v4.7._
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
    }

    /**
     * @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 downcasted) {
        downcasted = int32(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     *
     * _Available since v4.7._
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
    }

    /**
     * @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 downcasted) {
        downcasted = int16(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
    }

    /**
     * @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 downcasted) {
        downcasted = int8(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     *
     * _Available since v3.0._
     */
    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);
    }
}
          

/@openzeppelin/contracts/utils/introspection/IERC1820Registry.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/introspection/IERC1820Registry.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the global ERC1820 Registry, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register
 * implementers for interfaces in this registry, as well as query support.
 *
 * Implementers may be shared by multiple accounts, and can also implement more
 * than a single interface for each account. Contracts can implement interfaces
 * for themselves, but externally-owned accounts (EOA) must delegate this to a
 * contract.
 *
 * {IERC165} interfaces can also be queried via the registry.
 *
 * For an in-depth explanation and source code analysis, see the EIP text.
 */
interface IERC1820Registry {
    event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer);

    event ManagerChanged(address indexed account, address indexed newManager);

    /**
     * @dev Sets `newManager` as the manager for `account`. A manager of an
     * account is able to set interface implementers for it.
     *
     * By default, each account is its own manager. Passing a value of `0x0` in
     * `newManager` will reset the manager to this initial state.
     *
     * Emits a {ManagerChanged} event.
     *
     * Requirements:
     *
     * - the caller must be the current manager for `account`.
     */
    function setManager(address account, address newManager) external;

    /**
     * @dev Returns the manager for `account`.
     *
     * See {setManager}.
     */
    function getManager(address account) external view returns (address);

    /**
     * @dev Sets the `implementer` contract as ``account``'s implementer for
     * `interfaceHash`.
     *
     * `account` being the zero address is an alias for the caller's address.
     * The zero address can also be used in `implementer` to remove an old one.
     *
     * See {interfaceHash} to learn how these are created.
     *
     * Emits an {InterfaceImplementerSet} event.
     *
     * Requirements:
     *
     * - the caller must be the current manager for `account`.
     * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not
     * end in 28 zeroes).
     * - `implementer` must implement {IERC1820Implementer} and return true when
     * queried for support, unless `implementer` is the caller. See
     * {IERC1820Implementer-canImplementInterfaceForAddress}.
     */
    function setInterfaceImplementer(
        address account,
        bytes32 _interfaceHash,
        address implementer
    ) external;

    /**
     * @dev Returns the implementer of `interfaceHash` for `account`. If no such
     * implementer is registered, returns the zero address.
     *
     * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28
     * zeroes), `account` will be queried for support of it.
     *
     * `account` being the zero address is an alias for the caller's address.
     */
    function getInterfaceImplementer(address account, bytes32 _interfaceHash) external view returns (address);

    /**
     * @dev Returns the interface hash for an `interfaceName`, as defined in the
     * corresponding
     * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].
     */
    function interfaceHash(string calldata interfaceName) external pure returns (bytes32);

    /**
     * @notice Updates the cache with whether the contract implements an ERC165 interface or not.
     * @param account Address of the contract for which to update the cache.
     * @param interfaceId ERC165 interface for which to update the cache.
     */
    function updateERC165Cache(address account, bytes4 interfaceId) external;

    /**
     * @notice Checks whether a contract implements an ERC165 interface or not.
     * If the result is not cached a direct lookup on the contract address is performed.
     * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling
     * {updateERC165Cache} with the contract address.
     * @param account Address of the contract to check.
     * @param interfaceId ERC165 interface to check.
     * @return True if `account` implements `interfaceId`, false otherwise.
     */
    function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool);

    /**
     * @notice Checks whether a contract implements an ERC165 interface or not without using or updating the cache.
     * @param account Address of the contract to check.
     * @param interfaceId ERC165 interface to check.
     * @return True if `account` implements `interfaceId`, false otherwise.
     */
    function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool);
}
          

/@openzeppelin/contracts/utils/introspection/IERC165.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
          

/@openzeppelin/contracts/utils/Address.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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 functionCallWithValue(target, data, 0, "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");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or 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 {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // 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
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}
          

/@openzeppelin/contracts/token/ERC777/IERC777Sender.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC777/IERC777Sender.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC777TokensSender standard as defined in the EIP.
 *
 * {IERC777} Token holders can be notified of operations performed on their
 * tokens by having a contract implement this interface (contract holders can be
 * their own implementer) and registering it on the
 * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].
 *
 * See {IERC1820Registry} and {ERC1820Implementer}.
 */
interface IERC777Sender {
    /**
     * @dev Called by an {IERC777} token contract whenever a registered holder's
     * (`from`) tokens are about to be moved or destroyed. The type of operation
     * is conveyed by `to` being the zero address or not.
     *
     * This call occurs _before_ the token contract's state is updated, so
     * {IERC777-balanceOf}, etc., can be used to query the pre-operation state.
     *
     * This function may revert to prevent the operation from being executed.
     */
    function tokensToSend(
        address operator,
        address from,
        address to,
        uint256 amount,
        bytes calldata userData,
        bytes calldata operatorData
    ) external;
}
          

/@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC777/IERC777Recipient.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.
 *
 * Accounts can be notified of {IERC777} tokens being sent to them by having a
 * contract implement this interface (contract holders can be their own
 * implementer) and registering it on the
 * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].
 *
 * See {IERC1820Registry} and {ERC1820Implementer}.
 */
interface IERC777Recipient {
    /**
     * @dev Called by an {IERC777} token contract whenever tokens are being
     * moved or created into a registered account (`to`). The type of operation
     * is conveyed by `from` being the zero address or not.
     *
     * This call occurs _after_ the token contract's state is updated, so
     * {IERC777-balanceOf}, etc., can be used to query the post-operation state.
     *
     * This function may revert to prevent the operation from being executed.
     */
    function tokensReceived(
        address operator,
        address from,
        address to,
        uint256 amount,
        bytes calldata userData,
        bytes calldata operatorData
    ) external;
}
          

/@openzeppelin/contracts/token/ERC777/IERC777.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (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 Emitted when `amount` tokens are created by `operator` and assigned to `to`.
     *
     * Note that some additional user `data` and `operatorData` can be logged in the event.
     */
    event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);

    /**
     * @dev Emitted when `operator` destroys `amount` tokens from `account`.
     *
     * Note that some additional user `data` and `operatorData` can be logged in the event.
     */
    event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);

    /**
     * @dev Emitted when `operator` is made operator for `tokenHolder`.
     */
    event AuthorizedOperator(address indexed operator, address indexed tokenHolder);

    /**
     * @dev Emitted when `operator` is revoked its operator status for `tokenHolder`.
     */
    event RevokedOperator(address indexed operator, address indexed tokenHolder);

    /**
     * @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
    );
}
          

/@openzeppelin/contracts/token/ERC721/IERC721.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}
          

/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}
          

/@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
          

/@openzeppelin/contracts/token/ERC20/IERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

    /**
     * @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);
}
          

Compiler Settings

{"remappings":[],"optimizer":{"runs":0,"enabled":true},"metadata":{"bytecodeHash":"ipfs"},"libraries":{},"evmVersion":"paris","compilationTarget":{"contracts/token/superfluid/SuperGoodDollar.sol":"SuperGoodDollar"}}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_host","internalType":"contract ISuperfluid"}]},{"type":"error","name":"SF_TOKEN_AGREEMENT_ALREADY_EXISTS","inputs":[]},{"type":"error","name":"SF_TOKEN_AGREEMENT_DOES_NOT_EXIST","inputs":[]},{"type":"error","name":"SF_TOKEN_BURN_INSUFFICIENT_BALANCE","inputs":[]},{"type":"error","name":"SF_TOKEN_MOVE_INSUFFICIENT_BALANCE","inputs":[]},{"type":"error","name":"SF_TOKEN_ONLY_HOST","inputs":[]},{"type":"error","name":"SF_TOKEN_ONLY_LISTED_AGREEMENT","inputs":[]},{"type":"error","name":"SUPER_GOODDOLLAR_PAUSED","inputs":[]},{"type":"error","name":"SUPER_TOKEN_APPROVE_FROM_ZERO_ADDRESS","inputs":[]},{"type":"error","name":"SUPER_TOKEN_APPROVE_TO_ZERO_ADDRESS","inputs":[]},{"type":"error","name":"SUPER_TOKEN_BURN_FROM_ZERO_ADDRESS","inputs":[]},{"type":"error","name":"SUPER_TOKEN_CALLER_IS_NOT_OPERATOR_FOR_HOLDER","inputs":[]},{"type":"error","name":"SUPER_TOKEN_INFLATIONARY_DEFLATIONARY_NOT_SUPPORTED","inputs":[]},{"type":"error","name":"SUPER_TOKEN_MINT_TO_ZERO_ADDRESS","inputs":[]},{"type":"error","name":"SUPER_TOKEN_NFT_PROXY_ALREADY_SET","inputs":[]},{"type":"error","name":"SUPER_TOKEN_NOT_ERC777_TOKENS_RECIPIENT","inputs":[]},{"type":"error","name":"SUPER_TOKEN_NO_UNDERLYING_TOKEN","inputs":[]},{"type":"error","name":"SUPER_TOKEN_ONLY_GOV_OWNER","inputs":[]},{"type":"error","name":"SUPER_TOKEN_ONLY_HOST","inputs":[]},{"type":"error","name":"SUPER_TOKEN_ONLY_SELF","inputs":[]},{"type":"error","name":"SUPER_TOKEN_TRANSFER_FROM_ZERO_ADDRESS","inputs":[]},{"type":"error","name":"SUPER_TOKEN_TRANSFER_TO_TOKEN_ADDRESS","inputs":[]},{"type":"error","name":"SUPER_TOKEN_TRANSFER_TO_ZERO_ADDRESS","inputs":[]},{"type":"event","name":"AgreementCreated","inputs":[{"type":"address","name":"agreementClass","internalType":"address","indexed":true},{"type":"bytes32","name":"id","internalType":"bytes32","indexed":false},{"type":"bytes32[]","name":"data","internalType":"bytes32[]","indexed":false}],"anonymous":false},{"type":"event","name":"AgreementLiquidated","inputs":[{"type":"address","name":"agreementClass","internalType":"address","indexed":true},{"type":"bytes32","name":"id","internalType":"bytes32","indexed":false},{"type":"address","name":"penaltyAccount","internalType":"address","indexed":true},{"type":"address","name":"rewardAccount","internalType":"address","indexed":true},{"type":"uint256","name":"rewardAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"AgreementLiquidatedBy","inputs":[{"type":"address","name":"liquidatorAccount","internalType":"address","indexed":false},{"type":"address","name":"agreementClass","internalType":"address","indexed":true},{"type":"bytes32","name":"id","internalType":"bytes32","indexed":false},{"type":"address","name":"penaltyAccount","internalType":"address","indexed":true},{"type":"address","name":"bondAccount","internalType":"address","indexed":true},{"type":"uint256","name":"rewardAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"bailoutAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"AgreementLiquidatedV2","inputs":[{"type":"address","name":"agreementClass","internalType":"address","indexed":true},{"type":"bytes32","name":"id","internalType":"bytes32","indexed":false},{"type":"address","name":"liquidatorAccount","internalType":"address","indexed":true},{"type":"address","name":"targetAccount","internalType":"address","indexed":true},{"type":"address","name":"rewardAmountReceiver","internalType":"address","indexed":false},{"type":"uint256","name":"rewardAmount","internalType":"uint256","indexed":false},{"type":"int256","name":"targetAccountBalanceDelta","internalType":"int256","indexed":false},{"type":"bytes","name":"liquidationTypeData","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"AgreementStateUpdated","inputs":[{"type":"address","name":"agreementClass","internalType":"address","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint256","name":"slotId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"AgreementTerminated","inputs":[{"type":"address","name":"agreementClass","internalType":"address","indexed":true},{"type":"bytes32","name":"id","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"AgreementUpdated","inputs":[{"type":"address","name":"agreementClass","internalType":"address","indexed":true},{"type":"bytes32","name":"id","internalType":"bytes32","indexed":false},{"type":"bytes32[]","name":"data","internalType":"bytes32[]","indexed":false}],"anonymous":false},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"AuthorizedOperator","inputs":[{"type":"address","name":"operator","internalType":"address","indexed":true},{"type":"address","name":"tokenHolder","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Bailout","inputs":[{"type":"address","name":"bailoutAccount","internalType":"address","indexed":true},{"type":"uint256","name":"bailoutAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Burned","inputs":[{"type":"address","name":"operator","internalType":"address","indexed":true},{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"bytes","name":"data","internalType":"bytes","indexed":false},{"type":"bytes","name":"operatorData","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"CodeUpdated","inputs":[{"type":"bytes32","name":"uuid","internalType":"bytes32","indexed":false},{"type":"address","name":"codeAddress","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"ConstantInflowNFTCreated","inputs":[{"type":"address","name":"constantInflowNFT","internalType":"contract IConstantInflowNFT","indexed":true}],"anonymous":false},{"type":"event","name":"ConstantOutflowNFTCreated","inputs":[{"type":"address","name":"constantOutflowNFT","internalType":"contract IConstantOutflowNFT","indexed":true}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"type":"uint8","name":"version","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"Minted","inputs":[{"type":"address","name":"operator","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"bytes","name":"data","internalType":"bytes","indexed":false},{"type":"bytes","name":"operatorData","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"Paused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"RevokedOperator","inputs":[{"type":"address","name":"operator","internalType":"address","indexed":true},{"type":"address","name":"tokenHolder","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"previousAdminRole","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"newAdminRole","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Sent","inputs":[{"type":"address","name":"operator","internalType":"address","indexed":true},{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"bytes","name":"data","internalType":"bytes","indexed":false},{"type":"bytes","name":"operatorData","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"bytes","name":"data","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TransferFee","inputs":[{"type":"address","name":"from","internalType":"address","indexed":false},{"type":"address","name":"to","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"fee","internalType":"uint256","indexed":false},{"type":"bool","name":"senderPays","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"Unpaused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IConstantInflowNFT"}],"name":"CONSTANT_INFLOW_NFT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IConstantOutflowNFT"}],"name":"CONSTANT_OUTFLOW_NFT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DEFAULT_ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DOMAIN_SEPARATOR","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"MINTER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"PAUSER_ROLE","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addMinter","inputs":[{"type":"address","name":"_minter","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addPauser","inputs":[{"type":"address","name":"_pauser","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"authorizeOperator","inputs":[{"type":"address","name":"operator","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"balance","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"burn","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"burn","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"burnFrom","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"cap","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"castrate","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"createAgreement","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"},{"type":"bytes32[]","name":"data","internalType":"bytes32[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"creditGasFees","inputs":[{"type":"address","name":"from","internalType":"address"},{"type":"address","name":"feeRecipient","internalType":"address"},{"type":"address","name":"gatewayFeeRecipient","internalType":"address"},{"type":"address","name":"baseFeeRecipient","internalType":"address"},{"type":"uint256","name":"refund","internalType":"uint256"},{"type":"uint256","name":"tipTxFee","internalType":"uint256"},{"type":"uint256","name":"gatewayFee","internalType":"uint256"},{"type":"uint256","name":"baseTxFee","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"debitGasFees","inputs":[{"type":"address","name":"from","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"decreaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"subtractedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"defaultOperators","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"disableHostOperations","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"enableHostOperations","inputs":[{"type":"bool","name":"enabled","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"feeRecipient","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IFeesFormula"}],"name":"formula","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"contract ISuperAgreement[]"}],"name":"getAccountActiveAgreements","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32[]","name":"data","internalType":"bytes32[]"}],"name":"getAgreementData","inputs":[{"type":"address","name":"agreementClass","internalType":"address"},{"type":"bytes32","name":"id","internalType":"bytes32"},{"type":"uint256","name":"dataLength","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32[]","name":"slotData","internalType":"bytes32[]"}],"name":"getAgreementStateSlot","inputs":[{"type":"address","name":"agreementClass","internalType":"address"},{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"slotId","internalType":"uint256"},{"type":"uint256","name":"dataLength","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"codeAddress","internalType":"address"}],"name":"getCodeAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"fee","internalType":"uint256"},{"type":"bool","name":"senderPays","internalType":"bool"}],"name":"getFees","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"address","name":"sender","internalType":"address"},{"type":"address","name":"recipient","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"fee","internalType":"uint256"},{"type":"bool","name":"senderPays","internalType":"bool"}],"name":"getFees","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"host","internalType":"address"}],"name":"getHost","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRoleAdmin","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getRoleMember","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRoleMemberCount","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getUnderlyingToken","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"granularity","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIdentity"}],"name":"identity","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"increaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"addedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"underlyingToken","internalType":"contract IERC20"},{"type":"uint8","name":"underlyingDecimals","internalType":"uint8"},{"type":"string","name":"n","internalType":"string"},{"type":"string","name":"s","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"string","name":"n","internalType":"string"},{"type":"string","name":"s","internalType":"string"},{"type":"uint256","name":"_cap","internalType":"uint256"},{"type":"address","name":"_formula","internalType":"contract IFeesFormula"},{"type":"address","name":"_identity","internalType":"contract IIdentity"},{"type":"address","name":"_feeRecipient","internalType":"address"},{"type":"address","name":"_owner","internalType":"address"},{"type":"address","name":"_outflowNFT","internalType":"contract IConstantOutflowNFT"},{"type":"address","name":"_inflowNFT","internalType":"contract IConstantInflowNFT"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"isCritical","internalType":"bool"}],"name":"isAccountCritical","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"timestamp","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"isCritical","internalType":"bool"}],"name":"isAccountCriticalNow","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"isSolvent","internalType":"bool"}],"name":"isAccountSolvent","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"timestamp","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"isSolvent","internalType":"bool"}],"name":"isAccountSolventNow","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isMinter","inputs":[{"type":"address","name":"_minter","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isOperatorFor","inputs":[{"type":"address","name":"operator","internalType":"address"},{"type":"address","name":"tokenHolder","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isPauser","inputs":[{"type":"address","name":"_pauser","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"makeLiquidationPayoutsV2","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"},{"type":"bytes","name":"liquidationTypeData","internalType":"bytes"},{"type":"address","name":"liquidatorAccount","internalType":"address"},{"type":"bool","name":"useDefaultRewardAccount","internalType":"bool"},{"type":"address","name":"targetAccount","internalType":"address"},{"type":"uint256","name":"rewardAmount","internalType":"uint256"},{"type":"int256","name":"targetAccountBalanceDelta","internalType":"int256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"mint","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nonces","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"operationApprove","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"operationDecreaseAllowance","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"subtractedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"operationIncreaseAllowance","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"addedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"operationSend","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"userData","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"operationTransferFrom","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"spender","internalType":"address"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"operatorBurn","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"bytes","name":"operatorData","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"operatorSend","inputs":[{"type":"address","name":"sender","internalType":"address"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"bytes","name":"operatorData","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pause","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"permit","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPoolAdminNFT"}],"name":"poolAdminNFT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPoolMemberNFT"}],"name":"poolMemberNFT","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"proxiableUUID","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"int256","name":"availableBalance","internalType":"int256"},{"type":"uint256","name":"deposit","internalType":"uint256"},{"type":"uint256","name":"owedDeposit","internalType":"uint256"}],"name":"realtimeBalanceOf","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"timestamp","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"int256","name":"availableBalance","internalType":"int256"},{"type":"uint256","name":"deposit","internalType":"uint256"},{"type":"uint256","name":"owedDeposit","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"realtimeBalanceOfNow","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"recover","inputs":[{"type":"address","name":"token","internalType":"contract IERC20"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceMinter","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeOperator","inputs":[{"type":"address","name":"operator","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"selfApproveFor","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"send","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeRecipient","inputs":[{"type":"address","name":"_feeRecipient","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFormula","inputs":[{"type":"address","name":"_formula","internalType":"contract IFeesFormula"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setIdentity","inputs":[{"type":"address","name":"_identity","internalType":"contract IIdentityV2"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setNFTProxyContracts","inputs":[{"type":"address","name":"_constantOutflowNFT","internalType":"contract IConstantOutflowNFT"},{"type":"address","name":"_constantInflowNFT","internalType":"contract IConstantInflowNFT"},{"type":"address","name":"_poolAdminNFT","internalType":"contract IPoolAdminNFT"},{"type":"address","name":"_poolMemberNFT","internalType":"contract IPoolMemberNFT"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"settleBalance","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"int256","name":"delta","internalType":"int256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"terminateAgreement","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"},{"type":"uint256","name":"dataLength","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferAndCall","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"holder","internalType":"address"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"_owner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unpause","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateAgreementData","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"},{"type":"bytes32[]","name":"data","internalType":"bytes32[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateAgreementStateSlot","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"slotId","internalType":"uint256"},{"type":"bytes32[]","name":"slotData","internalType":"bytes32[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateCode","inputs":[{"type":"address","name":"newAddress","internalType":"address"}]}]
              

Contract Creation Code

0x60a06040523480156200001157600080fd5b50604051620060e2380380620060e2833981016040819052620000349162000046565b6001600160a01b031660805262000078565b6000602082840312156200005957600080fd5b81516001600160a01b03811681146200007157600080fd5b9392505050565b608051615fe5620000fd6000396000818161051f01528181610e4b01528181610ece0152818161122d015281816113a10152818161182b0152818161197b01528181611d17015281816121cc0152818161226901528181612313015281816123b901528181612c8601528181612d2d015281816138800152614a620152615fe56000f3fe608060405234801561001057600080fd5b50600436106104405760003560e01c806301ffc9a71461044557806306e485381461046d57806306fdde0314610482578063090c415e14610497578063095ea7b3146104ac5780630cd865ec146104bf57806312a6a3f8146104d257806316d055d6146104e557806318160ddd146104f85780631863e8091461050a57806320bc44251461051d57806323b872dd1461054c578063248a9ca31461055f57806327048397146105725780632c159a1a146105855780632ec8eec7146105995780632f2ff15d146105cc578063313ce567146105df578063355274ea146105ee5780633644e515146105f857806336568abe14610600578063386fa2211461061357806339364fd714610626578063395093511461064e5780633f4ba83a146106615780634000aea01461066957806340c10f191461067c57806342966c681461068f57806342fe0980146106a25780634414744f146106b557806346904840146106c357806346951954146106d757806346fbf68e146106ea5780634b2763b3146106fd5780634b61cc33146107105780634b75f54f146107305780634c5c0c851461074457806350d75d251461075757806352d1902d1461075f578063556f0dc71461076757806358cf96721461076e5780635c975abb146107815780635d5bf1781461078c57806362aa52871461079f57806362ad1b83146107b257806366a12fb6146107c55780636a30b253146107d85780636c2d9f2f146107eb57806370a08231146107fe57806378c11cec1461081157806379359f6f1461082457806379cc6790146108375780637ecebe001461084a57806382dc1ec4146108745780638456cb59146108875780638da5cb5b1461088f5780639010d07c1461089757806391d14854146108aa57806395714925146108bd578063959b8c3f146108d057806395d89b41146108e3578063983b2d56146108eb57806398650275146108fe5780639903ad38146109065780639bd9bbc61461090e578063a1b2bf8b14610921578063a217fddf14610934578063a457c2d71461093c578063a9059cbb1461094f578063aa271e1a14610962578063b84cdd4a14610975578063bb0d196e14610988578063c3187f621461099b578063c4b1584c146109ae578063c76058fc146109c1578063c780fd82146109d4578063ca0c1e7f146109e7578063ca15c873146109fa578063cf97256d14610a0d578063d505accf14610a20578063d539139314610a33578063d547741f14610a48578063d5a06d4c14610a5b578063d95b637114610a6e578063d9d078d614610a81578063dd62ed3e14610a94578063e63ab1e914610acd578063e74b981b14610ae2578063eb3537cc14610af5578063ecc06c7614610b23578063ee719bc814610b36578063ef43d2c614610b4f578063f2fde38b14610b62578063fad8b32a14610b75578063fc673c4f14610b88578063fe9d930314610b9b575b600080fd5b610458610453366004614c78565b610bae565b60405190151581526020015b60405180910390f35b610475610bd9565b6040516104649190614ca2565b61048a610bea565b6040516104649190614d3f565b6104aa6104a5366004614dc2565b610c7c565b005b6104586104ba366004614e1d565b610d30565b6104aa6104cd366004614e49565b610d46565b6104aa6104e0366004614e66565b610e31565b6104aa6104f3366004614eb1565b610e49565b6003545b604051908152602001610464565b6104aa610518366004614fc5565b610eb7565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516104649190615057565b61045861055a36600461506b565b61115c565b6104fc61056d3660046150ac565b611174565b6104aa6105803660046150c5565b611189565b6101525461053f906001600160a01b031681565b6105ac6105a7366004614e49565b611225565b604080519485526020850193909352918301526060820152608001610464565b6104aa6105da3660046150e7565b6112c8565b60405160128152602001610464565b6104fc6101535481565b6104fc6112e4565b6104aa61060e3660046150e7565b6112ee565b610475610621366004614e49565b61136d565b610639610634366004615117565b611410565b60408051928352901515602083015201610464565b61045861065c366004614e1d565b611496565b6104aa6114d2565b61045861067736600461519a565b6114e4565b61045861068a366004614e1d565b6115f5565b6104aa61069d3660046150ac565b6116f1565b6104aa6106b03660046151fa565b61175b565b610154546104589060ff1681565b6101505461053f906001600160a01b031681565b6104aa6106e5366004614e49565b6117fe565b6104586106f8366004614e49565b61180f565b6104aa61070b36600461506b565b611829565b61072361071e36600461528c565b6118bd565b60405161046491906152d2565b6101515461053f906001600160a01b031681565b60175461053f906001600160a01b031681565b61053f6118f8565b6104fc611902565b60016104fc565b6104aa61077c366004614e1d565b611926565b60e85460ff16610458565b6104aa61079a366004614e49565b61194e565b6104aa6107ad36600461506b565b611979565b6104aa6107c036600461530a565b6119df565b6104aa6107d336600461506b565b611a8d565b6104aa6107e63660046153a8565b611aad565b6107236107f9366004615428565b611af6565b6104fc61080c366004614e49565b611b38565b6104aa61081f36600461545d565b611b60565b610458610832366004614e49565b611d0f565b6104aa610845366004614e1d565b611d97565b6104fc610858366004614e49565b6001600160a01b0316600090815261014e602052604090205490565b6104aa610882366004614e49565b611e1b565b6104aa611e33565b61053f611e43565b61053f6108a53660046150c5565b611e4b565b6104586108b83660046150e7565b611e63565b6104aa6108cb36600461553e565b611e8e565b6104aa6108de366004614e49565b611ea8565b61048a611ef9565b6104aa6108f9366004614e49565b611f08565b6104aa611f20565b6104aa611f38565b6104aa61091c36600461519a565b611fef565b6104aa61092f366004614e66565b612043565b6104fc600081565b61045861094a366004614e1d565b6120fc565b61045861095d366004614e1d565b61214b565b610458610970366004614e49565b612159565b610458610983366004614e1d565b612173565b610458610996366004614e49565b6121c4565b6104aa6109a936600461559a565b61224c565b60195461053f906001600160a01b031681565b60185461053f906001600160a01b031681565b6104aa6109e236600461506b565b612267565b6104aa6109f53660046155b7565b612311565b6104fc610a083660046150ac565b61238b565b6104aa610a1b366004614e1d565b6123a2565b6104aa610a2e366004615622565b612490565b6104fc600080516020615f4383398151915281565b6104aa610a563660046150e7565b612625565b610639610a693660046150ac565b612641565b610458610a7c366004615690565b6126c4565b610458610a8f366004614e1d565b6126d2565b6104fc610aa2366004615690565b6001600160a01b03918216600090815260116020908152604080832093909416825291909152205490565b6104fc600080516020615f2383398151915281565b6104aa610af0366004614e49565b6126ec565b610b08610b03366004614e1d565b612717565b60408051938452602084019290925290820152606001610464565b6104aa610b31366004614e49565b612846565b6101545461053f9061010090046001600160a01b031681565b60165461053f906001600160a01b031681565b6104aa610b70366004614e49565b612871565b6104aa610b83366004614e49565b61288f565b6104aa610b963660046156be565b6128e0565b6104aa610ba9366004615705565b612989565b60006001600160e01b03198216635a05180f60e01b1480610bd35750610bd3826129cb565b92915050565b6060610be56012612a00565b905090565b6060600f8054610bf990615743565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2590615743565b8015610c725780601f10610c4757610100808354040283529160200191610c72565b820191906000526020600020905b815481529060010190602001808311610c5557829003601f168201915b5050505050905090565b6000338585604051602001610c939392919061577d565b604051602081830303815290604052805190602001209050610ce881848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612a6692505050565b6040518481526001600160a01b0386169033907f30f416fa68fca014a0f334464c64b000ba53e99b6d2afdea9d5ca756372d5985906020015b60405180910390a35050505050565b6000610d3d338484612aa7565b50600192915050565b6001600160a01b03811663a9059cbb610d60600080611e4b565b6040516370a0823160e01b81526001600160a01b038516906370a0823190610d8c903090600401615057565b602060405180830381865afa158015610da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcd91906157c6565b6040518363ffffffff1660e01b8152600401610dea9291906157df565b6020604051808303816000875af1158015610e09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e2d91906157f8565b5050565b610e39612b57565b610e44838383612b7b565b505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633141580610e8657506101545460ff1615155b15610ea45760405163c51efddd60e01b815260040160405180910390fd5b610eb084848484612c4f565b5050505050565b604051632329212160e21b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638ca4848490610f03903390600401615057565b602060405180830381865afa158015610f20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4491906157f8565b610f615760405163327fd99160e21b815260040160405180910390fd5b6000610f6b612c81565b90506001600160a01b038116610f7e5750845b600085610f8b5786610f8d565b815b90506000831361102a57610fa08361582b565b610fa985612dc0565b14610fb657610fb6615847565b610fbf84612dc0565b6001600160a01b03821660009081526002602052604081208054909190610fe790849061585d565b90915550506001600160a01b0385166000908152600260205260408120805485929061101490849061585d565b909155506110259050858286612e2e565b6110f4565b851561103857611038615847565b8261104285612dc0565b61104c919061585d565b6001600160a01b03831660009081526002602052604081208054909190611074908490615885565b90915550611083905084612dc0565b6001600160a01b038816600090815260026020526040812080549091906110ab90849061585d565b90915550506001600160a01b038516600090815260026020526040812080548592906110d890849061585d565b909155506110e99050828886612e2e565b6110f4828685612e2e565b846001600160a01b0316876001600160a01b0316336001600160a01b03167fb8381a3ce157650e06186e3e8f4dd4dc29236f2688b6eed1893d0a60d7c6386f8c8589898f6040516111499594939291906158a5565b60405180910390a4505050505050505050565b600061116a33858585612c4f565b90505b9392505050565b60009081526084602052604090206001015490565b60405133906000906111a190839086906020016158e3565b6040516020818303038152906040528051906020012090506111c38184612e61565b6111e05760405163dae1880960e01b815260040160405180910390fd5b6111ea8184612e9d565b60405184815233907f71a63dc095de07aa5512ad57a7596a39516317e316981a1cd71000057be1537b9060200160405180910390a250505050565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bbe4fd506040518163ffffffff1660e01b8152600401602060405180830381865afa158015611289573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ad91906157c6565b90506112b98582612717565b91979096509094509092509050565b6112d182611174565b6112da81612ebe565b610e448383612ec8565b6000610be5612eea565b6001600160a01b03811633146113635760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610e2d8282612f67565b6001600160a01b038181166000908152600160205260409081902054905163c56a069d60e01b8152901960048201526060917f0000000000000000000000000000000000000000000000000000000000000000169063c56a069d90602401600060405180830381865afa1580156113e8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bd39190810190615920565b61015154604051631eed540360e11b815260009182916001600160a01b0390911690633ddaa8069061144a908890889088906004016159d1565b6040805180830381865afa158015611466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148a91906159f0565b91509150935093915050565b3360008181526011602090815260408083206001600160a01b03871684529091528120549091610d3d9185906114cd908690615a15565b612aa7565b6114da612f89565b6114e2612fda565b565b60006114ee612b57565b60006114fb338787613026565b9050600061150b333389856131c7565b9050866001600160a01b0316336001600160a01b03167fe19260aff97b920c7df27010903aeb9c8d2be5d310a2c67824cf3f15396e4c1684888860405161155493929190615a28565b60405180910390a3863b156115eb576115a4878387878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061331092505050565b6115eb5760405162461bcd60e51b815260206004820152601860248201527710dbdb9d1c9858dd0819985b1b189858dac819985a5b195960421b604482015260640161135a565b9695505050505050565b600061160f600080516020615f4383398151915233611e63565b6116485760405162461bcd60e51b815260206004820152600a6024820152693737ba1036b4b73a32b960b11b604482015260640161135a565b611650612b57565b61015354156116c957610153548261166760035490565b6116719190615a15565b11156116c95760405162461bcd60e51b815260206004820152602160248201527f43616e6e6f7420696e63726561736520737570706c79206265796f6e642063616044820152600760fc1b606482015260840161135a565b60408051600080825260208201818152828401909352610d3d923392879287929091906133da565b61175833808360005b6040519080825280601f01601f191660200182016040528015611724576020820181803683370190505b5060005b6040519080825280601f01601f191660200182016040528015611752576020820181803683370190505b50613496565b50565b600054610100900460ff166117825760405162461bcd60e51b815260040161135a90615a5e565b600e805460ff8716600160a01b026001600160a81b03199091166001600160a01b03891617179055600f6117b7848683615af7565b5060106117c5828483615af7565b506117cf306134ab565b6040516000808252908190600080516020615f63833981519152906020015b60405180910390a3505050505050565b6118066135c1565b61175881613604565b6000610bd3600080516020615f2383398151915283611e63565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163314158061186657506101545460ff1615155b156118845760405163c51efddd60e01b815260040160405180910390fd5b6001600160a01b03808416600090815260116020908152604080832093861683529290522054610e4490849084906114cd908590615a15565b606060008585856040516020016118d69392919061577d565b6040516020818303038152906040528051906020012090506115eb81846137d6565b6000610be5613865565b7f596aa569dfde75b0375e5ba62bcfe0e1ce76eaca6130ef1c259fade04cb78b6890565b33156119445760405162461bcd60e51b815260040161135a90615bb6565b610e2d8282613878565b6119566135c1565b61015280546001600160a01b0319166001600160a01b0392909216919091179055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316331415806119b657506101545460ff1615155b156119d45760405163c51efddd60e01b815260040160405180910390fd5b610e44838383612aa7565b336119ec6012828a613988565b611a095760405163f7f0222760e01b815260040160405180910390fd5b611a838189898989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b815292508b91508a908190840183828082843760009201919091525060019250613a31915050565b5050505050505050565b3330146119d457604051630fff4cc960e31b815260040160405180910390fd5b3315611acb5760405162461bcd60e51b815260040161135a90615bb6565b611ad58885613a57565b611ae0888885613ab1565b611aeb888683613ab1565b611a83888784613ab1565b606060008484604051602001611b0d9291906158e3565b604051602081830303815290604052805190602001209050611b2f81846137d6565b95945050505050565b600080611b4483611225565b505050905060008112611b57578061116d565b60009392505050565b600054610100900460ff1615808015611b805750600054600160ff909116105b80611ba15750611b8f30613ace565b158015611ba1575060005460ff166001145b611bbd5760405162461bcd60e51b815260040161135a90615be0565b6000805460ff191660011790558015611be0576000805461ff0019166101001790555b611bf0600060128e8e8e8e61175b565b611bf8613add565b611c00613b04565b611c3f8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613b3792505050565b611c4a600085613b8a565b611c62600080516020615f4383398151915285613b8a565b611c7a600080516020615f2383398151915285613b8a565b61015080546001600160a01b038088166001600160a01b03199283161790925561015280548984169083161790556101518054928a1692909116919091179055610153889055611ccd8383600080613b94565b8015611d01576000805461ff001916905560405160018152600080516020615f038339815191529060200160405180910390a15b505050505050505050505050565b6000610bd3827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bbe4fd506040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8f91906157c6565b6000611da38333610aa2565b905081811015611e015760405162461bcd60e51b8152602060048201526024808201527f45524332303a206275726e20616d6f756e74206578636565647320616c6c6f77604482015263616e636560e01b606482015260840161135a565b611e0e8333848403612aa7565b610e4433848460006116fa565b611758600080516020615f23833981519152826112c8565b611e3b612f89565b6114e2613c43565b6000610be581805b600082815260b66020526040812061116d9083613c80565b60009182526084602090815260408084206001600160a01b0393909316845291905290205460ff1690565b611e966135c1565b611ea284848484613b94565b50505050565b33611eb560128284613c8c565b806001600160a01b0316826001600160a01b03167ff4caeb2d6ca8932a215a353d0703c326ec2d81fc68170f320eb2ab49e9df61f960405160405180910390a35050565b606060108054610bf990615743565b611758600080516020615f43833981519152826112c8565b6114e2600080516020615f43833981519152336112ee565b600054610100900460ff1615808015611f585750600054600160ff909116105b80611f795750611f6730613ace565b158015611f79575060005460ff166001145b611f955760405162461bcd60e51b815260040161135a90615be0565b6000805460ff191660011790558015611fb8576000805461ff0019166101001790555b8015611758576000805461ff001916905560405160018152600080516020615f03833981519152906020015b60405180910390a150565b611ea23333868686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052506040805160208101909152908152925060019150613a319050565b604051339060009061205b90839087906020016158e3565b6040516020818303038152906040528051906020012090506120b081858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612a6692505050565b336001600160a01b03167f0c4c547b3a4fcaa5be8353b3111472b124155bccc86de811d4a481c9e6e9faca8686866040516120ed93929190615c2e565b60405180910390a25050505050565b6000610d3d33846114cd856040518060600160405280602a8152602001615ed9602a91393360009081526011602090815260408083206001600160a01b038d1684529091529020549190613d90565b600061116d33338585612c4f565b6000610bd3600080516020615f4383398151915283611e63565b6000806000806121838686612717565b92509250925060006121ab82841161219c576000612dc0565b6121a68385615c6f565b612dc0565b6121b5908561585d565b60001315979650505050505050565b6000610bd3827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bbe4fd506040518163ffffffff1660e01b8152600401602060405180830381865afa158015612228573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098391906157c6565b6122546135c1565b610154805460ff19169115919091179055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316331415806122a457506101545460ff1615155b156122c25760405163c51efddd60e01b815260040160405180910390fd5b610e4483836114cd846040518060600160405280602a8152602001615ed9602a91396001600160a01b03808a166000908152601160209081526040808320938c16835292905220549190613d90565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163314158061234e57506101545460ff1615155b1561236c5760405163c51efddd60e01b815260040160405180910390fd5b611ea23385858585604051806020016040528060008152506001613a31565b600081815260b660205260408120610bd390613dbc565b604051632329212160e21b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638ca48484906123ee903390600401615057565b602060405180830381865afa15801561240b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242f91906157f8565b61244c5760405163327fd99160e21b815260040160405180910390fd5b6001600160a01b03821660009081526002602052604090205461247090829061585d565b6001600160a01b0390921660009081526002602052604090209190915550565b834211156124e05760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e65000000604482015260640161135a565b600061014f548888886124f28c613dc6565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061254d82613df8565b9050600061255d82878787613e46565b9050896001600160a01b0316816001600160a01b0316146125c05760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e61747572650000604482015260640161135a565b60405163335097db60e11b815230906366a12fb6906125e7908d908d908d90600401615c82565b600060405180830381600087803b15801561260157600080fd5b505af1158015612615573d6000803e3d6000fd5b5050505050505050505050505050565b61262e82611174565b61263781612ebe565b610e448383612f67565b61015154604051631eed540360e11b815260009182916001600160a01b0390911690633ddaa8069061267b908690859081906004016159d1565b6040805180830381865afa158015612697573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126bb91906159f0565b91509150915091565b600061116d60128484613988565b6000806126df8484612717565b5050600013949350505050565b6126f46135c1565b61015080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03821660009081526002602052604081205490808061273c8661136d565b905060005b815181101561283d57600080600084848151811061276157612761615ca6565b60200260200101516001600160a01b0316639b2e48bc308c8c6040518463ffffffff1660e01b815260040161279893929190615c82565b606060405180830381865afa1580156127b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d99190615cbc565b919450925090506127ea8288615a15565b96506127f68187615a15565b9550612813818311612809576000612dc0565b6121a68284615c6f565b61281d848a61585d565b6128279190615885565b97505050508061283690615cea565b9050612741565b50509250925092565b61284e6135c1565b61015180546001600160a01b0319166001600160a01b0392909216919091179055565b6128796135c1565b6128846000826112c8565b6117586000336112ee565b3361289c60128284613e6e565b806001600160a01b0316826001600160a01b03167f50546e66e5f44d728365dc3908c63bc5cfeeab470722c1677e3073a6ac294aa160405160405180910390a35050565b336128ed60128289613988565b61290a5760405163f7f0222760e01b815260040160405180910390fd5b61298081888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8c018190048102820181019092528a815292508a915089908190840183828082843760009201919091525061349692505050565b50505050505050565b610e4433338585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509250611728915050565b60006001600160e01b03198216637965db0b60e01b1480610bd357506301ffc9a760e01b6001600160e01b0319831614610bd3565b606081600001805480602002602001604051908101604052809291908181526020018280548015612a5a57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a3c575b50505050509050919050565b60005b8151811015610e44576000828281518110612a8657612a86615ca6565b6020026020010151905080828501555080612aa090615cea565b9050612a69565b6001600160a01b038316612ace57604051638163862760e01b815260040160405180910390fd5b6001600160a01b038216612af5576040516337c1c09d60e21b815260040160405180910390fd5b6001600160a01b0383811660008181526011602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60e85460ff16156114e257604051637f66be1760e01b815260040160405180910390fd5b6040513390600090612b9390839087906020016158e3565b60408051601f1981840301815291905280516020909101209050612bb78184612e61565b15612bd55760405163782a90fb60e11b815260040160405180910390fd5b612c1281858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612a6692505050565b816001600160a01b03167f770ea40a13a4644573ed785e5c7116890709947918747febc5add46feb531e2d8686866040516120ed93929190615c2e565b6000612c59612b57565b6000612c66858585613026565b9050612c74868686846131c7565b5060019695505050505050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663289b3c0d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ce2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d069190615d03565b604051638369a0f160e01b81529091506001600160a01b03821690638369a0f190612d79907f00000000000000000000000000000000000000000000000000000000000000009030907f9f60ae461adf056670e03ae602566409933242392cb06744f5747c9f38b05d0990600401615c82565b602060405180830381865afa158015612d96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dba9190615d03565b91505090565b60006001600160ff1b03821115612e2a5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b606482015260840161135a565b5090565b816001600160a01b0316836001600160a01b0316600080516020615f6383398151915283604051612b4a91815260200190565b6000805b82811015612e9357838101548015612e8257600192505050610bd3565b50612e8c81615cea565b9050612e65565b5060009392505050565b60005b81811015610e4457600083820155612eb781615cea565b9050612ea0565b6117588133613f66565b612ed28282613fbf565b600082815260b660205260409020610e449082614045565b6000610be57f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f612f1a61011a5490565b61011b546040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b612f71828261405a565b600082815260b660205260409020610e4490826140c1565b612fa1600080516020615f2383398151915233611e63565b6114e25760405162461bcd60e51b815260206004820152600a6024820152693737ba103830bab9b2b960b11b604482015260640161135a565b612fe26140d6565b60e8805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405161301c9190615057565b60405180910390a1565b6000806000613036848787611410565b915091506000821180156130b957506101525460405163639e625760e11b81526001600160a01b039091169063c73cc4ae90613076903390600401615057565b602060405180830381865afa158015613093573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b791906157f8565b155b156131bd578015806130dc57506130cf86611b38565b6130d98386615a15565b11155b6131285760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682062616c616e636520746f2070617920545820666565604482015260640161135a565b6101505461314390879081906001600160a01b0316856131c7565b50604080516001600160a01b038089168252871660208201529081018590526060810183905281151560808201527f3eba86eb3c0ea121e35980d4acae6eb9f1cdf0bf7c0c08443798cfd6e5299de39060a00160405180910390a1806131b2576131ad8285615c6f565b6131b4565b835b9250505061116d565b5091949350505050565b60006001600160a01b0384166131f05760405163eecd6c9b60e01b815260040160405180910390fd5b6001600160a01b0383166132175760405163e219bd3960e01b815260040160405180910390fd5b306001600160a01b03841603613240576040516376b3022760e01b815260040160405180910390fd5b600033905061327181868686604051806020016040528060008152506040518060200160405280600081525061411f565b846001600160a01b0316866001600160a01b0316146133045761330485876114cd866040518060600160405280602d8152602001615f83602d9139601160008c6001600160a01b03166001600160a01b0316815260200190815260200160002060008d6001600160a01b03166001600160a01b0316815260200190815260200160002054613d909092919063ffffffff16565b50600195945050505050565b604051635260769b60e11b815260009084906001600160a01b0382169063a4c0ed369061334590339088908890600401615d20565b6020604051808303816000875af1158015613364573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061338891906157f8565b6133cf5760405162461bcd60e51b815260206004820152601860248201527710dbdb9d1c9858dd0811985b1b189858dac819985a5b195960421b604482015260640161135a565b506001949350505050565b6001600160a01b03851661340157604051630d24315760e01b815260040160405180910390fd5b61340b8585613a57565b61341b86600087878686896141be565b846001600160a01b0316866001600160a01b03167f2fe5be0146f74c5bce36c0b80911af6c7d86ff27e89d5cfa61fc681327954e5d86858560405161346293929190615d47565b60405180910390a36040518481526001600160a01b03861690600090600080516020615f63833981519152906020016117ee565b61349e612b57565b610eb0858585858561430d565b6040516329965a1d60e01b8152731820a4b7618bde71dce8cdc73aab6c95905fad24906329965a1d906135069084907fac7fbab5f54a3ca8194167523c6753bfeb96a445279294b6125b68cce2177054903090600401615d72565b600060405180830381600087803b15801561352057600080fd5b505af1158015613534573d6000803e3d6000fd5b50506040516329965a1d60e01b8152731820a4b7618bde71dce8cdc73aab6c95905fad2492506329965a1d91506135939084907faea199e31a596269b42cdafd93407f14436db6e4cad65417994c2eb37381e05a903090600401615d72565b600060405180830381600087803b1580156135ad57600080fd5b505af1158015610eb0573d6000803e3d6000fd5b6135cc600033611e63565b6114e25760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015260640161135a565b600061360e613865565b6001600160a01b0316036136645760405162461bcd60e51b815260206004820152601d60248201527f5555505350726f786961626c653a206e6f742075706772616461626c65000000604482015260640161135a565b806001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156136a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136c691906157c6565b6136ce611902565b146137275760405162461bcd60e51b815260206004820152602360248201527f5555505350726f786961626c653a206e6f7420636f6d70617469626c65206c6f60448201526267696360e81b606482015260840161135a565b6001600160a01b038116300361377b5760405162461bcd60e51b815260206004820152601960248201527805555505350726f786961626c653a2070726f7879206c6f6f7603c1b604482015260640161135a565b61379181600080516020615eb983398151915255565b7fe011bc04c286c344a8fcbb8de77f953da762c3e25d8cdea984147fc4168a5dcc6137ba611902565b604080519182526001600160a01b038416602083015201611fe4565b6060816001600160401b038111156137f0576137f0614f02565b604051908082528060200260200182016040528015613819578160200160208202803683370190505b50905060005b8281101561385e5760008185015490508083838151811061384257613842615ca6565b60209081029190910101525061385781615cea565b905061381f565b5092915050565b600080516020615eb98339815191525490565b6000613900837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bbe4fd506040518163ffffffff1660e01b8152600401602060405180830381865afa1580156138dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0391906157c6565b5050905061390d82612dc0565b81121561392d5760405163043b37d160e21b815260040160405180910390fd5b61393682612dc0565b6001600160a01b0384166000908152600260205260409020546139599190615885565b6001600160a01b038416600090815260026020526040902055600354613980908390615c6f565b600355505050565b6000816001600160a01b0316836001600160a01b031614806139f757506001600160a01b038316600090815260018501602052604090205460ff1680156139f757506001600160a01b03808316600090815260038601602090815260408083209387168352929052205460ff16155b8061116a57506001600160a01b03808316600090815260028601602090815260408083209387168352929052205460ff1690509392505050565b613a39612b57565b6000613a46878787613026565b9050611a83888888848888886143c8565b613a6081612dc0565b6001600160a01b038316600090815260026020526040902054613a83919061585d565b6001600160a01b038316600090815260026020526040902055600354613aaa908290615a15565b6003555050565b6001600160a01b038216613ac457505050565b612e2e8282613a57565b6001600160a01b03163b151590565b600054610100900460ff166114e25760405162461bcd60e51b815260040161135a90615a5e565b600054610100900460ff16613b2b5760405162461bcd60e51b815260040161135a90615a5e565b60e8805460ff19169055565b600054610100900460ff16613b5e5760405162461bcd60e51b815260040161135a90615a5e565b613b8181604051806040016040528060018152602001603160f81b81525061446a565b611758816144ad565b610e2d8282612ec8565b601680546001600160a01b038087166001600160a01b03199283168117909355601780548783169084161790556018805486831690841617905560198054918516919092161790556040517fcf554eb342edf010a94e07701ae91e99e90b769f649f03aeb1153654ddd43c0190600090a26017546040516001600160a01b03909116907f8837af285f4d380af9227df9ebafa13d992b487fa6d7a4366bd4154576085b8990600090a250505050565b613c4b6144fc565b60e8805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861300f3390565b600061116d8383614542565b806001600160a01b0316826001600160a01b031603613d035760405162461bcd60e51b815260206004820152602d60248201527f4552433737374f70657261746f72733a20617574686f72697a696e672073656c60448201526c331030b99037b832b930ba37b960991b606482015260840161135a565b6001600160a01b038116600090815260018401602052604090205460ff1615613d59576001600160a01b03918216600090815260039390930160209081526040808520929093168452529020805460ff19169055565b6001600160a01b0380831660009081526002850160209081526040808320938516835292905220805460ff19166001179055505050565b60008184841115613db45760405162461bcd60e51b815260040161135a9190614d3f565b505050900390565b6000610bd3825490565b6001600160a01b038116600090815261014e60205260408120805491829190613dee83615cea565b9190505550919050565b6000610bd3613e05612eea565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b6000806000613e578787878761456c565b91509150613e6481614626565b5095945050505050565b336001600160a01b03821603613ed95760405162461bcd60e51b815260206004820152602a60248201527f4552433737374f70657261746f72733a207265766f6b696e672073656c662061604482015269399037b832b930ba37b960b11b606482015260840161135a565b6001600160a01b038116600090815260018401602052604090205460ff1615613f33576001600160a01b0380831660009081526003850160209081526040808320938516835292905220805460ff19166001179055505050565b6001600160a01b03918216600090815260029390930160209081526040808520929093168452529020805460ff19169055565b613f708282611e63565b610e2d57613f7d8161476b565b613f8883602061477d565b604051602001613f99929190615d95565b60408051601f198184030181529082905262461bcd60e51b825261135a91600401614d3f565b613fc98282611e63565b610e2d5760008281526084602090815260408083206001600160a01b03851684529091529020805460ff191660011790556140013390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600061116d836001600160a01b038416614918565b6140648282611e63565b15610e2d5760008281526084602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600061116d836001600160a01b038416614967565b60e85460ff166114e25760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161135a565b614132858561412d86612dc0565b614a5a565b836001600160a01b0316856001600160a01b0316876001600160a01b03167f06b541ddaa720db2b10a4d0cdac39b8d360425fc073085fac19bc8261467798786868660405161418393929190615d47565b60405180910390a4836001600160a01b0316856001600160a01b0316600080516020615f63833981519152856040516117ee91815260200190565b60405163555ddc6560e11b8152600090731820a4b7618bde71dce8cdc73aab6c95905fad249063aabbb8ca9061421a9089907fb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b906004016157df565b602060405180830381865afa158015614237573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061425b9190615d03565b90506001600160a01b038116156142d7576040516223de2960e01b81526001600160a01b038216906223de29906142a0908b908b908b908b908b908b90600401615e04565b600060405180830381600087803b1580156142ba57600080fd5b505af11580156142ce573d6000803e3d6000fd5b50505050611a83565b8115611a83576142ef866001600160a01b0316613ace565b15611a835760405163fe737d0560e01b815260040160405180910390fd5b6001600160a01b03841661433457604051632e8aac6160e21b815260040160405180910390fd5b61434385856000868686614b59565b61434d8484613878565b836001600160a01b0316856001600160a01b03167fa78a9be3a7b862d26933ad85fb11d80ef66b8f972d7cbba06621d583943a409885858560405161439493929190615d47565b60405180910390a36040518381526000906001600160a01b03861690600080516020615f6383398151915290602001610d21565b6001600160a01b0386166143ef5760405163eecd6c9b60e01b815260040160405180910390fd5b6001600160a01b0385166144165760405163e219bd3960e01b815260040160405180910390fd5b306001600160a01b0386160361443f576040516376b3022760e01b815260040160405180910390fd5b61444d878787878787614b59565b61445b87878787878761411f565b612980878787878787876141be565b600054610100900460ff166144915760405162461bcd60e51b815260040161135a90615a5e565b81516020928301208151919092012061011a9190915561011b55565b600054610100900460ff166144d45760405162461bcd60e51b815260040161135a90615a5e565b507f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c961014f55565b60e85460ff16156114e25760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161135a565b600082600001828154811061455957614559615ca6565b9060005260206000200154905092915050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115614599575060009050600361461d565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156145ed573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166146165760006001925092505061461d565b9150600090505b94509492505050565b600081600481111561463a5761463a615e5e565b036146425750565b600181600481111561465657614656615e5e565b0361469e5760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b604482015260640161135a565b60028160048111156146b2576146b2615e5e565b036146ff5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161135a565b600381600481111561471357614713615e5e565b036117585760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161135a565b6060610bd36001600160a01b03831660145b6060600061478c836002615e74565b614797906002615a15565b6001600160401b038111156147ae576147ae614f02565b6040519080825280601f01601f1916602001820160405280156147d8576020820181803683370190505b509050600360fc1b816000815181106147f3576147f3615ca6565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061482257614822615ca6565b60200101906001600160f81b031916908160001a9053506000614846846002615e74565b614851906001615a15565b90505b60018111156148c9576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061488557614885615ca6565b1a60f81b82828151811061489b5761489b615ca6565b60200101906001600160f81b031916908160001a90535060049490941c936148c281615e8b565b9050614854565b50831561116d5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640161135a565b600081815260018301602052604081205461495f57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610bd3565b506000610bd3565b60008181526001830160205260408120548015614a5057600061498b600183615c6f565b855490915060009061499f90600190615c6f565b9050818114614a045760008660000182815481106149bf576149bf615ca6565b90600052602060002001549050808760000184815481106149e2576149e2615ca6565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614a1557614a15615ea2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610bd3565b6000915050610bd3565b6000614abe847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bbe4fd506040518163ffffffff1660e01b8152600401602060405180830381865afa1580156138dc573d6000803e3d6000fd5b5050905081811215614ae357604051632f4cb94160e01b815260040160405180910390fd5b6001600160a01b038416600090815260026020526040902054614b07908390615885565b6001600160a01b038086166000908152600260205260408082209390935590851681522054614b3790839061585d565b6001600160a01b03909316600090815260026020526040902092909255505050565b60405163555ddc6560e11b8152600090731820a4b7618bde71dce8cdc73aab6c95905fad249063aabbb8ca90614bb59089907f29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895906004016157df565b602060405180830381865afa158015614bd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bf69190615d03565b90506001600160a01b0381161561298057604051633ad5cbc160e11b81526001600160a01b038216906375ab978290614c3d908a908a908a908a908a908a90600401615e04565b600060405180830381600087803b158015614c5757600080fd5b505af1158015614c6b573d6000803e3d6000fd5b5050505050505050505050565b600060208284031215614c8a57600080fd5b81356001600160e01b03198116811461116d57600080fd5b6020808252825182820181905260009190848201906040850190845b81811015614ce35783516001600160a01b031683529284019291840191600101614cbe565b50909695505050505050565b60005b83811015614d0a578181015183820152602001614cf2565b50506000910152565b60008151808452614d2b816020860160208601614cef565b601f01601f19169290920160200192915050565b60208152600061116d6020830184614d13565b6001600160a01b038116811461175857600080fd5b8035614d7281614d52565b919050565b60008083601f840112614d8957600080fd5b5081356001600160401b03811115614da057600080fd5b6020830191508360208260051b8501011115614dbb57600080fd5b9250929050565b60008060008060608587031215614dd857600080fd5b8435614de381614d52565b93506020850135925060408501356001600160401b03811115614e0557600080fd5b614e1187828801614d77565b95989497509550505050565b60008060408385031215614e3057600080fd5b8235614e3b81614d52565b946020939093013593505050565b600060208284031215614e5b57600080fd5b813561116d81614d52565b600080600060408486031215614e7b57600080fd5b8335925060208401356001600160401b03811115614e9857600080fd5b614ea486828701614d77565b9497909650939450505050565b60008060008060808587031215614ec757600080fd5b8435614ed281614d52565b93506020850135614ee281614d52565b92506040850135614ef281614d52565b9396929550929360600135925050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614f4057614f40614f02565b604052919050565b600082601f830112614f5957600080fd5b81356001600160401b03811115614f7257614f72614f02565b614f85601f8201601f1916602001614f18565b818152846020838601011115614f9a57600080fd5b816020850160208301376000918101602001919091529392505050565b801515811461175857600080fd5b600080600080600080600060e0888a031215614fe057600080fd5b8735965060208801356001600160401b03811115614ffd57600080fd5b6150098a828b01614f48565b965050604088013561501a81614d52565b9450606088013561502a81614fb7565b9350608088013561503a81614d52565b9699959850939692959460a0840135945060c09093013592915050565b6001600160a01b0391909116815260200190565b60008060006060848603121561508057600080fd5b833561508b81614d52565b9250602084013561509b81614d52565b929592945050506040919091013590565b6000602082840312156150be57600080fd5b5035919050565b600080604083850312156150d857600080fd5b50508035926020909101359150565b600080604083850312156150fa57600080fd5b82359150602083013561510c81614d52565b809150509250929050565b60008060006060848603121561512c57600080fd5b83359250602084013561513e81614d52565b9150604084013561514e81614d52565b809150509250925092565b60008083601f84011261516b57600080fd5b5081356001600160401b0381111561518257600080fd5b602083019150836020828501011115614dbb57600080fd5b600080600080606085870312156151b057600080fd5b84356151bb81614d52565b93506020850135925060408501356001600160401b038111156151dd57600080fd5b614e1187828801615159565b803560ff81168114614d7257600080fd5b6000806000806000806080878903121561521357600080fd5b863561521e81614d52565b955061522c602088016151e9565b945060408701356001600160401b038082111561524857600080fd5b6152548a838b01615159565b9096509450606089013591508082111561526d57600080fd5b5061527a89828a01615159565b979a9699509497509295939492505050565b600080600080608085870312156152a257600080fd5b84356152ad81614d52565b935060208501356152bd81614d52565b93969395505050506040820135916060013590565b6020808252825182820181905260009190848201906040850190845b81811015614ce3578351835292840192918401916001016152ee565b600080600080600080600060a0888a03121561532557600080fd5b873561533081614d52565b9650602088013561534081614d52565b95506040880135945060608801356001600160401b038082111561536357600080fd5b61536f8b838c01615159565b909650945060808a013591508082111561538857600080fd5b506153958a828b01615159565b989b979a50959850939692959293505050565b600080600080600080600080610100898b0312156153c557600080fd5b88356153d081614d52565b975060208901356153e081614d52565b965060408901356153f081614d52565b9550606089013561540081614d52565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b60008060006060848603121561543d57600080fd5b833561544881614d52565b95602085013595506040909401359392505050565b60008060008060008060008060008060006101208c8e03121561547f57600080fd5b6001600160401b038c3581101561549557600080fd5b6154a28e8e358f01615159565b909c509a5060208d01358110156154b857600080fd5b506154c98d60208e01358e01615159565b909950975060408c0135965060608c01356154e381614d52565b955060808c01356154f381614d52565b945061550160a08d01614d67565b935061550f60c08d01614d67565b925061551d60e08d01614d67565b915061552c6101008d01614d67565b90509295989b509295989b9093969950565b6000806000806080858703121561555457600080fd5b843561555f81614d52565b9350602085013561556f81614d52565b9250604085013561557f81614d52565b9150606085013561558f81614d52565b939692955090935050565b6000602082840312156155ac57600080fd5b813561116d81614fb7565b600080600080608085870312156155cd57600080fd5b84356155d881614d52565b935060208501356155e881614d52565b92506040850135915060608501356001600160401b0381111561560a57600080fd5b61561687828801614f48565b91505092959194509250565b600080600080600080600060e0888a03121561563d57600080fd5b873561564881614d52565b9650602088013561565881614d52565b95506040880135945060608801359350615674608089016151e9565b925060a0880135915060c0880135905092959891949750929550565b600080604083850312156156a357600080fd5b82356156ae81614d52565b9150602083013561510c81614d52565b600080600080600080608087890312156156d757600080fd5b86356156e281614d52565b95506020870135945060408701356001600160401b038082111561524857600080fd5b60008060006040848603121561571a57600080fd5b8335925060208401356001600160401b0381111561573757600080fd5b614ea486828701615159565b600181811c9082168061575757607f821691505b60208210810361577757634e487b7160e01b600052602260045260246000fd5b50919050565b6080808252600e908201526d41677265656d656e74537461746560901b60a08201526001600160a01b039384166020820152919092166040820152606081019190915260c00190565b6000602082840312156157d857600080fd5b5051919050565b6001600160a01b03929092168252602082015260400190565b60006020828403121561580a57600080fd5b815161116d81614fb7565b634e487b7160e01b600052601160045260246000fd5b6000600160ff1b820161584057615840615815565b5060000390565b634e487b7160e01b600052600160045260246000fd5b808201828112600083128015821682158216171561587d5761587d615815565b505092915050565b818103600083128015838313168383128216171561385e5761385e615815565b85815260018060a01b038516602082015283604082015282606082015260a0608082015260006158d860a0830184614d13565b979650505050505050565b6060808252600d908201526c41677265656d656e744461746160981b60808201526001600160a01b03929092166020830152604082015260a00190565b6000602080838503121561593357600080fd5b82516001600160401b038082111561594a57600080fd5b818501915085601f83011261595e57600080fd5b81518181111561597057615970614f02565b8060051b9150615981848301614f18565b818152918301840191848101908884111561599b57600080fd5b938501935b838510156159c557845192506159b583614d52565b82825293850193908501906159a0565b98975050505050505050565b9283526001600160a01b03918216602084015216604082015260600190565b60008060408385031215615a0357600080fd5b82519150602083015161510c81614fb7565b80820180821115610bd357610bd3615815565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b601f821115610e4457600081815260208120601f850160051c81016020861015615ad05750805b601f850160051c820191505b81811015615aef57828155600101615adc565b505050505050565b6001600160401b03831115615b0e57615b0e614f02565b615b2283615b1c8354615743565b83615aa9565b6000601f841160018114615b565760008515615b3e5750838201355b600019600387901b1c1916600186901b178355610eb0565b600083815260209020601f19861690835b82811015615b875786850135825560209485019460019092019101615b67565b5086821015615ba45760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60208082526010908201526f13db9b1e4815934818d85b8818d85b1b60821b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b838152604060208201819052810182905260006001600160fb1b03831115615c5557600080fd5b8260051b8085606085013791909101606001949350505050565b81810381811115610bd357610bd3615815565b6001600160a01b039384168152919092166020820152604081019190915260600190565b634e487b7160e01b600052603260045260246000fd5b600080600060608486031215615cd157600080fd5b8351925060208401519150604084015190509250925092565b600060018201615cfc57615cfc615815565b5060010190565b600060208284031215615d1557600080fd5b815161116d81614d52565b60018060a01b0384168152826020820152606060408201526000611b2f6060830184614d13565b838152606060208201526000615d606060830185614d13565b82810360408401526115eb8185614d13565b6001600160a01b0393841681526020810192909252909116604082015260600190565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b815260008351615dc7816017850160208801614cef565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615df8816028840160208801614cef565b01602801949350505050565b6001600160a01b0387811682528681166020830152851660408201526060810184905260c060808201819052600090615e3f90830185614d13565b82810360a0840152615e518185614d13565b9998505050505050505050565b634e487b7160e01b600052602160045260246000fd5b8082028115828204841417610bd357610bd3615815565b600081615e9a57615e9a615815565b506000190190565b634e487b7160e01b600052603160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5375706572546f6b656e3a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249865d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5375706572546f6b656e3a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365a2646970667358221220caac6dc494232b454d2de2240ef7f3edd496c7af33e64f3f0cb49a2a1d3e8dee64736f6c63430008130033000000000000000000000000a4ff07cf81c02cfd356184879d953970ca957585

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106104405760003560e01c806301ffc9a71461044557806306e485381461046d57806306fdde0314610482578063090c415e14610497578063095ea7b3146104ac5780630cd865ec146104bf57806312a6a3f8146104d257806316d055d6146104e557806318160ddd146104f85780631863e8091461050a57806320bc44251461051d57806323b872dd1461054c578063248a9ca31461055f57806327048397146105725780632c159a1a146105855780632ec8eec7146105995780632f2ff15d146105cc578063313ce567146105df578063355274ea146105ee5780633644e515146105f857806336568abe14610600578063386fa2211461061357806339364fd714610626578063395093511461064e5780633f4ba83a146106615780634000aea01461066957806340c10f191461067c57806342966c681461068f57806342fe0980146106a25780634414744f146106b557806346904840146106c357806346951954146106d757806346fbf68e146106ea5780634b2763b3146106fd5780634b61cc33146107105780634b75f54f146107305780634c5c0c851461074457806350d75d251461075757806352d1902d1461075f578063556f0dc71461076757806358cf96721461076e5780635c975abb146107815780635d5bf1781461078c57806362aa52871461079f57806362ad1b83146107b257806366a12fb6146107c55780636a30b253146107d85780636c2d9f2f146107eb57806370a08231146107fe57806378c11cec1461081157806379359f6f1461082457806379cc6790146108375780637ecebe001461084a57806382dc1ec4146108745780638456cb59146108875780638da5cb5b1461088f5780639010d07c1461089757806391d14854146108aa57806395714925146108bd578063959b8c3f146108d057806395d89b41146108e3578063983b2d56146108eb57806398650275146108fe5780639903ad38146109065780639bd9bbc61461090e578063a1b2bf8b14610921578063a217fddf14610934578063a457c2d71461093c578063a9059cbb1461094f578063aa271e1a14610962578063b84cdd4a14610975578063bb0d196e14610988578063c3187f621461099b578063c4b1584c146109ae578063c76058fc146109c1578063c780fd82146109d4578063ca0c1e7f146109e7578063ca15c873146109fa578063cf97256d14610a0d578063d505accf14610a20578063d539139314610a33578063d547741f14610a48578063d5a06d4c14610a5b578063d95b637114610a6e578063d9d078d614610a81578063dd62ed3e14610a94578063e63ab1e914610acd578063e74b981b14610ae2578063eb3537cc14610af5578063ecc06c7614610b23578063ee719bc814610b36578063ef43d2c614610b4f578063f2fde38b14610b62578063fad8b32a14610b75578063fc673c4f14610b88578063fe9d930314610b9b575b600080fd5b610458610453366004614c78565b610bae565b60405190151581526020015b60405180910390f35b610475610bd9565b6040516104649190614ca2565b61048a610bea565b6040516104649190614d3f565b6104aa6104a5366004614dc2565b610c7c565b005b6104586104ba366004614e1d565b610d30565b6104aa6104cd366004614e49565b610d46565b6104aa6104e0366004614e66565b610e31565b6104aa6104f3366004614eb1565b610e49565b6003545b604051908152602001610464565b6104aa610518366004614fc5565b610eb7565b7f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575855b6040516104649190615057565b61045861055a36600461506b565b61115c565b6104fc61056d3660046150ac565b611174565b6104aa6105803660046150c5565b611189565b6101525461053f906001600160a01b031681565b6105ac6105a7366004614e49565b611225565b604080519485526020850193909352918301526060820152608001610464565b6104aa6105da3660046150e7565b6112c8565b60405160128152602001610464565b6104fc6101535481565b6104fc6112e4565b6104aa61060e3660046150e7565b6112ee565b610475610621366004614e49565b61136d565b610639610634366004615117565b611410565b60408051928352901515602083015201610464565b61045861065c366004614e1d565b611496565b6104aa6114d2565b61045861067736600461519a565b6114e4565b61045861068a366004614e1d565b6115f5565b6104aa61069d3660046150ac565b6116f1565b6104aa6106b03660046151fa565b61175b565b610154546104589060ff1681565b6101505461053f906001600160a01b031681565b6104aa6106e5366004614e49565b6117fe565b6104586106f8366004614e49565b61180f565b6104aa61070b36600461506b565b611829565b61072361071e36600461528c565b6118bd565b60405161046491906152d2565b6101515461053f906001600160a01b031681565b60175461053f906001600160a01b031681565b61053f6118f8565b6104fc611902565b60016104fc565b6104aa61077c366004614e1d565b611926565b60e85460ff16610458565b6104aa61079a366004614e49565b61194e565b6104aa6107ad36600461506b565b611979565b6104aa6107c036600461530a565b6119df565b6104aa6107d336600461506b565b611a8d565b6104aa6107e63660046153a8565b611aad565b6107236107f9366004615428565b611af6565b6104fc61080c366004614e49565b611b38565b6104aa61081f36600461545d565b611b60565b610458610832366004614e49565b611d0f565b6104aa610845366004614e1d565b611d97565b6104fc610858366004614e49565b6001600160a01b0316600090815261014e602052604090205490565b6104aa610882366004614e49565b611e1b565b6104aa611e33565b61053f611e43565b61053f6108a53660046150c5565b611e4b565b6104586108b83660046150e7565b611e63565b6104aa6108cb36600461553e565b611e8e565b6104aa6108de366004614e49565b611ea8565b61048a611ef9565b6104aa6108f9366004614e49565b611f08565b6104aa611f20565b6104aa611f38565b6104aa61091c36600461519a565b611fef565b6104aa61092f366004614e66565b612043565b6104fc600081565b61045861094a366004614e1d565b6120fc565b61045861095d366004614e1d565b61214b565b610458610970366004614e49565b612159565b610458610983366004614e1d565b612173565b610458610996366004614e49565b6121c4565b6104aa6109a936600461559a565b61224c565b60195461053f906001600160a01b031681565b60185461053f906001600160a01b031681565b6104aa6109e236600461506b565b612267565b6104aa6109f53660046155b7565b612311565b6104fc610a083660046150ac565b61238b565b6104aa610a1b366004614e1d565b6123a2565b6104aa610a2e366004615622565b612490565b6104fc600080516020615f4383398151915281565b6104aa610a563660046150e7565b612625565b610639610a693660046150ac565b612641565b610458610a7c366004615690565b6126c4565b610458610a8f366004614e1d565b6126d2565b6104fc610aa2366004615690565b6001600160a01b03918216600090815260116020908152604080832093909416825291909152205490565b6104fc600080516020615f2383398151915281565b6104aa610af0366004614e49565b6126ec565b610b08610b03366004614e1d565b612717565b60408051938452602084019290925290820152606001610464565b6104aa610b31366004614e49565b612846565b6101545461053f9061010090046001600160a01b031681565b60165461053f906001600160a01b031681565b6104aa610b70366004614e49565b612871565b6104aa610b83366004614e49565b61288f565b6104aa610b963660046156be565b6128e0565b6104aa610ba9366004615705565b612989565b60006001600160e01b03198216635a05180f60e01b1480610bd35750610bd3826129cb565b92915050565b6060610be56012612a00565b905090565b6060600f8054610bf990615743565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2590615743565b8015610c725780601f10610c4757610100808354040283529160200191610c72565b820191906000526020600020905b815481529060010190602001808311610c5557829003601f168201915b5050505050905090565b6000338585604051602001610c939392919061577d565b604051602081830303815290604052805190602001209050610ce881848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612a6692505050565b6040518481526001600160a01b0386169033907f30f416fa68fca014a0f334464c64b000ba53e99b6d2afdea9d5ca756372d5985906020015b60405180910390a35050505050565b6000610d3d338484612aa7565b50600192915050565b6001600160a01b03811663a9059cbb610d60600080611e4b565b6040516370a0823160e01b81526001600160a01b038516906370a0823190610d8c903090600401615057565b602060405180830381865afa158015610da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcd91906157c6565b6040518363ffffffff1660e01b8152600401610dea9291906157df565b6020604051808303816000875af1158015610e09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e2d91906157f8565b5050565b610e39612b57565b610e44838383612b7b565b505050565b7f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575856001600160a01b031633141580610e8657506101545460ff1615155b15610ea45760405163c51efddd60e01b815260040160405180910390fd5b610eb084848484612c4f565b5050505050565b604051632329212160e21b81526001600160a01b037f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575851690638ca4848490610f03903390600401615057565b602060405180830381865afa158015610f20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4491906157f8565b610f615760405163327fd99160e21b815260040160405180910390fd5b6000610f6b612c81565b90506001600160a01b038116610f7e5750845b600085610f8b5786610f8d565b815b90506000831361102a57610fa08361582b565b610fa985612dc0565b14610fb657610fb6615847565b610fbf84612dc0565b6001600160a01b03821660009081526002602052604081208054909190610fe790849061585d565b90915550506001600160a01b0385166000908152600260205260408120805485929061101490849061585d565b909155506110259050858286612e2e565b6110f4565b851561103857611038615847565b8261104285612dc0565b61104c919061585d565b6001600160a01b03831660009081526002602052604081208054909190611074908490615885565b90915550611083905084612dc0565b6001600160a01b038816600090815260026020526040812080549091906110ab90849061585d565b90915550506001600160a01b038516600090815260026020526040812080548592906110d890849061585d565b909155506110e99050828886612e2e565b6110f4828685612e2e565b846001600160a01b0316876001600160a01b0316336001600160a01b03167fb8381a3ce157650e06186e3e8f4dd4dc29236f2688b6eed1893d0a60d7c6386f8c8589898f6040516111499594939291906158a5565b60405180910390a4505050505050505050565b600061116a33858585612c4f565b90505b9392505050565b60009081526084602052604090206001015490565b60405133906000906111a190839086906020016158e3565b6040516020818303038152906040528051906020012090506111c38184612e61565b6111e05760405163dae1880960e01b815260040160405180910390fd5b6111ea8184612e9d565b60405184815233907f71a63dc095de07aa5512ad57a7596a39516317e316981a1cd71000057be1537b9060200160405180910390a250505050565b6000806000807f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575856001600160a01b031663bbe4fd506040518163ffffffff1660e01b8152600401602060405180830381865afa158015611289573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ad91906157c6565b90506112b98582612717565b91979096509094509092509050565b6112d182611174565b6112da81612ebe565b610e448383612ec8565b6000610be5612eea565b6001600160a01b03811633146113635760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610e2d8282612f67565b6001600160a01b038181166000908152600160205260409081902054905163c56a069d60e01b8152901960048201526060917f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca957585169063c56a069d90602401600060405180830381865afa1580156113e8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bd39190810190615920565b61015154604051631eed540360e11b815260009182916001600160a01b0390911690633ddaa8069061144a908890889088906004016159d1565b6040805180830381865afa158015611466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148a91906159f0565b91509150935093915050565b3360008181526011602090815260408083206001600160a01b03871684529091528120549091610d3d9185906114cd908690615a15565b612aa7565b6114da612f89565b6114e2612fda565b565b60006114ee612b57565b60006114fb338787613026565b9050600061150b333389856131c7565b9050866001600160a01b0316336001600160a01b03167fe19260aff97b920c7df27010903aeb9c8d2be5d310a2c67824cf3f15396e4c1684888860405161155493929190615a28565b60405180910390a3863b156115eb576115a4878387878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061331092505050565b6115eb5760405162461bcd60e51b815260206004820152601860248201527710dbdb9d1c9858dd0819985b1b189858dac819985a5b195960421b604482015260640161135a565b9695505050505050565b600061160f600080516020615f4383398151915233611e63565b6116485760405162461bcd60e51b815260206004820152600a6024820152693737ba1036b4b73a32b960b11b604482015260640161135a565b611650612b57565b61015354156116c957610153548261166760035490565b6116719190615a15565b11156116c95760405162461bcd60e51b815260206004820152602160248201527f43616e6e6f7420696e63726561736520737570706c79206265796f6e642063616044820152600760fc1b606482015260840161135a565b60408051600080825260208201818152828401909352610d3d923392879287929091906133da565b61175833808360005b6040519080825280601f01601f191660200182016040528015611724576020820181803683370190505b5060005b6040519080825280601f01601f191660200182016040528015611752576020820181803683370190505b50613496565b50565b600054610100900460ff166117825760405162461bcd60e51b815260040161135a90615a5e565b600e805460ff8716600160a01b026001600160a81b03199091166001600160a01b03891617179055600f6117b7848683615af7565b5060106117c5828483615af7565b506117cf306134ab565b6040516000808252908190600080516020615f63833981519152906020015b60405180910390a3505050505050565b6118066135c1565b61175881613604565b6000610bd3600080516020615f2383398151915283611e63565b7f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575856001600160a01b03163314158061186657506101545460ff1615155b156118845760405163c51efddd60e01b815260040160405180910390fd5b6001600160a01b03808416600090815260116020908152604080832093861683529290522054610e4490849084906114cd908590615a15565b606060008585856040516020016118d69392919061577d565b6040516020818303038152906040528051906020012090506115eb81846137d6565b6000610be5613865565b7f596aa569dfde75b0375e5ba62bcfe0e1ce76eaca6130ef1c259fade04cb78b6890565b33156119445760405162461bcd60e51b815260040161135a90615bb6565b610e2d8282613878565b6119566135c1565b61015280546001600160a01b0319166001600160a01b0392909216919091179055565b7f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575856001600160a01b0316331415806119b657506101545460ff1615155b156119d45760405163c51efddd60e01b815260040160405180910390fd5b610e44838383612aa7565b336119ec6012828a613988565b611a095760405163f7f0222760e01b815260040160405180910390fd5b611a838189898989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b815292508b91508a908190840183828082843760009201919091525060019250613a31915050565b5050505050505050565b3330146119d457604051630fff4cc960e31b815260040160405180910390fd5b3315611acb5760405162461bcd60e51b815260040161135a90615bb6565b611ad58885613a57565b611ae0888885613ab1565b611aeb888683613ab1565b611a83888784613ab1565b606060008484604051602001611b0d9291906158e3565b604051602081830303815290604052805190602001209050611b2f81846137d6565b95945050505050565b600080611b4483611225565b505050905060008112611b57578061116d565b60009392505050565b600054610100900460ff1615808015611b805750600054600160ff909116105b80611ba15750611b8f30613ace565b158015611ba1575060005460ff166001145b611bbd5760405162461bcd60e51b815260040161135a90615be0565b6000805460ff191660011790558015611be0576000805461ff0019166101001790555b611bf0600060128e8e8e8e61175b565b611bf8613add565b611c00613b04565b611c3f8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613b3792505050565b611c4a600085613b8a565b611c62600080516020615f4383398151915285613b8a565b611c7a600080516020615f2383398151915285613b8a565b61015080546001600160a01b038088166001600160a01b03199283161790925561015280548984169083161790556101518054928a1692909116919091179055610153889055611ccd8383600080613b94565b8015611d01576000805461ff001916905560405160018152600080516020615f038339815191529060200160405180910390a15b505050505050505050505050565b6000610bd3827f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575856001600160a01b031663bbe4fd506040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8f91906157c6565b6000611da38333610aa2565b905081811015611e015760405162461bcd60e51b8152602060048201526024808201527f45524332303a206275726e20616d6f756e74206578636565647320616c6c6f77604482015263616e636560e01b606482015260840161135a565b611e0e8333848403612aa7565b610e4433848460006116fa565b611758600080516020615f23833981519152826112c8565b611e3b612f89565b6114e2613c43565b6000610be581805b600082815260b66020526040812061116d9083613c80565b60009182526084602090815260408084206001600160a01b0393909316845291905290205460ff1690565b611e966135c1565b611ea284848484613b94565b50505050565b33611eb560128284613c8c565b806001600160a01b0316826001600160a01b03167ff4caeb2d6ca8932a215a353d0703c326ec2d81fc68170f320eb2ab49e9df61f960405160405180910390a35050565b606060108054610bf990615743565b611758600080516020615f43833981519152826112c8565b6114e2600080516020615f43833981519152336112ee565b600054610100900460ff1615808015611f585750600054600160ff909116105b80611f795750611f6730613ace565b158015611f79575060005460ff166001145b611f955760405162461bcd60e51b815260040161135a90615be0565b6000805460ff191660011790558015611fb8576000805461ff0019166101001790555b8015611758576000805461ff001916905560405160018152600080516020615f03833981519152906020015b60405180910390a150565b611ea23333868686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052506040805160208101909152908152925060019150613a319050565b604051339060009061205b90839087906020016158e3565b6040516020818303038152906040528051906020012090506120b081858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612a6692505050565b336001600160a01b03167f0c4c547b3a4fcaa5be8353b3111472b124155bccc86de811d4a481c9e6e9faca8686866040516120ed93929190615c2e565b60405180910390a25050505050565b6000610d3d33846114cd856040518060600160405280602a8152602001615ed9602a91393360009081526011602090815260408083206001600160a01b038d1684529091529020549190613d90565b600061116d33338585612c4f565b6000610bd3600080516020615f4383398151915283611e63565b6000806000806121838686612717565b92509250925060006121ab82841161219c576000612dc0565b6121a68385615c6f565b612dc0565b6121b5908561585d565b60001315979650505050505050565b6000610bd3827f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575856001600160a01b031663bbe4fd506040518163ffffffff1660e01b8152600401602060405180830381865afa158015612228573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098391906157c6565b6122546135c1565b610154805460ff19169115919091179055565b7f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575856001600160a01b0316331415806122a457506101545460ff1615155b156122c25760405163c51efddd60e01b815260040160405180910390fd5b610e4483836114cd846040518060600160405280602a8152602001615ed9602a91396001600160a01b03808a166000908152601160209081526040808320938c16835292905220549190613d90565b7f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575856001600160a01b03163314158061234e57506101545460ff1615155b1561236c5760405163c51efddd60e01b815260040160405180910390fd5b611ea23385858585604051806020016040528060008152506001613a31565b600081815260b660205260408120610bd390613dbc565b604051632329212160e21b81526001600160a01b037f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575851690638ca48484906123ee903390600401615057565b602060405180830381865afa15801561240b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242f91906157f8565b61244c5760405163327fd99160e21b815260040160405180910390fd5b6001600160a01b03821660009081526002602052604090205461247090829061585d565b6001600160a01b0390921660009081526002602052604090209190915550565b834211156124e05760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e65000000604482015260640161135a565b600061014f548888886124f28c613dc6565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061254d82613df8565b9050600061255d82878787613e46565b9050896001600160a01b0316816001600160a01b0316146125c05760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e61747572650000604482015260640161135a565b60405163335097db60e11b815230906366a12fb6906125e7908d908d908d90600401615c82565b600060405180830381600087803b15801561260157600080fd5b505af1158015612615573d6000803e3d6000fd5b5050505050505050505050505050565b61262e82611174565b61263781612ebe565b610e448383612f67565b61015154604051631eed540360e11b815260009182916001600160a01b0390911690633ddaa8069061267b908690859081906004016159d1565b6040805180830381865afa158015612697573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126bb91906159f0565b91509150915091565b600061116d60128484613988565b6000806126df8484612717565b5050600013949350505050565b6126f46135c1565b61015080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03821660009081526002602052604081205490808061273c8661136d565b905060005b815181101561283d57600080600084848151811061276157612761615ca6565b60200260200101516001600160a01b0316639b2e48bc308c8c6040518463ffffffff1660e01b815260040161279893929190615c82565b606060405180830381865afa1580156127b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d99190615cbc565b919450925090506127ea8288615a15565b96506127f68187615a15565b9550612813818311612809576000612dc0565b6121a68284615c6f565b61281d848a61585d565b6128279190615885565b97505050508061283690615cea565b9050612741565b50509250925092565b61284e6135c1565b61015180546001600160a01b0319166001600160a01b0392909216919091179055565b6128796135c1565b6128846000826112c8565b6117586000336112ee565b3361289c60128284613e6e565b806001600160a01b0316826001600160a01b03167f50546e66e5f44d728365dc3908c63bc5cfeeab470722c1677e3073a6ac294aa160405160405180910390a35050565b336128ed60128289613988565b61290a5760405163f7f0222760e01b815260040160405180910390fd5b61298081888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8c018190048102820181019092528a815292508a915089908190840183828082843760009201919091525061349692505050565b50505050505050565b610e4433338585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509250611728915050565b60006001600160e01b03198216637965db0b60e01b1480610bd357506301ffc9a760e01b6001600160e01b0319831614610bd3565b606081600001805480602002602001604051908101604052809291908181526020018280548015612a5a57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a3c575b50505050509050919050565b60005b8151811015610e44576000828281518110612a8657612a86615ca6565b6020026020010151905080828501555080612aa090615cea565b9050612a69565b6001600160a01b038316612ace57604051638163862760e01b815260040160405180910390fd5b6001600160a01b038216612af5576040516337c1c09d60e21b815260040160405180910390fd5b6001600160a01b0383811660008181526011602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60e85460ff16156114e257604051637f66be1760e01b815260040160405180910390fd5b6040513390600090612b9390839087906020016158e3565b60408051601f1981840301815291905280516020909101209050612bb78184612e61565b15612bd55760405163782a90fb60e11b815260040160405180910390fd5b612c1281858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612a6692505050565b816001600160a01b03167f770ea40a13a4644573ed785e5c7116890709947918747febc5add46feb531e2d8686866040516120ed93929190615c2e565b6000612c59612b57565b6000612c66858585613026565b9050612c74868686846131c7565b5060019695505050505050565b6000807f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575856001600160a01b031663289b3c0d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ce2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d069190615d03565b604051638369a0f160e01b81529091506001600160a01b03821690638369a0f190612d79907f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575859030907f9f60ae461adf056670e03ae602566409933242392cb06744f5747c9f38b05d0990600401615c82565b602060405180830381865afa158015612d96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dba9190615d03565b91505090565b60006001600160ff1b03821115612e2a5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b606482015260840161135a565b5090565b816001600160a01b0316836001600160a01b0316600080516020615f6383398151915283604051612b4a91815260200190565b6000805b82811015612e9357838101548015612e8257600192505050610bd3565b50612e8c81615cea565b9050612e65565b5060009392505050565b60005b81811015610e4457600083820155612eb781615cea565b9050612ea0565b6117588133613f66565b612ed28282613fbf565b600082815260b660205260409020610e449082614045565b6000610be57f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f612f1a61011a5490565b61011b546040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b612f71828261405a565b600082815260b660205260409020610e4490826140c1565b612fa1600080516020615f2383398151915233611e63565b6114e25760405162461bcd60e51b815260206004820152600a6024820152693737ba103830bab9b2b960b11b604482015260640161135a565b612fe26140d6565b60e8805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405161301c9190615057565b60405180910390a1565b6000806000613036848787611410565b915091506000821180156130b957506101525460405163639e625760e11b81526001600160a01b039091169063c73cc4ae90613076903390600401615057565b602060405180830381865afa158015613093573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b791906157f8565b155b156131bd578015806130dc57506130cf86611b38565b6130d98386615a15565b11155b6131285760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682062616c616e636520746f2070617920545820666565604482015260640161135a565b6101505461314390879081906001600160a01b0316856131c7565b50604080516001600160a01b038089168252871660208201529081018590526060810183905281151560808201527f3eba86eb3c0ea121e35980d4acae6eb9f1cdf0bf7c0c08443798cfd6e5299de39060a00160405180910390a1806131b2576131ad8285615c6f565b6131b4565b835b9250505061116d565b5091949350505050565b60006001600160a01b0384166131f05760405163eecd6c9b60e01b815260040160405180910390fd5b6001600160a01b0383166132175760405163e219bd3960e01b815260040160405180910390fd5b306001600160a01b03841603613240576040516376b3022760e01b815260040160405180910390fd5b600033905061327181868686604051806020016040528060008152506040518060200160405280600081525061411f565b846001600160a01b0316866001600160a01b0316146133045761330485876114cd866040518060600160405280602d8152602001615f83602d9139601160008c6001600160a01b03166001600160a01b0316815260200190815260200160002060008d6001600160a01b03166001600160a01b0316815260200190815260200160002054613d909092919063ffffffff16565b50600195945050505050565b604051635260769b60e11b815260009084906001600160a01b0382169063a4c0ed369061334590339088908890600401615d20565b6020604051808303816000875af1158015613364573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061338891906157f8565b6133cf5760405162461bcd60e51b815260206004820152601860248201527710dbdb9d1c9858dd0811985b1b189858dac819985a5b195960421b604482015260640161135a565b506001949350505050565b6001600160a01b03851661340157604051630d24315760e01b815260040160405180910390fd5b61340b8585613a57565b61341b86600087878686896141be565b846001600160a01b0316866001600160a01b03167f2fe5be0146f74c5bce36c0b80911af6c7d86ff27e89d5cfa61fc681327954e5d86858560405161346293929190615d47565b60405180910390a36040518481526001600160a01b03861690600090600080516020615f63833981519152906020016117ee565b61349e612b57565b610eb0858585858561430d565b6040516329965a1d60e01b8152731820a4b7618bde71dce8cdc73aab6c95905fad24906329965a1d906135069084907fac7fbab5f54a3ca8194167523c6753bfeb96a445279294b6125b68cce2177054903090600401615d72565b600060405180830381600087803b15801561352057600080fd5b505af1158015613534573d6000803e3d6000fd5b50506040516329965a1d60e01b8152731820a4b7618bde71dce8cdc73aab6c95905fad2492506329965a1d91506135939084907faea199e31a596269b42cdafd93407f14436db6e4cad65417994c2eb37381e05a903090600401615d72565b600060405180830381600087803b1580156135ad57600080fd5b505af1158015610eb0573d6000803e3d6000fd5b6135cc600033611e63565b6114e25760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015260640161135a565b600061360e613865565b6001600160a01b0316036136645760405162461bcd60e51b815260206004820152601d60248201527f5555505350726f786961626c653a206e6f742075706772616461626c65000000604482015260640161135a565b806001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156136a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136c691906157c6565b6136ce611902565b146137275760405162461bcd60e51b815260206004820152602360248201527f5555505350726f786961626c653a206e6f7420636f6d70617469626c65206c6f60448201526267696360e81b606482015260840161135a565b6001600160a01b038116300361377b5760405162461bcd60e51b815260206004820152601960248201527805555505350726f786961626c653a2070726f7879206c6f6f7603c1b604482015260640161135a565b61379181600080516020615eb983398151915255565b7fe011bc04c286c344a8fcbb8de77f953da762c3e25d8cdea984147fc4168a5dcc6137ba611902565b604080519182526001600160a01b038416602083015201611fe4565b6060816001600160401b038111156137f0576137f0614f02565b604051908082528060200260200182016040528015613819578160200160208202803683370190505b50905060005b8281101561385e5760008185015490508083838151811061384257613842615ca6565b60209081029190910101525061385781615cea565b905061381f565b5092915050565b600080516020615eb98339815191525490565b6000613900837f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575856001600160a01b031663bbe4fd506040518163ffffffff1660e01b8152600401602060405180830381865afa1580156138dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0391906157c6565b5050905061390d82612dc0565b81121561392d5760405163043b37d160e21b815260040160405180910390fd5b61393682612dc0565b6001600160a01b0384166000908152600260205260409020546139599190615885565b6001600160a01b038416600090815260026020526040902055600354613980908390615c6f565b600355505050565b6000816001600160a01b0316836001600160a01b031614806139f757506001600160a01b038316600090815260018501602052604090205460ff1680156139f757506001600160a01b03808316600090815260038601602090815260408083209387168352929052205460ff16155b8061116a57506001600160a01b03808316600090815260028601602090815260408083209387168352929052205460ff1690509392505050565b613a39612b57565b6000613a46878787613026565b9050611a83888888848888886143c8565b613a6081612dc0565b6001600160a01b038316600090815260026020526040902054613a83919061585d565b6001600160a01b038316600090815260026020526040902055600354613aaa908290615a15565b6003555050565b6001600160a01b038216613ac457505050565b612e2e8282613a57565b6001600160a01b03163b151590565b600054610100900460ff166114e25760405162461bcd60e51b815260040161135a90615a5e565b600054610100900460ff16613b2b5760405162461bcd60e51b815260040161135a90615a5e565b60e8805460ff19169055565b600054610100900460ff16613b5e5760405162461bcd60e51b815260040161135a90615a5e565b613b8181604051806040016040528060018152602001603160f81b81525061446a565b611758816144ad565b610e2d8282612ec8565b601680546001600160a01b038087166001600160a01b03199283168117909355601780548783169084161790556018805486831690841617905560198054918516919092161790556040517fcf554eb342edf010a94e07701ae91e99e90b769f649f03aeb1153654ddd43c0190600090a26017546040516001600160a01b03909116907f8837af285f4d380af9227df9ebafa13d992b487fa6d7a4366bd4154576085b8990600090a250505050565b613c4b6144fc565b60e8805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861300f3390565b600061116d8383614542565b806001600160a01b0316826001600160a01b031603613d035760405162461bcd60e51b815260206004820152602d60248201527f4552433737374f70657261746f72733a20617574686f72697a696e672073656c60448201526c331030b99037b832b930ba37b960991b606482015260840161135a565b6001600160a01b038116600090815260018401602052604090205460ff1615613d59576001600160a01b03918216600090815260039390930160209081526040808520929093168452529020805460ff19169055565b6001600160a01b0380831660009081526002850160209081526040808320938516835292905220805460ff19166001179055505050565b60008184841115613db45760405162461bcd60e51b815260040161135a9190614d3f565b505050900390565b6000610bd3825490565b6001600160a01b038116600090815261014e60205260408120805491829190613dee83615cea565b9190505550919050565b6000610bd3613e05612eea565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b6000806000613e578787878761456c565b91509150613e6481614626565b5095945050505050565b336001600160a01b03821603613ed95760405162461bcd60e51b815260206004820152602a60248201527f4552433737374f70657261746f72733a207265766f6b696e672073656c662061604482015269399037b832b930ba37b960b11b606482015260840161135a565b6001600160a01b038116600090815260018401602052604090205460ff1615613f33576001600160a01b0380831660009081526003850160209081526040808320938516835292905220805460ff19166001179055505050565b6001600160a01b03918216600090815260029390930160209081526040808520929093168452529020805460ff19169055565b613f708282611e63565b610e2d57613f7d8161476b565b613f8883602061477d565b604051602001613f99929190615d95565b60408051601f198184030181529082905262461bcd60e51b825261135a91600401614d3f565b613fc98282611e63565b610e2d5760008281526084602090815260408083206001600160a01b03851684529091529020805460ff191660011790556140013390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600061116d836001600160a01b038416614918565b6140648282611e63565b15610e2d5760008281526084602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600061116d836001600160a01b038416614967565b60e85460ff166114e25760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161135a565b614132858561412d86612dc0565b614a5a565b836001600160a01b0316856001600160a01b0316876001600160a01b03167f06b541ddaa720db2b10a4d0cdac39b8d360425fc073085fac19bc8261467798786868660405161418393929190615d47565b60405180910390a4836001600160a01b0316856001600160a01b0316600080516020615f63833981519152856040516117ee91815260200190565b60405163555ddc6560e11b8152600090731820a4b7618bde71dce8cdc73aab6c95905fad249063aabbb8ca9061421a9089907fb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b906004016157df565b602060405180830381865afa158015614237573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061425b9190615d03565b90506001600160a01b038116156142d7576040516223de2960e01b81526001600160a01b038216906223de29906142a0908b908b908b908b908b908b90600401615e04565b600060405180830381600087803b1580156142ba57600080fd5b505af11580156142ce573d6000803e3d6000fd5b50505050611a83565b8115611a83576142ef866001600160a01b0316613ace565b15611a835760405163fe737d0560e01b815260040160405180910390fd5b6001600160a01b03841661433457604051632e8aac6160e21b815260040160405180910390fd5b61434385856000868686614b59565b61434d8484613878565b836001600160a01b0316856001600160a01b03167fa78a9be3a7b862d26933ad85fb11d80ef66b8f972d7cbba06621d583943a409885858560405161439493929190615d47565b60405180910390a36040518381526000906001600160a01b03861690600080516020615f6383398151915290602001610d21565b6001600160a01b0386166143ef5760405163eecd6c9b60e01b815260040160405180910390fd5b6001600160a01b0385166144165760405163e219bd3960e01b815260040160405180910390fd5b306001600160a01b0386160361443f576040516376b3022760e01b815260040160405180910390fd5b61444d878787878787614b59565b61445b87878787878761411f565b612980878787878787876141be565b600054610100900460ff166144915760405162461bcd60e51b815260040161135a90615a5e565b81516020928301208151919092012061011a9190915561011b55565b600054610100900460ff166144d45760405162461bcd60e51b815260040161135a90615a5e565b507f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c961014f55565b60e85460ff16156114e25760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161135a565b600082600001828154811061455957614559615ca6565b9060005260206000200154905092915050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115614599575060009050600361461d565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156145ed573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166146165760006001925092505061461d565b9150600090505b94509492505050565b600081600481111561463a5761463a615e5e565b036146425750565b600181600481111561465657614656615e5e565b0361469e5760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b604482015260640161135a565b60028160048111156146b2576146b2615e5e565b036146ff5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161135a565b600381600481111561471357614713615e5e565b036117585760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161135a565b6060610bd36001600160a01b03831660145b6060600061478c836002615e74565b614797906002615a15565b6001600160401b038111156147ae576147ae614f02565b6040519080825280601f01601f1916602001820160405280156147d8576020820181803683370190505b509050600360fc1b816000815181106147f3576147f3615ca6565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061482257614822615ca6565b60200101906001600160f81b031916908160001a9053506000614846846002615e74565b614851906001615a15565b90505b60018111156148c9576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061488557614885615ca6565b1a60f81b82828151811061489b5761489b615ca6565b60200101906001600160f81b031916908160001a90535060049490941c936148c281615e8b565b9050614854565b50831561116d5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640161135a565b600081815260018301602052604081205461495f57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610bd3565b506000610bd3565b60008181526001830160205260408120548015614a5057600061498b600183615c6f565b855490915060009061499f90600190615c6f565b9050818114614a045760008660000182815481106149bf576149bf615ca6565b90600052602060002001549050808760000184815481106149e2576149e2615ca6565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614a1557614a15615ea2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610bd3565b6000915050610bd3565b6000614abe847f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575856001600160a01b031663bbe4fd506040518163ffffffff1660e01b8152600401602060405180830381865afa1580156138dc573d6000803e3d6000fd5b5050905081811215614ae357604051632f4cb94160e01b815260040160405180910390fd5b6001600160a01b038416600090815260026020526040902054614b07908390615885565b6001600160a01b038086166000908152600260205260408082209390935590851681522054614b3790839061585d565b6001600160a01b03909316600090815260026020526040902092909255505050565b60405163555ddc6560e11b8152600090731820a4b7618bde71dce8cdc73aab6c95905fad249063aabbb8ca90614bb59089907f29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895906004016157df565b602060405180830381865afa158015614bd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bf69190615d03565b90506001600160a01b0381161561298057604051633ad5cbc160e11b81526001600160a01b038216906375ab978290614c3d908a908a908a908a908a908a90600401615e04565b600060405180830381600087803b158015614c5757600080fd5b505af1158015614c6b573d6000803e3d6000fd5b5050505050505050505050565b600060208284031215614c8a57600080fd5b81356001600160e01b03198116811461116d57600080fd5b6020808252825182820181905260009190848201906040850190845b81811015614ce35783516001600160a01b031683529284019291840191600101614cbe565b50909695505050505050565b60005b83811015614d0a578181015183820152602001614cf2565b50506000910152565b60008151808452614d2b816020860160208601614cef565b601f01601f19169290920160200192915050565b60208152600061116d6020830184614d13565b6001600160a01b038116811461175857600080fd5b8035614d7281614d52565b919050565b60008083601f840112614d8957600080fd5b5081356001600160401b03811115614da057600080fd5b6020830191508360208260051b8501011115614dbb57600080fd5b9250929050565b60008060008060608587031215614dd857600080fd5b8435614de381614d52565b93506020850135925060408501356001600160401b03811115614e0557600080fd5b614e1187828801614d77565b95989497509550505050565b60008060408385031215614e3057600080fd5b8235614e3b81614d52565b946020939093013593505050565b600060208284031215614e5b57600080fd5b813561116d81614d52565b600080600060408486031215614e7b57600080fd5b8335925060208401356001600160401b03811115614e9857600080fd5b614ea486828701614d77565b9497909650939450505050565b60008060008060808587031215614ec757600080fd5b8435614ed281614d52565b93506020850135614ee281614d52565b92506040850135614ef281614d52565b9396929550929360600135925050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614f4057614f40614f02565b604052919050565b600082601f830112614f5957600080fd5b81356001600160401b03811115614f7257614f72614f02565b614f85601f8201601f1916602001614f18565b818152846020838601011115614f9a57600080fd5b816020850160208301376000918101602001919091529392505050565b801515811461175857600080fd5b600080600080600080600060e0888a031215614fe057600080fd5b8735965060208801356001600160401b03811115614ffd57600080fd5b6150098a828b01614f48565b965050604088013561501a81614d52565b9450606088013561502a81614fb7565b9350608088013561503a81614d52565b9699959850939692959460a0840135945060c09093013592915050565b6001600160a01b0391909116815260200190565b60008060006060848603121561508057600080fd5b833561508b81614d52565b9250602084013561509b81614d52565b929592945050506040919091013590565b6000602082840312156150be57600080fd5b5035919050565b600080604083850312156150d857600080fd5b50508035926020909101359150565b600080604083850312156150fa57600080fd5b82359150602083013561510c81614d52565b809150509250929050565b60008060006060848603121561512c57600080fd5b83359250602084013561513e81614d52565b9150604084013561514e81614d52565b809150509250925092565b60008083601f84011261516b57600080fd5b5081356001600160401b0381111561518257600080fd5b602083019150836020828501011115614dbb57600080fd5b600080600080606085870312156151b057600080fd5b84356151bb81614d52565b93506020850135925060408501356001600160401b038111156151dd57600080fd5b614e1187828801615159565b803560ff81168114614d7257600080fd5b6000806000806000806080878903121561521357600080fd5b863561521e81614d52565b955061522c602088016151e9565b945060408701356001600160401b038082111561524857600080fd5b6152548a838b01615159565b9096509450606089013591508082111561526d57600080fd5b5061527a89828a01615159565b979a9699509497509295939492505050565b600080600080608085870312156152a257600080fd5b84356152ad81614d52565b935060208501356152bd81614d52565b93969395505050506040820135916060013590565b6020808252825182820181905260009190848201906040850190845b81811015614ce3578351835292840192918401916001016152ee565b600080600080600080600060a0888a03121561532557600080fd5b873561533081614d52565b9650602088013561534081614d52565b95506040880135945060608801356001600160401b038082111561536357600080fd5b61536f8b838c01615159565b909650945060808a013591508082111561538857600080fd5b506153958a828b01615159565b989b979a50959850939692959293505050565b600080600080600080600080610100898b0312156153c557600080fd5b88356153d081614d52565b975060208901356153e081614d52565b965060408901356153f081614d52565b9550606089013561540081614d52565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b60008060006060848603121561543d57600080fd5b833561544881614d52565b95602085013595506040909401359392505050565b60008060008060008060008060008060006101208c8e03121561547f57600080fd5b6001600160401b038c3581101561549557600080fd5b6154a28e8e358f01615159565b909c509a5060208d01358110156154b857600080fd5b506154c98d60208e01358e01615159565b909950975060408c0135965060608c01356154e381614d52565b955060808c01356154f381614d52565b945061550160a08d01614d67565b935061550f60c08d01614d67565b925061551d60e08d01614d67565b915061552c6101008d01614d67565b90509295989b509295989b9093969950565b6000806000806080858703121561555457600080fd5b843561555f81614d52565b9350602085013561556f81614d52565b9250604085013561557f81614d52565b9150606085013561558f81614d52565b939692955090935050565b6000602082840312156155ac57600080fd5b813561116d81614fb7565b600080600080608085870312156155cd57600080fd5b84356155d881614d52565b935060208501356155e881614d52565b92506040850135915060608501356001600160401b0381111561560a57600080fd5b61561687828801614f48565b91505092959194509250565b600080600080600080600060e0888a03121561563d57600080fd5b873561564881614d52565b9650602088013561565881614d52565b95506040880135945060608801359350615674608089016151e9565b925060a0880135915060c0880135905092959891949750929550565b600080604083850312156156a357600080fd5b82356156ae81614d52565b9150602083013561510c81614d52565b600080600080600080608087890312156156d757600080fd5b86356156e281614d52565b95506020870135945060408701356001600160401b038082111561524857600080fd5b60008060006040848603121561571a57600080fd5b8335925060208401356001600160401b0381111561573757600080fd5b614ea486828701615159565b600181811c9082168061575757607f821691505b60208210810361577757634e487b7160e01b600052602260045260246000fd5b50919050565b6080808252600e908201526d41677265656d656e74537461746560901b60a08201526001600160a01b039384166020820152919092166040820152606081019190915260c00190565b6000602082840312156157d857600080fd5b5051919050565b6001600160a01b03929092168252602082015260400190565b60006020828403121561580a57600080fd5b815161116d81614fb7565b634e487b7160e01b600052601160045260246000fd5b6000600160ff1b820161584057615840615815565b5060000390565b634e487b7160e01b600052600160045260246000fd5b808201828112600083128015821682158216171561587d5761587d615815565b505092915050565b818103600083128015838313168383128216171561385e5761385e615815565b85815260018060a01b038516602082015283604082015282606082015260a0608082015260006158d860a0830184614d13565b979650505050505050565b6060808252600d908201526c41677265656d656e744461746160981b60808201526001600160a01b03929092166020830152604082015260a00190565b6000602080838503121561593357600080fd5b82516001600160401b038082111561594a57600080fd5b818501915085601f83011261595e57600080fd5b81518181111561597057615970614f02565b8060051b9150615981848301614f18565b818152918301840191848101908884111561599b57600080fd5b938501935b838510156159c557845192506159b583614d52565b82825293850193908501906159a0565b98975050505050505050565b9283526001600160a01b03918216602084015216604082015260600190565b60008060408385031215615a0357600080fd5b82519150602083015161510c81614fb7565b80820180821115610bd357610bd3615815565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b601f821115610e4457600081815260208120601f850160051c81016020861015615ad05750805b601f850160051c820191505b81811015615aef57828155600101615adc565b505050505050565b6001600160401b03831115615b0e57615b0e614f02565b615b2283615b1c8354615743565b83615aa9565b6000601f841160018114615b565760008515615b3e5750838201355b600019600387901b1c1916600186901b178355610eb0565b600083815260209020601f19861690835b82811015615b875786850135825560209485019460019092019101615b67565b5086821015615ba45760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60208082526010908201526f13db9b1e4815934818d85b8818d85b1b60821b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b838152604060208201819052810182905260006001600160fb1b03831115615c5557600080fd5b8260051b8085606085013791909101606001949350505050565b81810381811115610bd357610bd3615815565b6001600160a01b039384168152919092166020820152604081019190915260600190565b634e487b7160e01b600052603260045260246000fd5b600080600060608486031215615cd157600080fd5b8351925060208401519150604084015190509250925092565b600060018201615cfc57615cfc615815565b5060010190565b600060208284031215615d1557600080fd5b815161116d81614d52565b60018060a01b0384168152826020820152606060408201526000611b2f6060830184614d13565b838152606060208201526000615d606060830185614d13565b82810360408401526115eb8185614d13565b6001600160a01b0393841681526020810192909252909116604082015260600190565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b815260008351615dc7816017850160208801614cef565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615df8816028840160208801614cef565b01602801949350505050565b6001600160a01b0387811682528681166020830152851660408201526060810184905260c060808201819052600090615e3f90830185614d13565b82810360a0840152615e518185614d13565b9998505050505050505050565b634e487b7160e01b600052602160045260246000fd5b8082028115828204841417610bd357610bd3615815565b600081615e9a57615e9a615815565b506000190190565b634e487b7160e01b600052603160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5375706572546f6b656e3a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249865d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5375706572546f6b656e3a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365a2646970667358221220caac6dc494232b454d2de2240ef7f3edd496c7af33e64f3f0cb49a2a1d3e8dee64736f6c63430008130033