S Price: $0.538554 (+3.92%)

Contract Diff Checker

Contract Name:
Minter

Contract Source Code:

File 1 of 1 : Minter

/**v3.0.1
 *0xf241f4fbe146a075424beadac2d2a743ad31fb8d
 *Submitted for verification at basescan.org on 2023-09-19
*/
/**v2.0.2
 *0x5a5919c191bc4a72cf80bce72cdec017b392254d
 *Submitted for verification at FtmScan.com on 2023-06-13
*/

/**v1.5.5
 *0x56a4e8c5ff356a8cbb9312fa31fbe482ac2b9cd5
 *Submitted for verification at FtmScan.com on 2023-03-31
*/
/**v1.3.15
 *0xc099610fe8B7E3effbFD4D8A4C34dD4C913B63F3
 *Submitted for verification at FtmScan.com on 2023-03-29
*/
/*v1.3
 *0x3215E01aC5cf536f768f07d68b6E75554a450B42
 *Submitted for verification at FtmScan.com on 2022-11-28
*/
/**v1.2
 *0xab6904e080bdb2c2e245cdcb7d3a7901f0bc963e
 *Submitted for verification at FtmScan.com on 2022-11-23
*/


/**
 *  EQUALIZER EXCHANGE
 *  The New Liquidity Hub of Fantom chain!
 *  https://equalizer.exchange  (Dapp)
 *  https://discord.gg/MaMhbgHMby   (Community)
 *
 *
 *
 *  ChangeLog:
 *
 *  Version: v3.0.2
 *  - Historical Epoch Records
 *    - Mints
 *    - Distributions
 *    - Price
 *
 *  Version: v1.3.16
 *  - Set "New Voter" for v1.5.5
 *
 *
 *  Contributors:
 *   -   Andre Cronje, Solidly.Exchange
 *   -   Velodrome.finance Team
 *   -   @smartcoding51
 *   -   543#3017 (Sam), ftm.guru & Equalizer.exchange
 *
 *
 *	SPDX-License-Identifier: UNLICENSED
*/


pragma solidity 0.8.9;
///pragma experimental ABIEncoderV2;


// File: contracts/interfaces/ITvlGuru.sol

//ftm.guru's Universal On-chain TVL Calculator
//Source: https://ftm.guru/docs
//Source: https://docs.ftm.guru
//Source: https://ftm.guru/rawdata/tvl
///interface ITVL {
    //Using Version = v7
    ///function p_lpt_coin_usd(address lp) external view returns(uint256);
    ///function p_lpt_usd(address u,address lp) external view returns(uint256);
    ///function p_t_coin_usd(address lp) external view returns(uint256);
    ///function p_t_e_coin_usd(address lp) external view returns(uint256);
    ///function p_glp_usd(address m, uint256 md, bool mx, address t, uint256 td) external view returns(uint256);
    ///function tvlOf_glp_usd(address q, address m, uint256 md, bool mx, address t, uint256 td) external view returns(uint256);
///}
interface IPriceGuru {
	function getAssetPrice(address) external view returns(uint);
}


// File: contracts/interfaces/IERC20.sol


pragma solidity 0.8.9;

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function transfer(address recipient, uint amount) external returns (bool);
    function decimals() external view returns (uint8);
    function symbol() external view returns (string memory);
    function balanceOf(address) external view returns (uint);
    function transferFrom(address sender, address recipient, uint amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint);
    function approve(address spender, uint value) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
}

// File: contracts/interfaces/IVotingEscrow.sol


pragma solidity 0.8.9;

interface IVotingEscrow {

    struct Point {
        int128 bias;
        int128 slope; // # -dweight / dt
        uint256 ts;
        uint256 blk; // block
    }

    function token() external view returns (address);
    function team() external returns (address);
    function epoch() external view returns (uint);
    function point_history(uint loc) external view returns (Point memory);
    function user_point_history(uint tokenId, uint loc) external view returns (Point memory);
    function user_point_epoch(uint tokenId) external view returns (uint);

