Source Code
Overview
MNT Balance
MNT Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
MarginTradingHook
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
import '../common/library/InitErrors.sol';
import {UnderACM} from '../common/UnderACM.sol';
import {BaseMappingIdHook} from './BaseMappingIdHook.sol';
import {
OrderType,
OrderStatus,
SwapType,
Order,
MarginPos,
SwapInfo,
IMarginTradingHook
} from '../interfaces/hook/IMarginTradingHook.sol';
import {IWNative} from '../interfaces/common/IWNative.sol';
import {IInitCore} from '../interfaces/core/IInitCore.sol';
import {ICallbackReceiver} from '../interfaces/receiver/ICallbackReceiver.sol';
import {IMulticall} from '../interfaces/common/IMulticall.sol';
import {ILendingPool} from '../interfaces/lending_pool/ILendingPool.sol';
import {IPosManager} from '../interfaces/core/IPosManager.sol';
import {IInitOracle} from '../interfaces/oracle/IInitOracle.sol';
import {IBaseSwapHelper} from '../interfaces/helper/swap_helper/IBaseSwapHelper.sol';
import {IERC20} from '@openzeppelin-contracts/token/ERC20/IERC20.sol';
import {SafeERC20} from '@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol';
import {Math} from '@openzeppelin-contracts/utils/math/Math.sol';
/// @notice user has to be able to receive native tokens
contract MarginTradingHook is BaseMappingIdHook, UnderACM, IMarginTradingHook, ICallbackReceiver {
using SafeERC20 for IERC20;
using Math for uint;
// constants
uint private constant ONE_E18 = 1e18;
uint private constant ONE_E36 = 1e36;
bytes32 private constant GOVERNOR = keccak256('governor');
// immutables
address public immutable WNATIVE;
// storages
address public swapHelper;
mapping(address => mapping(address => address)) private __quoteAssets;
mapping(uint => Order) private __orders;
mapping(uint => MarginPos) private __marginPositions;
mapping(uint => uint[]) private __posOrderIds;
uint public lastOrderId;
// modifiers
modifier onlyGovernor() {
ACM.checkRole(GOVERNOR, msg.sender);
_;
}
// constructor
constructor(address _core, address _posManager, address _wNative, address _acm)
BaseMappingIdHook(_core, _posManager)
UnderACM(_acm)
{
WNATIVE = _wNative;
}
// initializer
function initialize(address _swapHelper) external initializer {
swapHelper = _swapHelper;
emit SetSwapHelper(_swapHelper);
}
modifier depositNative() {
if (msg.value != 0) IWNative(WNATIVE).deposit{value: msg.value}();
_;
}
modifier refundNative() {
_;
// refund native token
uint wNativeBal = IERC20(WNATIVE).balanceOf(address(this));
// NOTE: no need receive function since we will use TransparentUpgradeableProxyReceiveETH
if (wNativeBal != 0) IWNative(WNATIVE).withdraw(wNativeBal);
uint nativeBal = address(this).balance;
if (nativeBal != 0) {
(bool success,) = payable(msg.sender).call{value: nativeBal}('');
_require(success, Errors.CALL_FAILED);
}
}
// functions
/// @inheritdoc IMarginTradingHook
function openPos(
uint16 _mode,
address _viewer,
address _tokenIn,
uint _amtIn,
address _borrPool,
uint _borrAmt,
address _collPool,
bytes calldata _data,
uint _minAmtOut
) external payable depositNative refundNative returns (uint posId, uint initPosId, uint amtOut) {
initPosId = IInitCore(CORE).createPos(_mode, _viewer);
address borrToken = ILendingPool(_borrPool).underlyingToken();
{
(address baseToken, address quoteToken) = getBaseAssetAndQuoteAsset(
ILendingPool(_collPool).underlyingToken(), ILendingPool(_borrPool).underlyingToken()
);
bool isLongBaseAsset = baseToken != borrToken;
__marginPositions[initPosId] = MarginPos(_collPool, _borrPool, baseToken, quoteToken, isLongBaseAsset);
}
posId = ++lastPosIds[msg.sender];
initPosIds[msg.sender][posId] = initPosId;
amtOut = _increasePosInternal(
IncreasePosInternalParam({
initPosId: initPosId,
tokenIn: _tokenIn,
amtIn: _amtIn,
borrPool: _borrPool,
borrAmt: _borrAmt,
collPool: _collPool,
data: _data,
minAmtOut: _minAmtOut
})
);
}
/// @inheritdoc IMarginTradingHook
function increasePos(
uint _posId,
address _tokenIn,
uint _amtIn,
uint _borrAmt,
bytes calldata _data,
uint _minAmtOut
) external payable depositNative refundNative returns (uint amtOut) {
uint initPosId = initPosIds[msg.sender][_posId];
_require(initPosId != 0, Errors.POSITION_NOT_FOUND);
MarginPos storage marginPos = __marginPositions[initPosId];
amtOut = _increasePosInternal(
IncreasePosInternalParam({
initPosId: initPosId,
tokenIn: _tokenIn,
amtIn: _amtIn,
borrPool: marginPos.borrPool,
borrAmt: _borrAmt,
collPool: marginPos.collPool,
data: _data,
minAmtOut: _minAmtOut
})
);
}
/// @dev increase margin pos internal logic
function _increasePosInternal(IncreasePosInternalParam memory _param) internal returns (uint amtOut) {
_transmitTokenIn(_param.tokenIn, _param.amtIn);
// perform multicall to INIT core:
// 1. borrow tokens
// 2. callback (perform swap from borr -> coll)
// 3. deposit collateral tokens
// 4. collateralize tokens
bytes[] memory multicallData = new bytes[](4);
multicallData[0] = abi.encodeWithSelector(
IInitCore(CORE).borrow.selector, _param.borrPool, _param.borrAmt, _param.initPosId, address(this)
);
address collToken = ILendingPool(_param.collPool).underlyingToken();
address borrToken = ILendingPool(_param.borrPool).underlyingToken();
_require(_param.tokenIn == collToken || _param.tokenIn == borrToken, Errors.INVALID_INPUT);
{
SwapInfo memory swapInfo =
SwapInfo(_param.initPosId, SwapType.OpenExactIn, borrToken, collToken, _param.minAmtOut, _param.data);
multicallData[1] =
abi.encodeWithSelector(IInitCore(CORE).callback.selector, address(this), 0, abi.encode(swapInfo));
}
multicallData[2] = abi.encodeWithSelector(IInitCore(CORE).mintTo.selector, _param.collPool, POS_MANAGER);
multicallData[3] =
abi.encodeWithSelector(IInitCore(CORE).collateralize.selector, _param.initPosId, _param.collPool);
// do multicall
bytes[] memory results = IMulticall(CORE).multicall(multicallData);
amtOut = abi.decode(abi.decode(results[1], (bytes)), (uint));
emit IncreasePos(_param.initPosId, _param.tokenIn, borrToken, _param.amtIn, _param.borrAmt);
}
/// @inheritdoc IMarginTradingHook
function addCollateral(uint _posId, uint _amtIn) external payable depositNative refundNative {
uint initPosId = initPosIds[msg.sender][_posId];
_require(initPosId != 0, Errors.POSITION_NOT_FOUND);
MarginPos storage marginPos = __marginPositions[initPosId];
address collToken = ILendingPool(marginPos.collPool).underlyingToken();
// transfer in tokens
_transmitTokenIn(collToken, _amtIn);
// transfer tokens to collPool
IERC20(collToken).safeTransfer(marginPos.collPool, _amtIn);
// mint collateral pool tokens
IInitCore(CORE).mintTo(marginPos.collPool, POS_MANAGER);
// collateralize to INIT position
IInitCore(CORE).collateralize(initPosId, marginPos.collPool);
}
/// @inheritdoc IMarginTradingHook
function removeCollateral(uint _posId, uint _shares, bool _returnNative) external refundNative {
uint initPosId = initPosIds[msg.sender][_posId];
_require(initPosId != 0, Errors.POSITION_NOT_FOUND);
MarginPos storage marginPos = __marginPositions[initPosId];
address collToken = ILendingPool(marginPos.collPool).underlyingToken();
// decollateralize collTokens to collPool
IInitCore(CORE).decollateralize(initPosId, marginPos.collPool, _shares, marginPos.collPool);
// redeem underlying
IInitCore(CORE).burnTo(marginPos.collPool, address(this));
// transfer collateral tokens out
uint balance = IERC20(collToken).balanceOf(address(this));
_transmitTokenOut(collToken, balance, _returnNative);
}
/// @inheritdoc IMarginTradingHook
function repayDebt(uint _posId, uint _repayShares)
external
payable
depositNative
refundNative
returns (uint repayAmt)
{
uint initPosId = initPosIds[msg.sender][_posId];
_require(initPosId != 0, Errors.POSITION_NOT_FOUND);
MarginPos storage marginPos = __marginPositions[initPosId];
address borrPool = marginPos.borrPool;
// calculate repay shares (if it exceeds position debt share, only repay what's available)
uint debtShares = IPosManager(POS_MANAGER).getPosDebtShares(initPosId, borrPool);
if (_repayShares > debtShares) _repayShares = debtShares;
// get borrow token amount to repay
address borrToken = ILendingPool(borrPool).underlyingToken();
uint amtToRepay = ILendingPool(borrPool).debtShareToAmtCurrent(_repayShares);
// transfer in borrow tokens
_transmitTokenIn(borrToken, amtToRepay);
// repay debt to INIT core
_ensureApprove(borrToken, amtToRepay);
repayAmt = IInitCore(CORE).repay(borrPool, _repayShares, initPosId);
}
/// @inheritdoc IMarginTradingHook
function reducePos(
uint _posId,
uint _collAmt,
uint _repayShares,
address _tokenOut,
uint _minAmtOut,
bool _returnNative,
bytes calldata _data
) external refundNative returns (uint amtOut) {
uint initPosId = initPosIds[msg.sender][_posId];
amtOut = _reducePosInternal(
ReducePosInternalParam({
initPosId: initPosId,
collAmt: _collAmt,
repayShares: _repayShares,
tokenOut: _tokenOut,
minAmtOut: _minAmtOut,
returnNative: _returnNative,
data: _data
})
);
}
function _reducePosInternal(ReducePosInternalParam memory _param) internal returns (uint amtOut) {
MarginPos memory marginPos = __marginPositions[_param.initPosId];
// check collAmt & repay shares
_require(
_param.collAmt <= IPosManager(POS_MANAGER).getCollAmt(_param.initPosId, marginPos.collPool),
Errors.INPUT_TOO_HIGH
);
_require(
_param.repayShares <= IPosManager(POS_MANAGER).getPosDebtShares(_param.initPosId, marginPos.borrPool),
Errors.INPUT_TOO_HIGH
);
address collToken = ILendingPool(marginPos.collPool).underlyingToken();
address borrToken = ILendingPool(marginPos.borrPool).underlyingToken();
_require(_param.tokenOut == collToken || _param.tokenOut == borrToken, Errors.INVALID_INPUT);
uint repayAmt = ILendingPool(marginPos.borrPool).debtShareToAmtCurrent(_param.repayShares);
_ensureApprove(borrToken, repayAmt);
// 1. decollateralize collateral tokens
// 2. redeem underlying collateral tokens
// 3. callback (perform swap from coll -> borr)
// 4. repay borrow tokens
bytes[] memory multicallData = new bytes[](4);
multicallData[0] = abi.encodeWithSelector(
IInitCore(CORE).decollateralize.selector,
_param.initPosId,
marginPos.collPool,
_param.collAmt,
marginPos.collPool
);
multicallData[1] = abi.encodeWithSelector(IInitCore(CORE).burnTo.selector, marginPos.collPool, address(this));
{
// if expect token out = borr token -> swap all (exact-in)
// if expect token out = coll token -> swap enough to repay (exact-out)
SwapType swapType = _param.tokenOut == borrToken ? SwapType.CloseExactIn : SwapType.CloseExactOut;
SwapInfo memory swapInfo = SwapInfo(_param.initPosId, swapType, collToken, borrToken, repayAmt, _param.data);
multicallData[2] =
abi.encodeWithSelector(IInitCore(CORE).callback.selector, address(this), 0, abi.encode(swapInfo));
}
multicallData[3] = abi.encodeWithSelector(
IInitCore(CORE).repay.selector, marginPos.borrPool, _param.repayShares, _param.initPosId
);
// do multicall
IMulticall(CORE).multicall(multicallData);
amtOut = IERC20(_param.tokenOut).balanceOf(address(this));
// slippage control check
_require(amtOut >= _param.minAmtOut, Errors.SLIPPAGE_CONTROL);
// transfer tokens out
_transmitTokenOut(_param.tokenOut, amtOut, _param.returnNative);
emit ReducePos(_param.initPosId, _param.tokenOut, amtOut, _param.collAmt, repayAmt);
}
/// @inheritdoc IMarginTradingHook
function addStopLossOrder(
uint _posId,
uint _triggerPrice_e36,
address _tokenOut,
uint _limitPrice_e36,
uint _collAmt
) external returns (uint orderId) {
orderId = _createOrder(_posId, _triggerPrice_e36, _tokenOut, _limitPrice_e36, _collAmt, OrderType.StopLoss);
}
/// @inheritdoc IMarginTradingHook
function addTakeProfitOrder(
uint _posId,
uint _triggerPrice_e36,
address _tokenOut,
uint _limitPrice_e36,
uint _collAmt
) external returns (uint orderId) {
orderId = _createOrder(_posId, _triggerPrice_e36, _tokenOut, _limitPrice_e36, _collAmt, OrderType.TakeProfit);
}
/// @inheritdoc IMarginTradingHook
function cancelOrder(uint _posId, uint _orderId) public {
uint initPosId = initPosIds[msg.sender][_posId];
_require(initPosId != 0, Errors.POSITION_NOT_FOUND);
Order storage order = __orders[_orderId];
_require(order.initPosId == initPosId, Errors.INVALID_INPUT);
_require(order.status == OrderStatus.Active, Errors.INVALID_INPUT);
order.status = OrderStatus.Cancelled;
emit CancelOrder(initPosId, _orderId);
}
/// @inheritdoc IMarginTradingHook
function fillOrder(uint _orderId) external {
Order memory order = __orders[_orderId];
_require(order.status == OrderStatus.Active, Errors.INVALID_INPUT);
MarginPos memory marginPos = __marginPositions[order.initPosId];
address collToken = ILendingPool(marginPos.collPool).underlyingToken();
address borrToken = ILendingPool(marginPos.borrPool).underlyingToken();
// if position is empty, cancel order
if (IPosManager(POS_MANAGER).getCollAmt(order.initPosId, marginPos.collPool) == 0) {
__orders[_orderId].status = OrderStatus.Cancelled;
emit CancelOrder(order.initPosId, _orderId);
return;
}
// validate trigger price condition
_validateTriggerPrice(order, marginPos);
// calculate fill order info
(uint amtOut, uint repayShares, uint repayAmt) = _calculateFillOrderInfo(order, marginPos, collToken);
// update order status
__orders[_orderId].status = OrderStatus.Filled;
// transfer in repay tokens
IERC20(borrToken).safeTransferFrom(msg.sender, address(this), repayAmt);
// repay tokens
_ensureApprove(borrToken, repayAmt);
IInitCore(CORE).repay(marginPos.borrPool, repayShares, order.initPosId);
// decollateralize coll pool tokens to executor
IInitCore(CORE).decollateralize(order.initPosId, marginPos.collPool, order.collAmt, msg.sender);
// transfer order owner's desired tokens to the specified recipient
IERC20(order.tokenOut).safeTransferFrom(msg.sender, order.recipient, amtOut);
emit FillOrder(order.initPosId, _orderId, order.tokenOut, amtOut);
}
/// @inheritdoc ICallbackReceiver
function coreCallback(address _sender, bytes calldata _data) external payable returns (bytes memory result) {
_require(msg.sender == CORE, Errors.NOT_INIT_CORE);
_require(_sender == address(this), Errors.NOT_AUTHORIZED);
SwapInfo memory swapInfo = abi.decode(_data, (SwapInfo));
MarginPos memory marginPos = __marginPositions[swapInfo.initPosId];
uint amtIn = IERC20(swapInfo.tokenIn).balanceOf(address(this));
IERC20(swapInfo.tokenIn).safeTransfer(swapHelper, amtIn); // transfer all token in to swap helper
uint amtOutBf = IERC20(swapInfo.tokenOut).balanceOf(address(this));
// swap helper swap token
IBaseSwapHelper(swapHelper).swap(swapInfo);
uint amtOut = IERC20(swapInfo.tokenOut).balanceOf(address(this));
uint swapAmtOut = amtOut - amtOutBf;
if (swapInfo.swapType == SwapType.OpenExactIn) {
// transfer to coll pool to mint
IERC20(swapInfo.tokenOut).safeTransfer(marginPos.collPool, amtOut);
emit SwapToIncreasePos(swapInfo.initPosId, swapInfo.tokenIn, swapInfo.tokenOut, amtIn, swapAmtOut);
} else {
// transfer to borr pool to repay
uint amtSwapped = amtIn;
if (swapInfo.swapType == SwapType.CloseExactOut) {
// slippage control to make sure that swap helper swap correctly
_require(swapAmtOut >= swapInfo.amtOut, Errors.SLIPPAGE_CONTROL);
amtSwapped -= IERC20(swapInfo.tokenIn).balanceOf(address(this));
}
emit SwapToReducePos(swapInfo.initPosId, swapInfo.tokenIn, swapInfo.tokenOut, amtSwapped, swapAmtOut);
}
result = abi.encode(swapAmtOut);
}
/// @inheritdoc IMarginTradingHook
function setQuoteAsset(address _tokenA, address _tokenB, address _quoteAsset) external onlyGovernor {
_require(_tokenA != address(0) && _tokenB != address(0), Errors.ZERO_VALUE);
_require(_quoteAsset == _tokenA || _quoteAsset == _tokenB, Errors.INVALID_INPUT);
_require(_tokenA != _tokenB, Errors.NOT_SORTED_OR_DUPLICATED_INPUT);
// sort tokenA and tokenB
(address token0, address token1) = _tokenA < _tokenB ? (_tokenA, _tokenB) : (_tokenB, _tokenA);
__quoteAssets[token0][token1] = _quoteAsset;
emit SetQuoteAsset(token0, token1, _quoteAsset);
}
/// @inheritdoc IMarginTradingHook
function setSwapHelper(address _swapHelper) external onlyGovernor {
swapHelper = _swapHelper;
emit SetSwapHelper(_swapHelper);
}
/// @inheritdoc IMarginTradingHook
function getBaseAssetAndQuoteAsset(address _tokenA, address _tokenB)
public
view
returns (address baseAsset, address quoteAsset)
{
// sort tokenA and tokenB
(address token0, address token1) = _tokenA < _tokenB ? (_tokenA, _tokenB) : (_tokenB, _tokenA);
quoteAsset = __quoteAssets[token0][token1];
_require(quoteAsset != address(0), Errors.ZERO_VALUE);
baseAsset = quoteAsset == token0 ? token1 : token0;
}
/// @inheritdoc IMarginTradingHook
function getOrder(uint _orderId) external view returns (Order memory) {
return __orders[_orderId];
}
/// @inheritdoc IMarginTradingHook
function getMarginPos(uint _initPosId) external view returns (MarginPos memory) {
return __marginPositions[_initPosId];
}
/// @inheritdoc IMarginTradingHook
function getPosOrdersLength(uint _initPosId) external view returns (uint) {
return __posOrderIds[_initPosId].length;
}
/// @notice _collAmt MUST be > 0
/// @dev create order internal logic
function _createOrder(
uint _posId,
uint _triggerPrice_e36,
address _tokenOut,
uint _limitPrice_e36,
uint _collAmt,
OrderType _orderType
) internal returns (uint orderId) {
orderId = ++lastOrderId;
_require(_collAmt != 0, Errors.ZERO_VALUE);
uint initPosId = initPosIds[msg.sender][_posId];
_require(initPosId != 0, Errors.POSITION_NOT_FOUND);
MarginPos memory marginPos = __marginPositions[initPosId];
_require(_tokenOut == marginPos.baseAsset || _tokenOut == marginPos.quoteAsset, Errors.INVALID_INPUT);
uint collAmt = IPosManager(POS_MANAGER).getCollAmt(initPosId, marginPos.collPool);
_require(_collAmt <= collAmt, Errors.INPUT_TOO_HIGH); // check specified coll amt is feasible
__orders[orderId] = (
Order({
initPosId: initPosId,
triggerPrice_e36: _triggerPrice_e36,
limitPrice_e36: _limitPrice_e36,
collAmt: _collAmt,
tokenOut: _tokenOut,
orderType: _orderType,
status: OrderStatus.Active,
recipient: msg.sender
})
);
__posOrderIds[initPosId].push(orderId);
emit CreateOrder(initPosId, orderId, _tokenOut, _triggerPrice_e36, _limitPrice_e36, _collAmt, _orderType);
}
/// @inheritdoc IMarginTradingHook
function cancelAndCreateNewOrder(
uint _posId,
uint _orderId,
uint _triggerPrice_e36,
address _tokenOut,
uint _limitPrice_e36,
uint _collAmt
) external returns (uint newOrderId) {
Order memory order = __orders[_orderId];
cancelOrder(_posId, _orderId);
newOrderId = _createOrder(_posId, _triggerPrice_e36, _tokenOut, _limitPrice_e36, _collAmt, order.orderType);
}
/// @dev calculate fill order info
/// @param _order margin order info
/// @param _marginPos margin pos info
/// @param _collToken margin pos's collateral token
function _calculateFillOrderInfo(Order memory _order, MarginPos memory _marginPos, address _collToken)
internal
returns (uint amtOut, uint repayShares, uint repayAmt)
{
(repayShares, repayAmt, _order.collAmt) = _getFillInfoCurrent(_order, _marginPos);
uint collTokenAmt = ILendingPool(_marginPos.collPool).toAmtCurrent(_order.collAmt);
// NOTE: all roundings favor the order owner (amtOut)
if (_collToken == _order.tokenOut) {
if (_marginPos.isLongBaseAsset) {
// long eth hold eth
// (2 * 1500 - 1500) = 1500 / 1500 = 1 eth
// ((c * limit - borrow) / limit
amtOut = collTokenAmt - repayAmt * ONE_E36 / _order.limitPrice_e36;
} else {
// short eth hold usdc
// 2000 - 1 * 1500 = 500 usdc
// (c - borrow * limit)
amtOut = collTokenAmt - (repayAmt * _order.limitPrice_e36 / ONE_E36);
}
} else {
if (_marginPos.isLongBaseAsset) {
// long eth hold usdc
// (2 * 1500 - 1500) = 1500 usdc
// ((c * limit - borrow)
amtOut = (collTokenAmt * _order.limitPrice_e36).ceilDiv(ONE_E36) - repayAmt;
} else {
// short eth hold eth
// (3000 - 1 * 1500) / 1500 = 1 eth
// (c - borrow * limit) / limit
amtOut = (collTokenAmt * ONE_E36).ceilDiv(_order.limitPrice_e36) - repayAmt;
}
}
}
/// @dev validate price for margin order for the margin position
/// @param _order margin order info
/// @param _marginPos margin position info
function _validateTriggerPrice(Order memory _order, MarginPos memory _marginPos) internal view {
address oracle = IInitCore(CORE).oracle();
uint markPrice_e36 = IInitOracle(oracle).getPrice_e36(_marginPos.baseAsset).mulDiv(
ONE_E36, IInitOracle(oracle).getPrice_e36(_marginPos.quoteAsset)
);
// validate mark price
// if long base asset, and order type is to take profit -> mark price should pass the trigger price (>=)
// if long base asset, and order type is to add stop loss -> mark price should be smaller than the trigger price (<=)
// if short base asset, and order type is to take profit -> mark price should be smaller than the trigger price (<=)
// if short base asset, and order type is to add stop loss -> mark price should be larger than the trigger price (>=)
(_order.orderType == OrderType.TakeProfit) == _marginPos.isLongBaseAsset
? _require(markPrice_e36 >= _order.triggerPrice_e36, Errors.INVALID_INPUT)
: _require(markPrice_e36 <= _order.triggerPrice_e36, Errors.INVALID_INPUT);
}
/// @notice if the specified order size is larger than the position's collateral, repay size is scaled proportionally.
/// @dev calculate repay size and position's collateral of the given margin order
/// @param _order order info
/// @param _marginPos margin position info
/// @return repayAmt repay amount
/// @return repayShares repay shares
/// @return newCollAmt new collateral amount
function _getFillInfoCurrent(Order memory _order, MarginPos memory _marginPos)
internal
returns (uint repayAmt, uint repayShares, uint newCollAmt)
{
uint totalCollAmt = IPosManager(POS_MANAGER).getCollAmt(_order.initPosId, _marginPos.collPool);
newCollAmt = _order.collAmt;
if (newCollAmt > totalCollAmt) newCollAmt = totalCollAmt;
uint totalDebtShares = IPosManager(POS_MANAGER).getPosDebtShares(_order.initPosId, _marginPos.borrPool);
repayShares = totalDebtShares * newCollAmt / totalCollAmt;
repayAmt = ILendingPool(_marginPos.borrPool).debtShareToAmtCurrent(repayShares);
}
/// @notice if msg.value is provided, then _amt to expect for the transfer is the amount needed on top of msg.value
/// @dev transfer _tokenIn in with specific amount
/// @param _tokenIn token in address
/// @param _amt token amount to expect (this amount includes msg.value if _tokenIn is wrapped native)
function _transmitTokenIn(address _tokenIn, uint _amt) internal {
uint amtToTransfer = _amt;
if (msg.value != 0) {
_require(_tokenIn == WNATIVE, Errors.NOT_WNATIVE);
amtToTransfer = _amt > msg.value ? amtToTransfer - msg.value : 0;
}
if (amtToTransfer != 0) IERC20(_tokenIn).safeTransferFrom(msg.sender, address(this), amtToTransfer);
}
/// @notice if _returnNative is true, this function does nothing
/// @dev transfer _tokenOut out with specific amount
/// @param _tokenOut token out address
/// @param _amt token amount to transfer
/// @param _returnNative whether to return in native token (only applies in case _tokenOut is wrapped native)
function _transmitTokenOut(address _tokenOut, uint _amt, bool _returnNative) internal {
// note: if token out is wNative and return native is true,
// leave token in this contract to be handled by refundNative modifier
// else transfer token out to msg.sender
if (_tokenOut != WNATIVE || !_returnNative) IERC20(_tokenOut).safeTransfer(msg.sender, _amt);
}
/// @inheritdoc IMarginTradingHook
function getPosOrderIds(uint _initPosId) external view returns (uint[] memory) {
return __posOrderIds[_initPosId];
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721ReceiverUpgradeable {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/utils/ERC721Holder.sol)
pragma solidity ^0.8.0;
import "../IERC721ReceiverUpgradeable.sol";
import "../../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC721Receiver} interface.
*
* Accepts all token transfers.
* Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.
*/
contract ERC721HolderUpgradeable is Initializable, IERC721ReceiverUpgradeable {
function __ERC721Holder_init() internal onlyInitializing {
}
function __ERC721Holder_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC721Receiver-onERC721Received}.
*
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) {
return this.onERC721Received.selector;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface 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.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
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.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/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;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(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));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
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");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library 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
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 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 256, 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 << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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.
*
* ```solidity
* 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: None
pragma solidity ^0.8.19;
import {IAccessControlManager} from '../interfaces/common/IAccessControlManager.sol';
abstract contract UnderACM {
// immutables
IAccessControlManager public immutable ACM; // access control manager
// constructor
constructor(address _acm) {
ACM = IAccessControlManager(_acm);
}
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
/// @notice For maximum readability, error code must be a hex-encoded ASCII in the form {#DDD}.
/// @dev Reverts if the _condition is false.
/// @param _condition boolean condition required to be true.
/// @param _errorCode hex-encoded ASCII error code
function _require(bool _condition, uint32 _errorCode) pure {
if (!_condition) revert(string(abi.encodePacked(_errorCode)));
}
library Errors {
// Common
uint32 internal constant ZERO_VALUE = 0x23313030; // hex-encoded ASCII of '#100'
uint32 internal constant NOT_INIT_CORE = 0x23313031; // hex-encoded ASCII of '#101'
uint32 internal constant SLIPPAGE_CONTROL = 0x23313032; // hex-encoded ASCII of '#102'
uint32 internal constant CALL_FAILED = 0x23313033; // hex-encoded ASCII of '#103'
uint32 internal constant NOT_OWNER = 0x23313034; // hex-encoded ASCII of '#104'
uint32 internal constant NOT_WNATIVE = 0x23313035; // hex-encoded ASCII of '#105'
uint32 internal constant ALREADY_SET = 0x23313036; // hex-encoded ASCII of '#106'
uint32 internal constant NOT_WHITELISTED = 0x23313037; // hex-encoded ASCII of '#107'
// Input
uint32 internal constant ARRAY_LENGTH_MISMATCHED = 0x23323030; // hex-encoded ASCII of '#200'
uint32 internal constant INPUT_TOO_LOW = 0x23323031; // hex-encoded ASCII of '#201'
uint32 internal constant INPUT_TOO_HIGH = 0x23323032; // hex-encoded ASCII of '#202'
uint32 internal constant INVALID_INPUT = 0x23323033; // hex-encoded ASCII of '#203'
uint32 internal constant INVALID_TOKEN_IN = 0x23323034; // hex-encoded ASCII of '#204'
uint32 internal constant INVALID_TOKEN_OUT = 0x23323035; // hex-encoded ASCII of '#205'
uint32 internal constant NOT_SORTED_OR_DUPLICATED_INPUT = 0x23323036; // hex-encoded ASCII of '#206'
// Core
uint32 internal constant POSITION_NOT_HEALTHY = 0x23333030; // hex-encoded ASCII of '#300'
uint32 internal constant POSITION_NOT_FOUND = 0x23333031; // hex-encoded ASCII of '#301'
uint32 internal constant LOCKED_MULTICALL = 0x23333032; // hex-encoded ASCII of '#302'
uint32 internal constant POSITION_HEALTHY = 0x23333033; // hex-encoded ASCII of '#303'
uint32 internal constant INVALID_HEALTH_AFTER_LIQUIDATION = 0x23333034; // hex-encoded ASCII of '#304'
uint32 internal constant FLASH_PAUSED = 0x23333035; // hex-encoded ASCII of '#305'
uint32 internal constant INVALID_FLASHLOAN = 0x23333036; // hex-encoded ASCII of '#306'
uint32 internal constant NOT_AUTHORIZED = 0x23333037; // hex-encoded ASCII of '#307'
uint32 internal constant INVALID_CALLBACK_ADDRESS = 0x23333038; // hex-encoded ASCII of '#308'
// Lending Pool
uint32 internal constant MINT_PAUSED = 0x23343030; // hex-encoded ASCII of '#400'
uint32 internal constant REDEEM_PAUSED = 0x23343031; // hex-encoded ASCII of '#401'
uint32 internal constant BORROW_PAUSED = 0x23343032; // hex-encoded ASCII of '#402'
uint32 internal constant REPAY_PAUSED = 0x23343033; // hex-encoded ASCII of '#403'
uint32 internal constant NOT_ENOUGH_CASH = 0x23343034; // hex-encoded ASCII of '#404'
uint32 internal constant INVALID_AMOUNT_TO_REPAY = 0x23343035; // hex-encoded ASCII of '#405'
uint32 internal constant SUPPLY_CAP_REACHED = 0x23343036; // hex-encoded ASCII of '#406'
uint32 internal constant BORROW_CAP_REACHED = 0x23343037; // hex-encoded ASCII of '#407'
// Config
uint32 internal constant INVALID_MODE = 0x23353030; // hex-encoded ASCII of '#500'
uint32 internal constant TOKEN_NOT_WHITELISTED = 0x23353031; // hex-encoded ASCII of '#501'
uint32 internal constant INVALID_FACTOR = 0x23353032; // hex-encoded ASCII of '#502'
// Position Manager
uint32 internal constant COLLATERALIZE_PAUSED = 0x23363030; // hex-encoded ASCII of '#600'
uint32 internal constant DECOLLATERALIZE_PAUSED = 0x23363031; // hex-encoded ASCII of '#601'
uint32 internal constant MAX_COLLATERAL_COUNT_REACHED = 0x23363032; // hex-encoded ASCII of '#602'
uint32 internal constant NOT_CONTAIN = 0x23363033; // hex-encoded ASCII of '#603'
uint32 internal constant ALREADY_COLLATERALIZED = 0x23363034; // hex-encoded ASCII of '#604'
// Oracle
uint32 internal constant NO_VALID_SOURCE = 0x23373030; // hex-encoded ASCII of '#700'
uint32 internal constant TOO_MUCH_DEVIATION = 0x23373031; // hex-encoded ASCII of '#701'
uint32 internal constant MAX_PRICE_DEVIATION_TOO_LOW = 0x23373032; // hex-encoded ASCII of '#702'
uint32 internal constant NO_PRICE_ID = 0x23373033; // hex-encoded ASCII of '#703'
uint32 internal constant PYTH_CONFIG_NOT_SET = 0x23373034; // hex-encoded ASCII of '#704'
uint32 internal constant DATAFEED_ID_NOT_SET = 0x23373035; // hex-encoded ASCII of '#705'
uint32 internal constant MAX_STALETIME_NOT_SET = 0x23373036; // hex-encoded ASCII of '#706'
uint32 internal constant MAX_STALETIME_EXCEEDED = 0x23373037; // hex-encoded ASCII of '#707'
uint32 internal constant PRIMARY_SOURCE_NOT_SET = 0x23373038; // hex-encoded ASCII of '#708'
uint32 internal constant DATAFEED_PROXY_NOT_SET = 0x23373039; // hex-encoded ASCII of '#709'
// Risk Manager
uint32 internal constant DEBT_CEILING_EXCEEDED = 0x23383030; // hex-encoded ASCII of '#800'
// Misc
uint32 internal constant INCORRECT_PAIR = 0x23393030; // hex-encoded ASCII of '#900'
uint32 internal constant UNIMPLEMENTED = 0x23393939; // hex-encoded ASCII of '#999'
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
import {IERC20} from '@openzeppelin-contracts/token/ERC20/IERC20.sol';
import {SafeERC20} from '@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol';
import {ERC721HolderUpgradeable} from
'@openzeppelin-contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol';
abstract contract BaseMappingIdHook is ERC721HolderUpgradeable {
using SafeERC20 for IERC20;
// immutables
address public immutable CORE;
address public immutable POS_MANAGER;
// storages
mapping(address => uint) public lastPosIds;
mapping(address => mapping(uint => uint)) public initPosIds;
// constructor
constructor(address _core, address _posManager) {
CORE = _core;
POS_MANAGER = _posManager;
}
/// @dev approve token for init core if needed
/// @param _token token address
/// @param _amt token amount to spend
function _ensureApprove(address _token, uint _amt) internal {
if (IERC20(_token).allowance(address(this), CORE) < _amt) {
IERC20(_token).safeApprove(CORE, type(uint).max);
}
}
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
/// @title Access Control Manager Interface
interface IAccessControlManager {
/// @dev check the role of the user, revert against an unauthorized user.
/// @param _role keccak256 hash of role name
/// @param _user user address to check for the role
function checkRole(bytes32 _role, address _user) external;
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
/// @title Multicall Interface
interface IMulticall {
/// @dev Perform multiple calls according to the provided _data. Reverts with reason if any of the calls failed.
/// @notice `msg.value` should not be trusted or used in the multicall data.
/// @param _data The encoded function data for each subcall.
/// @return results The call results, if success.
function multicall(bytes[] calldata _data) external payable returns (bytes[] memory results);
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
import {IERC20} from '@openzeppelin-contracts/token/ERC20/IERC20.sol';
/// @title Wrapped Native Interface
interface IWNative is IERC20 {
/// @dev wrap the native token to wrapped token using `msg.value` as the amount
function deposit() external payable;
/// @dev unwrap the wrapped token to native token
/// @param amount token amount to unwrap
function withdraw(uint amount) external;
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
import {EnumerableSet} from '@openzeppelin-contracts/utils/structs/EnumerableSet.sol';
// structs
struct TokenFactors {
uint128 collFactor_e18; // collateral factor in 1e18 (1e18 = 100%)
uint128 borrFactor_e18; // borrow factor in 1e18 (1e18 = 100%)
}
struct ModeConfig {
EnumerableSet.AddressSet collTokens; // enumerable set of collateral tokens
EnumerableSet.AddressSet borrTokens; // enumerable set of borrow tokens
uint64 maxHealthAfterLiq_e18; // max health factor allowed after liquidation
mapping(address => TokenFactors) factors; // token factors mapping
ModeStatus status; // mode status
uint8 maxCollWLpCount; // limit number of wLp to avoid out of gas
}
struct PoolConfig {
uint128 supplyCap; // pool supply cap
uint128 borrowCap; // pool borrow cap
bool canMint; // pool mint status
bool canBurn; // pool burn status
bool canBorrow; // pool borrow status
bool canRepay; // pool repay status
bool canFlash; // pool flash status
}
struct ModeStatus {
bool canCollateralize; // mode collateralize status
bool canDecollateralize; // mode decollateralize status
bool canBorrow; // mode borrow status
bool canRepay; // mode repay status
}
/// @title Config Interface
/// @notice Configuration parameters for the protocol.
interface IConfig {
event SetPoolConfig(address indexed pool, PoolConfig config);
event SetCollFactors_e18(uint16 indexed mode, address[] tokens, uint128[] _factors);
event SetBorrFactors_e18(uint16 indexed mode, address[] tokens, uint128[] factors);
event SetMaxHealthAfterLiq_e18(uint16 indexed mode, uint64 maxHealthAfterLiq_e18);
event SetWhitelistedWLps(address[] wLps, bool status);
event SetModeStatus(uint16 mode, ModeStatus status);
event SetMaxCollWLpCount(uint16 indexed mode, uint8 maxCollWLpCount);
/// @dev check if the wrapped lp is whitelisted.
/// @param _wlp wrapped lp address
/// @return whether the wrapped lp is whitelisted.
function whitelistedWLps(address _wlp) external view returns (bool);
/// @dev get mode config
/// @param _mode mode id
/// @return collTokens collateral token list
/// borrTokens borrow token list
/// maxHealthAfterLiq_e18 max health factor allowed after liquidation
/// maxCollWLpCount // limit number of wLp to avoid out of gas
function getModeConfig(uint16 _mode)
external
view
returns (
address[] memory collTokens,
address[] memory borrTokens,
uint maxHealthAfterLiq_e18,
uint8 maxCollWLpCount
);
/// @dev get pool config
/// @param _pool pool address
/// @return poolConfig pool config
function getPoolConfig(address _pool) external view returns (PoolConfig memory poolConfig);
/// @dev check if the pool within the specified mode is allowed for borrowing.
/// @param _mode mode id
/// @param _pool lending pool address
/// @return whether the pool within the mode is allowed for borrowing.
function isAllowedForBorrow(uint16 _mode, address _pool) external view returns (bool);
/// @dev check if the pool within the specified mode is allowed for collateralizing.
/// @param _mode mode id
/// @param _pool lending pool address
/// @return whether the pool within the mode is allowed for collateralizing.
function isAllowedForCollateral(uint16 _mode, address _pool) external view returns (bool);
/// @dev get the token factors (collateral and borrow factors)
/// @param _mode mode id
/// @param _pool lending pool address
/// @return tokenFactors token factors
function getTokenFactors(uint16 _mode, address _pool) external view returns (TokenFactors memory tokenFactors);
/// @notice if return the value of type(uint64).max, skip the health check after liquidation
/// @dev get the mode max health allowed after liquidation
/// @param _mode mode id
/// @param maxHealthAfterLiq_e18 max allowed health factor after liquidation
function getMaxHealthAfterLiq_e18(uint16 _mode) external view returns (uint maxHealthAfterLiq_e18);
/// @dev get the current mode status
/// @param _mode mode id
/// @return modeStatus mode status (collateralize, decollateralize, borrow or repay)
function getModeStatus(uint16 _mode) external view returns (ModeStatus memory modeStatus);
/// @dev set pool config
/// @param _pool lending pool address
/// @param _config new pool config
function setPoolConfig(address _pool, PoolConfig calldata _config) external;
/// @dev set pool collateral factors
/// @param _pools lending pool address list
/// @param _factors new collateral factor list in 1e18 (1e18 = 100%)
function setCollFactors_e18(uint16 _mode, address[] calldata _pools, uint128[] calldata _factors) external;
/// @dev set pool borrow factors
/// @param _pools lending pool address list
/// @param _factors new borrow factor list in 1e18 (1e18 = 100%)
function setBorrFactors_e18(uint16 _mode, address[] calldata _pools, uint128[] calldata _factors) external;
/// @dev set mode status
/// @param _status new mode status to set to (collateralize, decollateralize, borrow and repay)
function setModeStatus(uint16 _mode, ModeStatus calldata _status) external;
/// @notice only governor role can call
/// @dev set whitelisted wrapped lp statuses
/// @param _wLps wrapped lp list
/// @param _status whitelisted status to set to
function setWhitelistedWLps(address[] calldata _wLps, bool _status) external;
/// @dev set max health after liquidation (type(uint64).max means infinite, or no check)
/// @param _mode mode id
/// @param _maxHealthAfterLiq_e18 new max allowed health factor after liquidation
function setMaxHealthAfterLiq_e18(uint16 _mode, uint64 _maxHealthAfterLiq_e18) external;
/// @dev set mode's max collateral wrapped lp count to avoid out of gas
/// @param _mode mode id
/// @param _maxCollWLpCount max collateral wrapped lp count
function setMaxCollWLpCount(uint16 _mode, uint8 _maxCollWLpCount) external;
/// @dev get mode's max collateral wlp count
/// @param _mode mode id
/// @return the mode's max collateral wlp count
function getModeMaxCollWLpCount(uint16 _mode) external view returns (uint8);
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
import './IConfig.sol';
/// @title InitCore Interface
interface IInitCore {
event SetConfig(address indexed newConfig);
event SetOracle(address indexed newOracle);
event SetIncentiveCalculator(address indexed newIncentiveCalculator);
event SetRiskManager(address indexed newRiskManager);
event Borrow(address indexed pool, uint indexed posId, address indexed to, uint borrowAmt, uint shares);
event Repay(address indexed pool, uint indexed posId, address indexed repayer, uint shares, uint amtToRepay);
event CreatePosition(address indexed owner, uint indexed posId, uint16 mode, address viewer);
event SetPositionMode(uint indexed posId, uint16 mode);
event Collateralize(uint indexed posId, address indexed pool, uint amt);
event Decollateralize(uint indexed posId, address indexed pool, address indexed to, uint amt);
event CollateralizeWLp(uint indexed posId, address indexed wLp, uint indexed tokenId, uint amt);
event DecollateralizeWLp(uint indexed posId, address indexed wLp, uint indexed tokenId, address to, uint amt);
event Liquidate(uint indexed posId, address indexed liquidator, address poolOut, uint shares);
event LiquidateWLp(uint indexed posId, address indexed liquidator, address wLpOut, uint tokenId, uint amt);
struct LiquidateLocalVars {
IConfig config;
uint16 mode;
uint health_e18;
uint liqIncentive_e18;
address collToken;
address repayToken;
uint repayAmt;
uint repayAmtWithLiqIncentive;
}
/// @dev get position manager address
function POS_MANAGER() external view returns (address);
/// @dev get config address
function config() external view returns (address);
/// @dev get oracle address
function oracle() external view returns (address);
/// @dev get risk manager address
function riskManager() external view returns (address);
/// @dev get liquidation incentive calculator address
function liqIncentiveCalculator() external view returns (address);
/// @dev mint lending pool shares (using ∆balance in lending pool)
/// @param _pool lending pool address
/// @param _to address to receive share token
/// @return shares amount of share tokens minted
function mintTo(address _pool, address _to) external returns (uint shares);
/// @dev burn lending pool share tokens to receive underlying (using ∆balance in lending pool)
/// @param _pool lending pool address
/// @param _to address to receive underlying
/// @return amt amount of underlying to receive
function burnTo(address _pool, address _to) external returns (uint amt);
/// @dev borrow underlying from lending pool
/// @param _pool lending pool address
/// @param _amt amount of underlying to borrow
/// @param _posId position id to account for the borrowing
/// @param _to address to receive borrow underlying
/// @return shares the amount of debt shares for the borrowing
function borrow(address _pool, uint _amt, uint _posId, address _to) external returns (uint shares);
/// @dev repay debt to the lending pool
/// @param _pool address of lending pool
/// @param _shares debt shares to repay
/// @param _posId position id to repay debt
/// @return amt amount of underlying to repaid
function repay(address _pool, uint _shares, uint _posId) external returns (uint amt);
/// @dev create a new position
/// @param _mode position mode
/// @param _viewer position viewer address
function createPos(uint16 _mode, address _viewer) external returns (uint posId);
/// @dev change a position's mode
/// @param _posId position id to change mode
/// @param _mode position mode to change to
function setPosMode(uint _posId, uint16 _mode) external;
/// @dev collateralize lending pool share tokens to position
/// @param _posId position id to collateralize to
/// @param _pool lending pool address
function collateralize(uint _posId, address _pool) external;
/// @notice need to check the position's health after decollateralization
/// @dev decollateralize lending pool share tokens from the position
/// @param _posId position id to decollateral
/// @param _pool lending pool address
/// @param _shares amount of share tokens to decollateralize
/// @param _to address to receive token
function decollateralize(uint _posId, address _pool, uint _shares, address _to) external;
/// @dev collateralize wlp to position
/// @param _posId position id to collateralize to
/// @param _wLp wlp token address
/// @param _tokenId token id of wlp token to collateralize
function collateralizeWLp(uint _posId, address _wLp, uint _tokenId) external;
/// @notice need to check position's health after decollateralization
/// @dev decollateralize wlp from the position
/// @param _posId position id to decollateralize
/// @param _wLp wlp token address
/// @param _tokenId token id of wlp token to decollateralize
/// @param _amt amount of wlp token to decollateralize
function decollateralizeWLp(uint _posId, address _wLp, uint _tokenId, uint _amt, address _to) external;
/// @notice need to check position's health before liquidate & limit health after liqudate
/// @dev (partial) liquidate the position
/// @param _posId position id to liquidate
/// @param _poolToRepay address of lending pool to liquidate
/// @param _repayShares debt shares to repay
/// @param _tokenOut pool token to receive for the liquidation
/// @param _minShares min amount of pool token to receive after liquidate (slippage control)
/// @return amt the token amount out actually transferred out
function liquidate(uint _posId, address _poolToRepay, uint _repayShares, address _tokenOut, uint _minShares)
external
returns (uint amt);
/// @notice need to check position's health before liquidate & limit health after liqudate
/// @dev (partial) liquidate the position
/// @param _posId position id to liquidate
/// @param _poolToRepay address of lending pool to liquidate
/// @param _repayShares debt shares to liquidate
/// @param _wLp wlp to unwrap for liquidation
/// @param _tokenId wlp token id to burn for liquidation
/// @param _minLpOut min amount of lp to receive for liquidation
/// @return amt the token amount out actually transferred out
function liquidateWLp(
uint _posId,
address _poolToRepay,
uint _repayShares,
address _wLp,
uint _tokenId,
uint _minLpOut
) external returns (uint amt);
/// @notice caller must implement `flashCallback` function
/// @dev flashloan underlying tokens from lending pool
/// @param _pools lending pool address list to flashloan from
/// @param _amts token amount list to flashloan
/// @param _data data to execute in the callback function
function flash(address[] calldata _pools, uint[] calldata _amts, bytes calldata _data) external;
/// @dev make a callback to the target contract
/// @param _to target address to receive callback
/// @param _value msg.value to pass on to the callback
/// @param _data data to execute callback function
/// @return result callback result
function callback(address _to, uint _value, bytes calldata _data) external payable returns (bytes memory result);
/// @notice this is NOT a view function
/// @dev get current position's collateral credit in 1e36 (interest accrued up to current timestamp)
/// @param _posId position id to get collateral credit for
/// @return credit current position collateral credit
function getCollateralCreditCurrent_e36(uint _posId) external returns (uint credit);
/// @dev get current position's borrow credit in 1e36 (interest accrued up to current timestamp)
/// @param _posId position id to get borrow credit for
/// @return credit current position borrow credit
function getBorrowCreditCurrent_e36(uint _posId) external returns (uint credit);
/// @dev get current position's health factor in 1e18 (interest accrued up to current timestamp)
/// @param _posId position id to get health factor
/// @return health current position health factor
function getPosHealthCurrent_e18(uint _posId) external returns (uint health);
/// @dev set new config
function setConfig(address _config) external;
/// @dev set new oracle
function setOracle(address _oracle) external;
/// @dev set new liquidation incentve calculator
function setLiqIncentiveCalculator(address _liqIncentiveCalculator) external;
/// @dev set new risk manager
function setRiskManager(address _riskManager) external;
/// @dev transfer token from msg.sender to the target address
/// @param _token token address to transfer
/// @param _to address to receive token
/// @param _amt amount of token to transfer
function transferToken(address _token, address _to, uint _amt) external;
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
import {EnumerableSet} from '@openzeppelin-contracts/utils/structs/EnumerableSet.sol';
/// @title Position Interface
interface IPosManager {
event SetMaxCollCount(uint maxCollCount);
struct PosInfo {
address viewer; // viewer address
uint16 mode; // position mode
}
// NOTE: extra info for hooks (not used in core)
struct PosBorrExtraInfo {
uint128 totalInterest; // total accrued interest since the position is created
uint128 lastDebtAmt; // position's debt amount after the last interaction
}
struct PosCollInfo {
EnumerableSet.AddressSet collTokens; // enumerable set of collateral tokens
mapping(address => uint) collAmts; // collateral token to collateral amts mapping
EnumerableSet.AddressSet wLps; // enumerable set of collateral wlps
mapping(address => EnumerableSet.UintSet) ids; // wlp address to enumerable set of ids mapping
uint8 collCount; // current collateral count (erc20 + wlp)
uint8 wLpCount; // current collateral count (wlp)
}
struct PosBorrInfo {
EnumerableSet.AddressSet pools; // enumerable set of borrow tokens
mapping(address => uint) debtShares; // debt token to debt shares mapping
mapping(address => PosBorrExtraInfo) borrExtraInfos; // debt token to extra info mapping
}
/// @dev get the next nonce of the owner for calculating the next position id
/// @param _owner the position owner
/// @return nextNonce the next nonce of the position owner
function nextNonces(address _owner) external view returns (uint nextNonce);
/// @dev get core address
function core() external view returns (address core);
/// @dev get pending reward token amts for the pos id
/// @param _posId pos id
/// @param _rewardToken reward token
/// @return amt reward token amt
function pendingRewards(uint _posId, address _rewardToken) external view returns (uint amt);
/// @dev get whether the wlp is already collateralized to a position
/// @param _wLp wlp address
/// @param _tokenId wlp token id
/// @return whether the wlp is already collateralized to a position
function isCollateralized(address _wLp, uint _tokenId) external view returns (bool);
/// @dev get the position borrowed info (excluding the extra info)
/// @param _posId position id
/// @return pools the borrowed pool list
/// debtShares the debt shares list of the borrowed pools
function getPosBorrInfo(uint _posId) external view returns (address[] memory pools, uint[] memory debtShares);
/// @dev get the position borrowed extra info
/// @param _posId position id
/// @param _pool borrowed pool address
/// @return totalInterest total accrued interest since the position is created
/// lastDebtAmt position's debt amount after the last interaction
function getPosBorrExtraInfo(uint _posId, address _pool)
external
view
returns (uint totalInterest, uint lastDebtAmt);
/// @dev get the position collateral info
/// @param _posId position id
/// @return pools the collateral pool adddres list
/// amts collateral amts of the collateral pools
/// wLps the collateral wlp list
/// ids the ids of the collateral wlp list
/// wLpAmts the amounts of the collateral wlp list
function getPosCollInfo(uint _posId)
external
view
returns (
address[] memory pools,
uint[] memory amts,
address[] memory wLps,
uint[][] memory ids,
uint[][] memory wLpAmts
);
/// @dev get pool's collateral amount for the position
/// @param _posId position id
/// @param _pool collateral pool address
/// @return amt collateral amount
function getCollAmt(uint _posId, address _pool) external view returns (uint amt);
/// @dev get wrapped lp collateral amount for the position
/// @param _posId position id
/// @param _wLp collateral wlp address
/// @param _tokenId collateral wlp token id
/// @return amt collateral amount
function getCollWLpAmt(uint _posId, address _wLp, uint _tokenId) external view returns (uint amt);
/// @dev get position's collateral count
/// @param _posId position id
/// @return collCount position's collateral count
function getPosCollCount(uint _posId) external view returns (uint8 collCount);
/// @dev get position's wLp count
/// @param _posId position id
function getPosCollWLpCount(uint _posId) external view returns (uint8 wLpCount);
/// @dev get position info
/// @param _posId position id
/// @return viewerAddress position's viewer address
/// mode position's mode
function getPosInfo(uint _posId) external view returns (address viewerAddress, uint16 mode);
/// @dev get position mode
/// @param _posId position id
/// @return mode position's mode
function getPosMode(uint _posId) external view returns (uint16 mode);
/// @dev get pool's debt shares for the position
/// @param _posId position id
/// @param _pool lending pool address
/// @return debtShares debt shares
function getPosDebtShares(uint _posId, address _pool) external view returns (uint debtShares);
/// @dev get pos id at index corresponding to the viewer address (reverse mapping)
/// @param _viewer viewer address
/// @param _index index
/// @return posId pos id
function getViewerPosIdsAt(address _viewer, uint _index) external view returns (uint posId);
/// @dev get pos id length corresponding to the viewer address (reverse mapping)
/// @param _viewer viewer address
/// @return length pos ids length
function getViewerPosIdsLength(address _viewer) external view returns (uint length);
/// @notice only core can call this function
/// @dev update pool's debt share
/// @param _posId position id
/// @param _pool lending pool address
/// @param _debtShares new debt shares
function updatePosDebtShares(uint _posId, address _pool, int _debtShares) external;
/// @notice only core can call this function
/// @dev update position mode
/// @param _posId position id
/// @param _mode new position mode to set to
function updatePosMode(uint _posId, uint16 _mode) external;
/// @notice only core can call this function
/// @dev add lending pool share as collateral to the position
/// @param _posId position id
/// @param _pool lending pool address
/// @return amtIn pool's share collateral amount added to the position
function addCollateral(uint _posId, address _pool) external returns (uint amtIn);
/// @notice only core can call this function
/// @dev add wrapped lp share as collateral to the position
/// @param _posId position id
/// @param _wLp wlp address
/// @param _tokenId wlp token id
/// @return amtIn wlp collateral amount added to the position
function addCollateralWLp(uint _posId, address _wLp, uint _tokenId) external returns (uint amtIn);
/// @notice only core can call this function
/// @dev remove lending pool share from the position
/// @param _posId position id
/// @param _pool lending pool address
/// @param _receiver address to receive the shares
/// @return amtOut pool's share collateral amount removed from the position
function removeCollateralTo(uint _posId, address _pool, uint _shares, address _receiver)
external
returns (uint amtOut);
/// @notice only core can call this function
/// @dev remove wlp from the position
/// @param _posId position id
/// @param _wLp wlp address
/// @param _tokenId wlp token id
/// @param _amt wlp token amount to remove
/// @return amtOut wlp collateral amount removed from the position
function removeCollateralWLpTo(uint _posId, address _wLp, uint _tokenId, uint _amt, address _receiver)
external
returns (uint amtOut);
/// @notice only core can call this function
/// @dev create a new position
/// @param _owner position owner
/// @param _mode position mode
/// @param _viewer position viewer
/// @return posId position id
function createPos(address _owner, uint16 _mode, address _viewer) external returns (uint posId);
/// @dev harvest rewards from the wlp token
/// @param _posId position id
/// @param _wlp wlp address
/// @param _tokenId id of the wlp token
/// @param _to address to receive the rewards
/// @return tokens token address list harvested
/// amts token amt list harvested
function harvestTo(uint _posId, address _wlp, uint _tokenId, address _to)
external
returns (address[] memory tokens, uint[] memory amts);
/// @notice When removing the wrapped LP collateral, the rewards are harvested to the position manager
/// before unwrapping the LP and sending it to the user
/// @dev claim pending reward pending in the position manager
/// @param _posId position id
/// @param _tokens token address list to claim pending reward
/// @param _to address to receive the pending rewards
/// @return amts amount of each reward tokens claimed
function claimPendingRewards(uint _posId, address[] calldata _tokens, address _to)
external
returns (uint[] memory amts);
/// @notice authorized account could be the owner or approved addresses
/// @dev check if the accoount is authorized for the position
/// @param _account account address to check
/// @param _posId position id
/// @return whether the account is authorized to manage the position
function isAuthorized(address _account, uint _posId) external view returns (bool);
/// @notice only guardian can call this function
/// @dev set the max number of the different collateral count (to avoid out-of-gas error)
/// @param _maxCollCount new max collateral count
function setMaxCollCount(uint8 _maxCollCount) external;
/// @notice only position owner can call this function
/// @dev set new position viewer for pos id
/// @param _posId pos id
/// @param _viewer new viewer address
function setPosViewer(uint _posId, address _viewer) external;
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
import {SwapInfo} from '../../hook/IMarginTradingHook.sol';
interface IBaseSwapHelper {
function swap(SwapInfo calldata _swapInfo) external;
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
// @ mnt-eth = 3200, eth-usd = 2200
// pair | col | bor | B | Q | limit (sl) | limit (tp) |
// ETH-USD (long) | ETH | USD | ETH | USD | < 2000 | > 3000 |
// ETH-USD (short) | USD | ETH | ETH | USD | > 3000 | < 2000 |
// MNT-ETH (long) | MNT | ETH | ETH | MNT | < 3000 | > 4000 |
// MNT-ETH (short) | ETH | MNT | ETH | MNT | > 4000 | > 3000 |
// enums
enum OrderType {
StopLoss,
TakeProfit
}
enum OrderStatus {
Cancelled,
Active,
Filled
}
enum SwapType {
OpenExactIn,
CloseExactIn,
CloseExactOut
}
// structs
struct Order {
uint initPosId; // nft id
uint triggerPrice_e36; // price (base asset price / quote asset price) to trigger limit order
uint limitPrice_e36; // price limit price (base asset price / quote asset price) to fill order
uint collAmt; // size of collateral to be used in order
address tokenOut; // token to transfer to pos owner
OrderType orderType; // stop loss or take profit
OrderStatus status; // cancelled, active, filled
address recipient; // address to receive tokenOut
}
struct MarginPos {
address collPool; // lending pool to deposit holdToken
address borrPool; // lending pool to borrow borrowToken
address baseAsset; // base asset of position
address quoteAsset; // quote asset of position
bool isLongBaseAsset; // long base asset or not
}
struct SwapInfo {
uint initPosId; // nft id
SwapType swapType; // swap type
address tokenIn; // token to swap
address tokenOut; // token to receive from swap
uint amtOut; // token amount out info for the swap
bytes data; // swap data
}
/// @notice user has to be able to receive native tokens
interface IMarginTradingHook {
// events
event SwapToIncreasePos(
uint indexed initPosId, address indexed tokenIn, address indexed tokenOut, uint amtIn, uint amtOut
);
event SwapToReducePos(
uint indexed initPosId, address indexed tokenIn, address indexed tokenOut, uint amtIn, uint amtOut
);
event IncreasePos(
uint indexed initPosId, address indexed tokenIn, address indexed borrToken, uint amtIn, uint borrowAmt
);
event ReducePos(uint indexed initPosId, address indexed tokenOut, uint amtOut, uint size, uint repayAmt);
event CreateOrder(
uint indexed initPosId,
uint indexed orderId,
address tokenOut,
uint triggerPrice_e36,
uint limitPrice_e36,
uint size,
OrderType orderType
);
event CancelOrder(uint indexed initPosId, uint indexed orderId);
event FillOrder(uint indexed initPosId, uint indexed orderId, address tokenOut, uint amtOut);
event SetSwapHelper(address swapHelper);
event SetQuoteAsset(address tokenA, address tokenB, address quoteAsset);
// struct
struct IncreasePosInternalParam {
uint initPosId; // nft id
address tokenIn; // token to transfer from msg.sender
uint amtIn; // token amount to transfer from msg sender (for wNative, amt to transfer will reduce by msg value)
address borrPool; // lending pool to borrow
uint borrAmt; // token amount to borrow
address collPool; // lending pool to deposit
bytes data; // swap data
uint minAmtOut; // minimum token amount to receive from swap
}
struct ReducePosInternalParam {
uint initPosId; // nft id
uint collAmt; // collateral amt to reduce
uint repayShares; // debt shares to repay
address tokenOut; // token to transfer to msg sender
uint minAmtOut; // minimum amount of token to transfer to msg sender
bool returnNative; // return wNative as native token or not (using balanceOf(address(this)))
bytes data; // swap data
}
// functions
/// @dev open margin trading position
/// @param _mode position mode to be used
/// @param _viewer address to view position
/// @param _tokenIn token to transfer from msg.sender
/// @param _amtIn token amount to transfer from msg sender (for wNative, amt to transfer will reduce by msg value)
/// @param _borrPool lending pool to borrow
/// @param _borrAmt token amount to borrow
/// @param _collPool lending pool to deposit
/// @param _data swap data
/// @param _minAmtOut minimum tokenOut to receive from swap
/// @return posId margin trading position id
/// initPosId init position id (nft id)
/// amtOut amount of received token from swap
function openPos(
uint16 _mode,
address _viewer,
address _tokenIn,
uint _amtIn,
address _borrPool,
uint _borrAmt,
address _collPool,
bytes calldata _data,
uint _minAmtOut
) external payable returns (uint posId, uint initPosId, uint amtOut);
/// @dev increase position size (need to borrow)
/// @param _posId margin trading position id
/// @param _tokenIn token to transfer from msg.sender
/// @param _amtIn token amount to transfer from msg sender (for wNative, amt to transfer will reduce by msg value)
/// @param _borrAmt token amount to borrow
/// @param _data swap data
/// @param _minAmtOut minimum tokenOut to receive from swap
/// @return amtOut amount of received token from swap
function increasePos(
uint _posId,
address _tokenIn,
uint _amtIn,
uint _borrAmt,
bytes calldata _data,
uint _minAmtOut
) external payable returns (uint amtOut);
/// @dev add collarteral to position
/// @param _posId position id
/// @param _amtIn token amount to transfer from msg sender (for wNative, amt to transfer will reduce by msg value)
function addCollateral(uint _posId, uint _amtIn) external payable;
/// @dev remove collateral from position
/// @param _posId margin trading position id
/// @param _shares shares amount to withdraw
/// @param _returnNative return wNative as native token or not (using balanceOf(address(this)))
function removeCollateral(uint _posId, uint _shares, bool _returnNative) external;
/// @dev repay debt of position
/// @param _posId margin trading position id
/// @param _repayShares debt shares to repay
/// @return repayAmt actual amount of debt repaid
function repayDebt(uint _posId, uint _repayShares) external payable returns (uint repayAmt);
/// @dev reduce position size
/// @param _posId margin trading position id
/// @param _collAmt collateral amt to reduce
/// @param _repayShares debt shares to repay
/// @param _tokenOut token to transfer to msg sender
/// @param _minAmtOut minimum amount of token to transfer to msg sender
/// @param _returnNative return wNative as native token or not (using balanceOf(address(this)))
/// @param _data swap data
/// @return amtOut actual amount of token transferred to msg sender
function reducePos(
uint _posId,
uint _collAmt,
uint _repayShares,
address _tokenOut,
uint _minAmtOut,
bool _returnNative,
bytes calldata _data
) external returns (uint amtOut);
/// @dev create stop loss order
/// @param _posId margin trading position id
/// @param _triggerPrice_e36 oracle price (quote asset price / base asset price) to trigger limit order
/// @param _tokenOut token to transfer to msg sender
/// @param _limitPrice_e36 price limit price (quote asset price / base asset price) to fill order
/// @param _collAmt collateral size for the order
/// @return orderId order id
function addStopLossOrder(
uint _posId,
uint _triggerPrice_e36,
address _tokenOut,
uint _limitPrice_e36,
uint _collAmt
) external returns (uint orderId);
/// @dev create take profit order
/// @param _posId margin trading position id
/// @param _triggerPrice_e36 oracle price (quote asset price / base asset price) to trigger limit order
/// @param _tokenOut token to transfer to msg sender
/// @param _limitPrice_e36 price limit price (quote asset price / base asset price) to fill order
/// @param _collAmt share of collateral to use in order
/// @return orderId order id
function addTakeProfitOrder(
uint _posId,
uint _triggerPrice_e36,
address _tokenOut,
uint _limitPrice_e36,
uint _collAmt
) external returns (uint orderId);
/// @dev cancel and create new order
/// @param _orderId order id
/// @param _triggerPrice_e36 oracle price (quote asset price / base asset price) to trigger limit order
/// @param _tokenOut token to transfer to msg sender
/// @param _limitPrice_e36 price limit price (quote asset price / base asset price) to fill order
/// @param _collAmt share of collateral to use in order
/// @return newOrderId new order id
function cancelAndCreateNewOrder(
uint _posId,
uint _orderId,
uint _triggerPrice_e36,
address _tokenOut,
uint _limitPrice_e36,
uint _collAmt
) external returns (uint newOrderId);
/// @dev cancel order
/// @param _posId margin trading position id
/// @param _orderId order id
function cancelOrder(uint _posId, uint _orderId) external;
/// @dev arbitrager reduce position in order and collateral at limit price
/// @param _orderId order id
function fillOrder(uint _orderId) external;
/// @notice _tokenA and _tokenB MUST be different
/// @dev set quote asset of pair
/// @param _tokenA token A of pair
/// @param _tokenB token B of pair
/// @param _quoteAsset quote asset of pair
function setQuoteAsset(address _tokenA, address _tokenB, address _quoteAsset) external;
/// @dev set swap helper
/// @param _swapHelper swap helper address
function setSwapHelper(address _swapHelper) external;
/// @dev get base asset and token asset of pair
/// @param _tokenA token A of pair
/// @param _tokenB token B of pair
/// @return baseAsset base asset of pair
/// @return quoteAsset quote asset of pair
function getBaseAssetAndQuoteAsset(address _tokenA, address _tokenB)
external
view
returns (address baseAsset, address quoteAsset);
/// @dev get order information
/// @param _orderId order id
/// @return order order information
function getOrder(uint _orderId) external view returns (Order memory);
/// @dev get margin position information
/// @param _initPosId init position id (nft id)
/// @return marginPos margin position information
function getMarginPos(uint _initPosId) external view returns (MarginPos memory);
/// @dev get position's orders length
/// @param _initPosId init position id (nft id)
function getPosOrdersLength(uint _initPosId) external view returns (uint);
/// @dev get hook's order id
function lastOrderId() external view returns (uint);
/// @dev get all position's order ids
/// @param _initPosId init position id (nft id)
function getPosOrderIds(uint _initPosId) external view returns (uint[] memory);
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
/// @title Lending Pool Interface
/// @notice rebase token is not supported
interface ILendingPool {
event SetIrm(address _irm);
event SetReserveFactor_e18(uint _reserveFactor_e18);
event SetTreasury(address _treasury);
/// @dev get core address
function core() external view returns (address core);
/// @dev get the interest rate model address
function irm() external view returns (address model);
/// @dev get the reserve factor in 1e18 (1e18 = 100%)
function reserveFactor_e18() external view returns (uint factor_e18);
/// @dev get the pool's underlying token
function underlyingToken() external view returns (address token);
/// @notice total assets = cash + total debts
function totalAssets() external view returns (uint amt);
/// @dev get the pool total debt (underlying token)
function totalDebt() external view returns (uint debt);
/// @dev get the pool total debt shares
function totalDebtShares() external view returns (uint shares);
/// @dev calaculate the debt share from debt amount (without interest accrual)
/// @param _amt the amount of debt
/// @return shares amount of debt shares (rounded up)
function debtAmtToShareStored(uint _amt) external view returns (uint shares);
/// @dev calaculate the debt share from debt amount (with interest accrual)
/// @param _amt the amount of debt
/// @return shares current amount of debt shares (rounded up)
function debtAmtToShareCurrent(uint _amt) external returns (uint shares);
/// @dev calculate the corresponding debt amount from debt share (without interest accrual)
/// @param _shares the amount of debt shares
/// @return amt corresponding debt amount (rounded up)
function debtShareToAmtStored(uint _shares) external view returns (uint amt);
/// @notice this is NOT a view function
/// @dev calculate the corresponding debt amount from debt share (with interest accrual)
/// @param _shares the amount of debt shares
/// @return amt corresponding current debt amount (rounded up)
function debtShareToAmtCurrent(uint _shares) external returns (uint amt);
/// @dev get current supply rate per sec in 1e18
function getSupplyRate_e18() external view returns (uint supplyRate_e18);
/// @dev get current borrow rate per sec in 1e18
function getBorrowRate_e18() external view returns (uint borrowRate_e18);
/// @dev get the pool total cash (underlying token)
function cash() external view returns (uint amt);
/// @dev get the latest timestamp of interest accrual
/// @return lastAccruedTime last accrued time unix timestamp
function lastAccruedTime() external view returns (uint lastAccruedTime);
/// @dev get the treasury address
function treasury() external view returns (address treasury);
/// @notice only core can call this function
/// @dev mint shares to the receiver from the transfered assets
/// @param _receiver address to receive shares
/// @return mintShares amount of shares minted
function mint(address _receiver) external returns (uint mintShares);
/// @notice only core can call this function
/// @dev burn shares and send the underlying assets to the receiver
/// @param _receiver address to receive the underlying tokens
/// @return amt amount of underlying assets transferred
function burn(address _receiver) external returns (uint amt);
/// @notice only core can call this function
/// @dev borrow the asset from the lending pool
/// @param _receiver address to receive the borrowed asset
/// @param _amt amount of asset to borrow
/// @return debtShares debt shares amount recorded from borrowing
function borrow(address _receiver, uint _amt) external returns (uint debtShares);
/// @notice only core can call this function
/// @dev repay the borrowed assets
/// @param _shares the amount of debt shares to repay
/// @return amt assets amount used for repay
function repay(uint _shares) external returns (uint amt);
/// @dev accrue interest from the last accrual
function accrueInterest() external;
/// @dev get the share amounts from underlying asset amt
/// @param _amt the amount of asset to convert to shares
/// @return shares amount of shares (rounded down)
function toShares(uint _amt) external view returns (uint shares);
/// @dev get the asset amount from shares
/// @param _shares the amount of shares to convert to underlying asset amt
/// @return amt amount of underlying asset (rounded down)
function toAmt(uint _shares) external view returns (uint amt);
/// @dev get the share amounts from underlying asset amt (with interest accrual)
/// @param _amt the amount of asset to convert to shares
/// @return shares current amount of shares (rounded down)
function toSharesCurrent(uint _amt) external returns (uint shares);
/// @dev get the asset amount from shares (with interest accrual)
/// @param _shares the amount of shares to convert to underlying asset amt
/// @return amt current amount of underlying asset (rounded down)
function toAmtCurrent(uint _shares) external returns (uint amt);
/// @dev set the interest rate model
/// @param _irm new interest rate model address
function setIrm(address _irm) external;
/// @dev set the pool's reserve factor in 1e18
/// @param _reserveFactor_e18 new reserver factor in 1e18
function setReserveFactor_e18(uint _reserveFactor_e18) external;
/// @dev set the pool's treasury address
/// @param _treasury new treasury address
function setTreasury(address _treasury) external;
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
/// @title Base Oracle Interface
interface IBaseOracle {
/// @dev return the value of the token as USD, multiplied by 1e36.
/// @param _token token address
/// @return price_e36 token price in 1e36
function getPrice_e36(address _token) external view returns (uint price_e36);
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
import {IBaseOracle} from './IBaseOracle.sol';
/// @title Init Oracle Interface
interface IInitOracle is IBaseOracle {
event SetPrimarySource(address indexed token, address oracle);
event SetSecondarySource(address indexed token, address oracle);
event SetMaxPriceDeviation_e18(address indexed token, uint maxPriceDeviation_e18);
/// @dev return the oracle token's primary source
/// @param _token token address
/// @return primarySource primary oracle address
function primarySources(address _token) external view returns (address primarySource);
/// @dev return the oracle token's secondary source
/// @param _token token address
/// @return secondarySource secoundary oracle address
function secondarySources(address _token) external view returns (address secondarySource);
/// @dev return the max price deviation between the primary and secondary sources
/// @param _token token address
/// @return maxPriceDeviation_e18 max price deviation in 1e18
function maxPriceDeviations_e18(address _token) external view returns (uint maxPriceDeviation_e18);
/// @dev return the price of the tokens in USD, multiplied by 1e36.
/// @param _tokens token address list
/// @return prices_e36 the token prices for each tokens
function getPrices_e36(address[] calldata _tokens) external view returns (uint[] memory prices_e36);
/// @dev set primary source for tokens
/// @param _tokens token address list
/// @param _sources the primary source address for each tokens
function setPrimarySources(address[] calldata _tokens, address[] calldata _sources) external;
/// @dev set secondary source for tokens
/// @param _tokens token address list
/// @param _sources the secondary source address for each tokens
function setSecondarySources(address[] calldata _tokens, address[] calldata _sources) external;
/// @dev set max price deviation between the primary and sercondary sources
/// @param _tokens token address list
/// @param _maxPriceDeviations_e18 the max price deviation in 1e18 for each tokens
function setMaxPriceDeviations_e18(address[] calldata _tokens, uint[] calldata _maxPriceDeviations_e18) external;
}// SPDX-License-Identifier: None
pragma solidity ^0.8.19;
/// @title Callback Receiver Interface
interface ICallbackReceiver {
/// @dev handle the callback from core
/// @param _sender the sender address
/// @param _data the data payload to execute on the callback
/// @return result the encoded result of the callback
function coreCallback(address _sender, bytes calldata _data) external payable returns (bytes memory result);
}{
"evmVersion": "paris",
"libraries": {},
"metadata": {
"appendCBOR": true,
"bytecodeHash": "ipfs",
"useLiteralContent": false
},
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [
"@forge-std/=lib/forge-std/src/",
"@openzeppelin-contracts/=contracts/.cache/OpenZeppelin/v4.9.3/",
"@openzeppelin-contracts-upgradeable/=contracts/.cache/OpenZeppelin-Upgradeable/v4.9.3/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/"
],
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_core","type":"address"},{"internalType":"address","name":"_posManager","type":"address"},{"internalType":"address","name":"_wNative","type":"address"},{"internalType":"address","name":"_acm","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"initPosId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"CancelOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"initPosId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"orderId","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"triggerPrice_e36","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"limitPrice_e36","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"size","type":"uint256"},{"indexed":false,"internalType":"enum OrderType","name":"orderType","type":"uint8"}],"name":"CreateOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"initPosId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"orderId","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amtOut","type":"uint256"}],"name":"FillOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"initPosId","type":"uint256"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":true,"internalType":"address","name":"borrToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amtIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowAmt","type":"uint256"}],"name":"IncreasePos","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"initPosId","type":"uint256"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amtOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"size","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"repayAmt","type":"uint256"}],"name":"ReducePos","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenA","type":"address"},{"indexed":false,"internalType":"address","name":"tokenB","type":"address"},{"indexed":false,"internalType":"address","name":"quoteAsset","type":"address"}],"name":"SetQuoteAsset","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"swapHelper","type":"address"}],"name":"SetSwapHelper","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"initPosId","type":"uint256"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amtIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amtOut","type":"uint256"}],"name":"SwapToIncreasePos","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"initPosId","type":"uint256"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amtIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amtOut","type":"uint256"}],"name":"SwapToReducePos","type":"event"},{"inputs":[],"name":"ACM","outputs":[{"internalType":"contract IAccessControlManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CORE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POS_MANAGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WNATIVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_posId","type":"uint256"},{"internalType":"uint256","name":"_amtIn","type":"uint256"}],"name":"addCollateral","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_posId","type":"uint256"},{"internalType":"uint256","name":"_triggerPrice_e36","type":"uint256"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"uint256","name":"_limitPrice_e36","type":"uint256"},{"internalType":"uint256","name":"_collAmt","type":"uint256"}],"name":"addStopLossOrder","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_posId","type":"uint256"},{"internalType":"uint256","name":"_triggerPrice_e36","type":"uint256"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"uint256","name":"_limitPrice_e36","type":"uint256"},{"internalType":"uint256","name":"_collAmt","type":"uint256"}],"name":"addTakeProfitOrder","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_posId","type":"uint256"},{"internalType":"uint256","name":"_orderId","type":"uint256"},{"internalType":"uint256","name":"_triggerPrice_e36","type":"uint256"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"uint256","name":"_limitPrice_e36","type":"uint256"},{"internalType":"uint256","name":"_collAmt","type":"uint256"}],"name":"cancelAndCreateNewOrder","outputs":[{"internalType":"uint256","name":"newOrderId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_posId","type":"uint256"},{"internalType":"uint256","name":"_orderId","type":"uint256"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"coreCallback","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_orderId","type":"uint256"}],"name":"fillOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenA","type":"address"},{"internalType":"address","name":"_tokenB","type":"address"}],"name":"getBaseAssetAndQuoteAsset","outputs":[{"internalType":"address","name":"baseAsset","type":"address"},{"internalType":"address","name":"quoteAsset","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initPosId","type":"uint256"}],"name":"getMarginPos","outputs":[{"components":[{"internalType":"address","name":"collPool","type":"address"},{"internalType":"address","name":"borrPool","type":"address"},{"internalType":"address","name":"baseAsset","type":"address"},{"internalType":"address","name":"quoteAsset","type":"address"},{"internalType":"bool","name":"isLongBaseAsset","type":"bool"}],"internalType":"struct MarginPos","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_orderId","type":"uint256"}],"name":"getOrder","outputs":[{"components":[{"internalType":"uint256","name":"initPosId","type":"uint256"},{"internalType":"uint256","name":"triggerPrice_e36","type":"uint256"},{"internalType":"uint256","name":"limitPrice_e36","type":"uint256"},{"internalType":"uint256","name":"collAmt","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"enum OrderStatus","name":"status","type":"uint8"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct Order","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initPosId","type":"uint256"}],"name":"getPosOrderIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initPosId","type":"uint256"}],"name":"getPosOrdersLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_posId","type":"uint256"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"uint256","name":"_amtIn","type":"uint256"},{"internalType":"uint256","name":"_borrAmt","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"uint256","name":"_minAmtOut","type":"uint256"}],"name":"increasePos","outputs":[{"internalType":"uint256","name":"amtOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"initPosIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_swapHelper","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastOrderId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastPosIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_mode","type":"uint16"},{"internalType":"address","name":"_viewer","type":"address"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"uint256","name":"_amtIn","type":"uint256"},{"internalType":"address","name":"_borrPool","type":"address"},{"internalType":"uint256","name":"_borrAmt","type":"uint256"},{"internalType":"address","name":"_collPool","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"uint256","name":"_minAmtOut","type":"uint256"}],"name":"openPos","outputs":[{"internalType":"uint256","name":"posId","type":"uint256"},{"internalType":"uint256","name":"initPosId","type":"uint256"},{"internalType":"uint256","name":"amtOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_posId","type":"uint256"},{"internalType":"uint256","name":"_collAmt","type":"uint256"},{"internalType":"uint256","name":"_repayShares","type":"uint256"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"uint256","name":"_minAmtOut","type":"uint256"},{"internalType":"bool","name":"_returnNative","type":"bool"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"reducePos","outputs":[{"internalType":"uint256","name":"amtOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_posId","type":"uint256"},{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"bool","name":"_returnNative","type":"bool"}],"name":"removeCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_posId","type":"uint256"},{"internalType":"uint256","name":"_repayShares","type":"uint256"}],"name":"repayDebt","outputs":[{"internalType":"uint256","name":"repayAmt","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenA","type":"address"},{"internalType":"address","name":"_tokenB","type":"address"},{"internalType":"address","name":"_quoteAsset","type":"address"}],"name":"setQuoteAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_swapHelper","type":"address"}],"name":"setSwapHelper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapHelper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6101006040523480156200001257600080fd5b5060405162005a7238038062005a72833981016040819052620000359162000076565b6001600160a01b0393841660805291831660a05290821660c0521660e052620000d3565b80516001600160a01b03811681146200007157600080fd5b919050565b600080600080608085870312156200008d57600080fd5b620000988562000059565b9350620000a86020860162000059565b9250620000b86040860162000059565b9150620000c86060860162000059565b905092959194509250565b60805160a05160c05160e0516158386200023a600039600081816105f30152818161072d01528181610a2c01528181610ac1015281816111f701528181611350015281816113da0152818161179c0152818161182e01528181611f610152818161241f015281816124a80152818161259a0152818161282d015281816128c901528181612e9801528181612f21015281816130470152613da101526000818161070101528181611db40152612d2a0152600081816101ff0152818161080a01528181610f07015281816126f8015281816132a001528181613b5401528181613eaa01528181613f4a0152818161481101526148b20152600081816103c10152818161099b0152818161107a0152818161110a01528181611603015281816116970152818161190c01528181611ffd01528181612720015281816127b8015281816130dc01528181613167015281816134c401528181613c59015261445601526158386000f3fe6080604052600436106101c25760003560e01c80638192ac36116100f7578063b381cf4011610095578063d4e1d6df11610064578063d4e1d6df14610682578063d73cd47f146106af578063edd49038146106cf578063f9b80da1146106ef57600080fd5b8063b381cf40146105e1578063b6ed063214610615578063c4d66de814610635578063d09ef2411461065557600080fd5b80639559f3e4116100d15780639559f3e4146105605780639826439f14610580578063a517db8f146105ae578063a8f35adf146105ce57600080fd5b80638192ac36146104235780638a839fde14610443578063902a338b1461046357600080fd5b80633b253cc81161016457806367b830ad1161013e57806367b830ad1461037a5780636864eb161461039c5780636b6c0774146103af57806378476fe9146103e357600080fd5b80633b253cc81461032457806342086a5d146103445780635662ecc71461036457600080fd5b80630fc6a11c116101a05780630fc6a11c14610266578063127e12eb14610286578063150b7a02146102be578063376822d6146102f757600080fd5b8063015cb0a5146101c75780630278b670146101ed57806309be263814610239575b600080fd5b6101da6101d5366004614c5f565b610723565b6040519081526020015b60405180910390f35b3480156101f957600080fd5b506102217f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101e4565b34801561024557600080fd5b506101da610254366004614ca9565b60336020526000908152604090205481565b34801561027257600080fd5b50603554610221906001600160a01b031681565b34801561029257600080fd5b506101da6102a1366004614cc6565b603460209081526000928352604080842090915290825290205481565b3480156102ca57600080fd5b506102de6102d9366004614de0565b610b90565b6040516001600160e01b031990911681526020016101e4565b34801561030357600080fd5b506101da610312366004614e4c565b60009081526039602052604090205490565b34801561033057600080fd5b506101da61033f366004614e65565b610ba1565b34801561035057600080fd5b506101da61035f366004614eae565b610bbc565b34801561037057600080fd5b506101da603a5481565b34801561038657600080fd5b5061039a610395366004614e4c565b610cbe565b005b6101da6103aa366004614f4a565b6111ed565b3480156103bb57600080fd5b506102217f000000000000000000000000000000000000000000000000000000000000000081565b3480156103ef57600080fd5b506104036103fe366004614fc6565b6114ae565b604080516001600160a01b039384168152929091166020830152016101e4565b34801561042f57600080fd5b5061039a61043e36600461500d565b611542565b610456610451366004615046565b6118fc565b6040516101e491906150eb565b34801561046f57600080fd5b5061050f61047e366004614e4c565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915250600090815260386020908152604091829020825160a08101845281546001600160a01b03908116825260018301548116938201939093526002820154831693810193909352600301549081166060830152600160a01b900460ff161515608082015290565b6040516101e4919081516001600160a01b0390811682526020808401518216908301526040808401518216908301526060808401519091169082015260809182015115159181019190915260a00190565b34801561056c57600080fd5b5061039a61057b3660046150fe565b611d79565b61059361058e36600461513e565b611f55565b604080519384526020840192909252908201526060016101e4565b3480156105ba57600080fd5b506101da6105c9366004614e65565b612581565b61039a6105dc366004614c5f565b612592565b3480156105ed57600080fd5b506102217f000000000000000000000000000000000000000000000000000000000000000081565b34801561062157600080fd5b5061039a610630366004614c5f565b612994565b34801561064157600080fd5b5061039a610650366004614ca9565b612a46565b34801561066157600080fd5b50610675610670366004614e4c565b612ba6565b6040516101e4919061523b565b34801561068e57600080fd5b506106a261069d366004614e4c565b612c8d565b6040516101e491906152b8565b3480156106bb57600080fd5b5061039a6106ca366004614ca9565b612cef565b3480156106db57600080fd5b506101da6106ea3660046152fc565b612de3565b3480156106fb57600080fd5b506102217f000000000000000000000000000000000000000000000000000000000000000081565b600034156107a0577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561078657600080fd5b505af115801561079a573d6000803e3d6000fd5b50505050505b3360009081526034602090815260408083208684529091529020546107cb8115156323333031612ff6565b600081815260386020526040808220600181015491516310e28e7160e01b8152600481018590526001600160a01b0392831660248201819052919391927f000000000000000000000000000000000000000000000000000000000000000016906310e28e7190604401602060405180830381865afa158015610851573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610875919061538b565b905080861115610883578095505b6000826001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e791906153a4565b6040516331a86fe160e01b8152600481018990529091506000906001600160a01b038516906331a86fe1906024016020604051808303816000875af1158015610934573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610958919061538b565b9050610964828261303b565b61096e82826130bf565b604051638cd2e0c760e01b81526001600160a01b038581166004830152602482018a9052604482018890527f00000000000000000000000000000000000000000000000000000000000000001690638cd2e0c7906064016020604051808303816000875af11580156109e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a08919061538b565b6040516370a0823160e01b8152306004820152909750600096506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001695506370a0823194506024019250610a62915050565b602060405180830381865afa158015610a7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa3919061538b565b90508015610b2657604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015610b0d57600080fd5b505af1158015610b21573d6000803e3d6000fd5b505050505b478015610b8857604051600090339083908381818185875af1925050503d8060008114610b6f576040519150601f19603f3d011682016040523d82523d6000602084013e610b74565b606091505b50509050610b86816323313033612ff6565b505b505092915050565b630a85bd0160e11b5b949350505050565b6000610bb28686868686600061318e565b9695505050505050565b600085815260376020908152604080832081516101008101835281548152600180830154948201949094526002820154928101929092526003810154606083015260048101546001600160a01b0381166080840152849360a0840191600160a01b900460ff1690811115610c3257610c32615201565b6001811115610c4357610c43615201565b81526020016004820160159054906101000a900460ff166002811115610c6b57610c6b615201565b6002811115610c7c57610c7c615201565b8152600591909101546001600160a01b03166020909101529050610ca08888612994565b610cb288878787878660a0015161318e565b98975050505050505050565b600081815260376020908152604080832081516101008101835281548152600180830154948201949094526002820154928101929092526003810154606083015260048101546001600160a01b03811660808401529192909160a0840191600160a01b90910460ff1690811115610d3757610d37615201565b6001811115610d4857610d48615201565b81526020016004820160159054906101000a900460ff166002811115610d7057610d70615201565b6002811115610d8157610d81615201565b8152600591909101546001600160a01b03166020909101529050610dc160018260c001516002811115610db657610db6615201565b146323323033612ff6565b80516000908152603860209081526040808320815160a08101835281546001600160a01b03908116808352600184015482168387015260028401548216838601526003909301549081166060830152600160a01b900460ff16151560808201528251632495a59960e01b815292519094939192632495a5999260048083019391928290030181865afa158015610e5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7f91906153a4565b9050600082602001516001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ec5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee991906153a4565b8451845160405163402414b360e01b81529293506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263402414b392610f4e9290916004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015610f6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8f919061538b565b600003610fe357600085815260376020526040808220600401805460ff60a81b191690558551905187927fbb139d33583839e19389be0c788bb4983ba63129333b3ffe835a4c4af0e5dcb891a35050505050565b610fed84846134c0565b6000806000610ffd87878761369d565b60008b8152603760205260409020600401805460ff60a81b1916600160a91b1790559194509250905061103b6001600160a01b038516333084613824565b61104584826130bf565b60208601518751604051638cd2e0c760e01b81526001600160a01b0392831660048201526024810185905260448101919091527f000000000000000000000000000000000000000000000000000000000000000090911690638cd2e0c7906064016020604051808303816000875af11580156110c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e9919061538b565b508651865160608901516040516342d91bc360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016936342d91bc39361114493919290919033906004016153c1565b600060405180830381600087803b15801561115e57600080fd5b505af1158015611172573d6000803e3d6000fd5b50505060e0880151608089015161119692506001600160a01b031690339086613824565b86516080880151604080516001600160a01b039092168252602082018690528a92917f78c6ecc039f51fb5f61970280bf0c91681f694af59c658ee264c5d343bdd6daa910160405180910390a35050505050505050565b6000341561126a577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561125057600080fd5b505af1158015611264573d6000803e3d6000fd5b50505050505b3360009081526034602090815260408083208b84529091529020546112958115156323333031612ff6565b6000818152603860209081526040918290208251610100810184528481526001600160a01b03808d16828501528185018c9052600183015481166060830152608082018b905282541660a08201528351601f8901849004840281018401909452878452909261132c9260c0830191908a908a908190840183828082843760009201919091525050509082525060200186905261388f565b6040516370a0823160e01b8152306004820152909350600092506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691506370a0823190602401602060405180830381865afa158015611398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bc919061538b565b9050801561143f57604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561142657600080fd5b505af115801561143a573d6000803e3d6000fd5b505050505b4780156114a157604051600090339083908381818185875af1925050503d8060008114611488576040519150601f19603f3d011682016040523d82523d6000602084013e61148d565b606091505b5050905061149f816323313033612ff6565b505b5050979650505050505050565b600080600080846001600160a01b0316866001600160a01b0316106114d45784866114d7565b85855b6001600160a01b038083166000908152603660209081526040808320848616845290915290205416945090925090506115168315156323313030612ff6565b816001600160a01b0316836001600160a01b0316146115355781611537565b805b935050509250929050565b33600090815260346020908152604080832086845290915290205461156d8115156323333031612ff6565b600081815260386020908152604080832080548251632495a59960e01b815292519194936001600160a01b0390911692632495a59992600480830193928290030181865afa1580156115c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e791906153a4565b82546040516342d91bc360e01b81529192506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116926342d91bc3926116409288929116908a9082906004016153c1565b600060405180830381600087803b15801561165a57600080fd5b505af115801561166e573d6000803e3d6000fd5b50508354604051637fe6bc3d60e01b81526001600160a01b0391821660048201523060248201527f00000000000000000000000000000000000000000000000000000000000000009091169250637fe6bc3d91506044016020604051808303816000875af11580156116e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611708919061538b565b506040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611750573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611774919061538b565b9050611781828287613d9f565b50506040516370a0823160e01b8152306004820152600092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691506370a0823190602401602060405180830381865afa1580156117ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611810919061538b565b9050801561189357604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561187a57600080fd5b505af115801561188e573d6000803e3d6000fd5b505050505b4780156118f557604051600090339083908381818185875af1925050503d80600081146118dc576040519150601f19603f3d011682016040523d82523d6000602084013e6118e1565b606091505b505090506118f3816323313033612ff6565b505b5050505050565b6060611937336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146323313031612ff6565b6119506001600160a01b03851630146323333037612ff6565b600061195e838501856153e8565b80516000908152603860209081526040808320815160a08101835281546001600160a01b039081168252600183015481169482019490945260028201548416818401526003909101548084166060830152600160a01b900460ff16151560808201528185015191516370a0823160e01b8152306004820152949550939116906370a0823190602401602060405180830381865afa158015611a03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a27919061538b565b6035546040850151919250611a49916001600160a01b03908116911683613df3565b60608301516040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611a94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab8919061538b565b60355460405163c2f8bbf360e01b81529192506001600160a01b03169063c2f8bbf390611ae99087906004016154a2565b600060405180830381600087803b158015611b0357600080fd5b505af1158015611b17573d6000803e3d6000fd5b5050505060608401516040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611b66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b8a919061538b565b90506000611b98838361551e565b9050600086602001516002811115611bb257611bb2615201565b03611c3c5784516060870151611bd4916001600160a01b039091169084613df3565b85606001516001600160a01b031686604001516001600160a01b031687600001517f53213ad1644c4b9abd2a1229db22ef606e1aad9d76882f6c081b4bdbdf3dad718785604051611c2f929190918252602082015260400190565b60405180910390a4611d4f565b83600287602001516002811115611c5557611c55615201565b03611cea57611c6f87608001518310156323313032612ff6565b60408088015190516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611cb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cdd919061538b565b611ce7908261551e565b90505b86606001516001600160a01b031687604001516001600160a01b031688600001517f5928107fb4d041486e4299ebc0b9cb4733396fecbf531e53f9ae6bf3fa58ac418486604051611d45929190918252602082015260400190565b60405180910390a4505b60408051602081018390520160405160208183030381529060405296505050505050509392505050565b6040516312d9a6ad60e01b81527f1e46cebd6689d8c64011118478db0c61a89aa2646c860df401de476fbf37898360048201523360248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906312d9a6ad90604401600060405180830381600087803b158015611e0057600080fd5b505af1158015611e14573d6000803e3d6000fd5b50611e46925050506001600160a01b03841615801590611e3c57506001600160a01b03831615155b6323313030612ff6565b611e84836001600160a01b0316826001600160a01b03161480611e7a5750826001600160a01b0316826001600160a01b0316145b6323323033612ff6565b611ea7826001600160a01b0316846001600160a01b031614156323323036612ff6565b600080836001600160a01b0316856001600160a01b031610611eca578385611ecd565b84845b6001600160a01b0382811660008181526036602090815260408083208686168085529083529281902080546001600160a01b031916958b16958617905580519384529083019190915281019190915291935091507f3de6d5493137a9234846bdb84bffebd5bf0b008b6a838c6570a0fa48292c20819060600160405180910390a15050505050565b600080803415611fd4577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015611fba57600080fd5b505af1158015611fce573d6000803e3d6000fd5b50505050505b604051630bed2fd960e21b815261ffff8e1660048201526001600160a01b038d811660248301527f00000000000000000000000000000000000000000000000000000000000000001690632fb4bf64906044016020604051808303816000875af1158015612046573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206a919061538b565b91506000896001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d091906153a4565b905060008061219c8a6001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015612116573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213a91906153a4565b8d6001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015612178573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103fe91906153a4565b915091506000836001600160a01b0316836001600160a01b0316141590506040518060a001604052808c6001600160a01b031681526020018e6001600160a01b03168152602001846001600160a01b03168152602001836001600160a01b031681526020018215158152506038600088815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060608201518160030160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060808201518160030160146101000a81548160ff02191690831515021790555090505050505060336000336001600160a01b03166001600160a01b031681526020019081526020016000206000815461232690615531565b91905081905593508260346000336001600160a01b03166001600160a01b031681526020019081526020016000206000868152602001908152602001600020819055506123fb6040518061010001604052808581526020018e6001600160a01b031681526020018d81526020018c6001600160a01b031681526020018b81526020018a6001600160a01b0316815260200189898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060200187905261388f565b6040516370a0823160e01b8152306004820152909250600091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061248a919061538b565b9050801561250d57604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156124f457600080fd5b505af1158015612508573d6000803e3d6000fd5b505050505b47801561256f57604051600090339083908381818185875af1925050503d8060008114612556576040519150601f19603f3d011682016040523d82523d6000602084013e61255b565b606091505b5050905061256d816323313033612ff6565b505b50509a509a509a975050505050505050565b6000610bb28686868686600161318e565b341561260d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156125f357600080fd5b505af1158015612607573d6000803e3d6000fd5b50505050505b3360009081526034602090815260408083208584529091529020546126388115156323333031612ff6565b600081815260386020908152604080832080548251632495a59960e01b815292519194936001600160a01b0390911692632495a59992600480830193928290030181865afa15801561268e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b291906153a4565b90506126be818561303b565b81546126d7906001600160a01b03838116911686613df3565b8154604051634a8db60160e11b81526001600160a01b0391821660048201527f0000000000000000000000000000000000000000000000000000000000000000821660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063951b6c02906044016020604051808303816000875af115801561276b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061278f919061538b565b50815460405163abf4dd3960e01b8152600481018590526001600160a01b0391821660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063abf4dd3990604401600060405180830381600087803b1580156127fe57600080fd5b505af1158015612812573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600095507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031694506370a082319350602401915061286a9050565b602060405180830381865afa158015612887573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ab919061538b565b9050801561292e57604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561291557600080fd5b505af1158015612929573d6000803e3d6000fd5b505050505b47801561298e57604051600090339083908381818185875af1925050503d8060008114612977576040519150601f19603f3d011682016040523d82523d6000602084013e61297c565b606091505b505090506118f5816323313033612ff6565b50505050565b3360009081526034602090815260408083208584529091529020546129bf8115156323333031612ff6565b600082815260376020526040902080546129df9083146323323033612ff6565b612a0460016004830154600160a81b900460ff166002811115610db657610db6615201565b60048101805460ff60a81b19169055604051839083907fbb139d33583839e19389be0c788bb4983ba63129333b3ffe835a4c4af0e5dcb890600090a350505050565b600054610100900460ff1615808015612a665750600054600160ff909116105b80612a805750303b158015612a80575060005460ff166001145b612ae85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015612b0b576000805461ff0019166101001790555b603580546001600160a01b0319166001600160a01b0384169081179091556040519081527f9fd27a9e967ce43ed9a2500f7565d0f89346e02dda9e8584f14d9b3d5ddda8629060200160405180910390a18015612ba2576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b612bae614c00565b60008281526037602090815260409182902082516101008101845281548152600180830154938201939093526002820154938101939093526003810154606084015260048101546001600160a01b0381166080850152909160a0840191600160a01b900460ff1690811115612c2557612c25615201565b6001811115612c3657612c36615201565b81526020016004820160159054906101000a900460ff166002811115612c5e57612c5e615201565b6002811115612c6f57612c6f615201565b8152600591909101546001600160a01b031660209091015292915050565b600081815260396020908152604091829020805483518184028101840190945280845260609392830182828015612ce357602002820191906000526020600020905b815481526020019060010190808311612ccf575b50505050509050919050565b6040516312d9a6ad60e01b81527f1e46cebd6689d8c64011118478db0c61a89aa2646c860df401de476fbf37898360048201523360248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906312d9a6ad90604401600060405180830381600087803b158015612d7657600080fd5b505af1158015612d8a573d6000803e3d6000fd5b5050603580546001600160a01b0319166001600160a01b0385169081179091556040519081527f9fd27a9e967ce43ed9a2500f7565d0f89346e02dda9e8584f14d9b3d5ddda8629250602001905060405180910390a150565b3360009081526034602090815260408083208b8452825280832054815160e0810183528181528084018c90528083018b90526001600160a01b038a1660608201526080810189905287151560a08201528251601f87018590048502810185019093528583529092612e749260c083019188908890819084018382808284376000920191909152505050915250613e23565b6040516370a0823160e01b8152306004820152909250600091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612edf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f03919061538b565b90508015612f8657604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015612f6d57600080fd5b505af1158015612f81573d6000803e3d6000fd5b505050505b478015612fe857604051600090339083908381818185875af1925050503d8060008114612fcf576040519150601f19603f3d011682016040523d82523d6000602084013e612fd4565b606091505b50509050612fe6816323313033612ff6565b505b505098975050505050505050565b81612ba2576040516001600160e01b031960e083901b16602082015260240160408051601f198184030181529082905262461bcd60e51b8252612adf916004016150eb565b80341561309f576130847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b0316146323313035612ff6565b34821161309257600061309c565b61309c348261551e565b90505b80156130ba576130ba6001600160a01b038416333084613824565b505050565b604051636eb1769f60e11b81523060048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015282919084169063dd62ed3e90604401602060405180830381865afa15801561312e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613152919061538b565b1015612ba257612ba26001600160a01b0383167f00000000000000000000000000000000000000000000000000000000000000006000196145d8565b6000603a6000815461319f90615531565b918290555090506131b68315156323313030612ff6565b3360009081526034602090815260408083208a84529091529020546131e18115156323333031612ff6565b600081815260386020908152604091829020825160a08101845281546001600160a01b0390811682526001830154811693820193909352600282015483169381018490526003909101548083166060830152600160a01b900460ff1615156080820152916132759189161480611e7a575081606001516001600160a01b0316886001600160a01b0316146323323033612ff6565b805160405163402414b360e01b8152600481018490526001600160a01b0391821660248201526000917f0000000000000000000000000000000000000000000000000000000000000000169063402414b390604401602060405180830381865afa1580156132e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061330b919061538b565b905061331e818711156323323032612ff6565b6040518061010001604052808481526020018a8152602001888152602001878152602001896001600160a01b0316815260200186600181111561336357613363615201565b815260016020808301829052336040938401526000888152603782528390208451815590840151818301559183015160028301556060830151600383015560808301516004830180546001600160a01b039092166001600160a01b031983168117825560a08601519391926001600160a81b0319161790600160a01b9084908111156133f1576133f1615201565b021790555060c082015160048201805460ff60a81b1916600160a81b83600281111561341f5761341f615201565b021790555060e09190910151600590910180546001600160a01b0319166001600160a01b0390921691909117905560008381526039602090815260408083208054600181018255908452919092200185905551849084907f86ac53d8eeffaf93525a46596fefefbc428a4ad0a3b9696a33674d4ba034f832906134ab908c908e908d908d908d9061554a565b60405180910390a35050509695505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015613520573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061354491906153a4565b60608301516040516339fa57cb60e11b81526001600160a01b039182166004820152919250600091613646916ec097ce7bc90715b34b9f100000000091908516906373f4af9690602401602060405180830381865afa1580156135ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135cf919061538b565b60408681015190516339fa57cb60e11b81526001600160a01b039182166004820152908616906373f4af9690602401602060405180830381865afa15801561361b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061363f919061538b565b91906146ed565b6080840151909150151560018560a00151600181111561366857613668615201565b14146136885761368384602001518211156323323033612ff6565b61298e565b61298e84602001518210156323323033612ff6565b60008060006136ac86866147dd565b60608901819052875160405163263a31fb60e21b815260048101929092529294509092506000916001600160a01b0316906398e8c7ec906024016020604051808303816000875af1158015613705573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613729919061538b565b905086608001516001600160a01b0316856001600160a01b0316036137ab5785608001511561378b5760408701516137706ec097ce7bc90715b34b9f10000000008461557c565b61377a91906155a9565b613784908261551e565b935061381a565b6ec097ce7bc90715b34b9f1000000000876040015183613770919061557c565b8560800151156137e957816137df6ec097ce7bc90715b34b9f10000000008960400151846137d9919061557c565b906149ce565b613784919061551e565b8161380d88604001516ec097ce7bc90715b34b9f1000000000846137d9919061557c565b613817919061551e565b93505b5093509350939050565b6040516001600160a01b038085166024830152831660448201526064810182905261298e9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614a08565b60006138a38260200151836040015161303b565b60408051600480825260a08201909252600091816020015b60608152602001906001900390816138bb575050606084015160808501518551604080516001600160a01b03909416602485015260448401929092526064830152306084808401919091528151808403909101815260a490920190526020810180516001600160e01b03166308ba54eb60e21b1790528151919250908290600090613948576139486155cb565b602002602001018190525060008360a001516001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015613997573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139bb91906153a4565b9050600084606001516001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a2591906153a4565b9050613a6c826001600160a01b031686602001516001600160a01b03161480611e7a5750816001600160a01b031686602001516001600160a01b0316146323323033612ff6565b6040805160c0808201835287518252600060208084018290526001600160a01b03808716858701528716606085015260e08a015160808501529189015160a084015292519192633eb0617f60e11b923092613ac9918691016154a2565b60408051601f1981840301815290829052613ae89392916024016155e1565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505084600181518110613b2e57613b2e6155cb565b60209081029190910101525060a08501516040516001600160a01b0391821660248201527f00000000000000000000000000000000000000000000000000000000000000009091166044820152634a8db60160e11b90606401604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505083600281518110613bcd57613bcd6155cb565b6020908102919091010152845160a086015160405160248101929092526001600160a01b0316604482015263abf4dd3960e01b90606401604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505083600381518110613c4a57613c4a6155cb565b602002602001018190525060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ac9650d8856040518263ffffffff1660e01b8152600401613ca39190615617565b6000604051808303816000875af1158015613cc2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613cea91908101906156be565b905080600181518110613cff57613cff6155cb565b6020026020010151806020019051810190613d1a9190615781565b806020019051810190613d2d919061538b565b9450816001600160a01b031686602001516001600160a01b031687600001517f48990dad1f3df6d1f813e38b5b6afba377ae5212af0e6f493947afd00dcb7c2e89604001518a60800151604051613d8e929190918252602082015260400190565b60405180910390a450505050919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316141580613dde575080155b156130ba576130ba6001600160a01b03841633845b6040516001600160a01b0383166024820152604481018290526130ba90849063a9059cbb60e01b90606401613858565b80516000908152603860209081526040808320815160a08101835281546001600160a01b03908116808352600184015482169583019590955260028301548116828501526003909201548083166060830152600160a01b900460ff16151560808201528551925163402414b360e01b815260048101939093526024830193909352613f28917f00000000000000000000000000000000000000000000000000000000000000009091169063402414b390604401602060405180830381865afa158015613ef3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f17919061538b565b846020015111156323323032612ff6565b825160208201516040516310e28e7160e01b8152613fe3926001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016926310e28e7192613f919291906004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015613fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd2919061538b565b846040015111156323323032612ff6565b600081600001516001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015614027573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061404b91906153a4565b9050600082602001516001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015614091573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140b591906153a4565b90506140fc826001600160a01b031686606001516001600160a01b03161480611e7a5750816001600160a01b031686606001516001600160a01b0316146323323033612ff6565b600083602001516001600160a01b03166331a86fe187604001516040518263ffffffff1660e01b815260040161413491815260200190565b6020604051808303816000875af1158015614153573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614177919061538b565b905061418382826130bf565b60408051600480825260a08201909252600091816020015b606081526020019060019003908161419b5750508751865160208a01516040519394506342d91bc360e01b936141d89392919082906024016153c1565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b0383818316178352505050508160008151811061421e5761421e6155cb565b602090810291909101015284516040516001600160a01b039091166024820152306044820152637fe6bc3d60e01b90606401604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505081600181518110614296576142966155cb565b60200260200101819052506000836001600160a01b031688606001516001600160a01b0316146142c75760026142ca565b60015b905060006040518060c001604052808a6000015181526020018360028111156142f5576142f5615201565b8152602001876001600160a01b03168152602001866001600160a01b031681526020018581526020018a60c001518152509050637d60c2fe60e01b3060008360405160200161434491906154a2565b60408051601f19818403018152908290526143639392916024016155e1565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050836002815181106143a9576143a96155cb565b6020908102919091018101919091528701516040808b01518b5191516001600160a01b03909316602484015260448301526064820152638cd2e0c760e01b92506084019050604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505081600381518110614434576144346155cb565b6020908102919091010152604051631592ca1b60e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ac9650d89061448b908490600401615617565b6000604051808303816000875af11580156144aa573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526144d291908101906156be565b5060608701516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801561451d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614541919061538b565b955061455887608001518710156323313032612ff6565b61456b8760600151878960a00151613d9f565b86606001516001600160a01b031687600001517f872948bae2a774964cc9861d6fa3c1f1c5fcef12747050253523474e24d92c53888a60200151866040516145c6939291909283526020830191909152604082015260600190565b60405180910390a35050505050919050565b8015806146525750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa15801561462c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614650919061538b565b155b6146bd5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401612adf565b6040516001600160a01b0383166024820152604481018290526130ba90849063095ea7b360e01b90606401613858565b60008080600019858709858702925082811083820303915050806000036147275783828161471d5761471d615593565b04925050506147d6565b80841161476e5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b6044820152606401612adf565b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b8151815160405163402414b360e01b815260048101929092526001600160a01b0390811660248301526000918291829182917f0000000000000000000000000000000000000000000000000000000000000000169063402414b390604401602060405180830381865afa158015614858573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061487c919061538b565b90508560600151915080821115614891578091505b855160208601516040516310e28e7160e01b81526000926001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016926310e28e71926148f99291906004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015614916573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061493a919061538b565b905081614947848361557c565b61495191906155a9565b60208701516040516331a86fe160e01b8152600481018390529195506001600160a01b0316906331a86fe1906024016020604051808303816000875af115801561499f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149c3919061538b565b945050509250925092565b600082156149fc57816149e260018561551e565b6149ec91906155a9565b6149f79060016157b6565b6149ff565b60005b90505b92915050565b6000614a5d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614add9092919063ffffffff16565b9050805160001480614a7e575080806020019051810190614a7e91906157c9565b6130ba5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401612adf565b6060610b99848460008585600080866001600160a01b03168587604051614b0491906157e6565b60006040518083038185875af1925050503d8060008114614b41576040519150601f19603f3d011682016040523d82523d6000602084013e614b46565b606091505b5091509150614b5787838387614b62565b979650505050505050565b60608315614bd1578251600003614bca576001600160a01b0385163b614bca5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401612adf565b5081610b99565b610b998383815115614be65781518083602001fd5b8060405162461bcd60e51b8152600401612adf91906150eb565b6040518061010001604052806000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001811115614c4b57614c4b615201565b815260200160008152600060209091015290565b60008060408385031215614c7257600080fd5b50508035926020909101359150565b6001600160a01b0381168114614c9657600080fd5b50565b8035614ca481614c81565b919050565b600060208284031215614cbb57600080fd5b81356147d681614c81565b60008060408385031215614cd957600080fd5b8235614ce481614c81565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715614d2b57614d2b614cf2565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614d5a57614d5a614cf2565b604052919050565b600067ffffffffffffffff821115614d7c57614d7c614cf2565b50601f01601f191660200190565b600082601f830112614d9b57600080fd5b8135614dae614da982614d62565b614d31565b818152846020838601011115614dc357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215614df657600080fd5b8435614e0181614c81565b93506020850135614e1181614c81565b925060408501359150606085013567ffffffffffffffff811115614e3457600080fd5b614e4087828801614d8a565b91505092959194509250565b600060208284031215614e5e57600080fd5b5035919050565b600080600080600060a08688031215614e7d57600080fd5b85359450602086013593506040860135614e9681614c81565b94979396509394606081013594506080013592915050565b60008060008060008060c08789031215614ec757600080fd5b8635955060208701359450604087013593506060870135614ee781614c81565b9598949750929560808101359460a0909101359350915050565b60008083601f840112614f1357600080fd5b50813567ffffffffffffffff811115614f2b57600080fd5b602083019150836020828501011115614f4357600080fd5b9250929050565b600080600080600080600060c0888a031215614f6557600080fd5b873596506020880135614f7781614c81565b95506040880135945060608801359350608088013567ffffffffffffffff811115614fa157600080fd5b614fad8a828b01614f01565b989b979a5095989497959660a090950135949350505050565b60008060408385031215614fd957600080fd5b8235614fe481614c81565b91506020830135614ff481614c81565b809150509250929050565b8015158114614c9657600080fd5b60008060006060848603121561502257600080fd5b8335925060208401359150604084013561503b81614fff565b809150509250925092565b60008060006040848603121561505b57600080fd5b833561506681614c81565b9250602084013567ffffffffffffffff81111561508257600080fd5b61508e86828701614f01565b9497909650939450505050565b60005b838110156150b657818101518382015260200161509e565b50506000910152565b600081518084526150d781602086016020860161509b565b601f01601f19169290920160200192915050565b6020815260006149ff60208301846150bf565b60008060006060848603121561511357600080fd5b833561511e81614c81565b9250602084013561512e81614c81565b9150604084013561503b81614c81565b6000806000806000806000806000806101208b8d03121561515e57600080fd5b8a3561ffff8116811461517057600080fd5b995060208b013561518081614c81565b985061518e60408c01614c99565b975060608b013596506151a360808c01614c99565b955060a08b013594506151b860c08c01614c99565b935060e08b013567ffffffffffffffff8111156151d457600080fd5b6151e08d828e01614f01565b915080945050809250506101008b013590509295989b9194979a5092959850565b634e487b7160e01b600052602160045260246000fd5b6002811061522757615227615201565b9052565b60038110614c9657614c96615201565b60006101008201905082518252602083015160208301526040830151604083015260608301516060830152608083015160018060a01b03808216608085015260a0850151915061528e60a0850183615217565b60c0850151915061529e8261522b565b8160c08501528060e08601511660e0850152505092915050565b6020808252825182820181905260009190848201906040850190845b818110156152f0578351835292840192918401916001016152d4565b50909695505050505050565b60008060008060008060008060e0898b03121561531857600080fd5b883597506020890135965060408901359550606089013561533881614c81565b94506080890135935060a089013561534f81614fff565b925060c089013567ffffffffffffffff81111561536b57600080fd5b6153778b828c01614f01565b999c989b5096995094979396929594505050565b60006020828403121561539d57600080fd5b5051919050565b6000602082840312156153b657600080fd5b81516147d681614c81565b9384526001600160a01b039283166020850152604084019190915216606082015260800190565b6000602082840312156153fa57600080fd5b813567ffffffffffffffff8082111561541257600080fd5b9083019060c0828603121561542657600080fd5b61542e614d08565b8235815260208301356003811061544457600080fd5b602082015261545560408401614c99565b604082015261546660608401614c99565b60608201526080830135608082015260a08301358281111561548757600080fd5b61549387828601614d8a565b60a08301525095945050505050565b6020815281516020820152600060208301516154bd8161522b565b80604084015250604083015160018060a01b0380821660608501528060608601511660808501525050608083015160a083015260a083015160c080840152610b9960e08401826150bf565b634e487b7160e01b600052601160045260246000fd5b81810381811115614a0257614a02615508565b60006001820161554357615543615508565b5060010190565b6001600160a01b038616815260208101859052604081018490526060810183905260a08101610bb26080830184615217565b8082028115828204841417614a0257614a02615508565b634e487b7160e01b600052601260045260246000fd5b6000826155c657634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b038416815260ff8316602082015260606040820181905260009061560e908301846150bf565b95945050505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561566c57603f1988860301845261565a8583516150bf565b9450928501929085019060010161563e565b5092979650505050505050565b600082601f83011261568a57600080fd5b8151615698614da982614d62565b8181528460208386010111156156ad57600080fd5b610b9982602083016020870161509b565b600060208083850312156156d157600080fd5b825167ffffffffffffffff808211156156e957600080fd5b818501915085601f8301126156fd57600080fd5b81518181111561570f5761570f614cf2565b8060051b61571e858201614d31565b918252838101850191858101908984111561573857600080fd5b86860192505b83831015615774578251858111156157565760008081fd5b6157648b89838a0101615679565b835250918601919086019061573e565b9998505050505050505050565b60006020828403121561579357600080fd5b815167ffffffffffffffff8111156157aa57600080fd5b610b9984828501615679565b80820180821115614a0257614a02615508565b6000602082840312156157db57600080fd5b81516147d681614fff565b600082516157f881846020870161509b565b919091019291505056fea264697066735822122043cf9fdf571aaa2c1481beef702902646f539557ed148596f3f33f04e7557beb64736f6c63430008130033000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc50000000000000000000000000e7401707cd08c03cdb53daef3295ddfb68bba9200000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb8000000000000000000000000ce3292ca5abbdfa1db02142a67cffc708530675a
Deployed Bytecode
0x6080604052600436106101c25760003560e01c80638192ac36116100f7578063b381cf4011610095578063d4e1d6df11610064578063d4e1d6df14610682578063d73cd47f146106af578063edd49038146106cf578063f9b80da1146106ef57600080fd5b8063b381cf40146105e1578063b6ed063214610615578063c4d66de814610635578063d09ef2411461065557600080fd5b80639559f3e4116100d15780639559f3e4146105605780639826439f14610580578063a517db8f146105ae578063a8f35adf146105ce57600080fd5b80638192ac36146104235780638a839fde14610443578063902a338b1461046357600080fd5b80633b253cc81161016457806367b830ad1161013e57806367b830ad1461037a5780636864eb161461039c5780636b6c0774146103af57806378476fe9146103e357600080fd5b80633b253cc81461032457806342086a5d146103445780635662ecc71461036457600080fd5b80630fc6a11c116101a05780630fc6a11c14610266578063127e12eb14610286578063150b7a02146102be578063376822d6146102f757600080fd5b8063015cb0a5146101c75780630278b670146101ed57806309be263814610239575b600080fd5b6101da6101d5366004614c5f565b610723565b6040519081526020015b60405180910390f35b3480156101f957600080fd5b506102217f0000000000000000000000000e7401707cd08c03cdb53daef3295ddfb68bba9281565b6040516001600160a01b0390911681526020016101e4565b34801561024557600080fd5b506101da610254366004614ca9565b60336020526000908152604090205481565b34801561027257600080fd5b50603554610221906001600160a01b031681565b34801561029257600080fd5b506101da6102a1366004614cc6565b603460209081526000928352604080842090915290825290205481565b3480156102ca57600080fd5b506102de6102d9366004614de0565b610b90565b6040516001600160e01b031990911681526020016101e4565b34801561030357600080fd5b506101da610312366004614e4c565b60009081526039602052604090205490565b34801561033057600080fd5b506101da61033f366004614e65565b610ba1565b34801561035057600080fd5b506101da61035f366004614eae565b610bbc565b34801561037057600080fd5b506101da603a5481565b34801561038657600080fd5b5061039a610395366004614e4c565b610cbe565b005b6101da6103aa366004614f4a565b6111ed565b3480156103bb57600080fd5b506102217f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc581565b3480156103ef57600080fd5b506104036103fe366004614fc6565b6114ae565b604080516001600160a01b039384168152929091166020830152016101e4565b34801561042f57600080fd5b5061039a61043e36600461500d565b611542565b610456610451366004615046565b6118fc565b6040516101e491906150eb565b34801561046f57600080fd5b5061050f61047e366004614e4c565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915250600090815260386020908152604091829020825160a08101845281546001600160a01b03908116825260018301548116938201939093526002820154831693810193909352600301549081166060830152600160a01b900460ff161515608082015290565b6040516101e4919081516001600160a01b0390811682526020808401518216908301526040808401518216908301526060808401519091169082015260809182015115159181019190915260a00190565b34801561056c57600080fd5b5061039a61057b3660046150fe565b611d79565b61059361058e36600461513e565b611f55565b604080519384526020840192909252908201526060016101e4565b3480156105ba57600080fd5b506101da6105c9366004614e65565b612581565b61039a6105dc366004614c5f565b612592565b3480156105ed57600080fd5b506102217f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb881565b34801561062157600080fd5b5061039a610630366004614c5f565b612994565b34801561064157600080fd5b5061039a610650366004614ca9565b612a46565b34801561066157600080fd5b50610675610670366004614e4c565b612ba6565b6040516101e4919061523b565b34801561068e57600080fd5b506106a261069d366004614e4c565b612c8d565b6040516101e491906152b8565b3480156106bb57600080fd5b5061039a6106ca366004614ca9565b612cef565b3480156106db57600080fd5b506101da6106ea3660046152fc565b612de3565b3480156106fb57600080fd5b506102217f000000000000000000000000ce3292ca5abbdfa1db02142a67cffc708530675a81565b600034156107a0577f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561078657600080fd5b505af115801561079a573d6000803e3d6000fd5b50505050505b3360009081526034602090815260408083208684529091529020546107cb8115156323333031612ff6565b600081815260386020526040808220600181015491516310e28e7160e01b8152600481018590526001600160a01b0392831660248201819052919391927f0000000000000000000000000e7401707cd08c03cdb53daef3295ddfb68bba9216906310e28e7190604401602060405180830381865afa158015610851573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610875919061538b565b905080861115610883578095505b6000826001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e791906153a4565b6040516331a86fe160e01b8152600481018990529091506000906001600160a01b038516906331a86fe1906024016020604051808303816000875af1158015610934573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610958919061538b565b9050610964828261303b565b61096e82826130bf565b604051638cd2e0c760e01b81526001600160a01b038581166004830152602482018a9052604482018890527f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc51690638cd2e0c7906064016020604051808303816000875af11580156109e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a08919061538b565b6040516370a0823160e01b8152306004820152909750600096506001600160a01b037f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb81695506370a0823194506024019250610a62915050565b602060405180830381865afa158015610a7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa3919061538b565b90508015610b2657604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015610b0d57600080fd5b505af1158015610b21573d6000803e3d6000fd5b505050505b478015610b8857604051600090339083908381818185875af1925050503d8060008114610b6f576040519150601f19603f3d011682016040523d82523d6000602084013e610b74565b606091505b50509050610b86816323313033612ff6565b505b505092915050565b630a85bd0160e11b5b949350505050565b6000610bb28686868686600061318e565b9695505050505050565b600085815260376020908152604080832081516101008101835281548152600180830154948201949094526002820154928101929092526003810154606083015260048101546001600160a01b0381166080840152849360a0840191600160a01b900460ff1690811115610c3257610c32615201565b6001811115610c4357610c43615201565b81526020016004820160159054906101000a900460ff166002811115610c6b57610c6b615201565b6002811115610c7c57610c7c615201565b8152600591909101546001600160a01b03166020909101529050610ca08888612994565b610cb288878787878660a0015161318e565b98975050505050505050565b600081815260376020908152604080832081516101008101835281548152600180830154948201949094526002820154928101929092526003810154606083015260048101546001600160a01b03811660808401529192909160a0840191600160a01b90910460ff1690811115610d3757610d37615201565b6001811115610d4857610d48615201565b81526020016004820160159054906101000a900460ff166002811115610d7057610d70615201565b6002811115610d8157610d81615201565b8152600591909101546001600160a01b03166020909101529050610dc160018260c001516002811115610db657610db6615201565b146323323033612ff6565b80516000908152603860209081526040808320815160a08101835281546001600160a01b03908116808352600184015482168387015260028401548216838601526003909301549081166060830152600160a01b900460ff16151560808201528251632495a59960e01b815292519094939192632495a5999260048083019391928290030181865afa158015610e5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7f91906153a4565b9050600082602001516001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ec5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee991906153a4565b8451845160405163402414b360e01b81529293506001600160a01b037f0000000000000000000000000e7401707cd08c03cdb53daef3295ddfb68bba92169263402414b392610f4e9290916004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015610f6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8f919061538b565b600003610fe357600085815260376020526040808220600401805460ff60a81b191690558551905187927fbb139d33583839e19389be0c788bb4983ba63129333b3ffe835a4c4af0e5dcb891a35050505050565b610fed84846134c0565b6000806000610ffd87878761369d565b60008b8152603760205260409020600401805460ff60a81b1916600160a91b1790559194509250905061103b6001600160a01b038516333084613824565b61104584826130bf565b60208601518751604051638cd2e0c760e01b81526001600160a01b0392831660048201526024810185905260448101919091527f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc590911690638cd2e0c7906064016020604051808303816000875af11580156110c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e9919061538b565b508651865160608901516040516342d91bc360e01b81526001600160a01b037f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc516936342d91bc39361114493919290919033906004016153c1565b600060405180830381600087803b15801561115e57600080fd5b505af1158015611172573d6000803e3d6000fd5b50505060e0880151608089015161119692506001600160a01b031690339086613824565b86516080880151604080516001600160a01b039092168252602082018690528a92917f78c6ecc039f51fb5f61970280bf0c91681f694af59c658ee264c5d343bdd6daa910160405180910390a35050505050505050565b6000341561126a577f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561125057600080fd5b505af1158015611264573d6000803e3d6000fd5b50505050505b3360009081526034602090815260408083208b84529091529020546112958115156323333031612ff6565b6000818152603860209081526040918290208251610100810184528481526001600160a01b03808d16828501528185018c9052600183015481166060830152608082018b905282541660a08201528351601f8901849004840281018401909452878452909261132c9260c0830191908a908a908190840183828082843760009201919091525050509082525060200186905261388f565b6040516370a0823160e01b8152306004820152909350600092506001600160a01b037f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb81691506370a0823190602401602060405180830381865afa158015611398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bc919061538b565b9050801561143f57604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561142657600080fd5b505af115801561143a573d6000803e3d6000fd5b505050505b4780156114a157604051600090339083908381818185875af1925050503d8060008114611488576040519150601f19603f3d011682016040523d82523d6000602084013e61148d565b606091505b5050905061149f816323313033612ff6565b505b5050979650505050505050565b600080600080846001600160a01b0316866001600160a01b0316106114d45784866114d7565b85855b6001600160a01b038083166000908152603660209081526040808320848616845290915290205416945090925090506115168315156323313030612ff6565b816001600160a01b0316836001600160a01b0316146115355781611537565b805b935050509250929050565b33600090815260346020908152604080832086845290915290205461156d8115156323333031612ff6565b600081815260386020908152604080832080548251632495a59960e01b815292519194936001600160a01b0390911692632495a59992600480830193928290030181865afa1580156115c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e791906153a4565b82546040516342d91bc360e01b81529192506001600160a01b037f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc58116926342d91bc3926116409288929116908a9082906004016153c1565b600060405180830381600087803b15801561165a57600080fd5b505af115801561166e573d6000803e3d6000fd5b50508354604051637fe6bc3d60e01b81526001600160a01b0391821660048201523060248201527f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc59091169250637fe6bc3d91506044016020604051808303816000875af11580156116e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611708919061538b565b506040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611750573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611774919061538b565b9050611781828287613d9f565b50506040516370a0823160e01b8152306004820152600092507f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031691506370a0823190602401602060405180830381865afa1580156117ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611810919061538b565b9050801561189357604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561187a57600080fd5b505af115801561188e573d6000803e3d6000fd5b505050505b4780156118f557604051600090339083908381818185875af1925050503d80600081146118dc576040519150601f19603f3d011682016040523d82523d6000602084013e6118e1565b606091505b505090506118f3816323313033612ff6565b505b5050505050565b6060611937336001600160a01b037f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc516146323313031612ff6565b6119506001600160a01b03851630146323333037612ff6565b600061195e838501856153e8565b80516000908152603860209081526040808320815160a08101835281546001600160a01b039081168252600183015481169482019490945260028201548416818401526003909101548084166060830152600160a01b900460ff16151560808201528185015191516370a0823160e01b8152306004820152949550939116906370a0823190602401602060405180830381865afa158015611a03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a27919061538b565b6035546040850151919250611a49916001600160a01b03908116911683613df3565b60608301516040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611a94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab8919061538b565b60355460405163c2f8bbf360e01b81529192506001600160a01b03169063c2f8bbf390611ae99087906004016154a2565b600060405180830381600087803b158015611b0357600080fd5b505af1158015611b17573d6000803e3d6000fd5b5050505060608401516040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611b66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b8a919061538b565b90506000611b98838361551e565b9050600086602001516002811115611bb257611bb2615201565b03611c3c5784516060870151611bd4916001600160a01b039091169084613df3565b85606001516001600160a01b031686604001516001600160a01b031687600001517f53213ad1644c4b9abd2a1229db22ef606e1aad9d76882f6c081b4bdbdf3dad718785604051611c2f929190918252602082015260400190565b60405180910390a4611d4f565b83600287602001516002811115611c5557611c55615201565b03611cea57611c6f87608001518310156323313032612ff6565b60408088015190516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611cb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cdd919061538b565b611ce7908261551e565b90505b86606001516001600160a01b031687604001516001600160a01b031688600001517f5928107fb4d041486e4299ebc0b9cb4733396fecbf531e53f9ae6bf3fa58ac418486604051611d45929190918252602082015260400190565b60405180910390a4505b60408051602081018390520160405160208183030381529060405296505050505050509392505050565b6040516312d9a6ad60e01b81527f1e46cebd6689d8c64011118478db0c61a89aa2646c860df401de476fbf37898360048201523360248201527f000000000000000000000000ce3292ca5abbdfa1db02142a67cffc708530675a6001600160a01b0316906312d9a6ad90604401600060405180830381600087803b158015611e0057600080fd5b505af1158015611e14573d6000803e3d6000fd5b50611e46925050506001600160a01b03841615801590611e3c57506001600160a01b03831615155b6323313030612ff6565b611e84836001600160a01b0316826001600160a01b03161480611e7a5750826001600160a01b0316826001600160a01b0316145b6323323033612ff6565b611ea7826001600160a01b0316846001600160a01b031614156323323036612ff6565b600080836001600160a01b0316856001600160a01b031610611eca578385611ecd565b84845b6001600160a01b0382811660008181526036602090815260408083208686168085529083529281902080546001600160a01b031916958b16958617905580519384529083019190915281019190915291935091507f3de6d5493137a9234846bdb84bffebd5bf0b008b6a838c6570a0fa48292c20819060600160405180910390a15050505050565b600080803415611fd4577f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015611fba57600080fd5b505af1158015611fce573d6000803e3d6000fd5b50505050505b604051630bed2fd960e21b815261ffff8e1660048201526001600160a01b038d811660248301527f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc51690632fb4bf64906044016020604051808303816000875af1158015612046573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206a919061538b565b91506000896001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d091906153a4565b905060008061219c8a6001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015612116573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213a91906153a4565b8d6001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015612178573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103fe91906153a4565b915091506000836001600160a01b0316836001600160a01b0316141590506040518060a001604052808c6001600160a01b031681526020018e6001600160a01b03168152602001846001600160a01b03168152602001836001600160a01b031681526020018215158152506038600088815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060608201518160030160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060808201518160030160146101000a81548160ff02191690831515021790555090505050505060336000336001600160a01b03166001600160a01b031681526020019081526020016000206000815461232690615531565b91905081905593508260346000336001600160a01b03166001600160a01b031681526020019081526020016000206000868152602001908152602001600020819055506123fb6040518061010001604052808581526020018e6001600160a01b031681526020018d81526020018c6001600160a01b031681526020018b81526020018a6001600160a01b0316815260200189898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060200187905261388f565b6040516370a0823160e01b8152306004820152909250600091506001600160a01b037f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb816906370a0823190602401602060405180830381865afa158015612466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061248a919061538b565b9050801561250d57604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156124f457600080fd5b505af1158015612508573d6000803e3d6000fd5b505050505b47801561256f57604051600090339083908381818185875af1925050503d8060008114612556576040519150601f19603f3d011682016040523d82523d6000602084013e61255b565b606091505b5050905061256d816323313033612ff6565b505b50509a509a509a975050505050505050565b6000610bb28686868686600161318e565b341561260d577f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156125f357600080fd5b505af1158015612607573d6000803e3d6000fd5b50505050505b3360009081526034602090815260408083208584529091529020546126388115156323333031612ff6565b600081815260386020908152604080832080548251632495a59960e01b815292519194936001600160a01b0390911692632495a59992600480830193928290030181865afa15801561268e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b291906153a4565b90506126be818561303b565b81546126d7906001600160a01b03838116911686613df3565b8154604051634a8db60160e11b81526001600160a01b0391821660048201527f0000000000000000000000000e7401707cd08c03cdb53daef3295ddfb68bba92821660248201527f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc59091169063951b6c02906044016020604051808303816000875af115801561276b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061278f919061538b565b50815460405163abf4dd3960e01b8152600481018590526001600160a01b0391821660248201527f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc59091169063abf4dd3990604401600060405180830381600087803b1580156127fe57600080fd5b505af1158015612812573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600095507f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031694506370a082319350602401915061286a9050565b602060405180830381865afa158015612887573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ab919061538b565b9050801561292e57604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561291557600080fd5b505af1158015612929573d6000803e3d6000fd5b505050505b47801561298e57604051600090339083908381818185875af1925050503d8060008114612977576040519150601f19603f3d011682016040523d82523d6000602084013e61297c565b606091505b505090506118f5816323313033612ff6565b50505050565b3360009081526034602090815260408083208584529091529020546129bf8115156323333031612ff6565b600082815260376020526040902080546129df9083146323323033612ff6565b612a0460016004830154600160a81b900460ff166002811115610db657610db6615201565b60048101805460ff60a81b19169055604051839083907fbb139d33583839e19389be0c788bb4983ba63129333b3ffe835a4c4af0e5dcb890600090a350505050565b600054610100900460ff1615808015612a665750600054600160ff909116105b80612a805750303b158015612a80575060005460ff166001145b612ae85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015612b0b576000805461ff0019166101001790555b603580546001600160a01b0319166001600160a01b0384169081179091556040519081527f9fd27a9e967ce43ed9a2500f7565d0f89346e02dda9e8584f14d9b3d5ddda8629060200160405180910390a18015612ba2576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b612bae614c00565b60008281526037602090815260409182902082516101008101845281548152600180830154938201939093526002820154938101939093526003810154606084015260048101546001600160a01b0381166080850152909160a0840191600160a01b900460ff1690811115612c2557612c25615201565b6001811115612c3657612c36615201565b81526020016004820160159054906101000a900460ff166002811115612c5e57612c5e615201565b6002811115612c6f57612c6f615201565b8152600591909101546001600160a01b031660209091015292915050565b600081815260396020908152604091829020805483518184028101840190945280845260609392830182828015612ce357602002820191906000526020600020905b815481526020019060010190808311612ccf575b50505050509050919050565b6040516312d9a6ad60e01b81527f1e46cebd6689d8c64011118478db0c61a89aa2646c860df401de476fbf37898360048201523360248201527f000000000000000000000000ce3292ca5abbdfa1db02142a67cffc708530675a6001600160a01b0316906312d9a6ad90604401600060405180830381600087803b158015612d7657600080fd5b505af1158015612d8a573d6000803e3d6000fd5b5050603580546001600160a01b0319166001600160a01b0385169081179091556040519081527f9fd27a9e967ce43ed9a2500f7565d0f89346e02dda9e8584f14d9b3d5ddda8629250602001905060405180910390a150565b3360009081526034602090815260408083208b8452825280832054815160e0810183528181528084018c90528083018b90526001600160a01b038a1660608201526080810189905287151560a08201528251601f87018590048502810185019093528583529092612e749260c083019188908890819084018382808284376000920191909152505050915250613e23565b6040516370a0823160e01b8152306004820152909250600091506001600160a01b037f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb816906370a0823190602401602060405180830381865afa158015612edf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f03919061538b565b90508015612f8657604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015612f6d57600080fd5b505af1158015612f81573d6000803e3d6000fd5b505050505b478015612fe857604051600090339083908381818185875af1925050503d8060008114612fcf576040519150601f19603f3d011682016040523d82523d6000602084013e612fd4565b606091505b50509050612fe6816323313033612ff6565b505b505098975050505050505050565b81612ba2576040516001600160e01b031960e083901b16602082015260240160408051601f198184030181529082905262461bcd60e51b8252612adf916004016150eb565b80341561309f576130847f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b0316846001600160a01b0316146323313035612ff6565b34821161309257600061309c565b61309c348261551e565b90505b80156130ba576130ba6001600160a01b038416333084613824565b505050565b604051636eb1769f60e11b81523060048201526001600160a01b037f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc58116602483015282919084169063dd62ed3e90604401602060405180830381865afa15801561312e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613152919061538b565b1015612ba257612ba26001600160a01b0383167f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc56000196145d8565b6000603a6000815461319f90615531565b918290555090506131b68315156323313030612ff6565b3360009081526034602090815260408083208a84529091529020546131e18115156323333031612ff6565b600081815260386020908152604091829020825160a08101845281546001600160a01b0390811682526001830154811693820193909352600282015483169381018490526003909101548083166060830152600160a01b900460ff1615156080820152916132759189161480611e7a575081606001516001600160a01b0316886001600160a01b0316146323323033612ff6565b805160405163402414b360e01b8152600481018490526001600160a01b0391821660248201526000917f0000000000000000000000000e7401707cd08c03cdb53daef3295ddfb68bba92169063402414b390604401602060405180830381865afa1580156132e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061330b919061538b565b905061331e818711156323323032612ff6565b6040518061010001604052808481526020018a8152602001888152602001878152602001896001600160a01b0316815260200186600181111561336357613363615201565b815260016020808301829052336040938401526000888152603782528390208451815590840151818301559183015160028301556060830151600383015560808301516004830180546001600160a01b039092166001600160a01b031983168117825560a08601519391926001600160a81b0319161790600160a01b9084908111156133f1576133f1615201565b021790555060c082015160048201805460ff60a81b1916600160a81b83600281111561341f5761341f615201565b021790555060e09190910151600590910180546001600160a01b0319166001600160a01b0390921691909117905560008381526039602090815260408083208054600181018255908452919092200185905551849084907f86ac53d8eeffaf93525a46596fefefbc428a4ad0a3b9696a33674d4ba034f832906134ab908c908e908d908d908d9061554a565b60405180910390a35050509695505050505050565b60007f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc56001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015613520573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061354491906153a4565b60608301516040516339fa57cb60e11b81526001600160a01b039182166004820152919250600091613646916ec097ce7bc90715b34b9f100000000091908516906373f4af9690602401602060405180830381865afa1580156135ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135cf919061538b565b60408681015190516339fa57cb60e11b81526001600160a01b039182166004820152908616906373f4af9690602401602060405180830381865afa15801561361b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061363f919061538b565b91906146ed565b6080840151909150151560018560a00151600181111561366857613668615201565b14146136885761368384602001518211156323323033612ff6565b61298e565b61298e84602001518210156323323033612ff6565b60008060006136ac86866147dd565b60608901819052875160405163263a31fb60e21b815260048101929092529294509092506000916001600160a01b0316906398e8c7ec906024016020604051808303816000875af1158015613705573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613729919061538b565b905086608001516001600160a01b0316856001600160a01b0316036137ab5785608001511561378b5760408701516137706ec097ce7bc90715b34b9f10000000008461557c565b61377a91906155a9565b613784908261551e565b935061381a565b6ec097ce7bc90715b34b9f1000000000876040015183613770919061557c565b8560800151156137e957816137df6ec097ce7bc90715b34b9f10000000008960400151846137d9919061557c565b906149ce565b613784919061551e565b8161380d88604001516ec097ce7bc90715b34b9f1000000000846137d9919061557c565b613817919061551e565b93505b5093509350939050565b6040516001600160a01b038085166024830152831660448201526064810182905261298e9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614a08565b60006138a38260200151836040015161303b565b60408051600480825260a08201909252600091816020015b60608152602001906001900390816138bb575050606084015160808501518551604080516001600160a01b03909416602485015260448401929092526064830152306084808401919091528151808403909101815260a490920190526020810180516001600160e01b03166308ba54eb60e21b1790528151919250908290600090613948576139486155cb565b602002602001018190525060008360a001516001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015613997573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139bb91906153a4565b9050600084606001516001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a2591906153a4565b9050613a6c826001600160a01b031686602001516001600160a01b03161480611e7a5750816001600160a01b031686602001516001600160a01b0316146323323033612ff6565b6040805160c0808201835287518252600060208084018290526001600160a01b03808716858701528716606085015260e08a015160808501529189015160a084015292519192633eb0617f60e11b923092613ac9918691016154a2565b60408051601f1981840301815290829052613ae89392916024016155e1565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505084600181518110613b2e57613b2e6155cb565b60209081029190910101525060a08501516040516001600160a01b0391821660248201527f0000000000000000000000000e7401707cd08c03cdb53daef3295ddfb68bba929091166044820152634a8db60160e11b90606401604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505083600281518110613bcd57613bcd6155cb565b6020908102919091010152845160a086015160405160248101929092526001600160a01b0316604482015263abf4dd3960e01b90606401604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505083600381518110613c4a57613c4a6155cb565b602002602001018190525060007f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc56001600160a01b031663ac9650d8856040518263ffffffff1660e01b8152600401613ca39190615617565b6000604051808303816000875af1158015613cc2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613cea91908101906156be565b905080600181518110613cff57613cff6155cb565b6020026020010151806020019051810190613d1a9190615781565b806020019051810190613d2d919061538b565b9450816001600160a01b031686602001516001600160a01b031687600001517f48990dad1f3df6d1f813e38b5b6afba377ae5212af0e6f493947afd00dcb7c2e89604001518a60800151604051613d8e929190918252602082015260400190565b60405180910390a450505050919050565b7f00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb86001600160a01b0316836001600160a01b0316141580613dde575080155b156130ba576130ba6001600160a01b03841633845b6040516001600160a01b0383166024820152604481018290526130ba90849063a9059cbb60e01b90606401613858565b80516000908152603860209081526040808320815160a08101835281546001600160a01b03908116808352600184015482169583019590955260028301548116828501526003909201548083166060830152600160a01b900460ff16151560808201528551925163402414b360e01b815260048101939093526024830193909352613f28917f0000000000000000000000000e7401707cd08c03cdb53daef3295ddfb68bba929091169063402414b390604401602060405180830381865afa158015613ef3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f17919061538b565b846020015111156323323032612ff6565b825160208201516040516310e28e7160e01b8152613fe3926001600160a01b037f0000000000000000000000000e7401707cd08c03cdb53daef3295ddfb68bba9216926310e28e7192613f919291906004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015613fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd2919061538b565b846040015111156323323032612ff6565b600081600001516001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015614027573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061404b91906153a4565b9050600082602001516001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015614091573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140b591906153a4565b90506140fc826001600160a01b031686606001516001600160a01b03161480611e7a5750816001600160a01b031686606001516001600160a01b0316146323323033612ff6565b600083602001516001600160a01b03166331a86fe187604001516040518263ffffffff1660e01b815260040161413491815260200190565b6020604051808303816000875af1158015614153573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614177919061538b565b905061418382826130bf565b60408051600480825260a08201909252600091816020015b606081526020019060019003908161419b5750508751865160208a01516040519394506342d91bc360e01b936141d89392919082906024016153c1565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b0383818316178352505050508160008151811061421e5761421e6155cb565b602090810291909101015284516040516001600160a01b039091166024820152306044820152637fe6bc3d60e01b90606401604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505081600181518110614296576142966155cb565b60200260200101819052506000836001600160a01b031688606001516001600160a01b0316146142c75760026142ca565b60015b905060006040518060c001604052808a6000015181526020018360028111156142f5576142f5615201565b8152602001876001600160a01b03168152602001866001600160a01b031681526020018581526020018a60c001518152509050637d60c2fe60e01b3060008360405160200161434491906154a2565b60408051601f19818403018152908290526143639392916024016155e1565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050836002815181106143a9576143a96155cb565b6020908102919091018101919091528701516040808b01518b5191516001600160a01b03909316602484015260448301526064820152638cd2e0c760e01b92506084019050604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505081600381518110614434576144346155cb565b6020908102919091010152604051631592ca1b60e31b81526001600160a01b037f000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc5169063ac9650d89061448b908490600401615617565b6000604051808303816000875af11580156144aa573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526144d291908101906156be565b5060608701516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801561451d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614541919061538b565b955061455887608001518710156323313032612ff6565b61456b8760600151878960a00151613d9f565b86606001516001600160a01b031687600001517f872948bae2a774964cc9861d6fa3c1f1c5fcef12747050253523474e24d92c53888a60200151866040516145c6939291909283526020830191909152604082015260600190565b60405180910390a35050505050919050565b8015806146525750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa15801561462c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614650919061538b565b155b6146bd5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401612adf565b6040516001600160a01b0383166024820152604481018290526130ba90849063095ea7b360e01b90606401613858565b60008080600019858709858702925082811083820303915050806000036147275783828161471d5761471d615593565b04925050506147d6565b80841161476e5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b6044820152606401612adf565b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b8151815160405163402414b360e01b815260048101929092526001600160a01b0390811660248301526000918291829182917f0000000000000000000000000e7401707cd08c03cdb53daef3295ddfb68bba92169063402414b390604401602060405180830381865afa158015614858573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061487c919061538b565b90508560600151915080821115614891578091505b855160208601516040516310e28e7160e01b81526000926001600160a01b037f0000000000000000000000000e7401707cd08c03cdb53daef3295ddfb68bba9216926310e28e71926148f99291906004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015614916573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061493a919061538b565b905081614947848361557c565b61495191906155a9565b60208701516040516331a86fe160e01b8152600481018390529195506001600160a01b0316906331a86fe1906024016020604051808303816000875af115801561499f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149c3919061538b565b945050509250925092565b600082156149fc57816149e260018561551e565b6149ec91906155a9565b6149f79060016157b6565b6149ff565b60005b90505b92915050565b6000614a5d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614add9092919063ffffffff16565b9050805160001480614a7e575080806020019051810190614a7e91906157c9565b6130ba5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401612adf565b6060610b99848460008585600080866001600160a01b03168587604051614b0491906157e6565b60006040518083038185875af1925050503d8060008114614b41576040519150601f19603f3d011682016040523d82523d6000602084013e614b46565b606091505b5091509150614b5787838387614b62565b979650505050505050565b60608315614bd1578251600003614bca576001600160a01b0385163b614bca5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401612adf565b5081610b99565b610b998383815115614be65781518083602001fd5b8060405162461bcd60e51b8152600401612adf91906150eb565b6040518061010001604052806000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001811115614c4b57614c4b615201565b815260200160008152600060209091015290565b60008060408385031215614c7257600080fd5b50508035926020909101359150565b6001600160a01b0381168114614c9657600080fd5b50565b8035614ca481614c81565b919050565b600060208284031215614cbb57600080fd5b81356147d681614c81565b60008060408385031215614cd957600080fd5b8235614ce481614c81565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715614d2b57614d2b614cf2565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614d5a57614d5a614cf2565b604052919050565b600067ffffffffffffffff821115614d7c57614d7c614cf2565b50601f01601f191660200190565b600082601f830112614d9b57600080fd5b8135614dae614da982614d62565b614d31565b818152846020838601011115614dc357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215614df657600080fd5b8435614e0181614c81565b93506020850135614e1181614c81565b925060408501359150606085013567ffffffffffffffff811115614e3457600080fd5b614e4087828801614d8a565b91505092959194509250565b600060208284031215614e5e57600080fd5b5035919050565b600080600080600060a08688031215614e7d57600080fd5b85359450602086013593506040860135614e9681614c81565b94979396509394606081013594506080013592915050565b60008060008060008060c08789031215614ec757600080fd5b8635955060208701359450604087013593506060870135614ee781614c81565b9598949750929560808101359460a0909101359350915050565b60008083601f840112614f1357600080fd5b50813567ffffffffffffffff811115614f2b57600080fd5b602083019150836020828501011115614f4357600080fd5b9250929050565b600080600080600080600060c0888a031215614f6557600080fd5b873596506020880135614f7781614c81565b95506040880135945060608801359350608088013567ffffffffffffffff811115614fa157600080fd5b614fad8a828b01614f01565b989b979a5095989497959660a090950135949350505050565b60008060408385031215614fd957600080fd5b8235614fe481614c81565b91506020830135614ff481614c81565b809150509250929050565b8015158114614c9657600080fd5b60008060006060848603121561502257600080fd5b8335925060208401359150604084013561503b81614fff565b809150509250925092565b60008060006040848603121561505b57600080fd5b833561506681614c81565b9250602084013567ffffffffffffffff81111561508257600080fd5b61508e86828701614f01565b9497909650939450505050565b60005b838110156150b657818101518382015260200161509e565b50506000910152565b600081518084526150d781602086016020860161509b565b601f01601f19169290920160200192915050565b6020815260006149ff60208301846150bf565b60008060006060848603121561511357600080fd5b833561511e81614c81565b9250602084013561512e81614c81565b9150604084013561503b81614c81565b6000806000806000806000806000806101208b8d03121561515e57600080fd5b8a3561ffff8116811461517057600080fd5b995060208b013561518081614c81565b985061518e60408c01614c99565b975060608b013596506151a360808c01614c99565b955060a08b013594506151b860c08c01614c99565b935060e08b013567ffffffffffffffff8111156151d457600080fd5b6151e08d828e01614f01565b915080945050809250506101008b013590509295989b9194979a5092959850565b634e487b7160e01b600052602160045260246000fd5b6002811061522757615227615201565b9052565b60038110614c9657614c96615201565b60006101008201905082518252602083015160208301526040830151604083015260608301516060830152608083015160018060a01b03808216608085015260a0850151915061528e60a0850183615217565b60c0850151915061529e8261522b565b8160c08501528060e08601511660e0850152505092915050565b6020808252825182820181905260009190848201906040850190845b818110156152f0578351835292840192918401916001016152d4565b50909695505050505050565b60008060008060008060008060e0898b03121561531857600080fd5b883597506020890135965060408901359550606089013561533881614c81565b94506080890135935060a089013561534f81614fff565b925060c089013567ffffffffffffffff81111561536b57600080fd5b6153778b828c01614f01565b999c989b5096995094979396929594505050565b60006020828403121561539d57600080fd5b5051919050565b6000602082840312156153b657600080fd5b81516147d681614c81565b9384526001600160a01b039283166020850152604084019190915216606082015260800190565b6000602082840312156153fa57600080fd5b813567ffffffffffffffff8082111561541257600080fd5b9083019060c0828603121561542657600080fd5b61542e614d08565b8235815260208301356003811061544457600080fd5b602082015261545560408401614c99565b604082015261546660608401614c99565b60608201526080830135608082015260a08301358281111561548757600080fd5b61549387828601614d8a565b60a08301525095945050505050565b6020815281516020820152600060208301516154bd8161522b565b80604084015250604083015160018060a01b0380821660608501528060608601511660808501525050608083015160a083015260a083015160c080840152610b9960e08401826150bf565b634e487b7160e01b600052601160045260246000fd5b81810381811115614a0257614a02615508565b60006001820161554357615543615508565b5060010190565b6001600160a01b038616815260208101859052604081018490526060810183905260a08101610bb26080830184615217565b8082028115828204841417614a0257614a02615508565b634e487b7160e01b600052601260045260246000fd5b6000826155c657634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b038416815260ff8316602082015260606040820181905260009061560e908301846150bf565b95945050505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561566c57603f1988860301845261565a8583516150bf565b9450928501929085019060010161563e565b5092979650505050505050565b600082601f83011261568a57600080fd5b8151615698614da982614d62565b8181528460208386010111156156ad57600080fd5b610b9982602083016020870161509b565b600060208083850312156156d157600080fd5b825167ffffffffffffffff808211156156e957600080fd5b818501915085601f8301126156fd57600080fd5b81518181111561570f5761570f614cf2565b8060051b61571e858201614d31565b918252838101850191858101908984111561573857600080fd5b86860192505b83831015615774578251858111156157565760008081fd5b6157648b89838a0101615679565b835250918601919086019061573e565b9998505050505050505050565b60006020828403121561579357600080fd5b815167ffffffffffffffff8111156157aa57600080fd5b610b9984828501615679565b80820180821115614a0257614a02615508565b6000602082840312156157db57600080fd5b81516147d681614fff565b600082516157f881846020870161509b565b919091019291505056fea264697066735822122043cf9fdf571aaa2c1481beef702902646f539557ed148596f3f33f04e7557beb64736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc50000000000000000000000000e7401707cd08c03cdb53daef3295ddfb68bba9200000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb8000000000000000000000000ce3292ca5abbdfa1db02142a67cffc708530675a
-----Decoded View---------------
Arg [0] : _core (address): 0x972BcB0284cca0152527c4f70f8F689852bCAFc5
Arg [1] : _posManager (address): 0x0e7401707CD08c03CDb53DAEF3295DDFb68BBa92
Arg [2] : _wNative (address): 0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8
Arg [3] : _acm (address): 0xCE3292cA5AbbdFA1Db02142A67CFFc708530675a
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000972bcb0284cca0152527c4f70f8f689852bcafc5
Arg [1] : 0000000000000000000000000e7401707cd08c03cdb53daef3295ddfb68bba92
Arg [2] : 00000000000000000000000078c1b0c915c4faa5fffa6cabf0219da63d7f4cb8
Arg [3] : 000000000000000000000000ce3292ca5abbdfa1db02142a67cffc708530675a
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MNT
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.