ETH Price: $3,808.27 (-0.94%)

Contract

0xa58FBe38AAB33b9fadEf1B5Aaff4D7bC27C43aD4
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Claim Bribes236308062025-10-22 4:51:5919 hrs ago1761108719IN
0xa58FBe38...C27C43aD4
0 ETH0.000157351.58577662
Claim Bribes236279062025-10-21 19:06:3529 hrs ago1761073595IN
0xa58FBe38...C27C43aD4
0 ETH0.000146040.87669333
Claim Bribes236200292025-10-20 16:33:352 days ago1760978015IN
0xa58FBe38...C27C43aD4
0 ETH0.000024430.21003414
Claim Bribes236083032025-10-19 1:08:473 days ago1760836127IN
0xa58FBe38...C27C43aD4
0 ETH0.000037540.11828543
Claim Bribes236039902025-10-18 10:38:354 days ago1760783915IN
0xa58FBe38...C27C43aD4
0 ETH0.000014440.12413255
Claim Bribes236009282025-10-18 0:22:235 days ago1760746943IN
0xa58FBe38...C27C43aD4
0 ETH0.000021690.21863644
Claim Bribes235989762025-10-17 17:48:595 days ago1760723339IN
0xa58FBe38...C27C43aD4
0 ETH0.000208492.10106719
Claim Bribes235983522025-10-17 15:43:115 days ago1760715791IN
0xa58FBe38...C27C43aD4
0 ETH0.001959092.5447332
Process235967512025-10-17 10:21:355 days ago1760696495IN
0xa58FBe38...C27C43aD4
0 ETH0.000255362.9314285
Claim Bribes235962682025-10-17 8:44:475 days ago1760690687IN
0xa58FBe38...C27C43aD4
0 ETH0.004603635
Claim Bribes235937932025-10-17 0:26:356 days ago1760660795IN
0xa58FBe38...C27C43aD4
0 ETH0.000024970.25166445
Claim Bribes235929302025-10-16 21:32:596 days ago1760650379IN
0xa58FBe38...C27C43aD4
0 ETH0.001316321.26762893
Process235909162025-10-16 14:48:116 days ago1760626091IN
0xa58FBe38...C27C43aD4
0 ETH0.000197212.26393791
Process235894182025-10-16 9:45:356 days ago1760607935IN
0xa58FBe38...C27C43aD4
0 ETH0.01211258121.87417431
Deposit Bribe235894112025-10-16 9:44:116 days ago1760607851IN
0xa58FBe38...C27C43aD4
0 ETH0.000234942.56235061
Process235891062025-10-16 8:42:236 days ago1760604143IN
0xa58FBe38...C27C43aD4
0 ETH0.000116341.17065341
Process235889272025-10-16 8:06:116 days ago1760601971IN
0xa58FBe38...C27C43aD4
0 ETH0.000166591.67626871
Process235889232025-10-16 8:05:116 days ago1760601911IN
0xa58FBe38...C27C43aD4
0 ETH0.000166661.67695183
Claim Bribes235728382025-10-14 2:02:598 days ago1760407379IN
0xa58FBe38...C27C43aD4
0 ETH0.000021850.22021442
Claim Bribes235727672025-10-14 1:48:478 days ago1760406527IN
0xa58FBe38...C27C43aD4
0 ETH0.000038550.11852828
Claim Bribes235612802025-10-12 11:14:5910 days ago1760267699IN
0xa58FBe38...C27C43aD4
0 ETH0.000053870.12926931
Claim Bribes235537742025-10-11 10:05:3511 days ago1760177135IN
0xa58FBe38...C27C43aD4
0 ETH0.000061430.52807916
Claim Bribes235523252025-10-11 5:14:1111 days ago1760159651IN
0xa58FBe38...C27C43aD4
0 ETH0.000192310.88687299
Claim Bribes235429852025-10-09 21:53:1113 days ago1760046791IN
0xa58FBe38...C27C43aD4
0 ETH0.00004360.37483373
Claim Bribes235418602025-10-09 18:06:4713 days ago1760033207IN
0xa58FBe38...C27C43aD4
0 ETH0.000183241.1
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
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:
QuestInitiative

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 100000 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import { BribeInitiative } from "liquity-gov/src/BribeInitiative.sol";
import { Ownable2Step } from "openzeppelin-contracts/contracts/access/Ownable2Step.sol";
import { Ownable } from "openzeppelin-contracts/contracts/access/Ownable.sol";
import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";
import { SafeERC20 } from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import { IQuestBoard } from "./interfaces/IQuestBoard.sol";

