ETH Price: $2,509.54 (-3.07%)

Transaction Decoder

Block:
14653941 at Apr-25-2022 01:01:11 PM +UTC
Transaction Fee:
0.005504937618000462 ETH $13.81
Gas Used:
147,669 Gas / 37.278898198 Gwei

Emitted Events:

56 LEAG.Transfer( from=CommunityVault, to=[Receiver] Rewards, value=46490079365079360000000 )
57 LEAG.Approval( owner=CommunityVault, spender=[Receiver] Rewards, value=43714215277777817400000000 )
58 LEAG.Transfer( from=[Receiver] Rewards, to=[Sender] 0x06df6fbebc2866403036878990ee52faf50a8f87, value=60569022163421187886459 )
59 Rewards.Claim( user=[Sender] 0x06df6fbebc2866403036878990ee52faf50a8f87, amount=60569022163421187886459 )

Account State Difference:

  Address   Before After State Difference Code
0x06df6FbE...Af50a8F87
7.835074779469693098 Eth
Nonce: 112
7.829569841851692636 Eth
Nonce: 113
0.005504937618000462
(Hiveon Pool)
13,214.16466630550140618 Eth13,214.16479173336598167 Eth0.00012542786457549
0x53986D9a...A94e4B04b
0x7b39917f...1375D505D

Execution Trace

