Source Code
Overview
CELO Balance
CELO Value
$0.00Multichain Info
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Manager
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;
import { RewardsDistributor } from "src/base/RewardsDistributor.sol";
import { BasicManager } from "src/base/BasicManager.sol";
import { Errors } from "src/libraries/Errors.sol";
import { IRouter } from "src/interfaces/IRouter.sol";
import { INonfungiblePositionManager } from "src/interfaces/INonfungiblePositionManager.sol";
import { IVoter } from "src/interfaces/IVoter.sol";
import { IVotingEscrow } from "src/interfaces/IVotingEscrow.sol";
import { IRewardsDistributor } from "src/interfaces/IRewardsDistributor.sol";
contract Manager is BasicManager {
/// @dev Special function to receive ETH
receive() external payable { }
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @notice Initializes the contract
*/
function initialize(address _treasury, address _router, address _nonfungiblePositionManager) public initializer {
__Ownable_init(msg.sender);
__UUPSUpgradeable_init();
require(_treasury != address(0), Errors.ZeroAddress());
treasury = _treasury;
router = IRouter(_router);
NonfungiblePositionManager = INonfungiblePositionManager(_nonfungiblePositionManager);
emit RouterSet(_router);
emit NonfungiblePositionManagerSet(_nonfungiblePositionManager);
emit TreasurySet(_treasury);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;
import { BasicManager } from "src/base/BasicManager.sol";
import { VoterManager } from "src/base/VoterManager.sol";
import { Errors } from "src/libraries/Errors.sol";
import { IRewardsDistributor } from "src/interfaces/IRewardsDistributor.sol";
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { IMinter } from "src/interfaces/IMinter.sol";
abstract contract RewardsDistributor is BasicManager, VoterManager {
/**
* @notice The address of the rewards distributor
*/
IRewardsDistributor public rewardsDistributor;
/**
* @notice The address of the minter
*/
IMinter public minter;
/**
* @notice Emitted when call setRewardsDistributor
* @param rewardsDistributor The address of the new rewardsDistributor
*/
event RewardsDistributorSet(address rewardsDistributor);
/**
* @notice Emitted when call setMinter
* @param minter The address of the new minter
*/
event MinterSet(address minter);
/**
* @notice Claim rebases for a given token ID
* @param tokenId The token ID to claim for
* @param feeAmount The fee amount to be taken
* @return claimedRebases The amount of rebases claimed
*/
function claimRebases(uint256 tokenId, uint256 feeAmount)
external
payable
checkFeeWithoutAdditionETH(feeAmount)
returns (uint256 claimedRebases)
{
_sendFee(feeAmount);
IERC721(address(votingEscrow)).safeTransferFrom(msg.sender, address(this), tokenId);
minter.updatePeriod();
claimedRebases = rewardsDistributor.claim(tokenId);
// Return NFT and send rebases
IERC721(address(votingEscrow)).safeTransferFrom(address(this), msg.sender, tokenId);
}
/**
* @notice Claim rebases for a list of token IDs
* @param tokenIds Ids of veNFTs that you wish to claim rebases for
* @param feeAmount The fee amount to be taken
*/
function claimManyRebases(uint256[] memory tokenIds, uint256 feeAmount)
external
payable
checkFeeWithoutAdditionETH(feeAmount)
{
IERC721 veNFT = IERC721(address(votingEscrow));
_sendFee(feeAmount);
// Send all tokens frem the list to the contract
uint256 tokenIdsLength = tokenIds.length;
for (uint256 i = 0; i < tokenIdsLength; i++) {
veNFT.safeTransferFrom(msg.sender, address(this), tokenIds[i]);
}
minter.updatePeriod();
// Claim rebases
bool isClaimed = rewardsDistributor.claimMany(tokenIds);
require(isClaimed, Errors.RebasesNotClaimed());
// Return NFTs and send rebases
for (uint256 i = 0; i < tokenIdsLength; i++) {
veNFT.safeTransferFrom(address(this), msg.sender, tokenIds[i]);
}
}
/**
* @notice Sets the address of the rewards distributor
* @param _rewardsDistributor The address of the new rewardsDistributor
*/
function setRewardsDistributor(address _rewardsDistributor) external onlyOwner {
require(_rewardsDistributor != address(0), Errors.ZeroAddress());
rewardsDistributor = IRewardsDistributor(_rewardsDistributor);
emit RewardsDistributorSet(_rewardsDistributor);
}
/**
* @notice Sets the address of the minter
* @param _minter The address of the new minter
*/
function setMinter(address _minter) external onlyOwner {
require(_minter != address(0), Errors.ZeroAddress());
minter = IMinter(_minter);
emit MinterSet(_minter);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import { Errors } from "src/libraries/Errors.sol";
import { IRouter } from "src/interfaces/IRouter.sol";
import { INonfungiblePositionManager } from "src/interfaces/INonfungiblePositionManager.sol";
abstract contract BasicManager is UUPSUpgradeable, OwnableUpgradeable, IERC721Receiver {
/// @dev SafeERC20 is a wrapper around IERC20 that reverts if the transfer fails
using SafeERC20 for IERC20;
/// @dev Address is a wrapper around address payable
using Address for address payable;
/// @notice WETH address
address public constant WETH = 0x4200000000000000000000000000000000000006;
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
/// @notice The address of the Aerodrome router
IRouter public router;
/// @notice The address of the Aerodrome Nonfungible Position Manager
INonfungiblePositionManager public NonfungiblePositionManager;
/// @notice The address of the treasury
address public treasury;
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when call withdraw
* @param token The address of withdrawn token (if native - zero address)
* @param amount The amount of withdrawn tokens
* @param recipient The address of the recipient
*/
event Withdrawn(address token, uint256 amount, address recipient);
/**
* @notice Emitted when call setTreasury
* @param treasury The address of the new treasury
*/
event TreasurySet(address treasury);
/**
* @notice Emitted when call setRouter
* @param router The address of the new router
*/
event RouterSet(address router);
/**
* @notice Emitted when call setNonFungiblePositionManager
* @param nonfungiblePositionManager The address of the new nonfungiblePositionManager
*/
event NonfungiblePositionManagerSet(address nonfungiblePositionManager);
modifier checkFeeWithoutAdditionETH(uint256 feeAmount) {
require(feeAmount > 0, Errors.InvalidFeeAmount());
require(msg.value == feeAmount, Errors.InvalidFeeAmount());
_;
}
/*//////////////////////////////////////////////////////////////
FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Creates a new position wrapped in a NFT
* @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized
* a method does not exist, i.e. the pool is assumed to be initialized.
* @param params The params necessary to mint a position, encoded as `MintParams` in calldata
* @param feeAmount The amount of fee to be taken
* @return tokenId The ID of the token that represents the minted position
* @return liquidity The amount of liquidity for this position
* @return amount0 The amount of token0
* @return amount1 The amount of token1
*/
function mint(INonfungiblePositionManager.MintParams calldata params, uint256 feeAmount)
external
payable
returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1)
{
require(feeAmount > 0, Errors.InvalidFeeAmount());
require(msg.value >= feeAmount, Errors.InvalidFeeAmount());
require(params.recipient != address(this), Errors.InvalidRecipient());
require(params.token0 != address(0) && params.token1 != address(0), Errors.ZeroAddress());
uint256 ethAmount = msg.value - feeAmount;
uint256 amount0Desired = params.token0 == WETH ? params.amount0Desired - ethAmount : params.amount0Desired;
uint256 amount1Desired = params.token1 == WETH ? params.amount1Desired - ethAmount : params.amount1Desired;
IERC20 token0 = IERC20(params.token0);
IERC20 token1 = IERC20(params.token1);
token0.safeTransferFrom(msg.sender, address(this), amount0Desired);
token1.safeTransferFrom(msg.sender, address(this), amount1Desired);
token0.approve(address(NonfungiblePositionManager), params.amount0Desired);
token1.approve(address(NonfungiblePositionManager), params.amount1Desired);
// Send fee to treasury
_sendFee(feeAmount);
uint256 ethBalanceBefore = address(this).balance - ethAmount;
(tokenId, liquidity, amount0, amount1) = NonfungiblePositionManager.mint{ value: ethAmount }(params);
uint256 returnedETH = address(this).balance - ethBalanceBefore;
if (amount0 < params.amount0Desired) {
uint256 refund =
params.token0 == WETH ? params.amount0Desired - amount0 - returnedETH : params.amount0Desired - amount0;
token0.safeTransfer(msg.sender, refund);
}
if (amount1 < params.amount1Desired) {
uint256 refund =
params.token1 == WETH ? params.amount1Desired - amount1 - returnedETH : params.amount1Desired - amount1;
token1.safeTransfer(msg.sender, refund);
}
// Refund ETH
if (returnedETH > 0) Address.sendValue(payable(msg.sender), returnedETH);
}
/**
* @param params The params to increase liquidity
* @param params tokenId The ID of the token for which liquidity is being
* increased, amount0Desired The desired amount of token0 to be spent,
* amount1Desired The desired amount of token1 to be spent,
* amount0Min The minimum amount of token0 to spend,
* which serves as a slippage check, amount1Min
* The minimum amount of token1 to spend,
* which serves as a slippage check,deadline
* The time by which the transaction must be included to effect the change
* @param feeAmount The fee amount to be taken
* @return liquidity The new liquidity amount as a result of the increase
* @return amount0 The amount of token0 to acheive resulting liquidity
* @return amount1 The amount of token1 to acheive resulting liquidity
*/
function increaseLiquidity(INonfungiblePositionManager.IncreaseLiquidityParams calldata params, uint256 feeAmount)
external
payable
returns (uint128 liquidity, uint256 amount0, uint256 amount1)
{
require(feeAmount > 0, Errors.InvalidFeeAmount());
require(msg.value >= feeAmount, Errors.InvalidFeeAmount());
(,, address token0, address token1,,,,,,,,) = NonfungiblePositionManager.positions(params.tokenId);
uint256 balanceBefore = address(this).balance - msg.value;
// Send fee to treasury
_sendFee(feeAmount);
// Transfers
IERC721(address(NonfungiblePositionManager)).safeTransferFrom(msg.sender, address(this), params.tokenId);
IERC20(token0).safeTransferFrom(msg.sender, address(this), params.amount0Desired);
IERC20(token1).safeTransferFrom(msg.sender, address(this), params.amount1Desired);
// Approvals
IERC20(token0).approve(address(NonfungiblePositionManager), params.amount0Desired);
IERC20(token1).approve(address(NonfungiblePositionManager), params.amount1Desired);
(liquidity, amount0, amount1) = NonfungiblePositionManager.increaseLiquidity(params);
uint256 balanceAfter = address(this).balance;
// Refund ETH if needed
if (balanceAfter > balanceBefore) {
Address.sendValue(payable(msg.sender), balanceAfter - balanceBefore);
}
IERC721(address(NonfungiblePositionManager)).safeTransferFrom(address(this), msg.sender, params.tokenId);
// Refund tokens if needed
if (amount0 < params.amount0Desired) {
uint256 refund = params.amount0Desired - amount0;
IERC20(token0).safeTransfer(msg.sender, refund);
}
if (amount1 < params.amount1Desired) {
uint256 refund = params.amount1Desired - amount1;
IERC20(token1).safeTransfer(msg.sender, refund);
}
}
/**
* @notice Decreases the amount of liquidity in a position and accounts it to the position
* @param params tokenId The ID of the token for which liquidity is being
* decreased, amount The amount by which liquidity will be decreased,
* amount0Min The minimum amount of token0 that should be accounted for the
* burned liquidity, amount1Min The minimum amount of token1 that should be
* accounted for the burned liquidity, deadline The time by which
* the transaction must be included to effect the change
* @param feeAmount The fee amount to be taken
* @return amount0 The amount of token0 accounted to the position's tokens owed
* @return amount1 The amount of token1 accounted to the position's tokens owed
* @dev The use of this function can cause a loss to users of the NonfungiblePositionManager
* @dev for tokens that have very high decimals.
* @dev The amount of tokens necessary for the loss is: 3.4028237e+38.
* @dev This is equivalent to 1e20 value with 18 decimals.
*/
function decreaseLiquidity(INonfungiblePositionManager.DecreaseLiquidityParams calldata params, uint256 feeAmount)
external
payable
returns (uint256 amount0, uint256 amount1)
{
require(feeAmount > 0, Errors.InvalidFeeAmount());
require(msg.value >= feeAmount, Errors.InvalidFeeAmount());
(,, address token0, address token1,,,,,,,,) = NonfungiblePositionManager.positions(params.tokenId);
// Send fee to treasury
_sendFee(feeAmount);
// Transfer position
IERC721(address(NonfungiblePositionManager)).safeTransferFrom(msg.sender, address(this), params.tokenId);
uint256 token0Balance = IERC20(token0).balanceOf(address(this));
uint256 token1Balance = IERC20(token1).balanceOf(address(this));
(amount0, amount1) = NonfungiblePositionManager.decreaseLiquidity(params);
require(params.amount0Min <= amount0 || params.amount1Min <= amount1, Errors.LiquidityDecreaseFailed());
// Refund position
IERC721(address(NonfungiblePositionManager)).safeTransferFrom(address(this), msg.sender, params.tokenId);
// Refund tokens
IERC20(token0).safeTransfer(msg.sender, IERC20(token0).balanceOf(address(this)) - token0Balance);
IERC20(token1).safeTransfer(msg.sender, IERC20(token1).balanceOf(address(this)) - token1Balance);
}
/**
* @notice Add liquidity of two tokens to a Pool
* @dev Calculates the optimal amounts of tokenA and tokenB to deposit
* and adds liquidity to the pool.
* @param tokenA Address of token A
* @param tokenB Address of token B
* @param stable True if pool is stable, false if volatile
* @param amountADesired Amount of tokenA desired to deposit
* @param amountBDesired Amount of tokenB desired to deposit
* @param amountAMin Minimum amount of tokenA to deposit
* @param amountBMin Minimum amount of tokenB to deposit
* @param to Recipient of liquidity token
* @param deadline Deadline to receive liquidity
* @param feeAmount The fee amount to be taken
* @return amountA Amount of tokenA to actually deposit
* @return amountB Amount of tokenB to actually deposit
* @return liquidity Amount of liquidity token returned from deposit
*/
function addLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline,
uint256 feeAmount
)
external
payable
checkFeeWithoutAdditionETH(feeAmount)
returns (uint256 amountA, uint256 amountB, uint256 liquidity)
{
require(to != address(this), Errors.InvalidRecipient());
// Send fee to treasury
_sendFee(feeAmount);
IERC20(tokenA).safeTransferFrom(msg.sender, address(this), amountADesired);
IERC20(tokenB).safeTransferFrom(msg.sender, address(this), amountBDesired);
IERC20(tokenA).approve(address(router), amountADesired);
IERC20(tokenB).approve(address(router), amountBDesired);
(amountA, amountB, liquidity) = router.addLiquidity(
tokenA, tokenB, stable, amountADesired, amountBDesired, amountAMin, amountBMin, to, deadline
);
require(amountA >= amountAMin && amountB >= amountBMin, Errors.LiquidityAddFailed());
// Refund tokens
IERC20(tokenA).safeTransfer(msg.sender, amountADesired - amountA);
IERC20(tokenB).safeTransfer(msg.sender, amountBDesired - amountB);
}
/**
* @notice Add liquidity of a token and WETH (transferred as ETH) to a Pool
* @dev The sender must have already approved this contract to spend their tokens
* @param token The token to add liquidity for
* @param stable True if pool is stable, false if volatile
* @param amountTokenDesired Amount of token desired to deposit
* @param amountTokenMin Minimum amount of token to deposit
* @param amountETHMin Minimum amount of ETH to deposit
* @param to Recipient of liquidity token
* @param deadline Deadline to add liquidity
* @param feeAmount The fee amount to be taken
* @return amountToken Amount of token to actually deposit
* @return amountETH Amount of ETH to actually deposit
* @return liquidity Amount of liquidity token returned from deposit
*/
function addLiquidityETH(
address token,
bool stable,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
uint256 feeAmount
) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity) {
require(feeAmount > 0, Errors.InvalidFeeAmount());
require(msg.value > feeAmount, Errors.InvalidFeeAmount());
uint256 ethAmount = msg.value - feeAmount;
_sendFee(feeAmount);
IERC20(token).safeTransferFrom(msg.sender, address(this), amountTokenDesired);
IERC20(token).approve(address(router), amountTokenDesired);
(amountToken, amountETH, liquidity) = router.addLiquidityETH{ value: ethAmount }(
token, stable, amountTokenDesired, amountTokenMin, amountETHMin, to, deadline
);
require(amountToken >= amountTokenMin && amountETH >= amountETHMin, Errors.LiquidityAddFailed());
// Refund token
IERC20(token).safeTransfer(msg.sender, amountTokenDesired - amountToken);
// Refund ETH
if (ethAmount > amountETH) {
Address.sendValue(payable(msg.sender), ethAmount - amountETH);
}
}
/**
* @notice Remove liquidity of two tokens from a Pool
* @dev The sender must have already approved this contract to spend their liquidity token
* @param tokenA The first token of the pair
* @param tokenB The second token of the pair
* @param stable True if pool is stable, false if volatile
* @param liquidity Amount of liquidity to remove
* @param amountAMin Minimum amount of tokenA to receive
* @param amountBMin Minimum amount of tokenB to receive
* @param to Recipient of tokens received
* @param deadline Deadline to remove liquidity
* @param feeAmount The fee amount to be taken
* @return amountA Amount of tokenA received
* @return amountB Amount of tokenB received
*/
function removeLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline,
uint256 feeAmount
) external payable checkFeeWithoutAdditionETH(feeAmount) returns (uint256 amountA, uint256 amountB) {
require(to != address(this), Errors.InvalidRecipient());
require(to != address(0), Errors.ZeroAddress());
address defaultFactory = router.defaultFactory();
address pool = router.poolFor(tokenA, tokenB, stable, defaultFactory);
IERC20(pool).safeTransferFrom(msg.sender, address(this), liquidity);
IERC20(pool).approve(address(router), liquidity);
// Send fee to treasury
_sendFee(feeAmount);
(amountA, amountB) =
router.removeLiquidity(tokenA, tokenB, stable, liquidity, amountAMin, amountBMin, to, deadline);
require(amountA >= amountAMin && amountB >= amountBMin, Errors.LiquidityRemoveFailed());
}
/**
* @notice Remove liquidity of a token and WETH (returned as ETH) from a Pool
* @param token The token to remove liquidity for
* @param stable True if pool is stable, false if volatile
* @param liquidity The amount of liquidity to remove
* @param amountTokenMin The minimum amount of token to receive
* @param amountETHMin The minimum amount of ETH to receive
* @param to The recipient of the liquidity token
* @param deadline The deadline to receive liquidity
* @param feeAmount The fee amount to be taken
* @return amountToken The amount of token received
* @return amountETH The amount of ETH received
*/
function removeLiquidityETH(
address token,
bool stable,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
uint256 feeAmount
) external payable checkFeeWithoutAdditionETH(feeAmount) returns (uint256 amountToken, uint256 amountETH) {
require(to != address(this), Errors.InvalidRecipient());
address defaultFactory = router.defaultFactory();
address pool = router.poolFor(token, WETH, stable, defaultFactory);
IERC20(pool).safeTransferFrom(msg.sender, address(this), liquidity);
IERC20(pool).approve(address(router), liquidity);
// Send fee to treasury
_sendFee(feeAmount);
(amountToken, amountETH) =
router.removeLiquidityETH(token, stable, liquidity, amountTokenMin, amountETHMin, to, deadline);
require(amountToken >= amountTokenMin && amountETH >= amountETHMin, Errors.LiquidityRemoveFailed());
}
/**
* @notice Collects up to a maximum amount of fees owed to a specific position to the recipient
* @param params The collect parameters
* tokenId The ID of the NFT for which tokens are being collected,
* recipient The account that should receive the tokens,
* amount0Max The maximum amount of token0 to collect,
* amount1Max The maximum amount of token1 to collect
* @param feeAmount The fee amount to be taken
* @return amount0 The amount of fees collected in token0
* @return amount1 The amount of fees collected in token1
*/
function collect(INonfungiblePositionManager.CollectParams calldata params, uint256 feeAmount)
external
payable
checkFeeWithoutAdditionETH(feeAmount)
returns (uint256 amount0, uint256 amount1)
{
require(params.recipient != address(this) && params.recipient != address(0), Errors.InvalidRecipient());
IERC721(address(NonfungiblePositionManager)).safeTransferFrom(msg.sender, address(this), params.tokenId);
(amount0, amount1) = NonfungiblePositionManager.collect(params);
require(amount0 <= params.amount0Max && amount1 <= params.amount1Max, Errors.CollectionFailed());
IERC721(address(NonfungiblePositionManager)).safeTransferFrom(address(this), msg.sender, params.tokenId);
// Send fee to treasury
_sendFee(feeAmount);
}
// Implementing `onERC721Received` so this contract can receive custody of erc721 tokens
function onERC721Received(address, /*operator*/ address, uint256, /*_tokenId*/ bytes calldata)
external
pure
returns (bytes4)
{
return this.onERC721Received.selector;
}
/*//////////////////////////////////////////////////////////////
ADMINISTRATIVE
//////////////////////////////////////////////////////////////*/
/**
* @notice Withdraws tokens from the contract
* @dev Available only to the owner
* @dev If the token is ETH, `token` is set to address(0)
* @param token The address of the token
* @param amount The amount of the token
* @param recipient The address of the recipient
*/
function withdraw(address token, uint256 amount, address recipient) external onlyOwner {
if (recipient == address(0)) revert Errors.ZeroAddress();
if (token == address(0)) {
Address.sendValue(payable(recipient), amount);
} else {
IERC20(token).safeTransfer(recipient, amount);
}
emit Withdrawn(token, amount, recipient);
}
/**
* @dev Sets the address of the treasury
* @param _treasury The address of the treasury
*/
function setTreasury(address _treasury) external onlyOwner {
require(_treasury != address(0), Errors.ZeroAddress());
treasury = _treasury;
emit TreasurySet(_treasury);
}
/**
* @dev Sets the address of the router
* @param _router The address of the router
*/
function setRouter(address _router) external onlyOwner {
require(_router != address(0), Errors.ZeroAddress());
router = IRouter(_router);
emit RouterSet(_router);
}
/**
* @dev Sets the address of the nonfungible position manager
* @param _nonfungiblePositionManager The address of the nonfungible position manager
*/
function setNonFungiblePositionManager(address _nonfungiblePositionManager) external onlyOwner {
require(_nonfungiblePositionManager != address(0), Errors.ZeroAddress());
NonfungiblePositionManager = INonfungiblePositionManager(_nonfungiblePositionManager);
emit NonfungiblePositionManagerSet(_nonfungiblePositionManager);
}
/*//////////////////////////////////////////////////////////////
INTERNAL
//////////////////////////////////////////////////////////////*/
function _sendFee(uint256 feeAmount) internal {
payable(treasury).sendValue(feeAmount);
}
function _authorizeUpgrade(address newImplementation) internal override onlyOwner { }
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;
library Errors {
/// @dev Revert when passed zero address
error ZeroAddress();
/// @dev Revert when passed invalid fee amount
error InvalidFeeAmount();
/// @dev Revert when swap failed
error SwapFailed();
/// @dev Revert when passed invalid recipient
error InvalidRecipient();
/// @dev Revert when liquidity decrease failed
error LiquidityDecreaseFailed();
/// @dev Revert when liquidity increase failed
error LiquidityRemoveFailed();
/// @dev Revert when liquidity add failed
error LiquidityAddFailed();
/// @dev Revert when collection failed
error CollectionFailed();
/// @dev Revert when gauges not exists
error GaugesNotExists(address pool);
/// @dev Revert when caller is not token owner
error NotTokenOwner(uint256 tokenId);
/// @dev Revert when caller is not tokens owner
error NotTokensOwner(uint256 from, uint256 to);
/// @dev Revert when rebases not claimed
error RebasesNotClaimed();
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;
interface IRouter {
struct Route {
address from;
address to;
bool stable;
address factory;
}
/// @notice Address of Protocol PoolFactory.sol
function defaultFactory() external view returns (address);
/// @notice Calculate the address of a pool by its' factory.
/// Used by all Router functions containing a `Route[]` or `_factory` argument.
/// Reverts if _factory is not approved by the FactoryRegistry
/// @dev Returns a randomly generated address for a nonexistent pool
/// @param tokenA Address of token to query
/// @param tokenB Address of token to query
/// @param stable True if pool is stable, false if volatile
/// @param _factory Address of factory which created the pool
function poolFor(address tokenA, address tokenB, bool stable, address _factory)
external
view
returns (address pool);
/*//////////////////////////////////////////////////////////////
ADD LIQUIDITY
//////////////////////////////////////////////////////////////*/
/// @notice Add liquidity of two tokens to a Pool
/// @param tokenA .
/// @param tokenB .
/// @param stable True if pool is stable, false if volatile
/// @param amountADesired Amount of tokenA desired to deposit
/// @param amountBDesired Amount of tokenB desired to deposit
/// @param amountAMin Minimum amount of tokenA to deposit
/// @param amountBMin Minimum amount of tokenB to deposit
/// @param to Recipient of liquidity token
/// @param deadline Deadline to receive liquidity
/// @return amountA Amount of tokenA to actually deposit
/// @return amountB Amount of tokenB to actually deposit
/// @return liquidity Amount of liquidity token returned from deposit
function addLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
/// @notice Add liquidity of a token and WETH (transferred as ETH) to a Pool
/// @param token .
/// @param stable True if pool is stable, false if volatile
/// @param amountTokenDesired Amount of token desired to deposit
/// @param amountTokenMin Minimum amount of token to deposit
/// @param amountETHMin Minimum amount of ETH to deposit
/// @param to Recipient of liquidity token
/// @param deadline Deadline to add liquidity
/// @return amountToken Amount of token to actually deposit
/// @return amountETH Amount of tokenETH to actually deposit
/// @return liquidity Amount of liquidity token returned from deposit
function addLiquidityETH(
address token,
bool stable,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
/*//////////////////////////////////////////////////////////////
REMOVE LIQUIDITY
//////////////////////////////////////////////////////////////*/
/// @notice Remove liquidity of two tokens from a Pool
/// @param tokenA .
/// @param tokenB .
/// @param stable True if pool is stable, false if volatile
/// @param liquidity Amount of liquidity to remove
/// @param amountAMin Minimum amount of tokenA to receive
/// @param amountBMin Minimum amount of tokenB to receive
/// @param to Recipient of tokens received
/// @param deadline Deadline to remove liquidity
/// @return amountA Amount of tokenA received
/// @return amountB Amount of tokenB received
function removeLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
/// @notice Remove liquidity of a token and WETH (returned as ETH) from a Pool
/// @param token .
/// @param stable True if pool is stable, false if volatile
/// @param liquidity Amount of liquidity to remove
/// @param amountTokenMin Minimum amount of token to receive
/// @param amountETHMin Minimum amount of ETH to receive
/// @param to Recipient of liquidity token
/// @param deadline Deadline to receive liquidity
/// @return amountToken Amount of token received
/// @return amountETH Amount of ETH received
function removeLiquidityETH(
address token,
bool stable,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
/// @notice Remove liquidity of a fee-on-transfer token and WETH (returned as ETH) from a Pool
/// @param token .
/// @param stable True if pool is stable, false if volatile
/// @param liquidity Amount of liquidity to remove
/// @param amountTokenMin Minimum amount of token to receive
/// @param amountETHMin Minimum amount of ETH to receive
/// @param to Recipient of liquidity token
/// @param deadline Deadline to receive liquidity
/// @return amountETH Amount of ETH received
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
bool stable,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountETH);
/*//////////////////////////////////////////////////////////////
SWAP
//////////////////////////////////////////////////////////////*/
/// @notice Swap one token for another
/// @param amountIn Amount of token in
/// @param amountOutMin Minimum amount of desired token received
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
/// @return amounts Array of amounts returned per route
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
/// @notice Swap ETH for a token
/// @param amountOutMin Minimum amount of desired token received
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
/// @return amounts Array of amounts returned per route
function swapExactETHForTokens(uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline)
external
payable
returns (uint256[] memory amounts);
/// @notice Swap a token for WETH (returned as ETH)
/// @param amountIn Amount of token in
/// @param amountOutMin Minimum amount of desired ETH
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
/// @return amounts Array of amounts returned per route
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;
interface INonfungiblePositionManager {
struct MintParams {
address token0;
address token1;
int24 tickSpacing;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
uint160 sqrtPriceX96;
}
/// @notice Creates a new position wrapped in a NFT
/// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized
/// a method does not exist, i.e. the pool is assumed to be initialized.
/// @param params The params necessary to mint a position, encoded as `MintParams` in calldata
/// @return tokenId The ID of the token that represents the minted position
/// @return liquidity The amount of liquidity for this position
/// @return amount0 The amount of token0
/// @return amount1 The amount of token1
function mint(MintParams calldata params)
external
payable
returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
struct IncreaseLiquidityParams {
uint256 tokenId;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
/// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender`
/// @param params tokenId The ID of the token for which liquidity is being increased,
/// amount0Desired The desired amount of token0 to be spent,
/// amount1Desired The desired amount of token1 to be spent,
/// amount0Min The minimum amount of token0 to spend, which serves as a slippage check,
/// amount1Min The minimum amount of token1 to spend, which serves as a slippage check,
/// deadline The time by which the transaction must be included to effect the change
/// @return liquidity The new liquidity amount as a result of the increase
/// @return amount0 The amount of token0 to acheive resulting liquidity
/// @return amount1 The amount of token1 to acheive resulting liquidity
function increaseLiquidity(IncreaseLiquidityParams calldata params)
external
payable
returns (uint128 liquidity, uint256 amount0, uint256 amount1);
struct DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
/// @notice Decreases the amount of liquidity in a position and accounts it to the position
/// @param params tokenId The ID of the token for which liquidity is being decreased,
/// amount The amount by which liquidity will be decreased,
/// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity,
/// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity,
/// deadline The time by which the transaction must be included to effect the change
/// @return amount0 The amount of token0 accounted to the position's tokens owed
/// @return amount1 The amount of token1 accounted to the position's tokens owed
/// @dev The use of this function can cause a loss to users of the NonfungiblePositionManager
/// @dev for tokens that have very high decimals.
/// @dev The amount of tokens necessary for the loss is: 3.4028237e+38.
/// @dev This is equivalent to 1e20 value with 18 decimals.
function decreaseLiquidity(DecreaseLiquidityParams calldata params)
external
payable
returns (uint256 amount0, uint256 amount1);
/// @notice Returns the position information associated with a given token ID.
/// @dev Throws if the token ID is not valid.
/// @param tokenId The ID of the token that represents the position
/// @return nonce The nonce for permits
/// @return operator The address that is approved for spending
/// @return token0 The address of the token0 for a specific pool
/// @return token1 The address of the token1 for a specific pool
/// @return tickSpacing The tick spacing associated with the pool
/// @return tickLower The lower end of the tick range for the position
/// @return tickUpper The higher end of the tick range for the position
/// @return liquidity The liquidity of the position
/// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position
/// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position
/// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation
/// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation
function positions(uint256 tokenId)
external
view
returns (
uint96 nonce,
address operator,
address token0,
address token1,
int24 tickSpacing,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
/// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient
/// @notice Used to update staked positions before deposit and withdraw
/// @param params tokenId The ID of the NFT for which tokens are being collected,
/// recipient The account that should receive the tokens,
/// amount0Max The maximum amount of token0 to collect,
/// amount1Max The maximum amount of token1 to collect
/// @return amount0 The amount of fees collected in token0
/// @return amount1 The amount of fees collected in token1
function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;
interface IVoter {
/// @dev Pool => Gauge
function gauges(address pool) external view returns (address);
/// @notice Claim bribes for a given NFT.
/// @dev Utility to help batch bribe claims.
/// @param _bribes Array of BribeVotingReward contracts to collect from.
/// @param _tokens Array of tokens that are used as bribes.
/// @param _tokenId Id of veNFT that you wish to claim bribes for.
function claimBribes(address[] memory _bribes, address[][] memory _tokens, uint256 _tokenId) external;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;
interface IVotingEscrow {
/// @notice Address of token (AERO) used to create a veNFT
function token() external view returns (address);
/// @notice Deposit `_value` tokens for `_to` and lock for `_lockDuration`
/// @param _value Amount to deposit
/// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week)
/// @param _to Address to deposit
/// @return TokenId of created veNFT
function createLockFor(uint256 _value, uint256 _lockDuration, address _to) external returns (uint256);
/// @notice Deposit `_value` tokens for `_tokenId` and add to the lock
/// @dev Anyone (even a smart contract) can deposit for someone else, but
/// cannot extend their locktime and deposit for a brand new user
/// @param _tokenId lock NFT
/// @param _value Amount to add to user's lock
function depositFor(uint256 _tokenId, uint256 _value) external;
/// @notice Withdraw all tokens for `_tokenId`
/// @dev Only possible if the lock is both expired and not permanent
/// This will burn the veNFT. Any rebases or rewards that are unclaimed
/// will no longer be claimable. Claim all rebases and rewards prior to calling this.
function withdraw(uint256 _tokenId) external;
/// @notice Merges `_from` into `_to`.
/// @dev Cannot merge `_from` locks that are permanent or have already voted this epoch.
/// Cannot merge `_to` locks that have already expired.
/// This will burn the veNFT. Any rebases or rewards that are unclaimed
/// will no longer be claimable. Claim all rebases and rewards prior to calling this.
/// @param _from VeNFT to merge from.
/// @param _to VeNFT to merge into.
function merge(uint256 _from, uint256 _to) external;
/// @notice Splits veNFT into two new veNFTS - one with oldLocked.amount - `_amount`, and the second with `_amount`
/// @dev This burns the tokenId of the target veNFT
/// Callable by approved or owner
/// If this is called by approved, approved will not have permissions to manipulate the newly created veNFTs
/// Returns the two new split veNFTs to owner
/// If `from` is permanent, will automatically dedelegate.
/// This will burn the veNFT. Any rebases or rewards that are unclaimed
/// will no longer be claimable. Claim all rebases and rewards prior to calling this.
/// @param _from VeNFT to split.
/// @param _amount Amount to split from veNFT.
/// @return _tokenId1 Return tokenId of veNFT with oldLocked.amount - `_amount`.
/// @return _tokenId2 Return tokenId of veNFT with `_amount`.
function split(uint256 _from, uint256 _amount) external returns (uint256 _tokenId1, uint256 _tokenId2);
/// @notice Permanently lock a veNFT. Voting power will be equal to
/// `LockedBalance.amount` with no decay. Required to delegate.
/// @dev Only callable by unlocked normal veNFTs.
/// @param _tokenId tokenId to lock.
function lockPermanent(uint256 _tokenId) external;
/// @notice Unlock a permanently locked veNFT. Voting power will decay.
/// Will automatically dedelegate if delegated.
/// @dev Only callable by permanently locked veNFTs.
/// Cannot unlock if already voted this epoch.
/// @param _tokenId tokenId to unlock.
function unlockPermanent(uint256 _tokenId) external;
/// @notice Deposit `_value` additional tokens for `_tokenId` without modifying the unlock time
/// @param _value Amount of tokens to deposit and add to the lock
function increaseAmount(uint256 _tokenId, uint256 _value) external;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;
interface IRewardsDistributor {
/// @notice Claims rebases for a given token ID
/// @dev Allows claiming of rebases up to 50 epochs old
/// `Minter.updatePeriod()` must be called before claiming
/// @param tokenId The token ID to claim for
/// @return The amount of rebases claimed
function claim(uint256 tokenId) external returns (uint256);
/// @notice Claims rebases for a list of token IDs
/// @dev `Minter.updatePeriod()` must be called before claiming
/// @param tokenIds The token IDs to claim for
/// @return Whether or not the claim succeeded
function claimMany(uint256[] calldata tokenIds) external returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;
import { BasicManager } from "src/base/BasicManager.sol";
import { Errors } from "src/libraries/Errors.sol";
import { IVoter } from "src/interfaces/IVoter.sol";
import { IGauge } from "src/interfaces/IGauge.sol";
import { IVotingEscrow } from "src/interfaces/IVotingEscrow.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
abstract contract VoterManager is BasicManager {
/// @dev SafeERC20 is a wrapper around IERC20 that reverts if the transfer fails
using SafeERC20 for IERC20;
/// @notice The address of the voter
IVoter public voter;
/// @notice The address of the voting escrow
IVotingEscrow public votingEscrow;
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when call setVoter
* @param voter The address of the new voter
*/
event VoterSet(address voter);
/**
* @notice Emitted when call setVotingEscrow
* @param votingEscrow The address of the new votingEscrow
*/
event VotingEscrowSet(address votingEscrow);
/*//////////////////////////////////////////////////////////////
FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Stake LP tokens on AMM pool
* @param pool The address of the pool token
* @param amount The amount of liquidity to deposit
* @param recipient Recipient to give balance to
* @param feeAmount Fee amount to be taken
*/
function depositAMM(address pool, uint256 amount, address recipient, uint256 feeAmount)
external
payable
checkFeeWithoutAdditionETH(feeAmount)
{
require(recipient != address(this), Errors.InvalidRecipient());
// Send fee to treasury
_sendFee(feeAmount);
// Getting IGauge address of the token
address gauge = voter.gauges(pool);
require(gauge != address(0), Errors.GaugesNotExists(pool));
IERC20(pool).safeTransferFrom(msg.sender, address(this), amount);
IERC20(pool).approve(gauge, amount);
IGauge(gauge).deposit(amount, recipient);
}
/**
* @notice Deposit `value` tokens for a specified address and lock them for a given duration.
* @param value The amount of tokens to deposit.
* @param lockDuration The duration (in seconds) for which the tokens will be locked.
* This value is rounded down to the nearest week.
* @param to The address for which the tokens are being deposited and locked.
* @param feeAmount The fee amount to be taken
* @return TokenId The ID of the created veNFT.
*/
function createLockFor(uint256 value, uint256 lockDuration, address to, uint256 feeAmount)
external
payable
checkFeeWithoutAdditionETH(feeAmount)
returns (uint256)
{
require(to != address(this), Errors.InvalidRecipient());
IERC20 token = IERC20(votingEscrow.token());
_sendFee(feeAmount);
token.safeTransferFrom(msg.sender, address(this), value);
token.approve(address(votingEscrow), value);
return votingEscrow.createLockFor(value, lockDuration, to);
}
/**
* @notice Deposit `value` tokens for `tokenId` and add to the lock
* @param tokenId lock NFT
* @param value Amount to add to user's lock
* @param feeAmount The fee amount to be taken
* @dev Requires tokens approval for Manager from the caller
*/
function depositFor(uint256 tokenId, uint256 value, uint256 feeAmount)
external
payable
checkFeeWithoutAdditionETH(feeAmount)
{
IERC20 token = IERC20(votingEscrow.token());
_sendFee(feeAmount);
token.safeTransferFrom(msg.sender, address(this), value);
token.approve(address(votingEscrow), value);
votingEscrow.depositFor(tokenId, value);
}
/**
* @notice Withdraw all tokens for `tokenId`
* @param tokenId lock NFT
* @param feeAmount The fee amount to be taken
* @dev Requires approval for Manager from the caller (owner of NFT)
* @dev Only possible if the lock is both expired and not permanent
* This will burn the veNFT. Any rebases or rewards that are unclaimed
* will no longer be claimable. Claim all rebases and rewards prior to calling this.
* @dev Only possible if the caller is the token owner
*/
function withdraw(uint256 tokenId, uint256 feeAmount) external payable checkFeeWithoutAdditionETH(feeAmount) {
require(IERC721(address(votingEscrow)).ownerOf(tokenId) == msg.sender, Errors.NotTokenOwner(tokenId));
_sendFee(feeAmount);
uint256 balanceBefore = IERC20(votingEscrow.token()).balanceOf(address(this));
votingEscrow.withdraw(tokenId);
uint256 balanceAfter = IERC20(votingEscrow.token()).balanceOf(address(this));
IERC20(votingEscrow.token()).safeTransfer(msg.sender, balanceAfter - balanceBefore);
}
/**
* @notice Transfer veNFT to `to`
* @param tokenId lock NFT
* @param to Address to transfer veNFT to
* @param feeAmount The fee amount to be taken
* @dev Requires approval for Manager from the caller (owner of NFT)
* @dev Only possible if the caller is the token owner
*/
function transferLock(uint256 tokenId, address to, uint256 feeAmount)
external
payable
checkFeeWithoutAdditionETH(feeAmount)
{
require(IERC721(address(votingEscrow)).ownerOf(tokenId) == msg.sender, Errors.NotTokenOwner(tokenId));
_sendFee(feeAmount);
IERC721(address(votingEscrow)).safeTransferFrom(msg.sender, to, tokenId);
}
/**
* @notice Merges `from` into `to`.
* @dev Cannot merge `from` locks that are permanent or have already voted this epoch.
* Cannot merge `to` locks that have already expired.
* This will burn the veNFT. Any rebases or rewards that are unclaimed
* will no longer be claimable. Claim all rebases and rewards prior to calling this.
* @param from VeNFT to merge from.
* @param to VeNFT to merge into.
* @dev Requires both approvals from the caller (owner of both NFTs)
* @dev Requires tha caller is owner of both NFTs
*/
function merge(uint256 from, uint256 to, uint256 feeAmount)
external
payable
checkFeeWithoutAdditionETH(feeAmount)
{
require(
IERC721(address(votingEscrow)).ownerOf(from) == msg.sender
&& IERC721(address(votingEscrow)).ownerOf(to) == msg.sender,
Errors.NotTokensOwner(from, to)
);
_sendFee(feeAmount);
votingEscrow.merge(from, to);
}
/**
* @notice Splits veNFT into two new veNFTS - one with oldLocked.amount - `amount`, and the second with `amount`
* @dev This burns the tokenId of the target veNFT
* Callable by approved or owner
* This will burn the veNFT. Any rebases or rewards that are unclaimed
* will no longer be claimable. Claim all rebases and rewards prior to calling this.
* @dev Requires approval from the caller of the veNFT to the Manager
* @param from VeNFT to split.
* @param amount Amount to split from veNFT.
* @return _tokenId1 Return tokenId of veNFT with oldLocked.amount - `amount`.
* @return _tokenId2 Return tokenId of veNFT with `amount`.
*/
function split(uint256 from, uint256 amount, uint256 feeAmount)
external
payable
checkFeeWithoutAdditionETH(feeAmount)
returns (uint256 _tokenId1, uint256 _tokenId2)
{
require(IERC721(address(votingEscrow)).ownerOf(from) == msg.sender, Errors.NotTokenOwner(from));
_sendFee(feeAmount);
IERC721(address(votingEscrow)).safeTransferFrom(msg.sender, address(this), from);
(_tokenId1, _tokenId2) = votingEscrow.split(from, amount);
IERC721(address(votingEscrow)).safeTransferFrom(address(this), msg.sender, _tokenId1);
IERC721(address(votingEscrow)).safeTransferFrom(address(this), msg.sender, _tokenId2);
return (_tokenId1, _tokenId2);
}
/**
* @notice Deposit `_value` additional tokens for `_tokenId` without modifying the unlock time
* @param value Amount of tokens to deposit and add to the lock
* @param tokenId TokenId to deposit for
* @param feeAmount The fee amount to be taken
* @dev Requires ownership of the tokenId
*/
function increaseAmount(uint256 tokenId, uint256 value, uint256 feeAmount)
external
payable
checkFeeWithoutAdditionETH(feeAmount)
{
require(IERC721(address(votingEscrow)).ownerOf(tokenId) == msg.sender, Errors.NotTokenOwner(tokenId));
_sendFee(feeAmount);
IERC20 token = IERC20(votingEscrow.token());
token.safeTransferFrom(msg.sender, address(this), value);
token.approve(address(votingEscrow), value);
IVotingEscrow(votingEscrow).increaseAmount(tokenId, value);
}
/**
* @notice Claim bribes for a given NFT.
* @dev Utility to help batch bribe claims.
* @param bribes Array of BribeVotingReward contracts to collect from.
* @param tokens Array of tokens that are used as bribes.
* @param tokenId Id of veNFT that you wish to claim bribes for.
* @param feeAmount The fee amount to be taken
*/
function claimBribes(address[] memory bribes, address[][] memory tokens, uint256 tokenId, uint256 feeAmount)
external
payable
checkFeeWithoutAdditionETH(feeAmount)
{
require(IERC721(address(votingEscrow)).ownerOf(tokenId) == msg.sender, Errors.NotTokenOwner(tokenId));
_sendFee(feeAmount);
voter.claimBribes(bribes, tokens, tokenId);
}
/*//////////////////////////////////////////////////////////////
ADMINISTRATIVE
//////////////////////////////////////////////////////////////*/
/**
* @dev Sets the address of the voter
* @param _voter The address of the voter
*/
function setVoter(address _voter) external onlyOwner {
require(_voter != address(0), Errors.ZeroAddress());
voter = IVoter(_voter);
emit VoterSet(_voter);
}
/**
* @dev Sets the address of the voting escrow
* @param _votingEscrow The address of the voting escrow
*/
function setVotingEscrow(address _votingEscrow) external onlyOwner {
require(_votingEscrow != address(0), Errors.ZeroAddress());
votingEscrow = IVotingEscrow(_votingEscrow);
emit VotingEscrowSet(_votingEscrow);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC-721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @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 ERC-721 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 ERC-721
* 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 address zero.
*
* 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: UNLICENSED
pragma solidity 0.8.28;
interface IMinter {
/// @notice Processes emissions and rebases. Callable once per epoch (1 week).
/// @return _period Start of current epoch.
function updatePeriod() external returns (uint256 _period);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.22;
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC-1967 compliant implementation pointing to self.
* See {_onlyProxy}.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC-1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, bytes memory returndata) = recipient.call{value: amount}("");
if (!success) {
_revert(returndata);
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {Errors.FailedCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
* of an unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {Errors.FailedCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC-721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC-721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data)
external
returns (bytes4);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;
interface IGauge {
/// @notice Deposit LP tokens into gauge for any user
/// @param _amount .
/// @param _recipient Recipient to give balance to
function deposit(uint256 _amount, address _recipient) external;
/// @notice Withdraw LP tokens for user
/// @param _amount .
function withdraw(uint256 _amount) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @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[ERC 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
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.22;
import {IBeacon} from "../beacon/IBeacon.sol";
import {IERC1967} from "../../interfaces/IERC1967.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This library provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots.
*/
library ERC1967Utils {
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the ERC-1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit IERC1967.Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the ERC-1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit IERC1967.AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the ERC-1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit IERC1967.BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*/
interface IERC1967 {
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC-1967 implementation slot:
* ```solidity
* contract ERC1967 {
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct Int256Slot {
int256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Int256Slot` with member `value` located at `slot`.
*/
function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
/**
* @dev Returns a `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";{
"remappings": [
"\"forge-std/=lib/forge-std/src/\",/",
"\"@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/\",/",
"\"@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/\",/",
"\"@openzeppelin/upgrades/=lib/openzeppelin-foundry-upgrades/src/\"/",
"@openzeppelin/=node_modules/@openzeppelin/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"CollectionFailed","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidFeeAmount","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"LiquidityAddFailed","type":"error"},{"inputs":[],"name":"LiquidityDecreaseFailed","type":"error"},{"inputs":[],"name":"LiquidityRemoveFailed","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"nonfungiblePositionManager","type":"address"}],"name":"NonfungiblePositionManagerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"router","type":"address"}],"name":"RouterSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"treasury","type":"address"}],"name":"TreasurySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"NonfungiblePositionManager","outputs":[{"internalType":"contract INonfungiblePositionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"}],"internalType":"struct INonfungiblePositionManager.CollectParams","name":"params","type":"tuple"},{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"collect","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct INonfungiblePositionManager.DecreaseLiquidityParams","name":"params","type":"tuple"},{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"decreaseLiquidity","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount0Desired","type":"uint256"},{"internalType":"uint256","name":"amount1Desired","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct INonfungiblePositionManager.IncreaseLiquidityParams","name":"params","type":"tuple"},{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"increaseLiquidity","outputs":[{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_router","type":"address"},{"internalType":"address","name":"_nonfungiblePositionManager","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0Desired","type":"uint256"},{"internalType":"uint256","name":"amount1Desired","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"}],"internalType":"struct INonfungiblePositionManager.MintParams","name":"params","type":"tuple"},{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract IRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nonfungiblePositionManager","type":"address"}],"name":"setNonFungiblePositionManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_router","type":"address"}],"name":"setRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a080604052346100c257306080525f5160206129065f395f51905f525460ff8160401c166100b3576002600160401b03196001600160401b03821601610060575b60405161283f90816100c7823960805181818161176301526118330152f35b6001600160401b0319166001600160401b039081175f5160206129065f395f51905f525581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80610041565b63f92ee8a960e01b5f5260045ffd5b5f80fdfe608080604052600436101561001c575b50361561001a575f80fd5b005b5f905f3560e01c908163150b7a02146122365750806317389cf514611e9357806320190c6714611c0e578063328f81a9146119da5780634f1ef286146117b757806352d1902d1461175057806361d027b31461172757806369328dec146116815780636fe2e4d514611233578063715018a6146111ca5780638da5cb5b14611195578063ad3cb1cc14611139578063ad5c464814611116578063b7e325ed14610f55578063c0c53b8b14610d02578063c0d7865514610c92578063ca67b320146109c7578063e8555f0514610954578063eb582d131461092b578063f00e4ff714610671578063f0f44260146105ef578063f2fde38b146105c2578063f887ea401461059b5763fe17e77d0361000f57366003190160c081126105425760a0136105985760a435801561058a5780341061058a5760015460405163133f757160e31b815260048035908201819052929161018090829060249082906001600160a01b03165afa9182156104335784918593610546575b506002546101a991906001600160a01b0316612610565b60015484906001600160a01b0316803b1561054257816040518092632142170760e11b82528183816101e08b30336004850161249c565b03925af180156104ea57610529575b50506040516370a0823160e01b81523060048201526001600160a01b039190911691602082602481865afa9182156104ab5785926104f5575b506040516370a0823160e01b81523060048201526001600160a01b0391909116949091602083602481895afa9283156104ea5782936104b6575b5060018060a01b03600154169360405195630624e65f60e11b87528060048801526024356001600160801b0381168091036104575760248801526044359586604489015260408860a481886064359586606484015260843560848401525af19687156104ab5785988698610475575b50888891119182159261046a575b50501561045b576001546001600160a01b031690813b156104575761031f85928392604051948580948193632142170760e11b835233306004850161249c565b03925af180156104335790849161043e575b50506040516370a0823160e01b8152306004820152602081602481855afa9081156104335784916103ff575b506103739261036b9161247b565b903390612657565b6040516370a0823160e01b8152306004820152602081602481895afa9182156103f357916103b9575b509361036b6103ad9260409661247b565b82519182526020820152f35b9490506020853d6020116103eb575b816103d5602093836122f5565b810103126103e757935161036b61039c565b5f80fd5b3d91506103c8565b604051903d90823e3d90fd5b90506020813d60201161042b575b8161041a602093836122f5565b810103126103e7575161037361035d565b3d915061040d565b6040513d86823e3d90fd5b81610448916122f5565b61045357825f610331565b8280fd5b8480fd5b635e71d03360e01b8452600484fd5b11159050865f6102df565b90985061049b91975060403d6040116104a4575b61049381836122f5565b8101906124d6565b969097886102d1565b503d610489565b6040513d87823e3d90fd5b9092506020813d6020116104e2575b816104d2602093836122f5565b810103126103e75751915f610262565b3d91506104c5565b6040513d84823e3d90fd5b9091506020813d602011610521575b81610511602093836122f5565b810103126103e75751905f610228565b3d9150610504565b81610533916122f5565b61053e57835f6101ef565b8380fd5b5080fd5b61056e9193506101a992506101803d8111610583575b61056681836122f5565b8101906123d5565b50505050505050509392509050919290610192565b503d61055c565b62a4671960e71b8252600482fd5b80fd5b5034610598578060031936011261059857546040516001600160a01b039091168152602090f35b5034610598576020366003190112610598576105ec6105df6122a4565b6105e7612690565b612533565b80f35b5034610598576020366003190112610598576106096122a4565b610611612690565b6001600160a01b03168015610662576020817f3c864541ef71378c6229510ed90f376565ee42d9c5e0904a984a9e863e6db44f926001600160601b0360a01b6002541617600255604051908152a180f35b63d92e233d60e01b8252600482fd5b50610140366003190112610598576106876122a4565b906106906122ba565b906106996122e6565b92606435926084359060a4359460c4359460e4359460018060a01b0386168096036105425761012435801561091d5780340361091d5730871461090e576002546106ec91906001600160a01b0316612610565b6001600160a01b031692610702833033876125a4565b6001600160a01b031694610718853033896125a4565b815460405163095ea7b360e01b81526001600160a01b0390911660048201526024810184905260208160448186895af180156108e6576108f1575b50815460405163095ea7b360e01b81526001600160a01b03909116600482015260248101869052602081604481868b5af180156108e65790606092916108b9575b5061012460018060a01b038454169a846040519c8d948593635a47ddc360e01b85528a60048601528c6024860152151560448501528860648501528a60848501528d60a48501528c60c485015260e4840152610104356101048401525af19586156108ac57819782998398610871575b508810159081610866575b50156108575750866108369361083161085397969461036b8a61036b9661247b565b61247b565b604051938493846040919493926060820195825260208201520152565b0390f35b63760598e160e01b8152600490fd5b90508810155f61080f565b919850965061089991985060603d6060116108a5575b61089181836122f5565b810190612518565b9891979098965f610804565b503d610887565b50604051903d90823e3d90fd5b6108da9060203d6020116108df575b6108d281836122f5565b8101906124be565b610794565b503d6108c8565b6040513d85823e3d90fd5b6109099060203d6020116108df576108d281836122f5565b610753565b634e46966960e11b8352600483fd5b62a4671960e71b8352600483fd5b50346105985780600319360112610598576001546040516001600160a01b039091168152602090f35b50346105985760203660031901126105985761096e6122a4565b610976612690565b6001600160a01b03168015610662576020817ffc16f4d868f580252bff93cba89e723ac15fb82d773c5ff26ee487e8303ee50a926001600160601b0360a01b6001541617600155604051908152a180f35b506109d136612347565b93968496919695939515610c8457843403610c84576001600160a01b0383163014610c7557885460405163d4b6846d60e01b81528a92916001600160a01b031690602081600481855afa8015610433578490610c3b575b60405163874029d960e01b81526001600160a01b0385811660048301526006602160991b016024830152871515604483015290911660648201529160209150829060849082905afa80156108e65786918491610bf8575b50610ad5916020916001600160a01b0316610a9c823033846125a4565b855460405163095ea7b360e01b81526001600160a01b039091166004820152602481019290925290928391908290879082906044820190565b03925af19889156108e657610b03604098610b62938d9c610bdb575b506002546001600160a01b0316612610565b8354885163d7b0e0a560e01b81526001600160a01b03948516600482015295151560248701526044860197909752606485019a909a526084840188905293811660a484015260c4830198909852909687931691839190829060e4820190565b03925af19182156104335784938593610bb4575b508310159081610ba9575b5015610b97576040809350519182526020820152f35b600162b1876760e01b03198352600483fd5b90508110155f610b81565b909250610bd191935060403d6040116104a45761049381836122f5565b929092915f610b76565b610bf39060203d6020116108df576108d281836122f5565b610af1565b9150506020813d602011610c33575b81610c14602093836122f5565b8101031261045357602086610c2b610ad59361239f565b915091610a7f565b3d9150610c07565b506020813d602011610c6d575b81610c55602093836122f5565b8101031261053e57610c6860209161239f565b610a28565b3d9150610c48565b634e46966960e11b8952600489fd5b62a4671960e71b8952600489fd5b503461059857602036600319011261059857610cac6122a4565b610cb4612690565b6001600160a01b031680156106625781546001600160a01b031916811782556040519081527fc6b438e6a8a59579ce6a4406cbd203b740e0d47b458aae6596339bcd40c40d1590602090a180f35b503461059857606036600319011261059857610d1c6122a4565b610d246122ba565b610d2c6122d0565b5f5160206127ea5f395f51905f52549260ff8460401c16159367ffffffffffffffff811680159081610f4d575b6001149081610f43575b159081610f3a575b50610f2b5767ffffffffffffffff1981166001175f5160206127ea5f395f51905f525584610eff575b50610d9d612739565b610da5612739565b610dae33612533565b610db6612739565b6001600160a01b0316918215610ef057917ffc16f4d868f580252bff93cba89e723ac15fb82d773c5ff26ee487e8303ee50a602080937fc6b438e6a8a59579ce6a4406cbd203b740e0d47b458aae6596339bcd40c40d15827f3c864541ef71378c6229510ed90f376565ee42d9c5e0904a984a9e863e6db44f97866001600160601b0360a01b600254161760025560018060a01b031692836001600160601b0360a01b8c5416178b5560018060a01b031692836001600160601b0360a01b6001541617600155604051908152a1604051908152a1604051908152a1610e985780f35b68ff0000000000000000195f5160206127ea5f395f51905f5254165f5160206127ea5f395f51905f52557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b63d92e233d60e01b8552600485fd5b68ffffffffffffffffff191668010000000000000001175f5160206127ea5f395f51905f52555f610d94565b63f92ee8a960e01b8652600486fd5b9050155f610d6b565b303b159150610d63565b869150610d59565b50610f5f36612347565b9492959791909396851561091d578534111561091d57610f96610f82873461247b565b6002549097906001600160a01b0316612610565b6001600160a01b03811694610fad853033896125a4565b835460405163095ea7b360e01b81526001600160a01b03909116600482015260248101869052602081604481888b5af180156104ab57918693918b9c936110f9575b5085546040516302df835360e61b81526001600160a01b03938416600482015293151560248501526044840194909452606483019b909b526084820189905292831660a482015260c4810199909952168760e481875a94606095f19485156108ac578196829883976110ce575b5087101590816110c3575b5015610857575091611082869261036b87610853979661247b565b8181116110a9575b5050604051938493846040919493926060820195825260208201520152565b6110bc916110b69161247b565b33612610565b835f61108a565b90508710155f611067565b91975095506110ed91975060603d6060116108a55761089181836122f5565b9791969097955f61105c565b6111119060203d6020116108df576108d281836122f5565b610fef565b50346105985780600319360112610598576040516006602160991b018152602090f35b50346105985780600319360112610598576040805161115882826122f5565b6005815260208101640352e302e360dc1b81528251938492602084525180928160208601528585015e828201840152601f01601f19168101030190f35b50346105985780600319360112610598575f5160206127aa5f395f51905f52546040516001600160a01b039091168152602090f35b50346105985780600319360112610598576111e3612690565b5f5160206127aa5f395f51905f5280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5036600319016101a0811261054257610180136105985761018435801561058a5780341061058a57610124356001600160a01b038116929083810361054257308414611672576001600160a01b03611289612502565b16151580611659575b15610662576112a1833461247b565b6006602160991b016001600160a01b036112b9612502565b1603611650576112cb8160a43561247b565b925b6006602160991b016001600160a01b036112e56124ec565b1603611647576112f78260c43561247b565b935b6113336001600160a01b0361130c612502565b169561132b6001600160a01b036113216124ec565b169330338a6125a4565b3033846125a4565b60015460405163095ea7b360e01b81526001600160a01b03909116600482015260a435602482018190529390602081604481878b5af180156104335761162a575b5060015460405163095ea7b360e01b81526001600160a01b03909116600482015260c43560248201819052979060208160448188885af180156104ab57906113cd9291610bdb57506002546001600160a01b0316612610565b6113d7814761247b565b60015460405163b5007d1f60e01b8152919991966001600160a01b0391821692916114006122a4565b1660048901526001600160a01b036114166122ba565b1660248901526044358060020b80910361161e5760448901526064358060020b80910361161e5760648901526084358060020b80910361161e5760848901528660a48901528960c489015260e43560e48901526101043561010489015250610124870152610144356101448701526101643560018060a01b03811680910361045757866080938193610184936101648401525af19485156104ea5782968398849685986115b3575b5091876001600160801b039694926114da60809c97954761247b565b958693848b83811061157a575b50505050808210611526575b5050915050611516575b5060405194855216602084015260408301526060820152f35b6115209033612610565b5f6114fd565b611560946006602160991b016001600160a01b036115426124ec565b161415905061156a5761036b92916108319161247b565b3390612657565b5f808287826114f3565b611574925061247b565b90611559565b6115aa936006602160991b016001600160a01b03611596612502565b160361156a5761036b92916108319161247b565b5f80848b6114e7565b965096509650909196506080843d608011611622575b816115d6608093836122f5565b8101031261161e579160809684926001600160801b03946114da97965196611600602087016123c1565b9960606040880151970151989a9698995092949650909294996114be565b8680fd5b3d91506115c9565b6116429060203d6020116108df576108d281836122f5565b611374565b60c435936112f9565b60a435926112cd565b506001600160a01b0361166a6124ec565b161515611292565b634e46966960e11b8252600482fd5b50346105985760603660031901126105985761169b6122a4565b602435906116a76122d0565b916116b0612690565b6001600160a01b038316918215610ef0577fcbcdbdf10631a43cc99c80acace8232649421c3f4f73919f16013d47c83a687a936060936001600160a01b039092169290818461171857611704915083612610565b60405192835260208301526040820152a180f35b6117229185612657565b611704565b50346105985780600319360112610598576002546040516001600160a01b039091168152602090f35b50346105985780600319360112610598577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036117a85760206040515f5160206127ca5f395f51905f528152f35b63703e46dd60e11b8152600490fd5b506040366003190112610598576117cc6122a4565b6024359067ffffffffffffffff8211610453573660238301121561045357816004013590836117fa8361232b565b9361180860405195866122f5565b8385526020850193366024828401011161045357806024602093018637850101526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163081149081156119b8575b506119a95761186b612690565b6040516352d1902d60e01b81526001600160a01b0382169390602081600481885afa869181611975575b506118ae57634c9c8ce360e01b86526004859052602486fd5b93845f5160206127ca5f395f51905f528796036119635750823b15611951575f5160206127ca5f395f51905f5280546001600160a01b031916821790558491907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a2805115611936576119329382915190845af461192c6125e1565b91612764565b5080f35b50505050346119425780f35b63b398979f60e01b8152600490fd5b634c9c8ce360e01b8552600452602484fd5b632a87526960e21b8652600452602485fd5b9091506020813d6020116119a1575b81611991602093836122f5565b8101031261161e5751905f611895565b3d9150611984565b63703e46dd60e11b8452600484fd5b5f5160206127ca5f395f51905f52546001600160a01b0316141590505f61185e565b50366003190160a081126105425760801361059857608435908115611c0057813403611c0057611a086124ec565b6001600160a01b031630141580611be7575b15611bd85760015460043591906001600160a01b0316803b1561054257816040518092632142170760e11b8252818381611a598930336004850161249c565b03925af180156104ea57908291611bc3575b505060015460405163fc6f786560e01b815260048101849052926001600160a01b039182169291611a9a6122ba565b166024850152604435926001600160801b0384169081850361053e57816044870152606435916001600160801b03831691828403611bbf5787608481886040948760648401525af19586156104ab5785978697611b98575b50508611159182611b8b575b505015611b7c576001546001600160a01b031690813b1561045357611b3e83928392604051948580948193632142170760e11b835233306004850161249c565b03925af180156104ea57611b67575b50506002546040936103ad916001600160a01b0316612610565b611b728280926122f5565b6105985780611b4d565b63f0ff962b60e01b8252600482fd5b5084111590505f80611afe565b909650611bb591975060403d6040116104a45761049381836122f5565b969096955f611af2565b8580fd5b81611bcd916122f5565b61059857805f611a6b565b634e46966960e11b8152600490fd5b506001600160a01b03611bf86124ec565b161515611a1a565b62a4671960e71b8152600490fd5b5061012036600319011261059857611c246122a4565b611c2c6122ba565b611c346122e6565b6084359160a435916064359160c4356001600160a01b0381169190829003611e8f5761010435938415610c8457843403610c8457308314610c75578215611e8057885460405163d4b6846d60e01b8152986001600160a01b03909116938a929160208b600481895afa9a8b1561043357849b611e42575b5060405163874029d960e01b81526001600160a01b039182166004820181905295821660248201819052971515604482018190529b909116606482015294602090869060849082905afa9485156108e6578395611e00575b50611d5b9460209083906001600160a01b0316611d22823033846125a4565b855460405163095ea7b360e01b81526001600160a01b039091166004820152602481019290925290968791908290879082906044820190565b03925af180156108e65760409761010496611d8692610bdb57506002546001600160a01b0316612610565b60018060a01b038354169187519a8b97889663037b79b160e21b885260048801526024870152604486015260648501528860848501528760a485015260c484015260e43560e48401525af19182156104335784938593610bb457508310159081610ba9575015610b97576040809350519182526020820152f35b94506020853d602011611e3a575b81611e1b602093836122f5565b8101031261045357602082611e32611d5b9761239f565b965050611d03565b3d9150611e0e565b909a506020813d602011611e78575b81611e5e602093836122f5565b8101031261053e57611e7160209161239f565b9a90611cab565b3d9150611e51565b63d92e233d60e01b8952600489fd5b8780fd5b50366003190160e081126103e75760c0136103e75760c4358015612228578034106122285760015460405163133f757160e31b8152600480359082018190529093909161018090859060249082906001600160a01b03165afa9384156121ee575f905f956121f9575b50611f1e611f0a344761247b565b6002549095906001600160a01b0316612610565b6001546001600160a01b0316803b156103e7575f6040518092632142170760e11b8252818381611f538a30336004850161249c565b03925af180156121ee576121d9575b506001600160a01b03169360243590611f7d823033896125a4565b6001600160a01b03169460443591611f978330338a6125a4565b60015460405163095ea7b360e01b81526001600160a01b0390911660048201526024810182905260208160448188875af180156104ab576121bc575b5060015460405163095ea7b360e01b81526001600160a01b03909116600482015260248101849052602081604481888c5af180156104ab5761219f575b5083606060018060a01b036001541660c46040518098819363219f5d1760e01b83528b60048401528760248401528960448401526064356064840152608435608484015260a43560a48401525af19586156108ac57819782968398612152575b504781811161213e575b50506001546001600160a01b031690813b15610453576120b583928392604051948580948193632142170760e11b835233306004850161249c565b03925af180156104ea57612129575b50509183606097928487958310612114575b5050508083106120ff575b5050506001600160801b036040519316835260208301526040820152f35b61210c9261036b9161247b565b815f806120e1565b6121219261036b9161247b565b835f806120d6565b6121348280926122f5565b61059857806120c4565b61214b916110b69161247b565b5f8061207a565b9850965094506060873d606011612197575b81612171606093836122f5565b8101031261059857612182876123c1565b9460406020890151980151959795965f612070565b3d9150612164565b6121b79060203d6020116108df576108d281836122f5565b612010565b6121d49060203d6020116108df576108d281836122f5565b611fd3565b6121e69192505f906122f5565b5f905f611f62565b6040513d5f823e3d90fd5b90506122159194506101803d81116105835761056681836122f5565b505050505050505095925090505f611efc565b62a4671960e71b5f5260045ffd5b346103e75760803660031901126103e75761224f6122a4565b506122586122ba565b5060643567ffffffffffffffff81116103e757366023820112156103e757806004013567ffffffffffffffff81116103e757369101602401116103e757630a85bd0160e11b8152602090f35b600435906001600160a01b03821682036103e757565b602435906001600160a01b03821682036103e757565b604435906001600160a01b03821682036103e757565b6044359081151582036103e757565b90601f8019910116810190811067ffffffffffffffff82111761231757604052565b634e487b7160e01b5f52604160045260245ffd5b67ffffffffffffffff811161231757601f01601f191660200190565b6101009060031901126103e7576004356001600160a01b03811681036103e7579060243580151581036103e7579060443590606435906084359060a4356001600160a01b03811681036103e7579060c4359060e43590565b51906001600160a01b03821682036103e757565b51908160020b82036103e757565b51906001600160801b03821682036103e757565b9190826101809103126103e75781516001600160601b03811681036103e757916124016020820161239f565b9161240e6040830161239f565b9161241b6060820161239f565b91612428608083016123b3565b9161243560a082016123b3565b9161244260c083016123b3565b9161244f60e082016123c1565b91610100820151916101208101519161247861016061247161014085016123c1565b93016123c1565b90565b9190820391821161248857565b634e487b7160e01b5f52601160045260245ffd5b6001600160a01b03918216815291166020820152604081019190915260600190565b908160209103126103e7575180151581036103e75790565b91908260409103126103e7576020825192015190565b6024356001600160a01b03811681036103e75790565b6004356001600160a01b03811681036103e75790565b908160609103126103e7578051916040602083015192015190565b6001600160a01b03168015612591575f5160206127aa5f395f51905f5280546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b631e4fbdf760e01b5f525f60045260245ffd5b906125da906125cc6125df956040519586936323b872dd60e01b60208601526024850161249c565b03601f1981018452836122f5565b6126c3565b565b3d1561260b573d906125f28261232b565b9161260060405193846122f5565b82523d5f602084013e565b606090565b814710612640575f918291829182916001600160a01b03165af16126326125e1565b901561263b5750565b61271b565b504763cf47918160e01b5f5260045260245260445ffd5b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448201929092526125df916125da82606481016125cc565b5f5160206127aa5f395f51905f52546001600160a01b031633036126b057565b63118cdaa760e01b5f523360045260245ffd5b905f602091828151910182855af1156121ee575f513d61271257506001600160a01b0381163b155b6126f25750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b600114156126eb565b80511561272a57805190602001fd5b63d6bda27560e01b5f5260045ffd5b60ff5f5160206127ea5f395f51905f525460401c161561275557565b631afcd79f60e31b5f5260045ffd5b9061276f575061271b565b815115806127a0575b612780575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561277856fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a2646970667358221220e175e562936f19c3bac0e90bf77df835a344816cfeb3f405ed912d59f748b79a64736f6c634300081c0033f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00
Deployed Bytecode
0x608080604052600436101561001c575b50361561001a575f80fd5b005b5f905f3560e01c908163150b7a02146122365750806317389cf514611e9357806320190c6714611c0e578063328f81a9146119da5780634f1ef286146117b757806352d1902d1461175057806361d027b31461172757806369328dec146116815780636fe2e4d514611233578063715018a6146111ca5780638da5cb5b14611195578063ad3cb1cc14611139578063ad5c464814611116578063b7e325ed14610f55578063c0c53b8b14610d02578063c0d7865514610c92578063ca67b320146109c7578063e8555f0514610954578063eb582d131461092b578063f00e4ff714610671578063f0f44260146105ef578063f2fde38b146105c2578063f887ea401461059b5763fe17e77d0361000f57366003190160c081126105425760a0136105985760a435801561058a5780341061058a5760015460405163133f757160e31b815260048035908201819052929161018090829060249082906001600160a01b03165afa9182156104335784918593610546575b506002546101a991906001600160a01b0316612610565b60015484906001600160a01b0316803b1561054257816040518092632142170760e11b82528183816101e08b30336004850161249c565b03925af180156104ea57610529575b50506040516370a0823160e01b81523060048201526001600160a01b039190911691602082602481865afa9182156104ab5785926104f5575b506040516370a0823160e01b81523060048201526001600160a01b0391909116949091602083602481895afa9283156104ea5782936104b6575b5060018060a01b03600154169360405195630624e65f60e11b87528060048801526024356001600160801b0381168091036104575760248801526044359586604489015260408860a481886064359586606484015260843560848401525af19687156104ab5785988698610475575b50888891119182159261046a575b50501561045b576001546001600160a01b031690813b156104575761031f85928392604051948580948193632142170760e11b835233306004850161249c565b03925af180156104335790849161043e575b50506040516370a0823160e01b8152306004820152602081602481855afa9081156104335784916103ff575b506103739261036b9161247b565b903390612657565b6040516370a0823160e01b8152306004820152602081602481895afa9182156103f357916103b9575b509361036b6103ad9260409661247b565b82519182526020820152f35b9490506020853d6020116103eb575b816103d5602093836122f5565b810103126103e757935161036b61039c565b5f80fd5b3d91506103c8565b604051903d90823e3d90fd5b90506020813d60201161042b575b8161041a602093836122f5565b810103126103e7575161037361035d565b3d915061040d565b6040513d86823e3d90fd5b81610448916122f5565b61045357825f610331565b8280fd5b8480fd5b635e71d03360e01b8452600484fd5b11159050865f6102df565b90985061049b91975060403d6040116104a4575b61049381836122f5565b8101906124d6565b969097886102d1565b503d610489565b6040513d87823e3d90fd5b9092506020813d6020116104e2575b816104d2602093836122f5565b810103126103e75751915f610262565b3d91506104c5565b6040513d84823e3d90fd5b9091506020813d602011610521575b81610511602093836122f5565b810103126103e75751905f610228565b3d9150610504565b81610533916122f5565b61053e57835f6101ef565b8380fd5b5080fd5b61056e9193506101a992506101803d8111610583575b61056681836122f5565b8101906123d5565b50505050505050509392509050919290610192565b503d61055c565b62a4671960e71b8252600482fd5b80fd5b5034610598578060031936011261059857546040516001600160a01b039091168152602090f35b5034610598576020366003190112610598576105ec6105df6122a4565b6105e7612690565b612533565b80f35b5034610598576020366003190112610598576106096122a4565b610611612690565b6001600160a01b03168015610662576020817f3c864541ef71378c6229510ed90f376565ee42d9c5e0904a984a9e863e6db44f926001600160601b0360a01b6002541617600255604051908152a180f35b63d92e233d60e01b8252600482fd5b50610140366003190112610598576106876122a4565b906106906122ba565b906106996122e6565b92606435926084359060a4359460c4359460e4359460018060a01b0386168096036105425761012435801561091d5780340361091d5730871461090e576002546106ec91906001600160a01b0316612610565b6001600160a01b031692610702833033876125a4565b6001600160a01b031694610718853033896125a4565b815460405163095ea7b360e01b81526001600160a01b0390911660048201526024810184905260208160448186895af180156108e6576108f1575b50815460405163095ea7b360e01b81526001600160a01b03909116600482015260248101869052602081604481868b5af180156108e65790606092916108b9575b5061012460018060a01b038454169a846040519c8d948593635a47ddc360e01b85528a60048601528c6024860152151560448501528860648501528a60848501528d60a48501528c60c485015260e4840152610104356101048401525af19586156108ac57819782998398610871575b508810159081610866575b50156108575750866108369361083161085397969461036b8a61036b9661247b565b61247b565b604051938493846040919493926060820195825260208201520152565b0390f35b63760598e160e01b8152600490fd5b90508810155f61080f565b919850965061089991985060603d6060116108a5575b61089181836122f5565b810190612518565b9891979098965f610804565b503d610887565b50604051903d90823e3d90fd5b6108da9060203d6020116108df575b6108d281836122f5565b8101906124be565b610794565b503d6108c8565b6040513d85823e3d90fd5b6109099060203d6020116108df576108d281836122f5565b610753565b634e46966960e11b8352600483fd5b62a4671960e71b8352600483fd5b50346105985780600319360112610598576001546040516001600160a01b039091168152602090f35b50346105985760203660031901126105985761096e6122a4565b610976612690565b6001600160a01b03168015610662576020817ffc16f4d868f580252bff93cba89e723ac15fb82d773c5ff26ee487e8303ee50a926001600160601b0360a01b6001541617600155604051908152a180f35b506109d136612347565b93968496919695939515610c8457843403610c84576001600160a01b0383163014610c7557885460405163d4b6846d60e01b81528a92916001600160a01b031690602081600481855afa8015610433578490610c3b575b60405163874029d960e01b81526001600160a01b0385811660048301526006602160991b016024830152871515604483015290911660648201529160209150829060849082905afa80156108e65786918491610bf8575b50610ad5916020916001600160a01b0316610a9c823033846125a4565b855460405163095ea7b360e01b81526001600160a01b039091166004820152602481019290925290928391908290879082906044820190565b03925af19889156108e657610b03604098610b62938d9c610bdb575b506002546001600160a01b0316612610565b8354885163d7b0e0a560e01b81526001600160a01b03948516600482015295151560248701526044860197909752606485019a909a526084840188905293811660a484015260c4830198909852909687931691839190829060e4820190565b03925af19182156104335784938593610bb4575b508310159081610ba9575b5015610b97576040809350519182526020820152f35b600162b1876760e01b03198352600483fd5b90508110155f610b81565b909250610bd191935060403d6040116104a45761049381836122f5565b929092915f610b76565b610bf39060203d6020116108df576108d281836122f5565b610af1565b9150506020813d602011610c33575b81610c14602093836122f5565b8101031261045357602086610c2b610ad59361239f565b915091610a7f565b3d9150610c07565b506020813d602011610c6d575b81610c55602093836122f5565b8101031261053e57610c6860209161239f565b610a28565b3d9150610c48565b634e46966960e11b8952600489fd5b62a4671960e71b8952600489fd5b503461059857602036600319011261059857610cac6122a4565b610cb4612690565b6001600160a01b031680156106625781546001600160a01b031916811782556040519081527fc6b438e6a8a59579ce6a4406cbd203b740e0d47b458aae6596339bcd40c40d1590602090a180f35b503461059857606036600319011261059857610d1c6122a4565b610d246122ba565b610d2c6122d0565b5f5160206127ea5f395f51905f52549260ff8460401c16159367ffffffffffffffff811680159081610f4d575b6001149081610f43575b159081610f3a575b50610f2b5767ffffffffffffffff1981166001175f5160206127ea5f395f51905f525584610eff575b50610d9d612739565b610da5612739565b610dae33612533565b610db6612739565b6001600160a01b0316918215610ef057917ffc16f4d868f580252bff93cba89e723ac15fb82d773c5ff26ee487e8303ee50a602080937fc6b438e6a8a59579ce6a4406cbd203b740e0d47b458aae6596339bcd40c40d15827f3c864541ef71378c6229510ed90f376565ee42d9c5e0904a984a9e863e6db44f97866001600160601b0360a01b600254161760025560018060a01b031692836001600160601b0360a01b8c5416178b5560018060a01b031692836001600160601b0360a01b6001541617600155604051908152a1604051908152a1604051908152a1610e985780f35b68ff0000000000000000195f5160206127ea5f395f51905f5254165f5160206127ea5f395f51905f52557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b63d92e233d60e01b8552600485fd5b68ffffffffffffffffff191668010000000000000001175f5160206127ea5f395f51905f52555f610d94565b63f92ee8a960e01b8652600486fd5b9050155f610d6b565b303b159150610d63565b869150610d59565b50610f5f36612347565b9492959791909396851561091d578534111561091d57610f96610f82873461247b565b6002549097906001600160a01b0316612610565b6001600160a01b03811694610fad853033896125a4565b835460405163095ea7b360e01b81526001600160a01b03909116600482015260248101869052602081604481888b5af180156104ab57918693918b9c936110f9575b5085546040516302df835360e61b81526001600160a01b03938416600482015293151560248501526044840194909452606483019b909b526084820189905292831660a482015260c4810199909952168760e481875a94606095f19485156108ac578196829883976110ce575b5087101590816110c3575b5015610857575091611082869261036b87610853979661247b565b8181116110a9575b5050604051938493846040919493926060820195825260208201520152565b6110bc916110b69161247b565b33612610565b835f61108a565b90508710155f611067565b91975095506110ed91975060603d6060116108a55761089181836122f5565b9791969097955f61105c565b6111119060203d6020116108df576108d281836122f5565b610fef565b50346105985780600319360112610598576040516006602160991b018152602090f35b50346105985780600319360112610598576040805161115882826122f5565b6005815260208101640352e302e360dc1b81528251938492602084525180928160208601528585015e828201840152601f01601f19168101030190f35b50346105985780600319360112610598575f5160206127aa5f395f51905f52546040516001600160a01b039091168152602090f35b50346105985780600319360112610598576111e3612690565b5f5160206127aa5f395f51905f5280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5036600319016101a0811261054257610180136105985761018435801561058a5780341061058a57610124356001600160a01b038116929083810361054257308414611672576001600160a01b03611289612502565b16151580611659575b15610662576112a1833461247b565b6006602160991b016001600160a01b036112b9612502565b1603611650576112cb8160a43561247b565b925b6006602160991b016001600160a01b036112e56124ec565b1603611647576112f78260c43561247b565b935b6113336001600160a01b0361130c612502565b169561132b6001600160a01b036113216124ec565b169330338a6125a4565b3033846125a4565b60015460405163095ea7b360e01b81526001600160a01b03909116600482015260a435602482018190529390602081604481878b5af180156104335761162a575b5060015460405163095ea7b360e01b81526001600160a01b03909116600482015260c43560248201819052979060208160448188885af180156104ab57906113cd9291610bdb57506002546001600160a01b0316612610565b6113d7814761247b565b60015460405163b5007d1f60e01b8152919991966001600160a01b0391821692916114006122a4565b1660048901526001600160a01b036114166122ba565b1660248901526044358060020b80910361161e5760448901526064358060020b80910361161e5760648901526084358060020b80910361161e5760848901528660a48901528960c489015260e43560e48901526101043561010489015250610124870152610144356101448701526101643560018060a01b03811680910361045757866080938193610184936101648401525af19485156104ea5782968398849685986115b3575b5091876001600160801b039694926114da60809c97954761247b565b958693848b83811061157a575b50505050808210611526575b5050915050611516575b5060405194855216602084015260408301526060820152f35b6115209033612610565b5f6114fd565b611560946006602160991b016001600160a01b036115426124ec565b161415905061156a5761036b92916108319161247b565b3390612657565b5f808287826114f3565b611574925061247b565b90611559565b6115aa936006602160991b016001600160a01b03611596612502565b160361156a5761036b92916108319161247b565b5f80848b6114e7565b965096509650909196506080843d608011611622575b816115d6608093836122f5565b8101031261161e579160809684926001600160801b03946114da97965196611600602087016123c1565b9960606040880151970151989a9698995092949650909294996114be565b8680fd5b3d91506115c9565b6116429060203d6020116108df576108d281836122f5565b611374565b60c435936112f9565b60a435926112cd565b506001600160a01b0361166a6124ec565b161515611292565b634e46966960e11b8252600482fd5b50346105985760603660031901126105985761169b6122a4565b602435906116a76122d0565b916116b0612690565b6001600160a01b038316918215610ef0577fcbcdbdf10631a43cc99c80acace8232649421c3f4f73919f16013d47c83a687a936060936001600160a01b039092169290818461171857611704915083612610565b60405192835260208301526040820152a180f35b6117229185612657565b611704565b50346105985780600319360112610598576002546040516001600160a01b039091168152602090f35b50346105985780600319360112610598577f0000000000000000000000000138485163745706ab26bad4bf1824606d5b14356001600160a01b031630036117a85760206040515f5160206127ca5f395f51905f528152f35b63703e46dd60e11b8152600490fd5b506040366003190112610598576117cc6122a4565b6024359067ffffffffffffffff8211610453573660238301121561045357816004013590836117fa8361232b565b9361180860405195866122f5565b8385526020850193366024828401011161045357806024602093018637850101526001600160a01b037f0000000000000000000000000138485163745706ab26bad4bf1824606d5b1435163081149081156119b8575b506119a95761186b612690565b6040516352d1902d60e01b81526001600160a01b0382169390602081600481885afa869181611975575b506118ae57634c9c8ce360e01b86526004859052602486fd5b93845f5160206127ca5f395f51905f528796036119635750823b15611951575f5160206127ca5f395f51905f5280546001600160a01b031916821790558491907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a2805115611936576119329382915190845af461192c6125e1565b91612764565b5080f35b50505050346119425780f35b63b398979f60e01b8152600490fd5b634c9c8ce360e01b8552600452602484fd5b632a87526960e21b8652600452602485fd5b9091506020813d6020116119a1575b81611991602093836122f5565b8101031261161e5751905f611895565b3d9150611984565b63703e46dd60e11b8452600484fd5b5f5160206127ca5f395f51905f52546001600160a01b0316141590505f61185e565b50366003190160a081126105425760801361059857608435908115611c0057813403611c0057611a086124ec565b6001600160a01b031630141580611be7575b15611bd85760015460043591906001600160a01b0316803b1561054257816040518092632142170760e11b8252818381611a598930336004850161249c565b03925af180156104ea57908291611bc3575b505060015460405163fc6f786560e01b815260048101849052926001600160a01b039182169291611a9a6122ba565b166024850152604435926001600160801b0384169081850361053e57816044870152606435916001600160801b03831691828403611bbf5787608481886040948760648401525af19586156104ab5785978697611b98575b50508611159182611b8b575b505015611b7c576001546001600160a01b031690813b1561045357611b3e83928392604051948580948193632142170760e11b835233306004850161249c565b03925af180156104ea57611b67575b50506002546040936103ad916001600160a01b0316612610565b611b728280926122f5565b6105985780611b4d565b63f0ff962b60e01b8252600482fd5b5084111590505f80611afe565b909650611bb591975060403d6040116104a45761049381836122f5565b969096955f611af2565b8580fd5b81611bcd916122f5565b61059857805f611a6b565b634e46966960e11b8152600490fd5b506001600160a01b03611bf86124ec565b161515611a1a565b62a4671960e71b8152600490fd5b5061012036600319011261059857611c246122a4565b611c2c6122ba565b611c346122e6565b6084359160a435916064359160c4356001600160a01b0381169190829003611e8f5761010435938415610c8457843403610c8457308314610c75578215611e8057885460405163d4b6846d60e01b8152986001600160a01b03909116938a929160208b600481895afa9a8b1561043357849b611e42575b5060405163874029d960e01b81526001600160a01b039182166004820181905295821660248201819052971515604482018190529b909116606482015294602090869060849082905afa9485156108e6578395611e00575b50611d5b9460209083906001600160a01b0316611d22823033846125a4565b855460405163095ea7b360e01b81526001600160a01b039091166004820152602481019290925290968791908290879082906044820190565b03925af180156108e65760409761010496611d8692610bdb57506002546001600160a01b0316612610565b60018060a01b038354169187519a8b97889663037b79b160e21b885260048801526024870152604486015260648501528860848501528760a485015260c484015260e43560e48401525af19182156104335784938593610bb457508310159081610ba9575015610b97576040809350519182526020820152f35b94506020853d602011611e3a575b81611e1b602093836122f5565b8101031261045357602082611e32611d5b9761239f565b965050611d03565b3d9150611e0e565b909a506020813d602011611e78575b81611e5e602093836122f5565b8101031261053e57611e7160209161239f565b9a90611cab565b3d9150611e51565b63d92e233d60e01b8952600489fd5b8780fd5b50366003190160e081126103e75760c0136103e75760c4358015612228578034106122285760015460405163133f757160e31b8152600480359082018190529093909161018090859060249082906001600160a01b03165afa9384156121ee575f905f956121f9575b50611f1e611f0a344761247b565b6002549095906001600160a01b0316612610565b6001546001600160a01b0316803b156103e7575f6040518092632142170760e11b8252818381611f538a30336004850161249c565b03925af180156121ee576121d9575b506001600160a01b03169360243590611f7d823033896125a4565b6001600160a01b03169460443591611f978330338a6125a4565b60015460405163095ea7b360e01b81526001600160a01b0390911660048201526024810182905260208160448188875af180156104ab576121bc575b5060015460405163095ea7b360e01b81526001600160a01b03909116600482015260248101849052602081604481888c5af180156104ab5761219f575b5083606060018060a01b036001541660c46040518098819363219f5d1760e01b83528b60048401528760248401528960448401526064356064840152608435608484015260a43560a48401525af19586156108ac57819782968398612152575b504781811161213e575b50506001546001600160a01b031690813b15610453576120b583928392604051948580948193632142170760e11b835233306004850161249c565b03925af180156104ea57612129575b50509183606097928487958310612114575b5050508083106120ff575b5050506001600160801b036040519316835260208301526040820152f35b61210c9261036b9161247b565b815f806120e1565b6121219261036b9161247b565b835f806120d6565b6121348280926122f5565b61059857806120c4565b61214b916110b69161247b565b5f8061207a565b9850965094506060873d606011612197575b81612171606093836122f5565b8101031261059857612182876123c1565b9460406020890151980151959795965f612070565b3d9150612164565b6121b79060203d6020116108df576108d281836122f5565b612010565b6121d49060203d6020116108df576108d281836122f5565b611fd3565b6121e69192505f906122f5565b5f905f611f62565b6040513d5f823e3d90fd5b90506122159194506101803d81116105835761056681836122f5565b505050505050505095925090505f611efc565b62a4671960e71b5f5260045ffd5b346103e75760803660031901126103e75761224f6122a4565b506122586122ba565b5060643567ffffffffffffffff81116103e757366023820112156103e757806004013567ffffffffffffffff81116103e757369101602401116103e757630a85bd0160e11b8152602090f35b600435906001600160a01b03821682036103e757565b602435906001600160a01b03821682036103e757565b604435906001600160a01b03821682036103e757565b6044359081151582036103e757565b90601f8019910116810190811067ffffffffffffffff82111761231757604052565b634e487b7160e01b5f52604160045260245ffd5b67ffffffffffffffff811161231757601f01601f191660200190565b6101009060031901126103e7576004356001600160a01b03811681036103e7579060243580151581036103e7579060443590606435906084359060a4356001600160a01b03811681036103e7579060c4359060e43590565b51906001600160a01b03821682036103e757565b51908160020b82036103e757565b51906001600160801b03821682036103e757565b9190826101809103126103e75781516001600160601b03811681036103e757916124016020820161239f565b9161240e6040830161239f565b9161241b6060820161239f565b91612428608083016123b3565b9161243560a082016123b3565b9161244260c083016123b3565b9161244f60e082016123c1565b91610100820151916101208101519161247861016061247161014085016123c1565b93016123c1565b90565b9190820391821161248857565b634e487b7160e01b5f52601160045260245ffd5b6001600160a01b03918216815291166020820152604081019190915260600190565b908160209103126103e7575180151581036103e75790565b91908260409103126103e7576020825192015190565b6024356001600160a01b03811681036103e75790565b6004356001600160a01b03811681036103e75790565b908160609103126103e7578051916040602083015192015190565b6001600160a01b03168015612591575f5160206127aa5f395f51905f5280546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b631e4fbdf760e01b5f525f60045260245ffd5b906125da906125cc6125df956040519586936323b872dd60e01b60208601526024850161249c565b03601f1981018452836122f5565b6126c3565b565b3d1561260b573d906125f28261232b565b9161260060405193846122f5565b82523d5f602084013e565b606090565b814710612640575f918291829182916001600160a01b03165af16126326125e1565b901561263b5750565b61271b565b504763cf47918160e01b5f5260045260245260445ffd5b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448201929092526125df916125da82606481016125cc565b5f5160206127aa5f395f51905f52546001600160a01b031633036126b057565b63118cdaa760e01b5f523360045260245ffd5b905f602091828151910182855af1156121ee575f513d61271257506001600160a01b0381163b155b6126f25750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b600114156126eb565b80511561272a57805190602001fd5b63d6bda27560e01b5f5260045ffd5b60ff5f5160206127ea5f395f51905f525460401c161561275557565b631afcd79f60e31b5f5260045ffd5b9061276f575061271b565b815115806127a0575b612780575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561277856fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a2646970667358221220e175e562936f19c3bac0e90bf77df835a344816cfeb3f405ed912d59f748b79a64736f6c634300081c0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.