Sonic Blaze Testnet

Contract Diff Checker

Contract Name:
RewarderFactory

Contract Source Code:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Ownable2StepUpgradeable} from "openzeppelin-contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import {ImmutableClone} from "../libraries/ImmutableClone.sol";
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";

import {IRewarder} from "../interfaces/IRewarder.sol";
import {IBribeRewarder} from "../interfaces/IBribeRewarder.sol";
import {IBaseRewarder} from "../interfaces/IBaseRewarder.sol";
import {IRewarderFactory} from "../interfaces/IRewarderFactory.sol";

/**
 * @title Rewarder Factory Contract
 * @dev The Rewarder Factory Contract allows users to create bribe rewarders and admin to create masterchef.
 */
contract RewarderFactory is Ownable2StepUpgradeable, IRewarderFactory {
    mapping(RewarderType => IRewarder) private _implementations;

    mapping(RewarderType => IRewarder[]) private _rewarders;
    mapping(IRewarder => RewarderType) private _rewarderTypes;

    mapping(address => uint256) private _nonces;

    /// @dev holds whitelisted tokens with their minBribeAmount (> 0) as bribe amount per period
    //  minAmount == 0 means token is not whitelisted 
    mapping(address => uint256) private _whitelistedTokens;

    /// @dev fee for creating bribes in native token
    uint256 private _bribeCreatorFee;


    uint256[10] __gap;

    /**
     * @dev Disables the initialize function.
     */
    constructor() {
        _disableInitializers();
    }

    /**
     * @dev Initializes the RewarderFactory contract.
     * @param initialOwner The initial owner of the contract.
     */
    function initialize(
        address initialOwner,
        RewarderType[] calldata initialRewarderTypes,
        IRewarder[] calldata initialRewarders
    ) external reinitializer(1) {
        __Ownable_init(initialOwner);

        uint256 length = initialRewarderTypes.length;
        for (uint256 i; i < length; ++i) {
            _setRewarderImplementation(initialRewarderTypes[i], initialRewarders[i]);
        }

        _bribeCreatorFee = 0; // maybe in the future for non-whitelisted tokens
    }

    /**
     * @dev get the fee for creating bribes in native token decimals
     */
    function getBribeCreatorFee() external view returns (uint256) {
        return _bribeCreatorFee;
    }

    /**
     * @dev Returns if token is whitelisted and the minBribeAmount
     * 
     * @param token token address 
     * @return isWhitelisted true if whitelisted
     * @return minBribeAmount min bribe amount per period
     */
    function getWhitelistedTokenInfo (address token) external view returns (bool isWhitelisted, uint256 minBribeAmount) {
        minBribeAmount = _whitelistedTokens[token];
        isWhitelisted = minBribeAmount > 0;
    }

    /**
     * @dev Returns the rewarder implementation for the given rewarder type.
     * @param rewarderType The rewarder type.
     * @return The rewarder implementation for the given rewarder type.
     */
    function getRewarderImplementation(RewarderType rewarderType) external view returns (IRewarder) {
        return _implementations[rewarderType];
    }

    /**
     * @dev Returns the number of rewarders for the given rewarder type.
     * @param rewarderType The rewarder type.
     * @return The number of rewarders for the given rewarder type.
     */
    function getRewarderCount(RewarderType rewarderType) external view returns (uint256) {
        return _rewarders[rewarderType].length;
    }

    /**
     * @dev Returns the rewarder at the given index for the given rewarder type.
     * @param rewarderType The rewarder type.
     * @param index The index of the rewarder.
     * @return The rewarder at the given index for the given rewarder type.
     */
    function getRewarderAt(RewarderType rewarderType, uint256 index) external view returns (IRewarder) {
        return _rewarders[rewarderType][index];
    }

    /**
     * @dev Returns the rewarder type for the given rewarder.
     * @param rewarder The rewarder.
     * @return The rewarder type for the given rewarder.
     */
    function getRewarderType(IRewarder rewarder) external view returns (RewarderType) {
        return _rewarderTypes[rewarder];
    }

    /**
     * @dev Creates a rewarder.
     * Only the owner can call this function, except for veMoe rewarders.
     * @param rewarderType The rewarder type.
     * @param token The token to reward.
     * @param pid The pool ID.
     * @return rewarder The rewarder.
     */
    function createRewarder(RewarderType rewarderType, IERC20 token, uint256 pid)
        external
        returns (IBaseRewarder rewarder)
    {
        _checkOwner();

        if (rewarderType == RewarderType.BribeRewarder) revert RewarderFactory__InvalidRewarderType();

        rewarder = _clone(rewarderType, token, pid);

        emit RewarderCreated(rewarderType, token, pid, rewarder);
    }

    /**
     * @dev Create a bribe rewarder
     * Everyone can call this function. The bribe token needs to be whitelisted
     * @param token The token to reward.
     * @param pool The pool address
     * @return rewarder The rewarder.
     */
    function createBribeRewarder(IERC20 token, address pool) external returns (IBribeRewarder rewarder) {
        _checkWhitelist(address(token));

        rewarder = IBribeRewarder(_cloneBribe(RewarderType.BribeRewarder, token, pool));

        emit BribeRewarderCreated(RewarderType.BribeRewarder, token, pool, rewarder);
    }

    /**
     * Claim rewards for given rewarders
     * @param rewarders rewarders to claim
     * @param account account
     */
    function claimBribeRewards(IBribeRewarder[] memory rewarders, address account) external {
        for (uint256 i; i < rewarders.length; ++i) {
            rewarders[i].claim(account);
        }
    }

    /**
     * @dev Sets the rewarder implementation for the given rewarder type.
     * Only the owner can call this function.
     * @param rewarderType The rewarder type.
     * @param implementation The rewarder implementation.
     */
    function setRewarderImplementation(RewarderType rewarderType, IRewarder implementation) external onlyOwner {
        _setRewarderImplementation(rewarderType, implementation);
    }

    /**
     * @dev Set token with their minBribeAmounts for whitelist
     * Notice: For whitelist native rewards, use address(0)
     * 
     * @param tokens token addresses
     * @param minBribeAmounts minAmounts to bribe, 0 means token will be 'delisted'
     */
    function setWhitelist(address[] calldata tokens, uint256[] calldata minBribeAmounts) external onlyOwner {
        uint256 length = tokens.length;
        if (length != minBribeAmounts.length) revert RewarderFactory__InvalidLength();

        for (uint256 i; i < length; ++i) {
            _whitelistedTokens[tokens[i]] = minBribeAmounts[i];
        }
    }

    /**
     * @dev Clone the rewarder implementation for the given rewarder type and initialize it.
     * @param rewarderType The rewarder type.
     * @param token The token to reward.
     * @param pid The pool ID.
     * @return rewarder The rewarder.
     */
    function _clone(RewarderType rewarderType, IERC20 token, uint256 pid) private returns (IBaseRewarder rewarder) {
        if (rewarderType == RewarderType.InvalidRewarder) revert RewarderFactory__InvalidRewarderType();

        IRewarder implementation = _implementations[rewarderType];

        if (address(implementation) == address(0)) revert RewarderFactory__ZeroAddress();

        IRewarder[] storage rewarders = _rewarders[rewarderType];

        bytes memory immutableData = abi.encodePacked(token, pid);
        bytes32 salt = keccak256(abi.encodePacked(msg.sender, _nonces[msg.sender]++));

        rewarder = IBaseRewarder(ImmutableClone.cloneDeterministic(address(implementation), immutableData, salt));

        rewarders.push(rewarder);
        _rewarderTypes[rewarder] = rewarderType;

        rewarder.initialize(msg.sender);
    }

    function _cloneBribe(RewarderType rewarderType, IERC20 token, address pool)
        private
        returns (IBribeRewarder rewarder)
    {
        if (rewarderType != RewarderType.BribeRewarder) revert RewarderFactory__InvalidRewarderType();

        IRewarder implementation = _implementations[rewarderType];

        if (address(implementation) == address(0)) revert RewarderFactory__ZeroAddress();

        IRewarder[] storage rewarders = _rewarders[rewarderType];

        bytes memory immutableData = abi.encodePacked(token, pool);
        bytes32 salt = keccak256(abi.encodePacked(msg.sender, _nonces[msg.sender]++));

        rewarder = IBribeRewarder(ImmutableClone.cloneDeterministic(address(implementation), immutableData, salt));

        rewarders.push(rewarder);
        _rewarderTypes[rewarder] = rewarderType;

        rewarder.initialize(msg.sender);
    }

    /**
     * @dev Sets the rewarder implementation for the given rewarder type.
     * @param rewarderType The rewarder type.
     * @param implementation The rewarder implementation.
     */
    function _setRewarderImplementation(RewarderType rewarderType, IRewarder implementation) private {
        if (rewarderType == RewarderType.InvalidRewarder) revert RewarderFactory__InvalidRewarderType();

        _implementations[rewarderType] = implementation;

        emit RewarderImplementationSet(rewarderType, implementation);
    }

    /**
     * returns true if token is whitelisted (min amount > 0)
     * @param token token
     */
    function _checkWhitelist(address token) private view {
        if ( _whitelistedTokens[token] == 0) {
            revert RewarderFactory__TokenNotWhitelisted();
        }
    }

}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.20;