contract QuestInitiative is BribeInitiative, Ownable2Step {
    using SafeERC20 for IERC20;

    uint48 public constant DEFAULT_DURATION = 2;

    uint256 private constant BPS = 10000;

    address public questBoard;

    uint256 public pendingBudget;

    uint256 public previousQuest;

    address public targetGauge;

    struct QuestSettings {
        uint256 minRewardPerVote;
        uint256 maxRewardPerVote;
        IQuestBoard.QuestVoteType voteType;
        IQuestBoard.QuestCloseType closeType;
    }

    QuestSettings public _questSettings;
    address[] public questVoterList;

    error CannotCreateQuest();

    event QuestCreated(uint256 indexed questId);
    event SettingsRewardPerVoteUpdated(uint256 newMinRewardPerVote, uint256 newMaxRewardPerVote);
    event SettingsUpdated();

    constructor(
        address _governance, address _bold, address _bribeToken, address _board, address _gauge
    ) BribeInitiative(_governance, _bold, _bribeToken) Ownable(msg.sender) {
        questBoard = _board;
        targetGauge = _gauge;
    }

    function questSettings() external view returns (QuestSettings memory) {
        return _questSettings;
    }

    function process() external {
        _pullBudget();
        _createQuest();
    }

    function pullBudget() external {
        _pullBudget();
    }

    function _pullBudget() internal {
        uint256 amount = governance.claimForInitiative(address(this));
        pendingBudget += amount;
    }

    function _recoverUnusedBudget(uint256 questId) internal {
        uint256 withdrawable = IQuestBoard(questBoard).questWithdrawableAmount(questId);
        if(withdrawable == 0) return;

        uint256 prevBalance = bold.balanceOf(address(this));
        IQuestBoard(questBoard).withdrawUnusedRewards(questId, address(this));
        uint256 received = bold.balanceOf(address(this)) - prevBalance;

        pendingBudget += received;
    }

    function _createQuest() internal {
        QuestSettings memory settings = _questSettings;
        if (previousQuest != 0) {
            uint48[] memory periods = IQuestBoard(questBoard).getAllPeriodsForQuestId(previousQuest);
            uint256 lastPeriod = periods[periods.length - 1];
            // Previous Quest is not over, do not create a new one
            if (IQuestBoard(questBoard).getCurrentPeriod() <= lastPeriod) return;

            // Recover unused budget from previous Quest
            _recoverUnusedBudget(previousQuest);
        }

        uint256 feeRatio = IQuestBoard(questBoard).customPlatformFeeRatio(address(this));
        if(feeRatio == 0) feeRatio = IQuestBoard(questBoard).platformFeeRatio();
        uint256 amountOutAfterFee = (pendingBudget * BPS) / (BPS + feeRatio);
        uint256 feeAmount = (amountOutAfterFee * feeRatio) / BPS;
        pendingBudget -= (amountOutAfterFee + feeAmount);

        bold.safeIncreaseAllowance(address(questBoard), amountOutAfterFee + feeAmount);
        uint256 id = IQuestBoard(questBoard).createRangedQuest(
            targetGauge,
            address(bold),
            false, // Allows to create the Quest right now, and check the previous one is over before allowing to create a new one
            DEFAULT_DURATION,
            settings.minRewardPerVote,
            settings.maxRewardPerVote,
            amountOutAfterFee,
            feeAmount,
            settings.voteType,
            settings.closeType,
            questVoterList
        );
        previousQuest = id;

        emit QuestCreated(id);
    }
    
    function updateQuestSettings(
        uint256 _minRewardPerVote,
        uint256 _maxRewardPerVote,
        IQuestBoard.QuestVoteType _voteType,
        IQuestBoard.QuestCloseType _closeType,
        address[] memory _voterList
    ) external onlyOwner {
        _questSettings = QuestSettings({
            minRewardPerVote: _minRewardPerVote,
            maxRewardPerVote: _maxRewardPerVote,
            voteType: _voteType,
            closeType: _closeType
        });

        delete questVoterList;
        uint256 length = _voterList.length;
        for (uint256 i = 0; i < length; i++) {
            questVoterList.push(_voterList[i]);
        }

        emit SettingsUpdated();
        emit SettingsRewardPerVoteUpdated(_minRewardPerVote, _maxRewardPerVote);
    }

    function updateQuestRewardPerVote(
        uint256 _minRewardPerVote,
        uint256 _maxRewardPerVote
    ) external onlyOwner {
        _questSettings.minRewardPerVote = _minRewardPerVote;
        _questSettings.maxRewardPerVote = _maxRewardPerVote;

        emit SettingsRewardPerVoteUpdated(_minRewardPerVote, _maxRewardPerVote);
    }

    function updateQuestTypeSettings(
        IQuestBoard.QuestVoteType _voteType,
        IQuestBoard.QuestCloseType _closeType,
        address[] memory _voterList
    ) external onlyOwner {
        _questSettings.voteType = _voteType;
        _questSettings.closeType = _closeType;

        delete questVoterList;
        uint256 length = _voterList.length;
        for (uint256 i = 0; i < length; i++) {
            questVoterList.push(_voterList[i]);
        }

        emit SettingsUpdated();
    }
 
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {IERC20} from "openzeppelin/contracts/interfaces/IERC20.sol";
import {SafeERC20} from "openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import {IGovernance, UNREGISTERED_INITIATIVE} from "./interfaces/IGovernance.sol";
import {IInitiative} from "./interfaces/IInitiative.sol";
import {IBribeInitiative} from "./interfaces/IBribeInitiative.sol";

import {DoubleLinkedList} from "./utils/DoubleLinkedList.sol";
import {_lqtyToVotes} from "./utils/VotingPower.sol";

contract BribeInitiative is IInitiative, IBribeInitiative {
    using SafeERC20 for IERC20;
    using DoubleLinkedList for DoubleLinkedList.List;

    uint256 internal immutable EPOCH_START;
    uint256 internal immutable EPOCH_DURATION;

    /// @inheritdoc IBribeInitiative
    IGovernance public immutable governance;
    /// @inheritdoc IBribeInitiative
    IERC20 public immutable bold;
    /// @inheritdoc IBribeInitiative
    IERC20 public immutable bribeToken;

    /// @inheritdoc IBribeInitiative
    mapping(uint256 => Bribe) public bribeByEpoch;
    /// @inheritdoc IBribeInitiative
    mapping(address => mapping(uint256 => bool)) public claimedBribeAtEpoch;

    /// Double linked list of the total LQTY allocated at a given epoch
    DoubleLinkedList.List internal totalLQTYAllocationByEpoch;
    /// Double linked list of LQTY allocated by a user at a given epoch
    mapping(address => DoubleLinkedList.List) internal lqtyAllocationByUserAtEpoch;

    constructor(address _governance, address _bold, address _bribeToken) {
        require(_bribeToken != _bold, "BribeInitiative: bribe-token-cannot-be-bold");

        governance = IGovernance(_governance);
        bold = IERC20(_bold);
        bribeToken = IERC20(_bribeToken);

        EPOCH_START = governance.EPOCH_START();
        EPOCH_DURATION = governance.EPOCH_DURATION();
    }

    modifier onlyGovernance() {
        require(msg.sender == address(governance), "BribeInitiative: invalid-sender");
        _;
    }

    /// @inheritdoc IBribeInitiative
    function totalLQTYAllocatedByEpoch(uint256 _epoch) external view returns (uint256, uint256) {
        return (totalLQTYAllocationByEpoch.items[_epoch].lqty, totalLQTYAllocationByEpoch.items[_epoch].offset);
    }

    /// @inheritdoc IBribeInitiative
    function lqtyAllocatedByUserAtEpoch(address _user, uint256 _epoch) external view returns (uint256, uint256) {
        return (
            lqtyAllocationByUserAtEpoch[_user].items[_epoch].lqty,
            lqtyAllocationByUserAtEpoch[_user].items[_epoch].offset
        );
    }

    /// @inheritdoc IBribeInitiative
    function depositBribe(uint256 _boldAmount, uint256 _bribeTokenAmount, uint256 _epoch) external {
        uint256 epoch = governance.epoch();
        require(_epoch >= epoch, "BribeInitiative: now-or-future-epochs");

        bribeByEpoch[_epoch].remainingBoldAmount += _boldAmount;
        bribeByEpoch[_epoch].remainingBribeTokenAmount += _bribeTokenAmount;

        emit DepositBribe(msg.sender, _boldAmount, _bribeTokenAmount, _epoch);

        bold.safeTransferFrom(msg.sender, address(this), _boldAmount);
        bribeToken.safeTransferFrom(msg.sender, address(this), _bribeTokenAmount);
    }

    function _claimBribe(
        address _user,
        uint256 _epoch,
        uint256 _prevLQTYAllocationEpoch,
        uint256 _prevTotalLQTYAllocationEpoch
    ) internal returns (uint256 boldAmount, uint256 bribeTokenAmount) {
        require(_epoch < governance.epoch(), "BribeInitiative: cannot-claim-for-current-epoch");
        require(!claimedBribeAtEpoch[_user][_epoch], "BribeInitiative: already-claimed");

        Bribe memory bribe = bribeByEpoch[_epoch];
        require(bribe.remainingBoldAmount != 0 || bribe.remainingBribeTokenAmount != 0, "BribeInitiative: no-bribe");

        DoubleLinkedList.Item memory lqtyAllocation =
            lqtyAllocationByUserAtEpoch[_user].getItem(_prevLQTYAllocationEpoch);

        require(
            _prevLQTYAllocationEpoch <= _epoch && (lqtyAllocation.next > _epoch || lqtyAllocation.next == 0),
            "BribeInitiative: invalid-prev-lqty-allocation-epoch"
        );
        DoubleLinkedList.Item memory totalLQTYAllocation =
            totalLQTYAllocationByEpoch.getItem(_prevTotalLQTYAllocationEpoch);
        require(
            _prevTotalLQTYAllocationEpoch <= _epoch
                && (totalLQTYAllocation.next > _epoch || totalLQTYAllocation.next == 0),
            "BribeInitiative: invalid-prev-total-lqty-allocation-epoch"
        );

        require(totalLQTYAllocation.lqty > 0, "BribeInitiative: total-lqty-allocation-zero");
        require(lqtyAllocation.lqty > 0, "BribeInitiative: lqty-allocation-zero");

        // `Governance` guarantees that `votes` evaluates to 0 or greater for each initiative at the time of allocation.
        // Since the last possible moment to allocate within this epoch is 1 second before `epochEnd`, we have that:
        //  - `lqtyAllocation.lqty > 0` implies `votes > 0`
        //  - `totalLQTYAllocation.lqty > 0` implies `totalVotes > 0`

        uint256 epochEnd = EPOCH_START + _epoch * EPOCH_DURATION;
        uint256 totalVotes = _lqtyToVotes(totalLQTYAllocation.lqty, epochEnd, totalLQTYAllocation.offset);
        uint256 votes = _lqtyToVotes(lqtyAllocation.lqty, epochEnd, lqtyAllocation.offset);
        uint256 remainingVotes = totalVotes - bribe.claimedVotes;

        boldAmount = bribe.remainingBoldAmount * votes / remainingVotes;
        bribeTokenAmount = bribe.remainingBribeTokenAmount * votes / remainingVotes;
        bribe.remainingBoldAmount -= boldAmount;
        bribe.remainingBribeTokenAmount -= bribeTokenAmount;
        bribe.claimedVotes += votes;

        bribeByEpoch[_epoch] = bribe;
        claimedBribeAtEpoch[_user][_epoch] = true;

        emit ClaimBribe(_user, _epoch, boldAmount, bribeTokenAmount);
    }

    /// @inheritdoc IBribeInitiative
    function claimBribes(ClaimData[] calldata _claimData)
        external
        returns (uint256 boldAmount, uint256 bribeTokenAmount)
    {
        for (uint256 i = 0; i < _claimData.length; i++) {
            ClaimData memory claimData = _claimData[i];
            (uint256 boldAmount_, uint256 bribeTokenAmount_) = _claimBribe(
                msg.sender, claimData.epoch, claimData.prevLQTYAllocationEpoch, claimData.prevTotalLQTYAllocationEpoch
            );
            boldAmount += boldAmount_;
            bribeTokenAmount += bribeTokenAmount_;
        }

        if (boldAmount != 0) bold.safeTransfer(msg.sender, boldAmount);
        if (bribeTokenAmount != 0) bribeToken.safeTransfer(msg.sender, bribeTokenAmount);
    }

    /// @inheritdoc IInitiative
    function onRegisterInitiative(uint256) external virtual override onlyGovernance {}

    /// @inheritdoc IInitiative
    function onUnregisterInitiative(uint256) external virtual override onlyGovernance {}

    function _setTotalLQTYAllocationByEpoch(uint256 _epoch, uint256 _lqty, uint256 _offset, bool _insert) private {
        if (_insert) {
            totalLQTYAllocationByEpoch.insert(_epoch, _lqty, _offset, 0);
        } else {
            totalLQTYAllocationByEpoch.items[_epoch].lqty = _lqty;
            totalLQTYAllocationByEpoch.items[_epoch].offset = _offset;
        }
        emit ModifyTotalLQTYAllocation(_epoch, _lqty, _offset);
    }

    function _setLQTYAllocationByUserAtEpoch(
        address _user,
        uint256 _epoch,
        uint256 _lqty,
        uint256 _offset,
        bool _insert
    ) private {
        if (_insert) {
            lqtyAllocationByUserAtEpoch[_user].insert(_epoch, _lqty, _offset, 0);
        } else {
            lqtyAllocationByUserAtEpoch[_user].items[_epoch].lqty = _lqty;
            lqtyAllocationByUserAtEpoch[_user].items[_epoch].offset = _offset;
        }
        emit ModifyLQTYAllocation(_user, _epoch, _lqty, _offset);
    }

    /// @inheritdoc IBribeInitiative
    function getMostRecentUserEpoch(address _user) external view returns (uint256) {
        uint256 mostRecentUserEpoch = lqtyAllocationByUserAtEpoch[_user].getHead();

        return mostRecentUserEpoch;
    }

    /// @inheritdoc IBribeInitiative
    function getMostRecentTotalEpoch() external view returns (uint256) {
        uint256 mostRecentTotalEpoch = totalLQTYAllocationByEpoch.getHead();

        return mostRecentTotalEpoch;
    }

    function onAfterAllocateLQTY(
        uint256 _currentEpoch,
        address _user,
        IGovernance.UserState calldata,
        IGovernance.Allocation calldata _allocation,
        IGovernance.InitiativeState calldata _initiativeState
    ) external virtual onlyGovernance {
        uint256 mostRecentUserEpoch = lqtyAllocationByUserAtEpoch[_user].getHead();
        uint256 mostRecentTotalEpoch = totalLQTYAllocationByEpoch.getHead();

        _setTotalLQTYAllocationByEpoch(
            _currentEpoch,
            _initiativeState.voteLQTY,
            _initiativeState.voteOffset,
            mostRecentTotalEpoch != _currentEpoch // Insert if current > recent
        );

        _setLQTYAllocationByUserAtEpoch(
            _user,
            _currentEpoch,
            _allocation.voteLQTY,
            _allocation.voteOffset,
            mostRecentUserEpoch != _currentEpoch // Insert if user current > recent
        );
    }

    /// @inheritdoc IInitiative
    function onClaimForInitiative(uint256, uint256) external virtual override onlyGovernance {}
}

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

pragma solidity ^0.8.20;

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

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

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

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

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

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

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

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

pragma solidity ^0.8.20;

import {Context} from "../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.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

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

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

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

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

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

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

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

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

File 5 of 18 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

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

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

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

// SPDX-License-Identifier: None

pragma solidity 0.8.24;

interface IQuestBoard {
    enum QuestVoteType {
        NORMAL,
        BLACKLIST,
        WHITELIST
    }
    enum QuestCloseType {
        NORMAL,
        ROLLOVER,
        DISTRIBUTE
    }

    enum QuestRewardsType { FIXED, RANGE }

    /** @notice Struct with all the Quest types */
    struct QuestTypes {
        QuestVoteType voteType;
        QuestRewardsType rewardsType;
        QuestCloseType closeType;
    }

    struct Quest {
        // Address of the Quest creator (caller of createQuest() method)
        address creator;
        // Address of the ERC20 used for rewards
        address rewardToken;
        // Address of the target Gauge
        address gauge;
        // Total number of periods for the Quest
        uint48 duration;
        // Timestamp where the 1st QuestPeriod starts
        uint48 periodStart;
        // Total amount of rewards paid for this Quest
        // If changes were made to the parameters of this Quest, this will account
        // any added reward amounts
        uint256 totalRewardAmount;
        // Total reward amount that can be distributed for each period
        uint256 rewardAmountPerPeriod;
        // Min Amount of reward for each vote (for 1 veToken)
        uint256 minRewardPerVote;
        // Max Amount of reward for each vote (for 1 veToken)
        uint256 maxRewardPerVote;
        // Min Target Bias for the Gauge
        uint256 minObjectiveVotes;
        // Max Target Bias for the Gauge
        uint256 maxObjectiveVotes;
        // Quest Types
        QuestTypes types;
    }

    function createFixedQuest(
        address gauge,
        address rewardToken,
        bool startNextPeriod,
        uint48 duration,
        uint256 rewardPerVote,
        uint256 totalRewardAmount,
        uint256 feeAmount,
        QuestVoteType voteType,
        QuestCloseType closeType,
        address[] calldata voterList
    ) external returns (uint256);

    function createRangedQuest(
        address gauge,
        address rewardToken,
        bool startNextPeriod,
        uint48 duration,
        uint256 minRewardPerVote,
        uint256 maxRewardPerVote,
        uint256 totalRewardAmount,
        uint256 feeAmount,
        QuestVoteType voteType,
        QuestCloseType closeType,
        address[] calldata voterList
    ) external returns (uint256);

    function platformFeeRatio() external view returns (uint256);
    function customPlatformFeeRatio(address) external view returns (uint256);

    function getAllPeriodsForQuestId(uint256 questID) external view returns (uint48[] memory);

    function getCurrentPeriod() external view returns (uint256);

    function questWithdrawableAmount(uint256 questID) external view returns (uint256);

    function withdrawUnusedRewards(uint256 questID, address recipient) external;
}

File 8 of 18 : IGovernance.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {IERC20} from "openzeppelin/contracts/interfaces/IERC20.sol";

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

import {PermitParams} from "../utils/Types.sol";

uint256 constant UNREGISTERED_INITIATIVE = type(uint256).max;

interface IGovernance {
    enum HookStatus {
        Failed,
        Succeeded,
        NotCalled
    }

    /// @notice Emitted when a user deposits LQTY
    /// @param user The account depositing LQTY
    /// @param rewardRecipient The account receiving the LUSD/ETH rewards earned from staking in V1, if claimed
    /// @param lqtyAmount The amount of LQTY being deposited
    /// @return lusdReceived Amount of LUSD tokens received as a side-effect of staking new LQTY
    /// @return lusdSent Amount of LUSD tokens sent to `rewardRecipient` (may include previously received LUSD)
    /// @return ethReceived Amount of ETH received as a side-effect of staking new LQTY
    /// @return ethSent Amount of ETH sent to `rewardRecipient` (may include previously received ETH)
    event DepositLQTY(
        address indexed user,
        address rewardRecipient,
        uint256 lqtyAmount,
        uint256 lusdReceived,
        uint256 lusdSent,
        uint256 ethReceived,
        uint256 ethSent
    );

    /// @notice Emitted when a user withdraws LQTY or claims V1 staking rewards
    /// @param user The account withdrawing LQTY or claiming V1 staking rewards
    /// @param recipient The account receiving the LQTY withdrawn, and if claimed, the LUSD/ETH rewards earned from staking in V1
    /// @return lqtyReceived Amount of LQTY tokens actually withdrawn (may be lower than the `_lqtyAmount` passed to `withdrawLQTY`)
    /// @return lqtySent Amount of LQTY tokens sent to `recipient` (may include LQTY sent to the user's proxy from sources other than V1 staking)
    /// @return lusdReceived Amount of LUSD tokens received as a side-effect of staking new LQTY
    /// @return lusdSent Amount of LUSD tokens sent to `recipient` (may include previously received LUSD)
    /// @return ethReceived Amount of ETH received as a side-effect of staking new LQTY
    /// @return ethSent Amount of ETH sent to `recipient` (may include previously received ETH)
    event WithdrawLQTY(
        address indexed user,
        address recipient,
        uint256 lqtyReceived,
        uint256 lqtySent,
        uint256 lusdReceived,
        uint256 lusdSent,
        uint256 ethReceived,
        uint256 ethSent
    );

    event SnapshotVotes(uint256 votes, uint256 forEpoch, uint256 boldAccrued);
    event SnapshotVotesForInitiative(address indexed initiative, uint256 votes, uint256 vetos, uint256 forEpoch);

    event RegisterInitiative(address initiative, address registrant, uint256 atEpoch, HookStatus hookStatus);
    event UnregisterInitiative(address initiative, uint256 atEpoch, HookStatus hookStatus);

    event AllocateLQTY(
        address indexed user,
        address indexed initiative,
        int256 deltaVoteLQTY,
        int256 deltaVetoLQTY,
        uint256 atEpoch,
        HookStatus hookStatus
    );
    event ClaimForInitiative(address indexed initiative, uint256 bold, uint256 forEpoch, HookStatus hookStatus);

    struct Configuration {
        uint256 registrationFee;
        uint256 registrationThresholdFactor;
        uint256 unregistrationThresholdFactor;
        uint256 unregistrationAfterEpochs;
        uint256 votingThresholdFactor;
        uint256 minClaim;
        uint256 minAccrual;
        uint256 epochStart;
        uint256 epochDuration;
        uint256 epochVotingCutoff;
    }

    function registerInitialInitiatives(address[] memory _initiatives) external;

    /// @notice Address of the LQTY StakingV1 contract
    /// @return stakingV1 Address of the LQTY StakingV1 contract
    function stakingV1() external view returns (ILQTYStaking stakingV1);
    /// @notice Address of the LQTY token
    /// @return lqty Address of the LQTY token
    function lqty() external view returns (IERC20 lqty);
    /// @notice Address of the BOLD token
    /// @return bold Address of the BOLD token
    function bold() external view returns (IERC20 bold);
    /// @notice Timestamp at which the first epoch starts
    /// @return epochStart Timestamp at which the first epoch starts
    function EPOCH_START() external view returns (uint256 epochStart);
    /// @notice Duration of an epoch in seconds (e.g. 1 week)
    /// @return epochDuration Epoch duration
    function EPOCH_DURATION() external view returns (uint256 epochDuration);
    /// @notice Voting period of an epoch in seconds (e.g. 6 days)
    /// @return epochVotingCutoff Epoch voting cutoff
    function EPOCH_VOTING_CUTOFF() external view returns (uint256 epochVotingCutoff);
    /// @notice Minimum BOLD amount that has to be claimed, if an initiative doesn't have enough votes to meet the
    /// criteria then it's votes a excluded from the vote count and distribution
    /// @return minClaim Minimum claim amount
    function MIN_CLAIM() external view returns (uint256 minClaim);
    /// @notice Minimum amount of BOLD that have to be accrued for an epoch, otherwise accrual will be skipped for
    /// that epoch
    /// @return minAccrual Minimum amount of BOLD
    function MIN_ACCRUAL() external view returns (uint256 minAccrual);
    /// @notice Amount of BOLD to be paid in order to register a new initiative
    /// @return registrationFee Registration fee
    function REGISTRATION_FEE() external view returns (uint256 registrationFee);
    /// @notice Share of all votes that are necessary to register a new initiative
    /// @return registrationThresholdFactor Threshold factor
    function REGISTRATION_THRESHOLD_FACTOR() external view returns (uint256 registrationThresholdFactor);
    /// @notice Multiple of the voting threshold in vetos that are necessary to unregister an initiative
    /// @return unregistrationThresholdFactor Unregistration threshold factor
    function UNREGISTRATION_THRESHOLD_FACTOR() external view returns (uint256 unregistrationThresholdFactor);
    /// @notice Number of epochs an initiative has to be inactive before it can be unregistered
    /// @return unregistrationAfterEpochs Number of epochs
    function UNREGISTRATION_AFTER_EPOCHS() external view returns (uint256 unregistrationAfterEpochs);
    /// @notice Share of all votes that are necessary for an initiative to be included in the vote count
    /// @return votingThresholdFactor Voting threshold factor
    function VOTING_THRESHOLD_FACTOR() external view returns (uint256 votingThresholdFactor);

    /// @notice Returns the amount of BOLD accrued since last epoch (last snapshot)
    /// @return boldAccrued BOLD accrued
    function boldAccrued() external view returns (uint256 boldAccrued);

    struct VoteSnapshot {
        uint256 votes; // Votes at epoch transition
        uint256 forEpoch; // Epoch for which the votes are counted
    }

    struct InitiativeVoteSnapshot {
        uint256 votes; // Votes at epoch transition
        uint256 forEpoch; // Epoch for which the votes are counted
        uint256 lastCountedEpoch; // Epoch at which which the votes where counted last in the global snapshot
        uint256 vetos; // Vetos at epoch transition
    }

    /// @notice Returns the vote count snapshot of the previous epoch
    /// @return votes Number of votes
    /// @return forEpoch Epoch for which the votes are counted
    function votesSnapshot() external view returns (uint256 votes, uint256 forEpoch);
    /// @notice Returns the vote count snapshot for an initiative of the previous epoch
    /// @param _initiative Address of the initiative
    /// @return votes Number of votes
    /// @return forEpoch Epoch for which the votes are counted
    /// @return lastCountedEpoch Epoch at which which the votes where counted last in the global snapshot
    function votesForInitiativeSnapshot(address _initiative)
        external
        view
        returns (uint256 votes, uint256 forEpoch, uint256 lastCountedEpoch, uint256 vetos);

    struct Allocation {
        uint256 voteLQTY; // LQTY allocated vouching for the initiative
        uint256 voteOffset; // Offset associated with LQTY vouching for the initiative
        uint256 vetoLQTY; // LQTY vetoing the initiative
        uint256 vetoOffset; // Offset associated with LQTY vetoing the initiative
        uint256 atEpoch; // Epoch at which the allocation was last updated
    }

    struct UserState {
        uint256 unallocatedLQTY; // LQTY deposited and unallocated
        uint256 unallocatedOffset; // The offset sum corresponding to the unallocated LQTY
        uint256 allocatedLQTY; // LQTY allocated by the user to initatives
        uint256 allocatedOffset; // The offset sum corresponding to the allocated LQTY
    }

    struct InitiativeState {
        uint256 voteLQTY; // LQTY allocated vouching for the initiative
        uint256 voteOffset; // Offset associated with LQTY vouching for to the initative
        uint256 vetoLQTY; // LQTY allocated vetoing the initiative
        uint256 vetoOffset; // Offset associated with LQTY veoting the initative
        uint256 lastEpochClaim;
    }

    struct GlobalState {
        uint256 countedVoteLQTY; // Total LQTY that is included in vote counting
        uint256 countedVoteOffset; // Offset associated with the counted vote LQTY
    }

    /// @notice Returns the user's state
    /// @return unallocatedLQTY LQTY deposited and unallocated
    /// @return unallocatedOffset Offset associated with unallocated LQTY
    /// @return allocatedLQTY allocated by the user to initatives
    /// @return allocatedOffset Offset associated with allocated LQTY
    function userStates(address _user)
        external
        view
        returns (uint256 unallocatedLQTY, uint256 unallocatedOffset, uint256 allocatedLQTY, uint256 allocatedOffset);
    /// @notice Returns the initiative's state
    /// @param _initiative Address of the initiative
    /// @return voteLQTY LQTY allocated vouching for the initiative
    /// @return voteOffset Offset associated with voteLQTY
    /// @return vetoLQTY LQTY allocated vetoing the initiative
    /// @return vetoOffset Offset associated with vetoLQTY
    /// @return lastEpochClaim // Last epoch at which rewards were claimed
    function initiativeStates(address _initiative)
        external
        view
        returns (uint256 voteLQTY, uint256 voteOffset, uint256 vetoLQTY, uint256 vetoOffset, uint256 lastEpochClaim);
    /// @notice Returns the global state
    /// @return countedVoteLQTY Total LQTY that is included in vote counting
    /// @return countedVoteOffset Offset associated with countedVoteLQTY
    function globalState() external view returns (uint256 countedVoteLQTY, uint256 countedVoteOffset);
    /// @notice Returns the amount of voting and vetoing LQTY a user allocated to an initiative
    /// @param _user Address of the user
    /// @param _initiative Address of the initiative
    /// @return voteLQTY LQTY allocated vouching for the initiative
    /// @return voteOffset The offset associated with voteLQTY
    /// @return vetoLQTY allocated vetoing the initiative
    /// @return vetoOffset the offset associated with vetoLQTY
    /// @return atEpoch Epoch at which the allocation was last updated
    function lqtyAllocatedByUserToInitiative(address _user, address _initiative)
        external
        view
        returns (uint256 voteLQTY, uint256 voteOffset, uint256 vetoLQTY, uint256 vetoOffset, uint256 atEpoch);

    /// @notice Returns when an initiative was registered
    /// @param _initiative Address of the initiative
    /// @return atEpoch If `_initiative` is an active initiative, returns the epoch at which it was registered.
    ///                 If `_initiative` hasn't been registered, returns 0.
    ///                 If `_initiative` has been unregistered, returns `UNREGISTERED_INITIATIVE`.
    function registeredInitiatives(address _initiative) external view returns (uint256 atEpoch);

    /*//////////////////////////////////////////////////////////////
                                STAKING
    //////////////////////////////////////////////////////////////*/

    /// @notice Deposits LQTY
    /// @dev The caller has to approve their `UserProxy` address to spend the LQTY tokens
    /// @param _lqtyAmount Amount of LQTY to deposit
    function depositLQTY(uint256 _lqtyAmount) external;

    /// @notice Deposits LQTY
    /// @dev The caller has to approve their `UserProxy` address to spend the LQTY tokens
    /// @param _lqtyAmount Amount of LQTY to deposit
    /// @param _doSendRewards If true, send rewards claimed from LQTY staking
    /// @param _recipient Address to which the tokens should be sent
    function depositLQTY(uint256 _lqtyAmount, bool _doSendRewards, address _recipient) external;

    /// @notice Deposits LQTY via Permit
    /// @param _lqtyAmount Amount of LQTY to deposit
    /// @param _permitParams Permit parameters
    function depositLQTYViaPermit(uint256 _lqtyAmount, PermitParams calldata _permitParams) external;

    /// @notice Deposits LQTY via Permit
    /// @param _lqtyAmount Amount of LQTY to deposit
    /// @param _permitParams Permit parameters
    /// @param _doSendRewards If true, send rewards claimed from LQTY staking
    /// @param _recipient Address to which the tokens should be sent
    function depositLQTYViaPermit(
        uint256 _lqtyAmount,
        PermitParams calldata _permitParams,
        bool _doSendRewards,
        address _recipient
    ) external;

    /// @notice Withdraws LQTY and claims any accrued LUSD and ETH rewards from StakingV1
    /// @param _lqtyAmount Amount of LQTY to withdraw
    function withdrawLQTY(uint256 _lqtyAmount) external;

    /// @notice Withdraws LQTY and claims any accrued LUSD and ETH rewards from StakingV1
    /// @param _lqtyAmount Amount of LQTY to withdraw
    /// @param _doSendRewards If true, send rewards claimed from LQTY staking
    /// @param _recipient Address to which the tokens should be sent
    function withdrawLQTY(uint256 _lqtyAmount, bool _doSendRewards, address _recipient) external;

    /// @notice Claims staking rewards from StakingV1 without unstaking
    /// @dev Note: in the unlikely event that the caller's `UserProxy` holds any LQTY tokens, they will also be sent to `_rewardRecipient`
    /// @param _rewardRecipient Address that will receive the rewards
    /// @return lusdSent Amount of LUSD tokens sent to `_rewardRecipient` (may include previously received LUSD)
    /// @return ethSent Amount of ETH sent to `_rewardRecipient` (may include previously received ETH)
    function claimFromStakingV1(address _rewardRecipient) external returns (uint256 lusdSent, uint256 ethSent);

    /*//////////////////////////////////////////////////////////////
                                 VOTING
    //////////////////////////////////////////////////////////////*/

    /// @notice Returns the current epoch number
    /// @return epoch Current epoch
    function epoch() external view returns (uint256 epoch);
    /// @notice Returns the timestamp at which the current epoch started
    /// @return epochStart Epoch start of the current epoch
    function epochStart() external view returns (uint256 epochStart);
    /// @notice Returns the number of seconds that have gone by since the current epoch started
    /// @return secondsWithinEpoch Seconds within the current epoch
    function secondsWithinEpoch() external view returns (uint256 secondsWithinEpoch);

    /// @notice Returns the voting power for an entity (i.e. user or initiative) at a given timestamp
    /// @param _lqtyAmount Amount of LQTY associated with the entity
    /// @param _timestamp Timestamp at which to calculate voting power
    /// @param _offset The entity's offset sum
    /// @return votes Number of votes
    function lqtyToVotes(uint256 _lqtyAmount, uint256 _timestamp, uint256 _offset) external pure returns (uint256);

    /// @dev Returns the most up to date voting threshold
    /// In contrast to `getLatestVotingThreshold` this function updates the snapshot
    /// This ensures that the value returned is always the latest
    function calculateVotingThreshold() external returns (uint256);

    /// @dev Utility function to compute the threshold votes without recomputing the snapshot
    /// Note that `boldAccrued` is a cached value, this function works correctly only when called after an accrual
    function calculateVotingThreshold(uint256 _votes) external view returns (uint256);

    /// @notice Return the most up to date global snapshot and state as well as a flag to notify whether the state can be updated
    /// This is a convenience function to always retrieve the most up to date state values
    function getTotalVotesAndState()
        external
        view
        returns (VoteSnapshot memory snapshot, GlobalState memory state, bool shouldUpdate);

    /// @dev Given an initiative address, return it's most up to date snapshot and state as well as a flag to notify whether the state can be updated
    /// This is a convenience function to always retrieve the most up to date state values
    function getInitiativeSnapshotAndState(address _initiative)
        external
        view
        returns (
            InitiativeVoteSnapshot memory initiativeSnapshot,
            InitiativeState memory initiativeState,
            bool shouldUpdate
        );

    /// @notice Voting threshold is the max. of either:
    ///   - 4% of the total voting LQTY in the previous epoch
    ///   - or the minimum number of votes necessary to claim at least MIN_CLAIM BOLD
    /// This value can be offsynch, use the non view `calculateVotingThreshold` to always retrieve the most up to date value
    /// @return votingThreshold Voting threshold
    function getLatestVotingThreshold() external view returns (uint256 votingThreshold);

    /// @notice Snapshots votes for the previous epoch and accrues funds for the current epoch
    /// @param _initiative Address of the initiative
    /// @return voteSnapshot Vote snapshot
    /// @return initiativeVoteSnapshot Vote snapshot of the initiative
    function snapshotVotesForInitiative(address _initiative)
        external
        returns (VoteSnapshot memory voteSnapshot, InitiativeVoteSnapshot memory initiativeVoteSnapshot);

    /*//////////////////////////////////////////////////////////////
                                 FSM
    //////////////////////////////////////////////////////////////*/

    enum InitiativeStatus {
        NONEXISTENT,
        /// This Initiative Doesn't exist | This is never returned
        WARM_UP,
        /// This epoch was just registered
        SKIP,
        /// This epoch will result in no rewards and no unregistering
        CLAIMABLE,
        /// This epoch will result in claiming rewards
        CLAIMED,
        /// The rewards for this epoch have been claimed
        UNREGISTERABLE,
        /// Can be unregistered
        DISABLED // It was already Unregistered

    }

    function getInitiativeState(address _initiative)
        external
        returns (InitiativeStatus status, uint256 lastEpochClaim, uint256 claimableAmount);

    function getInitiativeState(
        address _initiative,
        VoteSnapshot memory _votesSnapshot,
        InitiativeVoteSnapshot memory _votesForInitiativeSnapshot,
        InitiativeState memory _initiativeState
    ) external view returns (InitiativeStatus status, uint256 lastEpochClaim, uint256 claimableAmount);

    /// @notice Registers a new initiative
    /// @param _initiative Address of the initiative
    function registerInitiative(address _initiative) external;
    // /// @notice Unregisters an initiative if it didn't receive enough votes in the last 4 epochs
    // /// or if it received more vetos than votes and the number of vetos are greater than 3 times the voting threshold
    // /// @param _initiative Address of the initiative
    function unregisterInitiative(address _initiative) external;

    /// @notice Allocates the user's LQTY to initiatives
    /// @dev The user can only allocate to active initiatives (older than 1 epoch) and has to have enough unallocated
    /// LQTY available, the initiatives listed must be unique, and towards the end of the epoch a user can only maintain or reduce their votes
    /// @param _initiativesToReset Addresses of the initiatives the caller was previously allocated to, must be reset to prevent desynch of voting power
    /// @param _initiatives Addresses of the initiatives to allocate to, can match or be different from `_resetInitiatives`
    /// @param _absoluteLQTYVotes LQTY to allocate to the initiatives as votes
    /// @param _absoluteLQTYVetos LQTY to allocate to the initiatives as vetos
    function allocateLQTY(
        address[] calldata _initiativesToReset,
        address[] memory _initiatives,
        int256[] memory _absoluteLQTYVotes,
        int256[] memory _absoluteLQTYVetos
    ) external;
    /// @notice Deallocates the user's LQTY from initiatives
    /// @param _initiativesToReset Addresses of initiatives to deallocate LQTY from
    /// @param _checkAll When true, the call will revert if there is still some allocated LQTY left after deallocating
    ///                  from all the addresses in `_initiativesToReset`
    function resetAllocations(address[] calldata _initiativesToReset, bool _checkAll) external;

    /// @notice Splits accrued funds according to votes received between all initiatives
    /// @param _initiative Addresse of the initiative
    /// @return claimed Amount of BOLD claimed
    function claimForInitiative(address _initiative) external returns (uint256 claimed);
}

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

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

interface IInitiative {
    /// @notice Callback hook that is called by Governance after the initiative was successfully registered
    /// @param _atEpoch Epoch at which the initiative is registered
    function onRegisterInitiative(uint256 _atEpoch) external;

    /// @notice Callback hook that is called by Governance after the initiative was unregistered
    /// @param _atEpoch Epoch at which the initiative is unregistered
    function onUnregisterInitiative(uint256 _atEpoch) external;

    /// @notice Callback hook that is called by Governance after the LQTY allocation is updated by a user
    /// @param _currentEpoch Epoch at which the LQTY allocation is updated
    /// @param _user Address of the user that updated their LQTY allocation
    /// @param _userState User state
    /// @param _allocation Allocation state from user to initiative
    /// @param _initiativeState Initiative state
    function onAfterAllocateLQTY(
        uint256 _currentEpoch,
        address _user,
        IGovernance.UserState calldata _userState,
        IGovernance.Allocation calldata _allocation,
        IGovernance.InitiativeState calldata _initiativeState
    ) external;

    /// @notice Callback hook that is called by Governance after the claim for the last epoch was distributed
    /// to the initiative
    /// @param _claimEpoch Epoch at which the claim was distributed
    /// @param _bold Amount of BOLD that was distributed
    function onClaimForInitiative(uint256 _claimEpoch, uint256 _bold) external;
}

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

import {IERC20} from "openzeppelin/contracts/interfaces/IERC20.sol";

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

interface IBribeInitiative {
    event DepositBribe(address depositor, uint256 boldAmount, uint256 bribeTokenAmount, uint256 epoch);
    event ModifyLQTYAllocation(address user, uint256 epoch, uint256 lqtyAllocated, uint256 offset);
    event ModifyTotalLQTYAllocation(uint256 epoch, uint256 totalLQTYAllocated, uint256 offset);
    event ClaimBribe(address user, uint256 epoch, uint256 boldAmount, uint256 bribeTokenAmount);

    /// @notice Address of the governance contract
    /// @return governance Adress of the governance contract
    function governance() external view returns (IGovernance governance);
    /// @notice Address of the BOLD token
    /// @return bold Address of the BOLD token
    function bold() external view returns (IERC20 bold);
    /// @notice Address of the bribe token
    /// @return bribeToken Address of the bribe token
    function bribeToken() external view returns (IERC20 bribeToken);

    struct Bribe {
        uint256 remainingBoldAmount;
        uint256 remainingBribeTokenAmount; // [scaled as 10 ** bribeToken.decimals()]
        uint256 claimedVotes;
    }

    /// @notice Amount of bribe tokens deposited for a given epoch
    /// @param _epoch Epoch at which the bribe was deposited
    /// @return remainingBoldAmount Amount of BOLD tokens that haven't been claimed yet
    /// @return remainingBribeTokenAmount Amount of bribe tokens that haven't been claimed yet
    /// @return claimedVotes Sum of voting power of users who have already claimed their bribes
    function bribeByEpoch(uint256 _epoch)
        external
        view
        returns (uint256 remainingBoldAmount, uint256 remainingBribeTokenAmount, uint256 claimedVotes);
    /// @notice Check if a user has claimed bribes for a given epoch
    /// @param _user Address of the user
    /// @param _epoch Epoch at which the bribe may have been claimed by the user
    /// @return claimed If the user has claimed the bribe
    function claimedBribeAtEpoch(address _user, uint256 _epoch) external view returns (bool claimed);

    /// @notice Total LQTY allocated to the initiative at a given epoch
    ///         Voting power can be calculated as `totalLQTYAllocated * timestamp - offset`
    /// @param _epoch Epoch at which the LQTY was allocated
    /// @return totalLQTYAllocated Total LQTY allocated
    /// @return offset Voting power offset
    function totalLQTYAllocatedByEpoch(uint256 _epoch)
        external
        view
        returns (uint256 totalLQTYAllocated, uint256 offset);
    /// @notice LQTY allocated by a user to the initiative at a given epoch
    ///         Voting power can be calculated as `lqtyAllocated * timestamp - offset`
    /// @param _user Address of the user
    /// @param _epoch Epoch at which the LQTY was allocated by the user
    /// @return lqtyAllocated LQTY allocated by the user
    /// @return offset Voting power offset
    function lqtyAllocatedByUserAtEpoch(address _user, uint256 _epoch)
        external
        view
        returns (uint256 lqtyAllocated, uint256 offset);

    /// @notice Deposit bribe tokens for a given epoch
    /// @dev The caller has to approve this contract to spend the BOLD and bribe tokens.
    /// The caller can only deposit bribes for future epochs
    /// @param _boldAmount Amount of BOLD tokens to deposit
    /// @param _bribeTokenAmount Amount of bribe tokens to deposit
    /// @param _epoch Epoch at which the bribe is deposited
    function depositBribe(uint256 _boldAmount, uint256 _bribeTokenAmount, uint256 _epoch) external;

    struct ClaimData {
        // Epoch at which the user wants to claim the bribes
        uint256 epoch;
        // Epoch at which the user updated the LQTY allocation for this initiative
        uint256 prevLQTYAllocationEpoch;
        // Epoch at which the total LQTY allocation is updated for this initiative
        uint256 prevTotalLQTYAllocationEpoch;
    }

    /// @notice Claim bribes for a user
    /// @dev The user can only claim bribes for past epochs.
    /// The arrays `_epochs`, `_prevLQTYAllocationEpochs` and `_prevTotalLQTYAllocationEpochs` should be sorted
    /// from oldest epoch to the newest. The length of the arrays has to be the same.
    /// @param _claimData Array specifying the epochs at which the user wants to claim the bribes
    function claimBribes(ClaimData[] calldata _claimData)
        external
        returns (uint256 boldAmount, uint256 bribeTokenAmount);

    /// @notice Given a user address return the last recorded epoch for their allocation
    function getMostRecentUserEpoch(address _user) external view returns (uint256);

    /// @notice Return the last recorded epoch for the system
    function getMostRecentTotalEpoch() external view returns (uint256);
}

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

/// @title DoubleLinkedList
/// @notice Implements a double linked list where the head is defined as the null item's prev pointer
/// and the tail is defined as the null item's next pointer ([tail][prev][item][next][head])
library DoubleLinkedList {
    struct Item {
        uint256 lqty;
        uint256 offset;
        uint256 prev;
        uint256 next;
    }

    struct List {
        mapping(uint256 => Item) items;
    }

    error IdIsZero();
    error ItemNotInList();
    error ItemInList();

    /// @notice Returns the head item id of the list
    /// @param list Linked list which contains the item
    /// @return _ Id of the head item
    function getHead(List storage list) internal view returns (uint256) {
        return list.items[0].prev;
    }

    /// @notice Returns the tail item id of the list
    /// @param list Linked list which contains the item
    /// @return _ Id of the tail item
    function getTail(List storage list) internal view returns (uint256) {
        return list.items[0].next;
    }

    /// @notice Returns the item id which follows item `id`. Returns the tail item id of the list if the `id` is 0.
    /// @param list Linked list which contains the items
    /// @param id Id of the current item
    /// @return _ Id of the current item's next item
    function getNext(List storage list, uint256 id) internal view returns (uint256) {
        return list.items[id].next;
    }

    /// @notice Returns the item id which precedes item `id`. Returns the head item id of the list if the `id` is 0.
    /// @param list Linked list which contains the items
    /// @param id Id of the current item
    /// @return _ Id of the current item's previous item
    function getPrev(List storage list, uint256 id) internal view returns (uint256) {
        return list.items[id].prev;
    }

    /// @notice Returns the value of item `id`
    /// @param list Linked list which contains the item
    /// @param id Id of the item
    /// @return LQTY associated with the item
    /// @return Offset associated with the item's LQTY
    function getLQTYAndOffset(List storage list, uint256 id) internal view returns (uint256, uint256) {
        return (list.items[id].lqty, list.items[id].offset);
    }

    /// @notice Returns the item `id`
    /// @param list Linked list which contains the item
    /// @param id Id of the item
    /// @return _ Item
    function getItem(List storage list, uint256 id) internal view returns (Item memory) {
        return list.items[id];
    }

    /// @notice Returns whether the list contains item `id`
    /// @param list Linked list which should contain the item
    /// @param id Id of the item to check
    /// @return _ True if the list contains the item, false otherwise
    function contains(List storage list, uint256 id) internal view returns (bool) {
        if (id == 0) revert IdIsZero();
        return (list.items[id].prev != 0 || list.items[id].next != 0 || list.items[0].next == id);
    }

    /// @notice Inserts an item with `id` in the list before item `next`
    /// - if `next` is 0, the item is inserted at the start (head) of the list
    /// @dev This function should not be called with an `id` that is already in the list.
    /// @param list Linked list which contains the next item and into which the new item will be inserted
    /// @param id Id of the item to insert
    /// @param lqty amount of LQTY
    /// @param offset associated with the LQTY amount
    /// @param next Id of the item which should follow item `id`
    function insert(List storage list, uint256 id, uint256 lqty, uint256 offset, uint256 next) internal {
        if (contains(list, id)) revert ItemInList();
        if (next != 0 && !contains(list, next)) revert ItemNotInList();
        uint256 prev = list.items[next].prev;
        list.items[prev].next = id;
        list.items[next].prev = id;
        list.items[id].prev = prev;
        list.items[id].next = next;
        list.items[id].lqty = lqty;
        list.items[id].offset = offset;
    }
}

File 12 of 18 : VotingPower.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

function _lqtyToVotes(uint256 _lqtyAmount, uint256 _timestamp, uint256 _offset) pure returns (uint256) {
    uint256 prod = _lqtyAmount * _timestamp;
    return prod > _offset ? prod - _offset : 0;
}

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

pragma solidity ^0.8.20;

/**
 * @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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

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

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

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

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

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

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}

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

interface ILQTYStaking {
    // --- Events --

    event LQTYTokenAddressSet(address _lqtyTokenAddress);
    event LUSDTokenAddressSet(address _lusdTokenAddress);
    event TroveManagerAddressSet(address _troveManager);
    event BorrowerOperationsAddressSet(address _borrowerOperationsAddress);
    event ActivePoolAddressSet(address _activePoolAddress);

    event StakeChanged(address indexed staker, uint256 newStake);
    event StakingGainsWithdrawn(address indexed staker, uint256 LUSDGain, uint256 ETHGain);
    event F_ETHUpdated(uint256 _F_ETH);
    event F_LUSDUpdated(uint256 _F_LUSD);
    event TotalLQTYStakedUpdated(uint256 _totalLQTYStaked);
    event EtherSent(address _account, uint256 _amount);
    event StakerSnapshotsUpdated(address _staker, uint256 _F_ETH, uint256 _F_LUSD);

    // --- Functions ---

    function setAddresses(
        address _lqtyTokenAddress,
        address _lusdTokenAddress,
        address _troveManagerAddress,
        address _borrowerOperationsAddress,
        address _activePoolAddress
    ) external;

    function stake(uint256 _LQTYamount) external;

    function unstake(uint256 _LQTYamount) external;

    function increaseF_ETH(uint256 _ETHFee) external;

    function increaseF_LUSD(uint256 _LQTYFee) external;

    function getPendingETHGain(address _user) external view returns (uint256);

    function getPendingLUSDGain(address _user) external view returns (uint256);

    function stakes(address _user) external view returns (uint256);

    function totalLQTYStaked() external view returns (uint256);
}

File 18 of 18 : Types.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

struct PermitParams {
    address owner;
    address spender;
    uint256 value;
    uint256 deadline;
    uint8 v;
    bytes32 r;
    bytes32 s;
}

uint256 constant WAD = 1e18;

Settings
{
  "remappings": [
    "forge-std/=lib/forge-std/src/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "liquity-gov/=lib/V2-gov/",
    "openzeppelin-contracts/contracts/=lib/V2-gov/lib/openzeppelin-contracts/contracts/",
    "uniswap/v4-core/=lib/V2-gov/lib/v4-core/",
    "@chimera/=lib/V2-gov/lib/chimera/src/",
    "@ensdomains/=lib/V2-gov/lib/v4-core/node_modules/@ensdomains/",
    "@openzeppelin/=lib/V2-gov/lib/v4-core/lib/openzeppelin-contracts/",
    "@openzeppelin/contracts/=lib/V2-gov/lib/openzeppelin-contracts/contracts/",
    "V2-gov/=lib/V2-gov/",
    "chimera/=lib/V2-gov/lib/chimera/src/",
    "erc4626-tests/=lib/V2-gov/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "hardhat/=lib/V2-gov/lib/v4-core/node_modules/hardhat/",
    "openzeppelin/=lib/V2-gov/lib/openzeppelin-contracts/",
    "solmate/=lib/V2-gov/lib/v4-core/lib/solmate/",
    "v4-core/=lib/V2-gov/lib/v4-core/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 100000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_governance","type":"address"},{"internalType":"address","name":"_bold","type":"address"},{"internalType":"address","name":"_bribeToken","type":"address"},{"internalType":"address","name":"_board","type":"address"},{"internalType":"address","name":"_gauge","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"CannotCreateQuest","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"IdIsZero","type":"error"},{"inputs":[],"name":"ItemInList","type":"error"},{"inputs":[],"name":"ItemNotInList","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"epoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"boldAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bribeTokenAmount","type":"uint256"}],"name":"ClaimBribe","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"boldAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bribeTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"DepositBribe","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"epoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lqtyAllocated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"offset","type":"uint256"}],"name":"ModifyLQTYAllocation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"epoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalLQTYAllocated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"offset","type":"uint256"}],"name":"ModifyTotalLQTYAllocation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"questId","type":"uint256"}],"name":"QuestCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMinRewardPerVote","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxRewardPerVote","type":"uint256"}],"name":"SettingsRewardPerVoteUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"SettingsUpdated","type":"event"},{"inputs":[],"name":"DEFAULT_DURATION","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_questSettings","outputs":[{"internalType":"uint256","name":"minRewardPerVote","type":"uint256"},{"internalType":"uint256","name":"maxRewardPerVote","type":"uint256"},{"internalType":"enum IQuestBoard.QuestVoteType","name":"voteType","type":"uint8"},{"internalType":"enum IQuestBoard.QuestCloseType","name":"closeType","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bold","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"bribeByEpoch","outputs":[{"internalType":"uint256","name":"remainingBoldAmount","type":"uint256"},{"internalType":"uint256","name":"remainingBribeTokenAmount","type":"uint256"},{"internalType":"uint256","name":"claimedVotes","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bribeToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"prevLQTYAllocationEpoch","type":"uint256"},{"internalType":"uint256","name":"prevTotalLQTYAllocationEpoch","type":"uint256"}],"internalType":"struct IBribeInitiative.ClaimData[]","name":"_claimData","type":"tuple[]"}],"name":"claimBribes","outputs":[{"internalType":"uint256","name":"boldAmount","type":"uint256"},{"internalType":"uint256","name":"bribeTokenAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"claimedBribeAtEpoch","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_boldAmount","type":"uint256"},{"internalType":"uint256","name":"_bribeTokenAmount","type":"uint256"},{"internalType":"uint256","name":"_epoch","type":"uint256"}],"name":"depositBribe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getMostRecentTotalEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getMostRecentUserEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"contract IGovernance","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_epoch","type":"uint256"}],"name":"lqtyAllocatedByUserAtEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_currentEpoch","type":"uint256"},{"internalType":"address","name":"_user","type":"address"},{"components":[{"internalType":"uint256","name":"unallocatedLQTY","type":"uint256"},{"internalType":"uint256","name":"unallocatedOffset","type":"uint256"},{"internalType":"uint256","name":"allocatedLQTY","type":"uint256"},{"internalType":"uint256","name":"allocatedOffset","type":"uint256"}],"internalType":"struct IGovernance.UserState","name":"","type":"tuple"},{"components":[{"internalType":"uint256","name":"voteLQTY","type":"uint256"},{"internalType":"uint256","name":"voteOffset","type":"uint256"},{"internalType":"uint256","name":"vetoLQTY","type":"uint256"},{"internalType":"uint256","name":"vetoOffset","type":"uint256"},{"internalType":"uint256","name":"atEpoch","type":"uint256"}],"internalType":"struct IGovernance.Allocation","name":"_allocation","type":"tuple"},{"components":[{"internalType":"uint256","name":"voteLQTY","type":"uint256"},{"internalType":"uint256","name":"voteOffset","type":"uint256"},{"internalType":"uint256","name":"vetoLQTY","type":"uint256"},{"internalType":"uint256","name":"vetoOffset","type":"uint256"},{"internalType":"uint256","name":"lastEpochClaim","type":"uint256"}],"internalType":"struct IGovernance.InitiativeState","name":"_initiativeState","type":"tuple"}],"name":"onAfterAllocateLQTY","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"onClaimForInitiative","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"onRegisterInitiative","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"onUnregisterInitiative","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingBudget","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"previousQuest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"process","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pullBudget","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"questBoard","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"questSettings","outputs":[{"components":[{"internalType":"uint256","name":"minRewardPerVote","type":"uint256"},{"internalType":"uint256","name":"maxRewardPerVote","type":"uint256"},{"internalType":"enum IQuestBoard.QuestVoteType","name":"voteType","type":"uint8"},{"internalType":"enum IQuestBoard.QuestCloseType","name":"closeType","type":"uint8"}],"internalType":"struct QuestInitiative.QuestSettings","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"questVoterList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"targetGauge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epoch","type":"uint256"}],"name":"totalLQTYAllocatedByEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minRewardPerVote","type":"uint256"},{"internalType":"uint256","name":"_maxRewardPerVote","type":"uint256"}],"name":"updateQuestRewardPerVote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minRewardPerVote","type":"uint256"},{"internalType":"uint256","name":"_maxRewardPerVote","type":"uint256"},{"internalType":"enum IQuestBoard.QuestVoteType","name":"_voteType","type":"uint8"},{"internalType":"enum IQuestBoard.QuestCloseType","name":"_closeType","type":"uint8"},{"internalType":"address[]","name":"_voterList","type":"address[]"}],"name":"updateQuestSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IQuestBoard.QuestVoteType","name":"_voteType","type":"uint8"},{"internalType":"enum IQuestBoard.QuestCloseType","name":"_closeType","type":"uint8"},{"internalType":"address[]","name":"_voterList","type":"address[]"}],"name":"updateQuestTypeSettings","outputs":[],"stateMutability":"nonpayable","type":"function"}]

61012060405234801562000011575f80fd5b506040516200368f3803806200368f83398101604081905262000034916200029a565b33858585816001600160a01b0316816001600160a01b031603620000b35760405162461bcd60e51b815260206004820152602b60248201527f4272696265496e69746961746976653a2062726962652d746f6b656e2d63616e60448201526a1b9bdd0b58994b589bdb1960aa1b60648201526084015b60405180910390fd5b6001600160a01b0380841660c081905283821660e05290821661010052604080516346d62a6360e01b815290516346d62a63916004808201926020929091908290030181865afa1580156200010a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000130919062000306565b6080818152505060c0516001600160a01b031663a70b9f0c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000176573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200019c919062000306565b60a0525050506001600160a01b038116620001cd57604051631e4fbdf760e01b81525f6004820152602401620000aa565b620001d8816200020f565b50600680546001600160a01b039384166001600160a01b03199182161790915560098054929093169116179055506200031e915050565b600580546001600160a01b03191690556200022a816200022d565b50565b600480546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b80516001600160a01b038116811462000295575f80fd5b919050565b5f805f805f60a08688031215620002af575f80fd5b620002ba866200027e565b9450620002ca602087016200027e565b9350620002da604087016200027e565b9250620002ea606087016200027e565b9150620002fa608087016200027e565b90509295509295909350565b5f6020828403121562000317575f80fd5b5051919050565b60805160a05160c05160e051610100516132d1620003be5f395f818161032c01528181610ad20152610e4101525f81816103ed01528181610a9001528181610dfa01528181611fe5015281816120750152818161246901526125b401525f8181610353015281816105f6015281816107ee015281816108ca01528181610f180152818161126b015261133a01525f61184e01525f61187901526132d15ff3fe608060405234801561000f575f80fd5b5060043610610201575f3560e01c806379ba509711610123578063c1932ea4116100b8578063e30c397811610088578063e89946e21161006e578063e89946e214610544578063f0f2698d1461058e578063f2fde38b14610596575f80fd5b8063e30c397814610513578063e6fc378614610531575f80fd5b8063c1932ea4146104b9578063c297fa0f146104cc578063c33fb877146104eb578063c9ea8f27146104f3575f80fd5b806392a55aef116100f357806392a55aef14610484578063955161cd1461028a578063bb2fe6461461049b578063bf5b0ad5146104a4575f80fd5b806379ba50971461040f5780637c1f36271461041757806381c4fea5146104535780638da5cb5b14610466575f80fd5b806358c93f78116101995780636012c588116101695780636012c5881461039057806363efdf4a146103a3578063715018a6146103e0578063727d0f35146103e8575f80fd5b806358c93f78146103275780635aa6e6751461034e5780635bab17b1146103755780635ed9ede214610388575f80fd5b80632695d74d116101d45780632695d74d1461028a5780632ddac0171461029d5780633c815549146102cb57806344d39c1b14610314575f80fd5b80630135d5331461020557806313122798146102425780631e18de1a146102625780631e41a0f814610277575b5f80fd5b610218610213366004612b09565b6105a9565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6006546102189073ffffffffffffffffffffffffffffffffffffffff1681565b610275610270366004612b20565b6105de565b005b610275610285366004612c86565b610686565b610275610298366004612b09565b6107d6565b600a54600b54600c546102bb92919060ff8082169161010090041684565b6040516102399493929190612d46565b6102f96102d9366004612b09565b5f6020819052908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610239565b610275610322366004612b20565b610878565b6102187f000000000000000000000000000000000000000000000000000000000000000081565b6102187f000000000000000000000000000000000000000000000000000000000000000081565b610275610383366004612d7b565b6108c7565b610275610b00565b61027561039e366004612da4565b610b0a565b6103d06103b1366004612e15565b600160209081525f928352604080842090915290825290205460ff1681565b6040519015158152602001610239565b610275610cd8565b6102187f000000000000000000000000000000000000000000000000000000000000000081565b610275610ce9565b61043e610425366004612b09565b5f90815260026020526040902080546001909101549091565b60408051928352602083019190915201610239565b61043e610461366004612e3d565b610d5d565b60045473ffffffffffffffffffffffffffffffffffffffff16610218565b61048d60075481565b604051908152602001610239565b61048d60085481565b6104ac610e6f565b6040516102399190612eac565b6102756104c7366004612f03565b610f00565b6104d4600281565b60405165ffffffffffff9091168152602001610239565b61027561102e565b6009546102189073ffffffffffffffffffffffffffffffffffffffff1681565b60055473ffffffffffffffffffffffffffffffffffffffff16610218565b61048d61053f366004612f8a565b61103e565b61043e610552366004612e15565b73ffffffffffffffffffffffffffffffffffffffff919091165f9081526003602090815260408083209383529290522080546001909101549091565b61048d61107b565b6102756105a4366004612f8a565b6110af565b600d81815481106105b8575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610682576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4272696265496e69746961746976653a20696e76616c69642d73656e6465720060448201526064015b60405180910390fd5b5050565b61068e61115f565b600c80548491907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360028111156106cb576106cb612ce4565b0217905550600c80548391907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010083600281111561070e5761070e612ce4565b021790555061071e600d5f612aa2565b80515f5b818110156107a757600d83828151811061073e5761073e612fa3565b6020908102919091018101518254600180820185555f9485529290932090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9093169290921790915501610722565b506040517f7c98a0e54e3d959a008c6978e0f8492849c33c7075f4b35e00ef60c0088c3707905f90a150505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610875576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4272696265496e69746961746976653a20696e76616c69642d73656e646572006044820152606401610679565b50565b61088061115f565b600a829055600b81905560408051838152602081018390527f41e8d332520308cb3ae775505e40854c4d5d7ebbed7d0d337166ca60bf7e4db4910160405180910390a15050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610931573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109559190612fd0565b9050808210156109e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4272696265496e69746961746976653a206e6f772d6f722d6675747572652d6560448201527f706f6368730000000000000000000000000000000000000000000000000000006064820152608401610679565b5f8281526020819052604081208054869290610a04908490613014565b90915550505f8281526020819052604081206001018054859290610a29908490613014565b90915550506040805133815260208101869052908101849052606081018390527f8da751404c1c12bd225230d318ca0913aab7a5f98c004ae97cf1b7072e7f119d9060800160405180910390a1610ab873ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163330876111b2565b610afa73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163330866111b2565b50505050565b610b0861123b565b565b610b1261115f565b6040518060800160405280868152602001858152602001846002811115610b3b57610b3b612ce4565b8152602001836002811115610b5257610b52612ce4565b90528051600a9081556020820151600b556040820151600c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836002811115610ba257610ba2612ce4565b021790555060608201518160020160016101000a81548160ff02191690836002811115610bd157610bd1612ce4565b0217905550610be59150600d90505f612aa2565b80515f5b81811015610c6e57600d838281518110610c0557610c05612fa3565b6020908102919091018101518254600180820185555f9485529290932090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9093169290921790915501610be9565b506040517f7c98a0e54e3d959a008c6978e0f8492849c33c7075f4b35e00ef60c0088c3707905f90a160408051878152602081018790527f41e8d332520308cb3ae775505e40854c4d5d7ebbed7d0d337166ca60bf7e4db4910160405180910390a1505050505050565b610ce061115f565b610b085f611305565b600554339073ffffffffffffffffffffffffffffffffffffffff168114610d54576040517f118cdaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610679565b61087581611305565b5f805f5b83811015610dd9575f858583818110610d7c57610d7c612fa3565b905060600201803603810190610d929190613027565b90505f80610dad33845f015185602001518660400151611336565b9092509050610dbc8287613014565b9550610dc88186613014565b94505060019092019150610d619050565b508115610e2157610e2173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163384611a69565b8015610e6857610e6873ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163383611a69565b9250929050565b610e77612abd565b60408051608081018252600a80548252600b546020830152600c54919290919083019060ff166002811115610eae57610eae612ce4565b6002811115610ebf57610ebf612ce4565b81526020016002820160019054906101000a900460ff166002811115610ee757610ee7612ce4565b6002811115610ef857610ef8612ce4565b905250919050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4272696265496e69746961746976653a20696e76616c69642d73656e646572006044820152606401610679565b73ffffffffffffffffffffffffffffffffffffffff84165f90815260036020908152604080832083805282529091206002908101549082527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077d54909161101090889085359086013582851415611aac565b61102586888635602088013586831415611b23565b50505050505050565b61103661123b565b610b08611bff565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260036020908152604080832083805290915281206002015481905b9392505050565b5f80805260026020527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077d5481905b92915050565b6110b761115f565b6005805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116811790915561111a60045473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60045473ffffffffffffffffffffffffffffffffffffffff163314610b08576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610679565b60405173ffffffffffffffffffffffffffffffffffffffff8481166024830152838116604483015260648201839052610afa9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612126565b6040517fc20fb59e0000000000000000000000000000000000000000000000000000000081523060048201525f907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063c20fb59e906024016020604051808303815f875af11580156112c6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112ea9190612fd0565b90508060075f8282546112fd9190613014565b909155505050565b600580547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055610875816121ba565b5f807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113a1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113c59190612fd0565b8510611453576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4272696265496e69746961746976653a2063616e6e6f742d636c61696d2d666f60448201527f722d63757272656e742d65706f636800000000000000000000000000000000006064820152608401610679565b73ffffffffffffffffffffffffffffffffffffffff86165f90815260016020908152604080832088845290915290205460ff16156114ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4272696265496e69746961746976653a20616c72656164792d636c61696d65646044820152606401610679565b5f858152602081815260409182902082516060810184528154808252600183015493820193909352600290910154928101929092521515806115325750602081015115155b611598576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4272696265496e69746961746976653a206e6f2d6272696265000000000000006044820152606401610679565b73ffffffffffffffffffffffffffffffffffffffff87165f9081526003602052604081206115c69087612230565b90508686111580156115e7575086816060015111806115e757506060810151155b611673576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f4272696265496e69746961746976653a20696e76616c69642d707265762d6c7160448201527f74792d616c6c6f636174696f6e2d65706f6368000000000000000000000000006064820152608401610679565b5f61167f600287612230565b90508786111580156116a0575087816060015111806116a057506060810151155b61172c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f4272696265496e69746961746976653a20696e76616c69642d707265762d746f60448201527f74616c2d6c7174792d616c6c6f636174696f6e2d65706f6368000000000000006064820152608401610679565b80516117ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f4272696265496e69746961746976653a20746f74616c2d6c7174792d616c6c6f60448201527f636174696f6e2d7a65726f0000000000000000000000000000000000000000006064820152608401610679565b8151611848576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4272696265496e69746961746976653a206c7174792d616c6c6f636174696f6e60448201527f2d7a65726f0000000000000000000000000000000000000000000000000000006064820152608401610679565b5f6118737f00000000000000000000000000000000000000000000000000000000000000008a613081565b61189d907f0000000000000000000000000000000000000000000000000000000000000000613014565b90505f6118b2835f0151838560200151612297565b90505f6118c7855f0151848760200151612297565b90505f8660400151836118da9190613098565b90508082885f01516118ec9190613081565b6118f691906130ab565b9850808288602001516119099190613081565b61191391906130ab565b975088875f018181516119269190613098565b90525060208701805189919061193d908390613098565b905250604087018051839190611954908390613014565b91508181525050865f808e81526020019081526020015f205f820151815f015560208201518160010155604082015181600201559050506001805f8f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8e81526020019081526020015f205f6101000a81548160ff0219169083151502179055507f520304589c9512f04f4c28f0a5f365d2620fea83386850175628ebfe3d52b6838d8d8b8b604051611a51949392919073ffffffffffffffffffffffffffffffffffffffff94909416845260208401929092526040830152606082015260800190565b60405180910390a15050505050505094509492505050565b60405173ffffffffffffffffffffffffffffffffffffffff838116602483015260448201839052611aa791859182169063a9059cbb906064016111f4565b505050565b8015611ac557611ac060028585855f6122c5565b611adc565b5f8481526002602052604090208381556001018290555b60408051858152602081018590529081018390527ff3585f583ce8a74a5f014115d0a23ad6246464e971fe5701465b9976dc9c5bcd9060600160405180910390a150505050565b8015611b615773ffffffffffffffffffffffffffffffffffffffff85165f908152600360205260408120611b5c918690869086906122c5565b611b9a565b73ffffffffffffffffffffffffffffffffffffffff85165f90815260036020908152604080832087845290915290208381556001018290555b6040805173ffffffffffffffffffffffffffffffffffffffff8716815260208101869052908101849052606081018390527f3cf1dea48fd0f5e4db76fa66b9f662a7a8e3c185f34763189efc609691e327529060800160405180910390a15050505050565b60408051608081018252600a80548252600b546020830152600c545f9383019060ff166002811115611c3357611c33612ce4565b6002811115611c4457611c44612ce4565b81526020016002820160019054906101000a900460ff166002811115611c6c57611c6c612ce4565b6002811115611c7d57611c7d612ce4565b90525060085490915015611e1b576006546008546040517ff29e9aa700000000000000000000000000000000000000000000000000000000815260048101919091525f9173ffffffffffffffffffffffffffffffffffffffff169063f29e9aa7906024015f60405180830381865afa158015611cfb573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611d4091908101906130e3565b90505f8160018351611d529190613098565b81518110611d6257611d62612fa3565b602002602001015165ffffffffffff1690508060065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663086146d26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ddf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e039190612fd0565b11611e0d57505050565b611e1860085461239b565b50505b6006546040517f77dd7cf70000000000000000000000000000000000000000000000000000000081523060048201525f9173ffffffffffffffffffffffffffffffffffffffff16906377dd7cf790602401602060405180830381865afa158015611e87573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eab9190612fd0565b9050805f03611f455760065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166357ae1cec6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f1e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f429190612fd0565b90505b5f611f5282612710613014565b612710600754611f629190613081565b611f6c91906130ab565b90505f612710611f7c8484613081565b611f8691906130ab565b9050611f928183613014565b60075f828254611fa29190613098565b909155505060065461200c9073ffffffffffffffffffffffffffffffffffffffff16611fce8385613014565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169190612645565b6006546009548551602087015160408089015160608a015191517f29b6a4300000000000000000000000000000000000000000000000000000000081525f9673ffffffffffffffffffffffffffffffffffffffff908116966329b6a430966120ad9692909116947f0000000000000000000000000000000000000000000000000000000000000000948a94600294928e928e92909190600d90600401613182565b6020604051808303815f875af11580156120c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120ed9190612fd0565b600881905560405190915081907ff2376f43586d93a15b606c89747962a511dee47a8afacda035909ddd4460b108905f90a25050505050565b5f61214773ffffffffffffffffffffffffffffffffffffffff8416836126f2565b905080515f1415801561216b5750808060200190518101906121699190613250565b155b15611aa7576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610679565b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b61225760405180608001604052805f81526020015f81526020015f81526020015f81525090565b505f908152602091825260409081902081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015290565b5f806122a38486613081565b90508281116122b2575f6122bc565b6122bc8382613098565b95945050505050565b6122cf85856126ff565b15612306576040517f3c57789e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b801580159061231c575061231a85826126ff565b155b15612353576040517fac9c4cae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f818152602095909552604080862060029081018054808952838920600390810189905591889055968852919096209586019490945592840192909255825560019190910155565b6006546040517f146bdb7d000000000000000000000000000000000000000000000000000000008152600481018390525f9173ffffffffffffffffffffffffffffffffffffffff169063146bdb7d90602401602060405180830381865afa158015612408573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061242c9190612fd0565b9050805f03612439575050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156124c3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124e79190612fd0565b6006546040517f8f4c72d80000000000000000000000000000000000000000000000000000000081526004810186905230602482015291925073ffffffffffffffffffffffffffffffffffffffff1690638f4c72d8906044015f604051808303815f87803b158015612557575f80fd5b505af1158015612569573d5f803e3d5ffd5b50506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f925083915073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156125f9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061261d9190612fd0565b6126279190613098565b90508060075f82825461263a9190613014565b909155505050505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff83811660248301525f919085169063dd62ed3e90604401602060405180830381865afa1580156126b8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126dc9190612fd0565b9050610afa84846126ed8585613014565b612784565b606061107483835f61285b565b5f815f03612739576040517fee7efd5700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526020849052604090206002015415158061276657505f8281526020849052604090206003015415155b806110745750505f8080526020929092526040909120600301541490565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052612810848261291a565b610afa5760405173ffffffffffffffffffffffffffffffffffffffff84811660248301525f604483015261285191869182169063095ea7b3906064016111f4565b610afa8482612126565b606081471015612899576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610679565b5f808573ffffffffffffffffffffffffffffffffffffffff1684866040516128c1919061326f565b5f6040518083038185875af1925050503d805f81146128fb576040519150601f19603f3d011682016040523d82523d5f602084013e612900565b606091505b50915091506129108683836129d1565b9695505050505050565b5f805f8473ffffffffffffffffffffffffffffffffffffffff1684604051612942919061326f565b5f604051808303815f865af19150503d805f811461297b576040519150601f19603f3d011682016040523d82523d5f602084013e612980565b606091505b50915091508180156129aa5750805115806129aa5750808060200190518101906129aa9190613250565b80156122bc57505050505073ffffffffffffffffffffffffffffffffffffffff163b151590565b6060826129e6576129e182612a60565b611074565b8151158015612a0a575073ffffffffffffffffffffffffffffffffffffffff84163b155b15612a59576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610679565b5080611074565b805115612a705780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5080545f8255905f5260205f20908101906108759190612af1565b60405180608001604052805f81526020015f81526020015f6002811115612ae657612ae6612ce4565b81526020015f905290565b5b80821115612b05575f8155600101612af2565b5090565b5f60208284031215612b19575f80fd5b5035919050565b5f8060408385031215612b31575f80fd5b50508035926020909101359150565b60038110610875575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612bc057612bc0612b4c565b604052919050565b5f67ffffffffffffffff821115612be157612be1612b4c565b5060051b60200190565b803573ffffffffffffffffffffffffffffffffffffffff81168114612c0e575f80fd5b919050565b5f82601f830112612c22575f80fd5b81356020612c37612c3283612bc8565b612b79565b8083825260208201915060208460051b870101935086841115612c58575f80fd5b602086015b84811015612c7b57612c6e81612beb565b8352918301918301612c5d565b509695505050505050565b5f805f60608486031215612c98575f80fd5b8335612ca381612b40565b92506020840135612cb381612b40565b9150604084013567ffffffffffffffff811115612cce575f80fd5b612cda86828701612c13565b9150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60038110610875577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8481526020810184905260808101612d5d84612d11565b836040830152612d6c83612d11565b82606083015295945050505050565b5f805f60608486031215612d8d575f80fd5b505081359360208301359350604090920135919050565b5f805f805f60a08688031215612db8575f80fd5b85359450602086013593506040860135612dd181612b40565b92506060860135612de181612b40565b9150608086013567ffffffffffffffff811115612dfc575f80fd5b612e0888828901612c13565b9150509295509295909350565b5f8060408385031215612e26575f80fd5b612e2f83612beb565b946020939093013593505050565b5f8060208385031215612e4e575f80fd5b823567ffffffffffffffff80821115612e65575f80fd5b818501915085601f830112612e78575f80fd5b813581811115612e86575f80fd5b866020606083028501011115612e9a575f80fd5b60209290920196919550909350505050565b815181526020808301519082015260408201516080820190612ecd81612d11565b60408301526060830151612ee081612d11565b8060608401525092915050565b5f60a08284031215612efd575f80fd5b50919050565b5f805f805f858703610200811215612f19575f80fd5b86359550612f2960208801612beb565b945060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc082011215612f5a575f80fd5b50604086019250612f6e8760c08801612eed565b9150612f7e876101608801612eed565b90509295509295909350565b5f60208284031215612f9a575f80fd5b61107482612beb565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215612fe0575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156110a9576110a9612fe7565b5f60608284031215613037575f80fd5b6040516060810181811067ffffffffffffffff8211171561305a5761305a612b4c565b80604052508235815260208301356020820152604083013560408201528091505092915050565b80820281158282048414176110a9576110a9612fe7565b818103818111156110a9576110a9612fe7565b5f826130de577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b5f60208083850312156130f4575f80fd5b825167ffffffffffffffff81111561310a575f80fd5b8301601f8101851361311a575f80fd5b8051613128612c3282612bc8565b81815260059190911b82018301908381019087831115613146575f80fd5b928401925b8284101561317757835165ffffffffffff81168114613168575f80fd5b8252928401929084019061314b565b979650505050505050565b5f610160820173ffffffffffffffffffffffffffffffffffffffff808f168452808e1660208501528c1515604085015265ffffffffffff8c1660608501528a60808501528960a08501528860c08501528760e08501526131e187612d11565b866101008501526131f186612d11565b61012084018690526101606101408501528454918290525f85815260208120926101808601915b818110156132385784548416835260019485019460209093019201613218565b50508093505050509c9b505050505050505050505050565b5f60208284031215613260575f80fd5b81518015158114611074575f80fd5b5f82515f5b8181101561328e5760208186018101518583015201613274565b505f92019182525091905056fea26469706673582212201e6eeadc28b747cb8dc5800409798a8d5bce413b21d1225e9a8b6bec2376a3c064736f6c63430008180033000000000000000000000000807def5e7d057df05c796f4bc75c3fe82bd6eee10000000000000000000000006440f144b7e50d6a8439336510312d2f54beb01d0000000000000000000000005de8ab7e27f6e7a1fff3e5b337584aa43961beef000000000000000000000000feb352930ca196a80b708cdd5dcb4eca94805dab0000000000000000000000005a099e2c2a41a5a0ad99e4971c711400eeef34db

Deployed Bytecode

0x608060405234801561000f575f80fd5b5060043610610201575f3560e01c806379ba509711610123578063c1932ea4116100b8578063e30c397811610088578063e89946e21161006e578063e89946e214610544578063f0f2698d1461058e578063f2fde38b14610596575f80fd5b8063e30c397814610513578063e6fc378614610531575f80fd5b8063c1932ea4146104b9578063c297fa0f146104cc578063c33fb877146104eb578063c9ea8f27146104f3575f80fd5b806392a55aef116100f357806392a55aef14610484578063955161cd1461028a578063bb2fe6461461049b578063bf5b0ad5146104a4575f80fd5b806379ba50971461040f5780637c1f36271461041757806381c4fea5146104535780638da5cb5b14610466575f80fd5b806358c93f78116101995780636012c588116101695780636012c5881461039057806363efdf4a146103a3578063715018a6146103e0578063727d0f35146103e8575f80fd5b806358c93f78146103275780635aa6e6751461034e5780635bab17b1146103755780635ed9ede214610388575f80fd5b80632695d74d116101d45780632695d74d1461028a5780632ddac0171461029d5780633c815549146102cb57806344d39c1b14610314575f80fd5b80630135d5331461020557806313122798146102425780631e18de1a146102625780631e41a0f814610277575b5f80fd5b610218610213366004612b09565b6105a9565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6006546102189073ffffffffffffffffffffffffffffffffffffffff1681565b610275610270366004612b20565b6105de565b005b610275610285366004612c86565b610686565b610275610298366004612b09565b6107d6565b600a54600b54600c546102bb92919060ff8082169161010090041684565b6040516102399493929190612d46565b6102f96102d9366004612b09565b5f6020819052908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610239565b610275610322366004612b20565b610878565b6102187f0000000000000000000000005de8ab7e27f6e7a1fff3e5b337584aa43961beef81565b6102187f000000000000000000000000807def5e7d057df05c796f4bc75c3fe82bd6eee181565b610275610383366004612d7b565b6108c7565b610275610b00565b61027561039e366004612da4565b610b0a565b6103d06103b1366004612e15565b600160209081525f928352604080842090915290825290205460ff1681565b6040519015158152602001610239565b610275610cd8565b6102187f0000000000000000000000006440f144b7e50d6a8439336510312d2f54beb01d81565b610275610ce9565b61043e610425366004612b09565b5f90815260026020526040902080546001909101549091565b60408051928352602083019190915201610239565b61043e610461366004612e3d565b610d5d565b60045473ffffffffffffffffffffffffffffffffffffffff16610218565b61048d60075481565b604051908152602001610239565b61048d60085481565b6104ac610e6f565b6040516102399190612eac565b6102756104c7366004612f03565b610f00565b6104d4600281565b60405165ffffffffffff9091168152602001610239565b61027561102e565b6009546102189073ffffffffffffffffffffffffffffffffffffffff1681565b60055473ffffffffffffffffffffffffffffffffffffffff16610218565b61048d61053f366004612f8a565b61103e565b61043e610552366004612e15565b73ffffffffffffffffffffffffffffffffffffffff919091165f9081526003602090815260408083209383529290522080546001909101549091565b61048d61107b565b6102756105a4366004612f8a565b6110af565b600d81815481106105b8575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000807def5e7d057df05c796f4bc75c3fe82bd6eee11614610682576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4272696265496e69746961746976653a20696e76616c69642d73656e6465720060448201526064015b60405180910390fd5b5050565b61068e61115f565b600c80548491907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360028111156106cb576106cb612ce4565b0217905550600c80548391907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010083600281111561070e5761070e612ce4565b021790555061071e600d5f612aa2565b80515f5b818110156107a757600d83828151811061073e5761073e612fa3565b6020908102919091018101518254600180820185555f9485529290932090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9093169290921790915501610722565b506040517f7c98a0e54e3d959a008c6978e0f8492849c33c7075f4b35e00ef60c0088c3707905f90a150505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000807def5e7d057df05c796f4bc75c3fe82bd6eee11614610875576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4272696265496e69746961746976653a20696e76616c69642d73656e646572006044820152606401610679565b50565b61088061115f565b600a829055600b81905560408051838152602081018390527f41e8d332520308cb3ae775505e40854c4d5d7ebbed7d0d337166ca60bf7e4db4910160405180910390a15050565b5f7f000000000000000000000000807def5e7d057df05c796f4bc75c3fe82bd6eee173ffffffffffffffffffffffffffffffffffffffff1663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610931573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109559190612fd0565b9050808210156109e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4272696265496e69746961746976653a206e6f772d6f722d6675747572652d6560448201527f706f6368730000000000000000000000000000000000000000000000000000006064820152608401610679565b5f8281526020819052604081208054869290610a04908490613014565b90915550505f8281526020819052604081206001018054859290610a29908490613014565b90915550506040805133815260208101869052908101849052606081018390527f8da751404c1c12bd225230d318ca0913aab7a5f98c004ae97cf1b7072e7f119d9060800160405180910390a1610ab873ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006440f144b7e50d6a8439336510312d2f54beb01d163330876111b2565b610afa73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005de8ab7e27f6e7a1fff3e5b337584aa43961beef163330866111b2565b50505050565b610b0861123b565b565b610b1261115f565b6040518060800160405280868152602001858152602001846002811115610b3b57610b3b612ce4565b8152602001836002811115610b5257610b52612ce4565b90528051600a9081556020820151600b556040820151600c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836002811115610ba257610ba2612ce4565b021790555060608201518160020160016101000a81548160ff02191690836002811115610bd157610bd1612ce4565b0217905550610be59150600d90505f612aa2565b80515f5b81811015610c6e57600d838281518110610c0557610c05612fa3565b6020908102919091018101518254600180820185555f9485529290932090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9093169290921790915501610be9565b506040517f7c98a0e54e3d959a008c6978e0f8492849c33c7075f4b35e00ef60c0088c3707905f90a160408051878152602081018790527f41e8d332520308cb3ae775505e40854c4d5d7ebbed7d0d337166ca60bf7e4db4910160405180910390a1505050505050565b610ce061115f565b610b085f611305565b600554339073ffffffffffffffffffffffffffffffffffffffff168114610d54576040517f118cdaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610679565b61087581611305565b5f805f5b83811015610dd9575f858583818110610d7c57610d7c612fa3565b905060600201803603810190610d929190613027565b90505f80610dad33845f015185602001518660400151611336565b9092509050610dbc8287613014565b9550610dc88186613014565b94505060019092019150610d619050565b508115610e2157610e2173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006440f144b7e50d6a8439336510312d2f54beb01d163384611a69565b8015610e6857610e6873ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005de8ab7e27f6e7a1fff3e5b337584aa43961beef163383611a69565b9250929050565b610e77612abd565b60408051608081018252600a80548252600b546020830152600c54919290919083019060ff166002811115610eae57610eae612ce4565b6002811115610ebf57610ebf612ce4565b81526020016002820160019054906101000a900460ff166002811115610ee757610ee7612ce4565b6002811115610ef857610ef8612ce4565b905250919050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000807def5e7d057df05c796f4bc75c3fe82bd6eee11614610f9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4272696265496e69746961746976653a20696e76616c69642d73656e646572006044820152606401610679565b73ffffffffffffffffffffffffffffffffffffffff84165f90815260036020908152604080832083805282529091206002908101549082527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077d54909161101090889085359086013582851415611aac565b61102586888635602088013586831415611b23565b50505050505050565b61103661123b565b610b08611bff565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260036020908152604080832083805290915281206002015481905b9392505050565b5f80805260026020527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077d5481905b92915050565b6110b761115f565b6005805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116811790915561111a60045473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60045473ffffffffffffffffffffffffffffffffffffffff163314610b08576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610679565b60405173ffffffffffffffffffffffffffffffffffffffff8481166024830152838116604483015260648201839052610afa9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612126565b6040517fc20fb59e0000000000000000000000000000000000000000000000000000000081523060048201525f907f000000000000000000000000807def5e7d057df05c796f4bc75c3fe82bd6eee173ffffffffffffffffffffffffffffffffffffffff169063c20fb59e906024016020604051808303815f875af11580156112c6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112ea9190612fd0565b90508060075f8282546112fd9190613014565b909155505050565b600580547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055610875816121ba565b5f807f000000000000000000000000807def5e7d057df05c796f4bc75c3fe82bd6eee173ffffffffffffffffffffffffffffffffffffffff1663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113a1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113c59190612fd0565b8510611453576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4272696265496e69746961746976653a2063616e6e6f742d636c61696d2d666f60448201527f722d63757272656e742d65706f636800000000000000000000000000000000006064820152608401610679565b73ffffffffffffffffffffffffffffffffffffffff86165f90815260016020908152604080832088845290915290205460ff16156114ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4272696265496e69746961746976653a20616c72656164792d636c61696d65646044820152606401610679565b5f858152602081815260409182902082516060810184528154808252600183015493820193909352600290910154928101929092521515806115325750602081015115155b611598576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4272696265496e69746961746976653a206e6f2d6272696265000000000000006044820152606401610679565b73ffffffffffffffffffffffffffffffffffffffff87165f9081526003602052604081206115c69087612230565b90508686111580156115e7575086816060015111806115e757506060810151155b611673576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f4272696265496e69746961746976653a20696e76616c69642d707265762d6c7160448201527f74792d616c6c6f636174696f6e2d65706f6368000000000000000000000000006064820152608401610679565b5f61167f600287612230565b90508786111580156116a0575087816060015111806116a057506060810151155b61172c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f4272696265496e69746961746976653a20696e76616c69642d707265762d746f60448201527f74616c2d6c7174792d616c6c6f636174696f6e2d65706f6368000000000000006064820152608401610679565b80516117ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f4272696265496e69746961746976653a20746f74616c2d6c7174792d616c6c6f60448201527f636174696f6e2d7a65726f0000000000000000000000000000000000000000006064820152608401610679565b8151611848576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4272696265496e69746961746976653a206c7174792d616c6c6f636174696f6e60448201527f2d7a65726f0000000000000000000000000000000000000000000000000000006064820152608401610679565b5f6118737f0000000000000000000000000000000000000000000000000000000000093a808a613081565b61189d907f00000000000000000000000000000000000000000000000000000000681bf400613014565b90505f6118b2835f0151838560200151612297565b90505f6118c7855f0151848760200151612297565b90505f8660400151836118da9190613098565b90508082885f01516118ec9190613081565b6118f691906130ab565b9850808288602001516119099190613081565b61191391906130ab565b975088875f018181516119269190613098565b90525060208701805189919061193d908390613098565b905250604087018051839190611954908390613014565b91508181525050865f808e81526020019081526020015f205f820151815f015560208201518160010155604082015181600201559050506001805f8f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8e81526020019081526020015f205f6101000a81548160ff0219169083151502179055507f520304589c9512f04f4c28f0a5f365d2620fea83386850175628ebfe3d52b6838d8d8b8b604051611a51949392919073ffffffffffffffffffffffffffffffffffffffff94909416845260208401929092526040830152606082015260800190565b60405180910390a15050505050505094509492505050565b60405173ffffffffffffffffffffffffffffffffffffffff838116602483015260448201839052611aa791859182169063a9059cbb906064016111f4565b505050565b8015611ac557611ac060028585855f6122c5565b611adc565b5f8481526002602052604090208381556001018290555b60408051858152602081018590529081018390527ff3585f583ce8a74a5f014115d0a23ad6246464e971fe5701465b9976dc9c5bcd9060600160405180910390a150505050565b8015611b615773ffffffffffffffffffffffffffffffffffffffff85165f908152600360205260408120611b5c918690869086906122c5565b611b9a565b73ffffffffffffffffffffffffffffffffffffffff85165f90815260036020908152604080832087845290915290208381556001018290555b6040805173ffffffffffffffffffffffffffffffffffffffff8716815260208101869052908101849052606081018390527f3cf1dea48fd0f5e4db76fa66b9f662a7a8e3c185f34763189efc609691e327529060800160405180910390a15050505050565b60408051608081018252600a80548252600b546020830152600c545f9383019060ff166002811115611c3357611c33612ce4565b6002811115611c4457611c44612ce4565b81526020016002820160019054906101000a900460ff166002811115611c6c57611c6c612ce4565b6002811115611c7d57611c7d612ce4565b90525060085490915015611e1b576006546008546040517ff29e9aa700000000000000000000000000000000000000000000000000000000815260048101919091525f9173ffffffffffffffffffffffffffffffffffffffff169063f29e9aa7906024015f60405180830381865afa158015611cfb573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611d4091908101906130e3565b90505f8160018351611d529190613098565b81518110611d6257611d62612fa3565b602002602001015165ffffffffffff1690508060065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663086146d26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ddf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e039190612fd0565b11611e0d57505050565b611e1860085461239b565b50505b6006546040517f77dd7cf70000000000000000000000000000000000000000000000000000000081523060048201525f9173ffffffffffffffffffffffffffffffffffffffff16906377dd7cf790602401602060405180830381865afa158015611e87573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eab9190612fd0565b9050805f03611f455760065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166357ae1cec6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f1e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f429190612fd0565b90505b5f611f5282612710613014565b612710600754611f629190613081565b611f6c91906130ab565b90505f612710611f7c8484613081565b611f8691906130ab565b9050611f928183613014565b60075f828254611fa29190613098565b909155505060065461200c9073ffffffffffffffffffffffffffffffffffffffff16611fce8385613014565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006440f144b7e50d6a8439336510312d2f54beb01d169190612645565b6006546009548551602087015160408089015160608a015191517f29b6a4300000000000000000000000000000000000000000000000000000000081525f9673ffffffffffffffffffffffffffffffffffffffff908116966329b6a430966120ad9692909116947f0000000000000000000000006440f144b7e50d6a8439336510312d2f54beb01d948a94600294928e928e92909190600d90600401613182565b6020604051808303815f875af11580156120c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120ed9190612fd0565b600881905560405190915081907ff2376f43586d93a15b606c89747962a511dee47a8afacda035909ddd4460b108905f90a25050505050565b5f61214773ffffffffffffffffffffffffffffffffffffffff8416836126f2565b905080515f1415801561216b5750808060200190518101906121699190613250565b155b15611aa7576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610679565b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b61225760405180608001604052805f81526020015f81526020015f81526020015f81525090565b505f908152602091825260409081902081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015290565b5f806122a38486613081565b90508281116122b2575f6122bc565b6122bc8382613098565b95945050505050565b6122cf85856126ff565b15612306576040517f3c57789e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b801580159061231c575061231a85826126ff565b155b15612353576040517fac9c4cae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f818152602095909552604080862060029081018054808952838920600390810189905591889055968852919096209586019490945592840192909255825560019190910155565b6006546040517f146bdb7d000000000000000000000000000000000000000000000000000000008152600481018390525f9173ffffffffffffffffffffffffffffffffffffffff169063146bdb7d90602401602060405180830381865afa158015612408573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061242c9190612fd0565b9050805f03612439575050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f907f0000000000000000000000006440f144b7e50d6a8439336510312d2f54beb01d73ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156124c3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124e79190612fd0565b6006546040517f8f4c72d80000000000000000000000000000000000000000000000000000000081526004810186905230602482015291925073ffffffffffffffffffffffffffffffffffffffff1690638f4c72d8906044015f604051808303815f87803b158015612557575f80fd5b505af1158015612569573d5f803e3d5ffd5b50506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f925083915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006440f144b7e50d6a8439336510312d2f54beb01d16906370a0823190602401602060405180830381865afa1580156125f9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061261d9190612fd0565b6126279190613098565b90508060075f82825461263a9190613014565b909155505050505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff83811660248301525f919085169063dd62ed3e90604401602060405180830381865afa1580156126b8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126dc9190612fd0565b9050610afa84846126ed8585613014565b612784565b606061107483835f61285b565b5f815f03612739576040517fee7efd5700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526020849052604090206002015415158061276657505f8281526020849052604090206003015415155b806110745750505f8080526020929092526040909120600301541490565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052612810848261291a565b610afa5760405173ffffffffffffffffffffffffffffffffffffffff84811660248301525f604483015261285191869182169063095ea7b3906064016111f4565b610afa8482612126565b606081471015612899576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610679565b5f808573ffffffffffffffffffffffffffffffffffffffff1684866040516128c1919061326f565b5f6040518083038185875af1925050503d805f81146128fb576040519150601f19603f3d011682016040523d82523d5f602084013e612900565b606091505b50915091506129108683836129d1565b9695505050505050565b5f805f8473ffffffffffffffffffffffffffffffffffffffff1684604051612942919061326f565b5f604051808303815f865af19150503d805f811461297b576040519150601f19603f3d011682016040523d82523d5f602084013e612980565b606091505b50915091508180156129aa5750805115806129aa5750808060200190518101906129aa9190613250565b80156122bc57505050505073ffffffffffffffffffffffffffffffffffffffff163b151590565b6060826129e6576129e182612a60565b611074565b8151158015612a0a575073ffffffffffffffffffffffffffffffffffffffff84163b155b15612a59576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610679565b5080611074565b805115612a705780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5080545f8255905f5260205f20908101906108759190612af1565b60405180608001604052805f81526020015f81526020015f6002811115612ae657612ae6612ce4565b81526020015f905290565b5b80821115612b05575f8155600101612af2565b5090565b5f60208284031215612b19575f80fd5b5035919050565b5f8060408385031215612b31575f80fd5b50508035926020909101359150565b60038110610875575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612bc057612bc0612b4c565b604052919050565b5f67ffffffffffffffff821115612be157612be1612b4c565b5060051b60200190565b803573ffffffffffffffffffffffffffffffffffffffff81168114612c0e575f80fd5b919050565b5f82601f830112612c22575f80fd5b81356020612c37612c3283612bc8565b612b79565b8083825260208201915060208460051b870101935086841115612c58575f80fd5b602086015b84811015612c7b57612c6e81612beb565b8352918301918301612c5d565b509695505050505050565b5f805f60608486031215612c98575f80fd5b8335612ca381612b40565b92506020840135612cb381612b40565b9150604084013567ffffffffffffffff811115612cce575f80fd5b612cda86828701612c13565b9150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60038110610875577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8481526020810184905260808101612d5d84612d11565b836040830152612d6c83612d11565b82606083015295945050505050565b5f805f60608486031215612d8d575f80fd5b505081359360208301359350604090920135919050565b5f805f805f60a08688031215612db8575f80fd5b85359450602086013593506040860135612dd181612b40565b92506060860135612de181612b40565b9150608086013567ffffffffffffffff811115612dfc575f80fd5b612e0888828901612c13565b9150509295509295909350565b5f8060408385031215612e26575f80fd5b612e2f83612beb565b946020939093013593505050565b5f8060208385031215612e4e575f80fd5b823567ffffffffffffffff80821115612e65575f80fd5b818501915085601f830112612e78575f80fd5b813581811115612e86575f80fd5b866020606083028501011115612e9a575f80fd5b60209290920196919550909350505050565b815181526020808301519082015260408201516080820190612ecd81612d11565b60408301526060830151612ee081612d11565b8060608401525092915050565b5f60a08284031215612efd575f80fd5b50919050565b5f805f805f858703610200811215612f19575f80fd5b86359550612f2960208801612beb565b945060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc082011215612f5a575f80fd5b50604086019250612f6e8760c08801612eed565b9150612f7e876101608801612eed565b90509295509295909350565b5f60208284031215612f9a575f80fd5b61107482612beb565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215612fe0575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156110a9576110a9612fe7565b5f60608284031215613037575f80fd5b6040516060810181811067ffffffffffffffff8211171561305a5761305a612b4c565b80604052508235815260208301356020820152604083013560408201528091505092915050565b80820281158282048414176110a9576110a9612fe7565b818103818111156110a9576110a9612fe7565b5f826130de577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b5f60208083850312156130f4575f80fd5b825167ffffffffffffffff81111561310a575f80fd5b8301601f8101851361311a575f80fd5b8051613128612c3282612bc8565b81815260059190911b82018301908381019087831115613146575f80fd5b928401925b8284101561317757835165ffffffffffff81168114613168575f80fd5b8252928401929084019061314b565b979650505050505050565b5f610160820173ffffffffffffffffffffffffffffffffffffffff808f168452808e1660208501528c1515604085015265ffffffffffff8c1660608501528a60808501528960a08501528860c08501528760e08501526131e187612d11565b866101008501526131f186612d11565b61012084018690526101606101408501528454918290525f85815260208120926101808601915b818110156132385784548416835260019485019460209093019201613218565b50508093505050509c9b505050505050505050505050565b5f60208284031215613260575f80fd5b81518015158114611074575f80fd5b5f82515f5b8181101561328e5760208186018101518583015201613274565b505f92019182525091905056fea26469706673582212201e6eeadc28b747cb8dc5800409798a8d5bce413b21d1225e9a8b6bec2376a3c064736f6c63430008180033

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

000000000000000000000000807def5e7d057df05c796f4bc75c3fe82bd6eee10000000000000000000000006440f144b7e50d6a8439336510312d2f54beb01d0000000000000000000000005de8ab7e27f6e7a1fff3e5b337584aa43961beef000000000000000000000000feb352930ca196a80b708cdd5dcb4eca94805dab0000000000000000000000005a099e2c2a41a5a0ad99e4971c711400eeef34db

-----Decoded View---------------
Arg [0] : _governance (address): 0x807DEf5E7d057DF05C796F4bc75C3Fe82Bd6EeE1
Arg [1] : _bold (address): 0x6440f144b7e50D6a8439336510312d2F54beB01D
Arg [2] : _bribeToken (address): 0x5DE8ab7E27f6E7A1fFf3E5B337584Aa43961BEeF
Arg [3] : _board (address): 0xfEb352930cA196a80B708CDD5dcb4eCA94805daB
Arg [4] : _gauge (address): 0x5a099E2C2a41A5A0aD99e4971c711400Eeef34db

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000807def5e7d057df05c796f4bc75c3fe82bd6eee1
Arg [1] : 0000000000000000000000006440f144b7e50d6a8439336510312d2f54beb01d
Arg [2] : 0000000000000000000000005de8ab7e27f6e7a1fff3e5b337584aa43961beef
Arg [3] : 000000000000000000000000feb352930ca196a80b708cdd5dcb4eca94805dab
Arg [4] : 0000000000000000000000005a099e2c2a41a5a0ad99e4971c711400eeef34db


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.