ETH Price: $2,123.74 (+7.15%)
Gas: 0.07 Gwei

Contract

0xFe702e86FF008Cd21068ddd9f50dcB64eEc1d2e7
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Epoch Manage...191402172024-02-02 10:48:47761 days ago1706870927IN
0xFe702e86...4eEc1d2e7
0 ETH0.0010527422.29351273

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LiquidateNegativeCollectionManualTrigger

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
london EvmVersion
File 1 of 20 : LiquidateNegativeCollectionManual.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {EpochManaged} from '@floor/utils/EpochManaged.sol';
import {CannotSetNullAddress} from '@floor/utils/Errors.sol';

import {StrategyFactory} from '@floor/strategies/StrategyFactory.sol';

import {IEpochEndTriggered} from '@floor-interfaces/utils/EpochEndTriggered.sol';
import {ISweepWars} from '@floor-interfaces/voting/SweepWars.sol';

/**
 * When an epoch ends, the vote with the most negative votes will be liquidated to an amount
 * relative to the number of negative votes it received. The amounts will be transferred to
 * the {Treasury} and will need to be subsequently liquidated by a trusted TREASURY_MANAGER.
 */
contract LiquidateNegativeCollectionManualTrigger is EpochManaged, IEpochEndTriggered {

    /// Event fired when losing collection strategy is liquidated
    event CollectionTokensLiquidated(address _worstCollection, address[] _strategies, uint _percentage);

    /// The sweep war contract used by this contract
    ISweepWars public immutable sweepWars;

    /// Internal strategies
    StrategyFactory public immutable strategyFactory;

    /// A threshold percentage that would be worth us working with
    uint public constant THRESHOLD = 1_000; // 1%

    /**
     * Sets our internal contracts.
     */
    constructor(address _sweepWars, address _strategyFactory) {
        // Prevent any zero-address contracts from being set
        if (_sweepWars == address(0) || _strategyFactory == address(0)) {
            revert CannotSetNullAddress();
        }

        sweepWars = ISweepWars(_sweepWars);
        strategyFactory = StrategyFactory(_strategyFactory);
    }

    /**
     * When the epoch ends, we check to see if any collections received negative votes. If
     * we do, then we find the collection with the most negative votes and liquidate a percentage
     * of the position for that collection based on a formula.
     */
    function endEpoch(uint /* epoch */) external onlyEpochManager {
        address worstCollection;
        int negativeCollectionVotes;
        int grossVotes;

        // Get a list of all collections that are part of the vote
        address[] memory collectionAddrs = sweepWars.voteOptions();

        // Get the number of collections to save gas in loops
        uint length = collectionAddrs.length;

        // Iterate over our collections and get the votes
        for (uint i; i < length;) {
            // Get the number of votes at the current epoch that is closing
            int votes = sweepWars.votes(collectionAddrs[i]);

            // If we have less votes, update our worst collection
            if (votes < negativeCollectionVotes) {
                negativeCollectionVotes = votes;
                worstCollection = collectionAddrs[i];
            }

            // Keep track of the gross number of votes for calculation purposes
            grossVotes += (votes >= 0) ? votes : -votes;

            unchecked {
                ++i;
            }
        }

        // If we have no gross votes, then we cannot calculate a percentage
        if (grossVotes == 0) {
            return;
        }

        // We then need to calculate the amount we exit our position by, depending on the number
        // of negative votes.
        uint percentage = uint(((negativeCollectionVotes * 10000) / grossVotes) * -1);

        // Ensure we have a negative vote that is past a threshold
        if (percentage < THRESHOLD) {
            return;
        }

        // We need to determine the holdings across our strategies and exit our positions sufficiently
        // and then subsequently sell against this position for ETH.
        address[] memory strategies = strategyFactory.collectionStrategies(worstCollection);
        emit CollectionTokensLiquidated(worstCollection, strategies, percentage);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';

import {CannotSetNullAddress} from '@floor/utils/Errors.sol';

import {IEpochManager} from '@floor-interfaces/EpochManager.sol';

abstract contract EpochManaged is Ownable {
    /// Emits when {EpochManager} is updated
    event EpochManagerUpdated(address epochManager);

    /// Stores the current {EpochManager} contract
    IEpochManager public epochManager;

    /**
     * Allows an updated {EpochManager} address to be set.
     */
    function setEpochManager(address _epochManager) external virtual onlyOwner {
        _setEpochManager(_epochManager);
    }

    /**
     * Allows an updated {EpochManager} address to be set by an inheriting contract.
     */
    function _setEpochManager(address _epochManager) internal virtual {
        if (_epochManager == address(0)) revert CannotSetNullAddress();
        epochManager = IEpochManager(_epochManager);
        emit EpochManagerUpdated(_epochManager);
    }

    /**
     * Gets the current epoch from our {EpochManager}.
     */
    function currentEpoch() internal view virtual returns (uint) {
        return epochManager.currentEpoch();
    }

    /**
     * Checks that the contract caller is the {EpochManager}.
     */
    modifier onlyEpochManager() {
        require(msg.sender == address(epochManager), 'Only EpochManager can call');
        _;
    }
}

File 3 of 20 : Errors.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

/**
 * A collection of generic errors that can be referenced across multiple
 * contracts. Contract-specific errors should still be stored in their
 * individual Solidity files.
 */

/// If a NULL address tries to be stored which should not be accepted
error CannotSetNullAddress();

/// If the caller has entered an insufficient amount to process the action. This
/// will likely be a zero amount.
error InsufficientAmount();

/// If the caller enters a percentage value that is too high for the requirements
error PercentageTooHigh(uint amount);

/// If a required ETH or token `transfer` call fails
error TransferFailed();

/// If a user calls a deposit related function with a zero amount
error CannotDepositZeroAmount();

/// If a user calls a withdrawal related function with a zero amount
error CannotWithdrawZeroAmount();

/// If there are no rewards available to be claimed
error NoRewardsAvailableToClaim();

/// If the requested collection is not approved
/// @param collection Address of the collection requested
error CollectionNotApproved(address collection);

/// If the requested strategy implementation is not approved
/// @param strategyImplementation Address of the strategy implementation requested
error StrategyNotApproved(address strategyImplementation);

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
import {Clones} from '@openzeppelin/contracts/proxy/Clones.sol';

import {AuthorityControl} from '@floor/authorities/AuthorityControl.sol';
import {CannotSetNullAddress, CollectionNotApproved, StrategyNotApproved} from '@floor/utils/Errors.sol';

import {ICollectionRegistry} from '@floor-interfaces/collections/CollectionRegistry.sol';
import {IBaseStrategy} from '@floor-interfaces/strategies/BaseStrategy.sol';
import {IStrategyFactory} from '@floor-interfaces/strategies/StrategyFactory.sol';
import {IStrategyRegistry} from '@floor-interfaces/strategies/StrategyRegistry.sol';
import {ITreasury} from '@floor-interfaces/Treasury.sol';

// No empty names, that's just silly
error StrategyNameCannotBeEmpty();

/**
 * Allows for strategies to be created, pairing them with an approved collection. The strategy
 * creation script needs to be as highly optimised as possible to ensure that the gas
 * costs are kept down.
 *
 * This factory will keep an index of created strategies and secondary information to ensure
 * that external applications can display and maintain a list of available strategies.
 */
contract StrategyFactory is AuthorityControl, IStrategyFactory {
    /// Maintains an array of all strategies created
    address[] private _strategies;

    /// Store our Treasury address
    address public treasury;

    /// Contract mappings to our approved collections
    ICollectionRegistry public immutable collectionRegistry;

    /// Contract mappings to our approved strategy implementations
    IStrategyRegistry public immutable strategyRegistry;

    /// Mappings to aide is discoverability
    mapping(uint => address) private _strategyIds;

    /// Mapping of collection to strategy addresses
    mapping(address => address[]) private _collectionStrategies;

    /// Stores a list of bypassed strategies
    mapping(address => bool) private _bypassStrategy;

    /**
     * Store our registries, mapped to their interfaces.
     *
     * @param _authority {AuthorityRegistry} contract address
     * @param _collectionRegistry Address of our {CollectionRegistry}
     */
    constructor(address _authority, address _collectionRegistry, address _strategyRegistry) AuthorityControl(_authority) {
        if (_collectionRegistry == address(0)) revert CannotSetNullAddress();
        if (_strategyRegistry == address(0)) revert CannotSetNullAddress();

        // Type-cast our interfaces and store our registry contracts
        collectionRegistry = ICollectionRegistry(_collectionRegistry);
        strategyRegistry = IStrategyRegistry(_strategyRegistry);
    }

    /**
     * Provides a list of all strategies created.
     *
     * @return Array of all strategies created by the {StrategyFactory}
     */
    function strategies() external view returns (address[] memory) {
        return _strategies;
    }

    /**
     * Returns an array of all strategies that belong to a specific collection.
     *
     * @param _collection The address of the collection to query
     *
     * @return address[] Array of strategy addresses
     */
    function collectionStrategies(address _collection) external view returns (address[] memory) {
        return _collectionStrategies[_collection];
    }

    /**
     * Provides a strategy against the provided `strategyId` (index). If the index does not exist,
     * then address(0) will be returned.
     *
     * @param _strategyId ID of the strategy to retrieve
     *
     * @return Address of the strategy
     */
    function strategy(uint _strategyId) external view returns (address) {
        return _strategyIds[_strategyId];
    }

    /**
     * Creates a strategy with an approved collection.
     *
     * @dev The strategy is not created using Clones as there are complications when
     * allocated roles and permissions.
     *
     * @param _name Human-readable name of the strategy
     * @param _strategy The strategy implemented by the strategy
     * @param _strategyInitData Bytes data required by the {Strategy} for initialization
     * @param _collection The address of the collection attached to the strategy
     *
     * @return strategyId_ ID of the newly created strategy
     * @return strategyAddr_ Address of the newly created strategy
     */
    function deployStrategy(bytes32 _name, address _strategy, bytes calldata _strategyInitData, address _collection)
        external
        onlyRole(STRATEGY_MANAGER)
        returns (uint strategyId_, address strategyAddr_)
    {
        // No empty names, that's just silly
        if (_name == '') revert StrategyNameCannotBeEmpty();

        // Make sure the strategy implementation is approved
        if (!strategyRegistry.isApproved(_strategy)) revert StrategyNotApproved(_strategy);

        // Make sure the collection is approved
        if (!collectionRegistry.isApproved(_collection)) revert CollectionNotApproved(_collection);

        // Capture our `strategyId`, before we increment the array length
        strategyId_ = _strategies.length;

        // Deploy a new {Strategy} instance using the clone mechanic
        strategyAddr_ = Clones.cloneDeterministic(_strategy, bytes32(strategyId_));

        // We then need to instantiate the strategy using our supplied `strategyInitData`
        IBaseStrategy(strategyAddr_).initialize(_name, strategyId_, _strategyInitData);

        // Add our strategies to our internal tracking
        _strategies.push(strategyAddr_);

        // Add our mappings for onchain discoverability
        _strategyIds[strategyId_] = strategyAddr_;
        _collectionStrategies[_collection].push(strategyAddr_);

        // Finally we can emit our event to notify watchers of a new strategy
        emit StrategyCreated(strategyId_, strategyAddr_, _collection);
    }

    /**
     * Allows individual strategies to be paused, meaning that assets can no longer be deposited,
     * although staked assets can always be withdrawn.
     *
     * @dev Events are fired within the strategy to allow listeners to update.
     *
     * @param _strategyId strategy ID to be updated
     * @param _paused If the strategy should be paused or unpaused
     */
    function pause(uint _strategyId, bool _paused) public onlyRole(STRATEGY_MANAGER) {
        IBaseStrategy(_strategyIds[_strategyId]).pause(_paused);
    }

    /**
     * Reads the yield generated by all strategies since the last time that this
     * function was called.
     */
    function snapshot(uint _epoch)
        external
        onlyRole(STRATEGY_MANAGER)
        returns (address[] memory strategies_, uint[] memory amounts_, uint totalAmount_)
    {
        // Get our underlying WETH address
        address weth = address(ITreasury(treasury).weth());

        // Prefine some variables
        address[] memory tokens;
        uint[] memory amounts;
        uint tokensLength;

        // Get the number of strategies and define our returned array lengths
        uint strategiesLength = _strategies.length;
        strategies_ = new address[](strategiesLength);
        amounts_ = new uint[](strategiesLength);

        // Iterate over strategies to pull out yield
        for (uint i; i < strategiesLength;) {
            // Prevent a bypassed strategy from snapshotting
            if (!_bypassStrategy[_strategies[i]]) {
                // Snapshot our strategy
                (tokens, amounts) = IBaseStrategy(_strategies[i]).snapshot();

                // Capture the strategy address, even if we receive no WETH yield
                strategies_[i] = _strategies[i];

                // Iterate over tokens to just find WETH amounts
                tokensLength = tokens.length;
                for (uint l; l < tokensLength;) {
                    // Ensure that we only handle WETH tokens with amounts
                    if (tokens[l] == address(weth) && amounts[l] != 0) {
                        // Capture the WETH yield relative to the strategy
                        amounts_[i] = amounts[l];

                        // Keep a tally of the total amount of WETH earned
                        totalAmount_ += amounts[l];
                    }

                    unchecked { ++l; }
                }
            }

            unchecked { ++i; }
        }

        emit StrategySnapshot(_epoch, strategies_, amounts_);
    }

    /**
     * Harvest available reward yield from the strategy. This won't affect the amount
     * depositted into the contract and should only harvest rewards directly into the
     * {Treasury}.
     *
     * @param _strategyId Strategy ID to be harvested
     */
    function harvest(uint _strategyId) external onlyRole(STRATEGY_MANAGER) {
        if (_bypassStrategy[_strategyIds[_strategyId]]) return;

        IBaseStrategy(_strategyIds[_strategyId]).harvest(treasury);
    }

    /**
     * Makes a call to a strategy withdraw function by passing the strategy ID and
     * `abi.encodeWithSelector` to build the bytes `_data` parameter. This will then
     * pass the data on to the strategy function and inject the treasury recipient
     * address within the call as the first function parameter.
     *
     * @dev It is required for the transaction to return a successful call, otherwise
     * the transaction will be reverted. The error response will be standardised so
     * debugging will require a trace, rather than just the end message.
     *
     * @param _strategyId Strategy ID to be withdrawn from
     * @param _data Strategy withdraw function call, using `encodeWithSelector`
     */
    function withdraw(uint _strategyId, bytes calldata _data) external onlyRole(STRATEGY_MANAGER) {
        // If we are bypassing the strategy, then skip this call
        if (_bypassStrategy[_strategyIds[_strategyId]]) return;

        // Extract the selector from data
        bytes4 _selector = bytes4(_data);

        // Create a replication of the bytes data that removes the selector
        bytes memory _newData = new bytes(_data.length - 4);
        for (uint i; i < _data.length - 4; i++) {
            _newData[i] = _data[i + 4];
        }

        // Make a call to our strategy that passes on our withdrawal data
        (bool success,) = _strategyIds[_strategyId].call(
            // Sandwich the selector against the recipient and remaining data
            abi.encodePacked(abi.encodeWithSelector(_selector, treasury), _newData)
        );

        // If our call failed, return a standardised message rather than decoding
        require(success, 'Unable to withdraw');
    }

    /**
     * Makes a call to a strategy withdraw function.
     *
     * @param _strategy Strategy address to be updated
     * @param _percentage The percentage of position to withdraw from
     */
    function withdrawPercentage(address _strategy, uint _percentage)
        external
        onlyRole(STRATEGY_MANAGER)
        returns (address[] memory tokens_, uint[] memory amounts_)
    {
        // Ensure our percentage is valid (less than 100% to 2 decimal places)
        require(_percentage > 0, 'Invalid percentage');
        require(_percentage <= 100_00, 'Invalid percentage');

        // Prevent a bypassed strategy from parsing withdrawal calculations
        if (_bypassStrategy[_strategy]) {
            return (tokens_, amounts_);
        }

        // Calls our strategy to withdraw a percentage of the holdings
        return IBaseStrategy(_strategy).withdrawPercentage(msg.sender, _percentage);
    }

    /**
     * Allow a strategy to be skipped when being processing. This is beneficial if a
     * strategy becomes corrupted at an external point and would otherwise prevent an
     * epoch from ending.
     *
     * @dev This does not shutdown the strategy as it can be undone. If a strategy wants
     * to wind down, then it should also be paused and a full withdraw made.
     */
    function bypassStrategy(address _strategy, bool _bypass) external onlyRole(STRATEGY_MANAGER) {
        _bypassStrategy[_strategy] = _bypass;
    }

    /**
     * Allows the {Treasury} contract address to be updated. All withdrawals will
     * be requested to be sent to this address when the `withdraw` is called.
     *
     * @dev This address is dynamically injected into the subsequent strategy
     * withdraw call.
     *
     * @param _treasury The new {Treasury} contract address
     */
    function setTreasury(address _treasury) public onlyRole(TREASURY_MANAGER) {
        if (_treasury == address(0)) revert CannotSetNullAddress();

        treasury = _treasury;
        emit TreasuryUpdated(_treasury);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IEpochEndTriggered {
    /**
     * Function that is triggered when an epoch ends.
     */
    function endEpoch(uint epoch) external;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * The GWV will allow users to assign their veFloor position to a strategy, or
 * optionally case it to a veFloor, which will use a constant value. As the
 * strategies will be rendered as an address, the veFloor vote will take a NULL
 * address value.
 *
 * At point of development this can take influence from:
 * https://github.com/saddle-finance/saddle-contract/blob/master/contracts/tokenomics/gauges/GaugeController.vy
 */
interface ISweepWars {
    /// Sent when a user casts or revokes their vote
    event VoteCast(address sender, address collection, int amount);

    /// Sent when a user has revoked their vote, or it is revoked on their behalf
    event VotesRevoked(address account, address collection, uint forVotesRevoked, uint againstVotesRevoked);

    /// Sent when the Sample Size is updated
    event SampleSizeUpdated(uint size);

    /// Sent when the {NftStaking} contract address is updated
    event NftStakingUpdated(address nftStaking);

    /**
     * Gets the number of votes for a collection at the current epoch.
     */
    function votes(address) external view returns (int);

    /**
     * The total voting power of a user, regardless of if they have cast votes
     * or not.
     */
    function userVotingPower(address _user) external view returns (uint);

    /**
     * The total number of votes that a user has available, calculated by:
     *
     * ```
     * votesAvailable_ = balanceOf(_user) - SUM(userVotes.votes_)
     * ```
     */
    function userVotesAvailable(address _user) external view returns (uint votesAvailable_);

    /**
     * Provides a list of collection addresses that can be voted on.
     */
    function voteOptions() external view returns (address[] memory collections_);

    /**
     * Allows a user to cast a vote using their veFloor allocation. We don't
     * need to monitor transfers as veFloor can only be minted or burned, and
     * we check the voters balance during the `snapshot` call.
     *
     * A user can vote with a partial amount of their veFloor holdings, and when
     * it comes to calculating their voting power this will need to be taken into
     * consideration that it will be:
     *
     * ```
     * staked balance + (gains from staking * (total balance - staked balance)%)
     * ```
     *
     * The {Treasury} cannot vote with it's holdings, as it shouldn't be holding
     * any staked Floor.
     */
    function vote(address _collection, int _amount) external;

    /**
     * Allows a user to revoke their votes from strategies. This will free up the
     * user's available votes that can subsequently be voted again with.
     */
    function revokeVotes(address[] memory _collection) external;

    /**
     * Allows an authorised contract or wallet to revoke all user votes. This
     * can be called when the veFLOOR balance is reduced.
     */
    function revokeAllUserVotes(address _account) external;

    /**
     * The snapshot function will need to iterate over all strategies that have
     * more than 0 votes against them. With that we will need to find each
     * strategy percentage share in relation to other strategies.
     *
     * This percentage share will instruct the {Treasury} on how much additional
     * FLOOR to allocate to the users staked in the strategies. These rewards will
     * become available in the {RewardLedger}.
     *
     * +----------------+-----------------+-------------------+-------------------+
     * | Voter          | veFloor         | Vote Weight       | Strategy          |
     * +----------------+-----------------+-------------------+-------------------+
     * | Alice          | 30              | 40                | 1                 |
     * | Bob            | 20              | 30                | 2                 |
     * | Carol          | 40              | 55                | 3                 |
     * | Dave           | 20              | 40                | 2                 |
     * | Emily          | 25              | 35                | 0                 |
     * +----------------+-----------------+-------------------+-------------------+
     *
     * With the above information, and assuming that the {Treasury} has allocated
     * 1000 FLOOR tokens to be additionally distributed in this snapshot, we would
     * have the following allocations going to the strategies.
     *
     * +----------------+-----------------+-------------------+-------------------+
     * | Strategy       | Votes Total     | Vote Percent      | veFloor Rewards   |
     * +----------------+-----------------+-------------------+-------------------+
     * | 0 (veFloor)    | 35              | 17.5%             | 175               |
     * | 1              | 40              | 20%               | 200               |
     * | 2              | 70              | 35%               | 350               |
     * | 3              | 55              | 27.5%             | 275               |
     * | 4              | 0               | 0%                | 0                 |
     * +----------------+-----------------+-------------------+-------------------+
     *
     * This would distribute the strategies allocated rewards against the staked
     * percentage in the strategy. Any Treasury holdings that would be given in rewards
     * are just deposited into the {Treasury} as FLOOR, bypassing the {RewardsLedger}.
     */
    function snapshot(uint tokens) external returns (address[] memory collections, uint[] memory amounts);
}

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

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _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 {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * Handles epoch management for all other contracts.
 */
interface IEpochManager {

    /// Emitted when an epoch is ended
    event EpochEnded(uint epoch, uint timestamp);

    /// Emitted when a new collection war is scheduled
    event CollectionAdditionWarScheduled(uint epoch, uint index);

    /// Emitted when required contracts are updated
    event EpochManagerContractsUpdated(address newCollectionWars, address voteMarket);

    /**
     * The current epoch that is running across the codebase.
     *
     * @return The current epoch
     */
    function currentEpoch() external view returns (uint);

    /**
     * Stores a mapping of an epoch to a collection addition war index.
     *
     * @param _epoch Epoch to check
     *
     * @return Index of the collection addition war. Will return 0 if none found
     */
    function collectionEpochs(uint _epoch) external view returns (uint);

    /**
     * Will return if the current epoch is a collection addition vote.
     *
     * @return If the current epoch is a collection addition
     */
    function isCollectionAdditionEpoch() external view returns (bool);

    /**
     * Will return if the specified epoch is a collection addition vote.
     *
     * @param epoch The epoch to check
     *
     * @return If the specified epoch is a collection addition
     */
    function isCollectionAdditionEpoch(uint epoch) external view returns (bool);

    /**
     * Allows an epoch to be scheduled to be a collection addition vote. An index will
     * be specified to show which collection addition will be used. The index will not
     * be a zero value.
     *
     * @param epoch The epoch that the Collection Addition will take place in
     * @param index The Collection Addition array index
     */
    function scheduleCollectionAdditionEpoch(uint epoch, uint index) external;

    /**
     * Triggers an epoch to end.
     *
     * @dev More information about this function can be found in the actual contract
     */
    function endEpoch() external;

    /**
     * Provides an estimated timestamp of when an epoch started, and also the earliest
     * that an epoch in the future could start.
     *
     * @param _epoch The epoch to find the estimated timestamp of
     *
     * @return The estimated timestamp of when the specified epoch started
     */
    function epochIterationTimestamp(uint _epoch) external returns (uint);

    /**
     * The length of an epoch in seconds.
     *
     * @return The length of the epoch in seconds
     */
    function EPOCH_LENGTH() external returns (uint);

    /**
     * Sets contracts that the epoch manager relies on. This doesn't have to include
     * all of the contracts that are {EpochManaged}, but only needs to set ones that the
     * {EpochManager} needs to interact with.
     */
    function setContracts(address _newCollectionWars, address _voteMarket) external;
}

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

pragma solidity ^0.8.0;

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 *
 * _Available since v3.4._
 */
library Clones {
    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create(0, 0x09, 0x37)
        }
        require(instance != address(0), "ERC1167: create failed");
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create2(0, 0x09, 0x37, salt)
        }
        require(instance != address(0), "ERC1167: create2 failed");
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x38), deployer)
            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
            mstore(add(ptr, 0x14), implementation)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
            mstore(add(ptr, 0x58), salt)
            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
            predicted := keccak256(add(ptr, 0x43), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {Context} from '@openzeppelin/contracts/utils/Context.sol';

import {CannotSetNullAddress} from '@floor/utils/Errors.sol';

import {IAuthorityControl} from '@floor-interfaces/authorities/AuthorityControl.sol';
import {IAuthorityRegistry} from '@floor-interfaces/authorities/AuthorityRegistry.sol';

/// If the account does not have the required role for the call.
/// @param caller The address making the call
/// @param role The role that is required for the call
error AccountDoesNotHaveRole(address caller, bytes32 role);

/// If the account does not have the required admin role for the call.
/// @param caller The address making the call
error AccountDoesNotHaveAdminRole(address caller);

/**
 * This contract is heavily based on the standardised OpenZeppelin `AccessControl` library.
 * This allows for the creation of role based access levels that can be assigned to 1-n
 * addresses.
 *
 * Contracts will be able to implement the AuthorityControl to provide access to the `onlyRole` modifier or the
 * `hasRole` function. This will ensure that the `msg.sender` is allowed to perform an action.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be
 * unique. The best way to achieve this is by using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("TreasuryManager");
 * ```
 */
contract AuthorityControl is Context, IAuthorityControl {
    /// CollectionManager - Can approve token addresses to be allowed to be used in strategies
    bytes32 public constant COLLECTION_MANAGER = keccak256('CollectionManager');

    /// EpochTrigger - Can run epoch trigger contract specific logic
    bytes32 public constant EPOCH_TRIGGER = keccak256('EpochTrigger');

    /// FloorManager - Can mint and manage Floor and VeFloor tokens
    bytes32 public constant FLOOR_MANAGER = keccak256('FloorManager');

    /// Governor - A likely DAO owned vote address to allow for wide scale decisions to
    /// be made and implemented.
    bytes32 public constant GOVERNOR = keccak256('Governor');

    /// Guardian - Wallet address that will allow for Governor based actions, except without
    /// timeframe restrictions.
    bytes32 public constant GUARDIAN = keccak256('Guardian');

    /// TreasuryManager - Access to Treasury asset management
    bytes32 public constant TREASURY_MANAGER = keccak256('TreasuryManager');

    /// StrategyManager - Can create new strategies against approved strategies and collections
    bytes32 public constant STRATEGY_MANAGER = keccak256('StrategyManager');

    /// VoteManager - Can manage account votes
    bytes32 public constant VOTE_MANAGER = keccak256('VoteManager');

    /// Reference to the {AuthorityRegistry} contract that maintains role allocations
    IAuthorityRegistry public immutable registry;

    /**
     * Modifier that checks that an account has a specific role. Reverts with a
     * standardized message if user does not have specified role.
     *
     * @param role The keccak256 encoded role string
     */
    modifier onlyRole(bytes32 role) {
        if (!registry.hasRole(role, _msgSender())) {
            revert AccountDoesNotHaveRole(_msgSender(), role);
        }
        _;
    }

    /**
     * Modifier that checks that an account has a governor or guardian role.
     * Reverts with a standardized message if sender does not have an admin role.
     */
    modifier onlyAdminRole() {
        if (!registry.hasAdminRole(_msgSender())) {
            revert AccountDoesNotHaveAdminRole(_msgSender());
        }
        _;
    }

    /**
     * The address that deploys the {AuthorityControl} becomes the default controller. This
     * can only be overwritten by the existing.
     *
     * @param _registry The address of our deployed AuthorityRegistry contract
     */
    constructor(address _registry) {
        if (_registry == address(0)) revert CannotSetNullAddress();
        registry = IAuthorityRegistry(_registry);
    }

    /**
     * Returns `true` if `account` has been granted `role`.
     *
     * @param role The keccak256 encoded role string
     * @param account Address to check ownership of role
     *
     * @return bool If the address has the specified user role
     */
    function hasRole(bytes32 role, address account) public view override returns (bool) {
        return registry.hasRole(role, account);
    }

    /**
     * Returns `true` if `account` has been granted either GOVERNOR or GUARDIAN role.
     *
     * @param account Address to check ownership of role
     *
     * @return bool If the address has the GOVERNOR or GUARDIAN role
     */
    function hasAdminRole(address account) public view returns (bool) {
        return registry.hasAdminRole(account);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * Allows collection contracts to be approved and revoked by addresses holding the
 * {CollectionManager} role. Only once approved can these collections be applied to
 * new or existing strategies. They will only need to be stored as a mapping of address
 * to boolean.
 */

interface ICollectionRegistry {
    /// Emitted when a collection is successfully approved
    event CollectionApproved(address contractAddr);

    /// Emitted when a collection has been successfully revoked
    event CollectionRevoked(address contractAddr);

    /**
     * Returns `true` if the contract address is an approved collection, otherwise
     * returns `false`.
     */
    function isApproved(address contractAddr) external view returns (bool);

    /**
     * Returns an array of all approved collections.
     */
    function approvedCollections() external view returns (address[] memory);

    /**
     * Approves a collection contract to be used for strategies.
     */
    function approveCollection(address contractAddr) external;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * Strategies will hold the logic for interacting with external platforms to stake
 * and harvest reward yield. Each strategy will require its own strategy implementation
 * to allow for different immutable variables to be defined during construct.
 *
 * This will follow a similar approach to how NFTX offer their eligibility module
 * logic, with a lot of the power coming from inheritence.
 *
 * When constructed, we want to give the {Treasury} a max uint approval of the yield
 * and underlying tokens.
 */
interface IBaseStrategy {
    /// @dev When strategy receives a deposit
    event Deposit(address token, uint amount, address caller);

    /// @dev When strategy is harvested
    event Harvest(address token, uint amount);

    /// @dev When a staked user exits their position
    event Withdraw(address token, uint amount, address recipient);

    /**
     * Allows the strategy to be initialised.
     */
    function initialize(bytes32 name, uint strategyId, bytes calldata initData) external;

    /**
     * Name of the strategy.
     */
    function name() external view returns (bytes32);

    /**
     * The numerical ID of the strategy that acts as an index for the {StrategyFactory}.
     */
    function strategyId() external view returns (uint);

    /**
     * Total rewards generated by the strategy in all time. This is pure bragging rights.
     */
    function lifetimeRewards(address token) external returns (uint amount_);

    /**
     * The amount of rewards claimed in the last claim call.
     */
    function lastEpochRewards(address token) external returns (uint amount_);

    /**
     * Gets rewards that are available to harvest.
     */
    function available() external returns (address[] memory, uint[] memory);

    /**
     * Extracts all rewards from third party and moves it to a recipient. This should
     * only be called by a specific action.
     *
     * @dev This _should_ always be imposed to be the {Treasury} by the {StrategyFactory}.
     */
    function harvest(address /* _recipient */ ) external;

    /**
     * Returns an array of tokens that the strategy supports.
     *
     * @return address[] The address of valid tokens
     */
    function validTokens() external view returns (address[] memory);

    /**
     * Makes a call to a strategy to withdraw a percentage of the deposited holdings.
     *
     * @param recipient Strategy address to be updated
     * @param percentage The 2 decimal accuracy of the percentage to withdraw (e.g. 100% = 10000)
     *
     * @return address[] Array of tokens withdrawn
     * @return uint[] Amounts of respective tokens withdrawn
     */
    function withdrawPercentage(address recipient, uint percentage) external returns (address[] memory, uint[] memory);

    /**
     * Pauses deposits from being made into the strategy. This should only be called by
     * a guardian or governor.
     *
     * @param _p Boolean value for if the strategy should be paused
     */
    function pause(bool _p) external;

    /**
     * Gets a read of new yield since the last call. This is what can be called when
     * the epoch ends to determine the amount generated within the epoch.
     */
    function snapshot() external returns (address[] memory, uint[] memory);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * Allows for strategies to be created, pairing them with a {Strategy} and an approved
 * collection. The strategy creation script needs to be as highly optimised as possible
 * to ensure that the gas costs are kept down.
 *
 * This factory will keep an index of created strategies and secondary information to ensure
 * that external applications can display and maintain a list of available strategies.
 *
 * The contract can be paused to prevent the creation of new strategies.
 */

interface IStrategyFactory {
    /// @dev Sent when a strategy is created successfully
    event StrategyCreated(uint indexed strategyId, address strategyAddress, address assetAddress);

    /// @dev Sent when a snapshot is taken
    event StrategySnapshot(uint epoch, address[] tokens, uint[] amounts);

    /// @dev Sent when the Treasury address is updated
    event TreasuryUpdated(address treasury);

    /**
     * Our stored {Treasury} address.
     */
    function treasury() external view returns (address);

    /**
     * Provides a list of all strategies created.
     *
     * @return Array of all strategies created by the {StrategyFactory}
     */
    function strategies() external view returns (address[] memory);

    /**
     * Returns an array of all strategies that belong to a specific collection.
     */
    function collectionStrategies(address _collection) external view returns (address[] memory);

    /**
     * Provides a strategy against the provided `strategyId` (index). If the index does not exist,
     * then address(0) will be returned.
     *
     * @param _strategyId ID of the strategy to retrieve
     *
     * @return Address of the strategy
     */
    function strategy(uint _strategyId) external view returns (address);

    /**
     * Creates a strategy with an approved collection.
     *
     * @dev The strategy is not created using Clones as there are complications when allocated
     * roles and permissions.
     *
     * @param _name Human-readable name of the strategy
     * @param _strategy The strategy implemented by the strategy
     * @param _strategyInitData Bytes data required by the {Strategy} for initialization
     * @param _collection The address of the collection attached to the strategy
     *
     * @return strategyId_ ID of the newly created strategy
     * @return strategyAddr_ Address of the newly created strategy
     */
    function deployStrategy(bytes32 _name, address _strategy, bytes calldata _strategyInitData, address _collection)
        external
        returns (uint strategyId_, address strategyAddr_);

    /**
     * Allows individual strategies to be paused, meaning that assets can no longer be deposited,
     * although staked assets can always be withdrawn.
     *
     * @dev Events are fired within the strategy to allow listeners to update.
     *
     * @param _strategyId Strategy ID to be paused
     * @param _paused If the strategy should be paused or unpaused
     */
    function pause(uint _strategyId, bool _paused) external;

    /**
     * Reads the yield generated by a strategy since the last time that this function was called.
     *
     * @param _epoch The current epoch being snapshotted
     *
     * @return tokens Tokens that have been generated as yield
     * @return amounts The amount of yield generated for the corresponding token
     */
    function snapshot(uint _epoch) external returns (address[] memory tokens, uint[] memory amounts, uint totalAmount);

    /**
     * Harvest available reward yield from the strategy. This won't affect the amount
     * depositted into the contract and should only harvest rewards directly into the
     * {Treasury}.
     *
     * @param _strategyId Strategy ID to be harvested
     */
    function harvest(uint _strategyId) external;

    /**
     * Makes a call to a strategy withdraw function by passing the strategy ID and
     * `abi.encodeWithSelector` to build the bytes `_data` parameter. This will then
     * pass the data on to the strategy function and inject the treasury recipient
     * address within the call as the first function parameter.
     *
     * @dev It is required for the transaction to return a successful call, otherwise
     * the transaction will be reverted. The error response will be standardised so
     * debugging will require a trace, rather than just the end message.
     *
     * @param _strategyId Strategy ID to be withdrawn from
     * @param _data Strategy withdraw function call, using `encodeWithSelector`
     */
    function withdraw(uint _strategyId, bytes calldata _data) external;

    /**
     * Makes a call to a strategy to withdraw a percentage of the deposited holdings.
     *
     * @param _strategy Strategy address to be updated
     * @param _percentage The 2 decimal accuracy of the percentage to withdraw (e.g. 100% = 10000)
     */
    function withdrawPercentage(address _strategy, uint _percentage) external returns (address[] memory, uint[] memory);

    /**
     * Allows the {Treasury} contract address to be updated. All withdrawals will
     * be requested to be sent to this address when the `withdraw` is called.
     *
     * @dev This address is dynamically injected into the subsequent strategy
     * withdraw call.
     *
     * @param _treasury The new {Treasury} contract address
     */
    function setTreasury(address _treasury) external;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * Allows strategy contracts to be approved and revoked by addresses holding the
 * {TREASURY_MANAGER} role. Only once approved can these strategy implementations be deployed
 * to new or existing strategies.
 */
interface IStrategyRegistry {
    /// Emitted when a strategy is approved or unapproved
    event ApprovedStrategyUpdated(address contractAddr, bool approved);

    /**
     * Checks if a strategy has previously been approved.
     *
     * @param contractAddr The strategy implementation address to be checked
     *
     * @return Returns `true` if the contract address is an approved strategy, otherwise
     * returns `false`.
     */
    function isApproved(address contractAddr) external view returns (bool);

    /**
     * Changes the approval state of a strategy implementation contract.
     *
     * The strategy address cannot be null, and if it is already the new state, then
     * no changes will be made.
     *
     * The caller must have the `TREASURY_MANAGER` role.
     *
     * @param contractAddr Address of unapproved strategy to approve
     * @param approved The new approval state for the implementation
     */
    function approveStrategy(address contractAddr, bool approved) external;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {IWETH} from '@floor-interfaces/tokens/WETH.sol';


library TreasuryEnums {
    /// Different sweep types that can be specified.
    enum SweepType {
        COLLECTION_ADDITION,
        SWEEP
    }

    /// Different approval types that can be specified.
    enum ApprovalType {
        NATIVE,
        ERC20,
        ERC721,
        ERC1155
    }
}

/**
 * @dev The Treasury will hold all assets.
 */
interface ITreasury {
    /// Stores data that allows the Treasury to action a sweep.
    struct Sweep {
        TreasuryEnums.SweepType sweepType;
        address[] collections;
        uint[] amounts;
        bool completed;
        string message;
    }

    /// The data structure format that will be mapped against to define a token
    /// approval request.
    struct ActionApproval {
        TreasuryEnums.ApprovalType _type; // Token type
        address assetContract; // Used by 20, 721 and 1155
        address target; // Used by 20, 721 and 1155
        uint amount; // Used by native and 20 tokens
    }

    /// @dev When native network token is withdrawn from the Treasury
    event Deposit(uint amount);

    /// @dev When an ERC20 is depositted into the Treasury
    event DepositERC20(address token, uint amount);

    /// @dev When an ERC721 is depositted into the Treasury
    event DepositERC721(address token, uint tokenId);

    /// @dev When an ERC1155 is depositted into the Treasury
    event DepositERC1155(address token, uint tokenId, uint amount);

    /// @dev When native network token is withdrawn from the Treasury
    event Withdraw(uint amount, address recipient);

    /// @dev When an ERC20 token is withdrawn from the Treasury
    event WithdrawERC20(address token, uint amount, address recipient);

    /// @dev When an ERC721 token is withdrawn from the Treasury
    event WithdrawERC721(address token, uint tokenId, address recipient);

    /// @dev When an ERC1155 is withdrawn from the Treasury
    event WithdrawERC1155(address token, uint tokenId, uint amount, address recipient);

    /// @dev When FLOOR is minted
    event FloorMinted(uint amount);

    /// @dev When a {Treasury} action is processed
    event ActionProcessed(address action, bytes data);

    /// @dev When a sweep is registered against an epoch
    event SweepRegistered(uint sweepEpoch, TreasuryEnums.SweepType sweepType, address[] collections, uint[] amounts);

    /// @dev When an action is assigned to a sweep epoch
    event SweepAction(uint sweepEpoch);

    /// @dev When an epoch is swept
    event EpochSwept(uint epochIndex);

    /// Emitted when the {MercenarySweeper} contract address is updated
    event MercenarySweeperUpdated(address mercSweeper);

    /// Emitted when the minimum sweep amount is updated
    event MinSweepAmountUpdated(uint minSweepAmount);

    /// Emitted when the {VeFloorStaking} contract is updated
    event VeFloorStakingUpdated(address veFloorStaking);

    /// Emitted when the {StrategyFactory} contract is updated
    event StrategyFactoryUpdated(address strategyFactory);

    /**
     * Our stored WETH address for the {Treasury}
     */
    function weth() external returns (IWETH);

    /**
     * Allow FLOOR token to be minted. This should be called from the deposit method
     * internally, but a public method will allow a {TreasuryManager} to bypass this
     * and create additional FLOOR tokens if needed.
     *
     * @dev We only want to do this on creation and for inflation. Have a think on how
     * we can implement this!
     */
    function mint(uint amount) external;

    /**
     * Allows an ERC20 token to be deposited and generates FLOOR tokens based on
     * the current determined value of FLOOR and the token.
     */
    function depositERC20(address token, uint amount) external;

    /**
     * Allows an ERC721 token to be deposited and generates FLOOR tokens based on
     * the current determined value of FLOOR and the token.
     */
    function depositERC721(address token, uint tokenId) external;

    /**
     * Allows an ERC1155 token(s) to be deposited and generates FLOOR tokens based on
     * the current determined value of FLOOR and the token.
     */
    function depositERC1155(address token, uint tokenId, uint amount) external;

    /**
     * Allows an approved user to withdraw native token.
     */
    function withdraw(address recipient, uint amount) external;

    /**
     * Allows an approved user to withdraw and ERC20 token from the Treasury.
     */
    function withdrawERC20(address recipient, address token, uint amount) external;

    /**
     * Allows an approved user to withdraw and ERC721 token from the Treasury.
     */
    function withdrawERC721(address recipient, address token, uint tokenId) external;

    /**
     * Allows an approved user to withdraw an ERC1155 token(s) from the Treasury.
     */
    function withdrawERC1155(address recipient, address token, uint tokenId, uint amount) external;

    /**
     * Actions a sweep to be used against a contract that implements {ISweeper}. This
     * will fulfill the sweep and we then mark the sweep as completed.
     */
    function sweepEpoch(uint epochIndex, address sweeper, bytes calldata data, uint mercSweep) external;

    /**
     * Allows the DAO to resweep an already swept "Sweep" struct, using a contract that
     * implements {ISweeper}. This will fulfill the sweep again and keep the sweep marked
     * as completed.
     */
    function resweepEpoch(uint epochIndex, address sweeper, bytes calldata data, uint mercSweep) external;

    /**
     * When an epoch ends, we have the ability to register a sweep against the {Treasury}
     * via an approved contract. This will store a DAO sweep that will need to be actioned
     * using the `sweepEpoch` function.
     */
    function registerSweep(uint epoch, address[] calldata collections, uint[] calldata amounts, TreasuryEnums.SweepType sweepType)
        external;

    /**
     * The minimum sweep amount that can be implemented, or excluded, as desired by the DAO.
     */
    function minSweepAmount() external returns (uint);

    /**
     * Allows the mercenary sweeper contract to be updated.
     */
    function setMercenarySweeper(address _mercSweeper) external;

    /**
     * Allows us to set a new VeFloorStaking contract that is used when sweeping epochs.
     */
    function setVeFloorStaking(address _veFloorStaking) external;
}

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

pragma solidity ^0.8.0;

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

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IAuthorityControl {
    /// CollectionManager - Can approve token addresses to be allowed to be used in strategies
    function COLLECTION_MANAGER() external returns (bytes32);

    /// EpochTrigger - Can run epoch trigger contract specific logic
    function EPOCH_TRIGGER() external returns (bytes32);

    /// FloorManager - Can mint and manage Floor and VeFloor tokens
    function FLOOR_MANAGER() external returns (bytes32);

    /// Governor - A likely DAO owned vote address to allow for wide scale decisions to
    /// be made and implemented.
    function GOVERNOR() external returns (bytes32);

    /// Guardian - Wallet address that will allow for Governor based actions, except without
    /// timeframe restrictions.
    function GUARDIAN() external returns (bytes32);

    /// TreasuryManager - Access to Treasury asset management
    function TREASURY_MANAGER() external returns (bytes32);

    /// StrategyManager - Can create new strategies against approved strategies and collections
    function STRATEGY_MANAGER() external returns (bytes32);

    /// VoteManager - Can manage account votes
    function VOTE_MANAGER() external returns (bytes32);

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

    /**
     * @dev Returns `true` if `account` has been granted either the GOVERNOR or
     * GUARDIAN `role`.
     */
    function hasAdminRole(address account) external view returns (bool);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * This interface expands upon the OpenZeppelin `IAccessControl` interface:
 * https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/master/contracts/access/IAccessControl.sol
 */

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

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

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

    /**
     * @dev Returns `true` if `account` has been granted either the GOVERNOR or
     * GUARDIAN `role`.
     */
    function hasAdminRole(address account) external view returns (bool);

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

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

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';

interface IWETH is IERC20 {
    function allowance(address, address) external view returns (uint);

    function balanceOf(address) external view returns (uint);

    function approve(address, uint) external returns (bool);

    function transfer(address, uint) external returns (bool);

    function transferFrom(address, address, uint) external returns (bool);

    function deposit() external payable;

    function withdraw(uint) external;
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

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

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@uniswap-v3/=lib/",
    "@uniswap/v3-periphery/=lib/v3-periphery/",
    "@chainlink/=lib/chainlink/",
    "@murky/=lib/murky/src/",
    "@solidity-math-utils/=lib/solidity-math-utils/project/contracts/",
    "@solidity-trigonometry/=lib/solidity-trigonometry/src/",
    "@1inch/=lib/",
    "@charmfi/=lib/charmfi-contracts-0.8.0-support/",
    "@sudoswap/=lib/lssvm/src/",
    "@floor/=src/contracts/",
    "@floor-interfaces/=src/interfaces/",
    "@floor-scripts/=script/",
    "@ERC721A/=lib/ERC721A/contracts/",
    "foundry-random/=lib/foundry-random/src/",
    "lssvm2/=lib/lssvm2/src/",
    "@nftx-protocol-v3/=lib/nftx-protocol-v3/src/",
    "@manifoldxyz/=lib/lssvm2/lib/",
    "@mocks/=lib/nftx-protocol-v3/src/mocks/",
    "@permit2/=lib/nftx-protocol-v3/lib/permit2/src/",
    "@prb/math/=lib/lssvm2/lib/prb-math/src/",
    "@prb/test/=lib/foundry-random/lib/prb-test/src/",
    "@src/=lib/nftx-protocol-v3/src/",
    "@test/=lib/nftx-protocol-v3/test/",
    "@uni-core/=lib/nftx-protocol-v3/src/uniswap/v3-core/",
    "@uni-periphery/=lib/nftx-protocol-v3/src/uniswap/v3-periphery/",
    "@uniswap/lib/=lib/nftx-protocol-v3/lib/solidity-lib/",
    "@uniswap/v2-core/=lib/nftx-protocol-v3/lib/v2-core/",
    "@uniswap/v3-core/contracts/=lib/nftx-protocol-v3/src/uniswap/v3-core/",
    "CramBit/=lib/foundry-random/lib/CramBit/",
    "ERC721A/=lib/ERC721A/contracts/",
    "base64-sol/=lib/nftx-protocol-v3/src/uniswap/v3-periphery/libraries/",
    "chainlink/=lib/chainlink/",
    "charmfi-contracts-0.8.0-support/=lib/charmfi-contracts-0.8.0-support/",
    "clones-with-immutable-args/=lib/lssvm2/lib/clones-with-immutable-args/src/",
    "crambit/=lib/foundry-random/lib/CramBit/src/",
    "create2-helpers/=lib/lssvm2/lib/royalty-registry-solidity/lib/create2-helpers/",
    "create3-factory/=lib/lssvm2/lib/create3-factory/",
    "foundry-huff/=lib/lssvm2/lib/foundry-huff/src/",
    "foundry-random/=lib/foundry-random/src/",
    "huffmate/=lib/lssvm2/lib/huffmate/src/",
    "libraries-solidity/=lib/lssvm2/lib/libraries-solidity/contracts/",
    "lssvm/=lib/lssvm/src/",
    "lssvm2/=lib/lssvm2/src/",
    "manifoldxyz/=lib/lssvm2/lib/royalty-registry-solidity/contracts/",
    "murky/=lib/murky/src/",
    "nftx-protocol-v3/=lib/nftx-protocol-v3/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "prb-math/=lib/solidity-trigonometry/lib/prb-math/contracts/",
    "prb-test/=lib/foundry-random/lib/prb-test/src/",
    "royalty-registry-solidity.git/=lib/lssvm/lib/royalty-registry-solidity.git/contracts/",
    "royalty-registry-solidity/=lib/lssvm2/lib/royalty-registry-solidity/",
    "solidity-bytes-utils/=lib/foundry-random/lib/solidity-bytes-utils/contracts/",
    "solidity-math-utils/=lib/solidity-math-utils/",
    "solidity-stringutils/=lib/lssvm2/lib/foundry-huff/lib/solidity-stringutils/",
    "solidity-trigonometry/=lib/solidity-trigonometry/src/",
    "solidity-utils/=lib/solidity-utils/contracts/",
    "solmate/=lib/lssvm2/lib/solmate/src/",
    "src/=lib/foundry-random/src/",
    "stringutils/=lib/lssvm2/lib/foundry-huff/lib/solidity-stringutils/",
    "v3-core/=lib/v3-core/contracts/",
    "v3-periphery/=lib/v3-periphery/contracts/",
    "weird-erc20/=lib/lssvm/lib/solmate/lib/weird-erc20/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_sweepWars","type":"address"},{"internalType":"address","name":"_strategyFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotSetNullAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_worstCollection","type":"address"},{"indexed":false,"internalType":"address[]","name":"_strategies","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"_percentage","type":"uint256"}],"name":"CollectionTokensLiquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"epochManager","type":"address"}],"name":"EpochManagerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"endEpoch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"epochManager","outputs":[{"internalType":"contract IEpochManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_epochManager","type":"address"}],"name":"setEpochManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategyFactory","outputs":[{"internalType":"contract StrategyFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sweepWars","outputs":[{"internalType":"contract ISweepWars","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c060405234801561001057600080fd5b50604051610a7d380380610a7d83398101604081905261002f916100f6565b6100383361008a565b6001600160a01b038216158061005557506001600160a01b038116155b156100735760405163d713c59760e01b815260040160405180910390fd5b6001600160a01b039182166080521660a052610129565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b03811681146100f157600080fd5b919050565b6000806040838503121561010957600080fd5b610112836100da565b9150610120602084016100da565b90509250929050565b60805160a05161091b6101626000396000818161012601526103f8015260008181609d015281816101e80152610280015261091b6000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c80638da5cb5b116100665780638da5cb5b146101105780639ef3571014610121578063d4d59edb14610148578063e2d2bfe31461015b578063f2fde38b1461016e57600080fd5b80632a2c6b86146100985780636164e45d146100dc578063715018a6146100f1578063785ffb37146100f9575b600080fd5b6100bf7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6100ef6100ea366004610671565b610181565b005b6100ef6104b1565b6101026103e881565b6040519081526020016100d3565b6000546001600160a01b03166100bf565b6100bf7f000000000000000000000000000000000000000000000000000000000000000081565b6100ef61015636600461069f565b6104c5565b6001546100bf906001600160a01b031681565b6100ef61017c36600461069f565b6104d6565b6001546001600160a01b031633146101e05760405162461bcd60e51b815260206004820152601a60248201527f4f6e6c792045706f63684d616e616765722063616e2063616c6c00000000000060448201526064015b60405180910390fd5b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166341495d1c6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610244573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261026c91908101906106e9565b805190915060005b8181101561038b5760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d8bff5a58584815181106102bf576102bf6107ae565b60200260200101516040518263ffffffff1660e01b81526004016102f291906001600160a01b0391909116815260200190565b602060405180830381865afa15801561030f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033391906107c4565b90508581121561035d57809550838281518110610352576103526107ae565b602002602001015196505b60008112156103745761036f816107f3565b610376565b805b610380908661080f565b945050600101610274565b508260000361039c57505050505050565b6000836103ab86612710610837565b6103b5919061086d565b6103c190600019610837565b90506103e88110156103d65750505050505050565b60405163630a6fc160e01b81526001600160a01b0387811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063630a6fc190602401600060405180830381865afa158015610441573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261046991908101906106e9565b90507f6ea7eec715d8ed2035e1da6761dc0452a89785257a9bb31fe0e1c631e3c1fc2f87828460405161049e939291906108a9565b60405180910390a1505050505050505b50565b6104b961054c565b6104c360006105a6565b565b6104cd61054c565b6104ae816105f6565b6104de61054c565b6001600160a01b0381166105435760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016101d7565b6104ae816105a6565b6000546001600160a01b031633146104c35760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101d7565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811661061d5760405163d713c59760e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f4b9d66d8e64dff6d9d2728f9a38da9739d3cfdbe676fde05564aae22f85084659060200160405180910390a150565b60006020828403121561068357600080fd5b5035919050565b6001600160a01b03811681146104ae57600080fd5b6000602082840312156106b157600080fd5b81356106bc8161068a565b9392505050565b634e487b7160e01b600052604160045260246000fd5b80516106e48161068a565b919050565b600060208083850312156106fc57600080fd5b825167ffffffffffffffff8082111561071457600080fd5b818501915085601f83011261072857600080fd5b81518181111561073a5761073a6106c3565b8060051b604051601f19603f8301168101818110858211171561075f5761075f6106c3565b60405291825284820192508381018501918883111561077d57600080fd5b938501935b828510156107a257610793856106d9565b84529385019392850192610782565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156107d657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b6000600160ff1b8201610808576108086107dd565b5060000390565b808201828112600083128015821682158216171561082f5761082f6107dd565b505092915050565b80820260008212600160ff1b84141615610853576108536107dd565b8181058314821517610867576108676107dd565b92915050565b60008261088a57634e487b7160e01b600052601260045260246000fd5b600160ff1b8214600019841416156108a4576108a46107dd565b500590565b6001600160a01b038481168252606060208084018290528551918401829052600092868201929091906080860190855b818110156108f75785518516835294830194918301916001016108d9565b50508094505050505082604083015294935050505056fea164736f6c6343000811000a00000000000000000000000009c9381417e0ecff536ec33375f1d5b2efa97d78000000000000000000000000df2e023ea56d752d0b5be79f65557987976676cc

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100935760003560e01c80638da5cb5b116100665780638da5cb5b146101105780639ef3571014610121578063d4d59edb14610148578063e2d2bfe31461015b578063f2fde38b1461016e57600080fd5b80632a2c6b86146100985780636164e45d146100dc578063715018a6146100f1578063785ffb37146100f9575b600080fd5b6100bf7f00000000000000000000000009c9381417e0ecff536ec33375f1d5b2efa97d7881565b6040516001600160a01b0390911681526020015b60405180910390f35b6100ef6100ea366004610671565b610181565b005b6100ef6104b1565b6101026103e881565b6040519081526020016100d3565b6000546001600160a01b03166100bf565b6100bf7f000000000000000000000000df2e023ea56d752d0b5be79f65557987976676cc81565b6100ef61015636600461069f565b6104c5565b6001546100bf906001600160a01b031681565b6100ef61017c36600461069f565b6104d6565b6001546001600160a01b031633146101e05760405162461bcd60e51b815260206004820152601a60248201527f4f6e6c792045706f63684d616e616765722063616e2063616c6c00000000000060448201526064015b60405180910390fd5b6000806000807f00000000000000000000000009c9381417e0ecff536ec33375f1d5b2efa97d786001600160a01b03166341495d1c6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610244573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261026c91908101906106e9565b805190915060005b8181101561038b5760007f00000000000000000000000009c9381417e0ecff536ec33375f1d5b2efa97d786001600160a01b031663d8bff5a58584815181106102bf576102bf6107ae565b60200260200101516040518263ffffffff1660e01b81526004016102f291906001600160a01b0391909116815260200190565b602060405180830381865afa15801561030f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033391906107c4565b90508581121561035d57809550838281518110610352576103526107ae565b602002602001015196505b60008112156103745761036f816107f3565b610376565b805b610380908661080f565b945050600101610274565b508260000361039c57505050505050565b6000836103ab86612710610837565b6103b5919061086d565b6103c190600019610837565b90506103e88110156103d65750505050505050565b60405163630a6fc160e01b81526001600160a01b0387811660048301526000917f000000000000000000000000df2e023ea56d752d0b5be79f65557987976676cc9091169063630a6fc190602401600060405180830381865afa158015610441573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261046991908101906106e9565b90507f6ea7eec715d8ed2035e1da6761dc0452a89785257a9bb31fe0e1c631e3c1fc2f87828460405161049e939291906108a9565b60405180910390a1505050505050505b50565b6104b961054c565b6104c360006105a6565b565b6104cd61054c565b6104ae816105f6565b6104de61054c565b6001600160a01b0381166105435760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016101d7565b6104ae816105a6565b6000546001600160a01b031633146104c35760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101d7565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811661061d5760405163d713c59760e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f4b9d66d8e64dff6d9d2728f9a38da9739d3cfdbe676fde05564aae22f85084659060200160405180910390a150565b60006020828403121561068357600080fd5b5035919050565b6001600160a01b03811681146104ae57600080fd5b6000602082840312156106b157600080fd5b81356106bc8161068a565b9392505050565b634e487b7160e01b600052604160045260246000fd5b80516106e48161068a565b919050565b600060208083850312156106fc57600080fd5b825167ffffffffffffffff8082111561071457600080fd5b818501915085601f83011261072857600080fd5b81518181111561073a5761073a6106c3565b8060051b604051601f19603f8301168101818110858211171561075f5761075f6106c3565b60405291825284820192508381018501918883111561077d57600080fd5b938501935b828510156107a257610793856106d9565b84529385019392850192610782565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156107d657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b6000600160ff1b8201610808576108086107dd565b5060000390565b808201828112600083128015821682158216171561082f5761082f6107dd565b505092915050565b80820260008212600160ff1b84141615610853576108536107dd565b8181058314821517610867576108676107dd565b92915050565b60008261088a57634e487b7160e01b600052601260045260246000fd5b600160ff1b8214600019841416156108a4576108a46107dd565b500590565b6001600160a01b038481168252606060208084018290528551918401829052600092868201929091906080860190855b818110156108f75785518516835294830194918301916001016108d9565b50508094505050505082604083015294935050505056fea164736f6c6343000811000a

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000009c9381417e0ecff536ec33375f1d5b2efa97d78000000000000000000000000df2e023ea56d752d0b5be79f65557987976676cc

-----Decoded View---------------
Arg [0] : _sweepWars (address): 0x09c9381417E0ECff536EC33375f1d5b2EFa97D78
Arg [1] : _strategyFactory (address): 0xdf2e023Ea56d752D0B5bE79f65557987976676CC

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000009c9381417e0ecff536ec33375f1d5b2efa97d78
Arg [1] : 000000000000000000000000df2e023ea56d752d0b5be79f65557987976676cc


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.