Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
CompoundVeFNXManagedNFTStrategyUpgradeable
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 2000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.19;
import {BaseManagedNFTStrategyUpgradeable, IManagedNFTManager} from "./BaseManagedNFTStrategyUpgradeable.sol";
import {SafeERC20Upgradeable, IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {IVotingEscrow} from "../core/interfaces/IVotingEscrow.sol";
import {ISingelTokenVirtualRewarder} from "./interfaces/ISingelTokenVirtualRewarder.sol";
import {ICompoundVeFNXManagedNFTStrategy} from "./interfaces/ICompoundVeFNXManagedNFTStrategy.sol";
import {IRouterV2PathProvider, SingelTokenBuybackUpgradeable} from "./SingelTokenBuybackUpgradeable.sol";
import {LibStrategyFlags} from "./libraries/LibStrategyFlags.sol";
/**
* @title Compound VeFNX Managed NFT Strategy Upgradeable
* @dev Strategy for managing VeFNX-related actions including compounding rewards and managing stakes.
* Extends the functionality of a base managed NFT strategy to interact with FENIX tokens.
* @notice This strategy handles the automated compounding of VeFNX tokens by reinvesting harvested rewards back into VeFNX.
*/
contract CompoundVeFNXManagedNFTStrategyUpgradeable is
ICompoundVeFNXManagedNFTStrategy,
BaseManagedNFTStrategyUpgradeable,
SingelTokenBuybackUpgradeable
{
using SafeERC20Upgradeable for IERC20Upgradeable;
/**
* @dev Emitted when an attempt is made to recover tokens that should not be recovered.
* This error typically occurs when a function tries to withdraw reserved or integral tokens
* from the contract, such as tokens that are part of the operational balance or are restricted
* due to their role in the contract's mechanics.
*/
error IncorrectRecoverToken();
/// @notice Address of the FENIX ERC20 token contract.
address public override fenix;
/// @notice Address of the virtual rewarder contract for managing reward distributions.
address public override virtualRewarder;
/**
* @dev Constructor that disables initialization on implementation.
*/
constructor(address blastGovernor_) {
__BlastGovernorClaimableSetup_init(blastGovernor_);
_disableInitializers();
}
/**
* @dev Initializes the strategy with necessary governance, operational addresses, and initial settings.
* @notice Sets up the strategy with a managed NFT manager, virtual rewarder, and router path provider along with initializing governance settings.
*
* @param blastGovernor_ The governance address capable of claiming and managing the contract.
* @param managedNFTManager_ The address of the managed NFT manager, responsible for managing NFT-based operations.
* @param virtualRewarder_ The address of the virtual rewarder, which handles reward distribution.
* @param routerV2PathProvider_ The address of the router V2 path provider, used for determining optimal token swap routes.
* @param name_ The name of the strategy, used for identification.
*/
function initialize(
address blastGovernor_,
address managedNFTManager_,
address virtualRewarder_,
address routerV2PathProvider_,
string memory name_
) external override initializer {
_checkAddressZero(virtualRewarder_);
__BaseManagedNFTStrategy__init(blastGovernor_, managedNFTManager_, name_);
__SingelTokenBuyback__init(routerV2PathProvider_);
fenix = IVotingEscrow(votingEscrow).token();
virtualRewarder = virtualRewarder_;
}
/**
* @notice Attaches an NFT to the strategy and initializes participation in the virtual reward system.
* @dev This function is called when an NFT is attached to this strategy, enabling it to start accumulating rewards.
*
* @param tokenId_ The identifier of the NFT to attach.
* @param userBalance_ The initial balance or stake associated with the NFT at the time of attachment.
*/
function onAttach(uint256 tokenId_, uint256 userBalance_) external override onlyManagedNFTManager {
ISingelTokenVirtualRewarder(virtualRewarder).deposit(tokenId_, userBalance_);
emit OnAttach(tokenId_, userBalance_);
}
/**
* @notice Detaches an NFT from the strategy, withdrawing all associated rewards and balances.
* @dev Handles the process of detaching an NFT, ensuring all accrued benefits are properly managed and withdrawn.
*
* @param tokenId_ The identifier of the NFT to detach.
* @param userBalance_ The remaining balance or stake associated with the NFT at the time of detachment.
* @return lockedRewards The amount of rewards locked and harvested upon detachment.
*/
function onDettach(uint256 tokenId_, uint256 userBalance_) external override onlyManagedNFTManager returns (uint256 lockedRewards) {
ISingelTokenVirtualRewarder virtualRewarderCache = ISingelTokenVirtualRewarder(virtualRewarder);
virtualRewarderCache.withdraw(tokenId_, userBalance_);
lockedRewards = virtualRewarderCache.harvest(tokenId_);
emit OnDettach(tokenId_, userBalance_, lockedRewards);
}
/**
* @notice Retrieves the total amount of locked rewards available for a specific NFT based on its tokenId.
* @param tokenId_ The identifier of the NFT to query.
* @return The total amount of locked rewards for the specified NFT.
*/
function getLockedRewardsBalance(uint256 tokenId_) external view returns (uint256) {
return ISingelTokenVirtualRewarder(virtualRewarder).calculateAvailableRewardsAmount(tokenId_);
}
/**
* @notice Retrieves the balance or stake associated with a specific NFT.
* @param tokenId_ The identifier of the NFT to query.
* @return The balance of the specified NFT.
*/
function balanceOf(uint256 tokenId_) external view returns (uint256) {
return ISingelTokenVirtualRewarder(virtualRewarder).balanceOf(tokenId_);
}
/**
* @notice Retrieves the total supply of stakes managed by the strategy.
* @return The total supply of stakes.
*/
function totalSupply() external view returns (uint256) {
return ISingelTokenVirtualRewarder(virtualRewarder).totalSupply();
}
/**
* @notice Compounds the earnings by reinvesting the harvested rewards into the underlying asset.
* @dev Calls the Voting Escrow contract to lock up harvested FENIX tokens, thereby compounding the rewards.
*/
function compound() external {
IERC20Upgradeable fenixCache = IERC20Upgradeable(fenix);
uint256 currentBalance = fenixCache.balanceOf(address(this));
if (currentBalance > 0) {
address votingEscrowCache = votingEscrow;
fenixCache.safeApprove(votingEscrowCache, currentBalance);
IVotingEscrow(votingEscrowCache).depositFor(managedTokenId, currentBalance, false, false);
ISingelTokenVirtualRewarder(virtualRewarder).notifyRewardAmount(currentBalance);
emit Compound(msg.sender, currentBalance);
}
}
/**
* @notice Sets a new address for the Router V2 Path Provider.
* @dev Accessible only by admins, this function updates the address used for determining swap routes in token buyback strategies.
* @param routerV2PathProvider_ The new Router V2 Path Provider address.
*/
function setRouterV2PathProvider(address routerV2PathProvider_) external virtual onlyAdmin {
_checkAddressZero(routerV2PathProvider_);
emit SetRouterV2PathProvider(routerV2PathProvider, routerV2PathProvider_);
routerV2PathProvider = routerV2PathProvider_;
}
/**
* @notice Claims bribes for the current strategy and recovers specified ERC20 tokens to a recipient.
* @dev This function allows the strategy to claim bribes from specified contracts and transfer
* non-strategic ERC20 tokens back to the designated recipient in a single transaction.
* @param bribes_ The list of addresses representing bribe contracts from which to claim rewards.
* @param tokens_ A nested array where each entry corresponds to a list of token addresses to claim from the respective bribe contract.
* @param recipient_ The address to which recovered tokens should be sent.
* @param tokensToRecover_ The list of ERC20 token addresses to be recovered and transferred to the recipient.
*
* Emits:
* - Emits `Erc20Recover` for each recovered token.
*/
function claimBribesWithERC20Recover(
address[] calldata bribes_,
address[][] calldata tokens_,
address recipient_,
address[] calldata tokensToRecover_
) external {
_checkBuybackSwapPermissions();
if (bribes_.length > 0) {
claimBribes(bribes_, tokens_);
}
for (uint256 i; i < tokensToRecover_.length; ) {
_erc20Recover(tokensToRecover_[i], recipient_);
unchecked {
i++;
}
}
}
/**
* @notice Recovers ERC20 tokens accidentally sent to this contract, excluding the managed token (FENIX).
* @dev Allows the admin to recover non-strategic ERC20 tokens sent to the contract.
* @param token_ The address of the token to recover.
* @param recipient_ The address where the recovered tokens should be sent.
*/
function erc20Recover(address token_, address recipient_) external {
_checkBuybackSwapPermissions();
_erc20Recover(token_, recipient_);
}
/**
* @dev Internal function to recover the full balance of an ERC20 token held by the contract
* and transfer it to a specified recipient.
* @param token_ The address of the ERC20 token to recover.
* @param recipient_ The address where the recovered tokens will be sent.
*
* Emits:
* - `Erc20Recover` event with details of the token recovery, including the caller, recipient, token address, and recovered amount.
*/
function _erc20Recover(address token_, address recipient_) internal {
if (
!LibStrategyFlags.hasFlag(
IManagedNFTManager(managedNFTManager).getStrategyFlags(address(this)),
LibStrategyFlags.IGNORE_RESTRICTIONS_ON_RECOVER_TOKENS
)
) {
if (token_ == address(fenix) || IRouterV2PathProvider(routerV2PathProvider).isAllowedTokenInInputRoutes(token_)) {
revert IncorrectRecoverToken();
}
}
uint256 amount = IERC20Upgradeable(token_).balanceOf(address(this));
if (amount > 0) {
IERC20Upgradeable(token_).safeTransfer(recipient_, amount);
emit Erc20Recover(msg.sender, recipient_, token_, amount);
}
}
/**
* @dev Internal function to enforce permissions or rules
*/
function _checkBuybackSwapPermissions() internal view virtual override {
IManagedNFTManager managedNFTManagerCache = IManagedNFTManager(managedNFTManager);
if (managedNFTManagerCache.isAdmin(msg.sender) || managedNFTManagerCache.isAuthorized(managedTokenId, msg.sender)) {
return;
}
revert AccessDenied();
}
/**
* @dev Internal helper to fetch the target token for buybacks.
* @return The address of the buyback target token.
*/
function _getBuybackTargetToken() internal view virtual override returns (address) {
return fenix;
}
/**
* @dev Checked provided address on zero value, throw AddressZero error in case when addr_ is zero
*
* @param addr_ The address which will checked on zero
*/
function _checkAddressZero(address addr_) internal pure override(BaseManagedNFTStrategyUpgradeable, SingelTokenBuybackUpgradeable) {
if (addr_ == address(0)) {
revert AddressZero();
}
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @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 IERC20PermitUpgradeable {
/**
* @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 v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
import "../extensions/IERC20PermitUpgradeable.sol";
import "../../../utils/AddressUpgradeable.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 SafeERC20Upgradeable {
using AddressUpgradeable for address;
/**
* @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(IERC20Upgradeable token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, 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(IERC20Upgradeable token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 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(IERC20Upgradeable token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @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(IERC20Upgradeable token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20PermitUpgradeable token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @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(IERC20Upgradeable 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, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @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(IERC20Upgradeable 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))) && AddressUpgradeable.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165Upgradeable.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721Upgradeable is IERC165Upgradeable {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface IVoter {
/**
* @notice Represents the state of a gauge.
* @param isGauge Indicates if the address is a gauge.
* @param isAlive Indicates if the gauge is active.
* @param internalBribe The address of the internal bribe contract.
* @param externalBribe The address of the external bribe contract.
* @param pool The address of the associated pool.
* @param claimable The amount of rewards claimable by the gauge.
* @param index The current index used for reward distribution calculations.
* @param lastDistributionTimestamp The last time rewards were distributed.
*/
struct GaugeState {
bool isGauge;
bool isAlive;
address internalBribe;
address externalBribe;
address pool;
uint256 claimable;
uint256 index;
uint256 lastDistributionTimestamp;
}
/**
* @notice Parameters for creating a veNFT through VotingEscrow.
* @param percentageToLock The percentage (in 18 decimals) of the claimed reward tokens to be locked.
* @param lockDuration The duration (in seconds) for which the tokens will be locked.
* @param to The address that will receive the veNFT.
* @param shouldBoosted Indicates whether the veNFT should have boosted properties.
* @param withPermanentLock Indicates if the lock should be permanent.
* @param managedTokenIdForAttach The ID of the managed veNFT token to which this lock will be attached.
*/
struct AggregateCreateLockParams {
uint256 percentageToLock;
uint256 lockDuration;
address to;
bool shouldBoosted;
bool withPermanentLock;
uint256 managedTokenIdForAttach;
}
/**
* @notice Parameters for claiming bribes using a specific tokenId.
* @param tokenId The token ID to claim bribes for.
* @param bribes The array of bribe contract addresses.
* @param tokens The array of arrays containing token addresses for each bribe.
*/
struct AggregateClaimBribesByTokenIdParams {
uint256 tokenId;
address[] bribes;
address[][] tokens;
}
/**
* @notice Parameters for claiming bribes.
* @param bribes The array of bribe contract addresses.
* @param tokens The array of arrays containing token addresses for each bribe.
*/
struct AggregateClaimBribesParams {
address[] bribes;
address[][] tokens;
}
/**
* @notice Parameters for claiming Merkl data.
* @param users The array of user addresses to claim for.
* @param tokens The array of token addresses.
* @param amounts The array of amounts to claim.
* @param proofs The array of arrays containing Merkle proofs.
*/
struct AggregateClaimMerklDataParams {
address[] users;
address[] tokens;
uint256[] amounts;
bytes32[][] proofs;
}
/**
* @notice Parameters for claiming VeFnx Merkl airdrop data.
* @param inPureTokens_ Boolean indicating if the claim is in pure tokens.
* @param amount The amount to claim.
* @param withPermanentLock_ Whether the lock should be permanent.
* @param managedTokenIdForAttach_ The ID of the managed NFT to attach, if any. 0 for ignore
* @param proofs The array of Merkle proofs.
*/
struct AggregateClaimVeFnxMerklAirdrop {
bool inPureTokens;
uint256 amount;
bool withPermanentLock;
uint256 managedTokenIdForAttach;
bytes32[] proofs;
}
/**
* @notice Emitted when a gauge is created.
* @param gauge The address of the created gauge.
* @param creator The address of the creator.
* @param internalBribe The address of the created internal bribe.
* @param externalBribe The address of the created external bribe.
* @param pool The address of the associated pool.
*/
event GaugeCreated(address indexed gauge, address creator, address internalBribe, address indexed externalBribe, address indexed pool);
/**
* @notice Emitted when a gauge is created.
* @param gauge The address of the created gauge.
* @param gaugeType Type identifier of the created gauge.
*/
event GaugeCreatedType(address indexed gauge, uint256 indexed gaugeType);
/**
* @notice Emitted when a gauge is killed.
* @param gauge The address of the killed gauge.
*/
event GaugeKilled(address indexed gauge);
/**
* @notice Emitted when a gauge is revived.
* @param gauge The address of the revived gauge.
*/
event GaugeRevived(address indexed gauge);
/**
* @dev Emitted when a user casts votes for multiple pools using a specific token.
*
* @param voter The address of the user who cast the votes.
* @param tokenId The ID of the token used for voting.
* @param epoch The epoch during which the votes were cast.
* @param pools An array of pool addresses that received votes.
* @param voteWeights An array representing the weight of votes allocated to each pool.
*
* Requirements:
* - `pools` and `voteWeights` arrays must have the same length.
*
* Note: The voting power represented in `voteWeights` is allocated across the specified `votedPools` for the given `epoch`.
* The `totalVotingPower` represents the cumulative voting power used in this vote.
*/
event VoteCast(
address indexed voter,
uint256 indexed tokenId,
uint256 indexed epoch,
address[] pools,
uint256[] voteWeights,
uint256 totalVotingPower
);
/**
* @dev Emitted when a user resets all votes for the current epoch.
*
* @param voter The address of the user who resets their votes.
* @param tokenId The ID of the token used for voting that is being reset.
* @param epoch The epoch during which the votes were reset.
* @param totalResetVotingPower The total voting power that was reset.
*
* Note: This event indicates that all previously cast votes for the specified `epoch` have been reset for the given `votingTokenId`.
* The `totalResetVotingPower` represents the cumulative voting power that was removed during the reset.
*/
event VoteReset(address indexed voter, uint256 indexed tokenId, uint256 indexed epoch, uint256 totalResetVotingPower);
/**
* @notice Emitted when rewards are notified for distribution.
* @param sender The address of the sender.
* @param reward The address of the reward token.
* @param amount The amount of rewards to distribute.
*/
event NotifyReward(address indexed sender, address indexed reward, uint256 amount);
/**
* @notice Emitted when rewards are distributed to a gauge.
* @param sender The address of the sender.
* @param gauge The address of the gauge receiving the rewards.
* @param amount The amount of rewards distributed.
*/
event DistributeReward(address indexed sender, address indexed gauge, uint256 amount);
/**
* @notice Emitted when the vote delay is updated.
* @param old The previous vote delay.
* @param latest The new vote delay.
*/
event SetVoteDelay(uint256 old, uint256 latest);
/**
* @notice Emitted when a contract address is updated.
* @param key The key representing the contract.
* @param value The new address of the contract.
*/
event UpdateAddress(string key, address indexed value);
/// @notice Event emitted when voting is paused or unpaused.
/// @dev Emits the current paused state of voting.
/// @param paused Indicates whether voting is paused (true) or unpaused (false).
event VotingPaused(bool indexed paused);
/**
* @notice Emitted when the distribution window duration is set or updated.
* @param duration New duration of the distribution window in seconds.
*/
event SetDistributionWindowDuration(uint256 indexed duration);
/**
* @notice Emitted when a token is attached to a managed NFT.
* @param tokenId ID of the user's token that is being attached.
* @param managedTokenId ID of the managed token to which the user's token is attached.
*/
event AttachToManagedNFT(uint256 indexed tokenId, uint256 indexed managedTokenId);
/**
* @notice Emitted when a token is detached from a managed NFT.
* @param tokenId ID of the user's token that is being detached.
*/
event DettachFromManagedNFT(uint256 indexed tokenId);
/**
* @notice Updates the address of a specified contract.
* @param key_ The key representing the contract.
* @param value_ The new address of the contract.
*/
function updateAddress(string memory key_, address value_) external;
/**
* @notice Sets the duration of the distribution window for voting.
* @param distributionWindowDuration_ The duration in seconds.
*/
function setDistributionWindowDuration(uint256 distributionWindowDuration_) external;
/**
* @notice Disables a gauge, preventing further rewards distribution.
* @param gauge_ The address of the gauge to be disabled.
*/
function killGauge(address gauge_) external;
/**
* @notice Revives a previously disabled gauge, allowing it to distribute rewards again.
* @param gauge_ The address of the gauge to be revived.
*/
function reviveGauge(address gauge_) external;
/**
* @notice Creates a new V2 gauge for a specified pool.
* @param pool_ The address of the pool for which to create a gauge.
* @return gauge The address of the created gauge.
* @return internalBribe The address of the created internal bribe.
* @return externalBribe The address of the created external bribe.
*/
function createV2Gauge(address pool_) external returns (address gauge, address internalBribe, address externalBribe);
/**
* @notice Creates a new V3 gauge for a specified pool.
* @param pool_ The address of the pool for which to create a gauge.
* @return gauge The address of the created gauge.
* @return internalBribe The address of the created internal bribe.
* @return externalBribe The address of the created external bribe.
*/
function createV3Gauge(address pool_) external returns (address gauge, address internalBribe, address externalBribe);
/**
* @notice Creates a custom gauge with specified parameters.
* @param gauge_ The address of the custom gauge.
* @param pool_ The address of the pool for which to create a gauge.
* @param tokenA_ The address of token A in the pool.
* @param tokenB_ The address of token B in the pool.
* @param externalBribesName_ The name of the external bribe.
* @param internalBribesName_ The name of the internal bribe.
* @return gauge The address of the created gauge.
* @return internalBribe The address of the created internal bribe.
* @return externalBribe The address of the created external bribe.
*/
function createCustomGauge(
address gauge_,
address pool_,
address tokenA_,
address tokenB_,
string memory externalBribesName_,
string memory internalBribesName_
) external returns (address gauge, address internalBribe, address externalBribe);
/**
* @notice Notifies the contract of a reward amount to be distributed.
* @param amount_ The amount of rewards to distribute.
*/
function notifyRewardAmount(uint256 amount_) external;
/**
* @notice Distributes fees to a list of gauges.
* @param gauges_ An array of gauge addresses to distribute fees to.
*/
function distributeFees(address[] calldata gauges_) external;
/**
* @notice Distributes rewards to all pools managed by the contract.
*/
function distributeAll() external;
/**
* @notice Distributes rewards to a specified range of pools.
* @param start_ The starting index of the pool array.
* @param finish_ The ending index of the pool array.
*/
function distribute(uint256 start_, uint256 finish_) external;
/**
* @notice Distributes rewards to a specified list of gauges.
* @param gauges_ An array of gauge addresses to distribute rewards to.
*/
function distribute(address[] calldata gauges_) external;
/**
* @notice Resets the votes for a given NFT token ID.
* @param tokenId_ The token ID for which to reset votes.
*/
function reset(uint256 tokenId_) external;
/**
* @notice Updates the voting preferences for a given token ID.
* @param tokenId_ The token ID for which to update voting preferences.
*/
function poke(uint256 tokenId_) external;
/**
* @notice Casts votes for a given NFT token ID.
* @param tokenId_ The token ID for which to cast votes.
* @param poolsVotes_ An array of pool addresses to vote for.
* @param weights_ An array of weights corresponding to the pools.
*/
function vote(uint256 tokenId_, address[] calldata poolsVotes_, uint256[] calldata weights_) external;
/**
* @notice Claims rewards from multiple gauges.
* @param _gauges An array of gauge addresses to claim rewards from.
*/
function claimRewards(address[] memory _gauges) external;
/**
* @notice Claims bribes for a given NFT token ID from multiple bribe contracts.
* @param _bribes An array of bribe contract addresses to claim bribes from.
* @param _tokens An array of token arrays, specifying the tokens to claim.
* @param tokenId_ The token ID for which to claim bribes.
*/
function claimBribes(address[] memory _bribes, address[][] memory _tokens, uint256 tokenId_) external;
/**
* @notice Claims bribes from multiple bribe contracts.
* @param _bribes An array of bribe contract addresses to claim bribes from.
* @param _tokens An array of token arrays, specifying the tokens to claim.
*/
function claimBribes(address[] memory _bribes, address[][] memory _tokens) external;
/**
* @notice Handles the deposit of voting power to a managed NFT.
* @dev This function is called after tokens are deposited into the Voting Escrow contract for a managed NFT.
* Only callable by the Voting Escrow contract.
* @param tokenId_ The ID of the token that has received the deposit.
* @param managedTokenId_ The ID of the managed token receiving the voting power.
* @custom:error AccessDenied Thrown if the caller is not the Voting Escrow contract.
*/
function onDepositToManagedNFT(uint256 tokenId_, uint256 managedTokenId_) external;
/**
* @notice Attaches a tokenId to a managed tokenId.
* @param tokenId_ The user's tokenId to be attached.
* @param managedTokenId_ The managed tokenId to attach to.
*/
function attachToManagedNFT(uint256 tokenId_, uint256 managedTokenId_) external;
/**
* @notice Detaches a tokenId from its managed tokenId.
* @param tokenId_ The user's tokenId to be detached.
*/
function dettachFromManagedNFT(uint256 tokenId_) external;
/**
* @notice Checks if the provided address is a registered gauge.
* @param gauge_ The address of the gauge to check.
* @return True if the address is a registered gauge, false otherwise.
*/
function isGauge(address gauge_) external view returns (bool);
/**
* @notice Returns the state of a specific gauge.
* @param gauge_ The address of the gauge.
* @return GaugeState The current state of the specified gauge.
*/
function getGaugeState(address gauge_) external view returns (GaugeState memory);
/**
* @notice Checks if the specified gauge is alive (i.e., enabled for reward distribution).
* @param gauge_ The address of the gauge to check.
* @return True if the gauge is alive, false otherwise.
*/
function isAlive(address gauge_) external view returns (bool);
/**
* @notice Returns the pool address associated with a specified gauge.
* @param gauge_ The address of the gauge to query.
* @return The address of the pool associated with the specified gauge.
*/
function poolForGauge(address gauge_) external view returns (address);
/**
* @notice Returns the gauge address associated with a specified pool.
* @param pool_ The address of the pool to query.
* @return The address of the gauge associated with the specified pool.
*/
function poolToGauge(address pool_) external view returns (address);
/**
* @notice Returns the address of the Voting Escrow contract.
* @return The address of the Voting Escrow contract.
*/
function votingEscrow() external view returns (address);
/**
* @notice Returns the address of the Minter contract.
* @return The address of the Minter contract.
*/
function minter() external view returns (address);
/**
* @notice Returns the address of the V2 Pool Factory contract.
* @return The address of the V2 Pool Factory contract.
*/
function v2PoolFactory() external view returns (address);
/**
* @notice Returns the address of the V3 Pool Factory contract.
* @return The address of the V3 Pool Factory contract.
*/
function v3PoolFactory() external view returns (address);
/**
* @notice Returns the V2 pool address at a specific index.
* @param index The index of the V2 pool.
* @return The address of the V2 pool at the specified index.
*/
function v2Pools(uint256 index) external view returns (address);
/**
* @notice Returns the V3 pool address at a specific index.
* @param index The index of the V3 pool.
* @return The address of the V3 pool at the specified index.
*/
function v3Pools(uint256 index) external view returns (address);
/**
* @notice Returns the total number of pools, V2 pools, and V3 pools managed by the contract.
* @return totalCount The total number of pools.
* @return v2PoolsCount The total number of V2 pools.
* @return v3PoolsCount The total number of V3 pools.
*/
function poolsCounts() external view returns (uint256 totalCount, uint256 v2PoolsCount, uint256 v3PoolsCount);
/**
* @notice Returns the current epoch timestamp used for reward calculations.
* @return The current epoch timestamp.
*/
function epochTimestamp() external view returns (uint256);
/**
* @notice Returns the weight for a specific pool in a given epoch.
* @param timestamp The timestamp of the epoch.
* @param pool The address of the pool.
* @return The weight of the pool in the specified epoch.
*/
function weightsPerEpoch(uint256 timestamp, address pool) external view returns (uint256);
/**
* @notice Returns the vote weight of a specific NFT token ID for a given pool.
* @param tokenId The ID of the NFT.
* @param pool The address of the pool.
* @return The vote weight of the token for the specified pool.
*/
function votes(uint256 tokenId, address pool) external view returns (uint256);
/**
* @notice Returns the number of pools that an NFT token ID has voted for.
* @param tokenId The ID of the NFT.
* @return The number of pools the token has voted for.
*/
function poolVoteLength(uint256 tokenId) external view returns (uint256);
/**
* @notice Returns the pool address at a specific index for which the NFT token ID has voted.
* @param tokenId The ID of the NFT.
* @param index The index of the pool.
* @return The address of the pool at the specified index.
*/
function poolVote(uint256 tokenId, uint256 index) external view returns (address);
/**
* @notice Returns the last timestamp when an NFT token ID voted.
* @param tokenId The ID of the NFT.
* @return The timestamp of the last vote.
*/
function lastVotedTimestamps(uint256 tokenId) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
/**
* @title IVotingEscrow
* @notice Interface for Voting Escrow, allowing users to lock tokens in exchange for veNFTs that are used in governance and other systems.
*/
interface IVotingEscrow is IERC721Upgradeable {
/**
* @notice Enum representing the types of deposits that can be made.
* @dev Defines the context in which a deposit is made:
* - `DEPOSIT_FOR_TYPE`: Regular deposit for an existing lock.
* - `CREATE_LOCK_TYPE`: Creating a new lock.
* - `INCREASE_UNLOCK_TIME`: Increasing the unlock time for an existing lock.
* - `MERGE_TYPE`: Merging two locks together.
*/
enum DepositType {
DEPOSIT_FOR_TYPE,
CREATE_LOCK_TYPE,
INCREASE_UNLOCK_TIME,
MERGE_TYPE
}
/**
* @notice Structure representing the state of a token.
* @dev This includes information about the lock, voting status, attachment status,
* the block of the last transfer, and the index (epoch) of its latest checkpoint.
* @param locked The locked balance (amount + end timestamp + permanent status) of the token.
* @param isVoted Whether the token has been used to vote in the current epoch.
* @param isAttached Whether the token is attached to a managed NFT.
* @param lastTranferBlock The block number of the last transfer.
* @param pointEpoch The epoch (checkpoint index) for the token’s most recent voting power change.
*/
struct TokenState {
LockedBalance locked;
bool isVoted;
bool isAttached;
uint256 lastTranferBlock;
uint256 pointEpoch;
}
/**
* @notice Structure representing a locked balance.
* @dev Contains the amount locked, the end timestamp of the lock, and whether the lock is permanent.
* @param amount The amount of tokens locked (signed integer for slope calculations).
* @param end The timestamp when the lock ends (0 if permanently locked).
* @param isPermanentLocked Whether the lock is permanent (no unlock time).
*/
struct LockedBalance {
int128 amount;
uint256 end;
bool isPermanentLocked;
}
/**
* @notice Structure representing a point in time for calculating voting power.
* @dev Used for slope/bias math across epochs.
* @param bias The bias of the lock, representing the remaining voting power.
* @param slope The rate at which voting power (bias) decays over time.
* @param ts The timestamp of the checkpoint.
* @param blk The block number of the checkpoint.
* @param permanent The permanently locked amount at this checkpoint.
*/
struct Point {
int128 bias;
int128 slope; // -dweight / dt
uint256 ts;
uint256 blk; // block
int128 permanent;
}
/**
* @notice Emitted when a boost is applied to a token's lock.
* @param tokenId The ID of the token that received the boost.
* @param value The amount of tokens used as a boost.
*/
event Boost(uint256 indexed tokenId, uint256 value);
/**
* @notice Emitted when a deposit is made into a lock.
* @param provider The address of the entity making the deposit.
* @param tokenId The ID of the token associated with the deposit.
* @param value The amount of tokens deposited.
* @param locktime The time (timestamp) until which the lock is extended.
* @param deposit_type The type of deposit (see {DepositType}).
* @param ts The timestamp when the deposit was made.
*/
event Deposit(address indexed provider, uint256 tokenId, uint256 value, uint256 indexed locktime, DepositType deposit_type, uint256 ts);
/**
* @notice Emitted when tokens are deposited to an attached NFT.
* @param provider The address of the user making the deposit.
* @param tokenId The ID of the NFT receiving the deposit.
* @param managedTokenId The ID of the managed token receiving the voting power.
* @param value The amount of tokens deposited.
*/
event DepositToAttachedNFT(address indexed provider, uint256 tokenId, uint256 managedTokenId, uint256 value);
/**
* @notice Emitted when a withdrawal is made from a lock.
* @param provider The address of the entity making the withdrawal.
* @param tokenId The ID of the token associated with the withdrawal.
* @param value The amount of tokens withdrawn.
* @param ts The timestamp when the withdrawal occurred.
*/
event Withdraw(address indexed provider, uint256 tokenId, uint256 value, uint256 ts);
/**
* @notice Emitted when the merging process of two veNFT locks is initiated.
* @param tokenFromId The ID of the token being merged from.
* @param tokenToId The ID of the token being merged into.
*/
event MergeInit(uint256 tokenFromId, uint256 tokenToId);
/**
* @notice Emitted when two veNFT locks are successfully merged.
* @param provider The address of the entity initiating the merge.
* @param tokenIdFrom The ID of the token being merged from.
* @param tokenIdTo The ID of the token being merged into.
*/
event Merge(address indexed provider, uint256 tokenIdFrom, uint256 tokenIdTo);
/**
* @notice Emitted when the total supply of voting power changes.
* @param prevSupply The previous total supply of voting power.
* @param supply The new total supply of voting power.
*/
event Supply(uint256 prevSupply, uint256 supply);
/**
* @notice Emitted when an address associated with the contract is updated.
* @param key The key representing the contract being updated.
* @param value The new address of the contract.
*/
event UpdateAddress(string key, address indexed value);
/**
* @notice Emitted when a token is permanently locked by a user.
* @param sender The address of the user who initiated the lock.
* @param tokenId The ID of the token that has been permanently locked.
*/
event LockPermanent(address indexed sender, uint256 indexed tokenId);
/**
* @notice Emitted when a token is unlocked from a permanent lock state by a user.
* @param sender The address of the user who initiated the unlock.
* @param tokenId The ID of the token that has been unlocked from its permanent state.
*/
event UnlockPermanent(address indexed sender, uint256 indexed tokenId);
/**
* @notice Emitted when a veFNX NFT lock is burned and the underlying FNX is released for use in bribes.
* @param sender The address which initiated the burn-to-bribes operation.
* @param tokenId The identifier of the veFNX NFT that was burned.
* @param value The amount of FNX tokens released from the burned lock.
*/
event BurnToBribes(address indexed sender, uint256 indexed tokenId, uint256 value);
/**
* @notice Returns the address of the token used in voting escrow.
* @return The address of the token contract.
*/
function token() external view returns (address);
/**
* @notice Returns the address of the voter contract.
* @return The address of the voter.
*/
function voter() external view returns (address);
/**
* @notice Checks if the specified address is approved or the owner of the given token.
* @param sender The address to check.
* @param tokenId The ID of the token to check.
* @return True if `sender` is approved or the owner of `tokenId`, otherwise false.
*/
function isApprovedOrOwner(address sender, uint256 tokenId) external view returns (bool);
/**
* @notice Checks if a specific NFT token is transferable.
* @dev In the current implementation, this function always returns `true`,
* meaning the contract does not enforce non-transferability at code level.
* @param tokenId_ The ID of the NFT to check.
* @return bool Always returns true in the current version.
*/
function isTransferable(uint256 tokenId_) external view returns (bool);
/**
* @notice Retrieves the state of a specific NFT.
* @param tokenId_ The ID of the NFT to query.
* @return The current {TokenState} of the specified NFT.
*/
function getNftState(uint256 tokenId_) external view returns (TokenState memory);
/**
* @notice Returns the total supply of voting power at the current block timestamp.
* @return The total supply of voting power.
*/
function votingPowerTotalSupply() external view returns (uint256);
/**
* @notice Returns the balance of a veNFT at the current block timestamp.
* @dev Balance is determined by the lock’s slope and bias at this moment.
* @param tokenId_ The ID of the veNFT to query.
* @return The current voting power (balance) of the veNFT.
*/
function balanceOfNFT(uint256 tokenId_) external view returns (uint256);
/**
* @notice Returns the balance of a veNFT at the current block timestamp, ignoring ownership changes.
* @dev This function is similar to {balanceOfNFT} but does not zero out the balance
* if the token was transferred in the same block.
* @param tokenId_ The ID of the veNFT to query.
* @return The current voting power (balance) of the veNFT.
*/
function balanceOfNftIgnoreOwnershipChange(uint256 tokenId_) external view returns (uint256);
/**
* @notice Updates the address of a specified contract.
* @param key_ The key representing the contract.
* @param value_ The new address of the contract.
* @dev Reverts with `InvalidAddressKey` if the key does not match any known setting.
* Emits an {UpdateAddress} event on success.
*/
function updateAddress(string memory key_, address value_) external;
/**
* @notice Hooks the voting state for a specified NFT.
* @dev Only callable by the voter contract. Used to mark a veNFT as having voted or not.
* @param tokenId_ The ID of the NFT.
* @param state_ True if the NFT is now considered “voted,” false otherwise.
* @custom:error AccessDenied If called by any address other than the voter.
*/
function votingHook(uint256 tokenId_, bool state_) external;
/**
* @notice Creates a new lock for a specified recipient.
* @param amount_ The amount of tokens to lock.
* @param lockDuration_ The duration in seconds for which the tokens will be locked.
* @param to_ The address of the recipient who will receive the new veNFT.
* @param shouldBoosted_ Whether the deposit should attempt to get a veBoost.
* @param withPermanentLock_ Whether the lock should be created as a permanent lock.
* @param managedTokenIdForAttach_ (Optional) The ID of the managed NFT to attach. Pass 0 to ignore.
* @return The ID of the newly created veNFT.
* @dev Reverts with `InvalidLockDuration` if lockDuration_ is 0 or too large.
* Reverts with `ValueZero` if amount_ is 0.
* Emits a {Deposit} event on success.
*/
function createLockFor(
uint256 amount_,
uint256 lockDuration_,
address to_,
bool shouldBoosted_,
bool withPermanentLock_,
uint256 managedTokenIdForAttach_
) external returns (uint256);
/**
* @notice Deposits tokens for a specific NFT, increasing its locked balance.
* @param tokenId_ The ID of the veNFT to top up.
* @param amount_ The amount of tokens to deposit.
* @param shouldBoosted_ Whether this deposit should attempt to get a veBoost.
* @param withPermanentLock_ Whether to apply a permanent lock alongside the deposit.
* @dev Reverts with `ValueZero` if amount_ is 0.
* Emits a {Deposit} event upon success.
*/
function depositFor(uint256 tokenId_, uint256 amount_, bool shouldBoosted_, bool withPermanentLock_) external;
/**
* @notice Increases the unlock time for an existing lock.
* @param tokenId_ The ID of the veNFT to extend.
* @param lockDuration_ The additional duration in seconds to add to the current unlock time.
* @dev Reverts with `InvalidLockDuration` if the new unlock time is invalid.
* Reverts with `AccessDenied` if the caller is not the owner or approved.
* Emits a {Deposit} event with the deposit type set to {INCREASE_UNLOCK_TIME}.
*/
function increase_unlock_time(uint256 tokenId_, uint256 lockDuration_) external;
/**
* @notice Deposits tokens and extends the lock duration for a veNFT in one call.
* @dev This may trigger veBoost if conditions are met.
* @param tokenId_ The ID of the veNFT.
* @param amount_ The amount of tokens to deposit.
* @param lockDuration_ The duration in seconds to add to the current unlock time.
* Emits one {Deposit} event for the deposit itself
* and another {Deposit} event for the unlock time increase.
*/
function depositWithIncreaseUnlockTime(uint256 tokenId_, uint256 amount_, uint256 lockDuration_) external;
/**
* @notice Deposits tokens directly into a veNFT that is attached to a managed NFT.
* @dev This updates the locked balance on the managed NFT, adjusts total supply,
* and emits {DepositToAttachedNFT} and {Supply} events.
* @param tokenId_ The ID of the attached veNFT.
* @param amount_ The amount of tokens to deposit.
* @custom:error NotManagedNft if the managed token ID is invalid or not recognized.
*/
function depositToAttachedNFT(uint256 tokenId_, uint256 amount_) external;
/**
* @notice Withdraws tokens from an expired lock (non-permanent).
* @param tokenId_ The ID of the veNFT to withdraw from.
* @dev Reverts with `AccessDenied` if caller is not owner or approved.
* Reverts with `TokenNoExpired` if the lock is not yet expired.
* Reverts with `PermanentLocked` if the lock is permanent.
* Emits a {Withdraw} event and a {Supply} event.
*/
function withdraw(uint256 tokenId_) external;
/**
* @notice Merges one veNFT (tokenFromId_) into another (tokenToId_).
* @param tokenFromId_ The ID of the source veNFT being merged.
* @param tokenToId_ The ID of the target veNFT receiving the locked tokens.
* @dev Reverts with `MergeTokenIdsTheSame` if both IDs are the same.
* Reverts with `AccessDenied` if the caller isn't owner or approved for both IDs.
* Emits a {MergeInit} event at the start, and a {Merge} event upon completion.
* Also emits a {Deposit} event reflecting the updated lock in the target token.
*/
function merge(uint256 tokenFromId_, uint256 tokenToId_) external;
/**
* @notice Permanently locks a veNFT.
* @param tokenId_ The ID of the veNFT to be permanently locked.
* @dev Reverts with `AccessDenied` if caller isn't owner or approved.
* Reverts with `TokenAttached` if the token is attached to a managed NFT.
* Reverts with `PermanentLocked` if the token already permanent lcoked
* Emits {LockPermanent} on success.
*/
function lockPermanent(uint256 tokenId_) external;
/**
* @notice Unlocks a permanently locked veNFT, reverting it to a temporary lock.
* @param tokenId_ The ID of the veNFT to unlock.
* @dev Reverts with `AccessDenied` if caller isn't owner or approved.
* Reverts with `TokenAttached` if the token is attached.
* Reverts with `NotPermanentLocked` if the lock isn't actually permanent.
* Emits {UnlockPermanent} on success.
*/
function unlockPermanent(uint256 tokenId_) external;
/**
* @notice Creates a new managed NFT for a given recipient.
* @param recipient_ The address that will receive the newly created managed NFT.
* @return The ID of the newly created managed NFT.
* @dev Reverts with `AccessDenied` if caller is not the managed NFT manager.
*/
function createManagedNFT(address recipient_) external returns (uint256);
/**
* @notice Attaches a veNFT (user’s token) to a managed NFT, combining their locked balances.
* @param tokenId_ The ID of the user’s veNFT being attached.
* @param managedTokenId_ The ID of the managed NFT.
* @return The amount of tokens locked during the attachment.
* @dev Reverts with `AccessDenied` if caller is not the managed NFT manager.
* Reverts with `ZeroVotingPower` if the user’s token has zero voting power.
* Reverts with `NotManagedNft` if the target is not recognized as a managed NFT.
*/
function onAttachToManagedNFT(uint256 tokenId_, uint256 managedTokenId_) external returns (uint256);
/**
* @notice Detaches a veNFT from a managed NFT.
* @param tokenId_ The ID of the user’s veNFT being detached.
* @param managedTokenId_ The ID of the managed NFT from which it’s being detached.
* @param newBalance_ The new locked balance the veNFT will hold after detachment.
* @dev Reverts with `AccessDenied` if caller is not the managed NFT manager.
* Reverts with `NotManagedNft` if the target is not recognized as a managed NFT.
*/
function onDettachFromManagedNFT(uint256 tokenId_, uint256 managedTokenId_, uint256 newBalance_) external;
/**
* @notice Burns a veFNX NFT to reclaim the underlying FNX tokens for use in bribes.
* @dev Must be called by `customBribeRewardRouter`.
* The token must not be permanently locked or attached.
* Also resets any votes before burning.
* Emits a {BurnToBribes} event on successful burn.
* @param tokenId_ The ID of the veFNX NFT to burn.
*/
function burnToBribes(uint256 tokenId_) external;
}// SPDX-License-Identifier: MIT
pragma solidity =0.8.19;
interface IRouterV2 {
struct route {
address from;
address to;
bool stable;
}
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
route[] calldata routes,
address to,
uint deadline
) external returns (uint[] memory amounts);
function pairFor(address tokenA, address tokenB, bool stable) external view returns (address pair);
function getAmountsOut(uint amountIn, route[] memory routes) external view returns (uint[] memory amounts);
function getAmountOut(uint amountIn, address tokenIn, address tokenOut) external view returns (uint amount, bool stable);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.19;
import {IBlastFull, YieldMode, GasMode} from "./interfaces/IBlastFull.sol";
import {IBlastGovernor} from "./interfaces/IBlastGovernor.sol";
/**
* @title Blast Governor Claiamble Setup
* @dev Abstract contract for setting up a governor in the Blast ecosystem.
* This contract provides an initialization function to configure a governor address
* for the Blast protocol, utilizing the `IBlast` interface.
*/
abstract contract BlastGovernorClaimableSetup {
/// @dev Error thrown when an operation involves a zero address where a valid address is required.
error AddressZero();
/**
* @dev Initializes the governor and claimable configuration for the Blast protocol.
* This internal function is meant to be called in the initialization process
* of a derived contract that sets up governance.
*
* @param blastGovernor_ The address of the governor to be configured in the Blast protocol.
* Must be a non-zero address.
*/
function __BlastGovernorClaimableSetup_init(address blastGovernor_) internal {
if (blastGovernor_ == address(0)) {
revert AddressZero();
}
IBlastFull(0x4300000000000000000000000000000000000002).configure(YieldMode.CLAIMABLE, GasMode.CLAIMABLE, blastGovernor_);
if (blastGovernor_.code.length > 0) {
IBlastGovernor(blastGovernor_).addGasHolder(address(this));
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/**
* @title IBlastFull Interface
* @dev Interface for interacting with the Blast protocol, specifically for configuring
* governance settings. This interface abstracts the function to set up a governor
* within the Blast ecosystem.
*/
enum GasMode {
VOID,
CLAIMABLE
}
enum YieldMode {
AUTOMATIC,
VOID,
CLAIMABLE
}
interface IBlastFull {
// configure
function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external;
function configure(YieldMode _yield, GasMode gasMode, address governor) external;
// base configuration options
function configureClaimableYield() external;
function configureClaimableYieldOnBehalf(address contractAddress) external;
function configureAutomaticYield() external;
function configureAutomaticYieldOnBehalf(address contractAddress) external;
function configureVoidYield() external;
function configureVoidYieldOnBehalf(address contractAddress) external;
function configureClaimableGas() external;
function configureClaimableGasOnBehalf(address contractAddress) external;
function configureVoidGas() external;
function configureVoidGasOnBehalf(address contractAddress) external;
function configureGovernor(address _governor) external;
function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external;
// claim yield
function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256);
function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256);
// claim gas
function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256);
// NOTE: can be off by 1 bip
function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) external returns (uint256);
function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256);
function claimGas(
address contractAddress,
address recipientOfGas,
uint256 gasToClaim,
uint256 gasSecondsToConsume
) external returns (uint256);
// read functions
function readClaimableYield(address contractAddress) external view returns (uint256);
function readYieldConfiguration(address contractAddress) external view returns (uint8);
function readGasParams(
address contractAddress
) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode);
function isGovernor(address) external view returns (bool);
function governorMap(address) external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity =0.8.19;
import {GasMode} from "./IBlastFull.sol";
/**
* @title IBlastGovernor
* @dev Interface for the BlastGovernor contract.
*/
interface IBlastGovernor {
/**
* @dev Structure representing gas parameters.
* @param contractAddress Address of the gas holder contract.
* @param etherSeconds Accumulated ether seconds.
* @param etherBalance Ether balance.
* @param lastUpdated Timestamp of the last update.
* @param gasMode Current gas mode.
*/
struct GasParamsResult {
address contractAddress;
uint256 etherSeconds;
uint256 etherBalance;
uint256 lastUpdated;
GasMode gasMode;
}
/**
* @dev Emitted when a gas holder is added.
* @param contractAddress The address of the added gas holder contract.
*/
event AddGasHolder(address indexed contractAddress);
/**
* @dev Emitted when gas is claimed.
* @param caller The address of the caller who initiated the claim.
* @param recipient The address of the recipient who receives the claimed gas.
* @param gasHolders The addresses of the gas holders from which gas was claimed.
* @param totalClaimedAmount The total amount of gas claimed.
*/
event ClaimGas(address indexed caller, address indexed recipient, address[] gasHolders, uint256 totalClaimedAmount);
/**
* @notice Adds a gas holder.
* @dev Adds a contract to the list of gas holders.
* @param contractAddress_ The address of the gas holder contract.
*/
function addGasHolder(address contractAddress_) external;
/**
* @notice Claims all gas for a recipient within the specified range.
* @param recipient_ The address of the recipient.
* @param offset_ The offset to start from.
* @param limit_ The maximum number of gas holders to process.
* @return totalClaimedGas The total amount of gas claimed.
*/
function claimAllGas(address recipient_, uint256 offset_, uint256 limit_) external returns (uint256 totalClaimedGas);
/**
* @notice Claims all gas for a recipient from specified gas holders.
* @param recipient_ The address of the recipient.
* @param holders_ The addresses of the gas holders.
* @return totalClaimedGas The total amount of gas claimed.
*/
function claimAllGasFromSpecifiedGasHolders(address recipient_, address[] memory holders_) external returns (uint256 totalClaimedGas);
/**
* @notice Claims gas at minimum claim rate for a recipient within the specified range.
* @param recipient_ The address of the recipient.
* @param minClaimRateBips_ The minimum claim rate in basis points.
* @param offset_ The offset to start from.
* @param limit_ The maximum number of gas holders to process.
* @return totalClaimedGas The total amount of gas claimed.
*/
function claimGasAtMinClaimRate(
address recipient_,
uint256 minClaimRateBips_,
uint256 offset_,
uint256 limit_
) external returns (uint256 totalClaimedGas);
/**
* @notice Claims gas at minimum claim rate for a recipient from specified gas holders.
* @param recipient_ The address of the recipient.
* @param minClaimRateBips_ The minimum claim rate in basis points.
* @param holders_ The addresses of the gas holders.
* @return totalClaimedGas The total amount of gas claimed.
*/
function claimGasAtMinClaimRateFromSpecifiedGasHolders(
address recipient_,
uint256 minClaimRateBips_,
address[] memory holders_
) external returns (uint256 totalClaimedGas);
/**
* @notice Claims maximum gas for a recipient within the specified range.
* @param recipient_ The address of the recipient.
* @param offset_ The offset to start from.
* @param limit_ The maximum number of gas holders to process.
* @return totalClaimedGas The total amount of gas claimed.
*/
function claimMaxGas(address recipient_, uint256 offset_, uint256 limit_) external returns (uint256 totalClaimedGas);
/**
* @notice Claims maximum gas for a recipient from specified gas holders.
* @param recipient_ The address of the recipient.
* @param holders_ The addresses of the gas holders.
* @return totalClaimedGas The total amount of gas claimed.
*/
function claimMaxGasFromSpecifiedGasHolders(address recipient_, address[] memory holders_) external returns (uint256 totalClaimedGas);
/**
* @notice Claims a specific amount of gas for a recipient within the specified range.
* @param recipient_ The address of the recipient.
* @param gasToClaim_ The amount of gas to claim.
* @param gasSecondsToConsume_ The amount of gas seconds to consume.
* @param offset_ The offset to start from.
* @param limit_ The maximum number of gas holders to process.
* @return totalClaimedGas The total amount of gas claimed.
*/
function claimGas(
address recipient_,
uint256 gasToClaim_,
uint256 gasSecondsToConsume_,
uint256 offset_,
uint256 limit_
) external returns (uint256 totalClaimedGas);
/**
* @notice Claims a specific amount of gas for a recipient from specified gas holders.
* @param recipient_ The address of the recipient.
* @param gasToClaim_ The amount of gas to claim.
* @param gasSecondsToConsume_ The amount of gas seconds to consume.
* @param holders_ The addresses of the gas holders.
* @return totalClaimedGas The total amount of gas claimed.
*/
function claimGasFromSpecifiedGasHolders(
address recipient_,
uint256 gasToClaim_,
uint256 gasSecondsToConsume_,
address[] memory holders_
) external returns (uint256 totalClaimedGas);
/**
* @notice Reads gas parameters within the specified range.
* @param offset_ The offset to start from.
* @param limit_ The maximum number of gas holders to process.
* @return gasHoldersParams The gas parameters of the gas holders.
*/
function readGasParams(uint256 offset_, uint256 limit_) external view returns (GasParamsResult[] memory gasHoldersParams);
/**
* @notice Reads gas parameters from specified gas holders.
* @param holders_ The addresses of the gas holders.
* @return gasHoldersParams The gas parameters of the gas holders.
*/
function readGasParamsFromSpecifiedGasHolders(
address[] memory holders_
) external view returns (GasParamsResult[] memory gasHoldersParams);
/**
* @notice Checks if a contract is a registered gas holder.
* @param contractAddress_ The address of the contract.
* @return isRegistered Whether the contract is a registered gas holder.
*/
function isRegisteredGasHolder(address contractAddress_) external view returns (bool isRegistered);
/**
* @notice Lists gas holders within the specified range.
* @param offset_ The offset to start from.
* @param limit_ The maximum number of gas holders to process.
* @return gasHolders The addresses of the gas holders.
*/
function listGasHolders(uint256 offset_, uint256 limit_) external view returns (address[] memory gasHolders);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface IUpgradeCall {
function upgradeCall() external;
}// SPDX-License-Identifier: MIT
pragma solidity =0.8.19;
import {IUpgradeCall} from "./interfaces/IUgradeCall.sol";
abstract contract UpgradeCall is IUpgradeCall {
function upgradeCall() external virtual override {}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.19;
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {BlastGovernorClaimableSetup} from "../integration/BlastGovernorClaimableSetup.sol";
import {IVoter} from "../core/interfaces/IVoter.sol";
import {IVotingEscrow} from "../core/interfaces/IVotingEscrow.sol";
import {IManagedNFTManager} from "./interfaces/IManagedNFTManager.sol";
import {IManagedNFTStrategy} from "./interfaces/IManagedNFTStrategy.sol";
import {UpgradeCall} from "../integration/UpgradeCall.sol";
/**
* @title Base Managed NFT Strategy Upgradeable
* @dev Abstract base contract for strategies managing NFTs with voting and reward capabilities.
* This contract serves as a foundation for specific managed NFT strategies, incorporating initializable patterns for upgradeability.
*/
abstract contract BaseManagedNFTStrategyUpgradeable is IManagedNFTStrategy, Initializable, BlastGovernorClaimableSetup, UpgradeCall {
/// @notice The name of the strategy for identification purposes.
string public override name;
/// @notice The description of the strategy for identification purposes.
string public override description;
/// @notice The creator of the strategy for identification purposes.
string public override creator;
/// @notice The address of the managed NFT manager that coordinates the overall strategy and access controls.
address public override managedNFTManager;
/// @notice The specific token ID of the NFT being managed under this strategy.
uint256 public override managedTokenId;
/// @notice The address of the voting escrow contract, which locks governance tokens to enable voting power.
address public override votingEscrow;
/// @notice The address of the voter contract, which handles governance actions and reward claims.
address public override voter;
/// @notice Error thrown when an unauthorized user attempts to perform an action reserved for specific roles.
error AccessDenied();
/// @notice Error thrown when attempting to attach a token ID that is either incorrect or already in use.
error IncorrectManagedTokenId();
/// @notice Error thrown when attempting to attach a token ID that has already been attached to another strategy.
error AlreadyAttached();
/// @dev Ensures that only the current managed NFT manager contract can call certain functions.
modifier onlyManagedNFTManager() {
if (managedNFTManager != msg.sender) {
revert AccessDenied();
}
_;
}
/// @dev Ensures that only administrators defined in the managed NFT manager can perform certain actions.
modifier onlyAdmin() {
if (!IManagedNFTManager(managedNFTManager).isAdmin(msg.sender)) {
revert AccessDenied();
}
_;
}
/// @dev Ensures that only authorized users, as determined by the managed NFT manager, can call certain functions.
modifier onlyAuthorized() {
if (!IManagedNFTManager(managedNFTManager).isAuthorized(managedTokenId, msg.sender)) {
revert AccessDenied();
}
_;
}
/**
* @dev Initializes the contract, setting up blast governor setup and necessary state variables.
* This initialization setup prevents further initialization and ensures proper governance setup.
* @param blastGovernor_ Address of the governance contract capable of claiming the contract
* @param managedNFTManager_ Address of the managed NFT manager
* @param name_ Descriptive name of the managed NFT strategy
*/
function __BaseManagedNFTStrategy__init(
address blastGovernor_,
address managedNFTManager_,
string memory name_
) internal onlyInitializing {
__BlastGovernorClaimableSetup_init(blastGovernor_);
_checkAddressZero(managedNFTManager_);
managedNFTManager = managedNFTManager_;
votingEscrow = IManagedNFTManager(managedNFTManager_).votingEscrow();
voter = IManagedNFTManager(managedNFTManager_).voter();
name = name_;
}
/**
* @notice Attaches a specific managed NFT to this strategy, setting up necessary governance or reward mechanisms.
* @dev This function can only be called by administrators. It sets the `managedTokenId` and ensures that the token is
* valid and owned by this contract. Emits an `AttachedManagedNFT` event upon successful attachment.
* @param managedTokenId_ The token ID of the NFT to be managed by this strategy.
* throws AlreadyAttached if the strategy is already attached to a managed NFT.
* throws IncorrectManagedTokenId if the provided token ID is not managed or not owned by this contract.
*/
function attachManagedNFT(uint256 managedTokenId_) external onlyAdmin {
if (managedTokenId != 0) {
revert AlreadyAttached();
}
if (
!IManagedNFTManager(managedNFTManager).isManagedNFT(managedTokenId_) ||
IVotingEscrow(votingEscrow).ownerOf(managedTokenId_) != address(this)
) {
revert IncorrectManagedTokenId();
}
managedTokenId = managedTokenId_;
emit AttachedManagedNFT(managedTokenId_);
}
/**
* @notice Allows administrative updating of the strategy's name for clarity or rebranding purposes.
* @dev Emits the SetName event upon successful update. This function can only be called by administrators.
*
* @param name_ The new name to set for the strategy, reflecting either its purpose or current operational focus.
*/
function setName(string calldata name_) external onlyAdmin {
name = name_;
emit SetName(name_);
}
/**
* @notice Allows administrative updating of the strategy's creator name for clarity or rebranding purposes.
* @dev Emits the SetCreator event upon successful update. This function can only be called by administrators.
*
* @param creator_ The new creator to set for the strategy, reflecting either its purpose or current operational focus.
*/
function setCreator(string calldata creator_) external onlyAdmin {
creator = creator_;
emit SetCreator(creator_);
}
/**
* @notice Allows administrative updating of the strategy's description.
* @dev Emits the SetDescription event upon successful update. This function can only be called by administrators.
*
* @param description_ The new description to set for the strategy, reflecting either its purpose or current operational focus.
*/
function setDescription(string calldata description_) external onlyAdmin {
description = description_;
emit SetDescription(description_);
}
/**
* @notice Casts votes based on the strategy's parameters.
* @param poolVote_ Array of pool addresses to vote for.
* @param weights_ Array of weights corresponding to each pool address.
*/
function vote(address[] calldata poolVote_, uint256[] calldata weights_) external onlyAuthorized {
IVoter(voter).vote(managedTokenId, poolVote_, weights_);
}
/**
* @notice Claims rewards from the specified gauges.
* @param gauges_ Array of gauge addresses from which to claim rewards.
*/
function claimRewards(address[] calldata gauges_) external {
IVoter(voter).claimRewards(gauges_);
}
/**
* @notice Claims bribes for specific tokens from specified bribe addresses.
* @param bribes_ Array of bribe addresses.
* @param tokens_ Array of arrays of token addresses corresponding to each bribe address.
*/
function claimBribes(address[] calldata bribes_, address[][] calldata tokens_) public {
IVoter(voter).claimBribes(bribes_, tokens_, managedTokenId);
}
/**
* @dev Checked provided address on zero value, throw AddressZero error in case when addr_ is zero
*
* @param addr_ The address which will checked on zero
*/
function _checkAddressZero(address addr_) internal pure virtual {
if (addr_ == address(0)) {
revert AddressZero();
}
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IManagedNFTStrategy} from "./IManagedNFTStrategy.sol";
import {ISingelTokenBuyback} from "./ISingelTokenBuyback.sol";
/**
* @title ICompoundVeFNXManagedNFTStrategy
* @dev Interface for a compound strategy specific to VeFNX tokens, extending the basic managed NFT strategy functionality.
* @notice This interface provides functionalities to handle compounding of VeFNX token rewards and interactions with a virtual rewarder contract.
*/
interface ICompoundVeFNXManagedNFTStrategy is IManagedNFTStrategy, ISingelTokenBuyback {
/**
* @dev Emitted when rewards are compounded by the caller.
*
* @param caller The address of the account that called the compound function.
* @param amount The amount of VeFNX tokens that were compounded.
*/
event Compound(address indexed caller, uint256 indexed amount);
/**
* @dev Emitted when an NFT is attached to the strategy, initializing reward mechanisms for it.
*
* @param tokenId The ID of the NFT that is being attached.
* @param userBalance The balance associated with the NFT at the time of attachment.
*/
event OnAttach(uint256 indexed tokenId, uint256 indexed userBalance);
/**
* @dev Emitted when an NFT is detached from the strategy, concluding reward mechanisms for it.
*
* @param tokenId The ID of the NFT that is being detached.
* @param userBalance The balance associated with the NFT at the time of detachment.
* @param lockedRewards The rewards that were locked and harvested upon detachment.
*/
event OnDettach(uint256 indexed tokenId, uint256 indexed userBalance, uint256 indexed lockedRewards);
/**
* @dev Emitted when ERC20 tokens are recovered from the contract by an admin.
*
* @param caller The address of the caller who initiated the recovery.
* @param recipient The recipient address where the recovered tokens were sent.
* @param token The address of the token that was recovered.
* @param amount The amount of the token that was recovered.
*/
event Erc20Recover(address indexed caller, address indexed recipient, address indexed token, uint256 amount);
/**
* @dev Emitted when the address of the Router V2 Path Provider is updated.
*
* @param oldRouterV2PathProvider The address of the previous Router V2 Path Provider.
* @param newRouterV2PathProvider The address of the new Router V2 Path Provider that has been set.
*/
event SetRouterV2PathProvider(address indexed oldRouterV2PathProvider, address indexed newRouterV2PathProvider);
/**
* @notice Compounds accumulated rewards into additional stakes or holdings.
* @dev Function to reinvest earned rewards back into the underlying asset to increase the principal amount.
* This is specific to strategies dealing with compounding mechanisms in DeFi protocols.
*/
function compound() external;
/**
* @notice Returns the address of the virtual rewarder associated with this strategy.
* @return address The contract address of the virtual rewarder that manages reward distributions for this strategy.
*/
function virtualRewarder() external view returns (address);
/**
* @notice Returns the address of the FENIX token used in this strategy.
* @return address The contract address of the FENIX token.
*/
function fenix() external view returns (address);
/**
* @notice Retrieves the total amount of locked rewards available for a specific NFT based on its tokenId.
* @param tokenId_ The identifier of the NFT to query.
* @return The total amount of locked rewards for the specified NFT.
*/
function getLockedRewardsBalance(uint256 tokenId_) external view returns (uint256);
/**
* @notice Retrieves the balance or stake associated with a specific NFT.
* @param tokenId_ The identifier of the NFT to query.
* @return The balance of the specified NFT.
*/
function balanceOf(uint256 tokenId_) external view returns (uint256);
/**
* @notice Retrieves the total supply of stakes managed by the strategy.
* @return The total supply of stakes.
*/
function totalSupply() external view returns (uint256);
/**
* @notice Claims bribes for the current strategy and recovers specified ERC20 tokens to a recipient.
* @dev This function allows the strategy to claim bribes from specified contracts and transfer
* non-strategic ERC20 tokens back to the designated recipient in a single transaction.
* @param bribes_ The list of addresses representing bribe contracts from which to claim rewards.
* @param tokens_ A nested array where each entry corresponds to a list of token addresses to claim from the respective bribe contract.
* @param recipient_ The address to which recovered tokens should be sent.
* @param tokensToRecover_ The list of ERC20 token addresses to be recovered and transferred to the recipient.
*
* Emits:
* - Emits `Erc20Recover` for each recovered token.
*/
function claimBribesWithERC20Recover(
address[] calldata bribes_,
address[][] calldata tokens_,
address recipient_,
address[] calldata tokensToRecover_
) external;
/**
* @notice Initializes the contract with necessary blast governance and operational addresses, and sets specific strategy parameters.
*
* @param blastGovernor_ Address of the blast governor contract.
* @param managedNFTManager_ Address of the managed NFT manager contract.
* @param virtualRewarder_ Address of the virtual rewarder contract.
* @param name_ Name of the strategy.
*/
function initialize(
address blastGovernor_,
address managedNFTManager_,
address virtualRewarder_,
address routerV2PathProvider_,
string memory name_
) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/**
* @title Interface for Managed NFT Manager
* @dev Defines the functions and events for managing NFTs, including attaching/detaching to strategies, authorization, and administrative checks.
*/
interface IManagedNFTManager {
/**
* @dev Emitted when the disabled state of a managed NFT is toggled.
* @param sender The address that triggered the state change.
* @param tokenId The ID of the managed NFT affected.
* @param isDisable True if the NFT is now disabled, false if it is enabled.
*/
event ToggleDisableManagedNFT(address indexed sender, uint256 indexed tokenId, bool indexed isDisable);
/**
* @dev Emitted when a new managed NFT is created and attached to a strategy.
* @param sender The address that performed the creation.
* @param strategy The address of the strategy to which the NFT is attached.
* @param tokenId The ID of the newly created managed NFT.
*/
event CreateManagedNFT(address indexed sender, address indexed strategy, uint256 indexed tokenId);
/**
* @dev Emitted when an NFT is whitelisted or removed from the whitelist.
* @param tokenId The ID of the NFT being modified.
* @param isWhitelisted True if the NFT is being whitelisted, false if it is being removed from the whitelist.
*/
event SetWhitelistedNFT(uint256 indexed tokenId, bool indexed isWhitelisted);
/**
* @dev Emitted when an authorized user is set for a managed NFT.
* @param managedTokenId The ID of the managed NFT.
* @param authorizedUser The address being authorized.
*/
event SetAuthorizedUser(uint256 indexed managedTokenId, address authorizedUser);
/**
* @dev Emitted when the strategy flags for a specific strategy are updated.
* @param strategy The address of the strategy whose flags are being updated.
* @param flags The new set of flags assigned to the strategy.
*/
event SetStrategyFlags(address indexed strategy, uint8 flags);
/**
* @notice Checks if a managed NFT is currently disabled.
* @param managedTokenId_ The ID of the managed NFT.
* @return True if the managed NFT is disabled, false otherwise.
*/
function isDisabledNFT(uint256 managedTokenId_) external view returns (bool);
/**
* @notice Determines if a token ID is recognized as a managed NFT within the system.
* @param managedTokenId_ The ID of the token to check.
* @return True if the token is a managed NFT, false otherwise.
*/
function isManagedNFT(uint256 managedTokenId_) external view returns (bool);
/**
* @notice Checks if an NFT is whitelisted within the management system.
* @param tokenId_ The ID of the NFT to check.
* @return True if the NFT is whitelisted, false otherwise.
*/
function isWhitelistedNFT(uint256 tokenId_) external view returns (bool);
/**
* @notice Verifies if a user's NFT is attached to any managed NFT.
* @param tokenId_ The ID of the user's NFT.
* @return True if the NFT is attached, false otherwise.
*/
function isAttachedNFT(uint256 tokenId_) external view returns (bool);
/**
* @notice Checks if a given account is an administrator of the managed NFT system.
* @param account_ The address to check.
* @return True if the address is an admin, false otherwise.
*/
function isAdmin(address account_) external view returns (bool);
/**
* @notice Retrieves the managed token ID that a user's NFT is attached to.
* @param tokenId_ The ID of the user's NFT.
* @return The ID of the managed token to which the NFT is attached.
*/
function getAttachedManagedTokenId(uint256 tokenId_) external view returns (uint256);
/**
* @notice Address of the Voting Escrow contract managing voting and staking mechanisms.
*/
function votingEscrow() external view returns (address);
/**
* @notice Address of the Voter contract responsible for handling governance actions related to managed NFTs.
*/
function voter() external view returns (address);
/**
* @notice Verifies if a given address is authorized to manage a specific managed NFT.
* @param managedTokenId_ The ID of the managed NFT.
* @param account_ The address to verify.
* @return True if the address is authorized, false otherwise.
*/
function isAuthorized(uint256 managedTokenId_, address account_) external view returns (bool);
/**
* @notice Retrieves the strategy flags for a given strategy.
* @param strategy_ The address of the strategy to retrieve flags for.
* @return The flags assigned to the specified strategy.
*/
function getStrategyFlags(address strategy_) external view returns (uint8);
/**
* @notice Assigns an authorized user for a managed NFT.
* @param managedTokenId_ The ID of the managed NFT.
* @param authorizedUser_ The address to authorize.
*/
function setAuthorizedUser(uint256 managedTokenId_, address authorizedUser_) external;
/**
* @notice Creates a managed NFT and attaches it to a strategy
* @param strategy_ The strategy to which the managed NFT will be attached
*/
function createManagedNFT(address strategy_) external returns (uint256 managedTokenId);
/**
* @notice Toggles the disabled state of a managed NFT
* @param managedTokenId_ The ID of the managed token to toggle
* @dev Enables or disables a managed token to control its operational status, with an event emitted for state change.
*/
function toggleDisableManagedNFT(uint256 managedTokenId_) external;
/**
* @notice Attaches a user's NFT to a managed NFT, enabling it within a specific strategy.
* @param tokenId_ The user's NFT token ID.
* @param managedTokenId The managed NFT token ID.
*/
function onAttachToManagedNFT(uint256 tokenId_, uint256 managedTokenId) external;
/**
* @notice Detaches a user's NFT from a managed NFT, disabling it within the strategy.
* @param tokenId_ The user's NFT token ID.
*/
function onDettachFromManagedNFT(uint256 tokenId_) external;
/**
* @notice Handles the deposit of tokens to an NFT attached to a managed token.
* @dev Called by the Voting Escrow contract when tokens are deposited to an NFT that is attached to a managed NFT.
* The function verifies the token is attached, checks if it is disabled, and updates the token's state.
* @param tokenId_ The token ID of the user's NFT.
* @param amount_ The amount of tokens to deposit.
* @custom:error IncorrectUserNFT Thrown if the provided token ID is not attached or if it is a managed token itself.
* @custom:error ManagedNFTIsDisabled Thrown if the managed token is currently disabled.
*/
function onDepositToAttachedNFT(uint256 tokenId_, uint256 amount_) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/**
* @title IManagedNFTStrategy
* @dev Interface for strategies managing NFTs ,
* participate in voting, and claim rewards.
*/
interface IManagedNFTStrategy {
/**
* @dev Emitted when the name of the strategy is changed.
* @param newName The new name that has been set for the strategy.
*/
event SetName(string newName);
/**
* @dev Emitted when the description of the strategy is changed.
* @param newDescription The new description that has been set for the strategy.
*/
event SetDescription(string newDescription);
/**
* @dev Emitted when the description of the strategy is changed.
* @param newCreator The new description that has been set for the strategy.
*/
event SetCreator(string newCreator);
/**
* @dev Emitted when a new managed NFT is successfully attached to the strategy.
* @param managedTokenId The ID of the managed NFT that has been attached.
*/
event AttachedManagedNFT(uint256 indexed managedTokenId);
/**
* @notice Called when an NFT is attached to a strategy.
* @dev Allows the strategy to perform initial setup or balance tracking when an NFT is first attached.
* @param tokenId The ID of the NFT being attached.
* @param userBalance The balance of governance tokens associated with the NFT at the time of attachment.
*/
function onAttach(uint256 tokenId, uint256 userBalance) external;
/**
* @notice Called when an NFT is detached from a strategy.
* @dev Allows the strategy to clean up or update records when an NFT is removed.
* @param tokenId The ID of the NFT being detached.
* @param userBalance The remaining balance of governance tokens associated with the NFT at the time of detachment.
*/
function onDettach(uint256 tokenId, uint256 userBalance) external returns (uint256 lockedRewards);
/**
* @notice Gets the address of the managed NFT manager contract.
* @return The address of the managed NFT manager.
*/
function managedNFTManager() external view returns (address);
/**
* @notice Gets the address of the voting escrow contract used for locking governance tokens.
* @return The address of the voting escrow contract.
*/
function votingEscrow() external view returns (address);
/**
* @notice Gets the address of the voter contract that coordinates governance actions.
* @return The address of the voter contract.
*/
function voter() external view returns (address);
/**
* @notice Retrieves the name of the strategy.
* @return A string representing the name of the strategy.
*/
function name() external view returns (string memory);
/**
* @notice Retrieves the creator name of the strategy.
* Empty string by default
* @return A string representing the name of the strategy.
*/
function creator() external view returns (string memory);
/**
* @notice Retrieves the description of the strategy.
* Empty string by default
* @return A string representing the name of the strategy.
*/
function description() external view returns (string memory);
/**
* @notice Retrieves the ID of the managed token.
* @return The token ID used by the strategy.
*/
function managedTokenId() external view returns (uint256);
/**
* @notice Submits a governance vote on behalf of the strategy.
* @param poolVote_ An array of addresses representing the pools to vote on.
* @param weights_ An array of weights corresponding to each pool vote.
*/
function vote(address[] calldata poolVote_, uint256[] calldata weights_) external;
/**
* @notice Claims rewards allocated to the managed NFTs from specified gauges.
* @param gauges_ An array of addresses representing the gauges from which rewards are to be claimed.
*/
function claimRewards(address[] calldata gauges_) external;
/**
* @notice Claims bribes allocated to the managed NFTs for specific tokens and pools.
* @param bribes_ An array of addresses representing the bribe pools.
* @param tokens_ An array of token addresses for each bribe pool where rewards can be claimed.
*/
function claimBribes(address[] calldata bribes_, address[][] calldata tokens_) external;
/**
* @notice Attaches a specific managed NFT to this strategy, setting up necessary governance or reward mechanisms.
* @dev This function can only be called by administrators. It sets the `managedTokenId` and ensures that the token is
* valid and owned by this contract. Emits an `AttachedManagedNFT` event upon successful attachment.
* @param managedTokenId_ The token ID of the NFT to be managed by this strategy.
* throws AlreadyAttached if the strategy is already attached to a managed NFT.
* throws IncorrectManagedTokenId if the provided token ID is not managed or not owned by this contract.
*/
function attachManagedNFT(uint256 managedTokenId_) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IRouterV2} from "../../dexV2/interfaces/IRouterV2.sol";
/**
* @title Interface for Router V2 Path Provider
* @notice Defines the required functionalities for managing routing paths within a decentralized exchange.
*/
interface IRouterV2PathProvider {
/**
* @notice Emitted when a new route is registered for a token
* @param token Address of the token for which the route is registered
* @param route Details of the registered route
*/
event RegisterRouteForToken(address indexed token, IRouterV2.route route);
/**
* @notice Emitted when the allowance of a token to be used in input routes is updated
* @param token Address of the token
* @param isAllowed New allowance status (true if allowed, false otherwise)
*/
event SetAllowedTokenInInputRouters(address indexed token, bool indexed isAllowed);
/**
* @notice Emitted when a new route is added to a token
* @param token Address of the token to which the route is added
* @param route Details of the route added
*/
event AddRouteToToken(address indexed token, IRouterV2.route route);
/**
* @notice Emitted when a route is removed from a token
* @param token Address of the token from which the route is removed
* @param route Details of the route removed
*/
event RemoveRouteFromToken(address indexed token, IRouterV2.route route);
/**
* @notice Sets whether a token can be used in input routes
* @param token_ Address of the token to set the permission
* @param isAllowed_ Boolean flag to allow or disallow the token
*/
function setAllowedTokenInInputRouters(address token_, bool isAllowed_) external;
/**
* @notice Fetches the address of the router
* @return The address of the router contract
*/
function router() external view returns (address);
/**
* @notice Fetches the address of the factory
* @return The address of the factory contract
*/
function factory() external view returns (address);
/**
* @notice Checks if a token is allowed in input routes
* @param token_ Address of the token to check
* @return True if the token is allowed, false otherwise
*/
function isAllowedTokenInInputRoutes(address token_) external view returns (bool);
/**
* @notice Retrieves all possible routes between two tokens
* @param inputToken_ Address of the input token
* @param outputToken_ Address of the output token
* @return routes A two-dimensional array of routes
*/
function getRoutesTokenToToken(address inputToken_, address outputToken_) external view returns (IRouterV2.route[][] memory routes);
/**
* @notice Determines the optimal route and output amount for a given input amount between two tokens
* @param inputToken_ Address of the input token
* @param outputToken_ Address of the output token
* @param amountIn_ Amount of the input token
* @return A tuple containing the optimal route and the output amount
*/
function getOptimalTokenToTokenRoute(
address inputToken_,
address outputToken_,
uint256 amountIn_
) external view returns (IRouterV2.route[] memory, uint256 amountOut);
/**
* @notice Calculates the output amount for a specified route given an input amount
* @param amountIn_ Amount of input tokens
* @param routes_ Routes to calculate the output amount
* @return The amount of output tokens
*/
function getAmountOutQuote(uint256 amountIn_, IRouterV2.route[] calldata routes_) external view returns (uint256);
/**
* @notice Validates if all routes provided are valid according to the system's rules
* @param inputRouters_ Array of routes to validate
* @return True if all routes are valid, false otherwise
*/
function isValidInputRoutes(IRouterV2.route[] calldata inputRouters_) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IRouterV2} from "../../dexV2/interfaces/IRouterV2.sol";
interface ISingelTokenBuyback {
event BuybackTokenByV2(
address indexed caller,
address indexed inputToken,
address indexed outputToken,
IRouterV2.route[] routes,
uint256 inputAmount,
uint256 outputAmount
);
/**
* @notice Address of the Router V2 Path Provider used for fetching and calculating optimal token swap routes.
* @dev This address is utilized to access routing functionality for executing token buybacks.
*/
function routerV2PathProvider() external view returns (address);
/**
* @notice Buys back tokens by swapping specified input tokens for a target token via a DEX
* @dev Executes a token swap using the optimal route found via Router V2 Path Provider. Ensures input token is not the target token and validates slippage.
*
* @param inputToken_ The ERC20 token to swap from.
* @param inputRouters_ Array of routes to potentially use for the swap.
* @param slippage_ The maximum allowed slippage for the swap, in basis points.
* @param deadline_ Unix timestamp after which the transaction will revert.
*/
function buybackTokenByV2(
address inputToken_,
IRouterV2.route[] calldata inputRouters_,
uint256 slippage_,
uint256 deadline_
) external returns (uint256 outputAmount);
/**
* @notice Retrieves the target token for buybacks.
* @dev Provides an abstraction layer over internal details, potentially allowing for dynamic updates in the future.
* @return The address of the token targeted for buyback operations.
*/
function getBuybackTargetToken() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/**
* @title Interface for Single Token Virtual Rewarder
* @dev Defines the basic interface for a reward system that handles deposits, withdrawals, and rewards based on token staking over different epochs.
*/
interface ISingelTokenVirtualRewarder {
/**
* @dev Emitted when a deposit is made.
* @param tokenId The identifier of the token being deposited.
* @param amount The amount of tokens deposited.
* @param epoch The epoch during which the deposit occurs.
*/
event Deposit(uint256 indexed tokenId, uint256 indexed amount, uint256 indexed epoch);
/**
* @dev Emitted when a withdrawal is made.
* @param tokenId The identifier of the token being withdrawn.
* @param amount The amount of tokens withdrawn.
* @param epoch The epoch during which the withdrawal occurs.
*/
event Withdraw(uint256 indexed tokenId, uint256 indexed amount, uint256 indexed epoch);
/**
* @dev Emitted when rewards are harvested.
* @param tokenId The identifier of the token for which rewards are harvested.
* @param rewardAmount The amount of rewards harvested.
* @param epochCount The epoch during which the harvest occurs.
*/
event Harvest(uint256 indexed tokenId, uint256 indexed rewardAmount, uint256 indexed epochCount);
/**
* @dev Emitted when a new reward amount is notified to be added to the pool.
* @param rewardAmount The amount of rewards added.
* @param epoch The epoch during which the reward is added.
*/
event NotifyReward(uint256 indexed rewardAmount, uint256 indexed epoch);
/**
* @notice Handles the deposit of tokens into the reward system.
* @param tokenId The identifier of the token being deposited.
* @param amount The amount of tokens to deposit.
*/
function deposit(uint256 tokenId, uint256 amount) external;
/**
* @notice Handles the withdrawal of tokens from the reward system.
* @param tokenId The identifier of the token being withdrawn.
* @param amount The amount of tokens to withdraw.
*/
function withdraw(uint256 tokenId, uint256 amount) external;
/**
* @notice Notifies the system of a new reward amount to be distributed.
* @param amount The amount of the new reward to add.
*/
function notifyRewardAmount(uint256 amount) external;
/**
* @notice Harvests rewards for a specific token.
* @param tokenId The identifier of the token for which to harvest rewards.
* @return reward The amount of harvested rewards.
*/
function harvest(uint256 tokenId) external returns (uint256 reward);
/**
* @notice Calculates the available amount of rewards for a specific token.
* @param tokenId The identifier of the token.
* @return reward The calculated reward amount.
*/
function calculateAvailableRewardsAmount(uint256 tokenId) external view returns (uint256 reward);
/**
* @notice Returns the strategy address associated with this contract.
* @return The address of the strategy.
*/
function strategy() external view returns (address);
/**
* @notice Returns the total supply of tokens under management.
* @return The total supply of tokens.
*/
function totalSupply() external view returns (uint256);
/**
* @notice Returns the balance of a specific token.
* @param tokenId The identifier of the token.
* @return The balance of the specified token.
*/
function balanceOf(uint256 tokenId) external view returns (uint256);
/**
* @notice Provides the balance of a specific tokenId at a given timestamp
*
* @param tokenId_ The ID of the token to check
* @param timestamp_ The specific timestamp to check the balance at
* @return The balance of the token at the given timestamp
*/
function balanceOfAt(uint256 tokenId_, uint256 timestamp_) external view returns (uint256);
/**
* @notice Provides the total supply of tokens at a given timestamp
*
* @param timestamp_ The timestamp to check the total supply at
* @return The total supply of tokens at the specified timestamp
*/
function totalSupplyAt(uint256 timestamp_) external view returns (uint256);
/**
* @notice Returns the reward per epoch for a specific epoch.
* @param epoch The epoch for which to retrieve the reward amount.
* @return The reward amount for the specified epoch.
*/
function rewardsPerEpoch(uint256 epoch) external view returns (uint256);
/**
* @notice Initializes the contract with necessary governance and operational addresses
* @dev Sets up blast governance and operational aspects of the contract. This function can only be called once.
*
* @param blastGovernor_ The governance address capable of claiming the contract
* @param strategy_ The strategy address that will interact with this contract
*/
function initialize(address blastGovernor_, address strategy_) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.19;
/**
* @title LibStrategyFlags
* @dev Provides utility functions for managing strategy flags in the context of managed strategies.
*/
library LibStrategyFlags {
/**
* @notice Checks if a given strategy flags set contains a specific flag.
* @dev Uses bitwise operations to determine the presence of a flag within the provided flags set.
* @param strategyFlags_ The set of flags to check
* @param flag_ The specific flag to verify
* @return res True if the flag is present in the set, false otherwise.
*/
function hasFlag(uint8 strategyFlags_, uint256 flag_) internal pure returns (bool res) {
assembly {
res := gt(and(strategyFlags_, flag_), 0)
}
}
/**
* @dev Flag constant used to indicate that restrictions on recovering tokens should be ignored.
*/
uint256 internal constant IGNORE_RESTRICTIONS_ON_RECOVER_TOKENS = 1;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.19;
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {SafeERC20Upgradeable, IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {IRouterV2} from "../dexV2/interfaces/IRouterV2.sol";
import {IRouterV2PathProvider} from "./interfaces/IRouterV2PathProvider.sol";
import {ISingelTokenBuyback} from "./interfaces/ISingelTokenBuyback.sol";
/**
* @title Single Token Buyback Upgradeable Contract
* @notice Implements token buyback functionality using DEX V2 Router.
* @dev This contract uses an upgradeable pattern along with the SafeERC20 library for token interactions.
*/
abstract contract SingelTokenBuybackUpgradeable is ISingelTokenBuyback, Initializable {
using SafeERC20Upgradeable for IERC20Upgradeable;
/**
* @dev Emitted when the input token for a buyback operation is the same as the target token.
*/
error IncorrectInputToken();
/**
* @dev Emitted when the slippage specified for a buyback exceeds the maximum allowable limit.
*/
error IncorrectSlippage();
/**
* @dev Emitted when attempting a buyback with an empty balance.
*/
error ZeroBalance();
/**
* @dev Emitted when the input routes provided for a buyback are invalid or do not conform to expected standards
*/
error InvalidInputRoutes();
/**
* @dev Emitted when no viable route is found for the buyback operation.
*/
error RouteNotFound();
/**
* @dev Emitted when a function argument is expected to be a valid address but receives a zero address.
*/
error ZeroAddress();
/**
* @notice Maximum slippage allowed for buyback operations, represented in basis points.
* @dev Slippage is capped at 400 basis points (4%).
*/
uint256 public constant MAX_SLIPPAGE = 400;
/**
* @notice Precision used for representing slippage percentages.
* @dev Slippage calculations are based on a granularity of 10,000 to represent 100%.
*/
uint256 public constant SLIPPAGE_PRECISION = 10_000;
/**
*
* @notice Address of the Router V2 Path Provider used for fetching and calculating optimal token swap routes.
* @dev This address is utilized to access routing functionality for executing token buybacks.
*/
address public override routerV2PathProvider;
/**
* @notice Ensures the slippage value is within the acceptable range.
* @param slippage_ The slippage value to check.
* @dev Reverts with IncorrectSlippage if the slippage exceeds the maximum allowed.
*/
modifier onlyCorrectSlippage(uint256 slippage_) {
if (slippage_ > MAX_SLIPPAGE) {
revert IncorrectSlippage();
}
_;
}
/**
* @notice Ensures the provided token is not the target buyback token.
* @param token_ The token address to check.
* @dev Reverts with IncorrectInputToken if the token address matches the buyback target token.
*/
modifier onlyCorrectInputToken(address token_) {
_checkAddressZero(token_);
if (token_ == _getBuybackTargetToken()) {
revert IncorrectInputToken();
}
_;
}
/**
* @notice Initializes the buyback contract with the address of the router V2 path provider.
* @param routerV2PathProvider_ The address of the router V2 path provider to be set.
* @dev This function should be called from the contract's initializer function.
*/
function __SingelTokenBuyback__init(address routerV2PathProvider_) internal onlyInitializing {
_checkAddressZero(routerV2PathProvider_);
routerV2PathProvider = routerV2PathProvider_;
}
/**
* @notice Buys back tokens by swapping specified input tokens for a target token via a DEX
* @dev Executes a token swap using the optimal route found via Router V2 Path Provider. Ensures input token is not the target token and validates slippage.
*
* @param inputToken_ The ERC20 token to swap from.
* @param inputRouters_ Array of routes to potentially use for the swap.
* @param slippage_ The maximum allowed slippage for the swap, in basis points.
* @param deadline_ Unix timestamp after which the transaction will revert.
*/
function buybackTokenByV2(
address inputToken_,
IRouterV2.route[] calldata inputRouters_,
uint256 slippage_,
uint256 deadline_
) external virtual override onlyCorrectInputToken(inputToken_) onlyCorrectSlippage(slippage_) returns (uint256 outputAmount) {
_checkBuybackSwapPermissions();
IERC20Upgradeable inputTokenCache = IERC20Upgradeable(inputToken_);
uint256 amountIn = inputTokenCache.balanceOf(address(this));
if (amountIn == 0) {
revert ZeroBalance();
}
address targetToken = _getBuybackTargetToken();
IRouterV2PathProvider routerV2PathProviderCache = IRouterV2PathProvider(routerV2PathProvider);
(IRouterV2.route[] memory optimalRoute, ) = routerV2PathProviderCache.getOptimalTokenToTokenRoute(
inputToken_,
targetToken,
amountIn
);
uint256 amountOutQuote;
if (optimalRoute.length > 0) {
amountOutQuote = routerV2PathProviderCache.getAmountOutQuote(amountIn, optimalRoute);
}
if (inputRouters_.length > 1) {
if (inputRouters_[0].from != inputToken_ || inputRouters_[inputRouters_.length - 1].to != targetToken) {
revert InvalidInputRoutes();
}
if (!routerV2PathProviderCache.isValidInputRoutes(inputRouters_)) {
revert InvalidInputRoutes();
}
uint256 amountOutQuoteInputRouters = routerV2PathProviderCache.getAmountOutQuote(amountIn, inputRouters_);
if (amountOutQuoteInputRouters > amountOutQuote) {
optimalRoute = inputRouters_;
amountOutQuote = amountOutQuoteInputRouters;
}
}
amountOutQuote = amountOutQuote - (amountOutQuote * slippage_) / SLIPPAGE_PRECISION;
if (amountOutQuote == 0) {
revert RouteNotFound();
}
IRouterV2 router = IRouterV2(routerV2PathProviderCache.router());
inputTokenCache.safeApprove(address(router), amountIn);
uint256 balanceBefore = IERC20Upgradeable(targetToken).balanceOf(address(this));
uint256[] memory amountsOut = router.swapExactTokensForTokens(amountIn, amountOutQuote, optimalRoute, address(this), deadline_);
uint256 amountOut = amountsOut[amountsOut.length - 1];
assert(IERC20Upgradeable(targetToken).balanceOf(address(this)) - balanceBefore == amountOut);
assert(amountOut > 0);
emit BuybackTokenByV2(msg.sender, inputToken_, targetToken, optimalRoute, amountIn, amountOut);
return amountOut;
}
/**
* @notice Retrieves the target token for buybacks.
* @dev Provides an abstraction layer over internal details, potentially allowing for dynamic updates in the future.
* @return The address of the token targeted for buyback operations.
*/
function getBuybackTargetToken() external view returns (address) {
return _getBuybackTargetToken();
}
/**
* @dev Internal function to enforce permissions or rules before allowing a buyback swap to proceed.
*/
function _checkBuybackSwapPermissions() internal view virtual;
/**
* @dev Internal helper to fetch the target token for buybacks.
* @return The address of the buyback target token.
*/
function _getBuybackTargetToken() internal view virtual returns (address);
/**
* @dev Checked provided address on zero value, throw AddressZero error in case when addr_ is zero
*
* @param addr_ The address which will checked on zero
*/
function _checkAddressZero(address addr_) internal pure virtual {
if (addr_ == address(0)) {
revert ZeroAddress();
}
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}{
"evmVersion": "paris",
"viaIR": true,
"optimizer": {
"enabled": true,
"runs": 2000
},
"metadata": {
"bytecodeHash": "none"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"blastGovernor_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessDenied","type":"error"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[],"name":"AlreadyAttached","type":"error"},{"inputs":[],"name":"IncorrectInputToken","type":"error"},{"inputs":[],"name":"IncorrectManagedTokenId","type":"error"},{"inputs":[],"name":"IncorrectRecoverToken","type":"error"},{"inputs":[],"name":"IncorrectSlippage","type":"error"},{"inputs":[],"name":"InvalidInputRoutes","type":"error"},{"inputs":[],"name":"RouteNotFound","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroBalance","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"managedTokenId","type":"uint256"}],"name":"AttachedManagedNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"inputToken","type":"address"},{"indexed":true,"internalType":"address","name":"outputToken","type":"address"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"indexed":false,"internalType":"struct IRouterV2.route[]","name":"routes","type":"tuple[]"},{"indexed":false,"internalType":"uint256","name":"inputAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outputAmount","type":"uint256"}],"name":"BuybackTokenByV2","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Compound","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Erc20Recover","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"userBalance","type":"uint256"}],"name":"OnAttach","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"userBalance","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"lockedRewards","type":"uint256"}],"name":"OnDettach","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"newCreator","type":"string"}],"name":"SetCreator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"newDescription","type":"string"}],"name":"SetDescription","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"newName","type":"string"}],"name":"SetName","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldRouterV2PathProvider","type":"address"},{"indexed":true,"internalType":"address","name":"newRouterV2PathProvider","type":"address"}],"name":"SetRouterV2PathProvider","type":"event"},{"inputs":[],"name":"MAX_SLIPPAGE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SLIPPAGE_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"managedTokenId_","type":"uint256"}],"name":"attachManagedNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"inputToken_","type":"address"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"internalType":"struct IRouterV2.route[]","name":"inputRouters_","type":"tuple[]"},{"internalType":"uint256","name":"slippage_","type":"uint256"},{"internalType":"uint256","name":"deadline_","type":"uint256"}],"name":"buybackTokenByV2","outputs":[{"internalType":"uint256","name":"outputAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"bribes_","type":"address[]"},{"internalType":"address[][]","name":"tokens_","type":"address[][]"}],"name":"claimBribes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"bribes_","type":"address[]"},{"internalType":"address[][]","name":"tokens_","type":"address[][]"},{"internalType":"address","name":"recipient_","type":"address"},{"internalType":"address[]","name":"tokensToRecover_","type":"address[]"}],"name":"claimBribesWithERC20Recover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"gauges_","type":"address[]"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"compound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"creator","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"},{"internalType":"address","name":"recipient_","type":"address"}],"name":"erc20Recover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fenix","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBuybackTargetToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getLockedRewardsBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"blastGovernor_","type":"address"},{"internalType":"address","name":"managedNFTManager_","type":"address"},{"internalType":"address","name":"virtualRewarder_","type":"address"},{"internalType":"address","name":"routerV2PathProvider_","type":"address"},{"internalType":"string","name":"name_","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"managedNFTManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managedTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"userBalance_","type":"uint256"}],"name":"onAttach","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"userBalance_","type":"uint256"}],"name":"onDettach","outputs":[{"internalType":"uint256","name":"lockedRewards","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"routerV2PathProvider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"creator_","type":"string"}],"name":"setCreator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"description_","type":"string"}],"name":"setDescription","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name_","type":"string"}],"name":"setName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"routerV2PathProvider_","type":"address"}],"name":"setRouterV2PathProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"upgradeCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"virtualRewarder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"poolVote_","type":"address[]"},{"internalType":"uint256[]","name":"weights_","type":"uint256[]"}],"name":"vote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"voter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"votingEscrow","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6080346200022c57601f6200373038819003918201601f191683019260009290916001600160401b0385118386101762000218578160209284926040978852833981010312620001db57516001600160a01b03811690818103620002145781156200020357734300000000000000000000000000000000000002803b15620001ff57838091606487518094819363c8992e6160e01b835260026004840152600160248401528860448401525af18015620001f557620001df575b503b6200017a575b50805460ff8160081c16620001265760ff80821603620000eb575b82516134d490816200025c8239f35b60ff908119161790557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024986020825160ff8152a13880620000dc565b825162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b803b15620001db5781809160248551809481936305573b1760e31b83523060048401525af18015620001d157908291620001b6575b50620000c1565b620001c19062000231565b620001ce578038620001af565b80fd5b83513d84823e3d90fd5b5080fd5b620001ed9093919362000231565b9138620000b9565b85513d86823e3d90fd5b8380fd5b8351639fabe1c160e01b8152600490fd5b8280fd5b634e487b7160e01b84526041600452602484fd5b600080fd5b6001600160401b0381116200024557604052565b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561001357600080fd5b600090813560e01c90816302d05d3f146126f95750806306fdde031461262a57806318160ddd1461258f5780631f23baf014610df557806321e8adc114611bbe5780632fb3b36114611532578063363b28161461150b57806336f0a8131461144a5780633bb2fad914611436578063453943f01461141957806346c96aac146113f25780634b985845146111b75780634f2bfe5b14611190578063537f95ff1461116957806358b06db9146111365780636f816a2014610fb25780637284e41614610ed45780637f36b27614610e1c578063801512e414610df557806390c3f38f14610bdb5780639b7fcc1d14610ae85780639cc7f70814610a7c578063b0dfa49814610a5e578063c2b79e9814610a40578063c47f002714610890578063e5c02d0714610656578063ecb0a2651461062f578063ed4ec0c214610589578063f69e2046146103de578063f83a20681461025f578063f9759518146102425763f9f031df1461018157600080fd5b3461022c57602060031936011261022c578060043567ffffffffffffffff811161023f576101b39036906004016128f8565b6001600160a01b036007541691823b1561023a5761020b928492836040518096819582947ff9f031df000000000000000000000000000000000000000000000000000000008452602060048501526024840191612a91565b03925af1801561022f5761021c5750f35b61022590612807565b61022c5780f35b80fd5b6040513d84823e3d90fd5b505050fd5b50fd5b503461022c578060031936011261022c5760206040516101908152f35b503461022c5761026e36612974565b6001600160a01b0391826004541633036103b4578392606e5416803b1561023a576040517f441a3e70000000000000000000000000000000000000000000000000000000008152826004820152836024820152848160448183865af19081156103a9578591610395575b50506020906024604051809781937fddc632620000000000000000000000000000000000000000000000000000000083528660048401525af193841561038a578394610351575b509280916020947f976d41f146303c848c29c530312f8a84501dc7eb4e78716492ecde07de6b48166040519580a48152f35b93506020843d8211610382575b8161036b6020938361281b565b8101031261037d57602093519361031f565b600080fd5b3d915061035e565b6040513d85823e3d90fd5b61039e90612807565b61023a5783386102d8565b6040513d87823e3d90fd5b60046040517f4ca88867000000000000000000000000000000000000000000000000000000008152fd5b503461022c578060031936011261022c576001600160a01b038181606d541691604051926370a0823160e01b8452306004850152602084602481845afa93841561038a578394610553575b5083610433578280f35b6104438483600654168093612c96565b600554813b1561054f5783916084839260405194859384927fbdb78cf600000000000000000000000000000000000000000000000000000000845260048401528960248401528160448401528160648401525af190811561038a57839161053b575b5050606e5416803b15610537578180916024604051809481937f3c6b16ab0000000000000000000000000000000000000000000000000000000083528860048401525af1801561022f57610523575b5050337f169f1815ebdea059aac3bb00ec9a9594c7a5ffcb64a17e8392b5d84909a145568380a3388181808280f35b61052c90612807565b6105375781386104f4565b5080fd5b61054490612807565b6105375781386104a5565b8380fd5b925092506020823d8211610581575b8161056f6020938361281b565b8101031261037d578391519238610429565b3d9150610562565b503461022c576020908160031936011261022c576024826001600160a01b03606e5416604051928380927f63db9f3300000000000000000000000000000000000000000000000000000000825260043560048301525afa91821561062357916105f6575b50604051908152f35b90508181813d831161061c575b61060d818361281b565b8101031261037d5751386105ed565b503d610603565b604051903d90823e3d90fd5b503461022c578060031936011261022c5760206001600160a01b03603a5416604051908152f35b503461022c576106653661298a565b6001600160a01b0360049392935416926040518094630935e01b60e21b825233600483015281602460209788935afa908115610885578491610850575b50156103b45767ffffffffffffffff821161083c5760036106c3815461279b565b601f81116107d9575b508394601f841160011461073957508284957ff8d93f004695a3cf9e4bf9528a1ef00f79d7be817a072dd634fbb4969df73b64959161072e575b508360011b9060001985841b1c19161790555b61072860405192839283612a69565b0390a180f35b905082013538610706565b601f198416958286527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9186905b8882106107c1575050847ff8d93f004695a3cf9e4bf9528a1ef00f79d7be817a072dd634fbb4969df73b649697106107a9575b5050600183811b019055610719565b83013560001985841b60f8161c19169055388061079a565b80600184958294958901358155019401920190610767565b816000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f850160051c810191878610610832575b601f0160051c01905b81811061082657506106cc565b60008155600101610819565b9091508190610810565b602483634e487b7160e01b81526041600452fd5b90508481813d831161087e575b610867818361281b565b8101031261054f57610878906129d4565b386106a2565b503d61085d565b6040513d86823e3d90fd5b503461022c5761089f3661298a565b6001600160a01b0360049392935416926040518094630935e01b60e21b825233600483015281602460209788935afa908115610885578491610a0b575b50156103b45767ffffffffffffffff821161083c57600161090683610901835461279b565b6129f5565b8394601f841160011461096b57508284957f4df9dcd34ae35f40f2c756fd8ac83210ed0b76d065543ee73d868aec7c7fcf029591610960575b5083821b906000198560031b1c191617905561072860405192839283612a69565b90508201353861093f565b601f198416958286527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf69186905b8882106109f4575050847f4df9dcd34ae35f40f2c756fd8ac83210ed0b76d065543ee73d868aec7c7fcf029697106109da575b50508083811b019055610719565b60001960f88660031b161c199084013516905538806109cc565b808584958294958901358155019401920190610999565b90508481813d8311610a39575b610a22818361281b565b8101031261054f57610a33906129d4565b386108dc565b503d610a18565b503461022c57610a5b610a5236612929565b92919091612ad7565b80f35b503461022c578060031936011261022c576020600554604051908152f35b503461022c576020908160031936011261022c576024826001600160a01b03606e5416604051928380927f9cc7f70800000000000000000000000000000000000000000000000000000000825260043560048301525afa91821561062357916105f65750604051908152f35b503461022c57602060031936011261022c57610b02612886565b6001600160a01b039060246020836004541660405192838092630935e01b60e21b82523360048301525afa908115610885578491610ba2575b50156103b45780610b6c7fffffffffffffffffffffffff00000000000000000000000000000000000000009261338d565b82603a549116809382167feec2b704b009c3bc5d7081ef086e0adec146f30174f60e673fd67d3dafd04f9f8680a31617603a5580f35b90506020813d8211610bd3575b81610bbc6020938361281b565b8101031261054f57610bcd906129d4565b38610b3b565b3d9150610baf565b503461022c57610bea3661298a565b6001600160a01b0360049392935416926040518094630935e01b60e21b825233600483015281602460209788935afa908115610885578491610dc0575b50156103b45767ffffffffffffffff821161083c57610c4760025461279b565b601f8111610d5c575b508293601f8311600114610cb857508183947fab7dca68789bfbe74d09f14600944885d215fdf09987a0aba59a2df7185772419491610cad575b508260011b906000198460031b1c19161760025561072860405192839283612a69565b905081013538610c8a565b601f19831694600285527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace9185905b878210610d44575050837fab7dca68789bfbe74d09f14600944885d215fdf09987a0aba59a2df718577241959610610d2a575b5050600182811b01600255610719565b60001960f88560031b161c19908301351690553880610d1a565b80600184958294958801358155019401920190610ce7565b60026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f840160051c810191868510610db6575b601f0160051c01905b818110610daa5750610c50565b60008155600101610d9d565b9091508190610d94565b90508481813d8311610dee575b610dd7818361281b565b8101031261054f57610de8906129d4565b38610c27565b503d610dcd565b503461022c578060031936011261022c5760206001600160a01b03606d5416604051908152f35b503461022c57610e2b36612974565b906001600160a01b03806004541633036103b4578390606e5416803b15610537578180916044604051809481937fe2bbb1580000000000000000000000000000000000000000000000000000000083528860048401528960248401525af1801561022f57610ebc575b50807fa36e70cdd3b81bea60553f6a49ec7d0c6eb23957b4ae3dc09fc38fdb40b97d1891a380f35b610ec590612807565b610ed0578238610e94565b8280fd5b503461022c578060031936011261022c576040516000600254610ef68161279b565b80845290600190818116908115610f8b5750600114610f30575b610f2c84610f208186038261281b565b6040519182918261283e565b0390f35b6002600090815292507f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b828410610f73575050508101602001610f2082610f10565b80546020858701810191909152909301928101610f5b565b60ff191660208087019190915292151560051b85019092019250610f209150839050610f10565b503461022c57610fc136612929565b6001600160a01b03938460045416926005549460405180957f609c6d7f00000000000000000000000000000000000000000000000000000000825260209687918180611027338d600484019092916001600160a01b036020916040840195845216910152565b03915afa90811561112b5789916110f2575b50156103b45787966007541692833b156110ee5761108e91604051977f7ac09bf70000000000000000000000000000000000000000000000000000000089526004890152606060248901526064880191612a91565b6003198682030160448701528381527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84116110ea578694868095938793829560051b809285830137010301925af1801561022f5761021c5750f35b8680fd5b8780fd5b90508581813d8311611124575b611109818361281b565b810103126111205761111a906129d4565b38611039565b8880fd5b503d6110ff565b6040513d8b823e3d90fd5b503461022c57604060031936011261022c57610a5b611153612886565b61115b61289c565b90611164613253565b612fdf565b503461022c578060031936011261022c5760206001600160a01b0360045416604051908152f35b503461022c578060031936011261022c5760206001600160a01b0360065416604051908152f35b503461022c5760208060031936011261053757600435906001600160a01b03908160045416604051630935e01b60e21b81523360048201528281602481855afa9081156113e75786916113ae575b50156103b4576005546113845781602491604051928380927feefff5d50000000000000000000000000000000000000000000000000000000082528860048301525afa9081156103a957859161134b575b50159182156112bb575b505061129157806005557f5056c93c1f67487732c02e2eafb6df6fcbbea593801837931daa75ccfbb16f738280a280f35b60046040517f9618038f000000000000000000000000000000000000000000000000000000008152fd5b9091506024828260065416604051928380927f6352211e0000000000000000000000000000000000000000000000000000000082528860048301525afa9283156103a9578593611313575b5050163014153880611260565b9080929350813d8311611344575b61132b818361281b565b8101031261054f5761133c906129e1565b903880611306565b503d611321565b90508181813d831161137d575b611362818361281b565b8101031261137957611373906129d4565b38611256565b8480fd5b503d611358565b60046040517f3ca9d617000000000000000000000000000000000000000000000000000000008152fd5b90508281813d83116113e0575b6113c5818361281b565b810103126113dc576113d6906129d4565b38611205565b8580fd5b503d6113bb565b6040513d88823e3d90fd5b503461022c578060031936011261022c5760206001600160a01b0360075416604051908152f35b503461022c578060031936011261022c5760206040516127108152f35b503461022c578060031936011261022c5780f35b503461022c57608060031936011261022c5767ffffffffffffffff600435818111610ed05761147d9036906004016128f8565b602492919235828111611379576114989036906004016128f8565b6114a39491946128b2565b936064359081116110ea576114bc9036906004016128f8565b9590936114c7613253565b806114f9575b50505050835b8381106114de578480f35b806114f38461116460019460051b8601612fcb565b016114d3565b61150293612ad7565b388080806114cd565b503461022c578060031936011261022c5760206001600160a01b03606e5416604051908152f35b503461022c5760a060031936011261022c5761154c612886565b61155461289c565b9061155d6128b2565b916001600160a01b03606435166064350361054f576084359067ffffffffffffffff8211611379573660238301121561137957848260040135926115a0846128dc565b936115ae604051958661281b565b8085523660248284010111610ed05780602460209301838701378401015284549260ff8460081c161593848095611bb1575b8015611b9a575b15611b305784600160ff198316178855611b02575b506116068561338d565b61161660ff875460081c16612c25565b6001600160a01b03811615611ad8577343000000000000000000000000000000000000023b156113dc576040517fc8992e6100000000000000000000000000000000000000000000000000000000815260026004820152600160248201526001600160a01b03821660448201528681606481837343000000000000000000000000000000000000025af18015611a4a57611ac5575b508086913b611a55575b5050806116c96001600160a01b039261338d565b16907fffffffffffffffffffffffff000000000000000000000000000000000000000091808360045416176004556040517f4f2bfe5b000000000000000000000000000000000000000000000000000000008152602081600481855afa908115611a4a578791611a00575b506004916001600160a01b0360209216856006541617600655604051928380927f46c96aac0000000000000000000000000000000000000000000000000000000082525afa80156113e75786906119c0575b6001600160a01b0391501682600754161760075580519067ffffffffffffffff82116119ac5781906117bd8261090160015461279b565b602090601f831160011461192b578792611920575b50506000198260011b9260031b1c1916176001555b60048454936117fb60ff8660081c16612c25565b61180660643561338d565b6001600160a01b036064351683603a541617603a5560206001600160a01b0360065416604051938480927ffc0c546a0000000000000000000000000000000000000000000000000000000082525afa9182156113e75786926118dc575b506001600160a01b0380921683606d541617606d551690606e541617606e5561188a575080f35b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1681557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160018152a180f35b91506020823d602011611918575b816118f76020938361281b565b810103126113dc576001600160a01b0361191181936129e1565b9250611863565b3d91506118ea565b0151905038806117d2565b600188527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf692601f1916885b818110611994575090846001959493921061197b575b505050811b016001556117e7565b015160001960f88460031b161c1916905538808061196d565b92936020600181928786015181550195019301611957565b602486634e487b7160e01b81526041600452fd5b506020813d6020116119f8575b816119da6020938361281b565b810103126113dc576119f36001600160a01b03916129e1565b611786565b3d91506119cd565b90506020813d602011611a42575b81611a1b6020938361281b565b810103126110ea576004916001600160a01b03611a396020936129e1565b92505091611734565b3d9150611a0e565b6040513d89823e3d90fd5b6001600160a01b0381163b1561053757816001600160a01b036024829360405194859384927f2ab9d8b8000000000000000000000000000000000000000000000000000000008452306004850152165af1801561022f57156116b557611aba90612807565b6113795784386116b5565b611ad190969196612807565b94386116ab565b60046040517f9fabe1c1000000000000000000000000000000000000000000000000000000008152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016610101178655386115fc565b608460405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152fd5b50303b1580156115e75750600160ff8216146115e7565b50600160ff8216106115e0565b503461022c57608060031936011261022c57611bd8612886565b9067ffffffffffffffff6024351161022c5736602360243501121561022c5767ffffffffffffffff602435600401351161022c57366024606081356004013502813501011161022c57611c2a8261338d565b6001600160a01b03606d5416806001600160a01b03841614612565576101906044351161253b57611c59613253565b6040516370a0823160e01b81523060048201526020816024816001600160a01b0388165afa90811561038a578391612509575b5080156124df576001600160a01b03603a541690604051917f50e5a4930000000000000000000000000000000000000000000000000000000083526001600160a01b03861660048401528360248401528160448401528483606481845afa9283156103a95785936123e1575b50828590805161234c575b5060016024356004013511612092575b60443581028181046044351482151715611f525790612710611d3692049061340d565b908115612068576020600491604051928380927ff887ea400000000000000000000000000000000000000000000000000000000082525afa9081156113e757869161202e575b50611d9a836001600160a01b0383166001600160a01b038a16612c96565b604051916370a0823160e01b8352306004840152602083602481895afa928315611a4a579087918294611ff7575b506040519283917ff41766d8000000000000000000000000000000000000000000000000000000008352866004840152602483015260a0604483015281836001600160a01b0382611e1c60a482018c6133b5565b30606483015260643560848301520393165af19081156113e7578691611f66575b5080516000198101908111611f52578151811015611f3e579060209160051b010151946040516370a0823160e01b8152306004820152602081602481895afa918215610623578092611f07575b5050602096611ecc87611ec67f2fdc4fb55cf4ca2cb838e89de746ac8212d38db4f04cf984782c2b5ee7805cc2956001600160a01b039561340d565b146134aa565b611ed78715156134aa565b611eec604051956060875260608701906133b5565b938886015286604086015216928033930390a4604051908152f35b9091506020823d602011611f36575b81611f236020938361281b565b8101031261022c57505186611ecc611e8a565b3d9150611f16565b602487634e487b7160e01b81526032600452fd5b602487634e487b7160e01b81526011600452fd5b90503d8087833e611f77818361281b565b8101906020818303126110ea5780519067ffffffffffffffff82116110ee57019080601f830112156110ea578151611fae8161339d565b92611fbc604051948561281b565b81845260208085019260051b82010192831161112057602001905b828210611fe75750505038611e3d565b8151815260209182019101611fd7565b915092506020813d602011612026575b816120146020938361281b565b810103126110ea578690519238611dc8565b3d9150612007565b90506020813d602011612060575b816120496020938361281b565b810103126113dc5761205a906129e1565b38611d7c565b3d915061203c565b60046040517fb5c0f440000000000000000000000000000000000000000000000000000000008152fd5b6024356004013515612324576001600160a01b0387166001600160a01b036120bd6024803501612fcb565b16148015906122d2575b61226e576040517e2f69d100000000000000000000000000000000000000000000000000000000815260206004820152602081806121136024820160243560040135602480350161343d565b0381865afa908115611a4a578791612298575b501561226e576040517fd500234c000000000000000000000000000000000000000000000000000000008152836004820152604060248201526020818061217b6044820160243560040135602480350161343d565b0381865afa908115611a4a57879161223c575b5081811161219d575b50611d13565b9350506121af6024356004013561339d565b6121bc604051918261281b565b602480356004810135835201602082015b60246060813560040135028135010182106121eb5750509238612197565b6060823603126110ee576020606091604051612206816127d5565b61220f856128c8565b815261221c8386016128c8565b8382015261222c60408601613430565b60408201528152019101906121cd565b90506020813d602011612266575b816122576020938361281b565b810103126110ea57513861218e565b3d915061224a565b60046040517f2a122915000000000000000000000000000000000000000000000000000000008152fd5b90506020813d6020116122ca575b816122b36020938361281b565b810103126110ea576122c4906129d4565b38612126565b3d91506122a6565b506004602435013560001981011161233857600460243501356000198101101561232457846001600160a01b0361231c604460606000196024356004013501026024350101612fcb565b1614156120c7565b602486634e487b7160e01b81526032600452fd5b602486634e487b7160e01b81526011600452fd5b6123959150602090604051809381927fd500234c0000000000000000000000000000000000000000000000000000000083528760048401526040602484015260448301906133b5565b0381855afa9081156113e75786916123af575b5038611d03565b90506020813d6020116123d9575b816123ca6020938361281b565b810103126113dc5751386123a8565b3d91506123bd565b9092503d8086833e6123f3818361281b565b60408282810103126113dc5781519067ffffffffffffffff82116110ea57808301601f8385010112156110ea57818301519061242e8261339d565b9361243c604051958661281b565b82855260208501938282016020606086028385010101116124db57602081830101945b6020606086028385010101861061247d575050505050509138611cf8565b60608685850103126124d757906060806020809460405161249d816127d5565b6124a68b6129e1565b81526124b3838c016129e1565b838201526124c360408c016129d4565b60408201528152019701969192505061245f565b8a80fd5b8980fd5b60046040517f669567ea000000000000000000000000000000000000000000000000000000008152fd5b90506020813d602011612533575b816125246020938361281b565b81010312610ed0575138611c8c565b3d9150612517565b60046040517f79bbc814000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6713c37e000000000000000000000000000000000000000000000000000000008152fd5b503461022c578060031936011261022c57600460206001600160a01b03606e5416604051928380927f18160ddd0000000000000000000000000000000000000000000000000000000082525afa90811561022f5782916125f5575b602082604051908152f35b90506020813d8211612622575b8161260f6020938361281b565b81010312610537576020915051386125ea565b3d9150612602565b503461022c578060031936011261022c576040519080600180549161264e8361279b565b808652928281169081156126cf5750600114612675575b610f2c85610f208187038261281b565b92508083527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8284106126b7575050508101602001610f2082610f2c612665565b8054602085870181019190915290930192810161269c565b869550610f2c96935060209250610f2094915060ff191682840152151560051b8201019293612665565b823461022c578060031936011261022c57806003546127178161279b565b808552916001918083169081156126cf575060011461274057610f2c85610f208187038261281b565b9250600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b828410612783575050508101602001610f2082610f2c612665565b80546020858701810191909152909301928101612768565b90600182811c921680156127cb575b60208310146127b557565b634e487b7160e01b600052602260045260246000fd5b91607f16916127aa565b6060810190811067ffffffffffffffff8211176127f157604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff81116127f157604052565b90601f601f19910116810190811067ffffffffffffffff8211176127f157604052565b60208082528251818301819052939260005b85811061287257505050601f19601f8460006040809697860101520116010190565b818101830151848201604001528201612850565b600435906001600160a01b038216820361037d57565b602435906001600160a01b038216820361037d57565b604435906001600160a01b038216820361037d57565b35906001600160a01b038216820361037d57565b67ffffffffffffffff81116127f157601f01601f191660200190565b9181601f8401121561037d5782359167ffffffffffffffff831161037d576020808501948460051b01011161037d57565b604060031982011261037d5767ffffffffffffffff9160043583811161037d5782612956916004016128f8565b9390939260243591821161037d57612970916004016128f8565b9091565b600319604091011261037d576004359060243590565b90602060031983011261037d5760043567ffffffffffffffff9283821161037d578060238301121561037d57816004013593841161037d576024848301011161037d576024019190565b5190811515820361037d57565b51906001600160a01b038216820361037d57565b90601f8211612a02575050565b6001916000908382527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f850160051c83019410612a5f575b601f0160051c01915b828110612a555750505050565b8181558301612a48565b9092508290612a3f565b90601f83604094601f1993602086528160208701528686013760008582860101520116010190565b91908082526020809201929160005b828110612aae575050505090565b9091929382806001926001600160a01b03612ac8896128c8565b16815201950193929101612aa0565b929190926001600160a01b0360075416926005805492853b1561037d579593909291612b366040519788967f7715ee75000000000000000000000000000000000000000000000000000000008852606060048901526064880191612a91565b600319868203016024870152818152602090818101958284821b83010196856000935b868510612b9d5750505050505050506000838195938193604483015203925af18015612b9157612b865750565b612b8f90612807565b565b6040513d6000823e3d90fd5b9193959798909294969950601f1982820301845289357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181121561037d57830187810191903567ffffffffffffffff811161037d5780871b3603831361037d57612c1089928392600195612a91565b9b0194019501929593918b9998979591612b59565b15612c2c57565b608460405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152fd5b91909181158015612d6c575b15612d02576040517f095ea7b30000000000000000000000000000000000000000000000000000000060208201526001600160a01b03939093166024840152604480840192909252908252612b8f9190612cfd60648361281b565b612dfa565b608460405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152fd5b506040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526020816044816001600160a01b03808916602483015286165afa908115612b9157600091612dc9575b5015612ca2565b906020823d8211612df2575b81612de26020938361281b565b8101031261022c57505138612dc2565b3d9150612dd5565b6001600160a01b031690604051604081019080821067ffffffffffffffff8311176127f157612e8b916040526020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af13d15612f33573d91612e70836128dc565b92612e7e604051948561281b565b83523d868885013e612f37565b90815190838215928315612f11575b505050905015612ea75750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b84809293945001031261022c575081612f2a91016129d4565b80388381612e9a565b6060915b91929015612f985750815115612f4b575090565b3b15612f545790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b825190915015612fab5750805190602001fd5b612fc79060405191829162461bcd60e51b83526004830161283e565b0390fd5b356001600160a01b038116810361037d5790565b6001600160a01b0391826004541691604090815180947fe74a37be00000000000000000000000000000000000000000000000000000000825230600483015281602460209788935afa90811561313b5790869291600091613214575b5060011615613146575b16938151926370a0823160e01b84523060048501528484602481895afa93841561313b5760009461310c575b5083613080575b505050505050565b82517fa9059cbb00000000000000000000000000000000000000000000000000000000868201526001600160a01b0382166024820152604480820186905281527f7ef226ba1a7b86b80b5b20bf503393a13fb72ae957fbf3235cdf02e60c3f295493906130f8906130f260648261281b565b88612dfa565b5193845216923392a4388080808080613078565b90938582813d8311613134575b613123818361281b565b8101031261022c5750519238613071565b503d613119565b83513d6000823e3d90fd5b90606d541685821690811490811561318e575b50613165578490613045565b600482517fb2b1d41a000000000000000000000000000000000000000000000000000000008152fd5b90508486603a54169160248551809481937f2404469100000000000000000000000000000000000000000000000000000000835260048301525afa90811561313b576000916131df575b5038613159565b908582813d831161320d575b6131f5818361281b565b8101031261022c5750613207906129d4565b386131d8565b503d6131eb565b909192508581813d831161324c575b61322d818361281b565b8101031261053757519060ff8216820361022c5750859190600161303b565b503d613223565b6001600160a01b036004541660405190630935e01b60e21b82523360048301526020908183602481845afa928315612b9157600093613356575b5082156132c5575b5050612b8f5760046040517f4ca88867000000000000000000000000000000000000000000000000000000008152fd5b6005546040517f609c6d7f000000000000000000000000000000000000000000000000000000008152600481019190915233602482015292508190839060449082905afa908115612b9157600091613322575b5090503880613295565b82813d831161334f575b613336818361281b565b8101031261022c5750613348906129d4565b8038613318565b503d61332c565b90928282813d8311613386575b61336d818361281b565b8101031261022c575061337f906129d4565b913861328d565b503d613363565b6001600160a01b031615611ad857565b67ffffffffffffffff81116127f15760051b60200190565b90815180825260208080930193019160005b8281106133d5575050505090565b835180516001600160a01b039081168752818401511686840152604090810151151590860152606090940193928101926001016133c7565b9190820391821161341a57565b634e487b7160e01b600052601160045260246000fd5b3590811515820361037d57565b9190808252602080920192916000905b82821061345b575050505090565b909192936001906001600160a01b0380613474886128c8565b1682526134828488016128c8565b16838201526040613494818801613430565b151590820152606090810195019392019061344d565b156134b157565b634e487b7160e01b600052600160045260246000fdfea164736f6c6343000813000a00000000000000000000000072e47b1eaaaac6c07ea4071f1d0d355f603e1cc1
Deployed Bytecode
0x608080604052600436101561001357600080fd5b600090813560e01c90816302d05d3f146126f95750806306fdde031461262a57806318160ddd1461258f5780631f23baf014610df557806321e8adc114611bbe5780632fb3b36114611532578063363b28161461150b57806336f0a8131461144a5780633bb2fad914611436578063453943f01461141957806346c96aac146113f25780634b985845146111b75780634f2bfe5b14611190578063537f95ff1461116957806358b06db9146111365780636f816a2014610fb25780637284e41614610ed45780637f36b27614610e1c578063801512e414610df557806390c3f38f14610bdb5780639b7fcc1d14610ae85780639cc7f70814610a7c578063b0dfa49814610a5e578063c2b79e9814610a40578063c47f002714610890578063e5c02d0714610656578063ecb0a2651461062f578063ed4ec0c214610589578063f69e2046146103de578063f83a20681461025f578063f9759518146102425763f9f031df1461018157600080fd5b3461022c57602060031936011261022c578060043567ffffffffffffffff811161023f576101b39036906004016128f8565b6001600160a01b036007541691823b1561023a5761020b928492836040518096819582947ff9f031df000000000000000000000000000000000000000000000000000000008452602060048501526024840191612a91565b03925af1801561022f5761021c5750f35b61022590612807565b61022c5780f35b80fd5b6040513d84823e3d90fd5b505050fd5b50fd5b503461022c578060031936011261022c5760206040516101908152f35b503461022c5761026e36612974565b6001600160a01b0391826004541633036103b4578392606e5416803b1561023a576040517f441a3e70000000000000000000000000000000000000000000000000000000008152826004820152836024820152848160448183865af19081156103a9578591610395575b50506020906024604051809781937fddc632620000000000000000000000000000000000000000000000000000000083528660048401525af193841561038a578394610351575b509280916020947f976d41f146303c848c29c530312f8a84501dc7eb4e78716492ecde07de6b48166040519580a48152f35b93506020843d8211610382575b8161036b6020938361281b565b8101031261037d57602093519361031f565b600080fd5b3d915061035e565b6040513d85823e3d90fd5b61039e90612807565b61023a5783386102d8565b6040513d87823e3d90fd5b60046040517f4ca88867000000000000000000000000000000000000000000000000000000008152fd5b503461022c578060031936011261022c576001600160a01b038181606d541691604051926370a0823160e01b8452306004850152602084602481845afa93841561038a578394610553575b5083610433578280f35b6104438483600654168093612c96565b600554813b1561054f5783916084839260405194859384927fbdb78cf600000000000000000000000000000000000000000000000000000000845260048401528960248401528160448401528160648401525af190811561038a57839161053b575b5050606e5416803b15610537578180916024604051809481937f3c6b16ab0000000000000000000000000000000000000000000000000000000083528860048401525af1801561022f57610523575b5050337f169f1815ebdea059aac3bb00ec9a9594c7a5ffcb64a17e8392b5d84909a145568380a3388181808280f35b61052c90612807565b6105375781386104f4565b5080fd5b61054490612807565b6105375781386104a5565b8380fd5b925092506020823d8211610581575b8161056f6020938361281b565b8101031261037d578391519238610429565b3d9150610562565b503461022c576020908160031936011261022c576024826001600160a01b03606e5416604051928380927f63db9f3300000000000000000000000000000000000000000000000000000000825260043560048301525afa91821561062357916105f6575b50604051908152f35b90508181813d831161061c575b61060d818361281b565b8101031261037d5751386105ed565b503d610603565b604051903d90823e3d90fd5b503461022c578060031936011261022c5760206001600160a01b03603a5416604051908152f35b503461022c576106653661298a565b6001600160a01b0360049392935416926040518094630935e01b60e21b825233600483015281602460209788935afa908115610885578491610850575b50156103b45767ffffffffffffffff821161083c5760036106c3815461279b565b601f81116107d9575b508394601f841160011461073957508284957ff8d93f004695a3cf9e4bf9528a1ef00f79d7be817a072dd634fbb4969df73b64959161072e575b508360011b9060001985841b1c19161790555b61072860405192839283612a69565b0390a180f35b905082013538610706565b601f198416958286527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9186905b8882106107c1575050847ff8d93f004695a3cf9e4bf9528a1ef00f79d7be817a072dd634fbb4969df73b649697106107a9575b5050600183811b019055610719565b83013560001985841b60f8161c19169055388061079a565b80600184958294958901358155019401920190610767565b816000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f850160051c810191878610610832575b601f0160051c01905b81811061082657506106cc565b60008155600101610819565b9091508190610810565b602483634e487b7160e01b81526041600452fd5b90508481813d831161087e575b610867818361281b565b8101031261054f57610878906129d4565b386106a2565b503d61085d565b6040513d86823e3d90fd5b503461022c5761089f3661298a565b6001600160a01b0360049392935416926040518094630935e01b60e21b825233600483015281602460209788935afa908115610885578491610a0b575b50156103b45767ffffffffffffffff821161083c57600161090683610901835461279b565b6129f5565b8394601f841160011461096b57508284957f4df9dcd34ae35f40f2c756fd8ac83210ed0b76d065543ee73d868aec7c7fcf029591610960575b5083821b906000198560031b1c191617905561072860405192839283612a69565b90508201353861093f565b601f198416958286527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf69186905b8882106109f4575050847f4df9dcd34ae35f40f2c756fd8ac83210ed0b76d065543ee73d868aec7c7fcf029697106109da575b50508083811b019055610719565b60001960f88660031b161c199084013516905538806109cc565b808584958294958901358155019401920190610999565b90508481813d8311610a39575b610a22818361281b565b8101031261054f57610a33906129d4565b386108dc565b503d610a18565b503461022c57610a5b610a5236612929565b92919091612ad7565b80f35b503461022c578060031936011261022c576020600554604051908152f35b503461022c576020908160031936011261022c576024826001600160a01b03606e5416604051928380927f9cc7f70800000000000000000000000000000000000000000000000000000000825260043560048301525afa91821561062357916105f65750604051908152f35b503461022c57602060031936011261022c57610b02612886565b6001600160a01b039060246020836004541660405192838092630935e01b60e21b82523360048301525afa908115610885578491610ba2575b50156103b45780610b6c7fffffffffffffffffffffffff00000000000000000000000000000000000000009261338d565b82603a549116809382167feec2b704b009c3bc5d7081ef086e0adec146f30174f60e673fd67d3dafd04f9f8680a31617603a5580f35b90506020813d8211610bd3575b81610bbc6020938361281b565b8101031261054f57610bcd906129d4565b38610b3b565b3d9150610baf565b503461022c57610bea3661298a565b6001600160a01b0360049392935416926040518094630935e01b60e21b825233600483015281602460209788935afa908115610885578491610dc0575b50156103b45767ffffffffffffffff821161083c57610c4760025461279b565b601f8111610d5c575b508293601f8311600114610cb857508183947fab7dca68789bfbe74d09f14600944885d215fdf09987a0aba59a2df7185772419491610cad575b508260011b906000198460031b1c19161760025561072860405192839283612a69565b905081013538610c8a565b601f19831694600285527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace9185905b878210610d44575050837fab7dca68789bfbe74d09f14600944885d215fdf09987a0aba59a2df718577241959610610d2a575b5050600182811b01600255610719565b60001960f88560031b161c19908301351690553880610d1a565b80600184958294958801358155019401920190610ce7565b60026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f840160051c810191868510610db6575b601f0160051c01905b818110610daa5750610c50565b60008155600101610d9d565b9091508190610d94565b90508481813d8311610dee575b610dd7818361281b565b8101031261054f57610de8906129d4565b38610c27565b503d610dcd565b503461022c578060031936011261022c5760206001600160a01b03606d5416604051908152f35b503461022c57610e2b36612974565b906001600160a01b03806004541633036103b4578390606e5416803b15610537578180916044604051809481937fe2bbb1580000000000000000000000000000000000000000000000000000000083528860048401528960248401525af1801561022f57610ebc575b50807fa36e70cdd3b81bea60553f6a49ec7d0c6eb23957b4ae3dc09fc38fdb40b97d1891a380f35b610ec590612807565b610ed0578238610e94565b8280fd5b503461022c578060031936011261022c576040516000600254610ef68161279b565b80845290600190818116908115610f8b5750600114610f30575b610f2c84610f208186038261281b565b6040519182918261283e565b0390f35b6002600090815292507f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b828410610f73575050508101602001610f2082610f10565b80546020858701810191909152909301928101610f5b565b60ff191660208087019190915292151560051b85019092019250610f209150839050610f10565b503461022c57610fc136612929565b6001600160a01b03938460045416926005549460405180957f609c6d7f00000000000000000000000000000000000000000000000000000000825260209687918180611027338d600484019092916001600160a01b036020916040840195845216910152565b03915afa90811561112b5789916110f2575b50156103b45787966007541692833b156110ee5761108e91604051977f7ac09bf70000000000000000000000000000000000000000000000000000000089526004890152606060248901526064880191612a91565b6003198682030160448701528381527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84116110ea578694868095938793829560051b809285830137010301925af1801561022f5761021c5750f35b8680fd5b8780fd5b90508581813d8311611124575b611109818361281b565b810103126111205761111a906129d4565b38611039565b8880fd5b503d6110ff565b6040513d8b823e3d90fd5b503461022c57604060031936011261022c57610a5b611153612886565b61115b61289c565b90611164613253565b612fdf565b503461022c578060031936011261022c5760206001600160a01b0360045416604051908152f35b503461022c578060031936011261022c5760206001600160a01b0360065416604051908152f35b503461022c5760208060031936011261053757600435906001600160a01b03908160045416604051630935e01b60e21b81523360048201528281602481855afa9081156113e75786916113ae575b50156103b4576005546113845781602491604051928380927feefff5d50000000000000000000000000000000000000000000000000000000082528860048301525afa9081156103a957859161134b575b50159182156112bb575b505061129157806005557f5056c93c1f67487732c02e2eafb6df6fcbbea593801837931daa75ccfbb16f738280a280f35b60046040517f9618038f000000000000000000000000000000000000000000000000000000008152fd5b9091506024828260065416604051928380927f6352211e0000000000000000000000000000000000000000000000000000000082528860048301525afa9283156103a9578593611313575b5050163014153880611260565b9080929350813d8311611344575b61132b818361281b565b8101031261054f5761133c906129e1565b903880611306565b503d611321565b90508181813d831161137d575b611362818361281b565b8101031261137957611373906129d4565b38611256565b8480fd5b503d611358565b60046040517f3ca9d617000000000000000000000000000000000000000000000000000000008152fd5b90508281813d83116113e0575b6113c5818361281b565b810103126113dc576113d6906129d4565b38611205565b8580fd5b503d6113bb565b6040513d88823e3d90fd5b503461022c578060031936011261022c5760206001600160a01b0360075416604051908152f35b503461022c578060031936011261022c5760206040516127108152f35b503461022c578060031936011261022c5780f35b503461022c57608060031936011261022c5767ffffffffffffffff600435818111610ed05761147d9036906004016128f8565b602492919235828111611379576114989036906004016128f8565b6114a39491946128b2565b936064359081116110ea576114bc9036906004016128f8565b9590936114c7613253565b806114f9575b50505050835b8381106114de578480f35b806114f38461116460019460051b8601612fcb565b016114d3565b61150293612ad7565b388080806114cd565b503461022c578060031936011261022c5760206001600160a01b03606e5416604051908152f35b503461022c5760a060031936011261022c5761154c612886565b61155461289c565b9061155d6128b2565b916001600160a01b03606435166064350361054f576084359067ffffffffffffffff8211611379573660238301121561137957848260040135926115a0846128dc565b936115ae604051958661281b565b8085523660248284010111610ed05780602460209301838701378401015284549260ff8460081c161593848095611bb1575b8015611b9a575b15611b305784600160ff198316178855611b02575b506116068561338d565b61161660ff875460081c16612c25565b6001600160a01b03811615611ad8577343000000000000000000000000000000000000023b156113dc576040517fc8992e6100000000000000000000000000000000000000000000000000000000815260026004820152600160248201526001600160a01b03821660448201528681606481837343000000000000000000000000000000000000025af18015611a4a57611ac5575b508086913b611a55575b5050806116c96001600160a01b039261338d565b16907fffffffffffffffffffffffff000000000000000000000000000000000000000091808360045416176004556040517f4f2bfe5b000000000000000000000000000000000000000000000000000000008152602081600481855afa908115611a4a578791611a00575b506004916001600160a01b0360209216856006541617600655604051928380927f46c96aac0000000000000000000000000000000000000000000000000000000082525afa80156113e75786906119c0575b6001600160a01b0391501682600754161760075580519067ffffffffffffffff82116119ac5781906117bd8261090160015461279b565b602090601f831160011461192b578792611920575b50506000198260011b9260031b1c1916176001555b60048454936117fb60ff8660081c16612c25565b61180660643561338d565b6001600160a01b036064351683603a541617603a5560206001600160a01b0360065416604051938480927ffc0c546a0000000000000000000000000000000000000000000000000000000082525afa9182156113e75786926118dc575b506001600160a01b0380921683606d541617606d551690606e541617606e5561188a575080f35b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1681557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160018152a180f35b91506020823d602011611918575b816118f76020938361281b565b810103126113dc576001600160a01b0361191181936129e1565b9250611863565b3d91506118ea565b0151905038806117d2565b600188527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf692601f1916885b818110611994575090846001959493921061197b575b505050811b016001556117e7565b015160001960f88460031b161c1916905538808061196d565b92936020600181928786015181550195019301611957565b602486634e487b7160e01b81526041600452fd5b506020813d6020116119f8575b816119da6020938361281b565b810103126113dc576119f36001600160a01b03916129e1565b611786565b3d91506119cd565b90506020813d602011611a42575b81611a1b6020938361281b565b810103126110ea576004916001600160a01b03611a396020936129e1565b92505091611734565b3d9150611a0e565b6040513d89823e3d90fd5b6001600160a01b0381163b1561053757816001600160a01b036024829360405194859384927f2ab9d8b8000000000000000000000000000000000000000000000000000000008452306004850152165af1801561022f57156116b557611aba90612807565b6113795784386116b5565b611ad190969196612807565b94386116ab565b60046040517f9fabe1c1000000000000000000000000000000000000000000000000000000008152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016610101178655386115fc565b608460405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152fd5b50303b1580156115e75750600160ff8216146115e7565b50600160ff8216106115e0565b503461022c57608060031936011261022c57611bd8612886565b9067ffffffffffffffff6024351161022c5736602360243501121561022c5767ffffffffffffffff602435600401351161022c57366024606081356004013502813501011161022c57611c2a8261338d565b6001600160a01b03606d5416806001600160a01b03841614612565576101906044351161253b57611c59613253565b6040516370a0823160e01b81523060048201526020816024816001600160a01b0388165afa90811561038a578391612509575b5080156124df576001600160a01b03603a541690604051917f50e5a4930000000000000000000000000000000000000000000000000000000083526001600160a01b03861660048401528360248401528160448401528483606481845afa9283156103a95785936123e1575b50828590805161234c575b5060016024356004013511612092575b60443581028181046044351482151715611f525790612710611d3692049061340d565b908115612068576020600491604051928380927ff887ea400000000000000000000000000000000000000000000000000000000082525afa9081156113e757869161202e575b50611d9a836001600160a01b0383166001600160a01b038a16612c96565b604051916370a0823160e01b8352306004840152602083602481895afa928315611a4a579087918294611ff7575b506040519283917ff41766d8000000000000000000000000000000000000000000000000000000008352866004840152602483015260a0604483015281836001600160a01b0382611e1c60a482018c6133b5565b30606483015260643560848301520393165af19081156113e7578691611f66575b5080516000198101908111611f52578151811015611f3e579060209160051b010151946040516370a0823160e01b8152306004820152602081602481895afa918215610623578092611f07575b5050602096611ecc87611ec67f2fdc4fb55cf4ca2cb838e89de746ac8212d38db4f04cf984782c2b5ee7805cc2956001600160a01b039561340d565b146134aa565b611ed78715156134aa565b611eec604051956060875260608701906133b5565b938886015286604086015216928033930390a4604051908152f35b9091506020823d602011611f36575b81611f236020938361281b565b8101031261022c57505186611ecc611e8a565b3d9150611f16565b602487634e487b7160e01b81526032600452fd5b602487634e487b7160e01b81526011600452fd5b90503d8087833e611f77818361281b565b8101906020818303126110ea5780519067ffffffffffffffff82116110ee57019080601f830112156110ea578151611fae8161339d565b92611fbc604051948561281b565b81845260208085019260051b82010192831161112057602001905b828210611fe75750505038611e3d565b8151815260209182019101611fd7565b915092506020813d602011612026575b816120146020938361281b565b810103126110ea578690519238611dc8565b3d9150612007565b90506020813d602011612060575b816120496020938361281b565b810103126113dc5761205a906129e1565b38611d7c565b3d915061203c565b60046040517fb5c0f440000000000000000000000000000000000000000000000000000000008152fd5b6024356004013515612324576001600160a01b0387166001600160a01b036120bd6024803501612fcb565b16148015906122d2575b61226e576040517e2f69d100000000000000000000000000000000000000000000000000000000815260206004820152602081806121136024820160243560040135602480350161343d565b0381865afa908115611a4a578791612298575b501561226e576040517fd500234c000000000000000000000000000000000000000000000000000000008152836004820152604060248201526020818061217b6044820160243560040135602480350161343d565b0381865afa908115611a4a57879161223c575b5081811161219d575b50611d13565b9350506121af6024356004013561339d565b6121bc604051918261281b565b602480356004810135835201602082015b60246060813560040135028135010182106121eb5750509238612197565b6060823603126110ee576020606091604051612206816127d5565b61220f856128c8565b815261221c8386016128c8565b8382015261222c60408601613430565b60408201528152019101906121cd565b90506020813d602011612266575b816122576020938361281b565b810103126110ea57513861218e565b3d915061224a565b60046040517f2a122915000000000000000000000000000000000000000000000000000000008152fd5b90506020813d6020116122ca575b816122b36020938361281b565b810103126110ea576122c4906129d4565b38612126565b3d91506122a6565b506004602435013560001981011161233857600460243501356000198101101561232457846001600160a01b0361231c604460606000196024356004013501026024350101612fcb565b1614156120c7565b602486634e487b7160e01b81526032600452fd5b602486634e487b7160e01b81526011600452fd5b6123959150602090604051809381927fd500234c0000000000000000000000000000000000000000000000000000000083528760048401526040602484015260448301906133b5565b0381855afa9081156113e75786916123af575b5038611d03565b90506020813d6020116123d9575b816123ca6020938361281b565b810103126113dc5751386123a8565b3d91506123bd565b9092503d8086833e6123f3818361281b565b60408282810103126113dc5781519067ffffffffffffffff82116110ea57808301601f8385010112156110ea57818301519061242e8261339d565b9361243c604051958661281b565b82855260208501938282016020606086028385010101116124db57602081830101945b6020606086028385010101861061247d575050505050509138611cf8565b60608685850103126124d757906060806020809460405161249d816127d5565b6124a68b6129e1565b81526124b3838c016129e1565b838201526124c360408c016129d4565b60408201528152019701969192505061245f565b8a80fd5b8980fd5b60046040517f669567ea000000000000000000000000000000000000000000000000000000008152fd5b90506020813d602011612533575b816125246020938361281b565b81010312610ed0575138611c8c565b3d9150612517565b60046040517f79bbc814000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6713c37e000000000000000000000000000000000000000000000000000000008152fd5b503461022c578060031936011261022c57600460206001600160a01b03606e5416604051928380927f18160ddd0000000000000000000000000000000000000000000000000000000082525afa90811561022f5782916125f5575b602082604051908152f35b90506020813d8211612622575b8161260f6020938361281b565b81010312610537576020915051386125ea565b3d9150612602565b503461022c578060031936011261022c576040519080600180549161264e8361279b565b808652928281169081156126cf5750600114612675575b610f2c85610f208187038261281b565b92508083527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8284106126b7575050508101602001610f2082610f2c612665565b8054602085870181019190915290930192810161269c565b869550610f2c96935060209250610f2094915060ff191682840152151560051b8201019293612665565b823461022c578060031936011261022c57806003546127178161279b565b808552916001918083169081156126cf575060011461274057610f2c85610f208187038261281b565b9250600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b828410612783575050508101602001610f2082610f2c612665565b80546020858701810191909152909301928101612768565b90600182811c921680156127cb575b60208310146127b557565b634e487b7160e01b600052602260045260246000fd5b91607f16916127aa565b6060810190811067ffffffffffffffff8211176127f157604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff81116127f157604052565b90601f601f19910116810190811067ffffffffffffffff8211176127f157604052565b60208082528251818301819052939260005b85811061287257505050601f19601f8460006040809697860101520116010190565b818101830151848201604001528201612850565b600435906001600160a01b038216820361037d57565b602435906001600160a01b038216820361037d57565b604435906001600160a01b038216820361037d57565b35906001600160a01b038216820361037d57565b67ffffffffffffffff81116127f157601f01601f191660200190565b9181601f8401121561037d5782359167ffffffffffffffff831161037d576020808501948460051b01011161037d57565b604060031982011261037d5767ffffffffffffffff9160043583811161037d5782612956916004016128f8565b9390939260243591821161037d57612970916004016128f8565b9091565b600319604091011261037d576004359060243590565b90602060031983011261037d5760043567ffffffffffffffff9283821161037d578060238301121561037d57816004013593841161037d576024848301011161037d576024019190565b5190811515820361037d57565b51906001600160a01b038216820361037d57565b90601f8211612a02575050565b6001916000908382527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f850160051c83019410612a5f575b601f0160051c01915b828110612a555750505050565b8181558301612a48565b9092508290612a3f565b90601f83604094601f1993602086528160208701528686013760008582860101520116010190565b91908082526020809201929160005b828110612aae575050505090565b9091929382806001926001600160a01b03612ac8896128c8565b16815201950193929101612aa0565b929190926001600160a01b0360075416926005805492853b1561037d579593909291612b366040519788967f7715ee75000000000000000000000000000000000000000000000000000000008852606060048901526064880191612a91565b600319868203016024870152818152602090818101958284821b83010196856000935b868510612b9d5750505050505050506000838195938193604483015203925af18015612b9157612b865750565b612b8f90612807565b565b6040513d6000823e3d90fd5b9193959798909294969950601f1982820301845289357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181121561037d57830187810191903567ffffffffffffffff811161037d5780871b3603831361037d57612c1089928392600195612a91565b9b0194019501929593918b9998979591612b59565b15612c2c57565b608460405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152fd5b91909181158015612d6c575b15612d02576040517f095ea7b30000000000000000000000000000000000000000000000000000000060208201526001600160a01b03939093166024840152604480840192909252908252612b8f9190612cfd60648361281b565b612dfa565b608460405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152fd5b506040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526020816044816001600160a01b03808916602483015286165afa908115612b9157600091612dc9575b5015612ca2565b906020823d8211612df2575b81612de26020938361281b565b8101031261022c57505138612dc2565b3d9150612dd5565b6001600160a01b031690604051604081019080821067ffffffffffffffff8311176127f157612e8b916040526020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af13d15612f33573d91612e70836128dc565b92612e7e604051948561281b565b83523d868885013e612f37565b90815190838215928315612f11575b505050905015612ea75750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b84809293945001031261022c575081612f2a91016129d4565b80388381612e9a565b6060915b91929015612f985750815115612f4b575090565b3b15612f545790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b825190915015612fab5750805190602001fd5b612fc79060405191829162461bcd60e51b83526004830161283e565b0390fd5b356001600160a01b038116810361037d5790565b6001600160a01b0391826004541691604090815180947fe74a37be00000000000000000000000000000000000000000000000000000000825230600483015281602460209788935afa90811561313b5790869291600091613214575b5060011615613146575b16938151926370a0823160e01b84523060048501528484602481895afa93841561313b5760009461310c575b5083613080575b505050505050565b82517fa9059cbb00000000000000000000000000000000000000000000000000000000868201526001600160a01b0382166024820152604480820186905281527f7ef226ba1a7b86b80b5b20bf503393a13fb72ae957fbf3235cdf02e60c3f295493906130f8906130f260648261281b565b88612dfa565b5193845216923392a4388080808080613078565b90938582813d8311613134575b613123818361281b565b8101031261022c5750519238613071565b503d613119565b83513d6000823e3d90fd5b90606d541685821690811490811561318e575b50613165578490613045565b600482517fb2b1d41a000000000000000000000000000000000000000000000000000000008152fd5b90508486603a54169160248551809481937f2404469100000000000000000000000000000000000000000000000000000000835260048301525afa90811561313b576000916131df575b5038613159565b908582813d831161320d575b6131f5818361281b565b8101031261022c5750613207906129d4565b386131d8565b503d6131eb565b909192508581813d831161324c575b61322d818361281b565b8101031261053757519060ff8216820361022c5750859190600161303b565b503d613223565b6001600160a01b036004541660405190630935e01b60e21b82523360048301526020908183602481845afa928315612b9157600093613356575b5082156132c5575b5050612b8f5760046040517f4ca88867000000000000000000000000000000000000000000000000000000008152fd5b6005546040517f609c6d7f000000000000000000000000000000000000000000000000000000008152600481019190915233602482015292508190839060449082905afa908115612b9157600091613322575b5090503880613295565b82813d831161334f575b613336818361281b565b8101031261022c5750613348906129d4565b8038613318565b503d61332c565b90928282813d8311613386575b61336d818361281b565b8101031261022c575061337f906129d4565b913861328d565b503d613363565b6001600160a01b031615611ad857565b67ffffffffffffffff81116127f15760051b60200190565b90815180825260208080930193019160005b8281106133d5575050505090565b835180516001600160a01b039081168752818401511686840152604090810151151590860152606090940193928101926001016133c7565b9190820391821161341a57565b634e487b7160e01b600052601160045260246000fd5b3590811515820361037d57565b9190808252602080920192916000905b82821061345b575050505090565b909192936001906001600160a01b0380613474886128c8565b1682526134828488016128c8565b16838201526040613494818801613430565b151590820152606090810195019392019061344d565b156134b157565b634e487b7160e01b600052600160045260246000fdfea164736f6c6343000813000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000072e47b1eaaaac6c07ea4071f1d0d355f603e1cc1
-----Decoded View---------------
Arg [0] : blastGovernor_ (address): 0x72e47b1eaAAaC6c07Ea4071f1d0d355f603E1cc1
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000072e47b1eaaaac6c07ea4071f1d0d355f603e1cc1
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.