import {OwnableUpgradeable} from "./OwnableUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step
    struct Ownable2StepStorage {
        address _pendingOwner;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00;

    function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) {
        assembly {
            $.slot := Ownable2StepStorageLocation
        }
    }

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

    function __Ownable2Step_init() internal onlyInitializing {
    }

    function __Ownable2Step_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        Ownable2StepStorage storage $ = _getOwnable2StepStorage();
        return $._pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        Ownable2StepStorage storage $ = _getOwnable2StepStorage();
        $._pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        Ownable2StepStorage storage $ = _getOwnable2StepStorage();
        delete $._pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

/**
 * @title Liquidity Book Immutable Clone Library
 * @notice Minimal immutable proxy library.
 * @author Trader Joe
 * @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol)
 * @author Minimal proxy by 0age (https://github.com/0age)
 * @author Clones with immutable args by wighawag, zefram.eth, Saw-mon & Natalie
 * (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args)
 * @dev Minimal proxy:
 * Although the sw0nt pattern saves 5 gas over the erc-1167 pattern during runtime,
 * it is not supported out-of-the-box on Etherscan. Hence, we choose to use the 0age pattern,
 * which saves 4 gas over the erc-1167 pattern during runtime, and has the smallest bytecode.
 * @dev Clones with immutable args (CWIA):
 * The implementation of CWIA here doesn't implements a `receive()` as it is not needed for LB.
 */
