Sonic Blaze Testnet

Contract Diff Checker

Contract Name:
LauncherPlugin

Contract Source Code:

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.24;

import {ILauncherPlugin} from "./interfaces/ILauncherPlugin.sol";
import {IVoter} from "./interfaces/IVoter.sol";

/// @author ShadowDEX on Sonic
/// @title LauncherPlugins contract for modular plug-n-play with Sonic memes
/** @dev There are two trusted roles in the LauncherPlugin system
 * Authority: Whitelisted external launchers, e.g. DegenExpress
 * Operator: Shadow operational multisig, or other timelocked/secure system
 * AccessHub: central authority management contract
 * These roles are to be managed securely, and with diligence to prevent abuse
 * However, the system already has checks in place to mitigate any possible abuse situations ahead of time
 */
contract LauncherPlugin is ILauncherPlugin {
    /// @inheritdoc ILauncherPlugin
    address public accessHub;
    /// @inheritdoc ILauncherPlugin
    address public operator;

    /// @notice the voter contract
    IVoter public immutable voter;

    /// @inheritdoc ILauncherPlugin
    mapping(address pool => bool isEnabled) public launcherPluginEnabled;
    /// @inheritdoc ILauncherPlugin
    mapping(address pool => LauncherConfigs) public poolConfigs;
    /// @inheritdoc ILauncherPlugin
    mapping(address pool => address feeDist) public feeDistToPool;
    /// @inheritdoc ILauncherPlugin
    mapping(address who => bool authority) public authorityMap;
    /// @inheritdoc ILauncherPlugin
    mapping(address authority => string name) public nameOfAuthority;

    /// @inheritdoc ILauncherPlugin
    uint256 public constant DENOM = 10_000;

    modifier onlyAuthority() {
        /// @dev authority check of either the operator of authority in the mapping
        require(
            authorityMap[msg.sender] || msg.sender == accessHub,
            NOT_AUTHORITY()
        );
        _;
    }

    modifier onlyOperator() {
        /// @dev redundant `operator` address put here as a safeguard for input errors on transferring roles
        require(
            msg.sender == accessHub || msg.sender == operator,
            NOT_OPERATOR()
        );
        _;
    }

    constructor(address _voter, address _accessHub, address _operator) {
        /// @dev initialize the voter
        voter = IVoter(_voter);
        /// @dev operator and team initially are the same
        accessHub = _accessHub;
        operator = _operator;
    }

    /// @inheritdoc ILauncherPlugin
    /// @dev should be called by another contract with proper batching of function calls
    function setConfigs(
        address _pool,
        uint256 _take,
        address _recipient
    ) external onlyAuthority {
        /// @dev ensure launcherPlugins are enabled
        require(launcherPluginEnabled[_pool], NOT_ENABLED());
        /// @dev ensure the fee is <= 100%
        require(_take <= DENOM, INVALID_TAKE());
        /// @dev store launcher configs in pool to struct mapping
        LauncherConfigs memory lc = LauncherConfigs(_take, _recipient);
        /// @dev store the pool configs in the mapping
        poolConfigs[_pool] = lc;
        /// @dev emit an event for configuration
        emit Configured(_pool, _take, _recipient);
    }
    /// @inheritdoc ILauncherPlugin
    /// @dev should be called by another contract with proper batching of function calls
    function enablePool(address _pool) external onlyAuthority {
        /// @dev require that the plugin is enabled
        require(!launcherPluginEnabled[_pool], ENABLED());
        /// @dev fetch the feeDistributor address
        address _feeDist = voter.feeDistributorForGauge(
            voter.gaugeForPool(_pool)
        );
        /// @dev set the feeDist for the pool
        feeDistToPool[_feeDist] = _pool;
        launcherPluginEnabled[_pool] = true;
        /// @dev emit with the name of the authority
        emit EnabledPool(_pool, nameOfAuthority[msg.sender]);
    }
    /// @inheritdoc ILauncherPlugin
    function migratePool(address _oldPool, address _newPool) external {
        require(
            msg.sender == address(voter) || msg.sender == operator,
            IVoter.NOT_AUTHORIZED(msg.sender)
        );
        require(launcherPluginEnabled[_oldPool], NOT_ENABLED());
        launcherPluginEnabled[_newPool] = true;
        /// @dev fetch the feedists for each pool
        (address _feeDist, address _newFeeDist) = (
            voter.feeDistributorForGauge(voter.gaugeForPool(_oldPool)),
            voter.feeDistributorForGauge(voter.gaugeForPool(_newPool))
        );
        /// @dev set the new pool's feedist
        feeDistToPool[_newFeeDist] = _newPool;
        /// @dev copy over the values
        poolConfigs[_newPool] = poolConfigs[_oldPool];
        /// @dev delete old values
        delete poolConfigs[_oldPool];
        /// @dev set to disabled
        launcherPluginEnabled[_oldPool] = false;
        /// @dev set the old fee dist to the new one as a safety measure
        feeDistToPool[_feeDist] = feeDistToPool[_newFeeDist];

        emit MigratedPool(_oldPool, _newPool);
    }
    /// @inheritdoc ILauncherPlugin
    function disablePool(address _pool) external onlyOperator {
        /// @dev require the plugin is already enabled
        require(launcherPluginEnabled[_pool], NOT_ENABLED());
        /// @dev wipe struct
        delete poolConfigs[_pool];
        /// @dev wipe the mapping for feeDist to the pool, incase the feeDist is overwritten
        delete feeDistToPool[
            voter.feeDistributorForGauge(voter.gaugeForPool(_pool))
        ];
        /// @dev set to disabled
        launcherPluginEnabled[_pool] = false;
        /// @dev emit an event
        emit DisabledPool(_pool);
    }
    /// @inheritdoc ILauncherPlugin
    function setOperator(address _newOperator) external onlyOperator {
        /// @dev ensure the new operator is not already the operator
        require(operator != _newOperator, ALREADY_OPERATOR());
        /// @dev store the oldOperator to use in the event, for info purposes
        address oldOperator = operator;
        /// @dev set operator as the new operator
        operator = _newOperator;
        /// @dev emit operator change event
        emit NewOperator(oldOperator, operator);
    }

    /// @inheritdoc ILauncherPlugin
    function grantAuthority(
        address _newAuthority,
        string calldata _name
    ) external onlyOperator {
        /// @dev ensure the proposed _newAuthority is not already one
        require(!authorityMap[_newAuthority], ALREADY_AUTHORITY());
        /// @dev set the mapping to true
        authorityMap[_newAuthority] = true;
        /// @dev emit the new authority event
        emit NewAuthority(_newAuthority);
        /// @dev label the authority
        _labelAuthority(_newAuthority, _name);
    }

    /// @inheritdoc ILauncherPlugin
    function revokeAuthority(address _oldAuthority) external onlyOperator {
        /// @dev ensure _oldAuthority is already an authority
        require(authorityMap[_oldAuthority], NOT_AUTHORITY());
        /// @dev set the mapping to false
        authorityMap[_oldAuthority] = false;
        /// @dev emit the remove authority event
        emit RemovedAuthority(_oldAuthority);
    }
    /// @inheritdoc ILauncherPlugin
    function label(
        address _authority,
        string calldata _label
    ) external onlyOperator {
        _labelAuthority(_authority, _label);
    }

    /// @inheritdoc ILauncherPlugin
    function values(
        address _feeDist
    ) external view returns (uint256 _take, address _recipient) {
        /// @dev fetch the poolConfigs from the mapping
        LauncherConfigs memory _tmp = poolConfigs[feeDistToPool[_feeDist]];
        /// @dev return the existing values
        return (_tmp.launcherTake, _tmp.takeRecipient);
    }

    /// @dev internal function called on creation and manually
    function _labelAuthority(
        address _authority,
        string calldata _label
    ) internal {
        /// @dev ensure they are an authority
        require(authorityMap[_authority]);
        /// @dev label the authority
        nameOfAuthority[_authority] = _label;
        /// @dev emit on label
        emit Labeled(_authority, _label);
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.24;

interface ILauncherPlugin {
    error NOT_AUTHORITY();
    error ALREADY_AUTHORITY();
    error NOT_OPERATOR();
    error ALREADY_OPERATOR();
    error NOT_ENABLED();
    error ENABLED();
    error INVALID_TAKE();

    /// @dev struct that holds the configurations of each specific pool
    struct LauncherConfigs {
        uint256 launcherTake;
        address takeRecipient;
    }

    event NewOperator(address indexed _old, address indexed _new);

    event NewAuthority(address indexed _newAuthority);
    event RemovedAuthority(address indexed _previousAuthority);

    event EnabledPool(address indexed pool, string indexed _name);
    event DisabledPool(address indexed pool);
    event MigratedPool(address indexed oldPool, address indexed newPool);
    event Configured(
        address indexed pool,
        uint256 take,
        address indexed recipient
    );

    event Labeled(address indexed authority, string indexed label);

    /// @notice address of the accessHub
    function accessHub() external view returns (address _accessHub);
    /// @notice protocol operator address
    function operator() external view returns (address _operator);

    /// @notice the denominator constant
    function DENOM() external view returns (uint256 _denominator);

    /// @notice whether configs are enabled for a pool
    /// @param _pool address of the pool
    /// @return bool
    function launcherPluginEnabled(address _pool) external view returns (bool);

    /// @notice maps whether an address is an authority or not
    /// @param _who the address to check
    /// @return _is true or false
    function authorityMap(address _who) external view returns (bool _is);

    /// @notice allows migrating the parameters from one pool to the other
    /// @param _oldPool the current address of the pair
    /// @param _newPool the new pool's address
    function migratePool(address _oldPool, address _newPool) external;

    /// @notice fetch the launcher configs if any
    /// @param _pool address of the pool
    /// @return LauncherConfigs the configs
    function poolConfigs(
        address _pool
    ) external view returns (uint256, address);
    /// @notice view functionality to see who is an authority
    function nameOfAuthority(address) external view returns (string memory);

    /// @notice returns the pool address for a feeDist
    /// @param _feeDist address of the feeDist
    /// @return _pool the pool address from the mapping
    function feeDistToPool(
        address _feeDist
    ) external view returns (address _pool);

    /// @notice set launcher configurations for a pool
    /// @param _pool address of the pool
    /// @param _take the fee that goes to the designated recipient
    /// @param _recipient the address that receives the fees
    function setConfigs(
        address _pool,
        uint256 _take,
        address _recipient
    ) external;

    /// @notice enables the pool for LauncherConfigs
    /// @param _pool address of the pool
    function enablePool(address _pool) external;

    /// @notice disables the pool for LauncherConfigs
    /// @dev clears mappings
    /// @param _pool address of the pool
    function disablePool(address _pool) external;

    /// @notice sets a new operator address
    /// @param _newOperator new operator address
    function setOperator(address _newOperator) external;

    /// @notice gives authority to a new contract/address
    /// @param _newAuthority the suggested new authority
    function grantAuthority(address _newAuthority, string calldata) external;

    /// @notice removes authority from a contract/address
    /// @param _oldAuthority the to-be-removed authority
    function revokeAuthority(address _oldAuthority) external;

    /// @notice labels an authority
    function label(address, string calldata) external;

    /// @notice returns the values for the launcherConfig of the specific feeDist
    /// @param _feeDist the address of the feeDist
    /// @return _launcherTake fee amount taken
    /// @return _recipient address that receives the fees
    function values(
        address _feeDist
    ) external view returns (uint256 _launcherTake, address _recipient);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.26;
pragma abicoder v2;

interface IVoter {
    error ACTIVE_GAUGE(address gauge);

    error GAUGE_INACTIVE(address gauge);

    error ALREADY_WHITELISTED();

    error NOT_AUTHORIZED(address caller);

    error NOT_WHITELISTED();

    error NOT_POOL();

    error FORBIDDEN();

    error NOT_INIT();

    error LENGTH_MISMATCH();

    error NO_GAUGE();

    error ALREADY_DISTRIBUTED(address gauge, uint256 period);

    error ZERO_VOTE(address pool);

    error RATIO_TOO_HIGH();

    error NOT_GT_ZERO();

    error VOTE_UNSUCCESSFUL();

    error UNAUTHORIZED();

    event GaugeCreated(
        address indexed gauge,
        address creator,
        address feeDistributor,
        address indexed pool
    );

    event GaugeKilled(address indexed gauge);

    event GaugeRevived(address indexed gauge);

    event Voted(address indexed owner, uint256 weight, address indexed pool);

    event Abstained(address indexed owner, uint256 weight);

    event Deposit(
        address indexed lp,
        address indexed gauge,
        address indexed owner,
        uint256 amount
    );

    event Withdraw(
        address indexed lp,
        address indexed gauge,
        address indexed owner,
        uint256 amount
    );

    event NotifyReward(
        address indexed sender,
        address indexed reward,
        uint256 amount
    );

    event DistributeReward(
        address indexed sender,
        address indexed gauge,
        uint256 amount
    );

    event EmissionsRatio(
        address indexed caller,
        uint256 oldRatio,
        uint256 newRatio
    );

    event NewGovernor(address indexed sender, address indexed governor);

    event Whitelisted(address indexed whitelister, address indexed token);

    event WhitelistRevoked(
        address indexed forbidder,
        address indexed token,
        bool status
    );

    event CustomGaugeCreated(
        address indexed gauge,
        address creator,
        address indexed token
    );

    event MainTickSpacingChanged(
        address indexed token0,
        address indexed token1,
        int24 indexed newMainTickSpacing
    );

    /// @notice returns the address of the current governor
    /// @return _governor address of the governor
    function governor() external view returns (address _governor);
    /// @notice the address of the vote module
    /// @return _voteModule the vote module contract address
    function voteModule() external view returns (address _voteModule);

    /// @notice the address of the shadow launcher plugin to enable third party launchers
    /// @return _launcherPlugin the address of the plugin
    function launcherPlugin() external view returns (address _launcherPlugin);

    /// @notice distributes emissions from the minter to the voter
    /// @param amount the amount of tokens to notify
    function notifyRewardAmount(uint256 amount) external;

    /// @notice distributes the emissions for a specific gauge
    /// @param _gauge the gauge address
    function distribute(address _gauge) external;

    /// @notice returns the address of the gauge factory
    /// @param _gaugeFactory gauge factory address
    function gaugeFactory() external view returns (address _gaugeFactory);

    /// @notice returns the address of the feeDistributor factory
    /// @return _feeDistributorFactory feeDist factory address
    function feeDistributorFactory()
        external
        view
        returns (address _feeDistributorFactory);

    /// @notice returns the address of the minter contract
    /// @return _minter address of the minter
    function minter() external view returns (address _minter);

    /// @notice check if the gauge is active for governance use
    /// @param _gauge address of the gauge
    /// @return _trueOrFalse if the gauge is alive
    function isAlive(address _gauge) external view returns (bool _trueOrFalse);

    /// @notice allows the token to be paired with other whitelisted assets to participate in governance
    /// @param _token the address of the token
    function whitelist(address _token) external;

    /// @notice effectively disqualifies a token from governance
    /// @param _token the address of the token
    function revokeWhitelist(address _token) external;

    /// @notice returns if the address is a gauge
    /// @param gauge address of the gauge
    /// @return _trueOrFalse boolean if the address is a gauge
    function isGauge(address gauge) external view returns (bool _trueOrFalse);

    /// @notice disable a gauge from governance
    /// @param _gauge address of the gauge
    function killGauge(address _gauge) external;

    /// @notice re-activate a dead gauge
    /// @param _gauge address of the gauge
    function reviveGauge(address _gauge) external;

    /// @notice re-cast a tokenID's votes
    /// @param owner address of the owner
    function poke(address owner) external;

    /// @notice sets the main tickspacing of a token pairing
    /// @param tokenA address of tokenA
    /// @param tokenB address of tokenB
    /// @param tickSpacing the main tickspacing to set to
    function setMainTickSpacing(
        address tokenA,
        address tokenB,
        int24 tickSpacing
    ) external;

    /// @notice create a legacy-type gauge for an arbitrary token
    /// @param _token 'token' to be used
    /// @return _arbitraryGauge the address of the new custom gauge
    function createArbitraryGauge(
        address _token
    ) external returns (address _arbitraryGauge);

    /// @notice returns if the address is a fee distributor
    /// @param _feeDistributor address of the feeDist
    /// @return _trueOrFalse if the address is a fee distributor
    function isFeeDistributor(
        address _feeDistributor
    ) external view returns (bool _trueOrFalse);

    /// @notice returns the address of the emission's token
    /// @return _emissionsToken emissions token contract address
    function emissionsToken() external view returns (address _emissionsToken);

    /// @notice returns the address of the pool's gauge, if any
    /// @param _pool pool address
    /// @return _gauge gauge address
    function gaugeForPool(address _pool) external view returns (address _gauge);

    /// @notice returns the address of the pool's feeDistributor, if any
    /// @param _gauge address of the gauge
    /// @return _feeDistributor address of the pool's feedist
    function feeDistributorForGauge(
        address _gauge
    ) external view returns (address _feeDistributor);

    /// @notice returns the new toPool that was redirected fromPool
    /// @param fromPool address of the original pool
    /// @return toPool the address of the redirected pool
    function poolRedirect(
        address fromPool
    ) external view returns (address toPool);

    /// @notice returns the gauge address of a CL pool
    /// @param tokenA address of token A in the pair
    /// @param tokenB address of token B in the pair
    /// @param tickSpacing tickspacing of the pool
    /// @return gauge address of the gauge
    function gaugeForClPool(
        address tokenA,
        address tokenB,
        int24 tickSpacing
    ) external view returns (address gauge);

    /// @notice returns the array of all tickspacings for the tokenA/tokenB combination
    /// @param tokenA address of token A in the pair
    /// @param tokenB address of token B in the pair
    /// @return _ts array of all the tickspacings
    function tickSpacingsForPair(
        address tokenA,
        address tokenB
    ) external view returns (int24[] memory _ts);

    /// @notice returns the main tickspacing used in the gauge/governance process
    /// @param tokenA address of token A in the pair
    /// @param tokenB address of token B in the pair
    /// @return _ts the main tickspacing
    function mainTickSpacingForPair(
        address tokenA,
        address tokenB
    ) external view returns (int24 _ts);

    /// @notice returns the block.timestamp divided by 1 week in seconds
    /// @return period the period used for gauges
    function getPeriod() external view returns (uint256 period);

    /// @notice cast a vote to direct emissions to gauges and earn incentives
    /// @param owner address of the owner
    /// @param _pools the list of pools to vote on
    /// @param _weights an arbitrary weight per pool which will be normalized to 100% regardless of numerical inputs
    function vote(
        address owner,
        address[] calldata _pools,
        uint256[] calldata _weights
    ) external;

    /// @notice reset the vote of an address
    /// @param owner address of the owner
    function reset(address owner) external;

    /// @notice set the governor address
    /// @param _governor the new governor address
    function setGovernor(address _governor) external;

    /// @notice recover stuck emissions
    /// @param _gauge the gauge address
    /// @param _period the period
    function stuckEmissionsRecovery(address _gauge, uint256 _period) external;

    /// @notice whitelists extra rewards for a gauge
    /// @param _gauge the gauge to whitelist rewards to
    /// @param _reward the reward to whitelist
    function whitelistGaugeRewards(address _gauge, address _reward) external;

    /// @notice removes a reward from the gauge whitelist
    /// @param _gauge the gauge to remove the whitelist from
    /// @param _reward the reward to remove from the whitelist
    function removeGaugeRewardWhitelist(
        address _gauge,
        address _reward
    ) external;

    /// @notice creates a legacy gauge for the pool
    /// @param _pool pool's address
    /// @return _gauge address of the new gauge
    function createGauge(address _pool) external returns (address _gauge);

    /// @notice create a concentrated liquidity gauge
    /// @param tokenA the address of tokenA
    /// @param tokenB the address of tokenB
    /// @param tickSpacing the tickspacing of the pool
    /// @return _clGauge address of the new gauge
    function createCLGauge(
        address tokenA,
        address tokenB,
        int24 tickSpacing
    ) external returns (address _clGauge);

    /// @notice claim concentrated liquidity gauge rewards for specific NFP token ids
    /// @param _gauges array of gauges
    /// @param _tokens two dimensional array for the tokens to claim
    /// @param _nfpTokenIds two dimensional array for the NFPs
    function claimClGaugeRewards(
        address[] calldata _gauges,
        address[][] calldata _tokens,
        uint256[][] calldata _nfpTokenIds
    ) external;

    /// @notice claim arbitrary rewards from specific feeDists
    /// @param owner address of the owner
    /// @param _feeDistributors address of the feeDists
    /// @param _tokens two dimensional array for the tokens to claim
    function claimIncentives(
        address owner,
        address[] calldata _feeDistributors,
        address[][] calldata _tokens
    ) external;

    /// @notice claim arbitrary rewards from specific gauges
    /// @param _gauges address of the gauges
    /// @param _tokens two dimensional array for the tokens to claim
    function claimRewards(
        address[] calldata _gauges,
        address[][] calldata _tokens
    ) external;

    /// @notice distribute emissions to a gauge for a specific period
    /// @param _gauge address of the gauge
    /// @param _period value of the period
    function distributeForPeriod(address _gauge, uint256 _period) external;

    /// @notice attempt distribution of emissions to all gauges
    function distributeAll() external;

    /// @notice distribute emissions to gauges by index
    /// @param startIndex start of the loop
    /// @param endIndex end of the loop
    function batchDistributeByIndex(
        uint256 startIndex,
        uint256 endIndex
    ) external;

    /// @notice returns the votes cast for a tokenID
    /// @param owner address of the owner
    /// @return votes an array of votes casted
    /// @return weights an array of the weights casted per pool
    function getVotes(
        address owner,
        uint256 period
    ) external view returns (address[] memory votes, uint256[] memory weights);

    /// @notice returns an array of all the gauges
    /// @return _gauges the array of gauges
    function getAllGauges() external view returns (address[] memory _gauges);

    /// @notice returns an array of all the feeDists
    /// @return _feeDistributors the array of feeDists
    function getAllFeeDistributors()
        external
        view
        returns (address[] memory _feeDistributors);

    /// @notice sets the xShadowRatio default
    function setGlobalRatio(uint256 _xRatio) external;

    /// @notice returns the array of all custom/arbitrary pools
    function getAllCustomPools()
        external
        view
        returns (address[] memory _customPools);

    /// @notice whether the token is whitelisted in governance
    function isWhitelisted(address _token) external view returns (bool _tf);

    /// @notice function for removing malicious or stuffed tokens
    function removeFeeDistributorReward(
        address _feeDist,
        address _token
    ) external;
}

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

Context size (optional):