    function ownerOf(uint) external view returns (address);
    function isApprovedOrOwner(address, uint) external view returns (bool);
    function transferFrom(address, address, uint) external;

    function voting(uint tokenId) external;
    function abstain(uint tokenId) external;
    function attach(uint tokenId) external;
    function detach(uint tokenId) external;

    function checkpoint() external;
    function deposit_for(uint tokenId, uint value) external;
    function create_lock_for(uint, uint, address) external returns (uint);

    function balanceOfNFT(uint) external view returns (uint);
    function totalSupply() external view returns (uint);
}

// File: contracts/interfaces/IGauge.sol


pragma solidity 0.8.9;

interface IGauge {
    function notifyRewardAmount(address token, uint amount) external;
    function getReward(address account, address[] memory tokens) external;
    function claimFees() external returns (uint claimed0, uint claimed1);
    function left(address token) external view returns (uint);
    function isForPair() external view returns (bool);
}

// File: contracts/interfaces/IVoter.sol


pragma solidity 0.8.9;

interface IVoter {
    function _ve() external view returns (address);
    function governor() external view returns (address);
    function emergencyCouncil() external view returns (address);
    function attachTokenToGauge(uint _tokenId, address account) external;
    function detachTokenFromGauge(uint _tokenId, address account) external;
    function emitDeposit(uint _tokenId, address account, uint amount) external;
    function emitWithdraw(uint _tokenId, address account, uint amount) external;
    function isWhitelisted(address token) external view returns (bool);
    function notifyRewardAmount(uint amount) external;
    function distribute(address _gauge) external;
}
// File: contracts/interfaces/IEqual.sol


pragma solidity 0.8.9;

interface IEqual {
    function totalSupply() external view returns (uint);
    function balanceOf(address) external view returns (uint);
    function approve(address spender, uint value) external returns (bool);
    function transfer(address, uint) external returns (bool);
    function transferFrom(address,address,uint) external returns (bool);
    function mint(address, uint) external returns (bool);
    function minter() external returns (address);
}


// File: contracts/libraries/Math.sol


pragma solidity 0.8.9;