Rewards.CALL( )
  • LEAG.transferFrom( sender=0x0f8039283F1E02bF65D174493FF3d173C7D82e8F, recipient=0x53986D9ab11E53d491840007B3935d8A94e4B04b, amount=46490079365079360000000 ) => ( True )
  • LEAG.balanceOf( account=0x53986D9ab11E53d491840007B3935d8A94e4B04b ) => ( 4903461153351733182814443 )
  • Kernel.STATICCALL( )
    • KernelFacet.DELEGATECALL( )
    • Kernel.70a08231( )
      • KernelFacet.balanceOf( user=0x06df6FbEbC2866403036878990Ee52FAf50a8F87 ) => ( 11760923216675328416920134 )
      • LEAG.transfer( recipient=0x06df6FbEbC2866403036878990Ee52FAf50a8F87, amount=60569022163421187886459 ) => ( True )
      • LEAG.balanceOf( account=0x53986D9ab11E53d491840007B3935d8A94e4B04b ) => ( 4842892131188311994927984 )
        File 1 of 5: Rewards
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        import "@openzeppelin/contracts/access/Ownable.sol";
        import "@openzeppelin/contracts/math/SafeMath.sol";
        import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
        import "./interfaces/IKernel.sol";
        contract Rewards is Ownable {
            using SafeMath for uint256;
            uint256 constant decimals = 10 ** 18;
            struct Pull {
                address source;
                uint256 startTs;
                uint256 endTs;
                uint256 totalDuration;
                uint256 totalAmount;
            }
            Pull public pullFeature;
            bool public disabled;
            uint256 public lastPullTs;
            uint256 public balanceBefore;
            uint256 public currentMultiplier;
            mapping(address => uint256) public userMultiplier;
            mapping(address => uint256) public owed;
            IKernel public kernel;
            IERC20 public rewardToken;
            event Claim(address indexed user, uint256 amount);
            constructor(address _owner, address _token, address _kernel) {
                require(_token != address(0), "reward token must not be 0x0");
                require(_kernel != address(0), "kernel address must not be 0x0");
                transferOwnership(_owner);
                rewardToken = IERC20(_token);
                kernel = IKernel(_kernel);
            }
            // registerUserAction is called by the Kernel every time the user does a deposit or withdrawal in order to
            // account for the changes in reward that the user should get
            // it updates the amount owed to the user without transferring the funds
            function registerUserAction(address user) public {
                require(msg.sender == address(kernel), 'only callable by kernel');
                _calculateOwed(user);
            }
            // claim calculates the currently owed reward and transfers the funds to the user
            function claim() public returns (uint256){
                _calculateOwed(msg.sender);
                uint256 amount = owed[msg.sender];
                require(amount > 0, "nothing to claim");
                owed[msg.sender] = 0;
                rewardToken.transfer(msg.sender, amount);
                // acknowledge the amount that was transferred to the user
                ackFunds();
                emit Claim(msg.sender, amount);
                return amount;
            }
            // ackFunds checks the difference between the last known balance of `token` and the current one
            // if it goes up, the multiplier is re-calculated
            // if it goes down, it only updates the known balance
            function ackFunds() public {
                uint256 balanceNow = rewardToken.balanceOf(address(this));
                if (balanceNow == 0 || balanceNow <= balanceBefore) {
                    balanceBefore = balanceNow;
                    return;
                }
                uint256 totalStakedLeag = kernel.leagStaked();
                // if there's no leag staked, it doesn't make sense to ackFunds because there's nobody to distribute them to
                // and the calculation would fail anyways due to division by 0
                if (totalStakedLeag == 0) {
                    return;
                }
                uint256 diff = balanceNow.sub(balanceBefore);
                uint256 multiplier = currentMultiplier.add(diff.mul(decimals).div(totalStakedLeag));
                balanceBefore = balanceNow;
                currentMultiplier = multiplier;
            }
            // setupPullToken is used to setup the rewards system; only callable by contract owner
            // set source to address(0) to disable the functionality
            function setupPullToken(address source, uint256 startTs, uint256 endTs, uint256 amount) public {
                require(msg.sender == owner(), "!owner");
                require(!disabled, "contract is disabled");
                if (pullFeature.source != address(0)) {
                    require(source == address(0), "contract is already set up, source must be 0x0");
                    disabled = true;
                } else {
                    require(source != address(0), "contract is not setup, source must be != 0x0");
                }
                if (source == address(0)) {
                    require(startTs == 0, "disable contract: startTs must be 0");
                    require(endTs == 0, "disable contract: endTs must be 0");
                    require(amount == 0, "disable contract: amount must be 0");
                } else {
                    require(endTs > startTs, "setup contract: endTs must be greater than startTs");
                    require(amount > 0, "setup contract: amount must be greater than 0");
                }
                pullFeature.source = source;
                pullFeature.startTs = startTs;
                pullFeature.endTs = endTs;
                pullFeature.totalDuration = endTs.sub(startTs);
                pullFeature.totalAmount = amount;
                if (lastPullTs < startTs) {
                    lastPullTs = startTs;
                }
            }
            // setKernel sets the address of the LeagueDao Kernel into the state variable
            function setKernel(address _kernel) public {
                require(_kernel != address(0), 'kernel address must not be 0x0');
                require(msg.sender == owner(), '!owner');
                kernel = IKernel(_kernel);
            }
            // _pullToken calculates the amount based on the time passed since the last pull relative
            // to the total amount of time that the pull functionality is active and executes a transferFrom from the
            // address supplied as `pullTokenFrom`, if enabled
            function _pullToken() internal {
                if (
                    pullFeature.source == address(0) ||
                    block.timestamp < pullFeature.startTs
                ) {
                    return;
                }
                uint256 timestampCap = pullFeature.endTs;
                if (block.timestamp < pullFeature.endTs) {
                    timestampCap = block.timestamp;
                }
                if (lastPullTs >= timestampCap) {
                    return;
                }
                uint256 timeSinceLastPull = timestampCap.sub(lastPullTs);
                uint256 shareToPull = timeSinceLastPull.mul(decimals).div(pullFeature.totalDuration);
                uint256 amountToPull = pullFeature.totalAmount.mul(shareToPull).div(decimals);
                lastPullTs = block.timestamp;
                rewardToken.transferFrom(pullFeature.source, address(this), amountToPull);
            }
            // _calculateOwed calculates and updates the total amount that is owed to an user and updates the user's multiplier
            // to the current value
            // it automatically attempts to pull the token from the source and acknowledge the funds
            function _calculateOwed(address user) internal {
                _pullToken();
                ackFunds();
                uint256 reward = _userPendingReward(user);
                owed[user] = owed[user].add(reward);
                userMultiplier[user] = currentMultiplier;
            }
            // _userPendingReward calculates the reward that should be based on the current multiplier / anything that's not included in the `owed[user]` value
            // it does not represent the entire reward that's due to the user unless added on top of `owed[user]`
            function _userPendingReward(address user) internal view returns (uint256) {
                uint256 multiplier = currentMultiplier.sub(userMultiplier[user]);
                return kernel.balanceOf(user).mul(multiplier).div(decimals);
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.6.0 <0.8.0;
        import "../utils/Context.sol";
        /**
         * @dev Contract module which provides a basic access control mechanism, where
         * there is an account (an owner) that can be granted exclusive access to
         * specific functions.
         *
         * By default, the owner account will be the one that deploys the contract. This
         * can later be changed with {transferOwnership}.
         *
         * This module is used through inheritance. It will make available the modifier
         * `onlyOwner`, which can be applied to your functions to restrict their use to
         * the owner.
         */
        abstract contract Ownable is Context {
            address private _owner;
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            /**
             * @dev Initializes the contract setting the deployer as the initial owner.
             */
            constructor () internal {
                address msgSender = _msgSender();
                _owner = msgSender;
                emit OwnershipTransferred(address(0), msgSender);
            }
            /**
             * @dev Returns the address of the current owner.
             */
            function owner() public view virtual returns (address) {
                return _owner;
            }
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner() {
                require(owner() == _msgSender(), "Ownable: caller is not the owner");
                _;
            }
            /**
             * @dev Leaves the contract without owner. It will not be possible to call
             * `onlyOwner` functions anymore. Can only be called by the current owner.
             *
             * NOTE: Renouncing ownership will leave the contract without an owner,
             * thereby removing any functionality that is only available to the owner.
             */
            function renounceOwnership() public virtual onlyOwner {
                emit OwnershipTransferred(_owner, address(0));
                _owner = address(0);
            }
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             * Can only be called by the current owner.
             */
            function transferOwnership(address newOwner) public virtual onlyOwner {
                require(newOwner != address(0), "Ownable: new owner is the zero address");
                emit OwnershipTransferred(_owner, newOwner);
                _owner = newOwner;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.6.0 <0.8.0;
        /**
         * @dev Wrappers over Solidity's arithmetic operations with added overflow
         * checks.
         *
         * Arithmetic operations in Solidity wrap on overflow. This can easily result
         * in bugs, because programmers usually assume that an overflow raises an
         * error, which is the standard behavior in high level programming languages.
         * `SafeMath` restores this intuition by reverting the transaction when 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.
         */
        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) {
                uint256 c = a + b;
                if (c < a) return (false, 0);
                return (true, c);
            }
            /**
             * @dev Returns the substraction of two unsigned integers, with an overflow flag.
             *
             * _Available since v3.4._
             */
            function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                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) {
                // 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) {
                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) {
                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) {
                uint256 c = a + b;
                require(c >= a, "SafeMath: addition overflow");
                return c;
            }
            /**
             * @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) {
                require(b <= a, "SafeMath: subtraction overflow");
                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) {
                if (a == 0) return 0;
                uint256 c = a * b;
                require(c / a == b, "SafeMath: multiplication overflow");
                return c;
            }
            /**
             * @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. 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) internal pure returns (uint256) {
                require(b > 0, "SafeMath: division by zero");
                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) {
                require(b > 0, "SafeMath: modulo by zero");
                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) {
                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.
             *
             * CAUTION: This function is deprecated because it requires allocating memory for the error
             * message unnecessarily. For custom revert reasons use {tryDiv}.
             *
             * 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) {
                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) {
                require(b > 0, errorMessage);
                return a % b;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.6.0 <0.8.0;
        /**
         * @dev Interface of the ERC20 standard as defined in the EIP.
         */
        interface IERC20 {
            /**
             * @dev Returns the amount of tokens in existence.
             */
            function totalSupply() external view returns (uint256);
            /**
             * @dev Returns the amount of tokens owned by `account`.
             */
            function balanceOf(address account) external view returns (uint256);
            /**
             * @dev Moves `amount` tokens from the caller's account to `recipient`.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transfer(address recipient, uint256 amount) external returns (bool);
            /**
             * @dev Returns the remaining number of tokens that `spender` will be
             * allowed to spend on behalf of `owner` through {transferFrom}. This is
             * zero by default.
             *
             * This value changes when {approve} or {transferFrom} are called.
             */
            function allowance(address owner, address spender) external view returns (uint256);
            /**
             * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * IMPORTANT: Beware that changing an allowance with this method brings the risk
             * that someone may use both the old and the new allowance by unfortunate
             * transaction ordering. One possible solution to mitigate this race
             * condition is to first reduce the spender's allowance to 0 and set the
             * desired value afterwards:
             * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
             *
             * Emits an {Approval} event.
             */
            function approve(address spender, uint256 amount) external returns (bool);
            /**
             * @dev Moves `amount` tokens from `sender` to `recipient` using the
             * allowance mechanism. `amount` is then deducted from the caller's
             * allowance.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
            /**
             * @dev Emitted when `value` tokens are moved from one account (`from`) to
             * another (`to`).
             *
             * Note that `value` may be zero.
             */
            event Transfer(address indexed from, address indexed to, uint256 value);
            /**
             * @dev Emitted when the allowance of a `spender` for an `owner` is set by
             * a call to {approve}. `value` is the new allowance.
             */
            event Approval(address indexed owner, address indexed spender, uint256 value);
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        import "../libraries/LibKernelStorage.sol";
        interface IKernel {
            // deposit allows a user to add more leag to his staked balance
            function deposit(uint256 amount) external;
            // withdraw allows a user to withdraw funds if the balance is not locked
            function withdraw(uint256 amount) external;
            // lock a user's currently staked balance until timestamp & add the bonus to his voting power
            function lock(uint256 timestamp) external;
            // delegate allows a user to delegate his voting power to another user
            function delegate(address to) external;
            // stopDelegate allows a user to take back the delegated voting power
            function stopDelegate() external;
            // lock the balance of a proposal creator until the voting ends; only callable by DAO
            function lockCreatorBalance(address user, uint256 timestamp) external;
            // balanceOf returns the current LEAG balance of a user (bonus not included)
            function balanceOf(address user) external view returns (uint256);
            // balanceAtTs returns the amount of LEAG that the user currently staked (bonus NOT included)
            function balanceAtTs(address user, uint256 timestamp) external view returns (uint256);
            // stakeAtTs returns the Stake object of the user that was valid at `timestamp`
            function stakeAtTs(address user, uint256 timestamp) external view returns (LibKernelStorage.Stake memory);
            // votingPower returns the voting power (bonus included) + delegated voting power for a user at the current block
            function votingPower(address user) external view returns (uint256);
            // votingPowerAtTs returns the voting power (bonus included) + delegated voting power for a user at a point in time
            function votingPowerAtTs(address user, uint256 timestamp) external view returns (uint256);
            // leagStaked returns the total raw amount of LEAG staked at the current block
            function leagStaked() external view returns (uint256);
            // leagStakedAtTs returns the total raw amount of LEAG users have deposited into the contract
            // it does not include any bonus
            function leagStakedAtTs(uint256 timestamp) external view returns (uint256);
            // delegatedPower returns the total voting power that a user received from other users
            function delegatedPower(address user) external view returns (uint256);
            // delegatedPowerAtTs returns the total voting power that a user received from other users at a point in time
            function delegatedPowerAtTs(address user, uint256 timestamp) external view returns (uint256);
            // multiplierAtTs calculates the multiplier at a given timestamp based on the user's stake a the given timestamp
            // it includes the decay mechanism
            function multiplierAtTs(address user, uint256 timestamp) external view returns (uint256);
            // userLockedUntil returns the timestamp until the user's balance is locked
            function userLockedUntil(address user) external view returns (uint256);
            // userDidDelegate returns the address to which a user delegated their voting power; address(0) if not delegated
            function userDelegatedTo(address user) external view returns (address);
            
        }
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.6.0 <0.8.0;
        /*
         * @dev Provides information about the current execution context, including the
         * sender of the transaction and its data. While these are generally available
         * via msg.sender and msg.data, they should not be accessed in such a direct
         * manner, since when dealing with GSN meta-transactions the account sending and
         * paying for execution may not be the actual sender (as far as an application
         * is concerned).
         *
         * This contract is only required for intermediate, library-like contracts.
         */
        abstract contract Context {
            function _msgSender() internal view virtual returns (address payable) {
                return msg.sender;
            }
            function _msgData() internal view virtual returns (bytes memory) {
                this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                return msg.data;
            }
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
        import "../interfaces/IRewards.sol";
        library LibKernelStorage {
            bytes32 constant STORAGE_POSITION = keccak256("com.enterdao.kernel.storage");
            struct Checkpoint {
                uint256 timestamp;
                uint256 amount;
            }
            struct Stake {
                uint256 timestamp;
                uint256 amount;
                uint256 expiryTimestamp;
                address delegatedTo;
            }
            struct Storage {
                bool initialized;
                // mapping of user address to history of Stake objects
                // every user action creates a new object in the history
                mapping(address => Stake[]) userStakeHistory;
                // array of leag staked Checkpoint
                // deposits/withdrawals create a new object in the history (max one per block)
                Checkpoint[] leagStakedHistory;
                // mapping of user address to history of delegated power
                // every delegate/stopDelegate call create a new checkpoint (max one per block)
                mapping(address => Checkpoint[]) delegatedPowerHistory;
                IERC20 leag;
                IRewards rewards;
            }
            function kernelStorage() internal pure returns (Storage storage ds) {
                bytes32 position = STORAGE_POSITION;
                assembly {
                    ds.slot := position
                }
            }
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        interface IRewards {
            function registerUserAction(address user) external;
        }
        

        File 2 of 5: CommunityVault
        pragma solidity ^0.6.0;
        import "@openzeppelin/contracts/access/Ownable.sol";
        import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
        contract CommunityVault is Ownable {
            IERC20 private _entr;
            constructor (address entr) public {
                _entr = IERC20(entr);
            }
            event SetAllowance(address indexed caller, address indexed spender, uint256 amount);
            function setAllowance(address spender, uint amount) public onlyOwner {
                _entr.approve(spender, amount);
                emit SetAllowance(msg.sender, spender, amount);
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.6.0;
        import "../GSN/Context.sol";
        /**
         * @dev Contract module which provides a basic access control mechanism, where
         * there is an account (an owner) that can be granted exclusive access to
         * specific functions.
         *
         * By default, the owner account will be the one that deploys the contract. This
         * can later be changed with {transferOwnership}.
         *
         * This module is used through inheritance. It will make available the modifier
         * `onlyOwner`, which can be applied to your functions to restrict their use to
         * the owner.
         */
        contract Ownable is Context {
            address private _owner;
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            /**
             * @dev Initializes the contract setting the deployer as the initial owner.
             */
            constructor () internal {
                address msgSender = _msgSender();
                _owner = msgSender;
                emit OwnershipTransferred(address(0), msgSender);
            }
            /**
             * @dev Returns the address of the current owner.
             */
            function owner() public view returns (address) {
                return _owner;
            }
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner() {
                require(_owner == _msgSender(), "Ownable: caller is not the owner");
                _;
            }
            /**
             * @dev Leaves the contract without owner. It will not be possible to call
             * `onlyOwner` functions anymore. Can only be called by the current owner.
             *
             * NOTE: Renouncing ownership will leave the contract without an owner,
             * thereby removing any functionality that is only available to the owner.
             */
            function renounceOwnership() public virtual onlyOwner {
                emit OwnershipTransferred(_owner, address(0));
                _owner = address(0);
            }
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             * Can only be called by the current owner.
             */
            function transferOwnership(address newOwner) public virtual onlyOwner {
                require(newOwner != address(0), "Ownable: new owner is the zero address");
                emit OwnershipTransferred(_owner, newOwner);
                _owner = newOwner;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.6.0;
        /**
         * @dev Interface of the ERC20 standard as defined in the EIP.
         */
        interface IERC20 {
            /**
             * @dev Returns the amount of tokens in existence.
             */
            function totalSupply() external view returns (uint256);
            /**
             * @dev Returns the amount of tokens owned by `account`.
             */
            function balanceOf(address account) external view returns (uint256);
            /**
             * @dev Moves `amount` tokens from the caller's account to `recipient`.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transfer(address recipient, uint256 amount) external returns (bool);
            /**
             * @dev Returns the remaining number of tokens that `spender` will be
             * allowed to spend on behalf of `owner` through {transferFrom}. This is
             * zero by default.
             *
             * This value changes when {approve} or {transferFrom} are called.
             */
            function allowance(address owner, address spender) external view returns (uint256);
            /**
             * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * IMPORTANT: Beware that changing an allowance with this method brings the risk
             * that someone may use both the old and the new allowance by unfortunate
             * transaction ordering. One possible solution to mitigate this race
             * condition is to first reduce the spender's allowance to 0 and set the
             * desired value afterwards:
             * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
             *
             * Emits an {Approval} event.
             */
            function approve(address spender, uint256 amount) external returns (bool);
            /**
             * @dev Moves `amount` tokens from `sender` to `recipient` using the
             * allowance mechanism. `amount` is then deducted from the caller's
             * allowance.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
            /**
             * @dev Emitted when `value` tokens are moved from one account (`from`) to
             * another (`to`).
             *
             * Note that `value` may be zero.
             */
            event Transfer(address indexed from, address indexed to, uint256 value);
            /**
             * @dev Emitted when the allowance of a `spender` for an `owner` is set by
             * a call to {approve}. `value` is the new allowance.
             */
            event Approval(address indexed owner, address indexed spender, uint256 value);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.6.0;
        /*
         * @dev Provides information about the current execution context, including the
         * sender of the transaction and its data. While these are generally available
         * via msg.sender and msg.data, they should not be accessed in such a direct
         * manner, since when dealing with GSN meta-transactions the account sending and
         * paying for execution may not be the actual sender (as far as an application
         * is concerned).
         *
         * This contract is only required for intermediate, library-like contracts.
         */
        abstract contract Context {
            function _msgSender() internal view virtual returns (address payable) {
                return msg.sender;
            }
            function _msgData() internal view virtual returns (bytes memory) {
                this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                return msg.data;
            }
        }
        

        File 3 of 5: LEAG
        //SPDX-License-Identifier: Unlicense
        pragma solidity ^0.8.0;
        import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
        import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
        import "@openzeppelin/contracts/access/Ownable.sol";
        contract LEAG is ERC20Burnable, ERC20Permit, Ownable {
            uint256 private constant SUPPLY = 1_000_000_000 * 10**18;
            constructor() ERC20("LeagueDAO Governance Token", "LEAG") ERC20Permit("LEAG") {
                _mint(msg.sender, SUPPLY);
            }
            function mint(address to, uint256 amount) public virtual onlyOwner {
                _mint(to, amount);
            }
        }// SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "../ERC20.sol";
        import "../../../utils/Context.sol";
        /**
         * @dev Extension of {ERC20} that allows token holders to destroy both their own
         * tokens and those that they have an allowance for, in a way that can be
         * recognized off-chain (via event analysis).
         */
        abstract contract ERC20Burnable is Context, ERC20 {
            /**
             * @dev Destroys `amount` tokens from the caller.
             *
             * See {ERC20-_burn}.
             */
            function burn(uint256 amount) public virtual {
                _burn(_msgSender(), amount);
            }
            /**
             * @dev Destroys `amount` tokens from `account`, deducting from the caller's
             * allowance.
             *
             * See {ERC20-_burn} and {ERC20-allowance}.
             *
             * Requirements:
             *
             * - the caller must have allowance for ``accounts``'s tokens of at least
             * `amount`.
             */
            function burnFrom(address account, uint256 amount) public virtual {
                uint256 currentAllowance = allowance(account, _msgSender());
                require(currentAllowance >= amount, "ERC20: burn amount exceeds allowance");
                unchecked {
                    _approve(account, _msgSender(), currentAllowance - amount);
                }
                _burn(account, amount);
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "./draft-IERC20Permit.sol";
        import "../ERC20.sol";
        import "../../../utils/cryptography/draft-EIP712.sol";
        import "../../../utils/cryptography/ECDSA.sol";
        import "../../../utils/Counters.sol";
        /**
         * @dev Implementation 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.
         *
         * _Available since v3.4._
         */
        abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
            using Counters for Counters.Counter;
            mapping(address => Counters.Counter) private _nonces;
            // solhint-disable-next-line var-name-mixedcase
            bytes32 private immutable _PERMIT_TYPEHASH =
                keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
            /**
             * @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.
             */
            constructor(string memory name) EIP712(name, "1") {}
            /**
             * @dev See {IERC20Permit-permit}.
             */
            function permit(
                address owner,
                address spender,
                uint256 value,
                uint256 deadline,
                uint8 v,
                bytes32 r,
                bytes32 s
            ) public virtual override {
                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 = ECDSA.recover(hash, v, r, s);
                require(signer == owner, "ERC20Permit: invalid signature");
                _approve(owner, spender, value);
            }
            /**
             * @dev See {IERC20Permit-nonces}.
             */
            function nonces(address owner) public view virtual override returns (uint256) {
                return _nonces[owner].current();
            }
            /**
             * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
             */
            // solhint-disable-next-line func-name-mixedcase
            function DOMAIN_SEPARATOR() external view override 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) {
                Counters.Counter storage nonce = _nonces[owner];
                current = nonce.current();
                nonce.increment();
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "../utils/Context.sol";
        /**
         * @dev Contract module which provides a basic access control mechanism, where
         * there is an account (an owner) that can be granted exclusive access to
         * specific functions.
         *
         * By default, the owner account will be the one that deploys the contract. This
         * can later be changed with {transferOwnership}.
         *
         * This module is used through inheritance. It will make available the modifier
         * `onlyOwner`, which can be applied to your functions to restrict their use to
         * the owner.
         */
        abstract contract Ownable is Context {
            address private _owner;
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            /**
             * @dev Initializes the contract setting the deployer as the initial owner.
             */
            constructor() {
                _setOwner(_msgSender());
            }
            /**
             * @dev Returns the address of the current owner.
             */
            function owner() public view virtual returns (address) {
                return _owner;
            }
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner() {
                require(owner() == _msgSender(), "Ownable: caller is not the owner");
                _;
            }
            /**
             * @dev Leaves the contract without owner. It will not be possible to call
             * `onlyOwner` functions anymore. Can only be called by the current owner.
             *
             * NOTE: Renouncing ownership will leave the contract without an owner,
             * thereby removing any functionality that is only available to the owner.
             */
            function renounceOwnership() public virtual onlyOwner {
                _setOwner(address(0));
            }
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             * Can only be called by the current owner.
             */
            function transferOwnership(address newOwner) public virtual onlyOwner {
                require(newOwner != address(0), "Ownable: new owner is the zero address");
                _setOwner(newOwner);
            }
            function _setOwner(address newOwner) private {
                address oldOwner = _owner;
                _owner = newOwner;
                emit OwnershipTransferred(oldOwner, newOwner);
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "./IERC20.sol";
        import "./extensions/IERC20Metadata.sol";
        import "../../utils/Context.sol";
        /**
         * @dev Implementation of the {IERC20} interface.
         *
         * This implementation is agnostic to the way tokens are created. This means
         * that a supply mechanism has to be added in a derived contract using {_mint}.
         * For a generic mechanism see {ERC20PresetMinterPauser}.
         *
         * TIP: For a detailed writeup see our guide
         * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
         * to implement supply mechanisms].
         *
         * We have followed general OpenZeppelin Contracts guidelines: functions revert
         * instead returning `false` on failure. This behavior is nonetheless
         * conventional and does not conflict with the expectations of ERC20
         * applications.
         *
         * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
         * This allows applications to reconstruct the allowance for all accounts just
         * by listening to said events. Other implementations of the EIP may not emit
         * these events, as it isn't required by the specification.
         *
         * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
         * functions have been added to mitigate the well-known issues around setting
         * allowances. See {IERC20-approve}.
         */
        contract ERC20 is Context, IERC20, IERC20Metadata {
            mapping(address => uint256) private _balances;
            mapping(address => mapping(address => uint256)) private _allowances;
            uint256 private _totalSupply;
            string private _name;
            string private _symbol;
            /**
             * @dev Sets the values for {name} and {symbol}.
             *
             * The default value of {decimals} is 18. To select a different value for
             * {decimals} you should overload it.
             *
             * All two of these values are immutable: they can only be set once during
             * construction.
             */
            constructor(string memory name_, string memory symbol_) {
                _name = name_;
                _symbol = symbol_;
            }
            /**
             * @dev Returns the name of the token.
             */
            function name() public view virtual override returns (string memory) {
                return _name;
            }
            /**
             * @dev Returns the symbol of the token, usually a shorter version of the
             * name.
             */
            function symbol() public view virtual override returns (string memory) {
                return _symbol;
            }
            /**
             * @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 this function is
             * overridden;
             *
             * 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() public view virtual override returns (uint8) {
                return 18;
            }
            /**
             * @dev See {IERC20-totalSupply}.
             */
            function totalSupply() public view virtual override returns (uint256) {
                return _totalSupply;
            }
            /**
             * @dev See {IERC20-balanceOf}.
             */
            function balanceOf(address account) public view virtual override returns (uint256) {
                return _balances[account];
            }
            /**
             * @dev See {IERC20-transfer}.
             *
             * Requirements:
             *
             * - `recipient` cannot be the zero address.
             * - the caller must have a balance of at least `amount`.
             */
            function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                _transfer(_msgSender(), recipient, amount);
                return true;
            }
            /**
             * @dev See {IERC20-allowance}.
             */
            function allowance(address owner, address spender) public view virtual override returns (uint256) {
                return _allowances[owner][spender];
            }
            /**
             * @dev See {IERC20-approve}.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             */
            function approve(address spender, uint256 amount) public virtual override returns (bool) {
                _approve(_msgSender(), spender, amount);
                return true;
            }
            /**
             * @dev See {IERC20-transferFrom}.
             *
             * Emits an {Approval} event indicating the updated allowance. This is not
             * required by the EIP. See the note at the beginning of {ERC20}.
             *
             * Requirements:
             *
             * - `sender` and `recipient` cannot be the zero address.
             * - `sender` must have a balance of at least `amount`.
             * - the caller must have allowance for ``sender``'s tokens of at least
             * `amount`.
             */
            function transferFrom(
                address sender,
                address recipient,
                uint256 amount
            ) public virtual override returns (bool) {
                _transfer(sender, recipient, amount);
                uint256 currentAllowance = _allowances[sender][_msgSender()];
                require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
                unchecked {
                    _approve(sender, _msgSender(), currentAllowance - amount);
                }
                return true;
            }
            /**
             * @dev Atomically increases the allowance granted to `spender` by the caller.
             *
             * This is an alternative to {approve} that can be used as a mitigation for
             * problems described in {IERC20-approve}.
             *
             * Emits an {Approval} event indicating the updated allowance.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             */
            function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
                return true;
            }
            /**
             * @dev Atomically decreases the allowance granted to `spender` by the caller.
             *
             * This is an alternative to {approve} that can be used as a mitigation for
             * problems described in {IERC20-approve}.
             *
             * Emits an {Approval} event indicating the updated allowance.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             * - `spender` must have allowance for the caller of at least
             * `subtractedValue`.
             */
            function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                uint256 currentAllowance = _allowances[_msgSender()][spender];
                require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
                unchecked {
                    _approve(_msgSender(), spender, currentAllowance - subtractedValue);
                }
                return true;
            }
            /**
             * @dev Moves `amount` of tokens from `sender` to `recipient`.
             *
             * This internal function is equivalent to {transfer}, and can be used to
             * e.g. implement automatic token fees, slashing mechanisms, etc.
             *
             * Emits a {Transfer} event.
             *
             * Requirements:
             *
             * - `sender` cannot be the zero address.
             * - `recipient` cannot be the zero address.
             * - `sender` must have a balance of at least `amount`.
             */
            function _transfer(
                address sender,
                address recipient,
                uint256 amount
            ) internal virtual {
                require(sender != address(0), "ERC20: transfer from the zero address");
                require(recipient != address(0), "ERC20: transfer to the zero address");
                _beforeTokenTransfer(sender, recipient, amount);
                uint256 senderBalance = _balances[sender];
                require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
                unchecked {
                    _balances[sender] = senderBalance - amount;
                }
                _balances[recipient] += amount;
                emit Transfer(sender, recipient, amount);
                _afterTokenTransfer(sender, recipient, amount);
            }
            /** @dev Creates `amount` tokens and assigns them to `account`, increasing
             * the total supply.
             *
             * Emits a {Transfer} event with `from` set to the zero address.
             *
             * Requirements:
             *
             * - `account` cannot be the zero address.
             */
            function _mint(address account, uint256 amount) internal virtual {
                require(account != address(0), "ERC20: mint to the zero address");
                _beforeTokenTransfer(address(0), account, amount);
                _totalSupply += amount;
                _balances[account] += amount;
                emit Transfer(address(0), account, amount);
                _afterTokenTransfer(address(0), account, amount);
            }
            /**
             * @dev Destroys `amount` tokens from `account`, reducing the
             * total supply.
             *
             * Emits a {Transfer} event with `to` set to the zero address.
             *
             * Requirements:
             *
             * - `account` cannot be the zero address.
             * - `account` must have at least `amount` tokens.
             */
            function _burn(address account, uint256 amount) internal virtual {
                require(account != address(0), "ERC20: burn from the zero address");
                _beforeTokenTransfer(account, address(0), amount);
                uint256 accountBalance = _balances[account];
                require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
                unchecked {
                    _balances[account] = accountBalance - amount;
                }
                _totalSupply -= amount;
                emit Transfer(account, address(0), amount);
                _afterTokenTransfer(account, address(0), amount);
            }
            /**
             * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
             *
             * This 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:
             *
             * - `owner` cannot be the zero address.
             * - `spender` cannot be the zero address.
             */
            function _approve(
                address owner,
                address spender,
                uint256 amount
            ) internal virtual {
                require(owner != address(0), "ERC20: approve from the zero address");
                require(spender != address(0), "ERC20: approve to the zero address");
                _allowances[owner][spender] = amount;
                emit Approval(owner, spender, amount);
            }
            /**
             * @dev Hook that is called before any transfer of tokens. This includes
             * minting and burning.
             *
             * Calling conditions:
             *
             * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
             * will be transferred to `to`.
             * - when `from` is zero, `amount` tokens will be minted for `to`.
             * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
             * - `from` and `to` are never both zero.
             *
             * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
             */
            function _beforeTokenTransfer(
                address from,
                address to,
                uint256 amount
            ) internal virtual {}
            /**
             * @dev Hook that is called after any transfer of tokens. This includes
             * minting and burning.
             *
             * Calling conditions:
             *
             * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
             * has been transferred to `to`.
             * - when `from` is zero, `amount` tokens have been minted for `to`.
             * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
             * - `from` and `to` are never both zero.
             *
             * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
             */
            function _afterTokenTransfer(
                address from,
                address to,
                uint256 amount
            ) internal virtual {}
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /**
         * @dev Provides information about the current execution context, including the
         * sender of the transaction and its data. While these are generally available
         * via msg.sender and msg.data, they should not be accessed in such a direct
         * manner, since when dealing with meta-transactions the account sending and
         * paying for execution may not be the actual sender (as far as an application
         * is concerned).
         *
         * This contract is only required for intermediate, library-like contracts.
         */
        abstract contract Context {
            function _msgSender() internal view virtual returns (address) {
                return msg.sender;
            }
            function _msgData() internal view virtual returns (bytes calldata) {
                return msg.data;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /**
         * @dev Interface of the ERC20 standard as defined in the EIP.
         */
        interface IERC20 {
            /**
             * @dev Returns the amount of tokens in existence.
             */
            function totalSupply() external view returns (uint256);
            /**
             * @dev Returns the amount of tokens owned by `account`.
             */
            function balanceOf(address account) external view returns (uint256);
            /**
             * @dev Moves `amount` tokens from the caller's account to `recipient`.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transfer(address recipient, uint256 amount) external returns (bool);
            /**
             * @dev Returns the remaining number of tokens that `spender` will be
             * allowed to spend on behalf of `owner` through {transferFrom}. This is
             * zero by default.
             *
             * This value changes when {approve} or {transferFrom} are called.
             */
            function allowance(address owner, address spender) external view returns (uint256);
            /**
             * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * IMPORTANT: Beware that changing an allowance with this method brings the risk
             * that someone may use both the old and the new allowance by unfortunate
             * transaction ordering. One possible solution to mitigate this race
             * condition is to first reduce the spender's allowance to 0 and set the
             * desired value afterwards:
             * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
             *
             * Emits an {Approval} event.
             */
            function approve(address spender, uint256 amount) external returns (bool);
            /**
             * @dev Moves `amount` tokens from `sender` to `recipient` using the
             * allowance mechanism. `amount` is then deducted from the caller's
             * allowance.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(
                address sender,
                address recipient,
                uint256 amount
            ) external returns (bool);
            /**
             * @dev Emitted when `value` tokens are moved from one account (`from`) to
             * another (`to`).
             *
             * Note that `value` may be zero.
             */
            event Transfer(address indexed from, address indexed to, uint256 value);
            /**
             * @dev Emitted when the allowance of a `spender` for an `owner` is set by
             * a call to {approve}. `value` is the new allowance.
             */
            event Approval(address indexed owner, address indexed spender, uint256 value);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "../IERC20.sol";
        /**
         * @dev Interface for the optional metadata functions from the ERC20 standard.
         *
         * _Available since v4.1._
         */
        interface IERC20Metadata is IERC20 {
            /**
             * @dev Returns the name of the token.
             */
            function name() external view returns (string memory);
            /**
             * @dev Returns the symbol of the token.
             */
            function symbol() external view returns (string memory);
            /**
             * @dev Returns the decimals places of the token.
             */
            function decimals() external view returns (uint8);
        }
        // SPDX-License-Identifier: MIT
        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);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "./ECDSA.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._
         */
        abstract contract EIP712 {
            /* solhint-disable var-name-mixedcase */
            // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
            // invalidate the cached domain separator if the chain id changes.
            bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
            uint256 private immutable _CACHED_CHAIN_ID;
            bytes32 private immutable _HASHED_NAME;
            bytes32 private immutable _HASHED_VERSION;
            bytes32 private immutable _TYPE_HASH;
            /* 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].
             */
            constructor(string memory name, string memory version) {
                bytes32 hashedName = keccak256(bytes(name));
                bytes32 hashedVersion = keccak256(bytes(version));
                bytes32 typeHash = keccak256(
                    "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                );
                _HASHED_NAME = hashedName;
                _HASHED_VERSION = hashedVersion;
                _CACHED_CHAIN_ID = block.chainid;
                _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
                _TYPE_HASH = typeHash;
            }
            /**
             * @dev Returns the domain separator for the current chain.
             */
            function _domainSeparatorV4() internal view returns (bytes32) {
                if (block.chainid == _CACHED_CHAIN_ID) {
                    return _CACHED_DOMAIN_SEPARATOR;
                } else {
                    return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
                }
            }
            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 ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /**
         * @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 ECDSA {
            enum RecoverError {
                NoError,
                InvalidSignature,
                InvalidSignatureLength,
                InvalidSignatureS,
                InvalidSignatureV
            }
            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");
                } else if (error == RecoverError.InvalidSignatureV) {
                    revert("ECDSA: invalid signature 'v' 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) {
                // Check the signature length
                // - case 65: r,s,v signature (standard)
                // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
                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.
                    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 if (signature.length == 64) {
                    bytes32 r;
                    bytes32 vs;
                    // ecrecover takes the signature parameters, and the only way to get them
                    // currently is to use assembly.
                    assembly {
                        r := mload(add(signature, 0x20))
                        vs := mload(add(signature, 0x40))
                    }
                    return tryRecover(hash, r, vs);
                } 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;
                uint8 v;
                assembly {
                    s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
                    v := add(shr(255, vs), 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 (v != 27 && v != 28) {
                    return (address(0), RecoverError.InvalidSignatureV);
                }
                // 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:\
        32", hash));
            }
            /**
             * @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));
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /**
         * @title Counters
         * @author Matt Condon (@shrugs)
         * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
         * of elements in a mapping, issuing ERC721 ids, or counting request ids.
         *
         * Include with `using Counters for Counters.Counter;`
         */
        library Counters {
            struct Counter {
                // This variable should never be directly accessed by users of the library: interactions must be restricted to
                // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
                // this feature: see https://github.com/ethereum/solidity/issues/4637
                uint256 _value; // default: 0
            }
            function current(Counter storage counter) internal view returns (uint256) {
                return counter._value;
            }
            function increment(Counter storage counter) internal {
                unchecked {
                    counter._value += 1;
                }
            }
            function decrement(Counter storage counter) internal {
                uint256 value = counter._value;
                require(value > 0, "Counter: decrement overflow");
                unchecked {
                    counter._value = value - 1;
                }
            }
            function reset(Counter storage counter) internal {
                counter._value = 0;
            }
        }
        

        File 4 of 5: Kernel
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        import "./interfaces/IDiamondCut.sol";
        import "./interfaces/IDiamondLoupe.sol";
        import "./libraries/LibDiamond.sol";
        import "./libraries/LibOwnership.sol";
        import "./libraries/LibDiamondStorage.sol";
        import "./interfaces/IERC165.sol";
        import "./interfaces/IERC173.sol";
        contract Kernel {
            constructor(IDiamondCut.FacetCut[] memory _diamondCut, address _owner) payable {
                require(_owner != address(0), "owner must not be 0x0");
                LibDiamond.diamondCut(_diamondCut, address(0), new bytes(0));
                LibOwnership.setContractOwner(_owner);
                LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage.diamondStorage();
                // adding ERC165 data
                ds.supportedInterfaces[type(IERC165).interfaceId] = true;
                ds.supportedInterfaces[type(IDiamondCut).interfaceId] = true;
                ds.supportedInterfaces[type(IDiamondLoupe).interfaceId] = true;
                ds.supportedInterfaces[type(IERC173).interfaceId] = true;
            }
            // Find facet for function that is called and execute the
            // function if a facet is found and return any value.
            fallback() external payable {
                LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage.diamondStorage();
                address facet = address(bytes20(ds.facets[msg.sig].facetAddress));
                require(facet != address(0), "Diamond: Function does not exist");
                assembly {
                    calldatacopy(0, 0, calldatasize())
                    let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
                    returndatacopy(0, 0, returndatasize())
                    switch result
                    case 0 {
                        revert(0, returndatasize())
                    }
                    default {
                        return (0, returndatasize())
                    }
                }
            }
            receive() external payable {}
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        interface IDiamondCut {
            enum FacetCutAction {Add, Replace, Remove}
            // Add=0, Replace=1, Remove=2
            struct FacetCut {
                address facetAddress;
                FacetCutAction action;
                bytes4[] functionSelectors;
            }
            /// @notice Add/replace/remove any number of functions and optionally execute
            ///         a function with delegatecall
            /// @param _diamondCut Contains the facet addresses and function selectors
            /// @param _init The address of the contract or facet to execute _calldata
            /// @param _calldata A function call, including function selector and arguments
            ///                  _calldata is executed with delegatecall on _init
            function diamondCut(
                FacetCut[] calldata _diamondCut,
                address _init,
                bytes calldata _calldata
            ) external;
            event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        // A loupe is a small magnifying glass used to look at diamonds.
        // These functions look at diamonds
        interface IDiamondLoupe {
            /// These functions are expected to be called frequently
            /// by tools.
            struct Facet {
                address facetAddress;
                bytes4[] functionSelectors;
            }
            /// @notice Gets all facet addresses and their four byte function selectors.
            /// @return facets_ Facet
            function facets() external view returns (Facet[] memory facets_);
            /// @notice Gets all the function selectors supported by a specific facet.
            /// @param _facet The facet address.
            /// @return facetFunctionSelectors_
            function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_);
            /// @notice Get all the facet addresses used by a diamond.
            /// @return facetAddresses_
            function facetAddresses() external view returns (address[] memory facetAddresses_);
            /// @notice Gets the facet that supports the given selector.
            /// @dev If facet is not found return address(0).
            /// @param _functionSelector The function selector.
            /// @return facetAddress_ The facet address.
            function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_);
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        import "../interfaces/IDiamondCut.sol";
        import "./LibDiamondStorage.sol";
        library LibDiamond {
            event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);
            // Internal function version of diamondCut
            // This code is almost the same as the external diamondCut,
            // except it is using 'Facet[] memory _diamondCut' instead of
            // 'Facet[] calldata _diamondCut'.
            // The code is duplicated to prevent copying calldata to memory which
            // causes an error for a two dimensional array.
            function diamondCut(
                IDiamondCut.FacetCut[] memory _diamondCut,
                address _init,
                bytes memory _calldata
            ) internal {
                uint256 selectorCount = LibDiamondStorage.diamondStorage().selectors.length;
                for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
                    selectorCount = executeDiamondCut(selectorCount, _diamondCut[facetIndex]);
                }
                emit DiamondCut(_diamondCut, _init, _calldata);
                initializeDiamondCut(_init, _calldata);
            }
            // executeDiamondCut takes one single FacetCut action and executes it
            // if FacetCutAction can't be identified, it reverts
            function executeDiamondCut(uint256 selectorCount, IDiamondCut.FacetCut memory cut) internal returns (uint256) {
                require(cut.functionSelectors.length > 0, "LibDiamond: No selectors in facet to cut");
                if (cut.action == IDiamondCut.FacetCutAction.Add) {
                    require(cut.facetAddress != address(0), "LibDiamond: add facet address can't be address(0)");
                    enforceHasContractCode(cut.facetAddress, "LibDiamond: add facet must have code");
                    return _handleAddCut(selectorCount, cut);
                }
                if (cut.action == IDiamondCut.FacetCutAction.Replace) {
                    require(cut.facetAddress != address(0), "LibDiamond: remove facet address can't be address(0)");
                    enforceHasContractCode(cut.facetAddress, "LibDiamond: remove facet must have code");
                    return _handleReplaceCut(selectorCount, cut);
                }
                if (cut.action == IDiamondCut.FacetCutAction.Remove) {
                    require(cut.facetAddress == address(0), "LibDiamond: remove facet address must be address(0)");
                    return _handleRemoveCut(selectorCount, cut);
                }
                revert("LibDiamondCut: Incorrect FacetCutAction");
            }
            // _handleAddCut executes a cut with the type Add
            // it reverts if the selector already exists
            function _handleAddCut(uint256 selectorCount, IDiamondCut.FacetCut memory cut) internal returns (uint256) {
                LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage.diamondStorage();
                for (uint256 selectorIndex; selectorIndex < cut.functionSelectors.length; selectorIndex++) {
                    bytes4 selector = cut.functionSelectors[selectorIndex];
                    address oldFacetAddress = ds.facets[selector].facetAddress;
                    require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists");
                    ds.facets[selector] = LibDiamondStorage.Facet(
                        cut.facetAddress,
                        uint16(selectorCount)
                    );
                    ds.selectors.push(selector);
                    selectorCount++;
                }
                return selectorCount;
            }
            // _handleReplaceCut executes a cut with the type Replace
            // it does not allow replacing immutable functions
            // it does not allow replacing with the same function
            // it does not allow replacing a function that does not exist
            function _handleReplaceCut(uint256 selectorCount, IDiamondCut.FacetCut memory cut) internal returns (uint256) {
                LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage.diamondStorage();
                for (uint256 selectorIndex; selectorIndex < cut.functionSelectors.length; selectorIndex++) {
                    bytes4 selector = cut.functionSelectors[selectorIndex];
                    address oldFacetAddress = ds.facets[selector].facetAddress;
                    // only useful if immutable functions exist
                    require(oldFacetAddress != address(this), "LibDiamondCut: Can't replace immutable function");
                    require(oldFacetAddress != cut.facetAddress, "LibDiamondCut: Can't replace function with same function");
                    require(oldFacetAddress != address(0), "LibDiamondCut: Can't replace function that doesn't exist");
                    // replace old facet address
                    ds.facets[selector].facetAddress = cut.facetAddress;
                }
                return selectorCount;
            }
            // _handleRemoveCut executes a cut with the type Remove
            // for efficiency, the selector to be deleted is replaced with the last one and then the last one is popped
            // it reverts if the function doesn't exist or it's immutable
            function _handleRemoveCut(uint256 selectorCount, IDiamondCut.FacetCut memory cut) internal returns (uint256) {
                LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage.diamondStorage();
                for (uint256 selectorIndex; selectorIndex < cut.functionSelectors.length; selectorIndex++) {
                    bytes4 selector = cut.functionSelectors[selectorIndex];
                    LibDiamondStorage.Facet memory oldFacet = ds.facets[selector];
                    require(oldFacet.facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist");
                    require(oldFacet.facetAddress != address(this), "LibDiamondCut: Can't remove immutable function.");
                    // replace selector with last selector
                    if (oldFacet.selectorPosition != selectorCount - 1) {
                        bytes4 lastSelector = ds.selectors[selectorCount - 1];
                        ds.selectors[oldFacet.selectorPosition] = lastSelector;
                        ds.facets[lastSelector].selectorPosition = oldFacet.selectorPosition;
                    }
                    // delete last selector
                    ds.selectors.pop();
                    delete ds.facets[selector];
                    selectorCount--;
                }
                return selectorCount;
            }
            function initializeDiamondCut(address _init, bytes memory _calldata) internal {
                if (_init == address(0)) {
                    require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but _calldata is not empty");
                    return;
                }
                require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)");
                if (_init != address(this)) {
                    enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
                }
                (bool success, bytes memory error) = _init.delegatecall(_calldata);
                if (!success) {
                    if (error.length > 0) {
                        // bubble up the error
                        revert(string(error));
                    } else {
                        revert("LibDiamondCut: _init function reverted");
                    }
                }
            }
            function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {
                uint256 contractSize;
                assembly {
                    contractSize := extcodesize(_contract)
                }
                require(contractSize > 0, _errorMessage);
            }
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        import "./LibDiamondStorage.sol";
        library LibOwnership {
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            function setContractOwner(address _newOwner) internal {
                LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage.diamondStorage();
                address previousOwner = ds.contractOwner;
                require(previousOwner != _newOwner, "Previous owner and new owner must be different");
                ds.contractOwner = _newOwner;
                emit OwnershipTransferred(previousOwner, _newOwner);
            }
            function contractOwner() internal view returns (address contractOwner_) {
                contractOwner_ = LibDiamondStorage.diamondStorage().contractOwner;
            }
            function enforceIsContractOwner() view internal {
                require(msg.sender == LibDiamondStorage.diamondStorage().contractOwner, "Must be contract owner");
            }
            modifier onlyOwner {
                require(msg.sender == LibDiamondStorage.diamondStorage().contractOwner, "Must be contract owner");
                _;
            }
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        library LibDiamondStorage {
            bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
            struct Facet {
                address facetAddress;
                uint16 selectorPosition;
            }
            struct DiamondStorage {
                // function selector => facet address and selector position in selectors array
                mapping(bytes4 => Facet) facets;
                bytes4[] selectors;
                // ERC165
                mapping(bytes4 => bool) supportedInterfaces;
                // owner of the contract
                address contractOwner;
            }
            function diamondStorage() internal pure returns (DiamondStorage storage ds) {
                bytes32 position = DIAMOND_STORAGE_POSITION;
                assembly {
                    ds.slot := position
                }
            }
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        interface IERC165 {
            /// @notice Query if a contract implements an interface
            /// @param interfaceId The interface identifier, as specified in ERC-165
            /// @dev Interface identification is specified in ERC-165. This function
            ///  uses less than 30,000 gas.
            /// @return `true` if the contract implements `interfaceID` and
            ///  `interfaceID` is not 0xffffffff, `false` otherwise
            function supportsInterface(bytes4 interfaceId) external view returns (bool);
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        /// @title ERC-173 Contract Ownership Standard
        ///  Note: the ERC-165 identifier for this interface is 0x7f5828d0
        /* is ERC165 */
        interface IERC173 {
            /// @dev This emits when ownership of a contract changes.
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            /// @notice Get the address of the owner
            /// @return owner_ The address of the owner.
            function owner() external view returns (address owner_);
            /// @notice Set the address of the new owner of the contract
            /// @dev Set _newOwner to address(0) to renounce any ownership.
            /// @param _newOwner The address of the new owner of the contract
            function transferOwnership(address _newOwner) external;
        }
        

        File 5 of 5: KernelFacet
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        import "../interfaces/IKernel.sol";
        import "../libraries/LibKernelStorage.sol";
        import "../libraries/LibOwnership.sol";
        import "@openzeppelin/contracts/math/SafeMath.sol";
        import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
        contract KernelFacet {
            using SafeMath for uint256;
            uint256 constant public MAX_LOCK = 365 days;
            uint256 constant BASE_MULTIPLIER = 1e18;
            event Deposit(address indexed user, uint256 amount, uint256 newBalance);
            event Withdraw(address indexed user, uint256 amountWithdrew, uint256 amountLeft);
            event Lock(address indexed user, uint256 timestamp);
            event Delegate(address indexed from, address indexed to);
            event DelegatedPowerIncreased(address indexed from, address indexed to, uint256 amount, uint256 to_newDelegatedPower);
            event DelegatedPowerDecreased(address indexed from, address indexed to, uint256 amount, uint256 to_newDelegatedPower);
            function initKernel(address _leag, address _rewards) public {
                require(_leag != address(0), "LEAG address must not be 0x0");
                LibKernelStorage.Storage storage ds = LibKernelStorage.kernelStorage();
                require(!ds.initialized, "Kernel: already initialized");
                LibOwnership.enforceIsContractOwner();
                ds.initialized = true;
                ds.leag = IERC20(_leag);
                ds.rewards = IRewards(_rewards);
            }
            // deposit allows a user to add more leag to his staked balance
            function deposit(uint256 amount) public {
                require(amount > 0, "Amount must be greater than 0");
               LibKernelStorage.Storage storage ds = LibKernelStorage.kernelStorage();
                uint256 allowance = ds.leag.allowance(msg.sender, address(this));
                require(allowance >= amount, "Token allowance too small");
                // this must be called before the user's balance is updated so the rewards contract can calculate
                // the amount owed correctly
                if (address(ds.rewards) != address(0)) {
                    ds.rewards.registerUserAction(msg.sender);
                }
                uint256 newBalance = balanceOf(msg.sender).add(amount);
                _updateUserBalance(ds.userStakeHistory[msg.sender], newBalance);
                _updateLockedLeag(leagStakedAtTs(block.timestamp).add(amount));
                address delegatedTo = userDelegatedTo(msg.sender);
                if (delegatedTo != address(0)) {
                    uint256 newDelegatedPower = delegatedPower(delegatedTo).add(amount);
                    _updateDelegatedPower(ds.delegatedPowerHistory[delegatedTo], newDelegatedPower);
                    emit DelegatedPowerIncreased(msg.sender, delegatedTo, amount, newDelegatedPower);
                }
                ds.leag.transferFrom(msg.sender, address(this), amount);
                emit Deposit(msg.sender, amount, newBalance);
            }
            // withdraw allows a user to withdraw funds if the balance is not locked
            function withdraw(uint256 amount) public {
                require(amount > 0, "Amount must be greater than 0");
                require(userLockedUntil(msg.sender) <= block.timestamp, "User balance is locked");
                uint256 balance = balanceOf(msg.sender);
                require(balance >= amount, "Insufficient balance");
                LibKernelStorage.Storage storage ds = LibKernelStorage.kernelStorage();
                // this must be called before the user's balance is updated so the rewards contract can calculate
                // the amount owed correctly
                if (address(ds.rewards) != address(0)) {
                    ds.rewards.registerUserAction(msg.sender);
                }
                _updateUserBalance(ds.userStakeHistory[msg.sender], balance.sub(amount));
                _updateLockedLeag(leagStakedAtTs(block.timestamp).sub(amount));
                address delegatedTo = userDelegatedTo(msg.sender);
                if (delegatedTo != address(0)) {
                    uint256 newDelegatedPower = delegatedPower(delegatedTo).sub(amount);
                    _updateDelegatedPower(ds.delegatedPowerHistory[delegatedTo], newDelegatedPower);
                    emit DelegatedPowerDecreased(msg.sender, delegatedTo, amount, newDelegatedPower);
                }
                ds.leag.transfer(msg.sender, amount);
                emit Withdraw(msg.sender, amount, balance.sub(amount));
            }
            // lock a user's currently staked balance until timestamp & add the bonus to his voting power
            function lock(uint256 timestamp) public {
                require(timestamp > block.timestamp, "Timestamp must be in the future");
                require(timestamp <= block.timestamp + MAX_LOCK, "Timestamp too big");
                require(balanceOf(msg.sender) > 0, "Sender has no balance");
                LibKernelStorage.Storage storage ds = LibKernelStorage.kernelStorage();
                LibKernelStorage.Stake[] storage checkpoints = ds.userStakeHistory[msg.sender];
                LibKernelStorage.Stake storage currentStake = checkpoints[checkpoints.length - 1];
                require(timestamp > currentStake.expiryTimestamp, "New timestamp lower than current lock timestamp");
                _updateUserLock(checkpoints, timestamp);
                emit Lock(msg.sender, timestamp);
            }
            function depositAndLock(uint256 amount, uint256 timestamp) public {
                deposit(amount);
                lock(timestamp);
            }
            // delegate allows a user to delegate his voting power to another user
            function delegate(address to) public {
                require(msg.sender != to, "Can't delegate to self");
                uint256 senderBalance = balanceOf(msg.sender);
                require(senderBalance > 0, "No balance to delegate");
                LibKernelStorage.Storage storage ds = LibKernelStorage.kernelStorage();
                emit Delegate(msg.sender, to);
                address delegatedTo = userDelegatedTo(msg.sender);
                if (delegatedTo != address(0)) {
                    uint256 newDelegatedPower = delegatedPower(delegatedTo).sub(senderBalance);
                    _updateDelegatedPower(ds.delegatedPowerHistory[delegatedTo], newDelegatedPower);
                    emit DelegatedPowerDecreased(msg.sender, delegatedTo, senderBalance, newDelegatedPower);
                }
                if (to != address(0)) {
                    uint256 newDelegatedPower = delegatedPower(to).add(senderBalance);
                    _updateDelegatedPower(ds.delegatedPowerHistory[to], newDelegatedPower);
                    emit DelegatedPowerIncreased(msg.sender, to, senderBalance, newDelegatedPower);
                }
                _updateUserDelegatedTo(ds.userStakeHistory[msg.sender], to);
            }
            // stopDelegate allows a user to take back the delegated voting power
            function stopDelegate() public {
                return delegate(address(0));
            }
            // balanceOf returns the current LEAG balance of a user (bonus not included)
            function balanceOf(address user) public view returns (uint256) {
                return balanceAtTs(user, block.timestamp);
            }
            // balanceAtTs returns the amount of LEAG that the user currently staked (bonus NOT included)
            function balanceAtTs(address user, uint256 timestamp) public view returns (uint256) {
                LibKernelStorage.Stake memory stake = stakeAtTs(user, timestamp);
                return stake.amount;
            }
            // stakeAtTs returns the Stake object of the user that was valid at `timestamp`
            function stakeAtTs(address user, uint256 timestamp) public view returns (LibKernelStorage.Stake memory) {
                LibKernelStorage.Storage storage ds = LibKernelStorage.kernelStorage();
                LibKernelStorage.Stake[] storage stakeHistory = ds.userStakeHistory[user];
                if (stakeHistory.length == 0 || timestamp < stakeHistory[0].timestamp) {
                    return LibKernelStorage.Stake(block.timestamp, 0, block.timestamp, address(0));
                }
                uint256 min = 0;
                uint256 max = stakeHistory.length - 1;
                if (timestamp >= stakeHistory[max].timestamp) {
                    return stakeHistory[max];
                }
                // binary search of the value in the array
                while (max > min) {
                    uint256 mid = (max + min + 1) / 2;
                    if (stakeHistory[mid].timestamp <= timestamp) {
                        min = mid;
                    } else {
                        max = mid - 1;
                    }
                }
                return stakeHistory[min];
            }
            // votingPower returns the voting power (bonus included) + delegated voting power for a user at the current block
            function votingPower(address user) public view returns (uint256) {
                return votingPowerAtTs(user, block.timestamp);
            }
            // votingPowerAtTs returns the voting power (bonus included) + delegated voting power for a user at a point in time
            function votingPowerAtTs(address user, uint256 timestamp) public view returns (uint256) {
                LibKernelStorage.Stake memory stake = stakeAtTs(user, timestamp);
                uint256 ownVotingPower;
                // if the user delegated his voting power to another user, then he doesn't have any voting power left
                if (stake.delegatedTo != address(0)) {
                    ownVotingPower = 0;
                } else {
                    uint256 balance = stake.amount;
                    uint256 multiplier = _stakeMultiplier(stake, timestamp);
                    ownVotingPower = balance.mul(multiplier).div(BASE_MULTIPLIER);
                }
                uint256 delegatedVotingPower = delegatedPowerAtTs(user, timestamp);
                return ownVotingPower.add(delegatedVotingPower);
            }
            // leagStaked returns the total raw amount of LEAG staked at the current block
            function leagStaked() public view returns (uint256) {
                return leagStakedAtTs(block.timestamp);
            }
            // leagStakedAtTs returns the total raw amount of LEAG users have deposited into the contract
            // it does not include any bonus
            function leagStakedAtTs(uint256 timestamp) public view returns (uint256) {
                return _checkpointsBinarySearch(LibKernelStorage.kernelStorage().leagStakedHistory, timestamp);
            }
            // delegatedPower returns the total voting power that a user received from other users
            function delegatedPower(address user) public view returns (uint256) {
                return delegatedPowerAtTs(user, block.timestamp);
            }
            // delegatedPowerAtTs returns the total voting power that a user received from other users at a point in time
            function delegatedPowerAtTs(address user, uint256 timestamp) public view returns (uint256) {
                return _checkpointsBinarySearch(LibKernelStorage.kernelStorage().delegatedPowerHistory[user], timestamp);
            }
            // same as multiplierAtTs but for the current block timestamp
            function multiplierOf(address user) public view returns (uint256) {
                return multiplierAtTs(user, block.timestamp);
            }
            // multiplierAtTs calculates the multiplier at a given timestamp based on the user's stake a the given timestamp
            // it includes the decay mechanism
            function multiplierAtTs(address user, uint256 timestamp) public view returns (uint256) {
                LibKernelStorage.Stake memory stake = stakeAtTs(user, timestamp);
                return _stakeMultiplier(stake, timestamp);
            }
            // userLockedUntil returns the timestamp until the user's balance is locked
            function userLockedUntil(address user) public view returns (uint256) {
                LibKernelStorage.Stake memory c = stakeAtTs(user, block.timestamp);
                return c.expiryTimestamp;
            }
            // userDelegatedTo returns the address to which a user delegated their voting power; address(0) if not delegated
            function userDelegatedTo(address user) public view returns (address) {
                LibKernelStorage.Stake memory c = stakeAtTs(user, block.timestamp);
                return c.delegatedTo;
            }
            // _checkpointsBinarySearch executes a binary search on a list of checkpoints that's sorted chronologically
            // looking for the closest checkpoint that matches the specified timestamp
            function _checkpointsBinarySearch(LibKernelStorage.Checkpoint[] storage checkpoints, uint256 timestamp) internal view returns (uint256) {
                if (checkpoints.length == 0 || timestamp < checkpoints[0].timestamp) {
                    return 0;
                }
                uint256 min = 0;
                uint256 max = checkpoints.length - 1;
                if (timestamp >= checkpoints[max].timestamp) {
                    return checkpoints[max].amount;
                }
                // binary search of the value in the array
                while (max > min) {
                    uint256 mid = (max + min + 1) / 2;
                    if (checkpoints[mid].timestamp <= timestamp) {
                        min = mid;
                    } else {
                        max = mid - 1;
                    }
                }
                return checkpoints[min].amount;
            }
            // _stakeMultiplier calculates the multiplier for the given stake at the given timestamp
            function _stakeMultiplier(LibKernelStorage.Stake memory stake, uint256 timestamp) internal view returns (uint256) {
                if (timestamp >= stake.expiryTimestamp) {
                    return BASE_MULTIPLIER;
                }
                uint256 diff = stake.expiryTimestamp - timestamp;
                if (diff >= MAX_LOCK) {
                    return BASE_MULTIPLIER.mul(2);
                }
                return BASE_MULTIPLIER.add(diff.mul(BASE_MULTIPLIER).div(MAX_LOCK));
            }
            // _updateUserBalance manages an array of checkpoints
            // if there's already a checkpoint for the same timestamp, the amount is updated
            // otherwise, a new checkpoint is inserted
            function _updateUserBalance(LibKernelStorage.Stake[] storage checkpoints, uint256 amount) internal {
                if (checkpoints.length == 0) {
                    checkpoints.push(LibKernelStorage.Stake(block.timestamp, amount, block.timestamp, address(0)));
                } else {
                    LibKernelStorage.Stake storage old = checkpoints[checkpoints.length - 1];
                    if (old.timestamp == block.timestamp) {
                        old.amount = amount;
                    } else {
                        checkpoints.push(LibKernelStorage.Stake(block.timestamp, amount, old.expiryTimestamp, old.delegatedTo));
                    }
                }
            }
            // _updateUserLock updates the expiry timestamp on the user's stake
            // it assumes that if the user already has a balance, which is checked for in the lock function
            // then there must be at least 1 checkpoint
            function _updateUserLock(LibKernelStorage.Stake[] storage checkpoints, uint256 expiryTimestamp) internal {
                LibKernelStorage.Stake storage old = checkpoints[checkpoints.length - 1];
                if (old.timestamp < block.timestamp) {
                    checkpoints.push(LibKernelStorage.Stake(block.timestamp, old.amount, expiryTimestamp, old.delegatedTo));
                } else {
                    old.expiryTimestamp = expiryTimestamp;
                }
            }
            // _updateUserDelegatedTo updates the delegateTo property on the user's stake
            // it assumes that if the user already has a balance, which is checked for in the delegate function
            // then there must be at least 1 checkpoint
            function _updateUserDelegatedTo(LibKernelStorage.Stake[] storage checkpoints, address to) internal {
                LibKernelStorage.Stake storage old = checkpoints[checkpoints.length - 1];
                if (old.timestamp < block.timestamp) {
                    checkpoints.push(LibKernelStorage.Stake(block.timestamp, old.amount, old.expiryTimestamp, to));
                } else {
                    old.delegatedTo = to;
                }
            }
            // _updateDelegatedPower updates the power delegated TO the user in the checkpoints history
            function _updateDelegatedPower(LibKernelStorage.Checkpoint[] storage checkpoints, uint256 amount) internal {
                if (checkpoints.length == 0 || checkpoints[checkpoints.length - 1].timestamp < block.timestamp) {
                    checkpoints.push(LibKernelStorage.Checkpoint(block.timestamp, amount));
                } else {
                    LibKernelStorage.Checkpoint storage old = checkpoints[checkpoints.length - 1];
                    old.amount = amount;
                }
            }
            // _updateLockedLeag stores the new `amount` into the LEAG locked history
            function _updateLockedLeag(uint256 amount) internal {
                LibKernelStorage.Storage storage ds = LibKernelStorage.kernelStorage();
                if (ds.leagStakedHistory.length == 0 || ds.leagStakedHistory[ds.leagStakedHistory.length - 1].timestamp < block.timestamp) {
                    ds.leagStakedHistory.push(LibKernelStorage.Checkpoint(block.timestamp, amount));
                } else {
                    LibKernelStorage.Checkpoint storage old = ds.leagStakedHistory[ds.leagStakedHistory.length - 1];
                    old.amount = amount;
                }
            }
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        import "../libraries/LibKernelStorage.sol";
        interface IKernel {
            // deposit allows a user to add more leag to his staked balance
            function deposit(uint256 amount) external;
            // withdraw allows a user to withdraw funds if the balance is not locked
            function withdraw(uint256 amount) external;
            // lock a user's currently staked balance until timestamp & add the bonus to his voting power
            function lock(uint256 timestamp) external;
            // delegate allows a user to delegate his voting power to another user
            function delegate(address to) external;
            // stopDelegate allows a user to take back the delegated voting power
            function stopDelegate() external;
            // lock the balance of a proposal creator until the voting ends; only callable by DAO
            function lockCreatorBalance(address user, uint256 timestamp) external;
            // balanceOf returns the current LEAG balance of a user (bonus not included)
            function balanceOf(address user) external view returns (uint256);
            // balanceAtTs returns the amount of LEAG that the user currently staked (bonus NOT included)
            function balanceAtTs(address user, uint256 timestamp) external view returns (uint256);
            // stakeAtTs returns the Stake object of the user that was valid at `timestamp`
            function stakeAtTs(address user, uint256 timestamp) external view returns (LibKernelStorage.Stake memory);
            // votingPower returns the voting power (bonus included) + delegated voting power for a user at the current block
            function votingPower(address user) external view returns (uint256);
            // votingPowerAtTs returns the voting power (bonus included) + delegated voting power for a user at a point in time
            function votingPowerAtTs(address user, uint256 timestamp) external view returns (uint256);
            // leagStaked returns the total raw amount of LEAG staked at the current block
            function leagStaked() external view returns (uint256);
            // leagStakedAtTs returns the total raw amount of LEAG users have deposited into the contract
            // it does not include any bonus
            function leagStakedAtTs(uint256 timestamp) external view returns (uint256);
            // delegatedPower returns the total voting power that a user received from other users
            function delegatedPower(address user) external view returns (uint256);
            // delegatedPowerAtTs returns the total voting power that a user received from other users at a point in time
            function delegatedPowerAtTs(address user, uint256 timestamp) external view returns (uint256);
            // multiplierAtTs calculates the multiplier at a given timestamp based on the user's stake a the given timestamp
            // it includes the decay mechanism
            function multiplierAtTs(address user, uint256 timestamp) external view returns (uint256);
            // userLockedUntil returns the timestamp until the user's balance is locked
            function userLockedUntil(address user) external view returns (uint256);
            // userDidDelegate returns the address to which a user delegated their voting power; address(0) if not delegated
            function userDelegatedTo(address user) external view returns (address);
            
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
        import "../interfaces/IRewards.sol";
        library LibKernelStorage {
            bytes32 constant STORAGE_POSITION = keccak256("com.enterdao.kernel.storage");
            struct Checkpoint {
                uint256 timestamp;
                uint256 amount;
            }
            struct Stake {
                uint256 timestamp;
                uint256 amount;
                uint256 expiryTimestamp;
                address delegatedTo;
            }
            struct Storage {
                bool initialized;
                // mapping of user address to history of Stake objects
                // every user action creates a new object in the history
                mapping(address => Stake[]) userStakeHistory;
                // array of leag staked Checkpoint
                // deposits/withdrawals create a new object in the history (max one per block)
                Checkpoint[] leagStakedHistory;
                // mapping of user address to history of delegated power
                // every delegate/stopDelegate call create a new checkpoint (max one per block)
                mapping(address => Checkpoint[]) delegatedPowerHistory;
                IERC20 leag;
                IRewards rewards;
            }
            function kernelStorage() internal pure returns (Storage storage ds) {
                bytes32 position = STORAGE_POSITION;
                assembly {
                    ds.slot := position
                }
            }
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        import "./LibDiamondStorage.sol";
        library LibOwnership {
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            function setContractOwner(address _newOwner) internal {
                LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage.diamondStorage();
                address previousOwner = ds.contractOwner;
                require(previousOwner != _newOwner, "Previous owner and new owner must be different");
                ds.contractOwner = _newOwner;
                emit OwnershipTransferred(previousOwner, _newOwner);
            }
            function contractOwner() internal view returns (address contractOwner_) {
                contractOwner_ = LibDiamondStorage.diamondStorage().contractOwner;
            }
            function enforceIsContractOwner() view internal {
                require(msg.sender == LibDiamondStorage.diamondStorage().contractOwner, "Must be contract owner");
            }
            modifier onlyOwner {
                require(msg.sender == LibDiamondStorage.diamondStorage().contractOwner, "Must be contract owner");
                _;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.6.0 <0.8.0;
        /**
         * @dev Wrappers over Solidity's arithmetic operations with added overflow
         * checks.
         *
         * Arithmetic operations in Solidity wrap on overflow. This can easily result
         * in bugs, because programmers usually assume that an overflow raises an
         * error, which is the standard behavior in high level programming languages.
         * `SafeMath` restores this intuition by reverting the transaction when 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.
         */
        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) {
                uint256 c = a + b;
                if (c < a) return (false, 0);
                return (true, c);
            }
            /**
             * @dev Returns the substraction of two unsigned integers, with an overflow flag.
             *
             * _Available since v3.4._
             */
            function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                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) {
                // 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) {
                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) {
                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) {
                uint256 c = a + b;
                require(c >= a, "SafeMath: addition overflow");
                return c;
            }
            /**
             * @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) {
                require(b <= a, "SafeMath: subtraction overflow");
                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) {
                if (a == 0) return 0;
                uint256 c = a * b;
                require(c / a == b, "SafeMath: multiplication overflow");
                return c;
            }
            /**
             * @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. 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) internal pure returns (uint256) {
                require(b > 0, "SafeMath: division by zero");
                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) {
                require(b > 0, "SafeMath: modulo by zero");
                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) {
                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.
             *
             * CAUTION: This function is deprecated because it requires allocating memory for the error
             * message unnecessarily. For custom revert reasons use {tryDiv}.
             *
             * 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) {
                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) {
                require(b > 0, errorMessage);
                return a % b;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.6.0 <0.8.0;
        /**
         * @dev Interface of the ERC20 standard as defined in the EIP.
         */
        interface IERC20 {
            /**
             * @dev Returns the amount of tokens in existence.
             */
            function totalSupply() external view returns (uint256);
            /**
             * @dev Returns the amount of tokens owned by `account`.
             */
            function balanceOf(address account) external view returns (uint256);
            /**
             * @dev Moves `amount` tokens from the caller's account to `recipient`.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transfer(address recipient, uint256 amount) external returns (bool);
            /**
             * @dev Returns the remaining number of tokens that `spender` will be
             * allowed to spend on behalf of `owner` through {transferFrom}. This is
             * zero by default.
             *
             * This value changes when {approve} or {transferFrom} are called.
             */
            function allowance(address owner, address spender) external view returns (uint256);
            /**
             * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * IMPORTANT: Beware that changing an allowance with this method brings the risk
             * that someone may use both the old and the new allowance by unfortunate
             * transaction ordering. One possible solution to mitigate this race
             * condition is to first reduce the spender's allowance to 0 and set the
             * desired value afterwards:
             * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
             *
             * Emits an {Approval} event.
             */
            function approve(address spender, uint256 amount) external returns (bool);
            /**
             * @dev Moves `amount` tokens from `sender` to `recipient` using the
             * allowance mechanism. `amount` is then deducted from the caller's
             * allowance.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
            /**
             * @dev Emitted when `value` tokens are moved from one account (`from`) to
             * another (`to`).
             *
             * Note that `value` may be zero.
             */
            event Transfer(address indexed from, address indexed to, uint256 value);
            /**
             * @dev Emitted when the allowance of a `spender` for an `owner` is set by
             * a call to {approve}. `value` is the new allowance.
             */
            event Approval(address indexed owner, address indexed spender, uint256 value);
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        interface IRewards {
            function registerUserAction(address user) external;
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.6;
        pragma experimental ABIEncoderV2;
        library LibDiamondStorage {
            bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
            struct Facet {
                address facetAddress;
                uint16 selectorPosition;
            }
            struct DiamondStorage {
                // function selector => facet address and selector position in selectors array
                mapping(bytes4 => Facet) facets;
                bytes4[] selectors;
                // ERC165
                mapping(bytes4 => bool) supportedInterfaces;
                // owner of the contract
                address contractOwner;
            }
            function diamondStorage() internal pure returns (DiamondStorage storage ds) {
                bytes32 position = DIAMOND_STORAGE_POSITION;
                assembly {
                    ds.slot := position
                }
            }
        }