// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)
pragma solidity ^0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// 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 {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
import "@openzeppelin/contracts-0.8/token/ERC20/IERC20.sol";
interface IBalancerPool is IERC20 {
enum SwapKind {
GIVEN_IN,
GIVEN_OUT
}
struct SwapRequest {
SwapKind kind;
IERC20 tokenIn;
IERC20 tokenOut;
uint256 amount;
// Misc data
bytes32 poolId;
uint256 lastChangeBlock;
address from;
address to;
bytes userData;
}
function getPoolId() external view returns (bytes32 poolId);
function symbol() external view returns (string memory s);
/**
* @dev This function returns the appreciation of one BPT relative to the
* underlying tokens. This starts at 1 when the pool is created and grows over time.
* Because of pre minted BPT, it uses `getVirtualSupply` instead of `totalSupply`.
*/
function getRate() external view returns (uint256);
/**
* @dev Returns the token rate for token. All token rates are fixed-point values with 18 decimals.
* In case there is no rate provider for the provided token it returns 1e18.
*/
function getTokenRate(IERC20 token) external view returns (uint256);
function getScalingFactor(IERC20 token) external view returns (uint256);
function onSwap(
SwapRequest memory swapRequest,
uint256[] memory balances,
uint256 indexIn,
uint256 indexOut
) external view returns (uint256 amount);
function getNormalizedWeights() external view returns (uint256[] memory);
function getSwapEnabled() external view returns (bool);
function getOwner() external view returns (address);
}
interface IBalancerVault {
enum PoolSpecialization {
GENERAL,
MINIMAL_SWAP_INFO,
TWO_TOKEN
}
enum JoinKind {
INIT,
EXACT_TOKENS_IN_FOR_BPT_OUT,
TOKEN_IN_FOR_EXACT_BPT_OUT,
ALL_TOKENS_IN_FOR_EXACT_BPT_OUT
}
enum ExitKind {
EXACT_BPT_IN_FOR_ONE_TOKEN_OUT,
EXACT_BPT_IN_FOR_TOKENS_OUT,
BPT_IN_FOR_EXACT_TOKENS_OUT
}
enum SwapKind {
GIVEN_IN,
GIVEN_OUT
}
/**
* @dev Data for each individual swap executed by `batchSwap`. The asset in and out fields are indexes into the
* `assets` array passed to that function, and ETH assets are converted to WETH.
*
* If `amount` is zero, the multihop mechanism is used to determine the actual amount based on the amount in/out
* from the previous swap, depending on the swap kind.
*
* The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
* used to extend swap behavior.
*/
struct BatchSwapStep {
bytes32 poolId;
uint256 assetInIndex;
uint256 assetOutIndex;
uint256 amount;
bytes userData;
}
/**
* @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the
* `recipient` account.
*
* If the caller is not `sender`, it must be an authorized relayer for them.
*
* If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20
* transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender`
* must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of
* `joinPool`.
*
* If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of
* transferred. This matches the behavior of `exitPool`.
*
* Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a
* revert.
*/
struct FundManagement {
address sender;
bool fromInternalBalance;
address payable recipient;
bool toInternalBalance;
}
/**
* @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on
* the `kind` value.
*
* `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address).
* Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault.
*
* The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
* used to extend swap behavior.
*/
struct SingleSwap {
bytes32 poolId;
SwapKind kind;
IAsset assetIn;
IAsset assetOut;
uint256 amount;
bytes userData;
}
// encoding formats https://github.com/balancer-labs/balancer-v2-monorepo/blob/master/pkg/balancer-js/src/pool-weighted/encoder.ts
struct JoinPoolRequest {
IAsset[] assets;
uint256[] maxAmountsIn;
bytes userData;
bool fromInternalBalance;
}
struct ExitPoolRequest {
IAsset[] assets;
uint256[] minAmountsOut;
bytes userData;
bool toInternalBalance;
}
function joinPool(
bytes32 poolId,
address sender,
address recipient,
JoinPoolRequest memory request
) external payable;
function exitPool(
bytes32 poolId,
address sender,
address payable recipient,
ExitPoolRequest calldata request
) external;
function getPool(bytes32 poolId) external view returns (address poolAddress, PoolSpecialization);
function getPoolTokenInfo(bytes32 poolId, IERC20 token)
external
view
returns (
uint256 cash,
uint256 managed,
uint256 lastChangeBlock,
address assetManager
);
function getPoolTokens(bytes32 poolId)
external
view
returns (
IERC20[] calldata tokens,
uint256[] calldata balances,
uint256 lastChangeBlock
);
/**
* @dev Performs a swap with a single Pool.
*
* If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens
* taken from the Pool, which must be greater than or equal to `limit`.
*
* If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens
* sent to the Pool, which must be less than or equal to `limit`.
*
* Internal Balance usage and the recipient are determined by the `funds` struct.
*
* Emits a `Swap` event.
*/
function swap(
SingleSwap memory singleSwap,
FundManagement memory funds,
uint256 limit,
uint256 deadline
) external returns (uint256 amountCalculated);
/**
* @dev Performs a series of swaps with one or multiple Pools. In each individual swap, the caller determines either
* the amount of tokens sent to or received from the Pool, depending on the `kind` value.
*
* Returns an array with the net Vault asset balance deltas. Positive amounts represent tokens (or ETH) sent to the
* Vault, and negative amounts represent tokens (or ETH) sent by the Vault. Each delta corresponds to the asset at
* the same index in the `assets` array.
*
* Swaps are executed sequentially, in the order specified by the `swaps` array. Each array element describes a
* Pool, the token to be sent to this Pool, the token to receive from it, and an amount that is either `amountIn` or
* `amountOut` depending on the swap kind.
*
* Multihop swaps can be executed by passing an `amount` value of zero for a swap. This will cause the amount in/out
* of the previous swap to be used as the amount in for the current one. In a 'given in' swap, 'tokenIn' must equal
* the previous swap's `tokenOut`. For a 'given out' swap, `tokenOut` must equal the previous swap's `tokenIn`.
*
* The `assets` array contains the addresses of all assets involved in the swaps. These are either token addresses,
* or the IAsset sentinel value for ETH (the zero address). Each entry in the `swaps` array specifies tokens in and
* out by referencing an index in `assets`. Note that Pools never interact with ETH directly: it will be wrapped to
* or unwrapped from WETH by the Vault.
*
* Internal Balance usage, sender, and recipient are determined by the `funds` struct. The `limits` array specifies
* the minimum or maximum amount of each token the vault is allowed to transfer.
*
* `batchSwap` can be used to make a single swap, like `swap` does, but doing so requires more gas than the
* equivalent `swap` call.
*
* Emits `Swap` events.
*/
function batchSwap(
SwapKind kind,
BatchSwapStep[] memory swaps,
IAsset[] memory assets,
FundManagement memory funds,
int256[] memory limits,
uint256 deadline
) external payable returns (int256[] memory);
function flashLoan(
IFlashLoanRecipient recipient,
IERC20[] memory tokens,
uint256[] memory amounts,
bytes memory userData
) external;
function queryBatchSwap(
SwapKind kind,
BatchSwapStep[] memory swaps,
IAsset[] memory assets,
FundManagement memory funds
) external returns (int256[] memory assetDeltas);
}
interface IAsset {
// solhint-disable-previous-line no-empty-blocks
}
interface IBalancerVaultHelper {
struct JoinPoolRequest {
IAsset[] assets;
uint256[] maxAmountsIn;
bytes userData;
bool fromInternalBalance;
}
struct ExitPoolRequest {
IAsset[] assets;
uint256[] minAmountsOut;
bytes userData;
bool toInternalBalance;
}
function queryJoin(
bytes32 poolId,
address sender,
address recipient,
IBalancerVault.JoinPoolRequest memory request
) external view returns (uint256 bptOut, uint256[] memory amountsIn);
function queryExit(
bytes32 poolId,
address sender,
address recipient,
IBalancerVault.ExitPoolRequest memory request
) external view returns (uint256 bptIn, uint256[] memory amountsOut);
}
/**
* @dev Interface for querying historical data from a Pool that can be used as a Price Oracle.
*
* This lets third parties retrieve average prices of tokens held by a Pool over a given period of time, as well as the
* price of the Pool share token (BPT) and invariant. Since the invariant is a sensible measure of Pool liquidity, it
* can be used to compare two different price sources, and choose the most liquid one.
*
* Once the oracle is fully initialized, all queries are guaranteed to succeed as long as they require no data that
* is not older than the largest safe query window.
*/
interface IBalancerTwapOracle {
// The three values that can be queried:
//
// - PAIR_PRICE: the price of the tokens in the Pool, expressed as the price of the second token in units of the
// first token. For example, if token A is worth $2, and token B is worth $4, the pair price will be 2.0.
// Note that the price is computed *including* the tokens decimals. This means that the pair price of a Pool with
// DAI and USDC will be close to 1.0, despite DAI having 18 decimals and USDC 6.
//
// - BPT_PRICE: the price of the Pool share token (BPT), in units of the first token.
// Note that the price is computed *including* the tokens decimals. This means that the BPT price of a Pool with
// USDC in which BPT is worth $5 will be 5.0, despite the BPT having 18 decimals and USDC 6.
//
// - INVARIANT: the value of the Pool's invariant, which serves as a measure of its liquidity.
enum Variable {
PAIR_PRICE,
BPT_PRICE,
INVARIANT
}
/**
* @dev Returns the time average weighted price corresponding to each of `queries`. Prices are represented as 18
* decimal fixed point values.
*/
function getTimeWeightedAverage(OracleAverageQuery[] memory queries)
external
view
returns (uint256[] memory results);
/**
* @dev Returns latest sample of `variable`. Prices are represented as 18 decimal fixed point values.
*/
function getLatest(Variable variable) external view returns (uint256);
/**
* @dev Information for a Time Weighted Average query.
*
* Each query computes the average over a window of duration `secs` seconds that ended `ago` seconds ago. For
* example, the average over the past 30 minutes is computed by settings secs to 1800 and ago to 0. If secs is 1800
* and ago is 1800 as well, the average between 60 and 30 minutes ago is computed instead.
*/
struct OracleAverageQuery {
Variable variable;
uint256 secs;
uint256 ago;
}
/**
* @dev Returns largest time window that can be safely queried, where 'safely' means the Oracle is guaranteed to be
* able to produce a result and not revert.
*
* If a query has a non-zero `ago` value, then `secs + ago` (the oldest point in time) must be smaller than this
* value for 'safe' queries.
*/
function getLargestSafeQueryWindow() external view returns (uint256);
/**
* @dev Returns the accumulators corresponding to each of `queries`.
*/
function getPastAccumulators(OracleAccumulatorQuery[] memory queries)
external
view
returns (int256[] memory results);
/**
* @dev Information for an Accumulator query.
*
* Each query estimates the accumulator at a time `ago` seconds ago.
*/
struct OracleAccumulatorQuery {
Variable variable;
uint256 ago;
}
}
interface IFlashLoanRecipient {
/**
* @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient.
*
* At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this
* call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the
* Vault, or else the entire flash loan will revert.
*
* `userData` is the same value passed in the `IVault.flashLoan` call.
*/
function receiveFlashLoan(
IERC20[] memory tokens,
uint256[] memory amounts,
uint256[] memory feeAmounts,
bytes memory userData
) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
import "@openzeppelin/contracts-0.8/utils/math/SafeMath.sol";
import "@openzeppelin/contracts-0.8/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts-0.8/utils/Address.sol";
import "@openzeppelin/contracts-0.8/token/ERC20/utils/SafeERC20.sol";
import { IBooster } from "../interfaces/IBooster.sol";
import { ILiqLocker } from "../interfaces/ILiqLocker.sol";
import { IBaseRewardPool } from "../interfaces/IBaseRewardPool.sol";
import { IRewardPool4626 } from "../interfaces/IRewardPool4626.sol";
import { ILitDepositorHelper } from "../interfaces/ILitDepositorHelper.sol";
import { IBalancerVault, IAsset, IBalancerTwapOracle } from "../interfaces/balancer/BalancerV2.sol";
// Note Oracle 0x9d43ccb1aD7E0081cC8A8F1fd54D16E54A637E30
interface IOracle {
/**
* @notice Computes the current strike price of the option
* @return price The strike price in terms of the payment token, scaled by 18 decimals.
* For example, if the payment token is $2 and the strike price is $4, the return value
* would be 2e18.
*/
function getPrice() external view returns (uint256 price);
}
// Note oLIT 0x627fee87d0D9D2c55098A06ac805Db8F98B158Aa
interface IOLit {
/**
* @notice Exercises options tokens to purchase the underlying tokens.
* @dev The options tokens are not burnt but sent to address(0) to avoid messing up the
* inflation schedule.
* The oracle may revert if it cannot give a secure result.
* @param amount The amount of options tokens to exercise
* @param maxPaymentAmount The maximum acceptable amount to pay. Used for slippage protection.
* @param recipient The recipient of the purchased underlying tokens
* @param deadline The Unix timestamp (in seconds) after which the call will revert
* @return paymentAmount The amount paid to the treasury to purchase the underlying tokens
*/
function exercise(
uint256 amount,
uint256 maxPaymentAmount,
address recipient,
uint256 deadline
) external returns (uint256 paymentAmount);
}
interface IFlashLoanSimpleReceiver {
/**
* @notice Executes an operation after receiving the flash-borrowed asset
* @dev Ensure that the contract can return the debt + premium, e.g., has
* enough funds to repay and has approved the Pool to pull the total amount
* @param asset The address of the flash-borrowed asset
* @param amount The amount of the flash-borrowed asset
* @param premium The fee of the flash-borrowed asset
* @param initiator The address of the flashloan initiator
* @param params The byte-encoded params passed when initiating the flashloan
* @return True if the execution of the operation succeeds, false otherwise
*/
function executeOperation(
address asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
) external returns (bool);
}
/**
* @title IPool
* @author Aave
* @notice Defines the basic interface for an Aave Pool.
*/
interface IPool {
/**
* @notice Allows smart contracts to access the liquidity of the pool within one transaction,
* as long as the amount taken plus a fee is returned.
* @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept
* into consideration. For further details please visit https://developers.aave.com
* @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanSimpleReceiver interface
* @param asset The address of the asset being flash-borrowed
* @param amount The amount of the asset being flash-borrowed
* @param params Variadic packed params to pass to the receiver as extra information
* @param referralCode The code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/
function flashLoanSimple(
address receiverAddress,
address asset,
uint256 amount,
bytes calldata params,
uint16 referralCode
) external;
/**
* @notice Returns the total fee on flash loans
* @return The total fee on flashloans
*/
function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128);
}
/**
* @title FlashOptionsExerciser
* @author LiquisFinance
* @notice Allows for claiming oLIT from RewardPools, exercise it and lock LIT received.
* @dev Implements AaveFlashloan in order to facilitate the conversion in one step.
*/
contract FlashOptionsExerciser is IFlashLoanSimpleReceiver {
using SafeERC20 for IERC20;
using Address for address;
using SafeMath for uint256;
address public owner;
address public immutable operator;
address public immutable liqLit;
address public immutable litDepositorHelper;
address public immutable lockerRewards;
address public immutable liqLocker;
address public immutable balVault = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;
address public immutable lit = 0xfd0205066521550D7d7AB19DA8F72bb004b4C341;
address public immutable olit = 0x627fee87d0D9D2c55098A06ac805Db8F98B158Aa;
address public immutable olitOracle = 0x9d43ccb1aD7E0081cC8A8F1fd54D16E54A637E30;
address public immutable weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public immutable aavePool = 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2;
uint16 internal referralCode; // Aave referral code
uint256 public constant basisOne = 10000;
bytes32 internal constant balancerPoolId = 0x9232a548dd9e81bac65500b5e0d918f8ba93675c000200000000000000000423;
struct LocalVariablesFlashLoan {
uint256 olitAmount;
uint256 amountToRepay;
uint256 price;
uint256 amountIn;
uint256 maxAmountIn;
uint256 amountNeeded;
uint256 wethBal;
uint256 maxGrossSlippage;
}
event OwnerUpdated(address newOwner);
event SetReferralCode(uint16 referralCode);
/**
* @param _liqLit ERC20 token minted when locking LIT to veLIT in VoterProxy through crvDepositor.
* @param _operator Booster main deposit contract; keeps track of pool info & user deposits; distributes rewards.
* @param _litDepositorHelper Converts LIT -> balBPT and then wraps to liqLIT via the crvDepositor.
* @param _lockerRewards BaseRewardPool where staking token is liqLIT
* @param _liqLocker LiqLocker contract address
*/
constructor(
address _liqLit,
address _operator,
address _litDepositorHelper,
address _lockerRewards,
address _liqLocker
) {
liqLit = _liqLit;
operator = _operator;
litDepositorHelper = _litDepositorHelper;
lockerRewards = _lockerRewards;
liqLocker = _liqLocker;
owner = msg.sender;
IERC20(weth).safeApprove(olit, type(uint256).max);
IERC20(lit).safeApprove(balVault, type(uint256).max);
IERC20(lit).safeApprove(litDepositorHelper, type(uint256).max);
emit OwnerUpdated(msg.sender);
}
/**
* @notice Update the contract owner
* @param _owner the new owner
* @dev Owner is responsible for setting initial config and updating operational params
*/
function setOwner(address _owner) external {
require(msg.sender == owner, "!auth");
owner = _owner;
emit OwnerUpdated(_owner);
}
/**
* @notice User converts their olit into liqLit, sends it back to the user or stakes it in liqLit staking
* @param _amount The amount of oLIT to exercise and lock
* @param _stake Stake liqLit into the liqLit staking rewards pool
* @param _minExchangeRate The minimal accepted oLIT to BAL-20WETH-80LIT exchange rate
* @return claimed The amount of BAL-20WETH-80LIT claimed and locked
*/
function exerciseAndLock(
uint256 _amount,
bool _stake,
uint256 _minExchangeRate
) external returns (uint256 claimed) {
IERC20(olit).safeTransferFrom(msg.sender, address(this), _amount);
// convert oLIT to LIT by exercising the option
_exerciseOptions(_amount);
// convert lit to liqLit, send it to sender or stake it in liqLit staking
claimed = _convertLitToLiqLit(_amount, _minExchangeRate, _stake);
}
/**
* @notice User claims their olit from different pools, converts into lit and sends it back to the user
* @param _pids Booster pools ids array to claim rewards from
* @param _locker Boolean that indicates if the user is staking in lockerRewards (BaseRewardPool)
* @param _liqLocker Boolean that indicates if the user is locking Liq in LiqLocker
* @param _minExchangeRate The minimal accepted oLIT to BAL-20WETH-80LIT exchange rate
* @return claimed The amount of LIT claimed and sent to caller
*/
function claimAndExercise(
uint256[] memory _pids,
bool _locker,
bool _liqLocker,
uint256 _minExchangeRate
) external returns (uint256 claimed) {
uint256 olitAmount = 0;
for (uint256 i = 0; i < _pids.length; i++) {
IBooster.PoolInfo memory pool = IBooster(operator).poolInfo(_pids[i]);
// claim all the rewards, only olit is sent here, the rest directly to sender
olitAmount += IBaseRewardPool(pool.crvRewards).getRewardFor(msg.sender, true);
}
if (_locker) {
olitAmount += IBaseRewardPool(lockerRewards).getRewardFor(msg.sender, true);
}
if (_liqLocker) {
olitAmount += ILiqLocker(liqLocker).getRewardFor(msg.sender);
}
// convert oLIT to LIT by exercising the option
_exerciseOptions(olitAmount);
// send lit to sender
claimed = _transferLitToSender(olitAmount, _minExchangeRate);
}
/**
* @notice User claims their olit from pool, converts into liqLit and sends it back to the user
* @param _pids Booster pools ids array to claim rewards from
* @param _locker Boolean that indicates if the user is staking in lockerRewards (BaseRewardPool)
* @param _liqLocker Boolean that indicates if the user is locking Liq in LiqLocker
* @param _stake Stake liqLit into the liqLit staking rewards pool
* @param _minExchangeRate The minimal accepted oLIT to BAL-20WETH-80LIT exchange rate
* @return claimed The amount of BAL-20WETH-80LIT rewards claimed and locked
*/
function claimAndLock(
uint256[] memory _pids,
bool _locker,
bool _liqLocker,
bool _stake,
uint256 _minExchangeRate
) external returns (uint256 claimed) {
uint256 olitAmount = 0;
for (uint256 i = 0; i < _pids.length; i++) {
IBooster.PoolInfo memory pool = IBooster(operator).poolInfo(_pids[i]);
// claim all the rewards, only olit is sent here, the rest directly to sender
olitAmount += IBaseRewardPool(pool.crvRewards).getRewardFor(msg.sender, true);
}
if (_locker) {
olitAmount += IBaseRewardPool(lockerRewards).getRewardFor(msg.sender, true);
}
if (_liqLocker) {
olitAmount += ILiqLocker(liqLocker).getRewardFor(msg.sender);
}
// convert oLIT to LIT by exercising the option
_exerciseOptions(olitAmount);
// convert lit to liqLit, send it to sender or stake it in liqLit staking
claimed = _convertLitToLiqLit(olitAmount, _minExchangeRate, _stake);
}
/**
* @notice Withdraw Bunni LpTokens, claim oLIT, convert into liqLit and sends it back to the user
* @param _pids Booster pools ids array to claim rewards from
* @param _locker Boolean that indicates if the user is staking in lockerRewards (BaseRewardPool)
* @param _liqLocker Boolean that indicates if the user is locking Liq in LiqLocker
* @param _stake Stake liqLit into the liqLit staking rewards pool
* @param _minExchangeRate The minimal accepted oLIT to BAL-20WETH-80LIT exchange rate
* @return claimed The amount of BAL-20WETH-80LIT rewards claimed and locked
* @dev owner needs to first approve this contract as spender on the rewards pool
*/
function withdrawAndLock(
uint256[] memory _pids,
uint256[] memory _amounts,
bool _locker,
bool _liqLocker,
bool _stake,
uint256 _minExchangeRate
) external returns (uint256 claimed) {
require(_pids.length == _amounts.length, "array length missmatch");
uint256 olitAmount = 0;
for (uint256 i = 0; i < _pids.length; i++) {
IBooster.PoolInfo memory pool = IBooster(operator).poolInfo(_pids[i]);
// sender will receive the Bunni LpTokens, already unwrapped
IRewardPool4626(pool.crvRewards).withdraw(_amounts[i], msg.sender, msg.sender);
// claim all the rewards, only oLIT is sent here, the rest directly to sender
olitAmount += IBaseRewardPool(pool.crvRewards).getRewardFor(msg.sender, true);
}
if (_locker) {
olitAmount += IBaseRewardPool(lockerRewards).getRewardFor(msg.sender, true);
}
if (_liqLocker) {
olitAmount += ILiqLocker(liqLocker).getRewardFor(msg.sender);
}
// convert oLIT to LIT by exercising the option
_exerciseOptions(olitAmount);
// convert lit to liqLit, send it to sender or stake it in liqLit staking
claimed = _convertLitToLiqLit(olitAmount, _minExchangeRate, _stake);
}
/**
* @notice User claims their olit from pool, converts into liqLit and sends it back to the user
* @param account The account for which to query earned rewards
* @param _pids Booster pools ids array to claim rewards from
* @param _locker Boolean that indicates if the user is staking in lockerRewards (BaseRewardPool)
* @param _liqLocker Boolean that indicates if the user is locking Liq in LiqLocker
* @return earned_ The amount of oLIT earned
* @dev Can be used to compute _minExchangeRate among other things
*/
function earned(
address account,
uint256[] memory _pids,
bool _locker,
bool _liqLocker
) external view returns (uint256 earned_) {
for (uint256 i = 0; i < _pids.length; i++) {
IBooster.PoolInfo memory pool = IBooster(operator).poolInfo(_pids[i]);
earned_ += IBaseRewardPool(pool.crvRewards).earned(account);
}
if (_locker) {
earned_ += IBaseRewardPool(lockerRewards).earned(account);
}
if (_liqLocker) {
earned_ += ILiqLocker(liqLocker).earned(account, olit);
}
}
function _transferLitToSender(uint256 _olitAmount, uint256 _minExchangeRate) internal returns (uint256 litOut) {
uint256 minOut = (_minExchangeRate * _olitAmount) / 1e18;
litOut = IERC20(lit).balanceOf(address(this));
require(litOut >= minOut, "slipped");
if (litOut > 0) {
IERC20(lit).safeTransfer(msg.sender, litOut);
}
}
function _convertLitToLiqLit(
uint256 _olitAmount,
uint256 _minExchangeRate,
bool _stake
) internal returns (uint256 bptOut) {
uint256 minOut = (_minExchangeRate * _olitAmount) / 1e18;
uint256 claimed = IERC20(lit).balanceOf(address(this));
if (claimed > 0) {
bptOut = _stake == true
? ILitDepositorHelper(litDepositorHelper).depositFor(
msg.sender,
claimed,
minOut,
true,
lockerRewards,
lit
)
: ILitDepositorHelper(litDepositorHelper).depositFor(
msg.sender,
claimed,
minOut,
true,
address(0),
lit
);
} // otherwise bptBalance = 0
}
function _balancerSwap(
uint256 _amountOutDesired,
uint256 _maxAmountIn,
IAsset _assetIn,
IAsset _assetOut
) internal returns (uint256 tokensIn) {
IBalancerVault.SingleSwap memory singleSwap = IBalancerVault.SingleSwap(
balancerPoolId,
IBalancerVault.SwapKind.GIVEN_OUT,
_assetIn,
_assetOut,
_amountOutDesired, // amount of assetOut desired from the trade
abi.encode(0)
);
tokensIn = IBalancerVault(balVault).swap(
singleSwap,
IBalancerVault.FundManagement(address(this), false, payable(address(this)), false),
_maxAmountIn, // limit amountIn we are willing to swap
block.timestamp
);
}
function _exerciseOptions(uint256 _olitAmount) internal {
if (_olitAmount == 0) return;
// amount of weth needed to process the olit, rounded up
uint256 amount = (_olitAmount * IOracle(olitOracle).getPrice()) / 1e18 + 1;
// encode _olitAmount to avoid an extra balanceOf call in next function
bytes memory userData = abi.encode(_olitAmount);
IPool(aavePool).flashLoanSimple(address(this), weth, amount, userData, referralCode);
}
function executeOperation(
address asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
) external override returns (bool) {
require(msg.sender == aavePool, "untrusted lender");
require(initiator == address(this), "untrusted initiator");
LocalVariablesFlashLoan memory vars;
vars.olitAmount = abi.decode(params, (uint256));
// exercise oLit option burns olitAmount of oLIT and mints olitAmount of LIT
IOLit(olit).exercise(vars.olitAmount, amount, address(this), block.timestamp);
// currently flashloan fee = 5, but that could vary
vars.amountToRepay = amount.add(premium);
vars.wethBal = IERC20(weth).balanceOf(address(this));
if (vars.wethBal < vars.amountToRepay) {
vars.amountNeeded = vars.amountToRepay.sub(vars.wethBal);
// it is fine to max by balance because we control for slippage with _minExchangeRate
vars.maxAmountIn = vars.olitAmount;
// swap the necessary lit into weth, swap must start with a non-zero amount in
_balancerSwap(vars.amountNeeded, vars.maxAmountIn, IAsset(lit), IAsset(weth));
}
// repay the flashloan, aavePool will pull the tokens from the contract
IERC20(asset).safeIncreaseAllowance(aavePool, vars.amountToRepay);
return true;
}
/**
* @param _referralCode The referral code for Aave Protocol.
*/
function setReferralCode(uint16 _referralCode) external {
require(msg.sender == owner, "!auth");
referralCode = _referralCode;
emit SetReferralCode(_referralCode);
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
interface IBaseRewardPool {
function pid() external view returns (uint256);
function earned(address account) external view returns (uint256);
function stake(uint256 _amount) external returns (bool);
function stakeAll() external returns (bool);
function stakeFor(address _for, uint256 _amount) external returns (bool);
function withdraw(uint256 amount, bool claim) external returns (bool);
function withdrawAll(bool claim) external;
function withdrawAndUnwrap(uint256 amount, bool claim) external returns (bool);
function withdrawAllAndUnwrap(bool claim) external;
function getReward(address _account, bool _claimExtras) external returns (bool);
function getReward() external returns (bool);
function getRewardFor(address _account, bool _claimExtras) external returns (uint256 rewardAmount);
function processIdleRewards() external;
function queueNewRewards(uint256 _rewards) external returns (bool);
function extraRewardsLength() external view returns (uint256);
function stakingToken() external view returns (address);
function rewardToken() external view returns (address);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
interface IBooster {
struct FeeDistro {
address distro;
address rewards;
bool active;
}
function feeTokens(address _token) external returns (FeeDistro memory);
function earmarkFees(address _feeToken) external returns (bool);
struct PoolInfo {
address lptoken;
address token;
address gauge;
address crvRewards;
address stash;
bool shutdown;
}
function earmarkRewards(uint256 _pid) external returns (bool);
function poolInfo(uint256 _pid) external view returns (PoolInfo memory poolInfo);
function poolLength() external view returns (uint256);
function lockRewards() external view returns (address);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @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);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
interface ILiqLocker {
function lock(address _account, uint256 _amount) external;
function checkpointEpoch() external;
function epochCount() external view returns (uint256);
function balanceAtEpochOf(uint256 _epoch, address _user) external view returns (uint256 amount);
function totalSupplyAtEpoch(uint256 _epoch) external view returns (uint256 supply);
function queueNewRewards(address _rewardsToken, uint256 reward) external;
function getReward(address _account, bool _stake) external;
function getReward(address _account) external;
function getRewardFor(address _account) external returns (uint256 rewardAmount);
function earned(address _account, address token) external view returns (uint256 userRewards);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
interface ILitDepositorHelper {
function deposit(
uint256 _amount,
uint256 _minOut,
bool _lock,
address _stakeAddress,
address _asset
) external payable returns (uint256 bptOut);
function depositFor(
address _for,
uint256 _amount,
uint256 _minOut,
bool _lock,
address _stakeAddress,
address _asset
) external payable returns (uint256 bptOut);
function convertLitToBpt(uint256 _amount, uint256 _minOut) external returns (uint256 bptOut);
function convertWethToBpt(uint256 _amount, uint256 _minOut) external returns (uint256 bptOut);
function convertEthToBpt(uint256 _minOut) external payable returns (uint256 bptOut);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
interface IRewardPool4626 {
function withdraw(
uint256 assets,
address receiver,
address owner
) external returns (uint256 shares);
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
function asset() external view returns (address);
function balanceOf(address account) external view returns (uint256);
function processIdleRewards() external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
{
"compilationTarget": {
"contracts/peripheral/FlashOptionsExerciser.sol": "FlashOptionsExerciser"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_liqLit","type":"address"},{"internalType":"address","name":"_operator","type":"address"},{"internalType":"address","name":"_litDepositorHelper","type":"address"},{"internalType":"address","name":"_lockerRewards","type":"address"},{"internalType":"address","name":"_liqLocker","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"SetReferralCode","type":"event"},{"inputs":[],"name":"aavePool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"basisOne","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_pids","type":"uint256[]"},{"internalType":"bool","name":"_locker","type":"bool"},{"internalType":"bool","name":"_liqLocker","type":"bool"},{"internalType":"uint256","name":"_minExchangeRate","type":"uint256"}],"name":"claimAndExercise","outputs":[{"internalType":"uint256","name":"claimed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_pids","type":"uint256[]"},{"internalType":"bool","name":"_locker","type":"bool"},{"internalType":"bool","name":"_liqLocker","type":"bool"},{"internalType":"bool","name":"_stake","type":"bool"},{"internalType":"uint256","name":"_minExchangeRate","type":"uint256"}],"name":"claimAndLock","outputs":[{"internalType":"uint256","name":"claimed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256[]","name":"_pids","type":"uint256[]"},{"internalType":"bool","name":"_locker","type":"bool"},{"internalType":"bool","name":"_liqLocker","type":"bool"}],"name":"earned","outputs":[{"internalType":"uint256","name":"earned_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"premium","type":"uint256"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"bytes","name":"params","type":"bytes"}],"name":"executeOperation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_stake","type":"bool"},{"internalType":"uint256","name":"_minExchangeRate","type":"uint256"}],"name":"exerciseAndLock","outputs":[{"internalType":"uint256","name":"claimed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liqLit","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liqLocker","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lit","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"litDepositorHelper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockerRewards","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"olit","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"olitOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_referralCode","type":"uint16"}],"name":"setReferralCode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_pids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"bool","name":"_locker","type":"bool"},{"internalType":"bool","name":"_liqLocker","type":"bool"},{"internalType":"bool","name":"_stake","type":"bool"},{"internalType":"uint256","name":"_minExchangeRate","type":"uint256"}],"name":"withdrawAndLock","outputs":[{"internalType":"uint256","name":"claimed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]