library ImmutableClone {
    error DeploymentFailed();
    error PackedDataTooBig();

    /**
     * @dev Deploys a deterministic clone of `implementation` using immutable arguments encoded in `data`, with `salt`
     * @param implementation The address of the implementation
     * @param data The encoded immutable arguments
     * @param salt The salt
     */
    function cloneDeterministic(address implementation, bytes memory data, bytes32 salt)
        internal
        returns (address instance)
    {
        assembly {
            // Compute the boundaries of the data and cache the memory slots around it.
            let mBefore2 := mload(sub(data, 0x40))
            let mBefore1 := mload(sub(data, 0x20))
            let dataLength := mload(data)
            let dataEnd := add(add(data, 0x20), dataLength)
            let mAfter1 := mload(dataEnd)

            // +2 bytes for telling how much data there is appended to the call.
            let extraLength := add(dataLength, 2)
            // The `creationSize` is `extraLength + 63`
            // The `runSize` is `creationSize - 10`.

            // if `extraLength` is greater than `0xffca` revert as the `creationSize` would be greater than `0xffff`.
            if gt(extraLength, 0xffca) {
                // Store the function selector of `PackedDataTooBig()`.
                mstore(0x00, 0xc8c78139)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            /**
             * ---------------------------------------------------------------------------------------------------+
             * CREATION (10 bytes)                                                                                |
             * ---------------------------------------------------------------------------------------------------|
             * Opcode     | Mnemonic          | Stack     | Memory                                                |
             * ---------------------------------------------------------------------------------------------------|
             * 61 runSize | PUSH2 runSize     | r         |                                                       |
             * 3d         | RETURNDATASIZE    | 0 r       |                                                       |
             * 81         | DUP2              | r 0 r     |                                                       |
             * 60 offset  | PUSH1 offset      | o r 0 r   |                                                       |
             * 3d         | RETURNDATASIZE    | 0 o r 0 r |                                                       |
             * 39         | CODECOPY          | 0 r       | [0..runSize): runtime code                            |
             * f3         | RETURN            |           | [0..runSize): runtime code                            |
             * ---------------------------------------------------------------------------------------------------|
             * RUNTIME (98 bytes + extraLength)                                                                   |
             * ---------------------------------------------------------------------------------------------------|
             * Opcode   | Mnemonic       | Stack                    | Memory                                      |
             * ---------------------------------------------------------------------------------------------------|
             *                                                                                                    |
             * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 36       | CALLDATASIZE   | cds                      |                                             |
             * 3d       | RETURNDATASIZE | 0 cds                    |                                             |
             * 3d       | RETURNDATASIZE | 0 0 cds                  |                                             |
             * 37       | CALLDATACOPY   |                          | [0..cds): calldata                          |
             *                                                                                                    |
             * ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d       | RETURNDATASIZE | 0                        | [0..cds): calldata                          |
             * 3d       | RETURNDATASIZE | 0 0                      | [0..cds): calldata                          |
             * 3d       | RETURNDATASIZE | 0 0 0                    | [0..cds): calldata                          |
             * 3d       | RETURNDATASIZE | 0 0 0 0                  | [0..cds): calldata                          |
             * 61 extra | PUSH2 extra    | e 0 0 0 0                | [0..cds): calldata                          |
             *                                                                                                    |
             * ::: copy extra data to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 80       | DUP1           | e e 0 0 0 0              | [0..cds): calldata                          |
             * 60 0x35  | PUSH1 0x35     | 0x35 e e 0 0 0 0         | [0..cds): calldata                          |
             * 36       | CALLDATASIZE   | cds 0x35 e e 0 0 0 0     | [0..cds): calldata                          |
             * 39       | CODECOPY       | e 0 0 0 0                | [0..cds): calldata, [cds..cds+e): extraData |
             *                                                                                                    |
             * ::: delegate call to the implementation contract ::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 36       | CALLDATASIZE   | cds e 0 0 0 0            | [0..cds): calldata, [cds..cds+e): extraData |
             * 01       | ADD            | cds+e 0 0 0 0            | [0..cds): calldata, [cds..cds+e): extraData |
             * 3d       | RETURNDATASIZE | 0 cds+e 0 0 0 0          | [0..cds): calldata, [cds..cds+e): extraData |
             * 73 addr  | PUSH20 addr    | addr 0 cds+e 0 0 0 0     | [0..cds): calldata, [cds..cds+e): extraData |
             * 5a       | GAS            | gas addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
             * f4       | DELEGATECALL   | success 0 0              | [0..cds): calldata, [cds..cds+e): extraData |
             *                                                                                                    |
             * ::: copy return data to memory ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d       | RETURNDATASIZE | rds success 0 0          | [0..cds): calldata, [cds..cds+e): extraData |
             * 3d       | RETURNDATASIZE | rds rds success 0 0      | [0..cds): calldata, [cds..cds+e): extraData |
             * 93       | SWAP4          | 0 rds success 0 rds      | [0..cds): calldata, [cds..cds+e): extraData |
             * 80       | DUP1           | 0 0 rds success 0 rds    | [0..cds): calldata, [cds..cds+e): extraData |
             * 3e       | RETURNDATACOPY | success 0 rds            | [0..rds): returndata                        |
             *                                                                                                    |
             * 60 0x33  | PUSH1 0x33     | 0x33 success 0 rds       | [0..rds): returndata                        |
             * 57       | JUMPI          | 0 rds                    | [0..rds): returndata                        |
             *                                                                                                    |
             * ::: revert ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * fd       | REVERT         |                          | [0..rds): returndata                        |
             *                                                                                                    |
             * ::: return ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 5b       | JUMPDEST       | 0 rds                    | [0..rds): returndata                        |
             * f3       | RETURN         |                          | [0..rds): returndata                        |
             * ---------------------------------------------------------------------------------------------------+
             */
            // Write the bytecode before the data.
            mstore(data, 0x5af43d3d93803e603357fd5bf3)
            // Write the address of the implementation.
            mstore(sub(data, 0x0d), implementation)
            mstore(
                sub(data, 0x21),
                or(
                    shl(0xd8, add(extraLength, 0x35)),
                    or(shl(0x48, extraLength), 0x6100003d81600a3d39f3363d3d373d3d3d3d610000806035363936013d73)
                )
            )
            mstore(dataEnd, shl(0xf0, extraLength))

            // Create the instance.
            instance := create2(0, sub(data, 0x1f), add(extraLength, 0x3f), salt)

            // If `instance` is zero, revert.
            if iszero(instance) {
                // Store the function selector of `DeploymentFailed()`.
                mstore(0x00, 0x30116425)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Restore the overwritten memory surrounding `data`.
            mstore(dataEnd, mAfter1)
            mstore(data, dataLength)
            mstore(sub(data, 0x20), mBefore1)
            mstore(sub(data, 0x40), mBefore2)
        }
    }

    /**
     * @dev Returns the initialization code hash of the clone of `implementation`
     * using immutable arguments encoded in `data`.
     * Used for mining vanity addresses with create2crunch.
     * @param implementation The address of the implementation contract.
     * @param data The encoded immutable arguments.
     * @return hash The initialization code hash.
     */
    function initCodeHash(address implementation, bytes memory data) internal pure returns (bytes32 hash) {
        assembly {
            // Compute the boundaries of the data and cache the memory slots around it.
            let mBefore2 := mload(sub(data, 0x40))
            let mBefore1 := mload(sub(data, 0x20))
            let dataLength := mload(data)
            let dataEnd := add(add(data, 0x20), dataLength)
            let mAfter1 := mload(dataEnd)

            // +2 bytes for telling how much data there is appended to the call.
            let extraLength := add(dataLength, 2)
            // The `creationSize` is `extraLength + 63`
            // The `runSize` is `creationSize - 10`.

            // if `extraLength` is greater than `0xffca` revert as the `creationSize` would be greater than `0xffff`.
            if gt(extraLength, 0xffca) {
                // Store the function selector of `PackedDataTooBig()`.
                mstore(0x00, 0xc8c78139)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Write the bytecode before the data.
            mstore(data, 0x5af43d3d93803e603357fd5bf3)
            // Write the address of the implementation.
            mstore(sub(data, 0x0d), implementation)
            mstore(
                sub(data, 0x21),
                or(
                    shl(0xd8, add(extraLength, 0x35)),
                    or(shl(0x48, extraLength), 0x6100003d81600a3d39f3363d3d373d3d3d3d610000806035363936013d73)
                )
            )
            mstore(dataEnd, shl(0xf0, extraLength))

            // Create the instance.
            hash := keccak256(sub(data, 0x1f), add(extraLength, 0x3f))

            // Restore the overwritten memory surrounding `data`.
            mstore(dataEnd, mAfter1)
            mstore(data, dataLength)
            mstore(sub(data, 0x20), mBefore1)
            mstore(sub(data, 0x40), mBefore2)
        }
    }

    /**
     * @dev Returns the address of the deterministic clone of
     * `implementation` using immutable arguments encoded in `data`, with `salt`, by `deployer`.
     * @param implementation The address of the implementation.
     * @param data The immutable arguments of the implementation.
     * @param salt The salt used to compute the address.
     * @param deployer The address of the deployer.
     * @return predicted The predicted address.
     */
    function predictDeterministicAddress(address implementation, bytes memory data, bytes32 salt, address deployer)
        internal
        pure
        returns (address predicted)
    {
        bytes32 hash = initCodeHash(implementation, data);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /**
     * @dev Returns the address when a contract with initialization code hash,
     * `hash`, is deployed with `salt`, by `deployer`.
     * @param hash The initialization code hash.
     * @param salt The salt used to compute the address.
     * @param deployer The address of the deployer.
     * @return predicted The predicted address.
     */
    function predictDeterministicAddress(bytes32 hash, bytes32 salt, address deployer)
        internal
        pure
        returns (address predicted)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the boundaries of the data and cache the memory slots around it.
            let mBefore := mload(0x35)

            // Compute and store the bytecode hash.
            mstore8(0x00, 0xff) // Write the prefix.
            mstore(0x35, hash)
            mstore(0x01, shl(96, deployer))
            mstore(0x15, salt)
            predicted := keccak256(0x00, 0x55)

            // Restore the part of the free memory pointer that has been overwritten.
            mstore(0x35, mBefore)
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

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

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

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

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

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

interface IRewarder {
    function getToken() external view returns (IERC20);

    function getCaller() external view returns (address);

    function initialize(address initialOwner) external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

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

interface IBribeRewarder is IRewarder {
    error BribeRewarder__OnlyVoter();
    error BribeRewarder__InsufficientFunds();
    error BribeRewarder__WrongStartId();
    error BribeRewarder__WrongEndId();
    error BribeRewarder__ZeroReward();
    error BribeRewarder__NativeTransferFailed();
    error BribeRewarder__NotOwner();
    error BribeRewarder__CannotRenounceOwnership();
    error BribeRewarder__NotNativeRewarder();
    error BribeRewarder__AlreadyInitialized();
    error BribeRewarder__PeriodNotFound();
    error BribeRewarder__AmountTooLow();
    error BribeRewarder__OnlyVoterAdmin();

    event Claimed(address indexed account, address indexed pool, uint256 amount);
    event Deposited(uint256 indexed periodId, address indexed account, address indexed pool, uint256 amount);
    event BribeInit(uint256 indexed startId, uint256 indexed lastId, uint256 amountPerPeriod);
    event Swept(IERC20 indexed token, address indexed account, uint256 amount);

    function bribe(uint256 startId, uint256 lastId, uint256 amountPerPeriod) external;

    function claim(address account) external;

    function deposit(uint256 periodId, address account, uint256 deltaAmount) external;

    function getPool() external view returns (address);

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

    function getBribePeriods() external view returns (address pool, uint256[] memory);

    function getStartVotingPeriodId() external view returns (uint256);

    function getLastVotingPeriodId() external view returns (uint256);

    function getAmountPerPeriod() external view returns (uint256);

    function sweep(IERC20 token, address account) external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

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

interface IBaseRewarder is IRewarder {
    error BaseRewarder__NativeTransferFailed();
    error BaseRewarder__InvalidCaller();
    error BaseRewarder__Stopped();
    error BaseRewarder__AlreadyStopped();
    error BaseRewarder__NotNativeRewarder();
    error BaseRewarder__ZeroAmount();
    error BaseRewarder__ZeroReward();
    error BaseRewarder__InvalidDuration();
    error BaseRewarder__InvalidPid(uint256 pid);
    error BaseRewarder__InvalidStartTimestamp(uint256 startTimestamp);
    error BaseRewarder__CannotRenounceOwnership();

    event Claim(address indexed account, IERC20 indexed token, uint256 reward);

    event RewardParameterUpdated(uint256 rewardPerSecond, uint256 startTimestamp, uint256 endTimestamp);

    event Stopped();

    event Swept(IERC20 indexed token, address indexed account, uint256 amount);

    function getToken() external view returns (IERC20);

    function getCaller() external view returns (address);

    function getPid() external view returns (uint256);

    function getRewarderParameter()
        external
        view
        returns (IERC20 token, uint256 rewardPerSecond, uint256 lastUpdateTimestamp, uint256 endTimestamp);

    function getRemainingReward() external view returns (uint256);

    function getPendingReward(address account, uint256 balance, uint256 totalSupply)
        external
        view
        returns (IERC20 token, uint256 pendingReward);

    function isStopped() external view returns (bool);

    function initialize(address initialOwner) external;

    function setRewardPerSecond(uint256 maxRewardPerSecond, uint256 expectedDuration)
        external
        returns (uint256 rewardPerSecond);

    function setRewarderParameters(uint256 maxRewardPerSecond, uint256 startTimestamp, uint256 expectedDuration)
        external
        returns (uint256 rewardPerSecond);

    function stop() external;

    function sweep(IERC20 token, address account) external;

    function onModify(address account, uint256 pid, uint256 oldBalance, uint256 newBalance, uint256 totalSupply)
        external
        returns (uint256);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

import {IRewarder} from "../interfaces/IRewarder.sol";
import {IBribeRewarder} from "../interfaces/IBribeRewarder.sol";
import {IBaseRewarder} from "../interfaces/IBaseRewarder.sol";

interface IRewarderFactory {
    error RewarderFactory__ZeroAddress();
    error RewarderFactory__InvalidRewarderType();
    error RewarderFactory__InvalidPid();
    error RewarderFactory__TokenNotWhitelisted();
    error RewarderFactory__InvalidLength();

    enum RewarderType {
        InvalidRewarder,
        MasterChefRewarder,
        BribeRewarder
    }

    event RewarderCreated(
        RewarderType indexed rewarderType, IERC20 indexed token, uint256 indexed pid, IBaseRewarder rewarder
    );

    event BribeRewarderCreated(
        RewarderType indexed rewarderType, IERC20 indexed token, address indexed pool, IBribeRewarder rewarder
    );

    event RewarderImplementationSet(RewarderType indexed rewarderType, IRewarder indexed implementation);

    function getBribeCreatorFee() external view returns (uint256);

    function getWhitelistedTokenInfo (address token) external view returns (bool, uint256);

    function getRewarderImplementation(RewarderType rewarderType) external view returns (IRewarder);

    function getRewarderCount(RewarderType rewarderType) external view returns (uint256);

    function getRewarderAt(RewarderType rewarderType, uint256 index) external view returns (IRewarder);

    function getRewarderType(IRewarder rewarder) external view returns (RewarderType);

    function setRewarderImplementation(RewarderType rewarderType, IRewarder implementation) external;

    function createRewarder(RewarderType rewarderType, IERC20 token, uint256 pid) external returns (IBaseRewarder);

    function createBribeRewarder(IERC20 token, address pool) external returns (IBribeRewarder);

    function setWhitelist(address[] calldata tokens, uint256[] calldata minBribeAmounts) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.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.
 *
 * The initial owner is set to the address provided by the deployer. 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 OwnableUpgradeable is Initializable, ContextUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Ownable
    struct OwnableStorage {
        address _owner;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;

    function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
        assembly {
            $.slot := OwnableStorageLocation
        }
    }

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    function __Ownable_init(address initialOwner) internal onlyInitializing {
        __Ownable_init_unchained(initialOwner);
    }

    function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

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

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

pragma solidity ^0.8.20;

/**
 * @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]
 * ```solidity
 * 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 Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

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

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._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() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

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

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

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

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

Context size (optional):