library Math {
    function max(uint a, uint b) internal pure returns (uint) {
        return a >= b ? a : b;
    }
    function min(uint a, uint b) internal pure returns (uint) {
        return a < b ? a : b;
    }
    function sqrt(uint y) internal pure returns (uint z) {
        if (y > 3) {
            z = y;
            uint x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }
    function cbrt(uint256 n) internal pure returns (uint256) { unchecked {
        uint256 x = 0;
        for (uint256 y = 1 << 255; y > 0; y >>= 3) {
            x <<= 1;
            uint256 z = 3 * x * (x + 1) + 1;
            if (n / y >= z) {
                n -= y * z;
                x += 1;
            }
        }
        return x;
    }}
}

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


// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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


// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;


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

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

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

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

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

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

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

// File: contracts/Minter.sol


pragma solidity 0.8.9;









/**
* @title Minter
* @notice codifies the minting rules as per ve(3,3), abstracted from the token to support
* any token that allows minting
*/
contract Minter is Initializable {
    /// @notice allows minting once per week (reset every Thursday 00:00 UTC)
    uint internal constant WEEK = 86400 * 7;
    uint internal constant PRECISION = 1000;
    uint internal constant LOCK = 86400 * 7 * 26;    /// @notice max lock period 26 weeeks
    uint public TAIL_EMISSION;

    uint internal emission;
    uint internal numEpoch;

    IEqual public _equal;
    IVoter public _voter;
    IVotingEscrow public _ve;
    IPriceGuru public PriceGuru;

    /// @notice represents a starting weekly emission of 50K EQUAL (EQUAL has 18 decimals)
    uint public weekly;
    uint public active_period;

    address public owner;
    address public team;
    address public pendingTeam;

    address public treasury;
    uint public treasuryRate;

    /// @notice Gauge address for EQUAL/WFTM pair
    address public pool2;
    uint public pool2Rate;

    address public ms;

    mapping(uint256 => uint256) public dists;
    mapping(uint256 => uint256) public mints;
    mapping(uint256 => uint256) public price;



	/********************************************************************************************/
	/*****************************************NON-STORAGE****************************************/
	/********************************************************************************************/
	/// NON-STORAGE

    event Mint(
        address indexed sender,
        uint weekly,
        uint circulating_supply,
        uint circulating_emission,
        uint balanceOf,
        uint treasuryEmissions,
        uint pool2Emissions,
        uint priceUSD
    );

    event Withdrawal(
        address indexed recipient,
        uint amount
    );

    /**
     * @dev initialize
     * @param __voter the voting & distribution system
     * @param __ve the ve(3,3) system that will be locked into
     */
    function initialize(
        address __voter,
        address __ve,
        uint256 __weekly,
        IPriceGuru __pg
    ) public initializer {
        owner = msg.sender;
        team = msg.sender;
        ms = msg.sender;
        treasuryRate = 20;
        pool2Rate = 10;
        emission = 980;
        TAIL_EMISSION = 2;
        weekly = __weekly;
        _equal = IEqual(IVotingEscrow(__ve).token());
        _voter = IVoter(__voter);
        _ve = IVotingEscrow(__ve);
        active_period = ((block.timestamp + (2 * WEEK)) / WEEK) * WEEK;
        PriceGuru = __pg;
    }

    /// @notice Inaugration Ceremony & Gifts
    function initialSetup(
        address[] memory claimants,
        uint[] memory amounts
    ) external {
        require(owner == msg.sender);
        uint _max;
        for (uint i = 0; i < claimants.length; i++) { _max += amounts[i]; }
        _equal.mint(address(this), _max);
        _equal.approve(address(_ve), type(uint).max);
        for (uint i = 0; i < claimants.length; i++) {
            _ve.create_lock_for(amounts[i], LOCK, claimants[i]);
        }
        owner = address(0);
        active_period = ((block.timestamp) / WEEK) * WEEK; // allow minter.update_period() to mint new emissions THIS Thursday
    }

    function setTeam(address _team) external {
        require(msg.sender == team, "not team");
        pendingTeam = _team;
    }

    function acceptTeam() external {
        require(msg.sender == pendingTeam, "not pending team");
        team = pendingTeam;
    }

    function setTreasury(address _treasury) external {
        require(msg.sender == team, "not team");
        treasury = _treasury;
    }

    function setOwner(address _newo) external {
        require(msg.sender == team, "not team");
        owner = _newo;
    }

    function setTreasuryRate(uint _treasuryRate) external {
        require(msg.sender == team, "not team");
        require(_treasuryRate <= PRECISION, "rate too high");
        treasuryRate = _treasuryRate;
    }

    function setPool2(address _pool2) external {
        require(msg.sender == team, "not team");
        require(_pool2 != address(0), "zero address");
        pool2 = _pool2;
    }

    /// @notice weekly emission takes the max of calculated (aka target) emission versus circulating tail end emission
    function weekly_emission() public view returns (uint) {
        if(numEpoch < 10) return calculate_emission();
        else return Math.max(calculate_emission(), circulating_emission());
    }

    /**
     * @notice emission calculation is 0.5% of available supply to mint adjusted
     * by circulating / total supply until EPOCH 104, 0.1% thereafter
     */
    function calculate_emission() public view returns (uint) {
        return (weekly * emission) / PRECISION;
    }

    /// @notice calculates tail end (infinity) emissions as 0.2% of total supply
    function circulating_emission() public view returns (uint) {
        return (circulating_supply() * TAIL_EMISSION) / PRECISION;
    }

    /// @notice calculate circulating supply as total token supply - locked supply
    function circulating_supply() public view returns (uint) {
        return _equal.totalSupply() - _ve.totalSupply();
    }

    // calculate inflation and adjust ve balances accordingly
    function calculate_growth(uint _minted) public view returns (uint) {
        uint _veTotal = _ve.totalSupply();
        uint _equalTotal = _equal.totalSupply();
        return
            (((((_minted * _veTotal) / _equalTotal) * _veTotal) / _equalTotal) *
                _veTotal) /
            _equalTotal /
            2;
    }

    /// v1.5.2 : Helper view functions
    function epochNumber() public view returns (uint) {
        return(numEpoch);
    }

    function decayFactor() public view returns (uint) {
        return(emission);
    }

    /// @notice update period can only be called once per cycle (1 week)
    function update_period() external returns (uint) {
        uint _period = active_period;
        if (block.timestamp >= _period + WEEK && owner == address(0)) { // only trigger if new week
            _period = (block.timestamp / WEEK) * WEEK;
            active_period = _period;
            weekly = weekly_emission();

            // uint _growth = calculate_growth(weekly);
            uint _treasuryEmissions = (treasuryRate * weekly) / PRECISION;
            uint _pool2Emissions = (pool2Rate * weekly) / PRECISION;
            uint _required = weekly + _treasuryEmissions + _pool2Emissions;
            uint _balanceOf = _equal.balanceOf(address(this));
            if (_balanceOf < _required) {
                _equal.mint(address(this), _required - _balanceOf);
            }

            unchecked {
                ++numEpoch;
            }
            if (numEpoch == 104) emission = PRECISION - TAIL_EMISSION;


            price[ _period ] = PriceGuru.getAssetPrice( address(_equal) );
            mints[ _period ] = _required - _balanceOf;
            dists[ _period ] = weekly;

            _equal.approve(address(_voter), weekly);
            _voter.notifyRewardAmount(weekly);

            {
            	address _treasury = treasury;
            	if(_treasury != address(0)) {
            		require(_equal.transfer(_treasury, _treasuryEmissions));
            	}
            }{
            	address _pool2 = pool2;
            	if(_pool2 != address(0)) {
            		_equal.approve(_pool2, _pool2Emissions);
            		IGauge(_pool2).notifyRewardAmount(address(_equal), _pool2Emissions);
            	}
            }


            emit Mint(msg.sender, weekly, circulating_supply(), circulating_emission(), _balanceOf, _treasuryEmissions, _pool2Emissions, price[ _period ]);
        }
        return _period;
    }

    /// @notice withdraw remaining EQUAL tokens
    function withdrawEQUAL(address _recipient) external {
        require(msg.sender == team, "not team");
        uint256 remaining = _equal.balanceOf(address(this));
        require(remaining > 0, "No remaining tokens");
        _equal.transfer(_recipient, remaining);
        // Emit withdrawal event
        emit Withdrawal(_recipient, remaining);
    }

    function reset() external {
        require(msg.sender == ms, "!ms");
        team = ms;
        pendingTeam = ms;
        treasury = ms;
    }

    function setNewVoter(address _v) external  {
        require(msg.sender == ms, "!ms");
        _voter = IVoter(_v);
    }

    function setDecayFactor(uint _f) external  {
        require(msg.sender == ms, "!ms");
        emission = _f;
        require(weekly_emission() < circulating_supply() / 100, "too high!");
    }

    function setGov(address _ms) external {
        require(msg.sender == ms, "!ms");
        team = ms;
        pendingTeam = ms;
        treasury = ms;
        ms = _ms;
    }

    function setWeeklyEmissionOverride(uint w) external {
        require(msg.sender == ms, "!ms");
        require(w > 3 * WEEK, "too low!");
        require(w < circulating_supply() / 100, "too high!");
		weekly = w;
	}
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):