Overview
ETH Balance
ETH Value
$0.00Latest 1 from a total of 1 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Automatic Loopin... | 18638424 | 9 days ago | IN | 0 ETH | 0.00000136 |
View more zero value Internal Transactions in Advanced View mode
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC3156FlashBorrower} from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {ILSTCollateralVault} from "src/interfaces/core/vaults/ILSTCollateralVault.sol";
import {IBorrowerOperations} from "src/interfaces/core/IBorrowerOperations.sol";
import {ICore} from "src/interfaces/core/ICore.sol";
import {ILeverageRouter} from "src/interfaces/periphery/ILeverageRouter.sol";
import {IDebtToken} from "src/interfaces/core/IDebtToken.sol";
import {IPositionManager} from "src/interfaces/core/IPositionManager.sol";
import {IPriceFeed} from "src/interfaces/core/IPriceFeed.sol";
import {ReentrancyGuardLib} from "src/libraries/ReentrancyGuardLib.sol";
import {UtilsLib} from "src/libraries/UtilsLib.sol";
import {SwappersLib} from "src/libraries/SwappersLib.sol";
import {PropMath} from "src/dependencies/PropMath.sol";
/**
* @title LeverageRouter
* @author Spinnaker Labs
* @notice This contract enables opening and increasing leveraged position using DebtToken's flash loans.
* @dev Whitelisted to not pay flashloan fees, and whitelisted as periphery contract to manage positions in behalf of the user.
*/
contract LeverageRouter is ILeverageRouter {
using SafeERC20 for IERC20;
using UtilsLib for bytes;
using Math for uint256;
bytes32 private constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan");
uint256 constant WAD = 1e18;
uint256 constant BP = 1e4;
IBorrowerOperations public immutable borrowerOperations;
ICore public immutable core;
IDebtToken public immutable debtToken;
IPriceFeed public immutable priceFeed;
SwappersLib.SwapperData internal swapperData;
modifier nonReentrant() {
ReentrancyGuardLib._guard();
_;
ReentrancyGuardLib._unlockGuard();
}
modifier onlyThis() {
// Only callable if inside a nonReentrant lock
ReentrancyGuardLib._internalGuard();
_;
}
modifier onlyOwner() {
if (msg.sender != core.owner()) {
revert NotOwner(msg.sender);
}
_;
}
constructor(address _borrowerOperations, address _debtToken, address _priceFeed, address[] memory _initialSwapRouters) {
if (_borrowerOperations == address(0) || _debtToken == address(0) || _priceFeed == address(0)) {
revert ZeroAddress();
}
borrowerOperations = IBorrowerOperations(_borrowerOperations);
core = borrowerOperations.CORE();
debtToken = IDebtToken(_debtToken);
priceFeed = IPriceFeed(_priceFeed);
// add routers on constructor
for (uint256 i; i < _initialSwapRouters.length; i++) {
SwappersLib.addWhitelistedSwapper(swapperData, _initialSwapRouters[i], true);
}
}
/// @inheritdoc ILeverageRouter
function automaticLoopingOpenPosition(IPositionManager positionManager, PositionLoopingParams calldata positionLoopingParams)
external
nonReentrant
{
bytes memory data = abi.encode(Action.OpenPosition, address(positionManager), positionLoopingParams, msg.sender);
uint256 flashLoanDebtTokenAmount = _getFlashLoanDebtTokenAmount(positionManager, positionLoopingParams);
if (
!debtToken.flashLoan(
IERC3156FlashBorrower(address(this)), address(debtToken), flashLoanDebtTokenAmount, data
)
) {
revert FlashLoanFailed();
}
}
/// @inheritdoc ILeverageRouter
function automaticLoopingAddCollateral(IPositionManager positionManager, PositionLoopingParams calldata positionLoopingParams)
external
nonReentrant
{
bytes memory data = abi.encode(Action.IncreaseColl, address(positionManager), positionLoopingParams, msg.sender);
uint256 flashLoanDebtTokenAmount = _getFlashLoanDebtTokenAmount(positionManager, positionLoopingParams);
if (
!debtToken.flashLoan(
IERC3156FlashBorrower(address(this)), address(debtToken), flashLoanDebtTokenAmount, data
)
) {
revert FlashLoanFailed();
}
}
function _getFlashLoanDebtTokenAmount(IPositionManager, PositionLoopingParams memory positionLoopingParams) internal view virtual returns (uint256) {
return positionLoopingParams.flashloanDebtTokenAmount;
}
function onFlashLoan(address initiator, address, /*token*/ uint256 amount, uint256, /*fee*/ bytes calldata data)
external
onlyThis
returns (bytes32)
{
if (msg.sender != address(debtToken) || initiator != address(this)) revert NotDebtToken(msg.sender);
(Action action, address positionManager, PositionLoopingParams memory params, address account) =
abi.decode(data, (Action, address, PositionLoopingParams, address));
_processFlashLoan(action, positionManager, params, account, amount);
return _RETURN_VALUE;
}
/// @inheritdoc ILeverageRouter
function claimLockedTokens(IERC20[] calldata tokens, uint256[] calldata amounts) external onlyOwner {
uint256 length = tokens.length;
for (uint256 i; i < length; ++i) {
if (address(tokens[i]) == address(0)) {
(bool success,) = core.feeReceiver().call{value: amounts[i]}("");
if (!success) {
revert NativeTokenTransferFailed();
}
} else {
tokens[i].safeTransfer(core.feeReceiver(), amounts[i]);
}
}
}
/// @inheritdoc ILeverageRouter
function calculateDebtAmount(
IPositionManager positionManager,
address position,
uint256 marginInAssets,
uint256 leverage,
uint256 minimumCR,
bool isRecoveryMode
) external view returns (uint256 debtAmount) {
if (leverage <= BP) revert("Leverage must be greater than 1");
LeverageMemory memory m;
address collVault = positionManager.collateralToken();
(m.currentColl, m.currentDebt) = positionManager.getPositionCollAndDebt(position);
m.collVaultPrice = priceFeed.fetchPrice(collVault);
m.prevICR = (m.currentColl != 0) ? PropMath._computeCR(m.currentColl, m.currentDebt, m.collVaultPrice) : 0;
m.marginInCollVault = marginInAssets != 0 ? ILSTCollateralVault(collVault).previewDeposit(marginInAssets) : 0;
{
uint256 maxLeverage = calculateMaxLeverage(
m.currentColl,
m.currentDebt,
m.marginInCollVault,
m.collVaultPrice,
minimumCR
);
if (leverage > maxLeverage) revert LeverageExceeded(leverage, maxLeverage);
}
m.additionalCollateral = (m.currentColl + m.marginInCollVault) * (leverage - BP) / BP;
if (m.additionalCollateral == 0) revert ZeroCollateral();
/// @dev Divided by DEBT_TOKEN price to increase precision of DEBT_TOKEN needed for the DEBT_TOKEN->collateral swap
debtAmount = m.additionalCollateral * m.collVaultPrice / priceFeed.fetchPrice(address(debtToken));
_check(positionManager, m, debtAmount, minimumCR, isRecoveryMode);
}
/// @inheritdoc ILeverageRouter
function calculateMaxLeverage(
uint256 currentColl,
uint256 currentDebt,
uint256 margin,
uint256 price,
uint256 minimumCR
) public pure returns (uint256 maxLeverageInBp) {
uint256 baseCollValue = (currentColl + margin) * price / WAD;
if (baseCollValue <= (minimumCR * currentDebt) / WAD) return 0;
uint256 numerator = (baseCollValue - currentDebt) * minimumCR / WAD;
uint256 denominator = (minimumCR - WAD) * baseCollValue / WAD;
maxLeverageInBp = numerator * BP / denominator;
}
function _processFlashLoan(
Action action,
address positionManager,
PositionLoopingParams memory params,
address account,
uint256 debtTokenFlashLoaned
) private {
uint256 prevStuckedDebtToken = debtToken.balanceOf(address(this)) - debtTokenFlashLoaned;
address collVault = IPositionManager(positionManager).collateralToken();
address asset = ILSTCollateralVault(collVault).asset();
if (params.marginCollAmount != 0) {
_transferFromAsset(asset, account, params.marginCollAmount);
}
uint256 collVaultShares =
_swapAndWrap(IPositionManager(positionManager), account, params, asset, collVault);
/// @dev All DEBT_TOKEN remaining is because it is stucked, which means we can productively use it to payback part of the flashloan
uint256 additionalStuckedDebtToken = debtToken.balanceOf(address(this)) - prevStuckedDebtToken;
uint256 totalDebtTokenToPayback = debtTokenFlashLoaned - additionalStuckedDebtToken;
if (action == Action.OpenPosition) {
_openPosition(positionManager, account, collVault, params.positionParams, collVaultShares, totalDebtTokenToPayback);
emit AutomaticLoopingOpenPosition(
positionManager,
account,
params.marginCollAmount,
collVaultShares,
debtTokenFlashLoaned
);
} else {
_increaseCollateral(positionManager, account, collVault, params.positionParams, collVaultShares, totalDebtTokenToPayback);
emit AutomaticLoopingAddCollateral(
positionManager,
account,
params.marginCollAmount,
collVaultShares,
debtTokenFlashLoaned
);
}
debtToken.approve(msg.sender, debtTokenFlashLoaned);
}
function _transferFromAsset(address asset, address account, uint256 margin) internal virtual {
IERC20(asset).safeTransferFrom(account, address(this), margin);
}
function _openPosition(
address positionManager,
address account,
address collVault,
PositionParams memory params,
uint256 collAmount,
uint256 debtTokenFlashLoaned
) private {
ILSTCollateralVault(collVault).approve(address(borrowerOperations), collAmount);
borrowerOperations.openPosition(
positionManager,
account,
params.maxFeePercentage,
collAmount,
debtTokenFlashLoaned,
params.upperHint,
params.lowerHint
);
}
function _increaseCollateral(
address positionManager,
address account,
address collVault,
PositionParams memory params,
uint256 collAmount,
uint256 debtTokenFlashLoaned
) private {
ILSTCollateralVault(collVault).approve(address(borrowerOperations), collAmount);
borrowerOperations.adjustPosition(
positionManager,
account,
params.maxFeePercentage,
collAmount,
0,
debtTokenFlashLoaned,
true,
params.upperHint,
params.lowerHint
);
}
function _swap(IPositionManager positionManager, address account, DexAggregatorParams memory params, address tokenIn, address tokenOut, uint256 amount)
internal
returns (uint256 tokenOutReceived)
{
(uint256 prevColl, uint256 prevDebt) = positionManager.getPositionCollAndDebt(account);
uint256 prevTokenOutBalance = IERC20(tokenOut).balanceOf(address(this));
IERC20(tokenIn).safeIncreaseAllowance(params.swapRouter, amount);
SwappersLib.executeSwap(swapperData, params.swapRouter, params.dexCalldata);
tokenOutReceived = IERC20(tokenOut).balanceOf(address(this)) - prevTokenOutBalance;
(uint256 newColl, uint256 newDebt) = positionManager.getPositionCollAndDebt(account);
if (tokenOutReceived < params.outputMin) {
revert InsufficientAssetReceived(tokenOutReceived, params.outputMin);
}
if (newColl != prevColl || newDebt != prevDebt) {
revert DebtOrCollateralChanged(newColl, newDebt, prevColl, prevDebt);
}
}
/// @dev Swaps DebtToken into an collateral asset and deposits the collateral asset into the collVault
function _swapAndWrap(
IPositionManager positionManager,
address account,
PositionLoopingParams memory params,
address asset,
address collVault
) internal virtual returns (uint256 collVaultSharesMinted) {
uint256 collAssetReceived = _swap(positionManager, account, params.debtTokenToColl, address(debtToken), asset, params.flashloanDebtTokenAmount) + params.marginCollAmount;
IERC20(asset).safeIncreaseAllowance(collVault, collAssetReceived);
collVaultSharesMinted = ILSTCollateralVault(collVault).deposit(collAssetReceived, address(this));
}
function _check(
IPositionManager positionManager,
LeverageMemory memory m,
uint256 debtAmount,
uint256 minimumCR,
bool isRecoveryMode
) private view {
uint256 gasCompensation = borrowerOperations.DEBT_GAS_COMPENSATION();
uint256 debtGasCompensation = m.currentColl == 0 ? gasCompensation : 0;
uint256 borrowingRate = isRecoveryMode ? 0 : positionManager.getBorrowingRateWithDecay();
uint256 additionalCompositeDebt = (debtAmount * (borrowingRate + WAD) / WAD);
uint256 totalNetDebt = m.currentDebt + additionalCompositeDebt;
uint256 totalCompositeDebt = totalNetDebt + debtGasCompensation;
uint256 totalCollateral = m.currentColl + m.marginInCollVault + m.additionalCollateral;
uint256 resultingICR = totalCollateral * m.collVaultPrice / totalCompositeDebt;
_checkValidCR(positionManager, minimumCR, isRecoveryMode, m, additionalCompositeDebt + debtGasCompensation, resultingICR);
uint256 minNetDebt = borrowerOperations.minNetDebt();
if (totalNetDebt - gasCompensation < minNetDebt) revert DebtTooLow(totalNetDebt, minNetDebt);
}
/// @dev Validates the minimumCR.
/// @dev This is used in the `calculateDebtAmount` function to check if the minimumCR value is valid.
function _checkValidCR(
IPositionManager positionManager,
uint256 minimumCR,
bool isRecoveryMode,
LeverageMemory memory m,
uint256 additionalDebt,
uint256 resultingICR
) private view {
if (resultingICR < minimumCR) revert PositionBelowMinimumCR(resultingICR, minimumCR);
if (isRecoveryMode) {
if (resultingICR < core.CCR()) revert CollateralRatioBelowCCR();
if (resultingICR < m.prevICR) revert PositionNotImprovedUnderRM(resultingICR, m.prevICR);
} else {
if (resultingICR < positionManager.MCR()) revert CollateralRatioBelowMCR();
(uint256 entireSystemPricedColl, uint256 entireSystemDebt) = borrowerOperations.getGlobalSystemBalances();
entireSystemPricedColl += (m.additionalCollateral + m.marginInCollVault) * m.collVaultPrice;
entireSystemDebt += additionalDebt;
uint256 newTCR = PropMath._computeCR(entireSystemPricedColl, entireSystemDebt);
uint256 CCR = borrowerOperations.CORE().CCR();
if (newTCR < CCR) revert RecoveryMode(newTCR, CCR);
}
}
function addWhitelistedSwapper(address _swapRouter, bool status) external onlyOwner {
SwappersLib.addWhitelistedSwapper(swapperData,_swapRouter, status);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (interfaces/IERC3156FlashBorrower.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC3156 FlashBorrower, as defined in
* https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
*
* _Available since v4.1._
*/
interface IERC3156FlashBorrower {
/**
* @dev Receive a flash loan.
* @param initiator The initiator of the loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param fee The additional amount of tokens to repay.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
* @return The keccak256 hash of "IERC3156FlashBorrower.onFlashLoan"
*/
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.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));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(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 (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {IBaseCollateralVault} from "./IBaseCollateralVault.sol";
import {ILSTWrapper} from "./ILSTWrapper.sol";
import {ILSTVault} from "../../utils/integrations/ILSTVault.sol";
import {EmissionsLib} from "src/libraries/EmissionsLib.sol";
interface ILSTCollateralVault is IBaseCollateralVault {
struct LSTCollVaultStorage {
uint16 minPerformanceFee;
uint16 maxPerformanceFee;
uint16 performanceFee; // over yield, in basis points
/// @dev We currently don't know the lstVault implementation, but if it were to be possible for them to remove tokens from the rewardTokens
/// There would be no need to remove it from here since the amounts should continue being accounted for in the virtual balance
EnumerableSet.AddressSet rewardedTokens;
ILSTVault _lstVault;
address mainRewardTokenVault;
address mainRewardToken;
ILSTWrapper lstWrapper;
uint96 lastUpdate;
mapping(address tokenIn => uint) threshold;
}
struct LSTInitParams {
BaseInitParams _baseParams;
uint16 _minPerformanceFee;
uint16 _maxPerformanceFee;
uint16 _performanceFee; // over yield, in basis points
ILSTVault _lstVault;
address _mainRewardTokenVault;
address _lstWrapper;
}
struct RebalanceParams {
address sentCurrency;
uint sentAmount;
address swapper;
bytes payload;
}
function rebalance(RebalanceParams calldata p) external;
function pullRewards() external;
function setUnlockRatePerSecond(address token, uint64 _unlockRatePerSecond) external;
function internalizeDonations(address[] memory tokens, uint128[] memory amounts) external;
function setPairThreshold(address tokenIn, uint thresholdInBP) external;
function setPerformanceFee(uint16 _performanceFee) external;
function setWithdrawFee(uint16 _withdrawFee) external;
function getBalance(address token) external view returns (uint);
function getBalanceOfWithFutureEmissions(address token) external view returns (uint);
function getFullProfitUnlockTimestamp(address token) external view returns (uint);
function unlockRatePerSecond(address token) external view returns (uint);
function getLockedEmissions(address token) external view returns (uint);
function getPerformanceFee() external view returns (uint16);
function rewardedTokens() external view returns (address[] memory);
function lstVault() external view returns (ILSTVault);
function mainRewardToken() external view returns (address);
function mainRewardTokenVault() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {ICore} from "./ICore.sol";
interface IBorrowerOperations {
struct Balances {
uint256[] collaterals;
uint256[] debts;
uint256[] prices;
}
event BorrowingFeePaid(address indexed borrower, uint256 amount);
event CollateralConfigured(address positionManager, address collateralToken);
event PositionCreated(address indexed _borrower, uint256 arrayIndex);
event PositionManagerRemoved(address positionManager);
event PositionUpdated(address indexed _borrower, uint256 _debt, uint256 _coll, uint256 stake, uint8 operation);
function addColl(
address positionManager,
address account,
uint256 _collateralAmount,
address _upperHint,
address _lowerHint
) external;
function adjustPosition(
address positionManager,
address account,
uint256 _maxFeePercentage,
uint256 _collDeposit,
uint256 _collWithdrawal,
uint256 _debtChange,
bool _isDebtIncrease,
address _upperHint,
address _lowerHint
) external;
function closePosition(address positionManager, address account) external;
function configureCollateral(address positionManager, address collateralToken) external;
function fetchBalances() external view returns (Balances memory balances);
function getGlobalSystemBalances() external view returns (uint256 totalPricedCollateral, uint256 totalDebt);
function getTCR() external view returns (uint256 globalTotalCollateralRatio);
function openPosition(
address positionManager,
address account,
uint256 _maxFeePercentage,
uint256 _collateralAmount,
uint256 _debtAmount,
address _upperHint,
address _lowerHint
) external;
function removePositionManager(address positionManager) external;
function repayDebt(
address positionManager,
address account,
uint256 _debtAmount,
address _upperHint,
address _lowerHint
) external;
function setDelegateApproval(address _delegate, bool _isApproved) external;
function setMinNetDebt(uint256 _minNetDebt) external;
function withdrawColl(
address positionManager,
address account,
uint256 _collWithdrawal,
address _upperHint,
address _lowerHint
) external;
function withdrawDebt(
address positionManager,
address account,
uint256 _maxFeePercentage,
uint256 _debtAmount,
address _upperHint,
address _lowerHint
) external;
function positionManagers(uint256) external view returns (address);
function checkRecoveryMode(uint256 TCR) external view returns (bool);
function DEBT_GAS_COMPENSATION() external view returns (uint256);
function DECIMAL_PRECISION() external view returns (uint256);
function PERCENT_DIVISOR() external view returns (uint256);
function CORE() external view returns (ICore);
function debtToken() external view returns (address);
function factory() external view returns (address);
function getCompositeDebt(uint256 _debt) external view returns (uint256);
function guardian() external view returns (address);
function isApprovedDelegate(address owner, address caller) external view returns (bool isApproved);
function minNetDebt() external view returns (uint256);
function owner() external view returns (address);
function positionManagersData(address) external view returns (address collateralToken, uint16 index);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IMetaCore} from "src/interfaces/core/IMetaCore.sol";
interface ICore {
// --- Public variables ---
function metaCore() external view returns (IMetaCore);
function startTime() external view returns (uint256);
function CCR() external view returns (uint256);
function dmBootstrapPeriod() external view returns (uint64);
function isPeriphery(address peripheryContract) external view returns (bool);
// --- External functions ---
function setPeripheryEnabled(address _periphery, bool _enabled) external;
function setPMBootstrapPeriod(address dm, uint64 _bootstrapPeriod) external;
function setNewCCR(uint256 _CCR) external;
function priceFeed() external view returns (address);
function owner() external view returns (address);
function pendingOwner() external view returns (address);
function guardian() external view returns (address);
function feeReceiver() external view returns (address);
function paused() external view returns (bool);
function lspBootstrapPeriod() external view returns (uint64);
function getLspEntryFee(address rebalancer) external view returns (uint16);
function getLspExitFee(address rebalancer) external view returns (uint16);
function interestProtocolShare() external view returns (uint16);
function defaultInterestReceiver() external view returns (address);
// --- Events ---
event CCRSet(uint256 initialCCR);
event PMBootstrapPeriodSet(address dm, uint64 bootstrapPeriod);
event PeripheryEnabled(address indexed periphery, bool enabled);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IERC3156FlashBorrower} from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import {IPositionManager} from "./../core/IPositionManager.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface ILeverageRouter is IERC3156FlashBorrower {
enum Action {
OpenPosition,
IncreaseColl,
RepayDebt
}
struct PositionParams {
uint256 maxFeePercentage;
address upperHint;
address lowerHint;
}
struct DexAggregatorParams {
bytes dexCalldata;
uint256 outputMin;
address swapRouter;
}
struct PositionLoopingParams {
/// @dev the amount of debtToken token to be borrowed via flashloan
uint256 flashloanDebtTokenAmount;
/// @dev the amount of the underlying asset (of CollVault) to be swapped into DebtToken tokens for repayment, along with debtAmount
uint256 marginCollAmount;
PositionParams positionParams;
DexAggregatorParams debtTokenToColl;
}
struct LeverageMemory {
uint256 currentColl;
uint256 currentDebt;
uint256 collVaultPrice;
uint256 prevICR;
uint256 marginInCollVault;
uint256 additionalCollateral;
}
error NotOwner(address sender);
error NotDebtToken(address caller);
error ZeroCollateral();
error ZeroAddress();
error FlashLoanFailed();
error InvalidDexSelector();
error CollateralRatioBelowCCR();
error CollateralRatioBelowMCR();
error InsufficientAssetReceived(uint256 assetReceived, uint256 outputMin);
error LeverageExceeded(uint256 leverage, uint256 maxLeverage);
error DebtTooLow(uint256 debtAmount, uint256 minNetDebt);
error NativeTokenTransferFailed();
error InsufficientPayBackAmount(uint256 debtTokenBalance, uint256 payBackAmount);
error PositionBelowMinimumCR(uint256 resultingCR, uint256 minimumCR);
error RecoveryMode(uint256 newTCR, uint256 CCR);
error PositionNotImprovedUnderRM(uint256 resultingICR, uint256 prevICR);
error DebtOrCollateralChanged(
uint256 currentColl,
uint256 currentDebt,
uint256 newColl,
uint256 newDebt
);
event AutomaticLoopingOpenPosition(
address indexed positionManager,
address indexed borrower,
uint256 marginCollAmount,
uint256 finalCollAmount, // after swapping debtToken to collateral
uint256 flashloanDebtTokenAmount
);
event AutomaticLoopingAddCollateral(
address indexed positionManager,
address indexed borrower,
uint256 marginCollAmount,
uint256 finalCollAmount, // after swapping debtToken to collateral
uint256 flashloanDebtTokenAmount
);
/**
* @dev Opens a leveraged position using flashloan, if internal swap has positive slippage, sends extra DEBT_TOKEN to the user
*/
function automaticLoopingOpenPosition(IPositionManager positionManager, PositionLoopingParams calldata positionLoopingParams) external;
/**
* @dev Increases a position by adding collateral using flashloan, if internal swap has positive slippage, sends extra DEBT_TOKEN to the user
*/
function automaticLoopingAddCollateral(IPositionManager positionManager, PositionLoopingParams calldata positionLoopingParams)
external;
/**
* @dev Determines the proper amount of debt tokens that can be borrowed based on the provided margin,
* desired collateral ratio (CR), and leverage.
* @param positionManager the address of PositionManager
* @param position the address of Borrower
* @param margin the asset amount to be used for the leveraged position, if the position is already opened, it can be 0
* @param leverage the leverage factor, representing how much the position is amplified relative to the margin and current collateral
* unit is in BP, where 20000 represents 2x leverage.
* @param minimumCR collateral Ratio to be applied, will be validated against a threshold tolerance of 50bp
* @param isRecoveryMode a boolean indicating whether the system is in recovery mode
* @return debtAmount the calculated amount of debt tokens that will be needed to be borrowed
*/
function calculateDebtAmount(
IPositionManager positionManager,
address position,
uint256 margin,
uint256 leverage,
uint256 minimumCR,
bool isRecoveryMode
) external view returns (uint256 debtAmount);
/**
* @dev Based on the minimum ICR a position wants to stay, calculates the maximum leverage that can be applied
* @param currentColl Amount in Collateral Vault in the position
* @param currentDebt Amount in Debt in the position
* @param margin Amount of margin to be used for the leveraged position, in the Collateral Vault
* @param price Dollar value of the collateral vault
* @param minimumCR WAD precision, e.g. 120% = 1.2e18
*/
function calculateMaxLeverage(
uint256 currentColl,
uint256 currentDebt,
uint256 margin,
uint256 price,
uint256 minimumCR
) external pure returns (uint256 maxLeverage);
/// @dev Allows owner to claim any remaining tokens, including NativeToken, stored in the router contract.
function claimLockedTokens(IERC20[] calldata tokens, uint256[] calldata amounts) external;
/// @dev Allows owner to add or remove a swap router from the whitelist.
function addWhitelistedSwapper(address _swapRouter, bool status) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC3156FlashBorrower } from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import "./ICore.sol";
interface IDebtToken is IERC20 {
// --- Events ---
event FlashLoanFeeUpdated(uint256 newFee);
// --- Public constants ---
function version() external view returns (string memory);
function permitTypeHash() external view returns (bytes32);
// --- Public immutables ---
function gasPool() external view returns (address);
function DEBT_GAS_COMPENSATION() external view returns (uint256);
// --- Public mappings ---
function liquidStabilityPools(address) external view returns (bool);
function borrowerOperations(address) external view returns (bool);
function factories(address) external view returns (bool);
function peripheries(address) external view returns (bool);
function positionManagers(address) external view returns (bool);
// --- External functions ---
function enablePositionManager(address _positionManager) external;
function mintWithGasCompensation(address _account, uint256 _amount) external returns (bool);
function burnWithGasCompensation(address _account, uint256 _amount) external returns (bool);
function mint(address _account, uint256 _amount) external;
function burn(address _account, uint256 _amount) external;
function decimals() external view returns (uint8);
function sendToPeriphery(address _sender, uint256 _amount) external;
function sendToSP(address _sender, uint256 _amount) external;
function returnFromPool(address _poolAddress, address _receiver, uint256 _amount) external;
function transfer(address recipient, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function maxFlashLoan(address token) external view returns (uint256);
function flashFee(address token, uint256 amount) external view returns (uint256);
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 amount,
bytes calldata data
) external returns (bool);
function whitelistLiquidStabilityPoolAddress(address _liquidStabilityPool, bool active) external;
function whitelistBorrowerOperationsAddress(address _borrowerOperations, bool active) external;
function whitelistFactoryAddress(address _factory, bool active) external;
function whitelistPeripheryAddress(address _periphery, bool active) external;
function whitelistPSM(address, bool) external;
function setDebtGasCompensation(uint256 _gasCompensation, bool _isFinalValue) external;
function setFlashLoanFee(uint256 _fee) external;
function DOMAIN_SEPARATOR() external view returns (bytes32);
function permit(
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC3156FlashBorrower} from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IFactory} from "./IFactory.sol";
interface IPositionManager {
event BaseRateUpdated(uint256 _baseRate);
event CollateralSent(address _to, uint256 _amount);
event LTermsUpdated(uint256 _L_collateral, uint256 _L_debt);
event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);
event Redemption(
address indexed _redeemer,
uint256 _attemptedDebtAmount,
uint256 _actualDebtAmount,
uint256 _collateralSent,
uint256 _collateralFee
);
event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);
event TotalStakesUpdated(uint256 _newTotalStakes);
event PositionIndexUpdated(address _borrower, uint256 _newIndex);
event PositionSnapshotsUpdated(uint256 _L_collateral, uint256 _L_debt);
event PositionUpdated(address indexed _borrower, uint256 _debt, uint256 _coll, uint256 _stake, uint8 _operation);
function addCollateralSurplus(address borrower, uint256 collSurplus) external;
function applyPendingRewards(address _borrower) external returns (uint256 coll, uint256 debt);
function claimCollateral(address borrower, address _receiver) external;
function closePosition(address _borrower, address _receiver, uint256 collAmount, uint256 debtAmount) external;
function closePositionByLiquidation(address _borrower) external;
function setCollVaultRouter(address _collVaultRouter) external;
function collectInterests() external;
function decayBaseRateAndGetBorrowingFee(uint256 _debt) external returns (uint256);
function decreaseDebtAndSendCollateral(address account, uint256 debt, uint256 coll) external;
function fetchPrice() external view returns (uint256);
function finalizeLiquidation(
address _liquidator,
uint256 _debt,
uint256 _coll,
uint256 _collSurplus,
uint256 _debtGasComp,
uint256 _collGasComp
) external;
function getEntireSystemBalances() external view returns (uint256, uint256, uint256);
function movePendingPositionRewardsToActiveBalances(uint256 _debt, uint256 _collateral) external;
function openPosition(
address _borrower,
uint256 _collateralAmount,
uint256 _compositeDebt,
uint256 NICR,
address _upperHint,
address _lowerHint
) external returns (uint256 stake, uint256 arrayIndex);
function redeemCollateral(
uint256 _debtAmount,
address _firstRedemptionHint,
address _upperPartialRedemptionHint,
address _lowerPartialRedemptionHint,
uint256 _partialRedemptionHintNICR,
uint256 _maxIterations,
uint256 _maxFeePercentage
) external;
function setAddresses(address _priceFeedAddress, address _sortedPositionsAddress, address _collateralToken) external;
function setParameters(
IFactory.DeploymentParams calldata _params
) external;
function setPaused(bool _paused) external;
function setPriceFeed(address _priceFeedAddress) external;
function startSunset() external;
function updateBalances() external;
function updatePositionFromAdjustment(
bool _isDebtIncrease,
uint256 _debtChange,
uint256 _netDebtChange,
bool _isCollIncrease,
uint256 _collChange,
address _upperHint,
address _lowerHint,
address _borrower,
address _receiver
) external returns (uint256, uint256, uint256);
function DEBT_GAS_COMPENSATION() external view returns (uint256);
function DECIMAL_PRECISION() external view returns (uint256);
function L_collateral() external view returns (uint256);
function L_debt() external view returns (uint256);
function MCR() external view returns (uint256);
function PERCENT_DIVISOR() external view returns (uint256);
function CORE() external view returns (address);
function SUNSETTING_INTEREST_RATE() external view returns (uint256);
function Positions(
address
)
external
view
returns (
uint256 debt,
uint256 coll,
uint256 stake,
uint8 status,
uint128 arrayIndex,
uint256 activeInterestIndex
);
function activeInterestIndex() external view returns (uint256);
function baseRate() external view returns (uint256);
function borrowerOperations() external view returns (address);
function borrowingFeeFloor() external view returns (uint256);
function collateralToken() external view returns (address);
function debtToken() external view returns (address);
function collVaultRouter() external view returns (address);
function defaultedCollateral() external view returns (uint256);
function defaultedDebt() external view returns (uint256);
function getBorrowingFee(uint256 _debt) external view returns (uint256);
function getBorrowingFeeWithDecay(uint256 _debt) external view returns (uint256);
function getBorrowingRate() external view returns (uint256);
function getBorrowingRateWithDecay() external view returns (uint256);
function getCurrentICR(address _borrower, uint256 _price) external view returns (uint256);
function getEntireDebtAndColl(
address _borrower
) external view returns (uint256 debt, uint256 coll, uint256 pendingDebtReward, uint256 pendingCollateralReward);
function getEntireSystemColl() external view returns (uint256);
function getEntireSystemDebt() external view returns (uint256);
function getNominalICR(address _borrower) external view returns (uint256);
function getPendingCollAndDebtRewards(address _borrower) external view returns (uint256, uint256);
function getRedemptionFeeWithDecay(uint256 _collateralDrawn) external view returns (uint256);
function getRedemptionRate() external view returns (uint256);
function getRedemptionRateWithDecay() external view returns (uint256);
function getTotalActiveCollateral() external view returns (uint256);
function getTotalActiveDebt() external view returns (uint256);
function getPositionCollAndDebt(address _borrower) external view returns (uint256 coll, uint256 debt);
function getPositionFromPositionOwnersArray(uint256 _index) external view returns (address);
function getPositionOwnersCount() external view returns (uint256);
function getPositionStake(address _borrower) external view returns (uint256);
function getPositionStatus(address _borrower) external view returns (uint256);
function guardian() external view returns (address);
function hasPendingRewards(address _borrower) external view returns (bool);
function interestPayable() external view returns (uint256);
function interestRate() external view returns (uint256);
function lastActiveIndexUpdate() external view returns (uint256);
function lastCollateralError_Redistribution() external view returns (uint256);
function lastDebtError_Redistribution() external view returns (uint256);
function lastFeeOperationTime() external view returns (uint256);
function liquidationManager() external view returns (address);
function maxBorrowingFee() external view returns (uint256);
function maxRedemptionFee() external view returns (uint256);
function maxSystemDebt() external view returns (uint256);
function minuteDecayFactor() external view returns (uint256);
function owner() external view returns (address);
function paused() external view returns (bool);
function priceFeed() external view returns (address);
function redemptionFeeFloor() external view returns (uint256);
function rewardSnapshots(address) external view returns (uint256 collateral, uint256 debt);
function sortedPositions() external view returns (address);
function sunsetting() external view returns (bool);
function surplusBalances(address) external view returns (uint256);
function systemDeploymentTime() external view returns (uint256);
function totalCollateralSnapshot() external view returns (uint256);
function totalStakes() external view returns (uint256);
function totalStakesSnapshot() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPriceFeed {
struct FeedType {
address spotOracle;
bool isCollVault;
}
event NewOracleRegistered(address token, address chainlinkAggregator, address underlyingDerivative);
event PriceFeedStatusUpdated(address token, address oracle, bool isWorking);
event PriceRecordUpdated(address indexed token, uint256 _price);
event NewCollVaultRegistered(address collVault, bool enable);
event NewSpotOracleRegistered(address token, address spotOracle);
function fetchPrice(address _token) external view returns (uint256);
function getMultiplePrices(address[] memory _tokens) external view returns (uint256[] memory prices);
function setOracle(
address _token,
address _chainlinkOracle,
uint32 _heartbeat,
uint16 _staleThreshold,
address underlyingDerivative
) external;
function whitelistCollateralVault(address _collateralVaultShareToken, bool enable) external;
function setSpotOracle(address _token, address _spotOracle) external;
function MAX_PRICE_DEVIATION_FROM_PREVIOUS_ROUND() external view returns (uint256);
function CORE() external view returns (address);
function RESPONSE_TIMEOUT() external view returns (uint256);
function TARGET_DIGITS() external view returns (uint256);
function guardian() external view returns (address);
function oracleRecords(
address
)
external
view
returns (
address chainLinkOracle,
uint8 decimals,
uint32 heartbeat,
uint16 staleThreshold,
address underlyingDerivative
);
function isCollVault(address _collateralVaultShareToken) external view returns (bool);
function isStableBPT(address _oracle) external view returns (bool);
function isWeightedBPT(address _oracle) external view returns (bool);
function getSpotOracle(address _token) external view returns (address);
function feedType(address _token) external view returns (FeedType memory);
function owner() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
library ReentrancyGuardLib {
error Reentrant();
error ReentrantInternal();
function _guard() internal {
bytes4 selector = Reentrant.selector;
assembly ("memory-safe") {
if tload(0) {
mstore(0, selector)
revert(0, 0x04)
}
tstore(0, 1)
}
}
function _unlockGuard() internal {
// Unlocks the guard, making the pattern composable.
// After the function exits, it can be called again, even in the same transaction.
assembly ("memory-safe") {
tstore(0, 0)
}
}
function _internalGuard() internal {
bytes4 selector = ReentrantInternal.selector;
assembly ("memory-safe") {
switch tload(0) // Reentrancy guard slot
case 1 { tstore(0, 2) } // Disable internal reentrancies
default {
mstore(0, selector)
revert(0, 0x04)
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
library UtilsLib {
function getSelector(bytes memory data) internal pure returns (bytes4 selector) {
require(data.length >= 4, "Dex calldata too short");
selector = bytes4(data);
}
function bubbleUpRevert(bytes memory reason) internal pure {
assembly {
revert(add(reason, 0x20), mload(reason))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {UtilsLib} from "src/libraries/UtilsLib.sol";
library SwappersLib {
using UtilsLib for bytes;
event SwapperAdded(address indexed swapRouter, bool status);
struct SwapperData {
mapping(address => bool) whitelistedSwappers;
}
function addWhitelistedSwapper(SwapperData storage self, address _swapRouter, bool status) internal {
self.whitelistedSwappers[_swapRouter] = status;
emit SwapperAdded(_swapRouter, status);
}
function executeSwap(SwapperData storage self, address swapRouter, bytes memory dexCalldata) internal {
require(self.whitelistedSwappers[swapRouter], "SwappersLib: swapper not whitelisted");
(bool success, bytes memory retData) = swapRouter.call(dexCalldata);
if (!success) {
retData.bubbleUpRevert();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
library PropMath {
uint256 internal constant DECIMAL_PRECISION = 1e18;
/* Precision for Nominal ICR (independent of price). Rationale for the value:
*
* - Making it “too high” could lead to overflows.
* - Making it “too low” could lead to an ICR equal to zero, due to truncation from Solidity floor division.
*
* This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39,
* and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.
*
*/
uint256 internal constant NICR_PRECISION = 1e20;
function _min(uint256 _a, uint256 _b) internal pure returns (uint256) {
return (_a < _b) ? _a : _b;
}
function _max(uint256 _a, uint256 _b) internal pure returns (uint256) {
return (_a >= _b) ? _a : _b;
}
/*
* Multiply two decimal numbers and use normal rounding rules:
* -round product up if 19'th mantissa digit >= 5
* -round product down if 19'th mantissa digit < 5
*
* Used only inside the exponentiation, _decPow().
*/
function decMul(uint256 x, uint256 y) internal pure returns (uint256 decProd) {
uint256 prod_xy = x * y;
decProd = (prod_xy + (DECIMAL_PRECISION / 2)) / DECIMAL_PRECISION;
}
/*
* _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.
*
* Uses the efficient "exponentiation by squaring" algorithm. O(log(n)) complexity.
*
* Called by two functions that represent time in units of minutes:
* 1) PositionManager._calcDecayedBaseRate
* 2) CommunityIssuance._getCumulativeIssuanceFraction
*
* The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals
* "minutes in 1000 years": 60 * 24 * 365 * 1000
*
* If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be
* negligibly different from just passing the cap, since:
*
* In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years
* In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible
*/
function _decPow(uint256 _base, uint256 _minutes) internal pure returns (uint256) {
if (_minutes > 525600000) {
_minutes = 525600000;
} // cap to avoid overflow
if (_minutes == 0) {
return DECIMAL_PRECISION;
}
uint256 y = DECIMAL_PRECISION;
uint256 x = _base;
uint256 n = _minutes;
// Exponentiation-by-squaring
while (n > 1) {
if (n % 2 == 0) {
x = decMul(x, x);
n = n / 2;
} else {
// if (n % 2 != 0)
y = decMul(x, y);
x = decMul(x, x);
n = (n - 1) / 2;
}
}
return decMul(x, y);
}
function _getAbsoluteDifference(uint256 _a, uint256 _b) internal pure returns (uint256) {
return (_a >= _b) ? _a - _b : _b - _a;
}
function _computeNominalCR(uint256 _coll, uint256 _debt) internal pure returns (uint256) {
if (_debt > 0) {
return (_coll * NICR_PRECISION) / _debt;
}
// Return the maximal value for uint256 if the Position has a debt of 0. Represents "infinite" CR.
else {
// if (_debt == 0)
return 2 ** 256 - 1;
}
}
function _computeCR(uint256 _coll, uint256 _debt, uint256 _price) internal pure returns (uint256) {
if (_debt > 0) {
uint256 newCollRatio = (_coll * _price) / _debt;
return newCollRatio;
}
// Return the maximal value for uint256 if the Position has a debt of 0. Represents "infinite" CR.
else {
// if (_debt == 0)
return 2 ** 256 - 1;
}
}
function _computeCR(uint256 _coll, uint256 _debt) internal pure returns (uint256) {
if (_debt > 0) {
uint256 newCollRatio = (_coll) / _debt;
return newCollRatio;
}
// Return the maximal value for uint256 if the Position has a debt of 0. Represents "infinite" CR.
else {
// if (_debt == 0)
return 2 ** 256 - 1;
}
}
function _isApproxEqAbs(uint256 a, uint256 b, uint256 tolerance) internal pure returns (bool) {
return a > b ? (a - b) <= tolerance : (b - a) <= tolerance;
}
function _isWithinToleranceAbove(
uint256 a,
uint256 b,
uint256 tolerance
) internal pure returns (bool) {
if (a < b) return false;
return (a - b) <= tolerance;
}
function _isWithinToleranceBelow(
uint256 a,
uint256 b,
uint256 tolerance
) internal pure returns (bool) {
if (a > b) return false;
return (b - a) <= tolerance;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @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
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://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 functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IERC4626, IERC20} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {IPositionManager} from "../IPositionManager.sol";
import {IMetaCore} from "../IMetaCore.sol";
import {IPriceFeed} from "../IPriceFeed.sol";
import {EmissionsLib} from "src/libraries/EmissionsLib.sol";
interface IBaseCollateralVault is IERC4626, IERC1822Proxiable {
struct BaseInitParams {
uint16 _minWithdrawFee;
uint16 _maxWithdrawFee;
uint16 _withdrawFee;
IMetaCore _metaCore;
// ERC4626
IERC20 _asset;
// ERC20
string _sharesName;
string _sharesSymbol;
}
struct BaseCollVaultStorage {
uint16 minWithdrawFee;
uint16 maxWithdrawFee;
uint16 withdrawFee; // over rewarded tokens, in basis points
uint8 assetDecimals;
IMetaCore _metaCore;
// Second mapping of this struct is usless, but it's for retrocompatibility with LSTCollateralVault
EmissionsLib.BalanceData balanceData;
}
function totalAssets() external view returns (uint); // todo: maybe remove this
function fetchPrice() external view returns (uint);
function getPrice(address token) external view returns (uint);
function receiveDonations(address[] memory tokens, uint[] memory amounts, address receiver) external;
function setWithdrawFee(uint16 _withdrawFee) external;
function getBalance(address token) external view returns (uint);
function getWithdrawFee() external view returns (uint16);
function getMetaCore() external view returns (IMetaCore);
function getPriceFeed() external view returns (IPriceFeed);
function assetDecimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
interface ILSTWrapper is IERC20 {
function metaCore() external view returns (address);
function lstCollVault() external view returns (address);
function decimals() external view returns (uint8);
function depositFor(address account, uint256 amount) external returns (bool);
function withdrawTo(address account, uint256 amount) external returns (bool);
function recover(address account) external returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface ILSTVault {
function stakingToken() external view returns (address);
function stake(uint256 amount) external;
function withdraw(uint256 amount) external;
function getReward() external;
function getRewardForUser(address account) external;
function rewardTokens(uint) external view returns (address);
function getAllRewardTokens() external view returns (address[] memory);
function earned(address account, address _rewardsToken) external view returns (uint256);
function registerVault(address stakingToken) external returns (address);
function balanceOf(address account) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
library EmissionsLib {
using SafeCast for uint256;
uint64 constant internal DEFAULT_UNLOCK_RATE = 1e11; // 10% per second
uint64 constant internal MAX_UNLOCK_RATE = 1e12; // 100%
struct BalanceData {
mapping(address token => uint) balance;
mapping(address token => EmissionSchedule) emissionSchedule;
}
struct EmissionSchedule {
uint128 emissions;
uint64 lockTimestamp;
uint64 _unlockRatePerSecond; // rate points
}
error AmountCannotBeZero();
error EmissionRateExceedsMax();
// error UnsupportedEmissionConfig();
event EmissionsAdded(address indexed token, uint128 amount);
event EmissionsSub(address indexed token, uint128 amount);
event NewUnlockRatePerSecond(address indexed token, uint64 unlockRatePerSecond);
/// @dev zero _unlockRatePerSecond parameter resets rate back to DEFAULT_UNLOCK_RATE
function setUnlockRatePerSecond(BalanceData storage $, address token, uint64 _unlockRatePerSecond) internal {
if (_unlockRatePerSecond > MAX_UNLOCK_RATE) revert EmissionRateExceedsMax();
_addEmissions($, token, 0); // update lockTimestamp and emissions
$.emissionSchedule[token]._unlockRatePerSecond = _unlockRatePerSecond;
emit NewUnlockRatePerSecond(token, _unlockRatePerSecond);
}
function addEmissions(BalanceData storage $, address token, uint128 amount) internal {
if (amount == 0) revert AmountCannotBeZero();
_addEmissions($, token, amount);
emit EmissionsAdded(token, amount);
}
function _addEmissions(BalanceData storage $, address token, uint128 amount) private {
EmissionSchedule memory schedule = $.emissionSchedule[token];
uint256 _unlockTimestamp = unlockTimestamp(schedule);
uint128 nextEmissions = (lockedEmissions(schedule, _unlockTimestamp) + amount).toUint128();
schedule.emissions = nextEmissions;
schedule.lockTimestamp = block.timestamp.toUint64();
$.balance[token] += amount;
$.emissionSchedule[token] = schedule;
}
function subEmissions(BalanceData storage $, address token, uint128 amount) internal {
if (amount == 0) revert AmountCannotBeZero();
_subEmissions($, token, amount);
emit EmissionsSub(token, amount);
}
function _subEmissions(BalanceData storage $, address token, uint128 amount) private {
EmissionSchedule memory schedule = $.emissionSchedule[token];
uint256 _unlockTimestamp = unlockTimestamp(schedule);
uint128 nextEmissions = (lockedEmissions(schedule, _unlockTimestamp) - amount).toUint128();
schedule.emissions = nextEmissions;
schedule.lockTimestamp = block.timestamp.toUint64();
$.balance[token] -= amount;
$.emissionSchedule[token] = schedule;
}
/// @dev Doesn't include locked emissions
function unlockedEmissions(EmissionSchedule memory schedule) internal view returns (uint256) {
return schedule.emissions - lockedEmissions(schedule, unlockTimestamp(schedule));
}
function balanceOfWithFutureEmissions(BalanceData storage $, address token) internal view returns (uint256) {
return $.balance[token];
}
/**
* @notice Returns the unlocked token emissions
*/
function balanceOf(BalanceData storage $, address token) internal view returns (uint256) {
EmissionSchedule memory schedule = $.emissionSchedule[token];
return $.balance[token] - lockedEmissions(schedule, unlockTimestamp(schedule));
}
/**
* @notice Returns locked emissions
*/
function lockedEmissions(EmissionSchedule memory schedule, uint256 _unlockTimestamp) internal view returns (uint256) {
if (block.timestamp >= _unlockTimestamp) {
// all emissions were unlocked
return 0;
} else {
// emissions are still unlocking, calculate the amount of already unlocked emissions
uint256 secondsSinceLockup = block.timestamp - schedule.lockTimestamp;
// design decision - use dimensionless 'unlock rate units' to unlock emissions over a fixed time window
uint256 ratePointsUnlocked = unlockRatePerSecond(schedule) * secondsSinceLockup;
// emissions remainder is designed to be added to balance in unlockTimestamp
return schedule.emissions - ratePointsUnlocked * schedule.emissions / MAX_UNLOCK_RATE;
}
}
// timestamp at which all emissions are fully unlocked
function unlockTimestamp(EmissionSchedule memory schedule) internal pure returns (uint256) {
// ceil to account for remainder seconds left after integer division
return divRoundUp(MAX_UNLOCK_RATE, unlockRatePerSecond(schedule)) + schedule.lockTimestamp;
}
function unlockRatePerSecond(EmissionSchedule memory schedule) internal pure returns (uint256) {
return schedule._unlockRatePerSecond == 0 ? DEFAULT_UNLOCK_RATE : schedule._unlockRatePerSecond;
}
function divRoundUp(uint256 dividend, uint256 divisor) internal pure returns (uint256) {
return (dividend + divisor - 1) / divisor;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IMetaCore {
// ---------------------------------
// Structures
// ---------------------------------
struct FeeInfo {
bool existsForDebtToken;
uint16 debtTokenFee;
}
struct RebalancerFeeInfo {
bool exists;
uint16 entryFee;
uint16 exitFee;
}
// ---------------------------------
// Public constants
// ---------------------------------
function OWNERSHIP_TRANSFER_DELAY() external view returns (uint256);
function DEFAULT_FLASH_LOAN_FEE() external view returns (uint16);
// ---------------------------------
// Public state variables
// ---------------------------------
function debtToken() external view returns (address);
function lspEntryFee() external view returns (uint16);
function lspExitFee() external view returns (uint16);
function interestProtocolShare() external view returns (uint16);
/// @dev Default interest receiver for all PositionManagers, unless overriden in the respective PM
function defaultInterestReceiver() external view returns (address);
function feeReceiver() external view returns (address);
function priceFeed() external view returns (address);
function owner() external view returns (address);
function pendingOwner() external view returns (address);
function ownershipTransferDeadline() external view returns (uint256);
function guardian() external view returns (address);
function paused() external view returns (bool);
function lspBootstrapPeriod() external view returns (uint64);
// ---------------------------------
// External functions
// ---------------------------------
function setFeeReceiver(address _feeReceiver) external;
function setPriceFeed(address _priceFeed) external;
function setGuardian(address _guardian) external;
/**
* @notice Global pause/unpause
* Pausing halts new deposits/borrowing across the protocol
*/
function setPaused(bool _paused) external;
/**
* @notice Extend or change the LSP bootstrap period,
* after which certain protocol mechanics change
*/
function setLspBootstrapPeriod(uint64 _bootstrapPeriod) external;
/**
* @notice Set a custom flash-loan fee for a given periphery contract
* @param _periphery Target contract that will get this custom fee
* @param _debtTokenFee Fee in basis points (bp)
* @param _existsForDebtToken Whether this custom fee is used when the caller = `debtToken`
*/
function setPeripheryFlashLoanFee(address _periphery, uint16 _debtTokenFee, bool _existsForDebtToken) external;
/**
* @notice Begin the ownership transfer process
* @param newOwner The address proposed to be the new owner
*/
function commitTransferOwnership(address newOwner) external;
/**
* @notice Finish the ownership transfer, after the mandatory delay
*/
function acceptTransferOwnership() external;
/**
* @notice Revoke a pending ownership transfer
*/
function revokeTransferOwnership() external;
/**
* @notice Look up a custom flash-loan fee for a specific periphery contract
* @param peripheryContract The contract that might have a custom fee
* @return The flash-loan fee in basis points
*/
function getPeripheryFlashLoanFee(address peripheryContract) external view returns (uint16);
/**
* @notice Set / override entry & exit fees for a special rebalancer contract
*/
function setRebalancerFee(address _rebalancer, uint16 _entryFee, uint16 _exitFee) external;
/**
* @notice Set the LSP entry fee globally
* @param _fee Fee in basis points
*/
function setEntryFee(uint16 _fee) external;
/**
* @notice Set the LSP exit fee globally
* @param _fee Fee in basis points
*/
function setExitFee(uint16 _fee) external;
/**
* @notice Set the interest protocol share globally to all PositionManagers
* @param _interestProtocolShare Share in basis points
*/
function setInterestProtocolShare(uint16 _interestProtocolShare) external;
/**
* @notice Look up the LSP entry fee for a rebalancer
* @param rebalancer Possibly has a special fee
* @return The entry fee in basis points
*/
function getLspEntryFee(address rebalancer) external view returns (uint16);
/**
* @notice Look up the LSP exit fee for a rebalancer
* @param rebalancer Possibly has a special fee
* @return The exit fee in basis points
*/
function getLspExitFee(address rebalancer) external view returns (uint16);
// ---------------------------------
// Events
// ---------------------------------
event NewOwnerCommitted(address indexed owner, address indexed pendingOwner, uint256 deadline);
event NewOwnerAccepted(address indexed oldOwner, address indexed newOwner);
event NewOwnerRevoked(address indexed owner, address indexed revokedOwner);
event FeeReceiverSet(address indexed feeReceiver);
event PriceFeedSet(address indexed priceFeed);
event GuardianSet(address indexed guardian);
event PeripheryFlashLoanFee(address indexed periphery, uint16 debtTokenFee);
event LSPBootstrapPeriodSet(uint64 bootstrapPeriod);
event RebalancerFees(address indexed rebalancer, uint16 entryFee, uint16 exitFee);
event EntryFeeSet(uint16 fee);
event ExitFeeSet(uint16 fee);
event InterestProtocolShareSet(uint16 interestProtocolShare);
event DefaultInterestReceiverSet(address indexed defaultInterestReceiver);
event Paused();
event Unpaused();
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IFactory {
// commented values are suggested default parameters
struct DeploymentParams {
uint256 minuteDecayFactor; // 999037758833783000 (half life of 12 hours)
uint256 redemptionFeeFloor; // 1e18 / 1000 * 5 (0.5%)
uint256 maxRedemptionFee; // 1e18 (100%)
uint256 borrowingFeeFloor; // 1e18 / 1000 * 5 (0.5%)
uint256 maxBorrowingFee; // 1e18 / 100 * 5 (5%)
uint256 interestRateInBps; // 100 (1%)
uint256 maxDebt;
uint256 MCR; // 12 * 1e17 (120%)
address collVaultRouter; // set to address(0) if PositionManager coll is not CollateralVault
}
event NewDeployment(address collateral, address priceFeed, address positionManager, address sortedPositions);
function deployNewInstance(
address collateral,
address priceFeed,
address customPositionManagerImpl,
address customSortedPositionsImpl,
DeploymentParams calldata params,
uint64 unlockRatePerSecond,
bool forceThroughLspBalanceCheck
) external;
function setImplementations(address _positionManagerImpl, address _sortedPositionsImpl) external;
function CORE() external view returns (address);
function borrowerOperations() external view returns (address);
function debtToken() external view returns (address);
function guardian() external view returns (address);
function liquidationManager() external view returns (address);
function owner() external view returns (address);
function sortedPositionsImpl() external view returns (address);
function liquidStabilityPool() external view returns (address);
function positionManagerCount() external view returns (uint256);
function positionManagerImpl() external view returns (address);
function positionManagers(uint256) external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.0;
import "../token/ERC20/IERC20.sol";
import "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*
* _Available since v4.7._
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(
uint256 assets,
address receiver,
address owner
) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: 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 v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin-upgradeable/contracts/=lib/openzeppelin-contracts-upgradeable/contracts/",
"solady/=lib/solady/src/",
"@solmate/=lib/solmate/src/",
"@chimera/=lib/chimera/src/",
"forge-std/=lib/forge-std/src/",
"@uniswap/v3-core/=lib/v3-core/",
"@uniswap/v3-periphery/=lib/v3-periphery/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"chimera/=lib/chimera/src/",
"ds-test/=lib/solmate/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"rewards/=lib/rewards/",
"solmate/=lib/solmate/src/",
"v3-core/=lib/v3-core/contracts/",
"v3-periphery/=lib/v3-periphery/contracts/"
],
"optimizer": {
"enabled": false,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_borrowerOperations","type":"address"},{"internalType":"address","name":"_debtToken","type":"address"},{"internalType":"address","name":"_priceFeed","type":"address"},{"internalType":"address[]","name":"_initialSwapRouters","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CollateralRatioBelowCCR","type":"error"},{"inputs":[],"name":"CollateralRatioBelowMCR","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentColl","type":"uint256"},{"internalType":"uint256","name":"currentDebt","type":"uint256"},{"internalType":"uint256","name":"newColl","type":"uint256"},{"internalType":"uint256","name":"newDebt","type":"uint256"}],"name":"DebtOrCollateralChanged","type":"error"},{"inputs":[{"internalType":"uint256","name":"debtAmount","type":"uint256"},{"internalType":"uint256","name":"minNetDebt","type":"uint256"}],"name":"DebtTooLow","type":"error"},{"inputs":[],"name":"FlashLoanFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"assetReceived","type":"uint256"},{"internalType":"uint256","name":"outputMin","type":"uint256"}],"name":"InsufficientAssetReceived","type":"error"},{"inputs":[{"internalType":"uint256","name":"debtTokenBalance","type":"uint256"},{"internalType":"uint256","name":"payBackAmount","type":"uint256"}],"name":"InsufficientPayBackAmount","type":"error"},{"inputs":[],"name":"InvalidDexSelector","type":"error"},{"inputs":[{"internalType":"uint256","name":"leverage","type":"uint256"},{"internalType":"uint256","name":"maxLeverage","type":"uint256"}],"name":"LeverageExceeded","type":"error"},{"inputs":[],"name":"NativeTokenTransferFailed","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"NotDebtToken","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"resultingCR","type":"uint256"},{"internalType":"uint256","name":"minimumCR","type":"uint256"}],"name":"PositionBelowMinimumCR","type":"error"},{"inputs":[{"internalType":"uint256","name":"resultingICR","type":"uint256"},{"internalType":"uint256","name":"prevICR","type":"uint256"}],"name":"PositionNotImprovedUnderRM","type":"error"},{"inputs":[{"internalType":"uint256","name":"newTCR","type":"uint256"},{"internalType":"uint256","name":"CCR","type":"uint256"}],"name":"RecoveryMode","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroCollateral","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"positionManager","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"marginCollAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"finalCollAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"flashloanDebtTokenAmount","type":"uint256"}],"name":"AutomaticLoopingAddCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"positionManager","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"marginCollAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"finalCollAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"flashloanDebtTokenAmount","type":"uint256"}],"name":"AutomaticLoopingOpenPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"swapRouter","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"SwapperAdded","type":"event"},{"inputs":[{"internalType":"address","name":"_swapRouter","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"addWhitelistedSwapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPositionManager","name":"positionManager","type":"address"},{"components":[{"internalType":"uint256","name":"flashloanDebtTokenAmount","type":"uint256"},{"internalType":"uint256","name":"marginCollAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"maxFeePercentage","type":"uint256"},{"internalType":"address","name":"upperHint","type":"address"},{"internalType":"address","name":"lowerHint","type":"address"}],"internalType":"struct ILeverageRouter.PositionParams","name":"positionParams","type":"tuple"},{"components":[{"internalType":"bytes","name":"dexCalldata","type":"bytes"},{"internalType":"uint256","name":"outputMin","type":"uint256"},{"internalType":"address","name":"swapRouter","type":"address"}],"internalType":"struct ILeverageRouter.DexAggregatorParams","name":"debtTokenToColl","type":"tuple"}],"internalType":"struct ILeverageRouter.PositionLoopingParams","name":"positionLoopingParams","type":"tuple"}],"name":"automaticLoopingAddCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPositionManager","name":"positionManager","type":"address"},{"components":[{"internalType":"uint256","name":"flashloanDebtTokenAmount","type":"uint256"},{"internalType":"uint256","name":"marginCollAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"maxFeePercentage","type":"uint256"},{"internalType":"address","name":"upperHint","type":"address"},{"internalType":"address","name":"lowerHint","type":"address"}],"internalType":"struct ILeverageRouter.PositionParams","name":"positionParams","type":"tuple"},{"components":[{"internalType":"bytes","name":"dexCalldata","type":"bytes"},{"internalType":"uint256","name":"outputMin","type":"uint256"},{"internalType":"address","name":"swapRouter","type":"address"}],"internalType":"struct ILeverageRouter.DexAggregatorParams","name":"debtTokenToColl","type":"tuple"}],"internalType":"struct ILeverageRouter.PositionLoopingParams","name":"positionLoopingParams","type":"tuple"}],"name":"automaticLoopingOpenPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowerOperations","outputs":[{"internalType":"contract IBorrowerOperations","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IPositionManager","name":"positionManager","type":"address"},{"internalType":"address","name":"position","type":"address"},{"internalType":"uint256","name":"marginInAssets","type":"uint256"},{"internalType":"uint256","name":"leverage","type":"uint256"},{"internalType":"uint256","name":"minimumCR","type":"uint256"},{"internalType":"bool","name":"isRecoveryMode","type":"bool"}],"name":"calculateDebtAmount","outputs":[{"internalType":"uint256","name":"debtAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"currentColl","type":"uint256"},{"internalType":"uint256","name":"currentDebt","type":"uint256"},{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"minimumCR","type":"uint256"}],"name":"calculateMaxLeverage","outputs":[{"internalType":"uint256","name":"maxLeverageInBp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"claimLockedTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"core","outputs":[{"internalType":"contract ICore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"debtToken","outputs":[{"internalType":"contract IDebtToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onFlashLoan","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"priceFeed","outputs":[{"internalType":"contract IPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
610100604052348015610010575f80fd5b5060405161489b38038061489b833981810160405281019061003291906104f3565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061009757505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b806100cd57505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b15610104576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff168152505060805173ffffffffffffffffffffffffffffffffffffffff16636b6c07746040518163ffffffff1660e01b8152600401602060405180830381865afa158015610183573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101a791906105ae565b73ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250508173ffffffffffffffffffffffffffffffffffffffff1660e08173ffffffffffffffffffffffffffffffffffffffff16815250505f5b8151811015610286576102795f838381518110610264576102636105d9565b5b6020026020010151600161029060201b60201c565b8080600101915050610244565b5050505050610639565b80835f015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff167f7dc49220c17ba736a5a8f465c46784ed2262884e4ea605ae95e6fd117a77a4218260405161032b9190610620565b60405180910390a2505050565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61037282610349565b9050919050565b61038281610368565b811461038c575f80fd5b50565b5f8151905061039d81610379565b92915050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6103ed826103a7565b810181811067ffffffffffffffff8211171561040c5761040b6103b7565b5b80604052505050565b5f61041e610338565b905061042a82826103e4565b919050565b5f67ffffffffffffffff821115610449576104486103b7565b5b602082029050602081019050919050565b5f80fd5b5f61047061046b8461042f565b610415565b905080838252602082019050602084028301858111156104935761049261045a565b5b835b818110156104bc57806104a8888261038f565b845260208401935050602081019050610495565b5050509392505050565b5f82601f8301126104da576104d96103a3565b5b81516104ea84826020860161045e565b91505092915050565b5f805f806080858703121561050b5761050a610341565b5b5f6105188782880161038f565b94505060206105298782880161038f565b935050604061053a8782880161038f565b925050606085015167ffffffffffffffff81111561055b5761055a610345565b5b610567878288016104c6565b91505092959194509250565b5f61057d82610368565b9050919050565b61058d81610573565b8114610597575f80fd5b50565b5f815190506105a881610584565b92915050565b5f602082840312156105c3576105c2610341565b5b5f6105d08482850161059a565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f8115159050919050565b61061a81610606565b82525050565b5f6020820190506106335f830184610611565b92915050565b60805160a05160c05160e05161418061071b5f395f818161049a01528181610627015261086a01525f818161026c015281816102a901528181610378015281816108a601528181610f7401528181610fb101528181611077015281816110f5015281816112a60152818161148801526119b701525f818161095b01528181610b4c01528181610cb401528181610e0001528181610f080152611d7401525f81816104be015281816115890152818161175501528181611abc01528181611b3c01528181611bfd01528181611c7d01528181611f36015261201201526141805ff3fe608060405234801561000f575f80fd5b50600436106100a7575f3560e01c80639573ea251161006f5780639573ea2514610163578063a6b505851461017f578063c11f5d5d146101af578063f2f4eb26146101cb578063f6038b67146101e9578063f8d8989814610205576100a7565b806323adce5f146100ab57806323e30c8b146100c7578063741bef1a146100f757806377553ad4146101155780638ca67ac914610133575b5f80fd5b6100c560048036038101906100c09190612a9d565b610223565b005b6100e160048036038101906100dc9190612bb5565b61036d565b6040516100ee9190612c63565b60405180910390f35b6100ff610498565b60405161010c9190612cd7565b60405180910390f35b61011d6104bc565b60405161012a9190612d10565b60405180910390f35b61014d60048036038101906101489190612d5e565b6104e0565b60405161015a9190612df6565b60405180910390f35b61017d60048036038101906101789190612e0f565b610959565b005b61019960048036038101906101949190612e4d565b610a64565b6040516101a69190612df6565b60405180910390f35b6101c960048036038101906101c49190612f6e565b610b4a565b005b6101d3610f06565b6040516101e0919061300c565b60405180910390f35b61020360048036038101906101fe9190612a9d565b610f2a565b005b61020d611075565b60405161021a9190613045565b60405180910390f35b61022b611099565b5f808383336040516020016102439493929190613362565b60405160208183030381529060405290505f61026884846102639061363d565b6110ba565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635cffe9de307f000000000000000000000000000000000000000000000000000000000000000084866040518563ffffffff1660e01b81526004016102e994939291906136cf565b6020604051808303815f875af1158015610305573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610329919061372d565b61035f576040517f92111eb200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50506103696110c7565b5050565b5f6103766110cc565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415806103fd57503073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614155b1561043f57336040517fef0452070000000000000000000000000000000000000000000000000000000081526004016104369190613758565b60405180910390fd5b5f805f80868681019061045291906137cf565b9350935093509350610467848484848d6110f1565b7f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd99450505050509695505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f6127108411610525576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161051c906138a9565b60405180910390fd5b61052d6129cf565b5f8873ffffffffffffffffffffffffffffffffffffffff1663b2016bd46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610577573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061059b91906138db565b90508873ffffffffffffffffffffffffffffffffffffffff1663eb7a7f7e896040518263ffffffff1660e01b81526004016105d69190613758565b6040805180830381865afa1580156105f0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610614919061391a565b835f0184602001828152508281525050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663ace1798e826040518263ffffffff1660e01b815260040161067e9190613758565b602060405180830381865afa158015610699573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106bd9190613958565b8260400181815250505f825f0151036106d6575f6106ed565b6106ec825f01518360200151846040015161152f565b5b8260600181815250505f8703610703575f61077c565b8073ffffffffffffffffffffffffffffffffffffffff1663ef8b30f7886040518263ffffffff1660e01b815260040161073c9190612df6565b602060405180830381865afa158015610757573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061077b9190613958565b5b8260800181815250505f6107a2835f01518460200151856080015186604001518a610a64565b9050808711156107eb5786816040517f6881ba1f0000000000000000000000000000000000000000000000000000000081526004016107e2929190613983565b60405180910390fd5b5061271080876107fb91906139d7565b8360800151845f015161080e9190613a0a565b6108189190613a3d565b6108229190613aab565b8260a00181815250505f8260a0015103610868576040517febb1e0ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663ace1798e7f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b81526004016108e19190613758565b602060405180830381865afa1580156108fc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109209190613958565b82604001518360a001516109349190613a3d565b61093e9190613aab565b925061094d8983858888611586565b50509695505050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109e691906138db565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a5557336040517f245aecd3000000000000000000000000000000000000000000000000000000008152600401610a4c9190613758565b60405180910390fd5b610a605f8383611844565b5050565b5f80670de0b6b3a7640000848689610a7c9190613a0a565b610a869190613a3d565b610a909190613aab565b9050670de0b6b3a76400008684610aa79190613a3d565b610ab19190613aab565b8111610ac0575f915050610b41565b5f670de0b6b3a7640000848884610ad791906139d7565b610ae19190613a3d565b610aeb9190613aab565b90505f670de0b6b3a764000083670de0b6b3a764000087610b0c91906139d7565b610b169190613a3d565b610b209190613aab565b90508061271083610b319190613a3d565b610b3b9190613aab565b93505050505b95945050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bb3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bd791906138db565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c4657336040517f245aecd3000000000000000000000000000000000000000000000000000000008152600401610c3d9190613758565b60405180910390fd5b5f8484905090505f5b81811015610efe575f73ffffffffffffffffffffffffffffffffffffffff16868683818110610c8157610c80613adb565b5b9050602002016020810190610c969190613b43565b73ffffffffffffffffffffffffffffffffffffffff1603610dfb575f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b3f006746040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d1b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d3f91906138db565b73ffffffffffffffffffffffffffffffffffffffff16858584818110610d6857610d67613adb565b5b90506020020135604051610d7b90613b9b565b5f6040518083038185875af1925050503d805f8114610db5576040519150601f19603f3d011682016040523d82523d5f602084013e610dba565b606091505b5050905080610df5576040517f3022f2e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610ef3565b610ef27f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b3f006746040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e67573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8b91906138db565b858584818110610e9e57610e9d613adb565b5b90506020020135888885818110610eb857610eb7613adb565b5b9050602002016020810190610ecd9190613b43565b73ffffffffffffffffffffffffffffffffffffffff166118ec9092919063ffffffff16565b5b806001019050610c4f565b505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b610f32611099565b5f6001838333604051602001610f4b9493929190613362565b60405160208183030381529060405290505f610f708484610f6b9061363d565b6110ba565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635cffe9de307f000000000000000000000000000000000000000000000000000000000000000084866040518563ffffffff1660e01b8152600401610ff194939291906136cf565b6020604051808303815f875af115801561100d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611031919061372d565b611067576040517f92111eb200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50506110716110c7565b5050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f63ed3ba6a660e01b90505f5c156110b357805f5260045ffd5b60015f5d50565b5f815f0151905092915050565b5f805d565b5f633c25791660e01b90505f5c600181146110e957815f5260045ffd5b60025f5d5050565b5f817f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161114c9190613758565b602060405180830381865afa158015611167573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061118b9190613958565b61119591906139d7565b90505f8573ffffffffffffffffffffffffffffffffffffffff1663b2016bd46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111e1573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061120591906138db565b90505f8173ffffffffffffffffffffffffffffffffffffffff166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611251573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061127591906138db565b90505f8660200151146112925761129181868860200151611972565b5b5f6112a088878985876119a4565b90505f847f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016112fd9190613758565b602060405180830381865afa158015611318573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061133c9190613958565b61134691906139d7565b90505f818761135591906139d7565b90505f600281111561136a5761136961305e565b5b8b600281111561137d5761137c61305e565b5b03611406576113948a89878c604001518786611a9e565b8773ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff167fceb7fc8aae017c84c14d3757032afb8d320f723f5d8f1a3274f2de722cb3f68c8b60200151868b6040516113f993929190613baf565b60405180910390a3611486565b6114188a89878c604001518786611bdf565b8773ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff167f7accea18c2c31aaa0e983d88efaa9ad7accf703abe513c864ef11835808611f48b60200151868b60405161147d93929190613baf565b60405180910390a35b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663095ea7b333896040518363ffffffff1660e01b81526004016114e1929190613be4565b6020604051808303815f875af11580156114fd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611521919061372d565b505050505050505050505050565b5f8083111561155b575f8383866115469190613a3d565b6115509190613aab565b90508091505061157f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90505b9392505050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634ba4a28b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115f0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116149190613958565b90505f80865f015114611627575f611629565b815b90505f836116a3578773ffffffffffffffffffffffffffffffffffffffff166366ca4a216040518163ffffffff1660e01b8152600401602060405180830381865afa15801561167a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061169e9190613958565b6116a5565b5f5b90505f670de0b6b3a764000080836116bd9190613a0a565b886116c89190613a3d565b6116d29190613aab565b90505f8189602001516116e59190613a0a565b90505f84826116f49190613a0a565b90505f8a60a001518b608001518c5f015161170f9190613a0a565b6117199190613a0a565b90505f828c604001518361172d9190613a3d565b6117379190613aab565b90506117528d8b8b8f8b8a61174c9190613a0a565b86611d25565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663969c24526040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117bc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117e09190613958565b90508089866117ef91906139d7565b10156118345784816040517fb9f105d700000000000000000000000000000000000000000000000000000000815260040161182b929190613983565b60405180910390fd5b5050505050505050505050505050565b80835f015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff167f7dc49220c17ba736a5a8f465c46784ed2262884e4ea605ae95e6fd117a77a421826040516118df9190613c1a565b60405180910390a2505050565b61196d8363a9059cbb60e01b848460405160240161190b929190613be4565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061215f565b505050565b61199f8230838673ffffffffffffffffffffffffffffffffffffffff16612224909392919063ffffffff16565b505050565b5f8084602001516119e0888888606001517f0000000000000000000000000000000000000000000000000000000000000000898b5f01516122ad565b6119ea9190613a0a565b9050611a1783828673ffffffffffffffffffffffffffffffffffffffff1661259e9092919063ffffffff16565b8273ffffffffffffffffffffffffffffffffffffffff16636e553f6582306040518363ffffffff1660e01b8152600401611a52929190613c33565b6020604051808303815f875af1158015611a6e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a929190613958565b91505095945050505050565b8373ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f0000000000000000000000000000000000000000000000000000000000000000846040518363ffffffff1660e01b8152600401611af9929190613be4565b6020604051808303815f875af1158015611b15573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b39919061372d565b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166326caa39d8787865f0151868689602001518a604001516040518863ffffffff1660e01b8152600401611baa9796959493929190613c5a565b5f604051808303815f87803b158015611bc1575f80fd5b505af1158015611bd3573d5f803e3d5ffd5b50505050505050505050565b8373ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f0000000000000000000000000000000000000000000000000000000000000000846040518363ffffffff1660e01b8152600401611c3a929190613be4565b6020604051808303815f875af1158015611c56573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c7a919061372d565b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639efeaeb28787865f0151865f8760018b602001518c604001516040518a63ffffffff1660e01b8152600401611cf099989796959493929190613d00565b5f604051808303815f87803b158015611d07575f80fd5b505af1158015611d19573d5f803e3d5ffd5b50505050505050505050565b84811015611d6c5780856040517ff6abf60f000000000000000000000000000000000000000000000000000000008152600401611d63929190613983565b60405180910390fd5b8315611e8c577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635733d58f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ddb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611dff9190613958565b811015611e38576040517f442afbd600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260600151811015611e87578083606001516040517f39505ed0000000000000000000000000000000000000000000000000000000008152600401611e7e929190613983565b60405180910390fd5b612157565b8573ffffffffffffffffffffffffffffffffffffffff1663794e57246040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ed5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ef99190613958565b811015611f32576040517ff6c0cbd600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663716c53c26040518163ffffffff1660e01b81526004016040805180830381865afa158015611f9c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fc0919061391a565b91509150846040015185608001518660a00151611fdd9190613a0a565b611fe79190613a3d565b82611ff29190613a0a565b915083816120009190613a0a565b90505f61200d83836126ad565b90505f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636b6c07746040518163ffffffff1660e01b8152600401602060405180830381865afa158015612079573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061209d9190613dc6565b73ffffffffffffffffffffffffffffffffffffffff16635733d58f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120e5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121099190613958565b9050808210156121525781816040517fac024a34000000000000000000000000000000000000000000000000000000008152600401612149929190613983565b60405180910390fd5b505050505b505050505050565b5f6121c0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166126f89092919063ffffffff16565b90505f8151111561221f57808060200190518101906121df919061372d565b61221e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161221590613e61565b60405180910390fd5b5b505050565b6122a7846323b872dd60e01b85858560405160240161224593929190613e7f565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061215f565b50505050565b5f805f8873ffffffffffffffffffffffffffffffffffffffff1663eb7a7f7e896040518263ffffffff1660e01b81526004016122e99190613758565b6040805180830381865afa158015612303573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612327919061391a565b915091505f8573ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016123659190613758565b602060405180830381865afa158015612380573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123a49190613958565b90506123d58860400151868973ffffffffffffffffffffffffffffffffffffffff1661259e9092919063ffffffff16565b6123e75f89604001518a5f015161270f565b808673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016124219190613758565b602060405180830381865afa15801561243c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124609190613958565b61246a91906139d7565b93505f808b73ffffffffffffffffffffffffffffffffffffffff1663eb7a7f7e8c6040518263ffffffff1660e01b81526004016124a79190613758565b6040805180830381865afa1580156124c1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124e5919061391a565b91509150896020015186101561253857858a602001516040517fc88d2ec700000000000000000000000000000000000000000000000000000000815260040161252f929190613983565b60405180910390fd5b84821415806125475750838114155b1561258f57818186866040517ff02b7d570000000000000000000000000000000000000000000000000000000081526004016125869493929190613eb4565b60405180910390fd5b50505050509695505050505050565b5f818473ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30866040518363ffffffff1660e01b81526004016125db929190613ef7565b602060405180830381865afa1580156125f6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061261a9190613958565b6126249190613a0a565b90506126a78463095ea7b360e01b8584604051602401612645929190613be4565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061215f565b50505050565b5f808211156126ce575f82846126c39190613aab565b9050809150506126f2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90505b92915050565b606061270684845f85612819565b90509392505050565b825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16612799576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161279090613f8e565b60405180910390fd5b5f808373ffffffffffffffffffffffffffffffffffffffff16836040516127c09190613fdc565b5f604051808303815f865af19150503d805f81146127f9576040519150601f19603f3d011682016040523d82523d5f602084013e6127fe565b606091505b50915091508161281257612811816128e2565b5b5050505050565b60608247101561285e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161285590614062565b60405180910390fd5b5f808673ffffffffffffffffffffffffffffffffffffffff1685876040516128869190613fdc565b5f6040518083038185875af1925050503d805f81146128c0576040519150601f19603f3d011682016040523d82523d5f602084013e6128c5565b606091505b50915091506128d6878383876128ea565b92505050949350505050565b805160208201fd5b6060831561294b575f835103612943576129038561295e565b612942576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612939906140ca565b60405180910390fd5b5b829050612956565b6129558383612980565b5b949350505050565b5f808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5f825111156129925781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129c6919061412a565b60405180910390fd5b6040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f612a3982612a10565b9050919050565b5f612a4a82612a2f565b9050919050565b612a5a81612a40565b8114612a64575f80fd5b50565b5f81359050612a7581612a51565b92915050565b5f80fd5b5f60c08284031215612a9457612a93612a7b565b5b81905092915050565b5f8060408385031215612ab357612ab2612a08565b5b5f612ac085828601612a67565b925050602083013567ffffffffffffffff811115612ae157612ae0612a0c565b5b612aed85828601612a7f565b9150509250929050565b612b0081612a2f565b8114612b0a575f80fd5b50565b5f81359050612b1b81612af7565b92915050565b5f819050919050565b612b3381612b21565b8114612b3d575f80fd5b50565b5f81359050612b4e81612b2a565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112612b7557612b74612b54565b5b8235905067ffffffffffffffff811115612b9257612b91612b58565b5b602083019150836001820283011115612bae57612bad612b5c565b5b9250929050565b5f805f805f8060a08789031215612bcf57612bce612a08565b5b5f612bdc89828a01612b0d565b9650506020612bed89828a01612b0d565b9550506040612bfe89828a01612b40565b9450506060612c0f89828a01612b40565b935050608087013567ffffffffffffffff811115612c3057612c2f612a0c565b5b612c3c89828a01612b60565b92509250509295509295509295565b5f819050919050565b612c5d81612c4b565b82525050565b5f602082019050612c765f830184612c54565b92915050565b5f819050919050565b5f612c9f612c9a612c9584612a10565b612c7c565b612a10565b9050919050565b5f612cb082612c85565b9050919050565b5f612cc182612ca6565b9050919050565b612cd181612cb7565b82525050565b5f602082019050612cea5f830184612cc8565b92915050565b5f612cfa82612ca6565b9050919050565b612d0a81612cf0565b82525050565b5f602082019050612d235f830184612d01565b92915050565b5f8115159050919050565b612d3d81612d29565b8114612d47575f80fd5b50565b5f81359050612d5881612d34565b92915050565b5f805f805f8060c08789031215612d7857612d77612a08565b5b5f612d8589828a01612a67565b9650506020612d9689828a01612b0d565b9550506040612da789828a01612b40565b9450506060612db889828a01612b40565b9350506080612dc989828a01612b40565b92505060a0612dda89828a01612d4a565b9150509295509295509295565b612df081612b21565b82525050565b5f602082019050612e095f830184612de7565b92915050565b5f8060408385031215612e2557612e24612a08565b5b5f612e3285828601612b0d565b9250506020612e4385828601612d4a565b9150509250929050565b5f805f805f60a08688031215612e6657612e65612a08565b5b5f612e7388828901612b40565b9550506020612e8488828901612b40565b9450506040612e9588828901612b40565b9350506060612ea688828901612b40565b9250506080612eb788828901612b40565b9150509295509295909350565b5f8083601f840112612ed957612ed8612b54565b5b8235905067ffffffffffffffff811115612ef657612ef5612b58565b5b602083019150836020820283011115612f1257612f11612b5c565b5b9250929050565b5f8083601f840112612f2e57612f2d612b54565b5b8235905067ffffffffffffffff811115612f4b57612f4a612b58565b5b602083019150836020820283011115612f6757612f66612b5c565b5b9250929050565b5f805f8060408587031215612f8657612f85612a08565b5b5f85013567ffffffffffffffff811115612fa357612fa2612a0c565b5b612faf87828801612ec4565b9450945050602085013567ffffffffffffffff811115612fd257612fd1612a0c565b5b612fde87828801612f19565b925092505092959194509250565b5f612ff682612ca6565b9050919050565b61300681612fec565b82525050565b5f60208201905061301f5f830184612ffd565b92915050565b5f61302f82612ca6565b9050919050565b61303f81613025565b82525050565b5f6020820190506130585f830184613036565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6003811061309c5761309b61305e565b5b50565b5f8190506130ac8261308b565b919050565b5f6130bb8261309f565b9050919050565b6130cb816130b1565b82525050565b6130da81612a2f565b82525050565b5f6130ee6020840184612b40565b905092915050565b6130ff81612b21565b82525050565b5f82905092915050565b5f61311d6020840184612b0d565b905092915050565b61312e81612a2f565b82525050565b606082016131445f8301836130e0565b6131505f8501826130f6565b5061315e602083018361310f565b61316b6020850182613125565b50613179604083018361310f565b6131866040850182613125565b50505050565b5f80fd5b5f823560016060038336030381126131ab576131aa61318c565b5b82810191505092915050565b5f80fd5b5f80fd5b5f80833560016020038436030381126131db576131da61318c565b5b83810192508235915060208301925067ffffffffffffffff821115613203576132026131b7565b5b600182023603831315613219576132186131bb565b5b509250929050565b5f82825260208201905092915050565b828183375f83830152505050565b5f601f19601f8301169050919050565b5f61325a8385613221565b9350613267838584613231565b6132708361323f565b840190509392505050565b5f6060830161328c5f8401846131bf565b8583035f87015261329e83828461324f565b925050506132af60208401846130e0565b6132bc60208601826130f6565b506132ca604084018461310f565b6132d76040860182613125565b508091505092915050565b5f60c083016132f35f8401846130e0565b6132ff5f8601826130f6565b5061330d60208401846130e0565b61331a60208601826130f6565b506133286040840184613105565b6133356040860182613134565b5061334360a0840184613190565b84820360a0860152613355828261327b565b9150508091505092915050565b5f6080820190506133755f8301876130c2565b61338260208301866130d1565b818103604083015261339481856132e2565b90506133a360608301846130d1565b95945050505050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6133e68261323f565b810181811067ffffffffffffffff82111715613405576134046133b0565b5b80604052505050565b5f6134176129ff565b905061342382826133dd565b919050565b5f80fd5b5f60608284031215613441576134406133ac565b5b61344b606061340e565b90505f61345a84828501612b40565b5f83015250602061346d84828501612b0d565b602083015250604061348184828501612b0d565b60408301525092915050565b5f80fd5b5f67ffffffffffffffff8211156134ab576134aa6133b0565b5b6134b48261323f565b9050602081019050919050565b5f6134d36134ce84613491565b61340e565b9050828152602081018484840111156134ef576134ee61348d565b5b6134fa848285613231565b509392505050565b5f82601f83011261351657613515612b54565b5b81356135268482602086016134c1565b91505092915050565b5f60608284031215613544576135436133ac565b5b61354e606061340e565b90505f82013567ffffffffffffffff81111561356d5761356c613428565b5b61357984828501613502565b5f83015250602061358c84828501612b40565b60208301525060406135a084828501612b0d565b60408301525092915050565b5f60c082840312156135c1576135c06133ac565b5b6135cb608061340e565b90505f6135da84828501612b40565b5f8301525060206135ed84828501612b40565b60208301525060406136018482850161342c565b60408301525060a082013567ffffffffffffffff81111561362557613624613428565b5b6136318482850161352f565b60608301525092915050565b5f61364836836135ac565b9050919050565b5f61365982612ca6565b9050919050565b6136698161364f565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f6136a18261366f565b6136ab8185613679565b93506136bb818560208601613689565b6136c48161323f565b840191505092915050565b5f6080820190506136e25f830187613660565b6136ef60208301866130d1565b6136fc6040830185612de7565b818103606083015261370e8184613697565b905095945050505050565b5f8151905061372781612d34565b92915050565b5f6020828403121561374257613741612a08565b5b5f61374f84828501613719565b91505092915050565b5f60208201905061376b5f8301846130d1565b92915050565b6003811061377d575f80fd5b50565b5f8135905061378e81613771565b92915050565b5f61379e82612a10565b9050919050565b6137ae81613794565b81146137b8575f80fd5b50565b5f813590506137c9816137a5565b92915050565b5f805f80608085870312156137e7576137e6612a08565b5b5f6137f487828801613780565b9450506020613805878288016137bb565b935050604085013567ffffffffffffffff81111561382657613825612a0c565b5b613832878288016135ac565b9250506060613843878288016137bb565b91505092959194509250565b5f82825260208201905092915050565b7f4c65766572616765206d7573742062652067726561746572207468616e2031005f82015250565b5f613893601f8361384f565b915061389e8261385f565b602082019050919050565b5f6020820190508181035f8301526138c081613887565b9050919050565b5f815190506138d581612af7565b92915050565b5f602082840312156138f0576138ef612a08565b5b5f6138fd848285016138c7565b91505092915050565b5f8151905061391481612b2a565b92915050565b5f80604083850312156139305761392f612a08565b5b5f61393d85828601613906565b925050602061394e85828601613906565b9150509250929050565b5f6020828403121561396d5761396c612a08565b5b5f61397a84828501613906565b91505092915050565b5f6040820190506139965f830185612de7565b6139a36020830184612de7565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6139e182612b21565b91506139ec83612b21565b9250828203905081811115613a0457613a036139aa565b5b92915050565b5f613a1482612b21565b9150613a1f83612b21565b9250828201905080821115613a3757613a366139aa565b5b92915050565b5f613a4782612b21565b9150613a5283612b21565b9250828202613a6081612b21565b91508282048414831517613a7757613a766139aa565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f613ab582612b21565b9150613ac083612b21565b925082613ad057613acf613a7e565b5b828204905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f613b1282612a2f565b9050919050565b613b2281613b08565b8114613b2c575f80fd5b50565b5f81359050613b3d81613b19565b92915050565b5f60208284031215613b5857613b57612a08565b5b5f613b6584828501613b2f565b91505092915050565b5f81905092915050565b50565b5f613b865f83613b6e565b9150613b9182613b78565b5f82019050919050565b5f613ba582613b7b565b9150819050919050565b5f606082019050613bc25f830186612de7565b613bcf6020830185612de7565b613bdc6040830184612de7565b949350505050565b5f604082019050613bf75f8301856130d1565b613c046020830184612de7565b9392505050565b613c1481612d29565b82525050565b5f602082019050613c2d5f830184613c0b565b92915050565b5f604082019050613c465f830185612de7565b613c5360208301846130d1565b9392505050565b5f60e082019050613c6d5f83018a6130d1565b613c7a60208301896130d1565b613c876040830188612de7565b613c946060830187612de7565b613ca16080830186612de7565b613cae60a08301856130d1565b613cbb60c08301846130d1565b98975050505050505050565b5f819050919050565b5f613cea613ce5613ce084613cc7565b612c7c565b612b21565b9050919050565b613cfa81613cd0565b82525050565b5f61012082019050613d145f83018c6130d1565b613d21602083018b6130d1565b613d2e604083018a612de7565b613d3b6060830189612de7565b613d486080830188613cf1565b613d5560a0830187612de7565b613d6260c0830186613c0b565b613d6f60e08301856130d1565b613d7d6101008301846130d1565b9a9950505050505050505050565b5f613d9582612a2f565b9050919050565b613da581613d8b565b8114613daf575f80fd5b50565b5f81519050613dc081613d9c565b92915050565b5f60208284031215613ddb57613dda612a08565b5b5f613de884828501613db2565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e5f8201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b5f613e4b602a8361384f565b9150613e5682613df1565b604082019050919050565b5f6020820190508181035f830152613e7881613e3f565b9050919050565b5f606082019050613e925f8301866130d1565b613e9f60208301856130d1565b613eac6040830184612de7565b949350505050565b5f608082019050613ec75f830187612de7565b613ed46020830186612de7565b613ee16040830185612de7565b613eee6060830184612de7565b95945050505050565b5f604082019050613f0a5f8301856130d1565b613f1760208301846130d1565b9392505050565b7f53776170706572734c69623a2073776170706572206e6f742077686974656c695f8201527f7374656400000000000000000000000000000000000000000000000000000000602082015250565b5f613f7860248361384f565b9150613f8382613f1e565b604082019050919050565b5f6020820190508181035f830152613fa581613f6c565b9050919050565b5f613fb68261366f565b613fc08185613b6e565b9350613fd0818560208601613689565b80840191505092915050565b5f613fe78284613fac565b915081905092915050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f5f8201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b5f61404c60268361384f565b915061405782613ff2565b604082019050919050565b5f6020820190508181035f83015261407981614040565b9050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000005f82015250565b5f6140b4601d8361384f565b91506140bf82614080565b602082019050919050565b5f6020820190508181035f8301526140e1816140a8565b9050919050565b5f81519050919050565b5f6140fc826140e8565b614106818561384f565b9350614116818560208601613689565b61411f8161323f565b840191505092915050565b5f6020820190508181035f83015261414281846140f2565b90509291505056fea2646970667358221220018341f2e0845ab22fca4ad193c4ce81f42aa27dbc7a2f95533a3fbebfe8c6fd64736f6c634300081a003300000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd40000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f000000000000000000000000d9069e3f3eeb45d4e05b765142ba28f3beb96f7a00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ac4c6e212a361c968f1725b4d055b47e63f80b75
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106100a7575f3560e01c80639573ea251161006f5780639573ea2514610163578063a6b505851461017f578063c11f5d5d146101af578063f2f4eb26146101cb578063f6038b67146101e9578063f8d8989814610205576100a7565b806323adce5f146100ab57806323e30c8b146100c7578063741bef1a146100f757806377553ad4146101155780638ca67ac914610133575b5f80fd5b6100c560048036038101906100c09190612a9d565b610223565b005b6100e160048036038101906100dc9190612bb5565b61036d565b6040516100ee9190612c63565b60405180910390f35b6100ff610498565b60405161010c9190612cd7565b60405180910390f35b61011d6104bc565b60405161012a9190612d10565b60405180910390f35b61014d60048036038101906101489190612d5e565b6104e0565b60405161015a9190612df6565b60405180910390f35b61017d60048036038101906101789190612e0f565b610959565b005b61019960048036038101906101949190612e4d565b610a64565b6040516101a69190612df6565b60405180910390f35b6101c960048036038101906101c49190612f6e565b610b4a565b005b6101d3610f06565b6040516101e0919061300c565b60405180910390f35b61020360048036038101906101fe9190612a9d565b610f2a565b005b61020d611075565b60405161021a9190613045565b60405180910390f35b61022b611099565b5f808383336040516020016102439493929190613362565b60405160208183030381529060405290505f61026884846102639061363d565b6110ba565b90507f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f73ffffffffffffffffffffffffffffffffffffffff16635cffe9de307f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f84866040518563ffffffff1660e01b81526004016102e994939291906136cf565b6020604051808303815f875af1158015610305573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610329919061372d565b61035f576040517f92111eb200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50506103696110c7565b5050565b5f6103766110cc565b7f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415806103fd57503073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614155b1561043f57336040517fef0452070000000000000000000000000000000000000000000000000000000081526004016104369190613758565b60405180910390fd5b5f805f80868681019061045291906137cf565b9350935093509350610467848484848d6110f1565b7f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd99450505050509695505050505050565b7f000000000000000000000000d9069e3f3eeb45d4e05b765142ba28f3beb96f7a81565b7f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd481565b5f6127108411610525576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161051c906138a9565b60405180910390fd5b61052d6129cf565b5f8873ffffffffffffffffffffffffffffffffffffffff1663b2016bd46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610577573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061059b91906138db565b90508873ffffffffffffffffffffffffffffffffffffffff1663eb7a7f7e896040518263ffffffff1660e01b81526004016105d69190613758565b6040805180830381865afa1580156105f0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610614919061391a565b835f0184602001828152508281525050507f000000000000000000000000d9069e3f3eeb45d4e05b765142ba28f3beb96f7a73ffffffffffffffffffffffffffffffffffffffff1663ace1798e826040518263ffffffff1660e01b815260040161067e9190613758565b602060405180830381865afa158015610699573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106bd9190613958565b8260400181815250505f825f0151036106d6575f6106ed565b6106ec825f01518360200151846040015161152f565b5b8260600181815250505f8703610703575f61077c565b8073ffffffffffffffffffffffffffffffffffffffff1663ef8b30f7886040518263ffffffff1660e01b815260040161073c9190612df6565b602060405180830381865afa158015610757573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061077b9190613958565b5b8260800181815250505f6107a2835f01518460200151856080015186604001518a610a64565b9050808711156107eb5786816040517f6881ba1f0000000000000000000000000000000000000000000000000000000081526004016107e2929190613983565b60405180910390fd5b5061271080876107fb91906139d7565b8360800151845f015161080e9190613a0a565b6108189190613a3d565b6108229190613aab565b8260a00181815250505f8260a0015103610868576040517febb1e0ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000d9069e3f3eeb45d4e05b765142ba28f3beb96f7a73ffffffffffffffffffffffffffffffffffffffff1663ace1798e7f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f6040518263ffffffff1660e01b81526004016108e19190613758565b602060405180830381865afa1580156108fc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109209190613958565b82604001518360a001516109349190613a3d565b61093e9190613aab565b925061094d8983858888611586565b50509695505050505050565b7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d5773ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109e691906138db565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a5557336040517f245aecd3000000000000000000000000000000000000000000000000000000008152600401610a4c9190613758565b60405180910390fd5b610a605f8383611844565b5050565b5f80670de0b6b3a7640000848689610a7c9190613a0a565b610a869190613a3d565b610a909190613aab565b9050670de0b6b3a76400008684610aa79190613a3d565b610ab19190613aab565b8111610ac0575f915050610b41565b5f670de0b6b3a7640000848884610ad791906139d7565b610ae19190613a3d565b610aeb9190613aab565b90505f670de0b6b3a764000083670de0b6b3a764000087610b0c91906139d7565b610b169190613a3d565b610b209190613aab565b90508061271083610b319190613a3d565b610b3b9190613aab565b93505050505b95945050505050565b7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d5773ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bb3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bd791906138db565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c4657336040517f245aecd3000000000000000000000000000000000000000000000000000000008152600401610c3d9190613758565b60405180910390fd5b5f8484905090505f5b81811015610efe575f73ffffffffffffffffffffffffffffffffffffffff16868683818110610c8157610c80613adb565b5b9050602002016020810190610c969190613b43565b73ffffffffffffffffffffffffffffffffffffffff1603610dfb575f7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d5773ffffffffffffffffffffffffffffffffffffffff1663b3f006746040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d1b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d3f91906138db565b73ffffffffffffffffffffffffffffffffffffffff16858584818110610d6857610d67613adb565b5b90506020020135604051610d7b90613b9b565b5f6040518083038185875af1925050503d805f8114610db5576040519150601f19603f3d011682016040523d82523d5f602084013e610dba565b606091505b5050905080610df5576040517f3022f2e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610ef3565b610ef27f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d5773ffffffffffffffffffffffffffffffffffffffff1663b3f006746040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e67573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8b91906138db565b858584818110610e9e57610e9d613adb565b5b90506020020135888885818110610eb857610eb7613adb565b5b9050602002016020810190610ecd9190613b43565b73ffffffffffffffffffffffffffffffffffffffff166118ec9092919063ffffffff16565b5b806001019050610c4f565b505050505050565b7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d5781565b610f32611099565b5f6001838333604051602001610f4b9493929190613362565b60405160208183030381529060405290505f610f708484610f6b9061363d565b6110ba565b90507f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f73ffffffffffffffffffffffffffffffffffffffff16635cffe9de307f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f84866040518563ffffffff1660e01b8152600401610ff194939291906136cf565b6020604051808303815f875af115801561100d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611031919061372d565b611067576040517f92111eb200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50506110716110c7565b5050565b7f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f81565b5f63ed3ba6a660e01b90505f5c156110b357805f5260045ffd5b60015f5d50565b5f815f0151905092915050565b5f805d565b5f633c25791660e01b90505f5c600181146110e957815f5260045ffd5b60025f5d5050565b5f817f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f73ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161114c9190613758565b602060405180830381865afa158015611167573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061118b9190613958565b61119591906139d7565b90505f8573ffffffffffffffffffffffffffffffffffffffff1663b2016bd46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111e1573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061120591906138db565b90505f8173ffffffffffffffffffffffffffffffffffffffff166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611251573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061127591906138db565b90505f8660200151146112925761129181868860200151611972565b5b5f6112a088878985876119a4565b90505f847f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f73ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016112fd9190613758565b602060405180830381865afa158015611318573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061133c9190613958565b61134691906139d7565b90505f818761135591906139d7565b90505f600281111561136a5761136961305e565b5b8b600281111561137d5761137c61305e565b5b03611406576113948a89878c604001518786611a9e565b8773ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff167fceb7fc8aae017c84c14d3757032afb8d320f723f5d8f1a3274f2de722cb3f68c8b60200151868b6040516113f993929190613baf565b60405180910390a3611486565b6114188a89878c604001518786611bdf565b8773ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff167f7accea18c2c31aaa0e983d88efaa9ad7accf703abe513c864ef11835808611f48b60200151868b60405161147d93929190613baf565b60405180910390a35b7f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f73ffffffffffffffffffffffffffffffffffffffff1663095ea7b333896040518363ffffffff1660e01b81526004016114e1929190613be4565b6020604051808303815f875af11580156114fd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611521919061372d565b505050505050505050505050565b5f8083111561155b575f8383866115469190613a3d565b6115509190613aab565b90508091505061157f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90505b9392505050565b5f7f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd473ffffffffffffffffffffffffffffffffffffffff16634ba4a28b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115f0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116149190613958565b90505f80865f015114611627575f611629565b815b90505f836116a3578773ffffffffffffffffffffffffffffffffffffffff166366ca4a216040518163ffffffff1660e01b8152600401602060405180830381865afa15801561167a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061169e9190613958565b6116a5565b5f5b90505f670de0b6b3a764000080836116bd9190613a0a565b886116c89190613a3d565b6116d29190613aab565b90505f8189602001516116e59190613a0a565b90505f84826116f49190613a0a565b90505f8a60a001518b608001518c5f015161170f9190613a0a565b6117199190613a0a565b90505f828c604001518361172d9190613a3d565b6117379190613aab565b90506117528d8b8b8f8b8a61174c9190613a0a565b86611d25565b5f7f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd473ffffffffffffffffffffffffffffffffffffffff1663969c24526040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117bc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117e09190613958565b90508089866117ef91906139d7565b10156118345784816040517fb9f105d700000000000000000000000000000000000000000000000000000000815260040161182b929190613983565b60405180910390fd5b5050505050505050505050505050565b80835f015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff167f7dc49220c17ba736a5a8f465c46784ed2262884e4ea605ae95e6fd117a77a421826040516118df9190613c1a565b60405180910390a2505050565b61196d8363a9059cbb60e01b848460405160240161190b929190613be4565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061215f565b505050565b61199f8230838673ffffffffffffffffffffffffffffffffffffffff16612224909392919063ffffffff16565b505050565b5f8084602001516119e0888888606001517f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f898b5f01516122ad565b6119ea9190613a0a565b9050611a1783828673ffffffffffffffffffffffffffffffffffffffff1661259e9092919063ffffffff16565b8273ffffffffffffffffffffffffffffffffffffffff16636e553f6582306040518363ffffffff1660e01b8152600401611a52929190613c33565b6020604051808303815f875af1158015611a6e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a929190613958565b91505095945050505050565b8373ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd4846040518363ffffffff1660e01b8152600401611af9929190613be4565b6020604051808303815f875af1158015611b15573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b39919061372d565b507f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd473ffffffffffffffffffffffffffffffffffffffff166326caa39d8787865f0151868689602001518a604001516040518863ffffffff1660e01b8152600401611baa9796959493929190613c5a565b5f604051808303815f87803b158015611bc1575f80fd5b505af1158015611bd3573d5f803e3d5ffd5b50505050505050505050565b8373ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd4846040518363ffffffff1660e01b8152600401611c3a929190613be4565b6020604051808303815f875af1158015611c56573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c7a919061372d565b507f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd473ffffffffffffffffffffffffffffffffffffffff16639efeaeb28787865f0151865f8760018b602001518c604001516040518a63ffffffff1660e01b8152600401611cf099989796959493929190613d00565b5f604051808303815f87803b158015611d07575f80fd5b505af1158015611d19573d5f803e3d5ffd5b50505050505050505050565b84811015611d6c5780856040517ff6abf60f000000000000000000000000000000000000000000000000000000008152600401611d63929190613983565b60405180910390fd5b8315611e8c577f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d5773ffffffffffffffffffffffffffffffffffffffff16635733d58f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ddb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611dff9190613958565b811015611e38576040517f442afbd600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260600151811015611e87578083606001516040517f39505ed0000000000000000000000000000000000000000000000000000000008152600401611e7e929190613983565b60405180910390fd5b612157565b8573ffffffffffffffffffffffffffffffffffffffff1663794e57246040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ed5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ef99190613958565b811015611f32576040517ff6c0cbd600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f807f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd473ffffffffffffffffffffffffffffffffffffffff1663716c53c26040518163ffffffff1660e01b81526004016040805180830381865afa158015611f9c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fc0919061391a565b91509150846040015185608001518660a00151611fdd9190613a0a565b611fe79190613a3d565b82611ff29190613a0a565b915083816120009190613a0a565b90505f61200d83836126ad565b90505f7f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd473ffffffffffffffffffffffffffffffffffffffff16636b6c07746040518163ffffffff1660e01b8152600401602060405180830381865afa158015612079573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061209d9190613dc6565b73ffffffffffffffffffffffffffffffffffffffff16635733d58f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120e5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121099190613958565b9050808210156121525781816040517fac024a34000000000000000000000000000000000000000000000000000000008152600401612149929190613983565b60405180910390fd5b505050505b505050505050565b5f6121c0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166126f89092919063ffffffff16565b90505f8151111561221f57808060200190518101906121df919061372d565b61221e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161221590613e61565b60405180910390fd5b5b505050565b6122a7846323b872dd60e01b85858560405160240161224593929190613e7f565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061215f565b50505050565b5f805f8873ffffffffffffffffffffffffffffffffffffffff1663eb7a7f7e896040518263ffffffff1660e01b81526004016122e99190613758565b6040805180830381865afa158015612303573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612327919061391a565b915091505f8573ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016123659190613758565b602060405180830381865afa158015612380573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123a49190613958565b90506123d58860400151868973ffffffffffffffffffffffffffffffffffffffff1661259e9092919063ffffffff16565b6123e75f89604001518a5f015161270f565b808673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016124219190613758565b602060405180830381865afa15801561243c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124609190613958565b61246a91906139d7565b93505f808b73ffffffffffffffffffffffffffffffffffffffff1663eb7a7f7e8c6040518263ffffffff1660e01b81526004016124a79190613758565b6040805180830381865afa1580156124c1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124e5919061391a565b91509150896020015186101561253857858a602001516040517fc88d2ec700000000000000000000000000000000000000000000000000000000815260040161252f929190613983565b60405180910390fd5b84821415806125475750838114155b1561258f57818186866040517ff02b7d570000000000000000000000000000000000000000000000000000000081526004016125869493929190613eb4565b60405180910390fd5b50505050509695505050505050565b5f818473ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30866040518363ffffffff1660e01b81526004016125db929190613ef7565b602060405180830381865afa1580156125f6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061261a9190613958565b6126249190613a0a565b90506126a78463095ea7b360e01b8584604051602401612645929190613be4565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061215f565b50505050565b5f808211156126ce575f82846126c39190613aab565b9050809150506126f2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90505b92915050565b606061270684845f85612819565b90509392505050565b825f015f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16612799576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161279090613f8e565b60405180910390fd5b5f808373ffffffffffffffffffffffffffffffffffffffff16836040516127c09190613fdc565b5f604051808303815f865af19150503d805f81146127f9576040519150601f19603f3d011682016040523d82523d5f602084013e6127fe565b606091505b50915091508161281257612811816128e2565b5b5050505050565b60608247101561285e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161285590614062565b60405180910390fd5b5f808673ffffffffffffffffffffffffffffffffffffffff1685876040516128869190613fdc565b5f6040518083038185875af1925050503d805f81146128c0576040519150601f19603f3d011682016040523d82523d5f602084013e6128c5565b606091505b50915091506128d6878383876128ea565b92505050949350505050565b805160208201fd5b6060831561294b575f835103612943576129038561295e565b612942576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612939906140ca565b60405180910390fd5b5b829050612956565b6129558383612980565b5b949350505050565b5f808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5f825111156129925781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129c6919061412a565b60405180910390fd5b6040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f612a3982612a10565b9050919050565b5f612a4a82612a2f565b9050919050565b612a5a81612a40565b8114612a64575f80fd5b50565b5f81359050612a7581612a51565b92915050565b5f80fd5b5f60c08284031215612a9457612a93612a7b565b5b81905092915050565b5f8060408385031215612ab357612ab2612a08565b5b5f612ac085828601612a67565b925050602083013567ffffffffffffffff811115612ae157612ae0612a0c565b5b612aed85828601612a7f565b9150509250929050565b612b0081612a2f565b8114612b0a575f80fd5b50565b5f81359050612b1b81612af7565b92915050565b5f819050919050565b612b3381612b21565b8114612b3d575f80fd5b50565b5f81359050612b4e81612b2a565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112612b7557612b74612b54565b5b8235905067ffffffffffffffff811115612b9257612b91612b58565b5b602083019150836001820283011115612bae57612bad612b5c565b5b9250929050565b5f805f805f8060a08789031215612bcf57612bce612a08565b5b5f612bdc89828a01612b0d565b9650506020612bed89828a01612b0d565b9550506040612bfe89828a01612b40565b9450506060612c0f89828a01612b40565b935050608087013567ffffffffffffffff811115612c3057612c2f612a0c565b5b612c3c89828a01612b60565b92509250509295509295509295565b5f819050919050565b612c5d81612c4b565b82525050565b5f602082019050612c765f830184612c54565b92915050565b5f819050919050565b5f612c9f612c9a612c9584612a10565b612c7c565b612a10565b9050919050565b5f612cb082612c85565b9050919050565b5f612cc182612ca6565b9050919050565b612cd181612cb7565b82525050565b5f602082019050612cea5f830184612cc8565b92915050565b5f612cfa82612ca6565b9050919050565b612d0a81612cf0565b82525050565b5f602082019050612d235f830184612d01565b92915050565b5f8115159050919050565b612d3d81612d29565b8114612d47575f80fd5b50565b5f81359050612d5881612d34565b92915050565b5f805f805f8060c08789031215612d7857612d77612a08565b5b5f612d8589828a01612a67565b9650506020612d9689828a01612b0d565b9550506040612da789828a01612b40565b9450506060612db889828a01612b40565b9350506080612dc989828a01612b40565b92505060a0612dda89828a01612d4a565b9150509295509295509295565b612df081612b21565b82525050565b5f602082019050612e095f830184612de7565b92915050565b5f8060408385031215612e2557612e24612a08565b5b5f612e3285828601612b0d565b9250506020612e4385828601612d4a565b9150509250929050565b5f805f805f60a08688031215612e6657612e65612a08565b5b5f612e7388828901612b40565b9550506020612e8488828901612b40565b9450506040612e9588828901612b40565b9350506060612ea688828901612b40565b9250506080612eb788828901612b40565b9150509295509295909350565b5f8083601f840112612ed957612ed8612b54565b5b8235905067ffffffffffffffff811115612ef657612ef5612b58565b5b602083019150836020820283011115612f1257612f11612b5c565b5b9250929050565b5f8083601f840112612f2e57612f2d612b54565b5b8235905067ffffffffffffffff811115612f4b57612f4a612b58565b5b602083019150836020820283011115612f6757612f66612b5c565b5b9250929050565b5f805f8060408587031215612f8657612f85612a08565b5b5f85013567ffffffffffffffff811115612fa357612fa2612a0c565b5b612faf87828801612ec4565b9450945050602085013567ffffffffffffffff811115612fd257612fd1612a0c565b5b612fde87828801612f19565b925092505092959194509250565b5f612ff682612ca6565b9050919050565b61300681612fec565b82525050565b5f60208201905061301f5f830184612ffd565b92915050565b5f61302f82612ca6565b9050919050565b61303f81613025565b82525050565b5f6020820190506130585f830184613036565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6003811061309c5761309b61305e565b5b50565b5f8190506130ac8261308b565b919050565b5f6130bb8261309f565b9050919050565b6130cb816130b1565b82525050565b6130da81612a2f565b82525050565b5f6130ee6020840184612b40565b905092915050565b6130ff81612b21565b82525050565b5f82905092915050565b5f61311d6020840184612b0d565b905092915050565b61312e81612a2f565b82525050565b606082016131445f8301836130e0565b6131505f8501826130f6565b5061315e602083018361310f565b61316b6020850182613125565b50613179604083018361310f565b6131866040850182613125565b50505050565b5f80fd5b5f823560016060038336030381126131ab576131aa61318c565b5b82810191505092915050565b5f80fd5b5f80fd5b5f80833560016020038436030381126131db576131da61318c565b5b83810192508235915060208301925067ffffffffffffffff821115613203576132026131b7565b5b600182023603831315613219576132186131bb565b5b509250929050565b5f82825260208201905092915050565b828183375f83830152505050565b5f601f19601f8301169050919050565b5f61325a8385613221565b9350613267838584613231565b6132708361323f565b840190509392505050565b5f6060830161328c5f8401846131bf565b8583035f87015261329e83828461324f565b925050506132af60208401846130e0565b6132bc60208601826130f6565b506132ca604084018461310f565b6132d76040860182613125565b508091505092915050565b5f60c083016132f35f8401846130e0565b6132ff5f8601826130f6565b5061330d60208401846130e0565b61331a60208601826130f6565b506133286040840184613105565b6133356040860182613134565b5061334360a0840184613190565b84820360a0860152613355828261327b565b9150508091505092915050565b5f6080820190506133755f8301876130c2565b61338260208301866130d1565b818103604083015261339481856132e2565b90506133a360608301846130d1565b95945050505050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6133e68261323f565b810181811067ffffffffffffffff82111715613405576134046133b0565b5b80604052505050565b5f6134176129ff565b905061342382826133dd565b919050565b5f80fd5b5f60608284031215613441576134406133ac565b5b61344b606061340e565b90505f61345a84828501612b40565b5f83015250602061346d84828501612b0d565b602083015250604061348184828501612b0d565b60408301525092915050565b5f80fd5b5f67ffffffffffffffff8211156134ab576134aa6133b0565b5b6134b48261323f565b9050602081019050919050565b5f6134d36134ce84613491565b61340e565b9050828152602081018484840111156134ef576134ee61348d565b5b6134fa848285613231565b509392505050565b5f82601f83011261351657613515612b54565b5b81356135268482602086016134c1565b91505092915050565b5f60608284031215613544576135436133ac565b5b61354e606061340e565b90505f82013567ffffffffffffffff81111561356d5761356c613428565b5b61357984828501613502565b5f83015250602061358c84828501612b40565b60208301525060406135a084828501612b0d565b60408301525092915050565b5f60c082840312156135c1576135c06133ac565b5b6135cb608061340e565b90505f6135da84828501612b40565b5f8301525060206135ed84828501612b40565b60208301525060406136018482850161342c565b60408301525060a082013567ffffffffffffffff81111561362557613624613428565b5b6136318482850161352f565b60608301525092915050565b5f61364836836135ac565b9050919050565b5f61365982612ca6565b9050919050565b6136698161364f565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f6136a18261366f565b6136ab8185613679565b93506136bb818560208601613689565b6136c48161323f565b840191505092915050565b5f6080820190506136e25f830187613660565b6136ef60208301866130d1565b6136fc6040830185612de7565b818103606083015261370e8184613697565b905095945050505050565b5f8151905061372781612d34565b92915050565b5f6020828403121561374257613741612a08565b5b5f61374f84828501613719565b91505092915050565b5f60208201905061376b5f8301846130d1565b92915050565b6003811061377d575f80fd5b50565b5f8135905061378e81613771565b92915050565b5f61379e82612a10565b9050919050565b6137ae81613794565b81146137b8575f80fd5b50565b5f813590506137c9816137a5565b92915050565b5f805f80608085870312156137e7576137e6612a08565b5b5f6137f487828801613780565b9450506020613805878288016137bb565b935050604085013567ffffffffffffffff81111561382657613825612a0c565b5b613832878288016135ac565b9250506060613843878288016137bb565b91505092959194509250565b5f82825260208201905092915050565b7f4c65766572616765206d7573742062652067726561746572207468616e2031005f82015250565b5f613893601f8361384f565b915061389e8261385f565b602082019050919050565b5f6020820190508181035f8301526138c081613887565b9050919050565b5f815190506138d581612af7565b92915050565b5f602082840312156138f0576138ef612a08565b5b5f6138fd848285016138c7565b91505092915050565b5f8151905061391481612b2a565b92915050565b5f80604083850312156139305761392f612a08565b5b5f61393d85828601613906565b925050602061394e85828601613906565b9150509250929050565b5f6020828403121561396d5761396c612a08565b5b5f61397a84828501613906565b91505092915050565b5f6040820190506139965f830185612de7565b6139a36020830184612de7565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6139e182612b21565b91506139ec83612b21565b9250828203905081811115613a0457613a036139aa565b5b92915050565b5f613a1482612b21565b9150613a1f83612b21565b9250828201905080821115613a3757613a366139aa565b5b92915050565b5f613a4782612b21565b9150613a5283612b21565b9250828202613a6081612b21565b91508282048414831517613a7757613a766139aa565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f613ab582612b21565b9150613ac083612b21565b925082613ad057613acf613a7e565b5b828204905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f613b1282612a2f565b9050919050565b613b2281613b08565b8114613b2c575f80fd5b50565b5f81359050613b3d81613b19565b92915050565b5f60208284031215613b5857613b57612a08565b5b5f613b6584828501613b2f565b91505092915050565b5f81905092915050565b50565b5f613b865f83613b6e565b9150613b9182613b78565b5f82019050919050565b5f613ba582613b7b565b9150819050919050565b5f606082019050613bc25f830186612de7565b613bcf6020830185612de7565b613bdc6040830184612de7565b949350505050565b5f604082019050613bf75f8301856130d1565b613c046020830184612de7565b9392505050565b613c1481612d29565b82525050565b5f602082019050613c2d5f830184613c0b565b92915050565b5f604082019050613c465f830185612de7565b613c5360208301846130d1565b9392505050565b5f60e082019050613c6d5f83018a6130d1565b613c7a60208301896130d1565b613c876040830188612de7565b613c946060830187612de7565b613ca16080830186612de7565b613cae60a08301856130d1565b613cbb60c08301846130d1565b98975050505050505050565b5f819050919050565b5f613cea613ce5613ce084613cc7565b612c7c565b612b21565b9050919050565b613cfa81613cd0565b82525050565b5f61012082019050613d145f83018c6130d1565b613d21602083018b6130d1565b613d2e604083018a612de7565b613d3b6060830189612de7565b613d486080830188613cf1565b613d5560a0830187612de7565b613d6260c0830186613c0b565b613d6f60e08301856130d1565b613d7d6101008301846130d1565b9a9950505050505050505050565b5f613d9582612a2f565b9050919050565b613da581613d8b565b8114613daf575f80fd5b50565b5f81519050613dc081613d9c565b92915050565b5f60208284031215613ddb57613dda612a08565b5b5f613de884828501613db2565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e5f8201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b5f613e4b602a8361384f565b9150613e5682613df1565b604082019050919050565b5f6020820190508181035f830152613e7881613e3f565b9050919050565b5f606082019050613e925f8301866130d1565b613e9f60208301856130d1565b613eac6040830184612de7565b949350505050565b5f608082019050613ec75f830187612de7565b613ed46020830186612de7565b613ee16040830185612de7565b613eee6060830184612de7565b95945050505050565b5f604082019050613f0a5f8301856130d1565b613f1760208301846130d1565b9392505050565b7f53776170706572734c69623a2073776170706572206e6f742077686974656c695f8201527f7374656400000000000000000000000000000000000000000000000000000000602082015250565b5f613f7860248361384f565b9150613f8382613f1e565b604082019050919050565b5f6020820190508181035f830152613fa581613f6c565b9050919050565b5f613fb68261366f565b613fc08185613b6e565b9350613fd0818560208601613689565b80840191505092915050565b5f613fe78284613fac565b915081905092915050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f5f8201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b5f61404c60268361384f565b915061405782613ff2565b604082019050919050565b5f6020820190508181035f83015261407981614040565b9050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000005f82015250565b5f6140b4601d8361384f565b91506140bf82614080565b602082019050919050565b5f6020820190508181035f8301526140e1816140a8565b9050919050565b5f81519050919050565b5f6140fc826140e8565b614106818561384f565b9350614116818560208601613689565b61411f8161323f565b840191505092915050565b5f6020820190508181035f83015261414281846140f2565b90509291505056fea2646970667358221220018341f2e0845ab22fca4ad193c4ce81f42aa27dbc7a2f95533a3fbebfe8c6fd64736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd40000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f000000000000000000000000d9069e3f3eeb45d4e05b765142ba28f3beb96f7a00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ac4c6e212a361c968f1725b4d055b47e63f80b75
-----Decoded View---------------
Arg [0] : _borrowerOperations (address): 0x49FD0C4fb5172b20b7636b13c49fb15dA52D5bd4
Arg [1] : _debtToken (address): 0x0F26bBb8962d73bC891327F14dB5162D5279899F
Arg [2] : _priceFeed (address): 0xD9069E3F3EEb45d4E05b765142ba28f3BeB96F7a
Arg [3] : _initialSwapRouters (address[]): 0xAC4c6e212A361c968F1725b4d055b47E63F80b75
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd4
Arg [1] : 0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f
Arg [2] : 000000000000000000000000d9069e3f3eeb45d4e05b765142ba28f3beb96f7a
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [5] : 000000000000000000000000ac4c6e212a361c968f1725b4d055b47e63f80b75
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.