Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Vault
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 10 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {MathUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
import {
IERC20Upgradeable,
SafeERC20Upgradeable
} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {IVault} from "./interfaces/IVault.sol";
import {SwapLogic} from "./libraries/logic/SwapLogic.sol";
import {SupplyLogic} from "./libraries/logic/SupplyLogic.sol";
import {PositionLogic} from "./libraries/logic/PositionLogic.sol";
import {GenericLogic} from "./libraries/logic/GenericLogic.sol";
import {ConfigureLogic} from "./libraries/logic/ConfigureLogic.sol";
import {BorrowingFeeLogic} from "./libraries/logic/BorrowingFeeLogic.sol";
import {FundingFeeLogic} from "./libraries/logic/FundingFeeLogic.sol";
import {StorageSlot} from "./libraries/logic/StorageSlot.sol";
import {IVaultPriceFeed} from "./interfaces/IVaultPriceFeed.sol";
import {DataTypes} from "./libraries/types/DataTypes.sol";
import {Constants} from "./libraries/helpers/Constants.sol";
contract Vault is Ownable2StepUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable, IVault {
using MathUpgradeable for uint256;
using SafeERC20Upgradeable for IERC20Upgradeable;
event ClaimFundingFee(address indexed account, address token, uint256 amount);
event SettleFundingFee(address indexed account, uint256 amount);
function initialize() external initializer {
__Ownable2Step_init();
__Pausable_init();
__ReentrancyGuard_init();
}
function setPermissionParams(
bool _inManagerMode,
bool _inPrivateLiquidationMode,
bool _isSwapEnabled,
bool _isLeverageEnabled
) external onlyOwner {
ConfigureLogic.setPermissionParams(
_inManagerMode, _inPrivateLiquidationMode, _isSwapEnabled, _isLeverageEnabled
);
}
function getPermissionParams() external view returns (bool, bool, bool, bool) {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
return (ps.inManagerMode, ps.inPrivateLiquidationMode, ps.isSwapEnabled, ps.isLeverageEnabled);
}
function setManager(address _manager, bool _isManager) external onlyOwner {
ConfigureLogic.setManager(_manager, _isManager);
}
function isManager(address _manager) external view returns (bool) {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
return ps.isManager[_manager];
}
function setLiquidator(address _liquidator, bool _isActive) external onlyOwner {
ConfigureLogic.setLiquidator(_liquidator, _isActive);
}
function isLiquidator(address _liquidator) external view returns (bool) {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
return ps.isLiquidator[_liquidator];
}
function setTokenPause(address _token, bool _isPause) external {
DataTypes.AddressStorage memory addrs = getAddresses();
require(msg.sender == owner() || msg.sender == addrs.router, "Vault: invalid caller");
ConfigureLogic.setTokenPause(_token, _isPause);
}
function isTokenPaused(address _token) public view returns (bool) {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
return ps.isTokenPaused[_token];
}
function setMaxGasPrice(uint256 _maxGasPrice) external onlyOwner {
ConfigureLogic.setMaxGasPrice(_maxGasPrice);
}
function getMaxGasPrice() external view returns (uint256) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
return ps.maxGasPrice;
}
function setAddresses(DataTypes.AddressStorage memory params) external onlyOwner {
ConfigureLogic.setAddresses(params);
}
function getAddresses() public view override returns (DataTypes.AddressStorage memory) {
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
DataTypes.AddressStorage memory addrsT;
addrsT.weth = addrs.weth;
addrsT.router = addrs.router;
addrsT.ulpManager = addrs.ulpManager;
addrsT.priceFeed = addrs.priceFeed;
addrsT.usdg = addrs.usdg;
addrsT.collateralToken = addrs.collateralToken;
addrsT.feesReceiver = addrs.feesReceiver;
return addrsT;
}
function setReserveRatio(uint256 _ratio) external onlyOwner {
ConfigureLogic.setReserveRatio(_ratio);
}
function getReserveRatio() external view override returns (uint256) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
return ps.reserveRatio;
}
function setMaxLeverage(uint256 _maxLeverage) external onlyOwner {
ConfigureLogic.setMaxLeverage(_maxLeverage);
}
function getMaxLeverage() external view returns (uint256) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
return ps.maxLeverage;
}
function setBufferAmount(address _token, uint256 _amount) external onlyOwner {
ConfigureLogic.setBufferAmount(_token, _amount);
}
function getBufferAmount(address _token) external view returns (uint256) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
return ps.bufferAmounts[_token];
}
function setMaxGlobalSizes(address[] memory _tokens, uint256[] memory _longSizes, uint256[] memory _shortSizes)
external
onlyOwner
{
ConfigureLogic.setMaxGlobalSizes(_tokens, _longSizes, _shortSizes);
}
function getGlobalData(address _token) external view override returns (DataTypes.GlobalData memory) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
DataTypes.GlobalData memory globalData;
globalData.maxGlobalLongSize = ps.maxGlobalLongSizes[_token];
globalData.globalLongSize = ps.globalLongSizes[_token];
globalData.globalLongAveragePrice = ps.globalLongAveragePrices[_token];
globalData.maxGlobalShortSize = ps.maxGlobalShortSizes[_token];
globalData.globalShortSize = ps.globalShortSizes[_token];
globalData.globalShortAveragePrice = ps.globalShortAveragePrices[_token];
return globalData;
}
function setFees(DataTypes.SetFeesParams memory params) external onlyOwner {
ConfigureLogic.setFees(params);
}
function getFees() external view override returns (DataTypes.SetFeesParams memory) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
DataTypes.SetFeesParams memory fee;
fee.taxBasisPoints = fs.taxBasisPoints;
fee.stableTaxBasisPoints = fs.stableTaxBasisPoints;
fee.mintBurnFeeBasisPoints = fs.mintBurnFeeBasisPoints;
fee.swapFeeBasisPoints = fs.swapFeeBasisPoints;
fee.stableSwapFeeBasisPoints = fs.stableSwapFeeBasisPoints;
fee.marginFeeBasisPoints = fs.marginFeeBasisPoints;
fee.liquidationFeeUsd = fs.liquidationFeeUsd;
fee.hasDynamicFees = fs.hasDynamicFees;
fee.balanceReward = fs.balanceReward;
return fee;
}
function setBorrowingRate(
uint256 _borrowingInterval,
uint256 _borrowingRateFactor,
uint256 _stableBorrowingRateFactor
) external onlyOwner {
(uint256 borrowingInterval, uint256 borrowingRateFactor, uint256 stableBorrowingRateFactor) = getBorrowingRate();
if (borrowingInterval != 0 || borrowingRateFactor != 0 || stableBorrowingRateFactor != 0) {
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
updateCumulativeBorrowingRate(addrs.collateralToken, addrs.collateralToken);
}
ConfigureLogic.setBorrowingRate(_borrowingInterval, _borrowingRateFactor, _stableBorrowingRateFactor);
}
function getBorrowingRate() public view override returns (uint256, uint256, uint256) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
return (fs.borrowingInterval, fs.borrowingRateFactor, fs.stableBorrowingRateFactor);
}
function setTokenConfig(
address _token,
uint256 _tokenDecimals,
uint256 _tokenWeight,
uint256 _maxUsdgAmount,
bool _isStable,
bool _isShortable
) external onlyOwner {
ConfigureLogic.setTokenConfig(
DataTypes.SetTokenConfigParams({
token: _token,
tokenDecimals: _tokenDecimals,
tokenWeight: _tokenWeight,
maxUsdgAmount: _maxUsdgAmount,
isStable: _isStable,
isShortable: _isShortable
})
);
}
function getTokenConfig(address _token) external view returns (DataTypes.SetTokenConfigParams memory) {
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
DataTypes.SetTokenConfigParams memory tokenConfig;
tokenConfig.token = _token;
tokenConfig.tokenDecimals = ts.tokenDecimals[_token];
tokenConfig.tokenWeight = ts.tokenWeights[_token];
tokenConfig.maxUsdgAmount = ts.maxUsdgAmounts[_token];
tokenConfig.isStable = ts.stableTokens[_token];
tokenConfig.isShortable = ts.shortableTokens[_token];
return tokenConfig;
}
function getTokenDecimal(address _token) external view override returns (uint256) {
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
return 10 ** ts.tokenDecimals[_token];
}
function clearTokenConfig(address _token) external onlyOwner {
ConfigureLogic.clearTokenConfig(_token);
}
function withdrawFees(address _token) external override returns (uint256) {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
require(ps.isWithdrawFeesAdmin[msg.sender], "not withdraw fee admin");
return GenericLogic.withdrawFees(_token);
}
function setFeesAdmin(address _admin, bool _isAdmin) external onlyOwner {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
ps.isWithdrawFeesAdmin[_admin] = _isAdmin;
}
function isFeesAdmin(address _admin) external view returns (bool) {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
return ps.isWithdrawFeesAdmin[_admin];
}
function setRouter(address _router, bool _isRouter) external {
ConfigureLogic.setRouter(_router, _isRouter);
}
function isRouter(address _account, address _router) external view returns (bool) {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
return ps.approvedRouters[_account][_router];
}
function setUsdgAmount(address _token, uint256 _amount) external onlyOwner {
ConfigureLogic.setUsdgAmount(_token, _amount);
}
function getUsdgAmount(address _token) external view returns (uint256) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
return ps.usdgAmounts[_token];
}
function setFundingFactor(
address[] memory _tokens,
uint256[] memory _fundingFactors,
uint256[] memory _fundingExponentFactors
) external onlyOwner {
require(
_tokens.length == _fundingFactors.length && _tokens.length == _fundingExponentFactors.length,
"inconsistent length"
);
for (uint256 i = 0; i < _tokens.length; i++) {
if (_fundingFactors[i] != 0 || _fundingExponentFactors[i] != 0) {
updateFundingState(_tokens[i]);
}
}
ConfigureLogic.setFundingFactor(_tokens, _fundingFactors, _fundingExponentFactors);
}
function getFundingFactor(address _token) public view override returns (uint256, uint256) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
return (fs.fundingFactors[_token], fs.fundingExponentFactors[_token]);
}
// deposit into the pool without minting USDG tokens
// useful in allowing the pool to become over-collaterised
function directPoolDeposit(address _token) external override nonReentrant whenNotPaused {
SupplyLogic.directPoolDeposit(_token);
}
function buyUSDG(address _token, address _receiver)
external
override
nonReentrant
whenNotPaused
returns (uint256)
{
require(!isTokenPaused(_token), "Vault: already paused");
return SupplyLogic.ExecuteBuyUSDG(_token, _receiver);
}
function sellUSDG(address _token, address _receiver)
external
override
nonReentrant
whenNotPaused
returns (uint256)
{
return SupplyLogic.ExecuteSellUSDG(_token, _receiver);
}
function swap(address _tokenIn, address _tokenOut, address _receiver)
external
override
nonReentrant
whenNotPaused
returns (uint256)
{
require(!isTokenPaused(_tokenIn) && !isTokenPaused(_tokenOut), "Vault: already paused");
uint256 amountIn = GenericLogic.transferIn(_tokenIn);
return SwapLogic.ExecuteSwap(_tokenIn, _tokenOut, amountIn, _receiver);
}
function increasePosition(
address _account,
address _collateralToken,
address _indexToken,
uint256 _sizeDelta,
bool _isLong
) external override nonReentrant whenNotPaused {
require(!isTokenPaused(_indexToken), "Vault: already paused");
PositionLogic.increasePosition(
DataTypes.IncreasePositionParams({
account: _account,
collateralToken: _collateralToken,
indexToken: _indexToken,
sizeDelta: _sizeDelta,
isLong: _isLong
})
);
}
function decreasePosition(
address _account,
address _collateralToken,
address _indexToken,
uint256 _collateralDelta,
uint256 _sizeDelta,
bool _isLong,
address _receiver
) external override nonReentrant whenNotPaused returns (uint256) {
return PositionLogic.decreasePosition(
DataTypes.DecreasePositionParams({
account: _account,
collateralToken: _collateralToken,
indexToken: _indexToken,
collateralDelta: _collateralDelta,
sizeDelta: _sizeDelta,
isLong: _isLong,
receiver: _receiver
})
);
}
function liquidatePosition(
address _account,
address _collateralToken,
address _indexToken,
bool _isLong,
address _feeReceiver
) external override nonReentrant whenNotPaused {
return PositionLogic.liquidatePosition(
DataTypes.LiquidatePositionParams({
account: _account,
collateralToken: _collateralToken,
indexToken: _indexToken,
isLong: _isLong,
feeReceiver: _feeReceiver
})
);
}
function validateLiquidation(
address _account,
address _collateralToken,
address _indexToken,
bool _isLong,
bool _raise
) external view override returns (uint256, uint256) {
return PositionLogic.validateLiquidation(_account, _collateralToken, _indexToken, _isLong, _raise);
}
function updateCumulativeBorrowingRate(address _collateralToken, address _indexToken)
public
nonReentrant
whenNotPaused
{
BorrowingFeeLogic.updateCumulativeBorrowingRate(_collateralToken, _indexToken);
}
function updateFundingState(address _indexToken) public nonReentrant whenNotPaused {
FundingFeeLogic.updateFundingState(_indexToken);
}
function getBorrowingFeeInfo(address _token) external view returns (uint256, uint256) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
return (fs.cumulativeBorrowingRates[_token], fs.lastBorrowingTimes[_token]);
}
function getMaxPrice(address _token) public view override returns (uint256) {
return GenericLogic.getMaxPrice(_token);
}
function getMinPrice(address _token) external view override returns (uint256) {
return GenericLogic.getMinPrice(_token);
}
function getPoolInfo(address _token) external view override returns (DataTypes.PoolInfo memory) {
return GenericLogic.getPoolInfo(_token);
}
function getWhitelistedToken() external view override returns (uint256, address[] memory) {
return GenericLogic.getWhitelistedToken();
}
function getTokenInfo(address _token) external view override returns (DataTypes.TokenInfo memory) {
return GenericLogic.getTokenInfo(_token);
}
function getFeeReserves(address _token) external view returns (uint256) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
return fs.feeReserves[_token];
}
function getUtilisation(address _token) public view returns (uint256) {
return GenericLogic.getUtilisation(_token);
}
function getPositionLeverage(address _account, address _collateralToken, address _indexToken, bool _isLong)
external
view
returns (uint256)
{
DataTypes.Position memory position = getPosition(_account, _collateralToken, _indexToken, _isLong);
require(position.collateral > 0, "Vault: invalid position");
return (position.size * Constants.PERCENTAGE_FACTOR) / position.collateral;
}
function getGlobalShortDelta(address _token) public view returns (bool, uint256) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
uint256 size = ps.globalShortSizes[_token];
if (size == 0) {
return (false, 0);
}
uint256 nextPrice = GenericLogic.getMaxPrice(_token);
uint256 averagePrice = ps.globalShortAveragePrices[_token];
uint256 priceDelta = averagePrice > nextPrice ? averagePrice - nextPrice : nextPrice - averagePrice;
uint256 delta = (size * priceDelta) / averagePrice;
bool hasProfit = averagePrice > nextPrice;
return (hasProfit, delta);
}
function getPosition(address _account, address _collateralToken, address _indexToken, bool _isLong)
public
view
override
returns (DataTypes.Position memory)
{
return PositionLogic.getPosition(_account, _collateralToken, _indexToken, _isLong);
}
function getRedemptionAmount(address _token, uint256 _usdgAmount) external view override returns (uint256) {
return GenericLogic.getRedemptionAmount(_token, _usdgAmount);
}
function getTargetUsdgAmount(address _token) external view returns (uint256) {
return GenericLogic.getTargetUsdgAmount(_token);
}
function getNextTargetUsdgAmount(address _token, uint256 _usdgDelta, bool _increment)
external
view
returns (uint256)
{
return GenericLogic.getNextTargetUsdgAmount(_token, _usdgDelta, _increment);
}
function getFeeBasisPoints(
address _token,
uint256 _usdgDelta,
uint256 _feeBasisPoints,
uint256 _taxBasisPoints,
bool _increment,
bool _isSwap
) external view override returns (uint256, bool, bool) {
return GenericLogic.getFeeBasisPoints(_token, _usdgDelta, _feeBasisPoints, _taxBasisPoints, _increment, _isSwap);
}
function tokenToUsdMin(address _token, uint256 _tokenAmount) external view override returns (uint256) {
return GenericLogic.tokenToUsdMin(_token, _tokenAmount);
}
function getFundingFeeAmount(address _account) external view returns (uint256) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
return fs.claimableFundingAmount[_account];
}
function claimFundingFees() external nonReentrant whenNotPaused returns (uint256) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
uint256 claimableFundingAmount = fs.claimableFundingAmount[msg.sender];
if (claimableFundingAmount > 0) {
claimableFundingAmount = GenericLogic.usdToTokenMin(addrs.collateralToken, claimableFundingAmount);
GenericLogic.transferOut(addrs.collateralToken, claimableFundingAmount, msg.sender);
fs.claimableFundingAmount[msg.sender] = 0;
emit ClaimFundingFee(msg.sender, addrs.collateralToken, claimableFundingAmount);
}
return claimableFundingAmount;
}
function getPositionDeltaAndFees(address _account, address _collateralToken, address _indexToken, bool _isLong)
external
view
returns (bool, uint256, uint256, uint256, uint256)
{
DataTypes.Position memory position = getPosition(_account, _collateralToken, _indexToken, _isLong);
(bool hasProfit, uint256 delta) =
PositionLogic.getDelta(_indexToken, position.size, position.averagePrice, _isLong);
uint256 borrowingFee = BorrowingFeeLogic.getBorrowingFee(
_account, _collateralToken, _indexToken, _isLong, position.size, position.entryBorrowingRate
);
DataTypes.PositionFundingFees memory positionFundingFees =
FundingFeeLogic.getFundingFees(_indexToken, _isLong, position);
return
(hasProfit, delta, borrowingFee, positionFundingFees.fundingFeeAmount, positionFundingFees.claimableAmount);
}
function getBatchSettleFundingFeeAmount(
address _account,
address[] memory _collateralToken,
address[] memory _indexToken,
bool[] memory _isLong
) external view returns (uint256) {
require(
_collateralToken.length == _indexToken.length && _collateralToken.length == _isLong.length,
"inconsistent length"
);
uint256 totalSettleFundingFee;
for (uint256 i = 0; i < _collateralToken.length; i++) {
bytes32 key = PositionLogic.getPositionKey(_account, _collateralToken[i], _indexToken[i], _isLong[i]);
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
DataTypes.Position storage position = ps.positions[key];
if (position.size == 0) {
continue;
}
DataTypes.PositionFundingFees memory positionFundingFees =
FundingFeeLogic.getFundingFees(_indexToken[i], _isLong[i], position);
totalSettleFundingFee += positionFundingFees.claimableAmount;
}
return totalSettleFundingFee;
}
function batchSettleFundingFee(
address[] memory _collateralToken,
address[] memory _indexToken,
bool[] memory _isLong
) external nonReentrant whenNotPaused {
require(
_collateralToken.length == _indexToken.length && _collateralToken.length == _isLong.length,
"inconsistent length"
);
uint256 totalSettleFundingFee;
for (uint256 i = 0; i < _collateralToken.length; i++) {
bytes32 key = PositionLogic.getPositionKey(msg.sender, _collateralToken[i], _indexToken[i], _isLong[i]);
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
DataTypes.Position storage position = ps.positions[key];
if (position.size == 0) {
continue;
}
DataTypes.PositionFundingFees memory positionFundingFees =
FundingFeeLogic.getFundingFees(_indexToken[i], _isLong[i], position);
FundingFeeLogic.incrementClaimableFundingAmount(msg.sender, positionFundingFees);
position.claimableFundingAmountPerSize = positionFundingFees.latestClaimableFundingAmountPerSize;
totalSettleFundingFee += positionFundingFees.claimableAmount;
}
emit SettleFundingFee(msg.sender, totalSettleFundingFee);
}
function getTotalFeesForPositionLiquidation(
address _account,
address _collateralToken,
address _indexToken,
bool _isLong
) external view returns (uint256) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
DataTypes.Position memory position = getPosition(_account, _collateralToken, _indexToken, _isLong);
uint256 positionFee = PositionLogic.getPositionFee(position.size);
uint256 borrowingFee = BorrowingFeeLogic.getBorrowingFee(
_account, _collateralToken, _indexToken, _isLong, position.size, position.entryBorrowingRate
);
DataTypes.PositionFundingFees memory positionFundingFees =
FundingFeeLogic.getFundingFees(_indexToken, _isLong, position);
uint256 totalFees = positionFee + borrowingFee + positionFundingFees.fundingFeeAmount + fs.liquidationFeeUsd;
return totalFees;
}
function setPause(bool flag) external onlyOwner {
if (flag) {
_pause();
} else {
_unpause();
}
}
function getPause() external view override returns (bool) {
return paused();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
import "./OwnableUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
function __Ownable2Step_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable2Step_init_unchained() internal onlyInitializing {
}
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() external {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
/**
* @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[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @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[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (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]
* ```
* 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.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @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[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @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[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20PermitUpgradeable {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
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.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
import "../extensions/draft-IERC20PermitUpgradeable.sol";
import "../../../utils/AddressUpgradeable.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20Upgradeable {
using AddressUpgradeable for address;
function safeTransfer(
IERC20Upgradeable token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20Upgradeable token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20PermitUpgradeable token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/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
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @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.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "./IVault.sol";
interface IUlpManager {
function ulp() external view returns (address);
function usdg() external view returns (address);
function vault() external view returns (IVault);
function cooldownDuration() external returns (uint256);
function getPrice(bool _maximise) external view returns (uint256);
function getAum(bool maximise) external view returns (uint256);
function getAumInUsdg(bool maximise) external view returns (uint256);
function getTokenInUsdg(address token, uint256 amount, bool maximise) external view returns (uint256);
function lastAddedAt(address _account) external returns (uint256);
function addLiquidity(address _token, uint256 _amount, uint256 _minUsdg, uint256 _minUlp)
external
returns (uint256);
function addLiquidityForAccount(
address _fundingAccount,
address _account,
address _token,
uint256 _amount,
uint256 _minUsdg,
uint256 _minUlp
) external returns (uint256);
function removeLiquidity(uint256 _ulpAmount, uint256 _minOut, address _receiver) external returns (uint256);
function removeLiquidityForAccount(address _account, uint256 _ulpAmount, uint256 _minOut, address _receiver)
external
returns (uint256);
function setCooldownDuration(uint256 _cooldownDuration) external;
struct TokenAmountOut {
address token;
uint256 amountOut;
uint256 amountOutFormatPrecision;
}
function getTokenAmountOut(uint256 _ulpAmount) external view returns (TokenAmountOut[] memory);
function getUsdgAmount(uint256 _ulpAmount) external view returns (address[] memory, uint256[] memory, uint256);
function getAumInUsdgWithoutProfit(bool maximise) external view returns (uint256, uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {DataTypes} from "../libraries/types/DataTypes.sol";
interface IVault {
function buyUSDG(address _token, address _receiver) external returns (uint256);
function sellUSDG(address _token, address _receiver) external returns (uint256);
function swap(address _tokenIn, address _tokenOut, address _receiver) external returns (uint256);
function increasePosition(
address _account,
address _collateralToken,
address _indexToken,
uint256 _sizeDelta,
bool _isLong
) external;
function decreasePosition(
address _account,
address _collateralToken,
address _indexToken,
uint256 _collateralDelta,
uint256 _sizeDelta,
bool _isLong,
address _receiver
) external returns (uint256);
function liquidatePosition(
address _account,
address _collateralToken,
address _indexToken,
bool _isLong,
address _feeReceiver
) external;
function getMaxPrice(address _token) external view returns (uint256);
function getMinPrice(address _token) external view returns (uint256);
function getPosition(address _account, address _collateralToken, address _indexToken, bool _isLong)
external
view
returns (DataTypes.Position memory);
function getRedemptionAmount(address _token, uint256 _usdgAmount) external view returns (uint256);
function tokenToUsdMin(address _token, uint256 _tokenAmount) external view returns (uint256);
function getTokenDecimal(address _token) external view returns (uint256);
function getBorrowingRate() external view returns (uint256, uint256, uint256);
function getFundingFactor(address _token) external view returns (uint256, uint256);
function getPoolInfo(address _token) external view returns (DataTypes.PoolInfo memory);
function getWhitelistedToken() external view returns (uint256, address[] memory);
function getTokenInfo(address _token) external view returns (DataTypes.TokenInfo memory);
function directPoolDeposit(address _token) external;
function getFeeBasisPoints(
address _token,
uint256 _usdgDelta,
uint256 _feeBasisPoints,
uint256 _taxBasisPoints,
bool _increment,
bool _isSwap
) external view returns (uint256, bool, bool);
function getFees() external view returns (DataTypes.SetFeesParams memory);
function getAddresses() external view returns (DataTypes.AddressStorage memory);
function isTokenPaused(address _token) external view returns (bool);
function setTokenPause(address _token, bool _isPause) external;
function getReserveRatio() external view returns (uint256);
function getGlobalData(address _token) external view returns (DataTypes.GlobalData memory);
function getPause() external view returns (bool);
function validateLiquidation(
address _account,
address _collateralToken,
address _indexToken,
bool _isLong,
bool _raise
) external view returns (uint256, uint256);
function withdrawFees(address _token) external returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IVaultPriceFeed {
function adjustmentBasisPoints(address _token) external view returns (uint256);
function isAdjustmentAdditive(address _token) external view returns (bool);
function getPrice(address _token, bool _maximise) external view returns (uint256);
function getLatestPrimaryPrice(address _token) external view returns (uint256);
function getPrimaryPrice(address _token, bool _maximise) external view returns (uint256);
function setTokenConfig(address _token, address _priceFeed, uint256 _priceDecimals, bool _isStrictStable)
external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
library Constants {
// public
uint256 public constant PERCENTAGE_FACTOR = 1e4;
uint256 public constant PRICE_PRECISION = 1e30;
uint256 public constant USDG_DECIMALS = 18;
uint256 public constant ULP_PRECISION = 1e18;
uint256 public constant COllATERAL_PRECISION = 1e18;
// Vault
uint256 public constant BORROWING_RATE_PRECISION = 1000000;
uint256 public constant MIN_LEVERAGE = 1e4; // 1x
uint256 public constant MAX_FEE_BASIS_POINTS = 500; // 5%
uint256 public constant MAX_LIQUIDATION_FEE_USD = 100 * PRICE_PRECISION; // 100 USD
uint256 public constant MIN_BORROWING_RATE_INTERVAL = 1 hours;
uint256 public constant MAX_BORROWING_RATE_FACTOR = 1e4; // 1%
// UlpManager
uint256 public constant MAX_COOLDOWN_DURATION = 48 hours;
// VaultPriceFeed
uint256 public constant ONE_USD = PRICE_PRECISION;
uint256 public constant MAX_SPREAD_BASIS_POINTS = 50;
uint256 public constant MAX_ADJUSTMENT_INTERVAL = 2 hours;
uint256 public constant MAX_ADJUSTMENT_BASIS_POINTS = 20;
// FastPrieFeed
uint256 public constant CUMULATIVE_DELTA_PRECISION = 10 * 1000 * 1000;
uint256 public constant MAX_REF_PRICE = type(uint160).max;
uint256 public constant MAX_CUMULATIVE_REF_DELTA = type(uint32).max;
uint256 public constant MAX_CUMULATIVE_FAST_DELTA = type(uint32).max;
// uint256(~0) is 256 bits of 1s
// shift the 1s by (256 - 32) to get (256 - 32) 0s followed by 32 1s
uint256 public constant BITMASK_32 = uint256(int256(~0)) >> (256 - 32);
uint256 public constant MAX_PRICE_DURATION = 30 minutes;
// Reward
uint256 public constant BONUS_DURATION = 365 days;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
library Errors {
string public constant VAULT_INVALID_MAXLEVERAGE = "0";
string public constant VAULT_INVALID_TAX_BASIS_POINTS = "1";
string public constant VAULT_INVALID_STABLE_TAX_BASIS_POINTS = "2";
string public constant VAULT_INVALID_MINT_BURN_FEE_BASIS_POINTS = "3";
string public constant VAULT_INVALID_SWAP_FEE_BASIS_POINTS = "4";
string public constant VAULT_INVALID_STABLE_SWAP_FEE_BASIS_POINTS = "5";
string public constant VAULT_INVALID_MARGIN_FEE_BASIS_POINTS = "6";
string public constant VAULT_INVALID_LIQUIDATION_FEE_USD = "7";
string public constant VAULT_INVALID_BORROWING_INTERVALE = "8";
string public constant VAULT_INVALID_BORROWING_RATE_FACTOR = "9";
string public constant VAULT_INVALID_STABLE_BORROWING_RATE_FACTOR = "10";
string public constant VAULT_TOKEN_NOT_WHITELISTED = "11";
string public constant VAULT_INVALID_TOKEN_AMOUNT = "12";
string public constant VAULT_INVALID_USDG_AMOUNT = "13";
string public constant VAULT_INVALID_REDEMPTION_AMOUNT = "14";
string public constant VAULT_INVALID_AMOUNT_OUT = "15";
string public constant VAULT_SWAPS_NOT_ENABLED = "16";
string public constant VAULT_TOKEN_IN_NOT_WHITELISTED = "17";
string public constant VAULT_TOKEN_OUT_NOT_WHITELISTED = "18";
string public constant VAULT_INVALID_TOKENS = "19";
string public constant VAULT_INVALID_AMOUNT_IN = "20";
string public constant VAULT_LEVERAGE_NOT_ENABLED = "21";
string public constant VAULT_INSUFFICIENT_COLLATERAL_FOR_FEES = "22";
string public constant VAULT_INVALID_POSITION_SIZE = "23";
string public constant VAULT_EMPTY_POSITION = "24";
string public constant VAULT_POSITION_SIZE_EXCEEDED = "25";
string public constant VAULT_POSITION_COLLATERAL_EXCEEDED = "26";
string public constant VAULT_INVALID_LIQUIDATOR = "27";
string public constant VAULT_POSITION_CAN_NOT_BE_LIQUIDATED = "28";
string public constant VAULT_INVALID_POSITION = "29";
string public constant VAULT_INVALID_AVERAGE_PRICE = "30";
string public constant VAULT_COLLATERAL_SHOULD_BE_WITHDRAWN = "31";
string public constant VAULT_SIZE_MUST_BE_MORE_THAN_COLLATERAL = "32";
string public constant VAULT_INVALID_MSG_SENDER = "33";
string public constant VAULT_MISMATCHED_TOKENS = "34";
string public constant VAULT_COLLATERAL_TOKEN_NOT_WHITELISTED = "35";
string public constant VAULT_COLLATERAL_TOKEN_MUST_NOT_BE_A_STABLE_TOKEN = "36";
string public constant VAULT_COLLATERAL_TOKEN_MUST_BE_STABLE_TOKEN = "37";
string public constant VAULT_INDEX_TOKEN_MUST_NOT_BE_STABLE_TOKEN = "38";
string public constant VAULT_INDEX_TOKEN_NOT_SHORTABLE = "39";
string public constant VAULT_INVALID_INCREASE = "40";
string public constant VAULT_RESERVE_EXCEEDS_POOL = "41";
string public constant VAULT_MAX_USDG_EXCEEDED = "42";
string public constant VAULT_FORBIDDEN = "43";
string public constant VAULT_MAX_GAS_PRICE_EXCEEDED = "44";
string public constant VAULT_POOL_AMOUNT_LESS_THAN_BUFFER_AMOUNT = "45";
string public constant VAULT_POOL_AMOUNT_EXCEEDED = "46";
string public constant VAULT_MAX_SHORTS_EXCEEDED = "47";
string public constant VAULT_INSUFFICIENT_RESERVE = "48";
string public constant VAULT_NOT_SWAPER = "51";
string public constant MATH_MULTIPLICATION_OVERFLOW = "52";
string public constant MATH_DIVISION_BY_ZERO = "53";
string public constant INVALID_CALLER = "54";
string public constant VAULT_MAX_LONG_EXCEEDED = "55";
string public constant VAULT_INDEX_TOKEN_NOT_WHITELISTED = "56";
// Funding Fee Error
string public constant EMPTY_OPEN_INTEREST = "60";
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {DataTypes} from "../types/DataTypes.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {Constants} from "../helpers/Constants.sol";
import {GenericLogic} from "./GenericLogic.sol";
import {IUlpManager} from "../../interfaces/IUlpManager.sol";
library BorrowingFeeLogic {
event UpdateBorrowingRate(address token, uint256 borrowngRate);
function getBorrowingFee(
address, /* _account */
address _collateralToken,
address, /* _indexToken */
bool, /* _isLong */
uint256 _size,
uint256 _entryBorrowingRate
) internal view returns (uint256) {
if (_size == 0) {
return 0;
}
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
uint256 borrowingRate = fs.cumulativeBorrowingRates[_collateralToken] - _entryBorrowingRate;
if (borrowingRate == 0) {
return 0;
}
return (_size * borrowingRate) / Constants.BORROWING_RATE_PRECISION;
}
function updateCumulativeBorrowingRate(address _collateralToken, address /*_indexToken*/ ) internal {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
if (fs.lastBorrowingTimes[_collateralToken] == 0) {
fs.lastBorrowingTimes[_collateralToken] = (block.timestamp / fs.borrowingInterval) * fs.borrowingInterval;
return;
}
if (fs.lastBorrowingTimes[_collateralToken] + fs.borrowingInterval > block.timestamp) {
return;
}
uint256 borrowingRate = getNextBorrowingRate(_collateralToken);
fs.cumulativeBorrowingRates[_collateralToken] = fs.cumulativeBorrowingRates[_collateralToken] + borrowingRate;
fs.lastBorrowingTimes[_collateralToken] = (block.timestamp / fs.borrowingInterval) * fs.borrowingInterval;
emit UpdateBorrowingRate(_collateralToken, fs.cumulativeBorrowingRates[_collateralToken]);
}
function getNextBorrowingRate(address _token) internal view returns (uint256) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
if (fs.lastBorrowingTimes[_token] + fs.borrowingInterval > block.timestamp) {
return 0;
}
uint256 intervals = (block.timestamp - fs.lastBorrowingTimes[_token]) / (fs.borrowingInterval);
uint256 _borrowingRateFactor = ts.stableTokens[_token] ? fs.stableBorrowingRateFactor : fs.borrowingRateFactor;
uint256 aum = IUlpManager(addrs.ulpManager).getAum(true);
uint256 price = GenericLogic.getMinPrice(_token);
uint256 decimals = ts.tokenDecimals[_token];
uint256 reservedUsd = (price * ps.reservedAmounts[_token]) / 10 ** decimals;
if (reservedUsd == 0 || aum == 0) {
return 0;
}
return (_borrowingRateFactor * reservedUsd * intervals) / aum;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {
IERC20Upgradeable,
SafeERC20Upgradeable
} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {MathUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
import {ValidationLogic} from "./ValidationLogic.sol";
import {GenericLogic} from "./GenericLogic.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {Errors} from "../helpers/Errors.sol";
import {Constants} from "../helpers/Constants.sol";
import {DataTypes} from "../types/DataTypes.sol";
library ConfigureLogic {
event SetMaxLeverage(uint256 maxLeverage);
event SetMaxGlobalSizes(address[] tokens, uint256[] longSizes, uint256[] shortSizes);
function setBorrowingRate(
uint256 _borrowingInterval,
uint256 _borrowingRateFactor,
uint256 _stableBorrowingRateFactor
) external {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
ValidationLogic.validate(
_borrowingInterval >= Constants.MIN_BORROWING_RATE_INTERVAL, Errors.VAULT_INVALID_BORROWING_INTERVALE
);
ValidationLogic.validate(
_borrowingRateFactor <= Constants.MAX_BORROWING_RATE_FACTOR, Errors.VAULT_INVALID_BORROWING_RATE_FACTOR
);
ValidationLogic.validate(
_stableBorrowingRateFactor <= Constants.MAX_BORROWING_RATE_FACTOR,
Errors.VAULT_INVALID_STABLE_BORROWING_RATE_FACTOR
);
fs.borrowingInterval = _borrowingInterval;
fs.borrowingRateFactor = _borrowingRateFactor;
fs.stableBorrowingRateFactor = _stableBorrowingRateFactor;
}
function setAddresses(DataTypes.AddressStorage memory params) external {
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
addrs.weth = params.weth;
addrs.router = params.router;
addrs.ulpManager = params.ulpManager;
addrs.priceFeed = params.priceFeed;
addrs.usdg = params.usdg;
addrs.collateralToken = params.collateralToken;
addrs.feesReceiver = params.feesReceiver;
}
function setFees(DataTypes.SetFeesParams memory params) external {
ValidationLogic.validate(
params.taxBasisPoints <= Constants.MAX_FEE_BASIS_POINTS, Errors.VAULT_INVALID_TAX_BASIS_POINTS
);
ValidationLogic.validate(
params.stableTaxBasisPoints <= Constants.MAX_FEE_BASIS_POINTS, Errors.VAULT_INVALID_STABLE_TAX_BASIS_POINTS
);
ValidationLogic.validate(
params.mintBurnFeeBasisPoints <= Constants.MAX_FEE_BASIS_POINTS,
Errors.VAULT_INVALID_MINT_BURN_FEE_BASIS_POINTS
);
ValidationLogic.validate(
params.swapFeeBasisPoints <= Constants.MAX_FEE_BASIS_POINTS, Errors.VAULT_INVALID_SWAP_FEE_BASIS_POINTS
);
ValidationLogic.validate(
params.stableSwapFeeBasisPoints <= Constants.MAX_FEE_BASIS_POINTS,
Errors.VAULT_INVALID_STABLE_SWAP_FEE_BASIS_POINTS
);
ValidationLogic.validate(
params.marginFeeBasisPoints <= Constants.MAX_FEE_BASIS_POINTS, Errors.VAULT_INVALID_MARGIN_FEE_BASIS_POINTS
);
ValidationLogic.validate(
params.liquidationFeeUsd <= Constants.MAX_LIQUIDATION_FEE_USD, Errors.VAULT_INVALID_LIQUIDATION_FEE_USD
);
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
fs.taxBasisPoints = params.taxBasisPoints;
fs.stableTaxBasisPoints = params.stableTaxBasisPoints;
fs.mintBurnFeeBasisPoints = params.mintBurnFeeBasisPoints;
fs.swapFeeBasisPoints = params.swapFeeBasisPoints;
fs.stableSwapFeeBasisPoints = params.stableSwapFeeBasisPoints;
fs.marginFeeBasisPoints = params.marginFeeBasisPoints;
fs.liquidationFeeUsd = params.liquidationFeeUsd;
fs.hasDynamicFees = params.hasDynamicFees;
fs.balanceReward = params.balanceReward;
}
function setRouter(address _router, bool _isRouter) external {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
ps.approvedRouters[msg.sender][_router] = _isRouter;
}
function setTokenConfig(DataTypes.SetTokenConfigParams memory params) external {
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
// increment token count for the first time
if (!ts.whitelistedTokens[params.token]) {
ts.whitelistedTokenCount = ts.whitelistedTokenCount + 1;
ts.allWhitelistedTokens.push(params.token);
}
uint256 totalTokenWeights = ts.totalTokenWeights;
totalTokenWeights = totalTokenWeights - ts.tokenWeights[params.token];
ts.whitelistedTokens[params.token] = true;
ts.tokenDecimals[params.token] = params.tokenDecimals;
ts.tokenWeights[params.token] = params.tokenWeight;
ts.maxUsdgAmounts[params.token] = params.maxUsdgAmount;
ts.stableTokens[params.token] = params.isStable;
ts.shortableTokens[params.token] = params.isShortable;
ts.totalTokenWeights = totalTokenWeights + params.tokenWeight;
}
function clearTokenConfig(address _token) external {
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
ValidationLogic.validate(ts.whitelistedTokens[_token], Errors.VAULT_TOKEN_NOT_WHITELISTED);
ts.totalTokenWeights = ts.totalTokenWeights - ts.tokenWeights[_token];
delete ts.whitelistedTokens[_token];
delete ts.tokenDecimals[_token];
delete ts.tokenWeights[_token];
delete ts.maxUsdgAmounts[_token];
delete ts.stableTokens[_token];
delete ts.shortableTokens[_token];
ts.whitelistedTokenCount = ts.whitelistedTokenCount - 1;
}
function setUsdgAmount(address _token, uint256 _amount) external {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
uint256 usdgAmount = ps.usdgAmounts[_token];
if (_amount > usdgAmount) {
GenericLogic.increaseUsdgAmount(_token, _amount - usdgAmount);
return;
}
GenericLogic.decreaseUsdgAmount(_token, usdgAmount - _amount);
}
function setFundingFactor(
address[] memory _tokens,
uint256[] memory _fundingFactors,
uint256[] memory _fundingExponentFactors
) external {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
for (uint256 i = 0; i < _tokens.length; i++) {
fs.fundingFactors[_tokens[i]] = _fundingFactors[i];
fs.fundingExponentFactors[_tokens[i]] = _fundingExponentFactors[i];
}
}
function setPermissionParams(
bool _inManagerMode,
bool _inPrivateLiquidationMode,
bool _isSwapEnabled,
bool _isLeverageEnabled
) external {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
ps.inManagerMode = _inManagerMode;
ps.inPrivateLiquidationMode = _inPrivateLiquidationMode;
ps.isSwapEnabled = _isSwapEnabled;
ps.isLeverageEnabled = _isLeverageEnabled;
}
function setManager(address _manager, bool _isManager) external {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
ps.isManager[_manager] = _isManager;
}
function setLiquidator(address _liquidator, bool _isActive) external {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
ps.isLiquidator[_liquidator] = _isActive;
}
function setTokenPause(address _token, bool _isPause) external {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
ps.isTokenPaused[_token] = _isPause;
}
function setMaxGasPrice(uint256 _maxGasPrice) external {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
ps.maxGasPrice = _maxGasPrice;
}
function setMaxLeverage(uint256 _maxLeverage) external {
ValidationLogic.validate(_maxLeverage > Constants.MIN_LEVERAGE, Errors.VAULT_INVALID_MAXLEVERAGE);
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
ps.maxLeverage = _maxLeverage;
emit SetMaxLeverage(_maxLeverage);
}
function setReserveRatio(uint256 _ratio) external {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
ps.reserveRatio = _ratio;
}
function setBufferAmount(address _token, uint256 _amount) external {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
ps.bufferAmounts[_token] = _amount;
}
function setMaxGlobalSizes(address[] memory _tokens, uint256[] memory _longSizes, uint256[] memory _shortSizes)
external
{
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
require(_tokens.length == _longSizes.length, "inconsistent length");
require(_tokens.length == _shortSizes.length, "inconsistent length");
for (uint256 i = 0; i < _tokens.length; i++) {
address token = _tokens[i];
ps.maxGlobalLongSizes[token] = _longSizes[i];
ps.maxGlobalShortSizes[token] = _shortSizes[i];
}
emit SetMaxGlobalSizes(_tokens, _longSizes, _shortSizes);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {DataTypes} from "../types/DataTypes.sol";
import {Errors} from "../helpers/Errors.sol";
import {Calc} from "../math/Calc.sol";
import {Precision} from "../math/Precision.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {GenericLogic} from "./GenericLogic.sol";
import {Constants} from "../helpers/Constants.sol";
struct PositionType {
uint256 long;
uint256 short;
}
struct GetNextFundingAmountPerSizeResult {
bool longsPayShorts;
uint256 fundingFactorPerSecond;
PositionType fundingFeeAmountPerSizeDelta;
PositionType claimableFundingAmountPerSizeDelta;
}
struct GetNextFundingAmountPerSizeCache {
uint256 longOpenInterest;
uint256 shortOpenInterest;
uint256 durationInSeconds;
uint256 sizeOfLargerSide;
uint256 fundingUsd;
}
struct GetNextFundingFactorPerSecondCache {
uint256 diffUsd;
uint256 totalOpenInterest;
uint256 fundingFactor;
uint256 fundingExponentFactor;
uint256 diffUsdAfterExponent;
uint256 diffUsdToOpenInterestFactor;
}
library FundingFeeLogic {
event UpdateFundingState(address token, uint256 lastFundingTime);
function getFundingFees(address _indexToken, bool _isLong, DataTypes.Position memory position)
internal
view
returns (DataTypes.PositionFundingFees memory)
{
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
DataTypes.PositionFundingFees memory positionFundingFees;
positionFundingFees.latestFundingFeeAmountPerSize = fs.fundingFeeAmountPerSizes[_indexToken][_isLong];
positionFundingFees.latestClaimableFundingAmountPerSize =
fs.claimableFundingAmountPerSizes[_indexToken][_isLong];
positionFundingFees.fundingFeeAmount = getFundingAmount(
positionFundingFees.latestFundingFeeAmountPerSize,
position.fundingFeeAmountPerSize,
position.size,
true // roundUpMagnitude
);
positionFundingFees.claimableAmount = getFundingAmount(
positionFundingFees.latestClaimableFundingAmountPerSize,
position.claimableFundingAmountPerSize,
position.size,
false // roundUpMagnitude
);
return positionFundingFees;
}
function updateFundingState(address _indexToken) external {
DataTypes.FeeStorage storage fee = StorageSlot.getVaultFeeStorage();
GetNextFundingAmountPerSizeResult memory result = getNextFundingAmountPerSize(_indexToken);
fee.fundingFeeAmountPerSizes[_indexToken][true] += result.fundingFeeAmountPerSizeDelta.long;
fee.fundingFeeAmountPerSizes[_indexToken][false] += result.fundingFeeAmountPerSizeDelta.short;
fee.claimableFundingAmountPerSizes[_indexToken][true] += result.claimableFundingAmountPerSizeDelta.long;
fee.claimableFundingAmountPerSizes[_indexToken][false] += result.claimableFundingAmountPerSizeDelta.short;
fee.lastFundingTimes[_indexToken] = block.timestamp;
emit UpdateFundingState(_indexToken, fee.lastFundingTimes[_indexToken]);
}
function getNextFundingAmountPerSize(address _indexToken)
internal
view
returns (GetNextFundingAmountPerSizeResult memory)
{
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
GetNextFundingAmountPerSizeResult memory result;
GetNextFundingAmountPerSizeCache memory cache;
cache.longOpenInterest = getOpenInterest(_indexToken, true);
cache.shortOpenInterest = getOpenInterest(_indexToken, false);
if (cache.longOpenInterest == 0 || cache.shortOpenInterest == 0) {
return result;
}
if (fs.lastFundingTimes[_indexToken] == 0) {
cache.durationInSeconds = 0;
} else {
cache.durationInSeconds = block.timestamp - fs.lastFundingTimes[_indexToken];
}
cache.sizeOfLargerSide =
cache.longOpenInterest > cache.shortOpenInterest ? cache.longOpenInterest : cache.shortOpenInterest;
(result.fundingFactorPerSecond, result.longsPayShorts) =
getNextFundingFactorPerSecond(_indexToken, cache.longOpenInterest, cache.shortOpenInterest);
cache.fundingUsd =
Precision.applyFactor(cache.sizeOfLargerSide, cache.durationInSeconds * result.fundingFactorPerSecond);
uint256 shortTokenPrice = Constants.ONE_USD;
if (result.longsPayShorts) {
result.fundingFeeAmountPerSizeDelta.long = getFundingAmountPerSizeDelta(
cache.fundingUsd,
cache.longOpenInterest,
shortTokenPrice,
true // roundUpMagnitude
);
result.claimableFundingAmountPerSizeDelta.short = getFundingAmountPerSizeDelta(
cache.fundingUsd,
cache.shortOpenInterest,
shortTokenPrice,
false // roundUpMagnitude
);
} else {
result.fundingFeeAmountPerSizeDelta.short = getFundingAmountPerSizeDelta(
cache.fundingUsd,
cache.shortOpenInterest,
shortTokenPrice,
true // roundUpMagnitude
);
result.claimableFundingAmountPerSizeDelta.long = getFundingAmountPerSizeDelta(
cache.fundingUsd,
cache.longOpenInterest,
shortTokenPrice,
false // roundUpMagnitude
);
}
return result;
}
// @dev get the next funding factor per second
// @return nextFundingFactorPerSecond, longsPayShorts
function getNextFundingFactorPerSecond(address _indexToken, uint256 _longOpenInterest, uint256 _shortOpenInterest)
internal
view
returns (uint256, bool)
{
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
GetNextFundingFactorPerSecondCache memory cache;
cache.diffUsd = Calc.diff(_longOpenInterest, _shortOpenInterest);
cache.totalOpenInterest = _longOpenInterest + _shortOpenInterest;
if (cache.diffUsd == 0) {
return (0, true);
}
require(cache.totalOpenInterest > 0, Errors.EMPTY_OPEN_INTEREST);
cache.fundingExponentFactor = fs.fundingExponentFactors[_indexToken];
cache.diffUsdAfterExponent = Precision.applyExponentFactor(cache.diffUsd, cache.fundingExponentFactor);
cache.diffUsdToOpenInterestFactor = Precision.toFactor(cache.diffUsdAfterExponent, cache.totalOpenInterest);
cache.fundingFactor = fs.fundingFactors[_indexToken];
return (
Precision.applyFactor(cache.diffUsdToOpenInterestFactor, cache.fundingFactor),
_longOpenInterest > _shortOpenInterest
);
}
// store funding values as token amount per (Precision.FLOAT_PRECISION_SQRT / Precision.FLOAT_PRECISION) of USD size
function getFundingAmountPerSizeDelta(
uint256 fundingUsd,
uint256 openInterest,
uint256 tokenPrice,
bool roundUpMagnitude
) internal pure returns (uint256) {
if (fundingUsd == 0 || openInterest == 0) {
return 0;
}
uint256 fundingUsdPerSize = Precision.mulDiv(
fundingUsd, Precision.FLOAT_PRECISION * Precision.FLOAT_PRECISION_SQRT, openInterest, roundUpMagnitude
);
if (roundUpMagnitude) {
return Calc.roundUpDivision(fundingUsdPerSize, tokenPrice);
} else {
return (fundingUsdPerSize) / tokenPrice;
}
}
function getOpenInterest(address _indexToken, bool _isLong) internal view returns (uint256) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
if (_isLong) {
return ps.globalLongSizes[_indexToken];
} else {
return ps.globalShortSizes[_indexToken];
}
}
// @dev get the funding amount to be deducted or distributed
//
// @param latestFundingAmountPerSize the latest funding amount per size
// @param positionFundingAmountPerSize the funding amount per size for the position
// @param positionSizeInUsd the position size in USD
// @param roundUpMagnitude whether the round up the result
//
// @return fundingAmount
function getFundingAmount(
uint256 latestFundingAmountPerSize,
uint256 positionFundingAmountPerSize,
uint256 positionSizeInUsd,
bool roundUpMagnitude
) internal pure returns (uint256) {
uint256 fundingDiffFactor = (latestFundingAmountPerSize - positionFundingAmountPerSize);
// a user could avoid paying funding fees by continually updating the position
// before the funding fee becomes large enough to be chargeable
// to avoid this, funding fee amounts should be rounded up
//
// this could lead to large additional charges if the token has a low number of decimals
// or if the token's value is very high, so care should be taken to inform users of this
//
// if the calculation is for the claimable amount, the amount should be rounded down instead
// divide the result by Precision.FLOAT_PRECISION * Precision.FLOAT_PRECISION_SQRT as the fundingAmountPerSize values
// are stored based on FLOAT_PRECISION_SQRT values
return Precision.mulDiv(positionSizeInUsd, fundingDiffFactor, Precision.FLOAT_PRECISION_SQRT, roundUpMagnitude);
}
function incrementClaimableFundingAmount(address _account, DataTypes.PositionFundingFees memory positionFundingFees)
internal
{
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
// if the position has negative funding fees, distribute it to allow it to be claimable
if (positionFundingFees.claimableAmount > 0) {
fs.claimableFundingAmount[_account] += positionFundingFees.claimableAmount;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {SignedMath} from "@openzeppelin/contracts/utils/math/SignedMath.sol";
import {
IERC20Upgradeable,
SafeERC20Upgradeable
} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {MathUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
import {ValidationLogic} from "./ValidationLogic.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {Constants} from "../helpers/Constants.sol";
import {Errors} from "../helpers/Errors.sol";
import {DataTypes} from "../types/DataTypes.sol";
import {IVaultPriceFeed} from "../../interfaces/IVaultPriceFeed.sol";
import {IUlpManager} from "../../interfaces/IUlpManager.sol";
library GenericLogic {
using MathUpgradeable for uint256;
using SafeCast for uint256;
using SafeCast for int256;
using SignedMath for int256;
using SafeERC20Upgradeable for IERC20Upgradeable;
event CollectSwapFees(address token, uint256 feeUsd, uint256 feeTokens, bool protocolPayFee);
event IncreasePoolAmount(address token, uint256 amount);
event DecreasePoolAmount(address token, uint256 amount);
event IncreaseUsdgAmount(address token, uint256 amount);
event DecreaseUsdgAmount(address token, uint256 amount);
event IncreaseReservedAmount(address token, uint256 amount);
event DecreaseReservedAmount(address token, uint256 amount);
event WithdrawFee(address token, uint256 amount, address receiver);
function collectSwapFees(address _token, uint256 _amount, int256 _feeBasisPoints) internal returns (uint256) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
uint256 afterFeeAmount;
uint256 feeAmount;
if (_feeBasisPoints < 0) {
afterFeeAmount =
(_amount * (Constants.PERCENTAGE_FACTOR + _feeBasisPoints.abs())) / Constants.PERCENTAGE_FACTOR;
emit CollectSwapFees(_token, tokenToUsdMin(_token, feeAmount), feeAmount, true);
return afterFeeAmount;
} else {
afterFeeAmount =
(_amount * (Constants.PERCENTAGE_FACTOR - _feeBasisPoints.abs())) / Constants.PERCENTAGE_FACTOR;
feeAmount = _amount - afterFeeAmount;
fs.feeReserves[_token] = fs.feeReserves[_token] + feeAmount;
emit CollectSwapFees(_token, tokenToUsdMin(_token, feeAmount), feeAmount, false);
return afterFeeAmount;
}
}
// cases to consider
// 1. initialAmount is far from targetAmount, action increases balance slightly => high rebate
// 2. initialAmount is far from targetAmount, action increases balance largely => high rebate
// 3. initialAmount is close to targetAmount, action increases balance slightly => low rebate
// 4. initialAmount is far from targetAmount, action reduces balance slightly => high tax
// 5. initialAmount is far from targetAmount, action reduces balance largely => high tax
// 6. initialAmount is close to targetAmount, action reduces balance largely => low tax
// 7. initialAmount is above targetAmount, nextAmount is below targetAmount and vice versa
// 8. a large swap should have similar fees as the same trade split into multiple smaller swaps
// avoid stack too deep
struct GetFeeBasisPointsCache {
uint256 fee;
bool haveBalanceReward;
bool isCrossBalance;
uint256 initialAmount;
uint256 nextAmount;
uint256 initialTargetAmount;
int256 initialDiff;
uint256 nextTargetAmount;
int256 nextDiff;
}
function getFeeBasisPoints(
address _token,
uint256 _usdgDelta,
uint256 _feeBasisPoints,
uint256 _taxBasisPoints,
bool _increment,
bool _isSwap
) internal view returns (uint256, bool, bool) {
GetFeeBasisPointsCache memory cache;
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
if (!fs.hasDynamicFees) {
return (_feeBasisPoints, false, false);
}
cache.initialAmount = ps.usdgAmounts[_token];
cache.nextAmount = cache.initialAmount + _usdgDelta;
if (!_increment) {
if (_usdgDelta > cache.initialAmount) {
cache.nextAmount = 0;
_usdgDelta = cache.initialAmount;
} else {
cache.nextAmount = cache.initialAmount - _usdgDelta;
}
}
cache.initialTargetAmount = getTargetUsdgAmount(_token);
if (_isSwap && !_increment) {
cache.initialTargetAmount = getNextTargetUsdgAmount(_token, _usdgDelta, true);
}
if (cache.initialTargetAmount == 0) {
return (_feeBasisPoints, false, false);
}
cache.initialDiff = cache.initialTargetAmount.toInt256() - cache.initialAmount.toInt256();
cache.nextTargetAmount = getNextTargetUsdgAmount(_token, _usdgDelta, _increment);
if (_isSwap && !_increment) {
cache.nextTargetAmount = getTargetUsdgAmount(_token);
}
if (cache.nextTargetAmount == 0) {
return (_feeBasisPoints, false, false);
}
cache.nextDiff = cache.nextTargetAmount.toInt256() - cache.nextAmount.toInt256();
if (_increment) {
// add liquidity
if (cache.nextDiff.abs() < cache.initialDiff.abs()) {
// action improves relative asset balance
uint256 rebateBps = (_taxBasisPoints * cache.initialDiff.abs()) / cache.nextTargetAmount;
cache.fee = rebateBps > _feeBasisPoints ? 0 : _feeBasisPoints - rebateBps;
if ((cache.initialDiff < 0 && cache.nextDiff <= 0) || (cache.initialDiff > 0 && cache.nextDiff >= 0)) {
// no cross balance, have balance reward
cache.haveBalanceReward = true;
cache.isCrossBalance = false;
} else {
// cross balance, no balance reward
cache.haveBalanceReward = false;
cache.isCrossBalance = true;
}
} else {
// action worsen relative asset balance
uint256 averageDiff = (cache.initialDiff.abs() + cache.nextDiff.abs()) / 2;
if (averageDiff > cache.nextTargetAmount) {
averageDiff = cache.nextTargetAmount;
}
uint256 taxBps = (_taxBasisPoints * averageDiff) / cache.nextTargetAmount;
if ((cache.initialDiff < 0 && cache.nextDiff <= 0) || (cache.initialDiff > 0 && cache.nextDiff >= 0)) {
// no cross balance, no balance reward
cache.fee = _feeBasisPoints + taxBps;
cache.haveBalanceReward = false;
cache.isCrossBalance = false;
} else {
// cross balance, no balance reward
cache.fee = _feeBasisPoints + taxBps;
cache.haveBalanceReward = false;
cache.isCrossBalance = true;
}
}
} else {
// remove liquidity
if ((cache.initialDiff < 0 && cache.nextDiff <= 0) || (cache.initialDiff > 0 && cache.nextDiff >= 0)) {
// no cross balance
// action improves relative asset balance
if (cache.nextDiff.abs() < cache.initialDiff.abs()) {
uint256 rebateBps = (_taxBasisPoints * cache.initialDiff.abs()) / cache.nextTargetAmount;
cache.fee = rebateBps > _feeBasisPoints ? 0 : _feeBasisPoints - rebateBps;
cache.haveBalanceReward = false;
cache.isCrossBalance = false;
} else {
uint256 averageDiff = (cache.initialDiff.abs() + cache.nextDiff.abs()) / 2;
if (averageDiff > cache.nextTargetAmount) {
averageDiff = cache.nextTargetAmount;
}
uint256 taxBps = (_taxBasisPoints * averageDiff) / cache.nextTargetAmount;
cache.fee = _feeBasisPoints + taxBps;
cache.haveBalanceReward = false;
cache.isCrossBalance = false;
}
} else {
// cross balance
uint256 averageDiff = (cache.initialDiff.abs() + cache.nextDiff.abs()) / 2;
if (averageDiff > cache.nextTargetAmount) {
averageDiff = cache.nextTargetAmount;
}
uint256 taxBps = (_taxBasisPoints * averageDiff) / cache.nextTargetAmount;
cache.fee = _feeBasisPoints + taxBps;
cache.haveBalanceReward = false;
cache.isCrossBalance = true;
}
}
if (_token != addrs.collateralToken) {
cache.haveBalanceReward = false;
}
if (!_increment && _token == addrs.collateralToken) {
cache.fee += fs.balanceReward;
}
return (cache.fee, cache.haveBalanceReward, cache.isCrossBalance);
}
function adjustForDecimals(uint256 _amount, address _tokenDiv, address _tokenMul) internal view returns (uint256) {
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
uint256 decimalsDiv = _tokenDiv == addrs.usdg ? Constants.USDG_DECIMALS : ts.tokenDecimals[_tokenDiv];
uint256 decimalsMul = _tokenMul == addrs.usdg ? Constants.USDG_DECIMALS : ts.tokenDecimals[_tokenMul];
return (_amount * 10 ** decimalsMul) / 10 ** decimalsDiv;
}
function adjustFor30Decimals(uint256 _amount, address _tokenMul) internal view returns (uint256) {
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
uint256 decimalsDiv = Constants.PRICE_PRECISION;
uint256 decimalsMul = ts.tokenDecimals[_tokenMul];
return (_amount * 10 ** decimalsMul) / decimalsDiv;
}
function getMaxPrice(address _token) internal view returns (uint256) {
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
return IVaultPriceFeed(addrs.priceFeed).getPrice(_token, true);
}
function getMinPrice(address _token) internal view returns (uint256) {
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
return IVaultPriceFeed(addrs.priceFeed).getPrice(_token, false);
}
function tokenToUsdMin(address _token, uint256 _tokenAmount) internal view returns (uint256) {
if (_tokenAmount == 0) {
return 0;
}
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
uint256 price = getMinPrice(_token);
uint256 decimals = ts.tokenDecimals[_token];
return (_tokenAmount * price) / 10 ** decimals;
}
function usdToTokenMax(address _token, uint256 _usdAmount) internal view returns (uint256) {
if (_usdAmount == 0) {
return 0;
}
return usdToToken(_token, _usdAmount, getMinPrice(_token));
}
function usdToTokenMin(address _token, uint256 _usdAmount) internal view returns (uint256) {
if (_usdAmount == 0) {
return 0;
}
return usdToToken(_token, _usdAmount, getMaxPrice(_token));
}
function usdToToken(address _token, uint256 _usdAmount, uint256 _price) internal view returns (uint256) {
if (_usdAmount == 0) {
return 0;
}
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
uint256 decimals = ts.tokenDecimals[_token];
return (_usdAmount * 10 ** decimals) / _price;
}
function getTargetUsdgAmount(address _token) internal view returns (uint256) {
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
uint256 supply = IERC20Upgradeable(addrs.usdg).totalSupply();
if (supply == 0) {
return 0;
}
uint256 weight = ts.tokenWeights[_token];
return (weight * supply) / ts.totalTokenWeights;
}
function getNextTargetUsdgAmount(address _token, uint256 _usdgDelta, bool _increment)
internal
view
returns (uint256)
{
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
uint256 supply = IERC20Upgradeable(addrs.usdg).totalSupply();
if (_increment) {
supply += _usdgDelta;
} else {
if (_usdgDelta > supply) {
return 0;
}
supply -= _usdgDelta;
}
if (supply == 0) {
return 0;
}
uint256 weight = ts.tokenWeights[_token];
return (weight * supply) / ts.totalTokenWeights;
}
function transferIn(address _token) internal returns (uint256) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
uint256 prevBalance = ps.tokenBalances[_token];
uint256 nextBalance = IERC20Upgradeable(_token).balanceOf(address(this));
ps.tokenBalances[_token] = nextBalance;
return nextBalance - prevBalance;
}
function transferOut(address _token, uint256 _amount, address _receiver) internal {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
IERC20Upgradeable(_token).safeTransfer(_receiver, _amount);
ps.tokenBalances[_token] = IERC20Upgradeable(_token).balanceOf(address(this));
}
function getRedemptionAmount(address _token, uint256 _usdgAmount) internal view returns (uint256) {
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
uint256 price = getMaxPrice(_token);
uint256 redemptionAmount = (_usdgAmount * Constants.PRICE_PRECISION) / price;
return adjustForDecimals(redemptionAmount, addrs.usdg, _token);
}
function increasePoolAmount(address _token, uint256 _amount) internal {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
ps.poolAmounts[_token] += _amount;
uint256 balance = IERC20Upgradeable(_token).balanceOf(address(this));
ValidationLogic.validate(ps.poolAmounts[_token] <= balance, Errors.VAULT_POOL_AMOUNT_EXCEEDED);
emit IncreasePoolAmount(_token, _amount);
}
function decreasePoolAmount(address _token, uint256 _amount, bool isDecreasePosition) internal {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
ValidationLogic.validate(ps.poolAmounts[_token] >= _amount, Errors.VAULT_POOL_AMOUNT_EXCEEDED);
ps.poolAmounts[_token] -= _amount;
if (!isDecreasePosition) {
ValidationLogic.validate(
ps.reservedAmounts[_token] <= ps.poolAmounts[_token], Errors.VAULT_RESERVE_EXCEEDS_POOL
);
}
emit DecreasePoolAmount(_token, _amount);
}
function increaseUsdgAmount(address _token, uint256 _amount) internal {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
ps.usdgAmounts[_token] = ps.usdgAmounts[_token] + _amount;
uint256 maxUsdgAmount = ts.maxUsdgAmounts[_token];
if (maxUsdgAmount != 0) {
ValidationLogic.validate(ps.usdgAmounts[_token] <= maxUsdgAmount, Errors.VAULT_MAX_USDG_EXCEEDED);
}
emit IncreaseUsdgAmount(_token, _amount);
}
function decreaseUsdgAmount(address _token, uint256 _amount) internal {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
uint256 value = ps.usdgAmounts[_token];
// since USDG can be minted using multiple assets
// it is possible for the USDG debt for a single asset to be less than zero
// the USDG debt is capped to zero for this case
if (value <= _amount) {
ps.usdgAmounts[_token] = 0;
emit DecreaseUsdgAmount(_token, value);
return;
}
ps.usdgAmounts[_token] = value - _amount;
emit DecreaseUsdgAmount(_token, _amount);
}
function increaseReservedAmount(address _token, uint256 _amount) internal {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
uint256 aum = IUlpManager(addrs.ulpManager).getAum(true);
ps.reservedAmounts[_token] = ps.reservedAmounts[_token] + _amount;
uint256 price = getMinPrice(_token);
uint256 decimals = ts.tokenDecimals[_token];
uint256 reservedUsd = (price * ps.reservedAmounts[_token]) / 10 ** decimals;
ValidationLogic.validate(reservedUsd <= aum, Errors.VAULT_RESERVE_EXCEEDS_POOL);
emit IncreaseReservedAmount(_token, _amount);
}
function decreaseReservedAmount(address _token, uint256 _amount) internal {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
ValidationLogic.validate(ps.reservedAmounts[_token] - _amount >= 0, Errors.VAULT_INSUFFICIENT_RESERVE);
ps.reservedAmounts[_token] -= _amount;
emit DecreaseReservedAmount(_token, _amount);
}
function increaseGlobalLongSize(address _token, uint256 _amount) internal {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
ps.globalLongSizes[_token] = ps.globalLongSizes[_token] + _amount;
uint256 maxSize = ps.maxGlobalLongSizes[_token];
if (maxSize != 0) {
ValidationLogic.validate(ps.globalLongSizes[_token] <= maxSize, Errors.VAULT_MAX_LONG_EXCEEDED);
}
}
function decreaseGlobalLongSize(address _token, uint256 _amount) internal {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
uint256 size = ps.globalLongSizes[_token];
if (_amount > size) {
ps.globalLongSizes[_token] = 0;
return;
}
ps.globalLongSizes[_token] = size - _amount;
}
function increaseGlobalShortSize(address _token, uint256 _amount) internal {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
ps.globalShortSizes[_token] = ps.globalShortSizes[_token] + _amount;
uint256 maxSize = ps.maxGlobalShortSizes[_token];
if (maxSize != 0) {
ValidationLogic.validate(ps.globalShortSizes[_token] <= maxSize, Errors.VAULT_MAX_SHORTS_EXCEEDED);
}
}
function decreaseGlobalShortSize(address _token, uint256 _amount) internal {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
uint256 size = ps.globalShortSizes[_token];
if (_amount > size) {
ps.globalShortSizes[_token] = 0;
return;
}
ps.globalShortSizes[_token] = size - _amount;
}
function updateTokenBalance(address _token) internal {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
uint256 nextBalance = IERC20Upgradeable(_token).balanceOf(address(this));
ps.tokenBalances[_token] = nextBalance;
}
function withdrawFees(address _token) external returns (uint256) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
require(addrs.feesReceiver != address(0), "feesReceiver is 0");
uint256 amount = fs.feeReserves[_token];
if (amount == 0) {
return 0;
}
fs.feeReserves[_token] = 0;
transferOut(_token, amount, addrs.feesReceiver);
emit WithdrawFee(_token, amount, addrs.feesReceiver);
return amount;
}
function getPoolInfo(address _token) external view returns (DataTypes.PoolInfo memory) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
DataTypes.PoolInfo memory poolInfo;
poolInfo.poolAmount = ps.poolAmounts[_token];
poolInfo.reservedAmount = ps.reservedAmounts[_token];
poolInfo.bufferAmount = ps.bufferAmounts[_token];
poolInfo.globalLongSize = ps.globalLongSizes[_token];
poolInfo.globalLongAveragePrice = ps.globalLongAveragePrices[_token];
poolInfo.globalShortSize = ps.globalShortSizes[_token];
poolInfo.globalShortAveragePrice = ps.globalShortAveragePrices[_token];
poolInfo.usdgAmount = ps.usdgAmounts[_token];
return poolInfo;
}
function getWhitelistedToken() internal view returns (uint256, address[] memory) {
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
return (ts.whitelistedTokenCount, ts.allWhitelistedTokens);
}
function getTokenInfo(address _token) internal view returns (DataTypes.TokenInfo memory) {
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
return DataTypes.TokenInfo({
tokenDecimal: ts.tokenDecimals[_token],
isWhitelistedToken: ts.whitelistedTokens[_token],
isStableToken: ts.stableTokens[_token],
maxUsdgAmount: ts.maxUsdgAmounts[_token]
});
}
function getBuyUsdgFeeBasisPoints(address _token, uint256 _usdgAmount) internal view returns (int256) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
(uint256 fee, bool haveBalanceReward,) =
getFeeBasisPoints(_token, _usdgAmount, fs.mintBurnFeeBasisPoints, fs.taxBasisPoints, true, false);
if (haveBalanceReward) {
return fee.toInt256() - fs.balanceReward.toInt256();
} else {
return fee.toInt256();
}
}
function getSellUsdgFeeBasisPoints(address _token, uint256 _usdgAmount) internal view returns (uint256) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
(uint256 fee,,) =
getFeeBasisPoints(_token, _usdgAmount, fs.mintBurnFeeBasisPoints, fs.taxBasisPoints, false, false);
return fee;
}
function getUtilisation(address _token) public view returns (uint256) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
uint256 poolAmount = ps.poolAmounts[_token];
if (poolAmount == 0) {
return 0;
}
return (ps.reservedAmounts[_token] * Constants.BORROWING_RATE_PRECISION) / poolAmount;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {SignedMath} from "@openzeppelin/contracts/utils/math/SignedMath.sol";
import {ValidationLogic} from "./ValidationLogic.sol";
import {GenericLogic} from "./GenericLogic.sol";
import {BorrowingFeeLogic} from "./BorrowingFeeLogic.sol";
import {FundingFeeLogic} from "./FundingFeeLogic.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {DataTypes} from "../types/DataTypes.sol";
import {Errors} from "../helpers/Errors.sol";
import {Calc} from "../math/Calc.sol";
import {Precision} from "../math/Precision.sol";
import {DataTypes} from "../types/DataTypes.sol";
import {Constants} from "../helpers/Constants.sol";
library PositionLogic {
using SafeCast for uint256;
using SafeCast for int256;
using SignedMath for int256;
event CollectMarginFees(address token, uint256 feeUsd, uint256 feeTokens);
event UpdatePnl(bytes32 key, bool hasProfit, uint256 delta);
event ClaimFundingFee(address indexed account, address token, uint256 amount);
event IncreasePosition(
bytes32 key, DataTypes.IncreasePositionParams params, uint256 collateralDelta, uint256 price, uint256 fee
);
event DecreasePosition(bytes32 key, DataTypes.DecreasePositionParams params, uint256 price, uint256 fee);
event LiquidatePosition(
bytes32 key,
address account,
address collateralToken,
address indexToken,
bool isLong,
uint256 size,
uint256 collateral,
uint256 reserveAmount,
int256 realisedPnl,
uint256 markPrice
);
event UpdatePosition(
bytes32 key,
uint256 size,
uint256 collateral,
uint256 averagePrice,
uint256 entryBorrowingRate,
uint256 reserveAmount,
int256 realisedPnl,
uint256 markPrice
);
event ClosePosition(
bytes32 key,
uint256 size,
uint256 collateral,
uint256 averagePrice,
uint256 entryBorrowingRate,
uint256 reserveAmount,
int256 realisedPnl
);
struct CollectMarginFeesParams {
address account;
address collateralToken;
address indexToken;
bool isLong;
uint256 sizeDelta;
DataTypes.Position position;
}
struct ReduceCollateralCache {
uint256 fee;
bool hasProfit;
uint256 adjustedDelta;
uint256 delta;
uint256 usdOut;
uint256 usdOutAfterFee;
DataTypes.PositionFundingFees fundingFees;
}
struct IncreasePositionCache {
uint256 entryPrice;
uint256 fee;
DataTypes.PositionFundingFees fundingFees;
uint256 collateralDelta;
uint256 collateralDeltaUsd;
uint256 reserveDelta;
}
struct DecreasePositionCache {
bytes32 key;
uint256 reservedAmount;
uint256 reserveDelta;
uint256 usdOut;
uint256 usdOutAfterFee;
DataTypes.PositionFundingFees fundingFees;
uint256 price;
uint256 amountOutAfterFees;
}
function increasePosition(DataTypes.IncreasePositionParams memory params) external {
IncreasePositionCache memory cache;
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
DataTypes.PermissionStorage storage permission = StorageSlot.getVaultPermissionStorage();
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
ValidationLogic.validateIncreasePositionParams(
permission.isLeverageEnabled, params.account, params.collateralToken, params.indexToken, params.isLong
);
bytes32 key = getPositionKey(params.account, params.collateralToken, params.indexToken, params.isLong);
DataTypes.Position storage position = ps.positions[key];
cache.entryPrice =
params.isLong ? GenericLogic.getMaxPrice(params.indexToken) : GenericLogic.getMinPrice(params.indexToken);
BorrowingFeeLogic.updateCumulativeBorrowingRate(params.collateralToken, params.indexToken);
FundingFeeLogic.updateFundingState(params.indexToken);
if (position.size == 0) {
position.averagePrice = cache.entryPrice;
position.fundingFeeAmountPerSize = fs.fundingFeeAmountPerSizes[params.indexToken][params.isLong];
position.claimableFundingAmountPerSize = fs.claimableFundingAmountPerSizes[params.indexToken][params.isLong];
}
if (position.size > 0 && params.sizeDelta > 0) {
position.averagePrice = getNextAveragePrice(
params.indexToken,
position.size,
position.averagePrice,
params.isLong,
cache.entryPrice,
params.sizeDelta
);
}
(cache.fee, cache.fundingFees) = collectMarginFees(
CollectMarginFeesParams({
account: params.account,
collateralToken: params.collateralToken,
indexToken: params.indexToken,
isLong: params.isLong,
sizeDelta: params.sizeDelta,
position: position
})
);
{
FundingFeeLogic.incrementClaimableFundingAmount(params.account, cache.fundingFees);
}
cache.collateralDelta = GenericLogic.transferIn(params.collateralToken);
cache.collateralDeltaUsd = GenericLogic.tokenToUsdMin(params.collateralToken, cache.collateralDelta);
position.fundingFeeAmountPerSize = cache.fundingFees.latestFundingFeeAmountPerSize;
position.claimableFundingAmountPerSize = cache.fundingFees.latestClaimableFundingAmountPerSize;
position.collateral = position.collateral + cache.collateralDeltaUsd;
ValidationLogic.validate(position.collateral >= cache.fee, Errors.VAULT_INSUFFICIENT_COLLATERAL_FOR_FEES);
position.collateral = position.collateral - cache.fee;
position.entryBorrowingRate = fs.cumulativeBorrowingRates[params.collateralToken];
position.size = position.size + params.sizeDelta;
position.lastIncreasedTime = block.timestamp;
ValidationLogic.validate(position.size > 0, Errors.VAULT_INVALID_POSITION_SIZE);
ValidationLogic.validatePosition(position.size, position.collateral);
validateLiquidation(params.account, params.collateralToken, params.indexToken, params.isLong, true);
// reserve tokens to pay profits on the position
cache.reserveDelta = GenericLogic.usdToTokenMax(params.collateralToken, params.sizeDelta);
if (ps.reserveRatio != 0) {
cache.reserveDelta = (cache.reserveDelta * ps.reserveRatio) / Constants.PERCENTAGE_FACTOR;
}
position.reserveAmount = position.reserveAmount + cache.reserveDelta;
GenericLogic.increaseReservedAmount(params.collateralToken, cache.reserveDelta);
if (params.isLong) {
if (ps.globalLongSizes[params.indexToken] == 0) {
ps.globalLongAveragePrices[params.indexToken] = cache.entryPrice;
} else {
ps.globalLongAveragePrices[params.indexToken] = getNextGlobalLongData(
params.account, params.collateralToken, params.indexToken, cache.entryPrice, params.sizeDelta, true
);
}
GenericLogic.increaseGlobalLongSize(params.indexToken, params.sizeDelta);
} else {
if (ps.globalShortSizes[params.indexToken] == 0) {
ps.globalShortAveragePrices[params.indexToken] = cache.entryPrice;
} else {
ps.globalShortAveragePrices[params.indexToken] = getNextGlobalShortData(
params.account, params.collateralToken, params.indexToken, cache.entryPrice, params.sizeDelta, true
);
}
GenericLogic.increaseGlobalShortSize(params.indexToken, params.sizeDelta);
}
emit IncreasePosition(key, params, cache.collateralDeltaUsd, cache.entryPrice, cache.fee);
emit UpdatePosition(
key,
position.size,
position.collateral,
position.averagePrice,
position.entryBorrowingRate,
position.reserveAmount,
position.realisedPnl,
cache.entryPrice
);
}
function decreasePosition(DataTypes.DecreasePositionParams memory params) external returns (uint256) {
ValidationLogic.validateDecreasePositionParams(params.account);
return _decreasePosition(params);
}
function _decreasePosition(DataTypes.DecreasePositionParams memory params) internal returns (uint256) {
DecreasePositionCache memory cache;
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
BorrowingFeeLogic.updateCumulativeBorrowingRate(params.collateralToken, params.indexToken);
FundingFeeLogic.updateFundingState(params.indexToken);
cache.key = getPositionKey(params.account, params.collateralToken, params.indexToken, params.isLong);
DataTypes.Position storage position = ps.positions[cache.key];
ValidationLogic.validate(position.size > 0, Errors.VAULT_EMPTY_POSITION);
ValidationLogic.validate(position.size >= params.sizeDelta, Errors.VAULT_POSITION_SIZE_EXCEEDED);
ValidationLogic.validate(
position.collateral >= params.collateralDelta, Errors.VAULT_POSITION_COLLATERAL_EXCEEDED
);
cache.reservedAmount = ps.reservedAmounts[params.indexToken];
cache.reserveDelta = (position.reserveAmount * (params.sizeDelta)) / position.size;
position.reserveAmount = position.reserveAmount - cache.reserveDelta;
GenericLogic.decreaseReservedAmount(params.collateralToken, cache.reserveDelta);
(cache.usdOut, cache.usdOutAfterFee, cache.fundingFees) = reduceCollateral(params);
cache.price =
params.isLong ? GenericLogic.getMinPrice(params.indexToken) : GenericLogic.getMaxPrice(params.indexToken);
FundingFeeLogic.incrementClaimableFundingAmount(params.account, cache.fundingFees);
if (params.isLong) {
ps.globalLongAveragePrices[params.indexToken] = getNextGlobalLongData(
params.account, params.collateralToken, params.indexToken, cache.price, params.sizeDelta, false
);
GenericLogic.decreaseGlobalLongSize(params.indexToken, params.sizeDelta);
} else {
ps.globalShortAveragePrices[params.indexToken] = getNextGlobalShortData(
params.account, params.collateralToken, params.indexToken, cache.price, params.sizeDelta, false
);
GenericLogic.decreaseGlobalShortSize(params.indexToken, params.sizeDelta);
}
if (position.size != params.sizeDelta) {
position.entryBorrowingRate = fs.cumulativeBorrowingRates[params.collateralToken];
position.fundingFeeAmountPerSize = cache.fundingFees.latestFundingFeeAmountPerSize;
position.claimableFundingAmountPerSize = cache.fundingFees.latestClaimableFundingAmountPerSize;
position.size = position.size - params.sizeDelta;
ValidationLogic.validatePosition(position.size, position.collateral);
validateLiquidation(params.account, params.collateralToken, params.indexToken, params.isLong, true);
emit UpdatePosition(
cache.key,
position.size,
position.collateral,
position.averagePrice,
position.entryBorrowingRate,
position.reserveAmount,
position.realisedPnl,
cache.price
);
} else {
emit ClosePosition(
cache.key,
position.size,
position.collateral,
position.averagePrice,
position.entryBorrowingRate,
position.reserveAmount,
position.realisedPnl
);
delete ps.positions[cache.key];
}
emit DecreasePosition(cache.key, params, cache.price, cache.usdOut - cache.usdOutAfterFee);
if (cache.usdOutAfterFee > 0) {
cache.amountOutAfterFees = GenericLogic.usdToTokenMin(params.collateralToken, cache.usdOutAfterFee);
GenericLogic.transferOut(params.collateralToken, cache.amountOutAfterFees, params.receiver);
return cache.amountOutAfterFees;
}
return 0;
}
function liquidatePosition(DataTypes.LiquidatePositionParams memory params) external {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
DataTypes.PermissionStorage storage permission = StorageSlot.getVaultPermissionStorage();
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
if (permission.inPrivateLiquidationMode) {
ValidationLogic.validate(permission.isLiquidator[msg.sender], Errors.VAULT_INVALID_LIQUIDATOR);
}
uint256 markPrice =
params.isLong ? GenericLogic.getMinPrice(params.indexToken) : GenericLogic.getMaxPrice(params.indexToken);
BorrowingFeeLogic.updateCumulativeBorrowingRate(params.collateralToken, params.indexToken);
FundingFeeLogic.updateFundingState(params.indexToken);
bytes32 key = getPositionKey(params.account, params.collateralToken, params.indexToken, params.isLong);
DataTypes.Position storage position = ps.positions[key];
ValidationLogic.validate(position.size > 0, Errors.VAULT_EMPTY_POSITION);
(uint256 liquidationState, uint256 marginFees) =
validateLiquidation(params.account, params.collateralToken, params.indexToken, params.isLong, false);
ValidationLogic.validate(liquidationState != 0, Errors.VAULT_POSITION_CAN_NOT_BE_LIQUIDATED);
if (liquidationState == 2) {
// max leverage exceeded but there is collateral remaining after deducting losses so decreasePosition instead
_decreasePosition(
DataTypes.DecreasePositionParams({
account: params.account,
collateralToken: params.collateralToken,
indexToken: params.indexToken,
collateralDelta: 0,
sizeDelta: position.size,
isLong: params.isLong,
receiver: params.account
})
);
return;
}
{
uint256 feeTokens = GenericLogic.usdToTokenMin(params.collateralToken, marginFees);
fs.feeReserves[params.collateralToken] = fs.feeReserves[params.collateralToken] + feeTokens;
emit CollectMarginFees(params.collateralToken, marginFees, feeTokens);
}
GenericLogic.decreaseReservedAmount(params.collateralToken, position.reserveAmount);
emit LiquidatePosition(
key,
params.account,
params.collateralToken,
params.indexToken,
params.isLong,
position.size,
position.collateral,
position.reserveAmount,
position.realisedPnl,
markPrice
);
if (marginFees < position.collateral) {
uint256 remainingCollateral = position.collateral - marginFees;
uint256 amount = GenericLogic.usdToTokenMin(params.collateralToken, remainingCollateral);
GenericLogic.increasePoolAmount(params.collateralToken, amount);
}
if (params.isLong) {
ps.globalLongAveragePrices[params.indexToken] = getNextGlobalLongData(
params.account, params.collateralToken, params.indexToken, markPrice, position.size, false
);
GenericLogic.decreaseGlobalLongSize(params.indexToken, position.size);
} else {
ps.globalShortAveragePrices[params.indexToken] = getNextGlobalShortData(
params.account, params.collateralToken, params.indexToken, markPrice, position.size, false
);
GenericLogic.decreaseGlobalShortSize(params.indexToken, position.size);
}
delete ps.positions[key];
// pay the fee receiver using the pool, we assume that in general the liquidated amount should be sufficient to cover
// the liquidation fees
GenericLogic.decreasePoolAmount(
params.collateralToken, GenericLogic.usdToTokenMin(params.collateralToken, fs.liquidationFeeUsd), true
);
GenericLogic.transferOut(
params.collateralToken,
GenericLogic.usdToTokenMin(params.collateralToken, fs.liquidationFeeUsd),
params.feeReceiver
);
}
function getPositionKey(address _account, address _collateralToken, address _indexToken, bool _isLong)
internal
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(_account, _collateralToken, _indexToken, _isLong));
}
// for longs has position profit: nextAveragePrice = (nextPrice * nextSize)/ (nextSize + delta)
// for longs has negative profit: nextAveragePrice = (nextPrice * nextSize)/ (nextSize - delta)
// for shorts has position profit: nextAveragePrice = (nextPrice * nextSize) / (nextSize - delta)
// for shorts has negative profit: nextAveragePrice = (nextPrice * nextSize) / (nextSize + delta)
function getNextAveragePrice(
address _indexToken,
uint256 _size,
uint256 _averagePrice,
bool _isLong,
uint256 _nextPrice,
uint256 _sizeDelta
) internal view returns (uint256) {
(bool hasProfit, uint256 delta) = getDelta(_indexToken, _size, _averagePrice, _isLong);
uint256 nextSize = _size + _sizeDelta;
uint256 divisor;
if (_isLong) {
divisor = hasProfit ? nextSize + delta : nextSize - delta;
} else {
divisor = hasProfit ? nextSize - delta : nextSize + delta;
}
return (_nextPrice * nextSize) / divisor;
}
function getDelta(address _indexToken, uint256 _size, uint256 _averagePrice, bool _isLong)
internal
view
returns (bool, uint256)
{
ValidationLogic.validate(_averagePrice > 0, Errors.VAULT_INVALID_AVERAGE_PRICE);
uint256 price = _isLong ? GenericLogic.getMinPrice(_indexToken) : GenericLogic.getMaxPrice(_indexToken);
uint256 priceDelta = _averagePrice > price ? _averagePrice - price : price - _averagePrice;
uint256 delta = (_size * priceDelta) / _averagePrice;
bool hasProfit;
if (_isLong) {
hasProfit = price > _averagePrice;
} else {
hasProfit = _averagePrice > price;
}
return (hasProfit, delta);
}
function collectMarginFees(CollectMarginFeesParams memory params)
internal
returns (uint256, DataTypes.PositionFundingFees memory)
{
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
uint256 feeUsd = getPositionFee(params.sizeDelta);
uint256 borrowingFee = BorrowingFeeLogic.getBorrowingFee(
params.account,
params.collateralToken,
params.indexToken,
params.isLong,
params.position.size,
params.position.entryBorrowingRate
);
// funding fee
DataTypes.PositionFundingFees memory positionFundingFees =
FundingFeeLogic.getFundingFees(params.indexToken, params.isLong, params.position);
feeUsd += borrowingFee + positionFundingFees.fundingFeeAmount;
uint256 feeUsdExcludingFunding = feeUsd - positionFundingFees.fundingFeeAmount;
uint256 feeTokensExcludingFunding = GenericLogic.usdToTokenMin(params.collateralToken, feeUsdExcludingFunding);
fs.feeReserves[params.collateralToken] = fs.feeReserves[params.collateralToken] + feeTokensExcludingFunding;
emit CollectMarginFees(params.collateralToken, feeUsd, feeTokensExcludingFunding);
return (feeUsd, positionFundingFees);
}
function getPositionFee(uint256 _sizeDelta) internal view returns (uint256) {
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
if (_sizeDelta == 0) {
return 0;
}
uint256 afterFeeUsd =
(_sizeDelta * (Constants.PERCENTAGE_FACTOR - fs.marginFeeBasisPoints)) / Constants.PERCENTAGE_FACTOR;
return _sizeDelta - afterFeeUsd;
}
// validateLiquidation returns (state, fees)
function validateLiquidation(
address _account,
address _collateralToken,
address _indexToken,
bool _isLong,
bool _raise
) internal view returns (uint256, uint256) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
bytes32 key = getPositionKey(_account, _collateralToken, _indexToken, _isLong);
DataTypes.Position storage position = ps.positions[key];
(bool hasProfit, uint256 delta) = getDelta(_indexToken, position.size, position.averagePrice, _isLong);
uint256 positionFee = getPositionFee(position.size);
uint256 borrowingFee = BorrowingFeeLogic.getBorrowingFee(
_account, _collateralToken, _indexToken, _isLong, position.size, position.entryBorrowingRate
);
DataTypes.PositionFundingFees memory positionFundingFees =
FundingFeeLogic.getFundingFees(_indexToken, _isLong, position);
uint256 marginFees = positionFee + borrowingFee + positionFundingFees.fundingFeeAmount;
if (!hasProfit && position.collateral < delta) {
if (_raise) {
revert("Vault: losses exceed collateral");
}
return (1, 0);
}
uint256 remainingCollateral = position.collateral;
if (!hasProfit) {
remainingCollateral = position.collateral - delta;
}
if (remainingCollateral < marginFees) {
if (_raise) {
revert("Vault: fees exceed collateral");
}
// cap the fees to the remainingCollateral
return (1, remainingCollateral);
}
if (remainingCollateral < marginFees + fs.liquidationFeeUsd) {
if (_raise) {
revert("Vault: liquidation fees exceed collateral");
}
return (1, marginFees);
}
if (remainingCollateral * ps.maxLeverage < position.size * Constants.PERCENTAGE_FACTOR) {
if (_raise) {
revert("Vault: maxLeverage exceeded");
}
return (2, marginFees);
}
return (0, marginFees);
}
function reduceCollateral(DataTypes.DecreasePositionParams memory params)
internal
returns (uint256, uint256, DataTypes.PositionFundingFees memory)
{
ReduceCollateralCache memory cache;
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
bytes32 key = getPositionKey(params.account, params.collateralToken, params.indexToken, params.isLong);
DataTypes.Position storage position = ps.positions[key];
(cache.fee, cache.fundingFees) = collectMarginFees(
CollectMarginFeesParams({
account: params.account,
collateralToken: params.collateralToken,
indexToken: params.indexToken,
isLong: params.isLong,
sizeDelta: params.sizeDelta,
position: position
})
);
(cache.hasProfit, cache.delta) =
getDelta(params.indexToken, position.size, position.averagePrice, params.isLong);
// get the proportional change in pnl
cache.adjustedDelta = (params.sizeDelta * cache.delta) / position.size;
// transfer profits out
if (cache.hasProfit && cache.adjustedDelta > 0) {
cache.usdOut = cache.adjustedDelta;
position.realisedPnl = position.realisedPnl + cache.adjustedDelta.toInt256();
// pay out realised profits from the pool amount for positions
uint256 tokenAmount = GenericLogic.usdToTokenMin(params.collateralToken, cache.adjustedDelta);
GenericLogic.decreasePoolAmount(params.collateralToken, tokenAmount, true);
}
if (!cache.hasProfit && cache.adjustedDelta > 0) {
position.collateral = position.collateral - cache.adjustedDelta;
uint256 tokenAmount = GenericLogic.usdToTokenMin(params.collateralToken, cache.adjustedDelta);
GenericLogic.increasePoolAmount(params.collateralToken, tokenAmount);
position.realisedPnl = position.realisedPnl - cache.adjustedDelta.toInt256();
}
// reduce the position's collateral by _collateralDelta
// transfer _collateralDelta out
if (params.collateralDelta > 0) {
cache.usdOut += params.collateralDelta;
position.collateral -= params.collateralDelta;
}
// if the position will be closed, then transfer the remaining collateral out
if (position.size == params.sizeDelta) {
cache.usdOut += position.collateral;
position.collateral = 0;
}
// if the usdOut is more than the fee then deduct the fee from the usdOut directly
// else deduct the fee from the position's collateral
cache.usdOutAfterFee = cache.usdOut;
if (cache.usdOut > cache.fee) {
cache.usdOutAfterFee = cache.usdOut - cache.fee;
} else {
position.collateral -= cache.fee;
}
emit UpdatePnl(key, cache.hasProfit, cache.adjustedDelta);
return (cache.usdOut, cache.usdOutAfterFee, cache.fundingFees);
}
function getPosition(address _account, address _collateralToken, address _indexToken, bool _isLong)
public
view
returns (DataTypes.Position memory)
{
bytes32 key = getPositionKey(_account, _collateralToken, _indexToken, _isLong);
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
return ps.positions[key];
}
function getNextGlobalLongData(
address _account,
address _collateralToken,
address _indexToken,
uint256 _nextPrice,
uint256 _sizeDelta,
bool _isIncrease
) internal view returns (uint256) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
int256 realisedPnl = getRealisedPnl(_account, _collateralToken, _indexToken, _sizeDelta, _isIncrease, true);
uint256 globalLongSize = ps.globalLongSizes[_indexToken];
uint256 averagePrice = ps.globalLongAveragePrices[_indexToken];
uint256 priceDelta = averagePrice > _nextPrice ? averagePrice - _nextPrice : _nextPrice - averagePrice;
uint256 nextSize;
uint256 delta;
// avoid stack to deep
{
nextSize = _isIncrease ? globalLongSize + _sizeDelta : globalLongSize - _sizeDelta;
if (nextSize == 0) {
return 0;
}
if (averagePrice == 0) {
return _nextPrice;
}
delta = (globalLongSize * priceDelta) / averagePrice;
}
uint256 nextAveragePrice =
getNextGlobalAveragePrice(averagePrice, _nextPrice, nextSize, delta, realisedPnl, true);
return nextAveragePrice;
}
function getNextGlobalShortData(
address _account,
address _collateralToken,
address _indexToken,
uint256 _nextPrice,
uint256 _sizeDelta,
bool _isIncrease
) internal view returns (uint256) {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
int256 realisedPnl = getRealisedPnl(_account, _collateralToken, _indexToken, _sizeDelta, _isIncrease, false);
uint256 globalShortSize = ps.globalShortSizes[_indexToken];
uint256 averagePrice = ps.globalShortAveragePrices[_indexToken];
uint256 priceDelta = averagePrice > _nextPrice ? averagePrice - _nextPrice : _nextPrice - averagePrice;
uint256 nextSize;
uint256 delta;
// avoid stack to deep
{
nextSize = _isIncrease ? globalShortSize + _sizeDelta : globalShortSize - _sizeDelta;
if (nextSize == 0) {
return 0;
}
if (averagePrice == 0) {
return _nextPrice;
}
delta = (globalShortSize * priceDelta) / averagePrice;
}
uint256 nextAveragePrice =
getNextGlobalAveragePrice(averagePrice, _nextPrice, nextSize, delta, realisedPnl, false);
return nextAveragePrice;
}
function getRealisedPnl(
address _account,
address _collateralToken,
address _indexToken,
uint256 _sizeDelta,
bool _isIncrease,
bool _isLong
) internal view returns (int256) {
if (_isIncrease) {
return 0;
}
DataTypes.Position memory position = getPosition(_account, _collateralToken, _indexToken, _isLong);
(bool hasProfit, uint256 delta) = getDelta(_indexToken, position.size, position.averagePrice, _isLong);
// get the proportional change in pnl
uint256 adjustedDelta = (_sizeDelta * delta) / position.size;
return hasProfit ? int256(adjustedDelta) : -int256(adjustedDelta);
}
function getNextGlobalAveragePrice(
uint256 _averagePrice,
uint256 _nextPrice,
uint256 _nextSize,
uint256 _delta,
int256 _realisedPnl,
bool _isLong
) internal pure returns (uint256) {
(bool hasProfit, uint256 nextDelta) = getNextDelta(_delta, _averagePrice, _nextPrice, _realisedPnl, _isLong);
uint256 divisor;
if (_isLong) {
divisor = hasProfit ? _nextSize + nextDelta : _nextSize - nextDelta;
} else {
divisor = hasProfit ? _nextSize - nextDelta : _nextSize + nextDelta;
}
return (_nextPrice * _nextSize) / divisor;
}
function getNextDelta(uint256 _delta, uint256 _averagePrice, uint256 _nextPrice, int256 _realisedPnl, bool _isLong)
internal
pure
returns (bool, uint256)
{
// global delta 10000, realised pnl 1000 => new pnl 9000
// global delta 10000, realised pnl -1000 => new pnl 11000
// global delta -10000, realised pnl 1000 => new pnl -11000
// global delta -10000, realised pnl -1000 => new pnl -9000
// global delta 10000, realised pnl 11000 => new pnl -1000 (flips sign)
// global delta -10000, realised pnl -11000 => new pnl 1000 (flips sign)
bool hasProfit;
if (_isLong) {
hasProfit = _nextPrice > _averagePrice;
} else {
hasProfit = _averagePrice > _nextPrice;
}
if (hasProfit) {
// global shorts pnl is positive
if (_realisedPnl > 0) {
if (uint256(_realisedPnl) > _delta) {
_delta = uint256(_realisedPnl) - _delta;
hasProfit = false;
} else {
_delta = _delta - uint256(_realisedPnl);
}
} else {
_delta = _delta + uint256(-_realisedPnl);
}
return (hasProfit, _delta);
}
if (_realisedPnl > 0) {
_delta = _delta + uint256(_realisedPnl);
} else {
if (uint256(-_realisedPnl) > _delta) {
_delta = uint256(-_realisedPnl) - _delta;
hasProfit = true;
} else {
_delta = _delta - uint256(-_realisedPnl);
}
}
return (hasProfit, _delta);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {DataTypes} from "../types/DataTypes.sol";
library StorageSlot {
bytes32 constant STORAGE_VAULT_ADDRESS = bytes32(uint256(keccak256("gemnify.vault.address.storage")) - 1);
bytes32 constant STORAGE_VAULT_TOKEN_CONFIG = bytes32(uint256(keccak256("gemnify.vault.token.config.storage")) - 1);
bytes32 constant STORAGE_VAULT_FEE = bytes32(uint256(keccak256("gemnify.vault.fee.storage")) - 1);
bytes32 constant STORAGE_VAULT_PERMISSION = bytes32(uint256(keccak256("gemnify.vault.permission.storage")) - 1);
bytes32 constant STORAGE_VAULT_POSITION = bytes32(uint256(keccak256("gemnify.vault.position.storage")) - 1);
function getVaultAddressStorage() internal pure returns (DataTypes.AddressStorage storage rs) {
bytes32 position = STORAGE_VAULT_ADDRESS;
assembly {
rs.slot := position
}
}
function getVaultTokenConfigStorage() internal pure returns (DataTypes.TokenConfigStorage storage rs) {
bytes32 position = STORAGE_VAULT_TOKEN_CONFIG;
assembly {
rs.slot := position
}
}
function getVaultFeeStorage() internal pure returns (DataTypes.FeeStorage storage rs) {
bytes32 position = STORAGE_VAULT_FEE;
assembly {
rs.slot := position
}
}
function getVaultPermissionStorage() internal pure returns (DataTypes.PermissionStorage storage rs) {
bytes32 position = STORAGE_VAULT_PERMISSION;
assembly {
rs.slot := position
}
}
function getVaultPositionStorage() internal pure returns (DataTypes.PositionStorage storage rs) {
bytes32 position = STORAGE_VAULT_POSITION;
assembly {
rs.slot := position
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {ValidationLogic} from "./ValidationLogic.sol";
import {GenericLogic} from "./GenericLogic.sol";
import {BorrowingFeeLogic} from "./BorrowingFeeLogic.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {Errors} from "../helpers/Errors.sol";
import {Constants} from "../helpers/Constants.sol";
import {DataTypes} from "../types/DataTypes.sol";
import {IUSDG} from "../../../tokens/interfaces/IUSDG.sol";
import {IVault} from "../../interfaces/IVault.sol";
library SupplyLogic {
using SafeCast for uint256;
using SafeCast for int256;
event DirectPoolDeposit(address token, uint256 amount);
event BuyUSDG(address account, address token, uint256 tokenAmount, uint256 usdgAmount, int256 feeBasisPoints);
event SellUSDG(address account, address token, uint256 usdgAmount, uint256 tokenAmount, uint256 feeBasisPoints);
function ExecuteBuyUSDG(address _token, address _receiver) external returns (uint256) {
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
ValidationLogic.validateManager();
ValidationLogic.validateWhitelistedToken(_token);
uint256 tokenAmount;
tokenAmount = GenericLogic.transferIn(_token);
ValidationLogic.validate(tokenAmount > 0, Errors.VAULT_INVALID_TOKEN_AMOUNT);
BorrowingFeeLogic.updateCumulativeBorrowingRate(addrs.collateralToken, addrs.collateralToken);
uint256 price = GenericLogic.getMinPrice(_token);
uint256 usdgAmount = (tokenAmount * price) / Constants.PRICE_PRECISION;
usdgAmount = GenericLogic.adjustForDecimals(usdgAmount, _token, addrs.usdg);
ValidationLogic.validate(usdgAmount > 0, Errors.VAULT_INVALID_USDG_AMOUNT);
int256 feeBasisPoints = GenericLogic.getBuyUsdgFeeBasisPoints(_token, usdgAmount);
uint256 amountAfterFees = GenericLogic.collectSwapFees(_token, tokenAmount, feeBasisPoints);
uint256 mintAmount = (amountAfterFees * price) / Constants.PRICE_PRECISION;
mintAmount = GenericLogic.adjustForDecimals(mintAmount, _token, addrs.usdg);
if (amountAfterFees > tokenAmount) {
GenericLogic.increaseUsdgAmount(_token, usdgAmount);
GenericLogic.increasePoolAmount(_token, tokenAmount);
IUSDG(addrs.usdg).mint(_receiver, usdgAmount);
} else {
GenericLogic.increaseUsdgAmount(_token, mintAmount);
GenericLogic.increasePoolAmount(_token, amountAfterFees);
IUSDG(addrs.usdg).mint(_receiver, mintAmount);
}
emit BuyUSDG(_receiver, _token, tokenAmount, mintAmount, feeBasisPoints);
return mintAmount;
}
function ExecuteSellUSDG(address _token, address _receiver) external returns (uint256) {
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
ValidationLogic.validateManager();
ValidationLogic.validateWhitelistedToken(_token);
uint256 usdgAmount = GenericLogic.transferIn(addrs.usdg);
ValidationLogic.validate(usdgAmount > 0, Errors.VAULT_INVALID_USDG_AMOUNT);
BorrowingFeeLogic.updateCumulativeBorrowingRate(addrs.collateralToken, addrs.collateralToken);
uint256 redemptionAmount = GenericLogic.getRedemptionAmount(_token, usdgAmount);
ValidationLogic.validate(redemptionAmount > 0, Errors.VAULT_INVALID_REDEMPTION_AMOUNT);
uint256 feeBasisPoints = GenericLogic.getSellUsdgFeeBasisPoints(_token, usdgAmount);
GenericLogic.decreaseUsdgAmount(_token, usdgAmount);
GenericLogic.decreasePoolAmount(_token, redemptionAmount, false);
IUSDG(addrs.usdg).burn(address(this), usdgAmount);
// the _transferIn call increased the value of tokenBalances[usdg]
// usually decreases in token balances are synced by calling _transferOut
// however, for usdg, the tokens are burnt, so _updateTokenBalance should
// be manually called to record the decrease in tokens
GenericLogic.updateTokenBalance(addrs.usdg);
uint256 amountOut = GenericLogic.collectSwapFees(_token, redemptionAmount, feeBasisPoints.toInt256());
ValidationLogic.validate(amountOut > 0, Errors.VAULT_INVALID_AMOUNT_OUT);
GenericLogic.transferOut(_token, amountOut, _receiver);
emit SellUSDG(_receiver, _token, usdgAmount, amountOut, feeBasisPoints);
return amountOut;
}
function directPoolDeposit(address _token) external {
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
ValidationLogic.validate(ts.whitelistedTokens[_token], Errors.VAULT_TOKEN_NOT_WHITELISTED);
BorrowingFeeLogic.updateCumulativeBorrowingRate(addrs.collateralToken, addrs.collateralToken);
uint256 tokenAmount = GenericLogic.transferIn(_token);
ValidationLogic.validate(tokenAmount > 0, Errors.VAULT_INVALID_TOKEN_AMOUNT);
GenericLogic.increasePoolAmount(_token, tokenAmount);
emit DirectPoolDeposit(_token, tokenAmount);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {BorrowingFeeLogic} from "./BorrowingFeeLogic.sol";
import {ValidationLogic} from "./ValidationLogic.sol";
import {GenericLogic} from "./GenericLogic.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {DataTypes} from "../types/DataTypes.sol";
import {Constants} from "../helpers/Constants.sol";
import {Errors} from "../helpers/Errors.sol";
library SwapLogic {
using SafeCast for uint256;
using SafeCast for int256;
event Swap(
address indexed account,
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOut,
uint256 amountOutAfterFees,
int256 feeBasisPoints
);
function ExecuteSwap(address _tokenIn, address _tokenOut, uint256 _amountIn, address _receiver)
external
returns (uint256)
{
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
ValidationLogic.validateSwapParams(ps.isSwapEnabled, _tokenIn, _tokenOut, _amountIn, ts.whitelistedTokens);
BorrowingFeeLogic.updateCumulativeBorrowingRate(addrs.collateralToken, addrs.collateralToken);
uint256 priceInMin = GenericLogic.getMinPrice(_tokenIn);
uint256 priceOutMax = GenericLogic.getMaxPrice(_tokenOut);
// adjust usdgAmounts by the same usdgAmount as debt is shifted between the assets
uint256 usdgAmount = (_amountIn * priceInMin) / Constants.PRICE_PRECISION;
usdgAmount = GenericLogic.adjustForDecimals(usdgAmount, _tokenIn, addrs.usdg);
uint256 amountOut = (_amountIn * priceInMin) / priceOutMax;
amountOut = GenericLogic.adjustForDecimals(amountOut, _tokenIn, _tokenOut);
int256 feeBasisPoints = getSwapFeeBasisPoints(_tokenIn, _tokenOut, usdgAmount);
uint256 amountOutAfterFees = GenericLogic.collectSwapFees(_tokenOut, amountOut, feeBasisPoints);
GenericLogic.increaseUsdgAmount(_tokenIn, usdgAmount);
GenericLogic.increasePoolAmount(_tokenIn, _amountIn);
GenericLogic.decreaseUsdgAmount(_tokenOut, usdgAmount);
if (amountOutAfterFees > amountOut) {
GenericLogic.decreasePoolAmount(_tokenOut, amountOutAfterFees, false);
} else {
GenericLogic.decreasePoolAmount(_tokenOut, amountOut, false);
}
ValidationLogic.validateBufferAmount(_tokenOut);
GenericLogic.transferOut(_tokenOut, amountOutAfterFees, _receiver);
emit Swap(_receiver, _tokenIn, _tokenOut, _amountIn, amountOut, amountOutAfterFees, feeBasisPoints);
return amountOutAfterFees;
}
function getSwapFeeBasisPoints(address _tokenIn, address _tokenOut, uint256 _usdgAmount)
internal
view
returns (int256)
{
DataTypes.FeeStorage storage fs = StorageSlot.getVaultFeeStorage();
uint256 baseBps = fs.stableSwapFeeBasisPoints;
uint256 taxBps = fs.stableTaxBasisPoints;
(uint256 feesBasisPoints0, bool haveBalanceReward0,) =
GenericLogic.getFeeBasisPoints(_tokenIn, _usdgAmount, baseBps, taxBps, true, true);
(uint256 feesBasisPoints1,, bool isCrossBalance1) =
GenericLogic.getFeeBasisPoints(_tokenOut, _usdgAmount, baseBps, taxBps, false, true);
// use the higher of the two fee basis points
uint256 fee = feesBasisPoints0 > feesBasisPoints1 ? feesBasisPoints0 : feesBasisPoints1;
if (haveBalanceReward0 && !isCrossBalance1) {
return fee.toInt256() - fs.balanceReward.toInt256();
} else {
return fee.toInt256();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Errors} from "../helpers/Errors.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {DataTypes} from "../types/DataTypes.sol";
library ValidationLogic {
function validateSwapParams(
bool _isSwapEnabled,
address _tokenIn,
address _tokenOut,
uint256 _amountIn,
mapping(address => bool) storage whitelistedTokens
) internal view {
validate(_isSwapEnabled, Errors.VAULT_SWAPS_NOT_ENABLED);
validate(whitelistedTokens[_tokenIn], Errors.VAULT_TOKEN_IN_NOT_WHITELISTED);
validate(whitelistedTokens[_tokenOut], Errors.VAULT_TOKEN_OUT_NOT_WHITELISTED);
validate(_tokenIn != _tokenOut, Errors.VAULT_INVALID_TOKENS);
validate(_amountIn > 0, Errors.VAULT_INVALID_AMOUNT_IN);
}
function validateIncreasePositionParams(
bool _isLeverageEnabled,
address _account,
address _collateralToken,
address _indexToken,
bool _isLong
) internal view {
validateLeverage(_isLeverageEnabled);
validateGasPrice();
validateRouter(_account);
validateTokens(_collateralToken, _indexToken, _isLong);
}
function validateDecreasePositionParams(address _account) internal view {
validateGasPrice();
validateRouter(_account);
}
function validateGasPrice() internal view {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
if (ps.maxGasPrice == 0) {
return;
}
validate(tx.gasprice <= ps.maxGasPrice, Errors.VAULT_MAX_GAS_PRICE_EXCEEDED);
}
function validateWhitelistedToken(address _token) internal view {
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
validate(ts.whitelistedTokens[_token], Errors.VAULT_TOKEN_IN_NOT_WHITELISTED);
}
function validateBufferAmount(address _token) internal view {
DataTypes.PositionStorage storage ps = StorageSlot.getVaultPositionStorage();
validate(ps.poolAmounts[_token] >= ps.bufferAmounts[_token], Errors.VAULT_POOL_AMOUNT_LESS_THAN_BUFFER_AMOUNT);
}
function validateManager() internal view {
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
if (ps.inManagerMode) {
validate(ps.isManager[msg.sender], Errors.VAULT_FORBIDDEN);
}
}
function validateTokens(address _collateralToken, address _indexToken, bool _isLong) internal view {
DataTypes.TokenConfigStorage storage ts = StorageSlot.getVaultTokenConfigStorage();
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
validate(_collateralToken == addrs.collateralToken, Errors.VAULT_COLLATERAL_TOKEN_MUST_BE_STABLE_TOKEN);
validate(ts.whitelistedTokens[_collateralToken], Errors.VAULT_COLLATERAL_TOKEN_NOT_WHITELISTED);
validate(ts.whitelistedTokens[_indexToken], Errors.VAULT_INDEX_TOKEN_NOT_WHITELISTED);
validate(ts.stableTokens[_collateralToken], Errors.VAULT_COLLATERAL_TOKEN_MUST_BE_STABLE_TOKEN);
validate(!ts.stableTokens[_indexToken], Errors.VAULT_INDEX_TOKEN_MUST_NOT_BE_STABLE_TOKEN);
if (!_isLong) {
validate(ts.shortableTokens[_indexToken], Errors.VAULT_INDEX_TOKEN_NOT_SHORTABLE);
}
}
function validatePosition(uint256 _size, uint256 _collateral) internal pure {
if (_size == 0) {
validate(_collateral == 0, Errors.VAULT_COLLATERAL_SHOULD_BE_WITHDRAWN);
return;
}
validate(_size >= _collateral, Errors.VAULT_SIZE_MUST_BE_MORE_THAN_COLLATERAL);
}
function validateRouter(address _account) internal view {
DataTypes.AddressStorage storage addrs = StorageSlot.getVaultAddressStorage();
DataTypes.PermissionStorage storage ps = StorageSlot.getVaultPermissionStorage();
if (msg.sender == addrs.router) {
return;
}
validate(ps.approvedRouters[_account][msg.sender], Errors.VAULT_INVALID_MSG_SENDER);
}
function validateLeverage(bool _isLeverageEnabled) internal pure {
validate(_isLeverageEnabled, Errors.VAULT_LEVERAGE_NOT_ENABLED);
}
function validateIncreasePosition(
address, /* _account */
address, /* _collateralToken */
address, /* _indexToken */
uint256, /* _sizeDelta */
bool /* _isLong */
) internal pure {
// no additional validations
}
function validateDecreasePosition(
address, /* _account */
address, /* _collateralToken */
address, /* _indexToken */
uint256, /* _collateralDelta */
uint256, /* _sizeDelta */
bool, /* _isLong */
address /* _receiver */
) internal pure {
// no additional validations
}
function validate(bool _condition, string memory _errorCode) internal pure {
require(_condition, _errorCode);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/math/SignedMath.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
/**
* @title Calc
* @dev Library for math functions
*/
library Calc {
using SignedMath for int256;
using SafeCast for uint256;
// this method assumes that min is less than max
function boundMagnitude(int256 value, uint256 min, uint256 max) internal pure returns (int256) {
uint256 magnitude = value.abs();
if (magnitude < min) {
magnitude = min;
}
if (magnitude > max) {
magnitude = max;
}
int256 sign = value == 0 ? int256(1) : value / value.abs().toInt256();
return magnitude.toInt256() * sign;
}
/**
* @dev Calculates the result of dividing the first number by the second number,
* rounded up to the nearest integer.
*
* @param a the dividend
* @param b the divisor
* @return the result of dividing the first number by the second number, rounded up to the nearest integer
*/
function roundUpDivision(uint256 a, uint256 b) internal pure returns (uint256) {
return (a + b - 1) / b;
}
/**
* Calculates the result of dividing the first number by the second number,
* rounded up to the nearest integer.
* The rounding is purely on the magnitude of a, if a is negative the result
* is a larger magnitude negative
*
* @param a the dividend
* @param b the divisor
* @return the result of dividing the first number by the second number, rounded up to the nearest integer
*/
function roundUpMagnitudeDivision(int256 a, uint256 b) internal pure returns (int256) {
if (a < 0) {
return (a - b.toInt256() + 1) / b.toInt256();
}
return (a + b.toInt256() - 1) / b.toInt256();
}
/**
* Adds two numbers together and return a uint256 value, treating the second number as a signed integer.
*
* @param a the first number
* @param b the second number
* @return the result of adding the two numbers together
*/
function sumReturnUint256(uint256 a, int256 b) internal pure returns (uint256) {
if (b > 0) {
return a + b.abs();
}
return a - b.abs();
}
/**
* Adds two numbers together and return an int256 value, treating the second number as a signed integer.
*
* @param a the first number
* @param b the second number
* @return the result of adding the two numbers together
*/
function sumReturnInt256(uint256 a, int256 b) internal pure returns (int256) {
return a.toInt256() + b;
}
/**
* @dev Calculates the absolute difference between two numbers.
*
* @param a the first number
* @param b the second number
* @return the absolute difference between the two numbers
*/
function diff(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a - b : b - a;
}
/**
* Adds two numbers together, the result is bounded to prevent overflows.
*
* @param a the first number
* @param b the second number
* @return the result of adding the two numbers together
*/
function boundedAdd(int256 a, int256 b) internal pure returns (int256) {
// if either a or b is zero or if the signs are different there should not be any overflows
if (a == 0 || b == 0 || (a < 0 && b > 0) || (a > 0 && b < 0)) {
return a + b;
}
// if adding `b` to `a` would result in a value less than the min int256 value
// then return the min int256 value
if (a < 0 && b <= type(int256).min - a) {
return type(int256).min;
}
// if adding `b` to `a` would result in a value more than the max int256 value
// then return the max int256 value
if (a > 0 && b >= type(int256).max - a) {
return type(int256).max;
}
return a + b;
}
/**
* Returns a - b, the result is bounded to prevent overflows.
* Note that this will revert if b is type(int256).min because of the usage of "-b".
*
* @param a the first number
* @param b the second number
* @return the bounded result of a - b
*/
function boundedSub(int256 a, int256 b) internal pure returns (int256) {
// if either a or b is zero or the signs are the same there should not be any overflow
if (a == 0 || b == 0 || (a > 0 && b > 0) || (a < 0 && b < 0)) {
return a - b;
}
// if adding `-b` to `a` would result in a value greater than the max int256 value
// then return the max int256 value
if (a > 0 && -b >= type(int256).max - a) {
return type(int256).max;
}
// if subtracting `b` from `a` would result in a value less than the min int256 value
// then return the min int256 value
if (a < 0 && -b <= type(int256).min - a) {
return type(int256).min;
}
return a - b;
}
/**
* Converts the given unsigned integer to a signed integer, using the given
* flag to determine whether the result should be positive or negative.
*
* @param a the unsigned integer to convert
* @param isPositive whether the result should be positive (if true) or negative (if false)
* @return the signed integer representation of the given unsigned integer
*/
function toSigned(uint256 a, bool isPositive) internal pure returns (int256) {
if (isPositive) {
return a.toInt256();
} else {
return -a.toInt256();
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
// there is a known issue with prb-math v3.x releases
// https://github.com/PaulRBerg/prb-math/issues/178
// due to this, either prb-math v2.x or v4.x versions should be used instead
import "prb-math/contracts/PRBMathUD60x18.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/math/SignedMath.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "./Calc.sol";
/**
* @title Precision
* @dev Library for precision values and conversions
*/
library Precision {
using SafeCast for uint256;
using SignedMath for int256;
uint256 public constant FLOAT_PRECISION = 10 ** 30;
uint256 public constant FLOAT_PRECISION_SQRT = 10 ** 15;
uint256 public constant WEI_PRECISION = 10 ** 18;
uint256 public constant BASIS_POINTS_DIVISOR = 10000;
uint256 public constant FLOAT_TO_WEI_DIVISOR = 10 ** 12;
/**
* Applies the given factor to the given value and returns the result.
*
* @param value The value to apply the factor to.
* @param factor The factor to apply.
* @return The result of applying the factor to the value.
*/
function applyFactor(uint256 value, uint256 factor) internal pure returns (uint256) {
return mulDiv(value, factor, FLOAT_PRECISION);
}
/**
* Applies the given factor to the given value and returns the result.
*
* @param value The value to apply the factor to.
* @param factor The factor to apply.
* @return The result of applying the factor to the value.
*/
function applyFactor(uint256 value, int256 factor) internal pure returns (int256) {
return mulDiv(value, factor, FLOAT_PRECISION);
}
function applyFactor(uint256 value, int256 factor, bool roundUpMagnitude) internal pure returns (int256) {
return mulDiv(value, factor, FLOAT_PRECISION, roundUpMagnitude);
}
function mulDiv(uint256 value, uint256 numerator, uint256 denominator) internal pure returns (uint256) {
return Math.mulDiv(value, numerator, denominator);
}
function mulDiv(int256 value, uint256 numerator, uint256 denominator) internal pure returns (int256) {
return mulDiv(numerator, value, denominator);
}
function mulDiv(uint256 value, int256 numerator, uint256 denominator) internal pure returns (int256) {
uint256 result = mulDiv(value, numerator.abs(), denominator);
return numerator > 0 ? result.toInt256() : -result.toInt256();
}
function mulDiv(uint256 value, int256 numerator, uint256 denominator, bool roundUpMagnitude)
internal
pure
returns (int256)
{
uint256 result = mulDiv(value, numerator.abs(), denominator, roundUpMagnitude);
return numerator > 0 ? result.toInt256() : -result.toInt256();
}
function mulDiv(uint256 value, uint256 numerator, uint256 denominator, bool roundUpMagnitude)
internal
pure
returns (uint256)
{
if (roundUpMagnitude) {
return Math.mulDiv(value, numerator, denominator, Math.Rounding.Up);
}
return Math.mulDiv(value, numerator, denominator);
}
function applyExponentFactor(uint256 floatValue, uint256 exponentFactor) internal pure returns (uint256) {
// `PRBMathUD60x18.pow` doesn't work for `x` less than one
if (floatValue < FLOAT_PRECISION) {
return 0;
}
if (exponentFactor == FLOAT_PRECISION) {
return floatValue;
}
// `PRBMathUD60x18.pow` accepts 2 fixed point numbers 60x18
// we need to convert float (30 decimals) to 60x18 (18 decimals) and then back to 30 decimals
uint256 weiValue = PRBMathUD60x18.pow(floatToWei(floatValue), floatToWei(exponentFactor));
return weiToFloat(weiValue);
}
function toFactor(uint256 value, uint256 divisor, bool roundUpMagnitude) internal pure returns (uint256) {
if (value == 0) return 0;
if (roundUpMagnitude) {
return Math.mulDiv(value, FLOAT_PRECISION, divisor, Math.Rounding.Up);
}
return Math.mulDiv(value, FLOAT_PRECISION, divisor);
}
function toFactor(uint256 value, uint256 divisor) internal pure returns (uint256) {
return toFactor(value, divisor, false);
}
function toFactor(int256 value, uint256 divisor) internal pure returns (int256) {
uint256 result = toFactor(value.abs(), divisor);
return value > 0 ? result.toInt256() : -result.toInt256();
}
/**
* Converts the given value from float to wei.
*
* @param value The value to convert.
* @return The converted value in wei.
*/
function floatToWei(uint256 value) internal pure returns (uint256) {
return value / FLOAT_TO_WEI_DIVISOR;
}
/**
* Converts the given value from wei to float.
*
* @param value The value to convert.
* @return The converted value in float.
*/
function weiToFloat(uint256 value) internal pure returns (uint256) {
return value * FLOAT_TO_WEI_DIVISOR;
}
/**
* Converts the given number of basis points to float.
*
* @param basisPoints The number of basis points to convert.
* @return The converted value in float.
*/
function basisPointsToFloat(uint256 basisPoints) internal pure returns (uint256) {
return basisPoints * FLOAT_PRECISION / BASIS_POINTS_DIVISOR;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
library DataTypes {
struct Position {
uint256 size;
uint256 collateral;
uint256 averagePrice;
uint256 entryBorrowingRate;
uint256 fundingFeeAmountPerSize;
uint256 claimableFundingAmountPerSize;
uint256 reserveAmount;
int256 realisedPnl;
uint256 lastIncreasedTime;
}
struct SetFeesParams {
uint256 taxBasisPoints;
uint256 stableTaxBasisPoints;
uint256 mintBurnFeeBasisPoints;
uint256 swapFeeBasisPoints;
uint256 stableSwapFeeBasisPoints;
uint256 marginFeeBasisPoints;
uint256 liquidationFeeUsd;
bool hasDynamicFees;
uint256 balanceReward;
}
struct SwapParams {
bool isSwapEnabled;
address tokenIn;
address tokenOut;
address receiver;
bool isStableSwap;
address usdg;
address priceFeed;
uint256 totalTokenWeights;
}
struct IncreasePositionParams {
address account;
address collateralToken;
address indexToken;
uint256 sizeDelta;
bool isLong;
}
struct DecreasePositionParams {
address account;
address collateralToken;
address indexToken;
uint256 collateralDelta;
uint256 sizeDelta;
bool isLong;
address receiver;
}
struct LiquidatePositionParams {
address account;
address collateralToken;
address indexToken;
bool isLong;
address feeReceiver;
}
struct SetTokenConfigParams {
address token;
uint256 tokenDecimals;
uint256 tokenWeight;
uint256 maxUsdgAmount;
bool isStable;
bool isShortable;
}
// vault storage
struct AddressStorage {
address weth;
address router;
address ulpManager;
address priceFeed;
address usdg;
address collateralToken;
address feesReceiver;
}
struct TokenConfigStorage {
uint256 whitelistedTokenCount;
uint256 totalTokenWeights;
address[] allWhitelistedTokens;
mapping(address => bool) whitelistedTokens;
mapping(address => uint256) tokenDecimals;
mapping(address => uint256) tokenWeights;
mapping(address => uint256) maxUsdgAmounts;
mapping(address => bool) stableTokens;
mapping(address => bool) shortableTokens;
}
struct FeeStorage {
uint256 taxBasisPoints;
uint256 stableTaxBasisPoints;
uint256 mintBurnFeeBasisPoints;
uint256 swapFeeBasisPoints;
uint256 stableSwapFeeBasisPoints;
uint256 marginFeeBasisPoints;
uint256 liquidationFeeUsd;
bool hasDynamicFees;
// encourage arbitrage when token ratios are imbalanced
uint256 balanceReward;
mapping(address => uint256) feeReserves;
// borrowing fee
uint256 borrowingInterval;
uint256 borrowingRateFactor;
uint256 stableBorrowingRateFactor;
mapping(address => uint256) cumulativeBorrowingRates;
mapping(address => uint256) lastBorrowingTimes;
// funding fee
mapping(address => uint256) fundingFactors;
mapping(address => uint256) fundingExponentFactors;
mapping(address => uint256) lastFundingTimes;
mapping(address => mapping(bool => uint256)) fundingFeeAmountPerSizes; // indexToken -> isLong -> fundingFeeAmountPerSize
mapping(address => mapping(bool => uint256)) claimableFundingAmountPerSizes; // indexToken -> isLong -> claimableFundingAmountPerSize
mapping(address => uint256) claimableFundingAmount; // user's account -> claimableFundingAmount,funding amount always collateralToken
}
struct PermissionStorage {
bool isSwapEnabled;
bool isLeverageEnabled;
bool inManagerMode;
bool inPrivateLiquidationMode;
mapping(address => mapping(address => bool)) approvedRouters;
mapping(address => bool) isLiquidator;
mapping(address => bool) isManager;
mapping(address => bool) isTokenPaused;
mapping(address => bool) isWithdrawFeesAdmin;
}
struct PositionStorage {
uint256 maxLeverage; // 1000x
uint256 maxGasPrice;
// reserveRatio can increase OI limit.
uint256 reserveRatio;
mapping(address => uint256) tokenBalances;
mapping(address => uint256) usdgAmounts;
mapping(address => uint256) poolAmounts;
mapping(address => uint256) reservedAmounts;
mapping(address => uint256) bufferAmounts;
mapping(bytes32 => Position) positions;
mapping(address => uint256) globalLongSizes;
mapping(address => uint256) globalLongAveragePrices;
mapping(address => uint256) maxGlobalLongSizes;
mapping(address => uint256) globalShortSizes;
mapping(address => uint256) globalShortAveragePrices;
mapping(address => uint256) maxGlobalShortSizes;
}
// tokenInfo
struct TokenInfo {
uint256 tokenDecimal;
bool isWhitelistedToken;
bool isStableToken;
uint256 maxUsdgAmount;
}
// poolInfo
struct PoolInfo {
uint256 poolAmount;
uint256 reservedAmount;
uint256 bufferAmount;
uint256 globalLongSize;
uint256 globalLongAveragePrice;
uint256 globalShortSize;
uint256 globalShortAveragePrice;
uint256 usdgAmount;
}
// funding fee
// @param fundingFeeAmount the position's funding fee amount
// @param claimableAmount the negative funding fee that is claimable
// @param latestFundingAmountPerSize the latest funding
// amount per size for the market
struct PositionFundingFees {
uint256 fundingFeeAmount;
uint256 claimableAmount;
uint256 latestFundingFeeAmountPerSize;
uint256 latestClaimableFundingAmountPerSize;
}
// Global Data for long and short position
struct GlobalData {
uint256 maxGlobalLongSize;
uint256 globalLongSize;
uint256 globalLongAveragePrice;
uint256 maxGlobalShortSize;
uint256 globalShortSize;
uint256 globalShortAveragePrice;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IUSDG {
function addVault(address _vault) external;
function removeVault(address _vault) external;
function mint(address _account, uint256 _amount) external;
function burn(address _account, uint256 _amount) external;
}// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.4;
/// @notice Emitted when the result overflows uint256.
error PRBMath__MulDivFixedPointOverflow(uint256 prod1);
/// @notice Emitted when the result overflows uint256.
error PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);
/// @notice Emitted when one of the inputs is type(int256).min.
error PRBMath__MulDivSignedInputTooSmall();
/// @notice Emitted when the intermediary absolute result overflows int256.
error PRBMath__MulDivSignedOverflow(uint256 rAbs);
/// @notice Emitted when the input is MIN_SD59x18.
error PRBMathSD59x18__AbsInputTooSmall();
/// @notice Emitted when ceiling a number overflows SD59x18.
error PRBMathSD59x18__CeilOverflow(int256 x);
/// @notice Emitted when one of the inputs is MIN_SD59x18.
error PRBMathSD59x18__DivInputTooSmall();
/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.
error PRBMathSD59x18__DivOverflow(uint256 rAbs);
/// @notice Emitted when the input is greater than 133.084258667509499441.
error PRBMathSD59x18__ExpInputTooBig(int256 x);
/// @notice Emitted when the input is greater than 192.
error PRBMathSD59x18__Exp2InputTooBig(int256 x);
/// @notice Emitted when flooring a number underflows SD59x18.
error PRBMathSD59x18__FloorUnderflow(int256 x);
/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.
error PRBMathSD59x18__FromIntOverflow(int256 x);
/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.
error PRBMathSD59x18__FromIntUnderflow(int256 x);
/// @notice Emitted when the product of the inputs is negative.
error PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);
/// @notice Emitted when multiplying the inputs overflows SD59x18.
error PRBMathSD59x18__GmOverflow(int256 x, int256 y);
/// @notice Emitted when the input is less than or equal to zero.
error PRBMathSD59x18__LogInputTooSmall(int256 x);
/// @notice Emitted when one of the inputs is MIN_SD59x18.
error PRBMathSD59x18__MulInputTooSmall();
/// @notice Emitted when the intermediary absolute result overflows SD59x18.
error PRBMathSD59x18__MulOverflow(uint256 rAbs);
/// @notice Emitted when the intermediary absolute result overflows SD59x18.
error PRBMathSD59x18__PowuOverflow(uint256 rAbs);
/// @notice Emitted when the input is negative.
error PRBMathSD59x18__SqrtNegativeInput(int256 x);
/// @notice Emitted when the calculating the square root overflows SD59x18.
error PRBMathSD59x18__SqrtOverflow(int256 x);
/// @notice Emitted when addition overflows UD60x18.
error PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);
/// @notice Emitted when ceiling a number overflows UD60x18.
error PRBMathUD60x18__CeilOverflow(uint256 x);
/// @notice Emitted when the input is greater than 133.084258667509499441.
error PRBMathUD60x18__ExpInputTooBig(uint256 x);
/// @notice Emitted when the input is greater than 192.
error PRBMathUD60x18__Exp2InputTooBig(uint256 x);
/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.
error PRBMathUD60x18__FromUintOverflow(uint256 x);
/// @notice Emitted when multiplying the inputs overflows UD60x18.
error PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);
/// @notice Emitted when the input is less than 1.
error PRBMathUD60x18__LogInputTooSmall(uint256 x);
/// @notice Emitted when the calculating the square root overflows UD60x18.
error PRBMathUD60x18__SqrtOverflow(uint256 x);
/// @notice Emitted when subtraction underflows UD60x18.
error PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);
/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library
/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point
/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.
library PRBMath {
/// STRUCTS ///
struct SD59x18 {
int256 value;
}
struct UD60x18 {
uint256 value;
}
/// STORAGE ///
/// @dev How many trailing decimals can be represented.
uint256 internal constant SCALE = 1e18;
/// @dev Largest power of two divisor of SCALE.
uint256 internal constant SCALE_LPOTD = 262144;
/// @dev SCALE inverted mod 2^256.
uint256 internal constant SCALE_INVERSE =
78156646155174841979727994598816262306175212592076161876661_508869554232690281;
/// FUNCTIONS ///
/// @notice Calculates the binary exponent of x using the binary fraction method.
/// @dev Has to use 192.64-bit fixed-point numbers.
/// See https://ethereum.stackexchange.com/a/96594/24693.
/// @param x The exponent as an unsigned 192.64-bit fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
function exp2(uint256 x) internal pure returns (uint256 result) {
unchecked {
// Start from 0.5 in the 192.64-bit fixed-point format.
result = 0x800000000000000000000000000000000000000000000000;
// Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows
// because the initial result is 2^191 and all magic factors are less than 2^65.
if (x & 0x8000000000000000 > 0) {
result = (result * 0x16A09E667F3BCC909) >> 64;
}
if (x & 0x4000000000000000 > 0) {
result = (result * 0x1306FE0A31B7152DF) >> 64;
}
if (x & 0x2000000000000000 > 0) {
result = (result * 0x1172B83C7D517ADCE) >> 64;
}
if (x & 0x1000000000000000 > 0) {
result = (result * 0x10B5586CF9890F62A) >> 64;
}
if (x & 0x800000000000000 > 0) {
result = (result * 0x1059B0D31585743AE) >> 64;
}
if (x & 0x400000000000000 > 0) {
result = (result * 0x102C9A3E778060EE7) >> 64;
}
if (x & 0x200000000000000 > 0) {
result = (result * 0x10163DA9FB33356D8) >> 64;
}
if (x & 0x100000000000000 > 0) {
result = (result * 0x100B1AFA5ABCBED61) >> 64;
}
if (x & 0x80000000000000 > 0) {
result = (result * 0x10058C86DA1C09EA2) >> 64;
}
if (x & 0x40000000000000 > 0) {
result = (result * 0x1002C605E2E8CEC50) >> 64;
}
if (x & 0x20000000000000 > 0) {
result = (result * 0x100162F3904051FA1) >> 64;
}
if (x & 0x10000000000000 > 0) {
result = (result * 0x1000B175EFFDC76BA) >> 64;
}
if (x & 0x8000000000000 > 0) {
result = (result * 0x100058BA01FB9F96D) >> 64;
}
if (x & 0x4000000000000 > 0) {
result = (result * 0x10002C5CC37DA9492) >> 64;
}
if (x & 0x2000000000000 > 0) {
result = (result * 0x1000162E525EE0547) >> 64;
}
if (x & 0x1000000000000 > 0) {
result = (result * 0x10000B17255775C04) >> 64;
}
if (x & 0x800000000000 > 0) {
result = (result * 0x1000058B91B5BC9AE) >> 64;
}
if (x & 0x400000000000 > 0) {
result = (result * 0x100002C5C89D5EC6D) >> 64;
}
if (x & 0x200000000000 > 0) {
result = (result * 0x10000162E43F4F831) >> 64;
}
if (x & 0x100000000000 > 0) {
result = (result * 0x100000B1721BCFC9A) >> 64;
}
if (x & 0x80000000000 > 0) {
result = (result * 0x10000058B90CF1E6E) >> 64;
}
if (x & 0x40000000000 > 0) {
result = (result * 0x1000002C5C863B73F) >> 64;
}
if (x & 0x20000000000 > 0) {
result = (result * 0x100000162E430E5A2) >> 64;
}
if (x & 0x10000000000 > 0) {
result = (result * 0x1000000B172183551) >> 64;
}
if (x & 0x8000000000 > 0) {
result = (result * 0x100000058B90C0B49) >> 64;
}
if (x & 0x4000000000 > 0) {
result = (result * 0x10000002C5C8601CC) >> 64;
}
if (x & 0x2000000000 > 0) {
result = (result * 0x1000000162E42FFF0) >> 64;
}
if (x & 0x1000000000 > 0) {
result = (result * 0x10000000B17217FBB) >> 64;
}
if (x & 0x800000000 > 0) {
result = (result * 0x1000000058B90BFCE) >> 64;
}
if (x & 0x400000000 > 0) {
result = (result * 0x100000002C5C85FE3) >> 64;
}
if (x & 0x200000000 > 0) {
result = (result * 0x10000000162E42FF1) >> 64;
}
if (x & 0x100000000 > 0) {
result = (result * 0x100000000B17217F8) >> 64;
}
if (x & 0x80000000 > 0) {
result = (result * 0x10000000058B90BFC) >> 64;
}
if (x & 0x40000000 > 0) {
result = (result * 0x1000000002C5C85FE) >> 64;
}
if (x & 0x20000000 > 0) {
result = (result * 0x100000000162E42FF) >> 64;
}
if (x & 0x10000000 > 0) {
result = (result * 0x1000000000B17217F) >> 64;
}
if (x & 0x8000000 > 0) {
result = (result * 0x100000000058B90C0) >> 64;
}
if (x & 0x4000000 > 0) {
result = (result * 0x10000000002C5C860) >> 64;
}
if (x & 0x2000000 > 0) {
result = (result * 0x1000000000162E430) >> 64;
}
if (x & 0x1000000 > 0) {
result = (result * 0x10000000000B17218) >> 64;
}
if (x & 0x800000 > 0) {
result = (result * 0x1000000000058B90C) >> 64;
}
if (x & 0x400000 > 0) {
result = (result * 0x100000000002C5C86) >> 64;
}
if (x & 0x200000 > 0) {
result = (result * 0x10000000000162E43) >> 64;
}
if (x & 0x100000 > 0) {
result = (result * 0x100000000000B1721) >> 64;
}
if (x & 0x80000 > 0) {
result = (result * 0x10000000000058B91) >> 64;
}
if (x & 0x40000 > 0) {
result = (result * 0x1000000000002C5C8) >> 64;
}
if (x & 0x20000 > 0) {
result = (result * 0x100000000000162E4) >> 64;
}
if (x & 0x10000 > 0) {
result = (result * 0x1000000000000B172) >> 64;
}
if (x & 0x8000 > 0) {
result = (result * 0x100000000000058B9) >> 64;
}
if (x & 0x4000 > 0) {
result = (result * 0x10000000000002C5D) >> 64;
}
if (x & 0x2000 > 0) {
result = (result * 0x1000000000000162E) >> 64;
}
if (x & 0x1000 > 0) {
result = (result * 0x10000000000000B17) >> 64;
}
if (x & 0x800 > 0) {
result = (result * 0x1000000000000058C) >> 64;
}
if (x & 0x400 > 0) {
result = (result * 0x100000000000002C6) >> 64;
}
if (x & 0x200 > 0) {
result = (result * 0x10000000000000163) >> 64;
}
if (x & 0x100 > 0) {
result = (result * 0x100000000000000B1) >> 64;
}
if (x & 0x80 > 0) {
result = (result * 0x10000000000000059) >> 64;
}
if (x & 0x40 > 0) {
result = (result * 0x1000000000000002C) >> 64;
}
if (x & 0x20 > 0) {
result = (result * 0x10000000000000016) >> 64;
}
if (x & 0x10 > 0) {
result = (result * 0x1000000000000000B) >> 64;
}
if (x & 0x8 > 0) {
result = (result * 0x10000000000000006) >> 64;
}
if (x & 0x4 > 0) {
result = (result * 0x10000000000000003) >> 64;
}
if (x & 0x2 > 0) {
result = (result * 0x10000000000000001) >> 64;
}
if (x & 0x1 > 0) {
result = (result * 0x10000000000000001) >> 64;
}
// We're doing two things at the same time:
//
// 1. Multiply the result by 2^n + 1, where "2^n" is the integer part and the one is added to account for
// the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191
// rather than 192.
// 2. Convert the result to the unsigned 60.18-decimal fixed-point format.
//
// This works because 2^(191-ip) = 2^ip / 2^191, where "ip" is the integer part "2^n".
result *= SCALE;
result >>= (191 - (x >> 64));
}
}
/// @notice Finds the zero-based index of the first one in the binary representation of x.
/// @dev See the note on msb in the "Find First Set" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set
/// @param x The uint256 number for which to find the index of the most significant bit.
/// @return msb The index of the most significant bit as an uint256.
function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {
if (x >= 2**128) {
x >>= 128;
msb += 128;
}
if (x >= 2**64) {
x >>= 64;
msb += 64;
}
if (x >= 2**32) {
x >>= 32;
msb += 32;
}
if (x >= 2**16) {
x >>= 16;
msb += 16;
}
if (x >= 2**8) {
x >>= 8;
msb += 8;
}
if (x >= 2**4) {
x >>= 4;
msb += 4;
}
if (x >= 2**2) {
x >>= 2;
msb += 2;
}
if (x >= 2**1) {
// No need to shift x any more.
msb += 1;
}
}
/// @notice Calculates floor(x*y÷denominator) with full precision.
///
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.
///
/// Requirements:
/// - The denominator cannot be zero.
/// - The result must fit within uint256.
///
/// Caveats:
/// - This function does not work with fixed-point numbers.
///
/// @param x The multiplicand as an uint256.
/// @param y The multiplier as an uint256.
/// @param denominator The divisor as an uint256.
/// @return result The result as an uint256.
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
// 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) {
unchecked {
result = prod0 / denominator;
}
return result;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (prod1 >= denominator) {
revert PRBMath__MulDivOverflow(prod1, denominator);
}
///////////////////////////////////////////////
// 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.
unchecked {
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 lpotdod = denominator & (~denominator + 1);
assembly {
// Divide denominator by lpotdod.
denominator := div(denominator, lpotdod)
// Divide [prod1 prod0] by lpotdod.
prod0 := div(prod0, lpotdod)
// Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.
lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * lpotdod;
// 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 floor(x*y÷1e18) with full precision.
///
/// @dev Variant of "mulDiv" with constant folding, i.e. in which the denominator is always 1e18. Before returning the
/// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of
/// being rounded to 1e-18. See "Listing 6" and text above it at https://accu.org/index.php/journals/1717.
///
/// Requirements:
/// - The result must fit within uint256.
///
/// Caveats:
/// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works.
/// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:
/// 1. x * y = type(uint256).max * SCALE
/// 2. (x * y) % SCALE >= SCALE / 2
///
/// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.
/// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 >= SCALE) {
revert PRBMath__MulDivFixedPointOverflow(prod1);
}
uint256 remainder;
uint256 roundUpUnit;
assembly {
remainder := mulmod(x, y, SCALE)
roundUpUnit := gt(remainder, 499999999999999999)
}
if (prod1 == 0) {
unchecked {
result = (prod0 / SCALE) + roundUpUnit;
return result;
}
}
assembly {
result := add(
mul(
or(
div(sub(prod0, remainder), SCALE_LPOTD),
mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))
),
SCALE_INVERSE
),
roundUpUnit
)
}
}
/// @notice Calculates floor(x*y÷denominator) with full precision.
///
/// @dev An extension of "mulDiv" for signed numbers. Works by computing the signs and the absolute values separately.
///
/// Requirements:
/// - None of the inputs can be type(int256).min.
/// - The result must fit within int256.
///
/// @param x The multiplicand as an int256.
/// @param y The multiplier as an int256.
/// @param denominator The divisor as an int256.
/// @return result The result as an int256.
function mulDivSigned(
int256 x,
int256 y,
int256 denominator
) internal pure returns (int256 result) {
if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {
revert PRBMath__MulDivSignedInputTooSmall();
}
// Get hold of the absolute values of x, y and the denominator.
uint256 ax;
uint256 ay;
uint256 ad;
unchecked {
ax = x < 0 ? uint256(-x) : uint256(x);
ay = y < 0 ? uint256(-y) : uint256(y);
ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);
}
// Compute the absolute value of (x*y)÷denominator. The result must fit within int256.
uint256 rAbs = mulDiv(ax, ay, ad);
if (rAbs > uint256(type(int256).max)) {
revert PRBMath__MulDivSignedOverflow(rAbs);
}
// Get the signs of x, y and the denominator.
uint256 sx;
uint256 sy;
uint256 sd;
assembly {
sx := sgt(x, sub(0, 1))
sy := sgt(y, sub(0, 1))
sd := sgt(denominator, sub(0, 1))
}
// XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.
// If yes, the result should be negative.
result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);
}
/// @notice Calculates the square root of x, rounding down.
/// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
///
/// Caveats:
/// - This function does not work with fixed-point numbers.
///
/// @param x The uint256 number for which to calculate the square root.
/// @return result The result as an uint256.
function sqrt(uint256 x) internal pure returns (uint256 result) {
if (x == 0) {
return 0;
}
// Set the initial guess to the least power of two that is greater than or equal to sqrt(x).
uint256 xAux = uint256(x);
result = 1;
if (xAux >= 0x100000000000000000000000000000000) {
xAux >>= 128;
result <<= 64;
}
if (xAux >= 0x10000000000000000) {
xAux >>= 64;
result <<= 32;
}
if (xAux >= 0x100000000) {
xAux >>= 32;
result <<= 16;
}
if (xAux >= 0x10000) {
xAux >>= 16;
result <<= 8;
}
if (xAux >= 0x100) {
xAux >>= 8;
result <<= 4;
}
if (xAux >= 0x10) {
xAux >>= 4;
result <<= 2;
}
if (xAux >= 0x8) {
result <<= 1;
}
// The operations can never overflow because the result is max 2^127 when it enters this block.
unchecked {
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1; // Seven iterations should be enough
uint256 roundedDownResult = x / result;
return result >= roundedDownResult ? roundedDownResult : result;
}
}
}// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.4;
import "./PRBMath.sol";
/// @title PRBMathUD60x18
/// @author Paul Razvan Berg
/// @notice Smart contract library for advanced fixed-point math that works with uint256 numbers considered to have 18
/// trailing decimals. We call this number representation unsigned 60.18-decimal fixed-point, since there can be up to 60
/// digits in the integer part and up to 18 decimals in the fractional part. The numbers are bound by the minimum and the
/// maximum values permitted by the Solidity type uint256.
library PRBMathUD60x18 {
/// @dev Half the SCALE number.
uint256 internal constant HALF_SCALE = 5e17;
/// @dev log2(e) as an unsigned 60.18-decimal fixed-point number.
uint256 internal constant LOG2_E = 1_442695040888963407;
/// @dev The maximum value an unsigned 60.18-decimal fixed-point number can have.
uint256 internal constant MAX_UD60x18 =
115792089237316195423570985008687907853269984665640564039457_584007913129639935;
/// @dev The maximum whole value an unsigned 60.18-decimal fixed-point number can have.
uint256 internal constant MAX_WHOLE_UD60x18 =
115792089237316195423570985008687907853269984665640564039457_000000000000000000;
/// @dev How many trailing decimals can be represented.
uint256 internal constant SCALE = 1e18;
/// @notice Calculates the arithmetic average of x and y, rounding down.
/// @param x The first operand as an unsigned 60.18-decimal fixed-point number.
/// @param y The second operand as an unsigned 60.18-decimal fixed-point number.
/// @return result The arithmetic average as an unsigned 60.18-decimal fixed-point number.
function avg(uint256 x, uint256 y) internal pure returns (uint256 result) {
// The operations can never overflow.
unchecked {
// The last operand checks if both x and y are odd and if that is the case, we add 1 to the result. We need
// to do this because if both numbers are odd, the 0.5 remainder gets truncated twice.
result = (x >> 1) + (y >> 1) + (x & y & 1);
}
}
/// @notice Yields the least unsigned 60.18 decimal fixed-point number greater than or equal to x.
///
/// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.
/// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
///
/// Requirements:
/// - x must be less than or equal to MAX_WHOLE_UD60x18.
///
/// @param x The unsigned 60.18-decimal fixed-point number to ceil.
/// @param result The least integer greater than or equal to x, as an unsigned 60.18-decimal fixed-point number.
function ceil(uint256 x) internal pure returns (uint256 result) {
if (x > MAX_WHOLE_UD60x18) {
revert PRBMathUD60x18__CeilOverflow(x);
}
assembly {
// Equivalent to "x % SCALE" but faster.
let remainder := mod(x, SCALE)
// Equivalent to "SCALE - remainder" but faster.
let delta := sub(SCALE, remainder)
// Equivalent to "x + delta * (remainder > 0 ? 1 : 0)" but faster.
result := add(x, mul(delta, gt(remainder, 0)))
}
}
/// @notice Divides two unsigned 60.18-decimal fixed-point numbers, returning a new unsigned 60.18-decimal fixed-point number.
///
/// @dev Uses mulDiv to enable overflow-safe multiplication and division.
///
/// Requirements:
/// - The denominator cannot be zero.
///
/// @param x The numerator as an unsigned 60.18-decimal fixed-point number.
/// @param y The denominator as an unsigned 60.18-decimal fixed-point number.
/// @param result The quotient as an unsigned 60.18-decimal fixed-point number.
function div(uint256 x, uint256 y) internal pure returns (uint256 result) {
result = PRBMath.mulDiv(x, SCALE, y);
}
/// @notice Returns Euler's number as an unsigned 60.18-decimal fixed-point number.
/// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant).
function e() internal pure returns (uint256 result) {
result = 2_718281828459045235;
}
/// @notice Calculates the natural exponent of x.
///
/// @dev Based on the insight that e^x = 2^(x * log2(e)).
///
/// Requirements:
/// - All from "log2".
/// - x must be less than 133.084258667509499441.
///
/// @param x The exponent as an unsigned 60.18-decimal fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
function exp(uint256 x) internal pure returns (uint256 result) {
// Without this check, the value passed to "exp2" would be greater than 192.
if (x >= 133_084258667509499441) {
revert PRBMathUD60x18__ExpInputTooBig(x);
}
// Do the fixed-point multiplication inline to save gas.
unchecked {
uint256 doubleScaleProduct = x * LOG2_E;
result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE);
}
}
/// @notice Calculates the binary exponent of x using the binary fraction method.
///
/// @dev See https://ethereum.stackexchange.com/q/79903/24693.
///
/// Requirements:
/// - x must be 192 or less.
/// - The result must fit within MAX_UD60x18.
///
/// @param x The exponent as an unsigned 60.18-decimal fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
function exp2(uint256 x) internal pure returns (uint256 result) {
// 2^192 doesn't fit within the 192.64-bit format used internally in this function.
if (x >= 192e18) {
revert PRBMathUD60x18__Exp2InputTooBig(x);
}
unchecked {
// Convert x to the 192.64-bit fixed-point format.
uint256 x192x64 = (x << 64) / SCALE;
// Pass x to the PRBMath.exp2 function, which uses the 192.64-bit fixed-point number representation.
result = PRBMath.exp2(x192x64);
}
}
/// @notice Yields the greatest unsigned 60.18 decimal fixed-point number less than or equal to x.
/// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.
/// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
/// @param x The unsigned 60.18-decimal fixed-point number to floor.
/// @param result The greatest integer less than or equal to x, as an unsigned 60.18-decimal fixed-point number.
function floor(uint256 x) internal pure returns (uint256 result) {
assembly {
// Equivalent to "x % SCALE" but faster.
let remainder := mod(x, SCALE)
// Equivalent to "x - remainder * (remainder > 0 ? 1 : 0)" but faster.
result := sub(x, mul(remainder, gt(remainder, 0)))
}
}
/// @notice Yields the excess beyond the floor of x.
/// @dev Based on the odd function definition https://en.wikipedia.org/wiki/Fractional_part.
/// @param x The unsigned 60.18-decimal fixed-point number to get the fractional part of.
/// @param result The fractional part of x as an unsigned 60.18-decimal fixed-point number.
function frac(uint256 x) internal pure returns (uint256 result) {
assembly {
result := mod(x, SCALE)
}
}
/// @notice Converts a number from basic integer form to unsigned 60.18-decimal fixed-point representation.
///
/// @dev Requirements:
/// - x must be less than or equal to MAX_UD60x18 divided by SCALE.
///
/// @param x The basic integer to convert.
/// @param result The same number in unsigned 60.18-decimal fixed-point representation.
function fromUint(uint256 x) internal pure returns (uint256 result) {
unchecked {
if (x > MAX_UD60x18 / SCALE) {
revert PRBMathUD60x18__FromUintOverflow(x);
}
result = x * SCALE;
}
}
/// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down.
///
/// @dev Requirements:
/// - x * y must fit within MAX_UD60x18, lest it overflows.
///
/// @param x The first operand as an unsigned 60.18-decimal fixed-point number.
/// @param y The second operand as an unsigned 60.18-decimal fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
function gm(uint256 x, uint256 y) internal pure returns (uint256 result) {
if (x == 0) {
return 0;
}
unchecked {
// Checking for overflow this way is faster than letting Solidity do it.
uint256 xy = x * y;
if (xy / x != y) {
revert PRBMathUD60x18__GmOverflow(x, y);
}
// We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE
// during multiplication. See the comments within the "sqrt" function.
result = PRBMath.sqrt(xy);
}
}
/// @notice Calculates 1 / x, rounding toward zero.
///
/// @dev Requirements:
/// - x cannot be zero.
///
/// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the inverse.
/// @return result The inverse as an unsigned 60.18-decimal fixed-point number.
function inv(uint256 x) internal pure returns (uint256 result) {
unchecked {
// 1e36 is SCALE * SCALE.
result = 1e36 / x;
}
}
/// @notice Calculates the natural logarithm of x.
///
/// @dev Based on the insight that ln(x) = log2(x) / log2(e).
///
/// Requirements:
/// - All from "log2".
///
/// Caveats:
/// - All from "log2".
/// - This doesn't return exactly 1 for 2.718281828459045235, for that we would need more fine-grained precision.
///
/// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the natural logarithm.
/// @return result The natural logarithm as an unsigned 60.18-decimal fixed-point number.
function ln(uint256 x) internal pure returns (uint256 result) {
// Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x)
// can return is 196205294292027477728.
unchecked {
result = (log2(x) * SCALE) / LOG2_E;
}
}
/// @notice Calculates the common logarithm of x.
///
/// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common
/// logarithm based on the insight that log10(x) = log2(x) / log2(10).
///
/// Requirements:
/// - All from "log2".
///
/// Caveats:
/// - All from "log2".
///
/// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the common logarithm.
/// @return result The common logarithm as an unsigned 60.18-decimal fixed-point number.
function log10(uint256 x) internal pure returns (uint256 result) {
if (x < SCALE) {
revert PRBMathUD60x18__LogInputTooSmall(x);
}
// Note that the "mul" in this block is the assembly multiplication operation, not the "mul" function defined
// in this contract.
// prettier-ignore
assembly {
switch x
case 1 { result := mul(SCALE, sub(0, 18)) }
case 10 { result := mul(SCALE, sub(1, 18)) }
case 100 { result := mul(SCALE, sub(2, 18)) }
case 1000 { result := mul(SCALE, sub(3, 18)) }
case 10000 { result := mul(SCALE, sub(4, 18)) }
case 100000 { result := mul(SCALE, sub(5, 18)) }
case 1000000 { result := mul(SCALE, sub(6, 18)) }
case 10000000 { result := mul(SCALE, sub(7, 18)) }
case 100000000 { result := mul(SCALE, sub(8, 18)) }
case 1000000000 { result := mul(SCALE, sub(9, 18)) }
case 10000000000 { result := mul(SCALE, sub(10, 18)) }
case 100000000000 { result := mul(SCALE, sub(11, 18)) }
case 1000000000000 { result := mul(SCALE, sub(12, 18)) }
case 10000000000000 { result := mul(SCALE, sub(13, 18)) }
case 100000000000000 { result := mul(SCALE, sub(14, 18)) }
case 1000000000000000 { result := mul(SCALE, sub(15, 18)) }
case 10000000000000000 { result := mul(SCALE, sub(16, 18)) }
case 100000000000000000 { result := mul(SCALE, sub(17, 18)) }
case 1000000000000000000 { result := 0 }
case 10000000000000000000 { result := SCALE }
case 100000000000000000000 { result := mul(SCALE, 2) }
case 1000000000000000000000 { result := mul(SCALE, 3) }
case 10000000000000000000000 { result := mul(SCALE, 4) }
case 100000000000000000000000 { result := mul(SCALE, 5) }
case 1000000000000000000000000 { result := mul(SCALE, 6) }
case 10000000000000000000000000 { result := mul(SCALE, 7) }
case 100000000000000000000000000 { result := mul(SCALE, 8) }
case 1000000000000000000000000000 { result := mul(SCALE, 9) }
case 10000000000000000000000000000 { result := mul(SCALE, 10) }
case 100000000000000000000000000000 { result := mul(SCALE, 11) }
case 1000000000000000000000000000000 { result := mul(SCALE, 12) }
case 10000000000000000000000000000000 { result := mul(SCALE, 13) }
case 100000000000000000000000000000000 { result := mul(SCALE, 14) }
case 1000000000000000000000000000000000 { result := mul(SCALE, 15) }
case 10000000000000000000000000000000000 { result := mul(SCALE, 16) }
case 100000000000000000000000000000000000 { result := mul(SCALE, 17) }
case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) }
case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) }
case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) }
case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) }
case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) }
case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) }
case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) }
case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) }
case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) }
case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) }
case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) }
case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) }
case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) }
case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) }
case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) }
case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) }
case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) }
case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) }
case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) }
case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) }
case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) }
case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) }
case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) }
case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) }
case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) }
case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) }
case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) }
case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) }
case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) }
case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) }
case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) }
case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) }
case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) }
case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) }
case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) }
case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) }
case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) }
case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) }
case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) }
case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) }
case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) }
case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 59) }
default {
result := MAX_UD60x18
}
}
if (result == MAX_UD60x18) {
// Do the fixed-point division inline to save gas. The denominator is log2(10).
unchecked {
result = (log2(x) * SCALE) / 3_321928094887362347;
}
}
}
/// @notice Calculates the binary logarithm of x.
///
/// @dev Based on the iterative approximation algorithm.
/// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation
///
/// Requirements:
/// - x must be greater than or equal to SCALE, otherwise the result would be negative.
///
/// Caveats:
/// - The results are nor perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation.
///
/// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the binary logarithm.
/// @return result The binary logarithm as an unsigned 60.18-decimal fixed-point number.
function log2(uint256 x) internal pure returns (uint256 result) {
if (x < SCALE) {
revert PRBMathUD60x18__LogInputTooSmall(x);
}
unchecked {
// Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n).
uint256 n = PRBMath.mostSignificantBit(x / SCALE);
// The integer part of the logarithm as an unsigned 60.18-decimal fixed-point number. The operation can't overflow
// because n is maximum 255 and SCALE is 1e18.
result = n * SCALE;
// This is y = x * 2^(-n).
uint256 y = x >> n;
// If y = 1, the fractional part is zero.
if (y == SCALE) {
return result;
}
// Calculate the fractional part via the iterative approximation.
// The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster.
for (uint256 delta = HALF_SCALE; delta > 0; delta >>= 1) {
y = (y * y) / SCALE;
// Is y^2 > 2 and so in the range [2,4)?
if (y >= 2 * SCALE) {
// Add the 2^(-m) factor to the logarithm.
result += delta;
// Corresponds to z/2 on Wikipedia.
y >>= 1;
}
}
}
}
/// @notice Multiplies two unsigned 60.18-decimal fixed-point numbers together, returning a new unsigned 60.18-decimal
/// fixed-point number.
/// @dev See the documentation for the "PRBMath.mulDivFixedPoint" function.
/// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.
/// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.
/// @return result The product as an unsigned 60.18-decimal fixed-point number.
function mul(uint256 x, uint256 y) internal pure returns (uint256 result) {
result = PRBMath.mulDivFixedPoint(x, y);
}
/// @notice Returns PI as an unsigned 60.18-decimal fixed-point number.
function pi() internal pure returns (uint256 result) {
result = 3_141592653589793238;
}
/// @notice Raises x to the power of y.
///
/// @dev Based on the insight that x^y = 2^(log2(x) * y).
///
/// Requirements:
/// - All from "exp2", "log2" and "mul".
///
/// Caveats:
/// - All from "exp2", "log2" and "mul".
/// - Assumes 0^0 is 1.
///
/// @param x Number to raise to given power y, as an unsigned 60.18-decimal fixed-point number.
/// @param y Exponent to raise x to, as an unsigned 60.18-decimal fixed-point number.
/// @return result x raised to power y, as an unsigned 60.18-decimal fixed-point number.
function pow(uint256 x, uint256 y) internal pure returns (uint256 result) {
if (x == 0) {
result = y == 0 ? SCALE : uint256(0);
} else {
result = exp2(mul(log2(x), y));
}
}
/// @notice Raises x (unsigned 60.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the
/// famous algorithm "exponentiation by squaring".
///
/// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring
///
/// Requirements:
/// - The result must fit within MAX_UD60x18.
///
/// Caveats:
/// - All from "mul".
/// - Assumes 0^0 is 1.
///
/// @param x The base as an unsigned 60.18-decimal fixed-point number.
/// @param y The exponent as an uint256.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
function powu(uint256 x, uint256 y) internal pure returns (uint256 result) {
// Calculate the first iteration of the loop in advance.
result = y & 1 > 0 ? x : SCALE;
// Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster.
for (y >>= 1; y > 0; y >>= 1) {
x = PRBMath.mulDivFixedPoint(x, x);
// Equivalent to "y % 2 == 1" but faster.
if (y & 1 > 0) {
result = PRBMath.mulDivFixedPoint(result, x);
}
}
}
/// @notice Returns 1 as an unsigned 60.18-decimal fixed-point number.
function scale() internal pure returns (uint256 result) {
result = SCALE;
}
/// @notice Calculates the square root of x, rounding down.
/// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
///
/// Requirements:
/// - x must be less than MAX_UD60x18 / SCALE.
///
/// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the square root.
/// @return result The result as an unsigned 60.18-decimal fixed-point .
function sqrt(uint256 x) internal pure returns (uint256 result) {
unchecked {
if (x > MAX_UD60x18 / SCALE) {
revert PRBMathUD60x18__SqrtOverflow(x);
}
// Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two unsigned
// 60.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root).
result = PRBMath.sqrt(x * SCALE);
}
}
/// @notice Converts a unsigned 60.18-decimal fixed-point number to basic integer form, rounding down in the process.
/// @param x The unsigned 60.18-decimal fixed-point number to convert.
/// @return result The same number in basic integer form.
function toUint(uint256 x) internal pure returns (uint256 result) {
unchecked {
result = x / SCALE;
}
}
}{
"optimizer": {
"enabled": true,
"runs": 10
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {
"contracts/core/libraries/logic/ConfigureLogic.sol": {
"ConfigureLogic": "0xab4eb71128d543c4beeabf5845d51e2e858abb9e"
},
"contracts/core/libraries/logic/FundingFeeLogic.sol": {
"FundingFeeLogic": "0xa71a515de4acf04fb66e5923e5c0bd3146794c05"
},
"contracts/core/libraries/logic/GenericLogic.sol": {
"GenericLogic": "0x10671bc2f07593e208b1762b101fdfea8689067e"
},
"contracts/core/libraries/logic/PositionLogic.sol": {
"PositionLogic": "0x8d8fb6320ab54f5ba37c532c91978f3b61f14877"
},
"contracts/core/libraries/logic/SupplyLogic.sol": {
"SupplyLogic": "0x77cdd46002cd7ae83a72622127acb2f7ae53a7da"
},
"contracts/core/libraries/logic/SwapLogic.sol": {
"SwapLogic": "0xff6ec5be53b532e4b5aac66dab16fd54575e6323"
}
}
}Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimFundingFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SettleFundingFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_collateralToken","type":"address[]"},{"internalType":"address[]","name":"_indexToken","type":"address[]"},{"internalType":"bool[]","name":"_isLong","type":"bool[]"}],"name":"batchSettleFundingFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"buyUSDG","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimFundingFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"clearTokenConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"uint256","name":"_collateralDelta","type":"uint256"},{"internalType":"uint256","name":"_sizeDelta","type":"uint256"},{"internalType":"bool","name":"_isLong","type":"bool"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"decreasePosition","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"directPoolDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAddresses","outputs":[{"components":[{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"ulpManager","type":"address"},{"internalType":"address","name":"priceFeed","type":"address"},{"internalType":"address","name":"usdg","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"feesReceiver","type":"address"}],"internalType":"struct DataTypes.AddressStorage","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address[]","name":"_collateralToken","type":"address[]"},{"internalType":"address[]","name":"_indexToken","type":"address[]"},{"internalType":"bool[]","name":"_isLong","type":"bool[]"}],"name":"getBatchSettleFundingFeeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getBorrowingFeeInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBorrowingRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getBufferAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_usdgDelta","type":"uint256"},{"internalType":"uint256","name":"_feeBasisPoints","type":"uint256"},{"internalType":"uint256","name":"_taxBasisPoints","type":"uint256"},{"internalType":"bool","name":"_increment","type":"bool"},{"internalType":"bool","name":"_isSwap","type":"bool"}],"name":"getFeeBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getFeeReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFees","outputs":[{"components":[{"internalType":"uint256","name":"taxBasisPoints","type":"uint256"},{"internalType":"uint256","name":"stableTaxBasisPoints","type":"uint256"},{"internalType":"uint256","name":"mintBurnFeeBasisPoints","type":"uint256"},{"internalType":"uint256","name":"swapFeeBasisPoints","type":"uint256"},{"internalType":"uint256","name":"stableSwapFeeBasisPoints","type":"uint256"},{"internalType":"uint256","name":"marginFeeBasisPoints","type":"uint256"},{"internalType":"uint256","name":"liquidationFeeUsd","type":"uint256"},{"internalType":"bool","name":"hasDynamicFees","type":"bool"},{"internalType":"uint256","name":"balanceReward","type":"uint256"}],"internalType":"struct DataTypes.SetFeesParams","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getFundingFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getFundingFeeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getGlobalData","outputs":[{"components":[{"internalType":"uint256","name":"maxGlobalLongSize","type":"uint256"},{"internalType":"uint256","name":"globalLongSize","type":"uint256"},{"internalType":"uint256","name":"globalLongAveragePrice","type":"uint256"},{"internalType":"uint256","name":"maxGlobalShortSize","type":"uint256"},{"internalType":"uint256","name":"globalShortSize","type":"uint256"},{"internalType":"uint256","name":"globalShortAveragePrice","type":"uint256"}],"internalType":"struct DataTypes.GlobalData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getGlobalShortDelta","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxGasPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxLeverage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getMaxPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getMinPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_usdgDelta","type":"uint256"},{"internalType":"bool","name":"_increment","type":"bool"}],"name":"getNextTargetUsdgAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPause","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPermissionParams","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getPoolInfo","outputs":[{"components":[{"internalType":"uint256","name":"poolAmount","type":"uint256"},{"internalType":"uint256","name":"reservedAmount","type":"uint256"},{"internalType":"uint256","name":"bufferAmount","type":"uint256"},{"internalType":"uint256","name":"globalLongSize","type":"uint256"},{"internalType":"uint256","name":"globalLongAveragePrice","type":"uint256"},{"internalType":"uint256","name":"globalShortSize","type":"uint256"},{"internalType":"uint256","name":"globalShortAveragePrice","type":"uint256"},{"internalType":"uint256","name":"usdgAmount","type":"uint256"}],"internalType":"struct DataTypes.PoolInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"bool","name":"_isLong","type":"bool"}],"name":"getPosition","outputs":[{"components":[{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"averagePrice","type":"uint256"},{"internalType":"uint256","name":"entryBorrowingRate","type":"uint256"},{"internalType":"uint256","name":"fundingFeeAmountPerSize","type":"uint256"},{"internalType":"uint256","name":"claimableFundingAmountPerSize","type":"uint256"},{"internalType":"uint256","name":"reserveAmount","type":"uint256"},{"internalType":"int256","name":"realisedPnl","type":"int256"},{"internalType":"uint256","name":"lastIncreasedTime","type":"uint256"}],"internalType":"struct DataTypes.Position","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"bool","name":"_isLong","type":"bool"}],"name":"getPositionDeltaAndFees","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"bool","name":"_isLong","type":"bool"}],"name":"getPositionLeverage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_usdgAmount","type":"uint256"}],"name":"getRedemptionAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReserveRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getTargetUsdgAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getTokenConfig","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenDecimals","type":"uint256"},{"internalType":"uint256","name":"tokenWeight","type":"uint256"},{"internalType":"uint256","name":"maxUsdgAmount","type":"uint256"},{"internalType":"bool","name":"isStable","type":"bool"},{"internalType":"bool","name":"isShortable","type":"bool"}],"internalType":"struct DataTypes.SetTokenConfigParams","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getTokenDecimal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getTokenInfo","outputs":[{"components":[{"internalType":"uint256","name":"tokenDecimal","type":"uint256"},{"internalType":"bool","name":"isWhitelistedToken","type":"bool"},{"internalType":"bool","name":"isStableToken","type":"bool"},{"internalType":"uint256","name":"maxUsdgAmount","type":"uint256"}],"internalType":"struct DataTypes.TokenInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"bool","name":"_isLong","type":"bool"}],"name":"getTotalFeesForPositionLiquidation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getUsdgAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getUtilisation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWhitelistedToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"uint256","name":"_sizeDelta","type":"uint256"},{"internalType":"bool","name":"_isLong","type":"bool"}],"name":"increasePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"isFeesAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_liquidator","type":"address"}],"name":"isLiquidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"name":"isManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_router","type":"address"}],"name":"isRouter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"isTokenPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"bool","name":"_isLong","type":"bool"},{"internalType":"address","name":"_feeReceiver","type":"address"}],"name":"liquidatePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"sellUSDG","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"ulpManager","type":"address"},{"internalType":"address","name":"priceFeed","type":"address"},{"internalType":"address","name":"usdg","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"feesReceiver","type":"address"}],"internalType":"struct DataTypes.AddressStorage","name":"params","type":"tuple"}],"name":"setAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_borrowingInterval","type":"uint256"},{"internalType":"uint256","name":"_borrowingRateFactor","type":"uint256"},{"internalType":"uint256","name":"_stableBorrowingRateFactor","type":"uint256"}],"name":"setBorrowingRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setBufferAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"taxBasisPoints","type":"uint256"},{"internalType":"uint256","name":"stableTaxBasisPoints","type":"uint256"},{"internalType":"uint256","name":"mintBurnFeeBasisPoints","type":"uint256"},{"internalType":"uint256","name":"swapFeeBasisPoints","type":"uint256"},{"internalType":"uint256","name":"stableSwapFeeBasisPoints","type":"uint256"},{"internalType":"uint256","name":"marginFeeBasisPoints","type":"uint256"},{"internalType":"uint256","name":"liquidationFeeUsd","type":"uint256"},{"internalType":"bool","name":"hasDynamicFees","type":"bool"},{"internalType":"uint256","name":"balanceReward","type":"uint256"}],"internalType":"struct DataTypes.SetFeesParams","name":"params","type":"tuple"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"bool","name":"_isAdmin","type":"bool"}],"name":"setFeesAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"uint256[]","name":"_fundingFactors","type":"uint256[]"},{"internalType":"uint256[]","name":"_fundingExponentFactors","type":"uint256[]"}],"name":"setFundingFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_liquidator","type":"address"},{"internalType":"bool","name":"_isActive","type":"bool"}],"name":"setLiquidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"},{"internalType":"bool","name":"_isManager","type":"bool"}],"name":"setManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGasPrice","type":"uint256"}],"name":"setMaxGasPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"uint256[]","name":"_longSizes","type":"uint256[]"},{"internalType":"uint256[]","name":"_shortSizes","type":"uint256[]"}],"name":"setMaxGlobalSizes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxLeverage","type":"uint256"}],"name":"setMaxLeverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"flag","type":"bool"}],"name":"setPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_inManagerMode","type":"bool"},{"internalType":"bool","name":"_inPrivateLiquidationMode","type":"bool"},{"internalType":"bool","name":"_isSwapEnabled","type":"bool"},{"internalType":"bool","name":"_isLeverageEnabled","type":"bool"}],"name":"setPermissionParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ratio","type":"uint256"}],"name":"setReserveRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_router","type":"address"},{"internalType":"bool","name":"_isRouter","type":"bool"}],"name":"setRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenDecimals","type":"uint256"},{"internalType":"uint256","name":"_tokenWeight","type":"uint256"},{"internalType":"uint256","name":"_maxUsdgAmount","type":"uint256"},{"internalType":"bool","name":"_isStable","type":"bool"},{"internalType":"bool","name":"_isShortable","type":"bool"}],"name":"setTokenConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"bool","name":"_isPause","type":"bool"}],"name":"setTokenPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setUsdgAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"swap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"tokenToUsdMin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"}],"name":"updateCumulativeBorrowingRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_indexToken","type":"address"}],"name":"updateFundingState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"bool","name":"_isLong","type":"bool"},{"internalType":"bool","name":"_raise","type":"bool"}],"name":"validateLiquidation","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"withdrawFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b50615a6180620000216000396000f3fe608060405234801561001057600080fd5b506004361061038a5760003560e01c806381a612d6116101dc57806381a612d6146107f957806382a084901461080c5780638585f4d21461081f57806387ed714414610832578063891c5a731461084557806389201c761461085857806389c98c061461086b5780638b4f3b2c146108735780638da5cb5b14610886578063933162121461089b5780639498a8ca146108ae57806397a6760c146108c1578063a39fac12146108d4578063a5e90eee146108e9578063b364accb146108fc578063b375d49214610926578063bd2521ac14610939578063bedb86fb1461094c578063c14bfd361461095f578063c3c6467414610972578063cb67e3b114610985578063cb8d3b1f146109a5578063d2fa635e146109b8578063d3127e63146109cb578063d3405289146109de578063d54d5a9f146109f1578063d66b000d14610a04578063d91ed30a14610a17578063db8d55f114610a2a578063de2ea94814610a3f578063dfa2ce1c14610a52578063e124e6d214610a65578063e30c397814610a78578063e67f59a714610a80578063ef12c67e14610a93578063f2fde38b14610aa6578063f36b242514610ab9578063f3ae241514610adc578063fe75443314610aef57600080fd5b806304fef1db1461038f57806306bfa938146103b557806308a99df9146104295780630a48d5a9146104595780630ea8b3bf1461046c578063164e68de146104745780631f69565f1461048757806321f9dace146104d15780632c668ec1146104e65780632ef94257146104f9578063322b3d9814610501578063336e94d3146105295780633459a82f1461053c5780633a05dcc1146105525780633cb6b783146105655780633e3002b6146105a25780633e3ca9d3146105b5578063417584ee146105cd5780634453a374146105e057806348d91abf146105f35780634a3f088d1461060657806351723e8214610686578063529a356f146106995780635534aa5f146106ac57806356ac1d5c146106bf57806356b6d0d5146106d757806358e86625146106df5780635c401439146106f25780635c975abb146107055780635e76ad54146107105780635f7bc1191461072357806360986cef1461073657806362883ccd14610749578063655a62571461075c578063711e6190146107bb578063715018a6146107ce57806379ba5097146107d65780638129fc1c146107de578063817bb857146107e6575b600080fd5b6103a261039d366004614a81565b610b02565b6040519081526020015b60405180910390f35b6103c86103c3366004614a81565b610b83565b6040516103ac9190600061010082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015292915050565b61043c610437366004614ab5565b610c43565b6040805193845291151560208401521515908201526060016103ac565b6103a2610467366004614b1a565b610c69565b6103a2610c7c565b6103a2610482366004614a81565b610c8e565b61049a610495366004614a81565b610d73565b6040516103ac9190815181526020808301511515908201526040808301511515908201526060918201519181019190915260800190565b6104e46104df366004614b44565b610d84565b005b6103a26104f4366004614b1a565b610dc6565b6103a2610dd2565b61051461050f366004614a81565b610eb9565b604080519283526020830191909152016103ac565b6104e4610537366004614ab5565b610ef8565b610544610fa8565b6040516103ac929190614b7b565b6103a2610560366004614a81565b610fbc565b610578610573366004614bd2565b610fc7565b6040805195151586526020860194909452928401919091526060830152608082015260a0016103ac565b6103a26105b0366004614c28565b611040565b6105bd611055565b60405190151581526020016103ac565b6104e46105db366004614dc7565b611068565b6104e46105ee366004614b44565b611197565b6104e4610601366004614e4e565b61120c565b610619610614366004614bd2565b611314565b6040516103ac9190600061012082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525092915050565b6103a2610694366004614bd2565b611401565b6105bd6106a7366004614a81565b611488565b6103a26106ba366004614a81565b6114b8565b6106c76114e5565b6040516103ac9493929190614eb0565b6103a261151f565b6103a26106ed366004614a81565b611534565b6105bd610700366004614a81565b611568565b60975460ff166105bd565b6105bd61071e366004614a81565b611598565b6104e4610731366004614a81565b6115c8565b6104e4610744366004614f35565b61164c565b6103a2610757366004614a81565b611849565b61076f61076a366004614a81565b611876565b6040516103ac9190600060c082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b6103a26107c9366004614fb2565b611910565b6104e46119a8565b6104e46119bc565b6104e4611a37565b6103a26107f4366004614fb2565b611b5e565b6103a2610807366004614a81565b611bcf565b6103a261081a366004614fe5565b611bda565b6104e461082d366004614b1a565b611cf4565b6103a2610840366004614a81565b611d35565b6103a2610853366004614a81565b611d62565b6103a261086636600461505f565b611d8f565b6103a2611eae565b6104e46108813660046150f7565b611ec3565b61088e611f2b565b6040516103ac9190615110565b6103a26108a9366004615124565b611f3a565b6105146108bc366004614a81565b612035565b6104e46108cf366004614a81565b612074565b6108dc6120bb565b6040516103ac9190615167565b6104e46108f7366004614b44565b612135565b61090f61090a366004614a81565b612176565b6040805192151583526020830191909152016103ac565b6104e46109343660046151c7565b612229565b6103a2610947366004614bd2565b612268565b6104e461095a366004615276565b6122f7565b6104e461096d366004615293565b612315565b6104e4610980366004614b44565b612354565b610998610993366004614a81565b61238d565b6040516103ac9190615313565b6104e46109b3366004614b44565b612426565b6104e46109c63660046150f7565b6124eb565b6104e46109d93660046150f7565b61252b565b6104e46109ec366004614fb2565b61256b565b6105146109ff36600461535f565b612593565b6104e4610a12366004614b1a565b6125b2565b6104e4610a253660046153bc565b6125f3565b610a3261266e565b6040516103ac91906153fd565b6104e4610a4d366004615463565b6126ea565b6105bd610a60366004614fb2565b612794565b6103a2610a73366004614a81565b6127d3565b61088e6127de565b6104e4610a8e366004614a81565b6127ed565b6104e4610aa1366004614dc7565b61282c565b6104e4610ab4366004614a81565b61286f565b610ac16128d5565b604080519384526020840192909252908201526060016103ac565b6105bd610aea366004614a81565b6128ff565b6104e4610afd3660046154ca565b61292f565b6040516304fef1db60e01b81526000907310671bc2f07593e208b1762b101fdfea8689067e906304fef1db90610b3c908590600401615110565b602060405180830381865af4158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d91906154f6565b92915050565b610bcb60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405162d7f52760e31b81527310671bc2f07593e208b1762b101fdfea8689067e906306bfa93890610c01908590600401615110565b61010060405180830381865af4158015610c1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d919061550f565b6000806000610c568989898989896129d5565b9250925092505b96509650969350505050565b6000610c758383612fc4565b9392505050565b600080610c87613020565b5492915050565b600080610c9961304e565b33600090815260058201602052604090205490915060ff16610cfb5760405162461bcd60e51b81526020600482015260166024820152753737ba103bb4ba34323930bb903332b29030b236b4b760511b60448201526064015b60405180910390fd5b604051630b27346f60e11b81527310671bc2f07593e208b1762b101fdfea8689067e9063164e68de90610d32908690600401615110565b602060405180830381865af4158015610d4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7591906154f6565b610d7b61490e565b610b7d8261307c565b610d8c6130fc565b6000610d9661304e565b6001600160a01b039390931660009081526005909301602052506040909120805460ff1916911515919091179055565b6000610c75838361315b565b6000610ddc6131b5565b610de461320e565b6000610dee613254565b90506000610dfa613282565b3360009081526014840160205260409020549091508015610ea8576005820154610e2d906001600160a01b0316826132b0565b6005830154909150610e49906001600160a01b031682336132d5565b33600081815260148501602052604080822091909155600584015490517f80814eb170ced28dd8eb312180365462e4b9878baf473b6d4302dde21011a89f91610e9f916001600160a01b0390911690859061559e565b60405180910390a25b92505050610eb6600160c955565b90565b6000806000610ec6613254565b6001600160a01b039094166000908152600f850160209081526040808320546010909701909152902054939492505050565b610f006130fc565b73ab4eb71128d543c4beeabf5845d51e2e858abb9e63669c5bfe6040518060c00160405280896001600160a01b0316815260200188815260200187815260200186815260200185151581526020018415158152506040518263ffffffff1660e01b8152600401610f709190615313565b60006040518083038186803b158015610f8857600080fd5b505af4158015610f9c573d6000803e3d6000fd5b50505050505050505050565b60006060610fb461338d565b915091509091565b6000610b7d8261340b565b600080600080600080610fdc8a8a8a8a611314565b9050600080610ff58a846000015185604001518c6134de565b9150915060006110118d8d8d8d88600001518960600151613589565b905060006110208c8c87613609565b8051602090910151949f939e50919c50909a509198509650505050505050565b600061104d8484846136ad565b949350505050565b600061106360975460ff1690565b905090565b6110706130fc565b81518351148015611082575080518351145b61109e5760405162461bcd60e51b8152600401610cf2906155b7565b60005b8351811015611126578281815181106110bc576110bc6155e4565b602002602001015160001415806110ed57508181815181106110e0576110e06155e4565b6020026020010151600014155b1561111457611114848281518110611107576111076155e4565b6020026020010151612074565b8061111e81615610565b9150506110a1565b506040516320bac27760e11b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063417584ee9061116290869086908690600401615664565b60006040518083038186803b15801561117a57600080fd5b505af415801561118e573d6000803e3d6000fd5b50505050505050565b61119f6130fc565b604051631114e8dd60e21b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e90634453a374906111d890859085906004016156cf565b60006040518083038186803b1580156111f057600080fd5b505af4158015611204573d6000803e3d6000fd5b505050505050565b6112146131b5565b61121c61320e565b61122583611598565b156112425760405162461bcd60e51b8152600401610cf2906156ea565b6040805160a0810182526001600160a01b03878116825286811660208301908152868216838501908152606084018781528615156080860190815295516306109c4f60e31b8152945184166004860152915183166024850152519091166044830152516064820152905115156084820152738d8fb6320ab54f5ba37c532c91978f3b61f1487790633084e2789060a4015b60006040518083038186803b1580156112eb57600080fd5b505af41580156112ff573d6000803e3d6000fd5b5050505061130d600160c955565b5050505050565b6113636040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051634a3f088d60e01b81526001600160a01b0380871660048301528086166024830152841660448201528215156064820152738d8fb6320ab54f5ba37c532c91978f3b61f1487790634a3f088d9060840161012060405180830381865af41580156113d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f89190615719565b95945050505050565b60008061141086868686611314565b905060008160200151116114605760405162461bcd60e51b81526020600482015260176024820152762b30bab63a1d1034b73b30b634b2103837b9b4ba34b7b760491b6044820152606401610cf2565b602081015181516114749061271090615794565b61147e91906157c1565b9695505050505050565b60008061149361304e565b6001600160a01b03909316600090815260029093016020525050604090205460ff1690565b6000806114c3613020565b6001600160a01b03909316600090815260049093016020525050604090205490565b60008060008060006114f561304e565b5460ff62010000820481169763010000008304821697508183169650610100909204169350915050565b60008061152a613020565b6002015492915050565b60008061153f6137cf565b6001600160a01b0384166000908152600482016020526040902054909150610c7590600a6158c7565b60008061157361304e565b6001600160a01b03909316600090815260059093016020525050604090205460ff1690565b6000806115a361304e565b6001600160a01b03909316600090815260049093016020525050604090205460ff1690565b6115d06131b5565b6115d861320e565b604051635f7bc11960e01b81527377cdd46002cd7ae83a72622127acb2f7ae53a7da90635f7bc1199061160f908490600401615110565b60006040518083038186803b15801561162757600080fd5b505af415801561163b573d6000803e3d6000fd5b50505050611649600160c955565b50565b6116546131b5565b61165c61320e565b8151835114801561166e575080518351145b61168a5760405162461bcd60e51b8152600401610cf2906155b7565b6000805b84518110156118035760006116f0338784815181106116af576116af6155e4565b60200260200101518785815181106116c9576116c96155e4565b60200260200101518786815181106116e3576116e36155e4565b60200260200101516137fd565b905060006116fc613020565b600083815260088201602052604081208054929350919003611720575050506117f1565b60006117c5888681518110611737576117376155e4565b6020026020010151888781518110611751576117516155e4565b602002602001015184604051806101200160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815260200160078201548152602001600882015481525050613609565b90506117d13382613853565b6060810151600583015560208101516117ea90876158d3565b9550505050505b806117fb81615610565b91505061168e565b5060405181815233907f953615e1b3502c33b28f9e7bab58b4a721d74651f2a323a199ba094aae3b2f4c9060200160405180910390a250611844600160c955565b505050565b600080611854613254565b6001600160a01b03909316600090815260149093016020525050604090205490565b61187e61493a565b6000611888613020565b905061189261493a565b6001600160a01b039093166000818152600b8301602090815260408083205487528383526009850182528083205487830152838352600a850182528083205487820152838352600e85018252808320546060880152838352600c85018252808320546080880152928252600d90930190925290205460a08301525090565b600061191a6131b5565b61192261320e565b60405163234a0b6b60e01b81527377cdd46002cd7ae83a72622127acb2f7ae53a7da9063234a0b6b9061195b90869086906004016158e6565b602060405180830381865af4158015611978573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199c91906154f6565b9050610b7d600160c955565b6119b06130fc565b6119ba60006138af565b565b33806119c66127de565b6001600160a01b031614611a2e5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610cf2565b611649816138af565b600054610100900460ff1615808015611a575750600054600160ff909116105b80611a785750611a66306138c8565b158015611a78575060005460ff166001145b611adb5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610cf2565b6000805460ff191660011790558015611afe576000805461ff0019166101001790555b611b066138d7565b611b0e613906565b611b16613935565b8015611649576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b6000611b686131b5565b611b7061320e565b611b7983611598565b15611b965760405162461bcd60e51b8152600401610cf2906156ea565b604051639f2a556160e01b81527377cdd46002cd7ae83a72622127acb2f7ae53a7da90639f2a55619061195b90869086906004016158e6565b6000610b7d82613964565b6000611be46131b5565b611bec61320e565b6040805160e0810182526001600160a01b038a8116825289811660208301908152898216838501908152606084018a8152608085018a815289151560a0870190815289861660c0880190815297516335dde3a160e11b815296518616600488015293518516602487015291518416604486015251606485015251608484015251151560a4830152915190911660c4820152738d8fb6320ab54f5ba37c532c91978f3b61f1487790636bbbc7429060e401602060405180830381865af4158015611cb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cdd91906154f6565b9050611ce9600160c955565b979650505050505050565b611cfc6130fc565b6040516342c2fa6960e11b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e90638585f4d2906111d8908590859060040161559e565b600080611d40613020565b6001600160a01b03909316600090815260079093016020525050604090205490565b600080611d6d613254565b6001600160a01b03909316600090815260099093016020525050604090205490565b600082518451148015611da3575081518451145b611dbf5760405162461bcd60e51b8152600401610cf2906155b7565b6000805b8551811015611ea4576000611e1888888481518110611de457611de46155e4565b6020026020010151888581518110611dfe57611dfe6155e4565b60200260200101518886815181106116e3576116e36155e4565b90506000611e24613020565b600083815260088201602052604081208054929350919003611e4857505050611e92565b6000611e79898681518110611e5f57611e5f6155e4565b6020026020010151898781518110611751576117516155e4565b9050806020015186611e8b91906158d3565b9550505050505b80611e9c81615610565b915050611dc3565b5095945050505050565b600080611eb9613020565b6001015492915050565b611ecb6130fc565b6040516322d3cecb60e21b81526004810182905273ab4eb71128d543c4beeabf5845d51e2e858abb9e90638b4f3b2c906024015b60006040518083038186803b158015611f1757600080fd5b505af415801561130d573d6000803e3d6000fd5b6033546001600160a01b031690565b6000611f446131b5565b611f4c61320e565b611f5584611598565b158015611f685750611f6683611598565b155b611f845760405162461bcd60e51b8152600401610cf2906156ea565b6000611f8f856139c2565b60405160016276c04560e11b031981526001600160a01b0380881660048301528087166024830152604482018390528516606482015290915073ff6ec5be53b532e4b5aac66dab16fd54575e63239063ff127f7690608401602060405180830381865af4158015612004573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202891906154f6565b915050610c75600160c955565b6000806000612042613254565b6001600160a01b039094166000908152600d85016020908152604080832054600e909701909152902054939492505050565b61207c6131b5565b61208461320e565b6040516325e99d8360e21b815273a71a515de4acf04fb66e5923e5c0bd3146794c05906397a6760c9061160f908490600401615110565b6120c3614970565b60006120cd613282565b90506120d7614970565b81546001600160a01b0390811682526001830154811660208301526002830154811660408301526003830154811660608301526004830154811660808301526005830154811660a083015260069092015490911660c0820152919050565b61213d6130fc565b6040516352f4877760e11b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063a5e90eee906111d890859085906004016156cf565b6000806000612183613020565b6001600160a01b0385166000908152600c820160205260408120549192508190036121b5575060009485945092505050565b60006121c086613a7a565b6001600160a01b0387166000908152600d850160205260408120549192508282116121f4576121ef8284615900565b6121fe565b6121fe8383615900565b905060008261220d8387615794565b61221791906157c1565b93909211989297509195505050505050565b6122316130fc565b604051631395c1d560e31b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e90639cae0ea890611eff908490600401615167565b600080612273613254565b9050600061228387878787611314565b905060006122948260000151613abb565b905060006122ae8989898987600001518860600151613589565b905060006122bd888886613609565b600686015481519192506000916122d485876158d3565b6122de91906158d3565b6122e891906158d3565b9b9a5050505050505050505050565b6122ff6130fc565b801561230d57611649613b10565b611649613b64565b61231d6130fc565b60405163903fe8f160e01b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063903fe8f190611eff9084906004016153fd565b6040516330f1919d60e21b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063c3c64674906111d890859085906004016156cf565b6123956149ac565b600061239f6137cf565b90506123a96149ac565b6001600160a01b0390931680845260008181526004830160209081526040808320548288015283835260058501825280832054818801528383526006850182528083205460608801528383526007850182528083205460ff9081161515608089015293835260089094019052919091205416151560a08301525090565b60006124306120bb565b905061243a611f2b565b6001600160a01b0316336001600160a01b0316148061246e575080602001516001600160a01b0316336001600160a01b0316145b6124b25760405162461bcd60e51b81526020600482015260156024820152742b30bab63a1d1034b73b30b634b21031b0b63632b960591b6044820152606401610cf2565b60405163cb8d3b1f60e01b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063cb8d3b1f9061116290869086906004016156cf565b6124f36130fc565b60405163697d31af60e11b81526004810182905273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063d2fa635e90602401611eff565b6125336130fc565b60405163d3127e6360e01b81526004810182905273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063d3127e6390602401611eff565b6125736131b5565b61257b61320e565b6125858282613b9d565b61258f600160c955565b5050565b6000806125a38787878787613d0d565b915091505b9550959350505050565b6125ba6130fc565b60405163d66b000d60e01b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063d66b000d906111d8908590859060040161559e565b6125fb6130fc565b604051636c8f698560e11b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063d91ed30a90612638908790879087908790600401614eb0565b60006040518083038186803b15801561265057600080fd5b505af4158015612664573d6000803e3d6000fd5b5050505050505050565b6126766149ef565b6000612680613254565b905061268a6149ef565b8154815260018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c0820152600782015460ff16151560e0820152600890910154610100820152919050565b6126f26131b5565b6126fa61320e565b6040805160a0810182526001600160a01b03878116825286811660208301908152868216838501908152861515606085019081528684166080860190815295516317fd4e1d60e01b81529451841660048601529151831660248501525182166044840152511515606483015291519091166084820152738d8fb6320ab54f5ba37c532c91978f3b61f14877906317fd4e1d9060a4016112d3565b60008061279f61304e565b6001600160a01b03948516600090815260019190910160209081526040808320959096168252939093525050205460ff1690565b6000610b7d82613a7a565b6065546001600160a01b031690565b6127f56130fc565b60405163e67f59a760e01b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063e67f59a790611eff908490600401615110565b6128346130fc565b604051637789633f60e11b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063ef12c67e9061116290869086908690600401615664565b6128776130fc565b606580546001600160a01b0319166001600160a01b03831690811790915561289d611f2b565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6000806000806128e3613254565b600a810154600b820154600c9092015490969195509350915050565b60008061290a61304e565b6001600160a01b03909316600090815260039093016020525050604090205460ff1690565b6129376130fc565b60008060006129446128d5565b92509250925082600014158061295957508115155b8061296357508015155b1561298f576000612972613282565b600581015490915061298d906001600160a01b03168061256b565b505b60405163fe75443360e01b815260048101879052602481018690526044810185905273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063fe75443390606401610f70565b6000806000612a2d604051806101200160405280600081526020016000151581526020016000151581526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6000612a37613254565b90506000612a43613020565b90506000612a4f613282565b600784015490915060ff16612a71578a60008096509650965050505050610c5d565b6001600160a01b038d16600090815260048301602052604090205460608501819052612a9e908d906158d3565b608085015288612add5783606001518c1115612ac7576000608085015260608401519b50612add565b8b8460600151612ad79190615900565b60808501525b612ae68d61340b565b60a0850152878015612af6575088155b15612b0d57612b078d8d60016136ad565b60a08501525b8360a00151600003612b2c578a60008096509650965050505050610c5d565b612b39846060015161404e565b612b468560a0015161404e565b612b509190615913565b60c0850152612b608d8d8b6136ad565b60e0850152878015612b70575088155b15612b8457612b7e8d61340b565b60e08501525b8360e00151600003612ba3578a60008096509650965050505050610c5d565b612bb0846080015161404e565b612bbd8560e0015161404e565b612bc79190615913565b6101008501528815612d8657612be08460c001516140bc565b612bee8561010001516140bc565b1015612ca05760008460e00151612c088660c001516140bc565b612c12908d615794565b612c1c91906157c1565b90508b8111612c3457612c2f818d615900565b612c37565b60005b855260c08501516000138015612c535750600085610100015113155b80612c73575060008560c00151138015612c735750600085610100015112155b15612c8b576001602086015260006040860152612c9a565b60006020860152600160408601525b50612f49565b60006002612cb28661010001516140bc565b612cbf8760c001516140bc565b612cc991906158d3565b612cd391906157c1565b90508460e00151811115612ce8575060e08401515b60e0850151600090612cfa838e615794565b612d0491906157c1565b905060008660c00151128015612d205750600086610100015113155b80612d40575060008660c00151138015612d405750600086610100015112155b15612d6457612d4f818e6158d3565b86526000602087018190526040870152612d7f565b612d6e818e6158d3565b865260006020870152600160408701525b5050612f49565b60008460c00151128015612da05750600084610100015113155b80612dc0575060008460c00151138015612dc05750600084610100015112155b15612ec657612dd28460c001516140bc565b612de08561010001516140bc565b1015612e3f5760008460e00151612dfa8660c001516140bc565b612e04908d615794565b612e0e91906157c1565b90508b8111612e2657612e21818d615900565b612e29565b60005b8552506000602085018190526040850152612f49565b60006002612e518661010001516140bc565b612e5e8760c001516140bc565b612e6891906158d3565b612e7291906157c1565b90508460e00151811115612e87575060e08401515b60e0850151600090612e99838e615794565b612ea391906157c1565b9050612eaf818e6158d3565b865250506000602085018190526040850152612f49565b60006002612ed88661010001516140bc565b612ee58760c001516140bc565b612eef91906158d3565b612ef991906157c1565b90508460e00151811115612f0e575060e08401515b60e0850151600090612f20838e615794565b612f2a91906157c1565b9050612f36818e6158d3565b8652505060006020850152600160408501525b60058101546001600160a01b038e8116911614612f6857600060208501525b88158015612f85575060058101546001600160a01b038e81169116145b15612fa257600883015484518590612f9e9083906158d3565b9052505b505081516020830151604090930151909c929b50995090975050505050505050565b600081600003612fd657506000610b7d565b6000612fe06137cf565b90506000612fed85613964565b6001600160a01b038616600090815260048401602052604090205490915061301681600a6158c7565b6114748387615794565b600080610b7d60017f0a6857889562f1d40df97cc84c0aafc7cd2f70e5ce2a65223fd89163f728a8d0615900565b600080610b7d60017fec44c653f648cabed39c0c4eda0c4e30c82628a3e671ccda53ec8daf9f3b79c7615900565b61308461490e565b600061308e6137cf565b604080516080810182526001600160a01b0390951660008181526004840160209081528382205488528282526003850181528382205460ff9081161515828a015283835260078601825284832054161515888501529181526006909301905290205460608401525090919050565b33613105611f2b565b6001600160a01b0316146119ba5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610cf2565b600080613166613282565b9050600061317385613a7a565b905060008161318e68327cb2734119d3b7a9601e1b87615794565b61319891906157c1565b600484015490915061147e9082906001600160a01b0316886140cf565b600260c954036132075760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cf2565b600260c955565b60975460ff16156119ba5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610cf2565b600080610b7d60017fd5ec53cc5875be7de9fa162234144bc5c71b4ebad2607fd6e72e68038a0e4eca615900565b600080610b7d60017ff2b245feeb42e92aedfd7870377f08ee43c2d83f1add271009599c7c6f1e7f04615900565b6000816000036132c257506000610b7d565b610c7583836132d086613a7a565b614188565b60006132df613020565b90506132f56001600160a01b03851683856141d8565b6040516370a0823160e01b81526001600160a01b038516906370a0823190613321903090600401615110565b602060405180830381865afa15801561333e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061336291906154f6565b6001600160a01b039094166000908152600390910160205260409020929092555050565b600160c955565b60006060600061339b6137cf565b9050806000015481600201808054806020026020016040519081016040528092919081815260200182805480156133fb57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116133dd575b5050505050905092509250509091565b600080613416613282565b905060006134226137cf565b905060008260040160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561347b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349f91906154f6565b9050806000036134b457506000949350505050565b6001600160a01b038516600090815260058301602052604090205460018301546114748383615794565b6000806135086000851160405180604001604052806002815260200161033360f41b81525061422e565b60008361351d5761351887613a7a565b613526565b61352687613964565b905060008186116135405761353b8683615900565b61354a565b61354a8287615900565b9050600086613559838a615794565b61356391906157c1565b905060008615613576575086831161357b565b508287115b999098509650505050505050565b60008260000361359b5750600061147e565b60006135a5613254565b6001600160a01b0388166000908152600d82016020526040812054919250906135cf908590615900565b9050806000036135e45760009250505061147e565b620f42406135f28287615794565b6135fc91906157c1565b9998505050505050505050565b613611614a3d565b600061361b613254565b9050613625614a3d565b6001600160a01b038616600081815260128401602090815260408083208915158085529083528184205486830190815294845260138701835281842090845290915290205460608301525160808501518551613684929190600161424d565b8152606081015160a0850151855161369f929190600061424d565b602082015295945050505050565b6000806136b8613282565b905060006136c46137cf565b905060008260040160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561371d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061374191906154f6565b9050841561375a5761375386826158d3565b905061377b565b8086111561376e5760009350505050610c75565b6137788682615900565b90505b8060000361378f5760009350505050610c75565b6001600160a01b038716600090815260058301602052604090205460018301546137b98383615794565b6137c391906157c1565b98975050505050505050565b600080610b7d60017f715b167b7990ed658f7189ec1ff00e4d03196ef2816956a21e1391dfc17fa859615900565b604080516001600160601b0319606096871b811660208084019190915295871b811660348301529390951b9092166048850152151560f81b605c8401528051808403603d018152605d9093019052815191012090565b600061385d613254565b602083015190915015611844578160200151816014016000856001600160a01b03166001600160a01b0316815260200190815260200160002060008282546138a591906158d3565b9091555050505050565b606580546001600160a01b03191690556116498161426f565b6001600160a01b03163b151590565b600054610100900460ff166138fe5760405162461bcd60e51b8152600401610cf29061593a565b6119ba6142c1565b600054610100900460ff1661392d5760405162461bcd60e51b8152600401610cf29061593a565b6119ba6142f1565b600054610100900460ff1661395c5760405162461bcd60e51b8152600401610cf29061593a565b6119ba614324565b60008061396f613282565b60038101546040516303b6b4bb60e51b81529192506001600160a01b0316906376d69760906139a59086906000906004016156cf565b602060405180830381865afa158015610d4f573d6000803e3d6000fd5b6000806139cd613020565b6001600160a01b03841660008181526003830160205260408082205490516370a0823160e01b8152939450929091906370a0823190613a10903090600401615110565b602060405180830381865afa158015613a2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a5191906154f6565b6001600160a01b0386166000908152600385016020526040902081905590506113f88282615900565b600080613a85613282565b60038101546040516303b6b4bb60e51b81529192506001600160a01b0316906376d69760906139a59086906001906004016156cf565b600080613ac6613254565b905082600003613ad95750600092915050565b60006127108260050154612710613af09190615900565b613afa9086615794565b613b0491906157c1565b905061104d8185615900565b613b1861320e565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613b4d3390565b604051613b5a9190615110565b60405180910390a1565b613b6c61434b565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33613b4d565b6000613ba7613254565b6001600160a01b0384166000908152600e8201602052604081205491925003613c0657600a810154613bd981426157c1565b613be39190615794565b6001600160a01b039093166000908152600e909101602052604090209190915550565b600a8101546001600160a01b0384166000908152600e830160205260409020544291613c31916158d3565b1115613c3c57505050565b6000613c4784614394565b6001600160a01b0385166000908152600d84016020526040902054909150613c709082906158d3565b6001600160a01b0385166000908152600d84016020526040902055600a820154613c9a81426157c1565b613ca49190615794565b6001600160a01b0385166000908152600e84016020908152604080832093909355600d850190528190205490517fb3adf30b9391ba27493eb9bebf178ba6471ef14184e403152c47ab1d6a5844b091613cff9187919061559e565b60405180910390a150505050565b6000806000613d1a613020565b90506000613d26613254565b90506000613d368a8a8a8a6137fd565b600081815260088501602052604081208054600282015493945090928291613d61918d91908d6134de565b915091506000613d748460000154613abb565b90506000613d8e8f8f8f8f89600001548a60030154613589565b90506000613e038e8e88604051806101200160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815260200160078201548152602001600882015481525050613609565b8051909150600090613e1584866158d3565b613e1f91906158d3565b905085158015613e325750848760010154105b15613e9c578c15613e855760405162461bcd60e51b815260206004820152601f60248201527f5661756c743a206c6f737365732065786365656420636f6c6c61746572616c006044820152606401610cf2565b600160009b509b50505050505050505050506125a8565b600187015486613eb957858860010154613eb69190615900565b90505b81811015613f25578d15613f0f5760405162461bcd60e51b815260206004820152601d60248201527f5661756c743a20666565732065786365656420636f6c6c61746572616c0000006044820152606401610cf2565b60019c509a506125a89950505050505050505050565b60068a0154613f3490836158d3565b811015613fb1578d15613f9b5760405162461bcd60e51b815260206004820152602960248201527f5661756c743a206c69717569646174696f6e20666565732065786365656420636044820152681bdb1b185d195c985b60ba1b6064820152608401610cf2565b5060019b5099506125a898505050505050505050565b8754613fc09061271090615794565b8b54613fcc9083615794565b1015614034578d1561401e5760405162461bcd60e51b815260206004820152601b60248201527a15985d5b1d0e881b585e13195d995c9859d948195e18d959591959602a1b6044820152606401610cf2565b5060029b5099506125a898505050505050505050565b5060009b5099505050505050505050509550959350505050565b60006001600160ff1b038211156140b85760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b6064820152608401610cf2565b5090565b6000808212156140b85781600003610b7d565b6000806140da613282565b905060006140e66137cf565b60048301549091506000906001600160a01b03878116911614614123576001600160a01b0386166000908152600483016020526040902054614126565b60125b60048401549091506000906001600160a01b03878116911614614163576001600160a01b0386166000908152600484016020526040902054614166565b60125b905061417382600a6158c7565b61417e82600a6158c7565b6137b9908a615794565b60008260000361419a57506000610c75565b60006141a46137cf565b6001600160a01b0386166000908152600482016020526040902054909150836141ce82600a6158c7565b6114749087615794565b6118448363a9059cbb60e01b84846040516024016141f792919061559e565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261459f565b80826118445760405162461bcd60e51b8152600401610cf291906159a9565b60008061425a8587615900565b905061147e848266038d7ea4c6800086614671565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166142e85760405162461bcd60e51b8152600401610cf29061593a565b6119ba336138af565b600054610100900460ff166143185760405162461bcd60e51b8152600401610cf29061593a565b6097805460ff19169055565b600054610100900460ff166133865760405162461bcd60e51b8152600401610cf29061593a565b60975460ff166119ba5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610cf2565b60008061439f613254565b905060006143ab613020565b905060006143b76137cf565b905060006143c3613282565b600a8501546001600160a01b0388166000908152600e8701602052604090205491925042916143f291906158d3565b11156144045750600095945050505050565b600a8401546001600160a01b0387166000908152600e860160205260408120549091906144319042615900565b61443b91906157c1565b6001600160a01b03881660009081526007850160205260408120549192509060ff1661446b5785600b0154614471565b85600c01545b600284015460405163019c8a3b60e11b8152600160048201529192506000916001600160a01b0390911690630339147690602401602060405180830381865afa1580156144c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144e691906154f6565b905060006144f38a613964565b6001600160a01b038b16600090815260048801602052604081205491925061451c82600a6158c7565b6001600160a01b038d16600090815260068b0160205260409020546145419085615794565b61454b91906157c1565b9050801580614558575083155b1561456f575060009b9a5050505050505050505050565b838661457b8388615794565b6145859190615794565b61458f91906157c1565b9c9b505050505050505050505050565b60006145f4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166146989092919063ffffffff16565b805190915015611844578080602001905181019061461291906159dc565b6118445760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610cf2565b6000811561468d5761468685858560016146a7565b905061104d565b6113f88585856146f8565b606061104d84846000856147a7565b6000806146b58686866146f8565b905060018360028111156146cb576146cb6159f9565b1480156146e85750600084806146e3576146e36157ab565b868809115b156113f85761147e6001826158d3565b600080806000198587098587029250828110838203039150508060000361473257838281614728576147286157ab565b0492505050610c75565b80841161473e57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6060824710156148085760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610cf2565b600080866001600160a01b031685876040516148249190615a0f565b60006040518083038185875af1925050503d8060008114614861576040519150601f19603f3d011682016040523d82523d6000602084013e614866565b606091505b5091509150611ce987838387606083156148df5782516000036148d85761488c856138c8565b6148d85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cf2565b508161104d565b61104d83838151156148f45781518083602001fd5b8060405162461bcd60e51b8152600401610cf291906159a9565b604051806080016040528060008152602001600015158152602001600015158152602001600081525090565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040518060c0016040528060006001600160a01b031681526020016000815260200160008152602001600081526020016000151581526020016000151581525090565b60405180610120016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600015158152602001600081525090565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b80356001600160a01b0381168114614a7c57600080fd5b919050565b600060208284031215614a9357600080fd5b610c7582614a65565b801515811461164957600080fd5b8035614a7c81614a9c565b60008060008060008060c08789031215614ace57600080fd5b614ad787614a65565b95506020870135945060408701359350606087013592506080870135614afc81614a9c565b915060a0870135614b0c81614a9c565b809150509295509295509295565b60008060408385031215614b2d57600080fd5b614b3683614a65565b946020939093013593505050565b60008060408385031215614b5757600080fd5b614b6083614a65565b91506020830135614b7081614a9c565b809150509250929050565b6000604082018483526020604081850152818551808452606086019150828701935060005b81811015614bc55784516001600160a01b031683529383019391830191600101614ba0565b5090979650505050505050565b60008060008060808587031215614be857600080fd5b614bf185614a65565b9350614bff60208601614a65565b9250614c0d60408601614a65565b91506060850135614c1d81614a9c565b939692955090935050565b600080600060608486031215614c3d57600080fd5b614c4684614a65565b9250602084013591506040840135614c5d81614a9c565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b0381118282101715614ca157614ca1614c68565b60405290565b604051601f8201601f191681016001600160401b0381118282101715614ccf57614ccf614c68565b604052919050565b60006001600160401b03821115614cf057614cf0614c68565b5060051b60200190565b600082601f830112614d0b57600080fd5b81356020614d20614d1b83614cd7565b614ca7565b82815260059290921b84018101918181019086841115614d3f57600080fd5b8286015b84811015614d6157614d5481614a65565b8352918301918301614d43565b509695505050505050565b600082601f830112614d7d57600080fd5b81356020614d8d614d1b83614cd7565b82815260059290921b84018101918181019086841115614dac57600080fd5b8286015b84811015614d615780358352918301918301614db0565b600080600060608486031215614ddc57600080fd5b83356001600160401b0380821115614df357600080fd5b614dff87838801614cfa565b94506020860135915080821115614e1557600080fd5b614e2187838801614d6c565b93506040860135915080821115614e3757600080fd5b50614e4486828701614d6c565b9150509250925092565b600080600080600060a08688031215614e6657600080fd5b614e6f86614a65565b9450614e7d60208701614a65565b9350614e8b60408701614a65565b9250606086013591506080860135614ea281614a9c565b809150509295509295909350565b93151584529115156020840152151560408301521515606082015260800190565b600082601f830112614ee257600080fd5b81356020614ef2614d1b83614cd7565b82815260059290921b84018101918181019086841115614f1157600080fd5b8286015b84811015614d61578035614f2881614a9c565b8352918301918301614f15565b600080600060608486031215614f4a57600080fd5b83356001600160401b0380821115614f6157600080fd5b614f6d87838801614cfa565b94506020860135915080821115614f8357600080fd5b614f8f87838801614cfa565b93506040860135915080821115614fa557600080fd5b50614e4486828701614ed1565b60008060408385031215614fc557600080fd5b614fce83614a65565b9150614fdc60208401614a65565b90509250929050565b600080600080600080600060e0888a03121561500057600080fd5b61500988614a65565b965061501760208901614a65565b955061502560408901614a65565b9450606088013593506080880135925060a088013561504381614a9c565b915061505160c08901614a65565b905092959891949750929550565b6000806000806080858703121561507557600080fd5b61507e85614a65565b935060208501356001600160401b038082111561509a57600080fd5b6150a688838901614cfa565b945060408701359150808211156150bc57600080fd5b6150c888838901614cfa565b935060608701359150808211156150de57600080fd5b506150eb87828801614ed1565b91505092959194509250565b60006020828403121561510957600080fd5b5035919050565b6001600160a01b0391909116815260200190565b60008060006060848603121561513957600080fd5b61514284614a65565b925061515060208501614a65565b915061515e60408501614a65565b90509250925092565b60e08101610b7d828480516001600160a01b03908116835260208083015182169084015260408083015182169084015260608083015182169084015260808083015182169084015260a08281015182169084015260c09182015116910152565b600060e082840312156151d957600080fd5b60405160e081016001600160401b03811182821017156151fb576151fb614c68565b60405261520783614a65565b815261521560208401614a65565b602082015261522660408401614a65565b604082015261523760608401614a65565b606082015261524860808401614a65565b608082015261525960a08401614a65565b60a082015261526a60c08401614a65565b60c08201529392505050565b60006020828403121561528857600080fd5b8135610c7581614a9c565b600061012082840312156152a657600080fd5b6152ae614c7e565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c08201526152fa60e08401614aaa565b60e0820152610100928301359281019290925250919050565b81516001600160a01b0316815260208083015190820152604080830151908201526060808301519082015260808083015115159082015260a08083015115159082015260c08101610b7d565b600080600080600060a0868803121561537757600080fd5b61538086614a65565b945061538e60208701614a65565b935061539c60408701614a65565b925060608601356153ac81614a9c565b91506080860135614ea281614a9c565b600080600080608085870312156153d257600080fd5b84356153dd81614a9c565b935060208501356153ed81614a9c565b92506040850135614c0d81614a9c565b6101208101610b7d8284805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e0810151151560e08301526101008082015181840152505050565b600080600080600060a0868803121561547b57600080fd5b61548486614a65565b945061549260208701614a65565b93506154a060408701614a65565b925060608601356154b081614a9c565b91506154be60808701614a65565b90509295509295909350565b6000806000606084860312156154df57600080fd5b505081359360208301359350604090920135919050565b60006020828403121561550857600080fd5b5051919050565b600061010080838503121561552357600080fd5b604051908101906001600160401b038211818310171561554557615545614c68565b81604052835181526020840151602082015260408401516040820152606084015160608201526080840151608082015260a084015160a082015260c084015160c082015260e084015160e0820152809250505092915050565b6001600160a01b03929092168252602082015260400190565b6020808252601390820152720d2dcc6dedce6d2e6e8cadce840d8cadccee8d606b1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201615622576156226155fa565b5060010190565b600081518084526020808501945080840160005b838110156156595781518752958201959082019060010161563d565b509495945050505050565b606080825284519082018190526000906020906080840190828801845b828110156156a65781516001600160a01b031684529284019290840190600101615681565b505050838103828501526156ba8187615629565b915050828103604084015261147e8185615629565b6001600160a01b039290921682521515602082015260400190565b60208082526015908201527415985d5b1d0e88185b1c9958591e481c185d5cd959605a1b604082015260600190565b6000610120828403121561572c57600080fd5b615734614c7e565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b8082028115828204841417610b7d57610b7d6155fa565b634e487b7160e01b600052601260045260246000fd5b6000826157de57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561581e578160001904821115615804576158046155fa565b8085161561581157918102915b93841c93908002906157e8565b509250929050565b60008261583557506001610b7d565b8161584257506000610b7d565b816001811461585857600281146158625761587e565b6001915050610b7d565b60ff841115615873576158736155fa565b50506001821b610b7d565b5060208310610133831016604e8410600b84101617156158a1575081810a610b7d565b6158ab83836157e3565b80600019048211156158bf576158bf6155fa565b029392505050565b6000610c758383615826565b80820180821115610b7d57610b7d6155fa565b6001600160a01b0392831681529116602082015260400190565b81810381811115610b7d57610b7d6155fa565b8181036000831280158383131683831282161715615933576159336155fa565b5092915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60005b838110156159a0578181015183820152602001615988565b50506000910152565b60208152600082518060208401526159c8816040850160208701615985565b601f01601f19169190910160400192915050565b6000602082840312156159ee57600080fd5b8151610c7581614a9c565b634e487b7160e01b600052602160045260246000fd5b60008251615a21818460208701615985565b919091019291505056fea26469706673582212207d0ff70aea193d611058345ada9a87535f03c734d7175dd3fc0237ad2bae319d64736f6c63430008130033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061038a5760003560e01c806381a612d6116101dc57806381a612d6146107f957806382a084901461080c5780638585f4d21461081f57806387ed714414610832578063891c5a731461084557806389201c761461085857806389c98c061461086b5780638b4f3b2c146108735780638da5cb5b14610886578063933162121461089b5780639498a8ca146108ae57806397a6760c146108c1578063a39fac12146108d4578063a5e90eee146108e9578063b364accb146108fc578063b375d49214610926578063bd2521ac14610939578063bedb86fb1461094c578063c14bfd361461095f578063c3c6467414610972578063cb67e3b114610985578063cb8d3b1f146109a5578063d2fa635e146109b8578063d3127e63146109cb578063d3405289146109de578063d54d5a9f146109f1578063d66b000d14610a04578063d91ed30a14610a17578063db8d55f114610a2a578063de2ea94814610a3f578063dfa2ce1c14610a52578063e124e6d214610a65578063e30c397814610a78578063e67f59a714610a80578063ef12c67e14610a93578063f2fde38b14610aa6578063f36b242514610ab9578063f3ae241514610adc578063fe75443314610aef57600080fd5b806304fef1db1461038f57806306bfa938146103b557806308a99df9146104295780630a48d5a9146104595780630ea8b3bf1461046c578063164e68de146104745780631f69565f1461048757806321f9dace146104d15780632c668ec1146104e65780632ef94257146104f9578063322b3d9814610501578063336e94d3146105295780633459a82f1461053c5780633a05dcc1146105525780633cb6b783146105655780633e3002b6146105a25780633e3ca9d3146105b5578063417584ee146105cd5780634453a374146105e057806348d91abf146105f35780634a3f088d1461060657806351723e8214610686578063529a356f146106995780635534aa5f146106ac57806356ac1d5c146106bf57806356b6d0d5146106d757806358e86625146106df5780635c401439146106f25780635c975abb146107055780635e76ad54146107105780635f7bc1191461072357806360986cef1461073657806362883ccd14610749578063655a62571461075c578063711e6190146107bb578063715018a6146107ce57806379ba5097146107d65780638129fc1c146107de578063817bb857146107e6575b600080fd5b6103a261039d366004614a81565b610b02565b6040519081526020015b60405180910390f35b6103c86103c3366004614a81565b610b83565b6040516103ac9190600061010082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015292915050565b61043c610437366004614ab5565b610c43565b6040805193845291151560208401521515908201526060016103ac565b6103a2610467366004614b1a565b610c69565b6103a2610c7c565b6103a2610482366004614a81565b610c8e565b61049a610495366004614a81565b610d73565b6040516103ac9190815181526020808301511515908201526040808301511515908201526060918201519181019190915260800190565b6104e46104df366004614b44565b610d84565b005b6103a26104f4366004614b1a565b610dc6565b6103a2610dd2565b61051461050f366004614a81565b610eb9565b604080519283526020830191909152016103ac565b6104e4610537366004614ab5565b610ef8565b610544610fa8565b6040516103ac929190614b7b565b6103a2610560366004614a81565b610fbc565b610578610573366004614bd2565b610fc7565b6040805195151586526020860194909452928401919091526060830152608082015260a0016103ac565b6103a26105b0366004614c28565b611040565b6105bd611055565b60405190151581526020016103ac565b6104e46105db366004614dc7565b611068565b6104e46105ee366004614b44565b611197565b6104e4610601366004614e4e565b61120c565b610619610614366004614bd2565b611314565b6040516103ac9190600061012082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525092915050565b6103a2610694366004614bd2565b611401565b6105bd6106a7366004614a81565b611488565b6103a26106ba366004614a81565b6114b8565b6106c76114e5565b6040516103ac9493929190614eb0565b6103a261151f565b6103a26106ed366004614a81565b611534565b6105bd610700366004614a81565b611568565b60975460ff166105bd565b6105bd61071e366004614a81565b611598565b6104e4610731366004614a81565b6115c8565b6104e4610744366004614f35565b61164c565b6103a2610757366004614a81565b611849565b61076f61076a366004614a81565b611876565b6040516103ac9190600060c082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b6103a26107c9366004614fb2565b611910565b6104e46119a8565b6104e46119bc565b6104e4611a37565b6103a26107f4366004614fb2565b611b5e565b6103a2610807366004614a81565b611bcf565b6103a261081a366004614fe5565b611bda565b6104e461082d366004614b1a565b611cf4565b6103a2610840366004614a81565b611d35565b6103a2610853366004614a81565b611d62565b6103a261086636600461505f565b611d8f565b6103a2611eae565b6104e46108813660046150f7565b611ec3565b61088e611f2b565b6040516103ac9190615110565b6103a26108a9366004615124565b611f3a565b6105146108bc366004614a81565b612035565b6104e46108cf366004614a81565b612074565b6108dc6120bb565b6040516103ac9190615167565b6104e46108f7366004614b44565b612135565b61090f61090a366004614a81565b612176565b6040805192151583526020830191909152016103ac565b6104e46109343660046151c7565b612229565b6103a2610947366004614bd2565b612268565b6104e461095a366004615276565b6122f7565b6104e461096d366004615293565b612315565b6104e4610980366004614b44565b612354565b610998610993366004614a81565b61238d565b6040516103ac9190615313565b6104e46109b3366004614b44565b612426565b6104e46109c63660046150f7565b6124eb565b6104e46109d93660046150f7565b61252b565b6104e46109ec366004614fb2565b61256b565b6105146109ff36600461535f565b612593565b6104e4610a12366004614b1a565b6125b2565b6104e4610a253660046153bc565b6125f3565b610a3261266e565b6040516103ac91906153fd565b6104e4610a4d366004615463565b6126ea565b6105bd610a60366004614fb2565b612794565b6103a2610a73366004614a81565b6127d3565b61088e6127de565b6104e4610a8e366004614a81565b6127ed565b6104e4610aa1366004614dc7565b61282c565b6104e4610ab4366004614a81565b61286f565b610ac16128d5565b604080519384526020840192909252908201526060016103ac565b6105bd610aea366004614a81565b6128ff565b6104e4610afd3660046154ca565b61292f565b6040516304fef1db60e01b81526000907310671bc2f07593e208b1762b101fdfea8689067e906304fef1db90610b3c908590600401615110565b602060405180830381865af4158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d91906154f6565b92915050565b610bcb60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405162d7f52760e31b81527310671bc2f07593e208b1762b101fdfea8689067e906306bfa93890610c01908590600401615110565b61010060405180830381865af4158015610c1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d919061550f565b6000806000610c568989898989896129d5565b9250925092505b96509650969350505050565b6000610c758383612fc4565b9392505050565b600080610c87613020565b5492915050565b600080610c9961304e565b33600090815260058201602052604090205490915060ff16610cfb5760405162461bcd60e51b81526020600482015260166024820152753737ba103bb4ba34323930bb903332b29030b236b4b760511b60448201526064015b60405180910390fd5b604051630b27346f60e11b81527310671bc2f07593e208b1762b101fdfea8689067e9063164e68de90610d32908690600401615110565b602060405180830381865af4158015610d4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7591906154f6565b610d7b61490e565b610b7d8261307c565b610d8c6130fc565b6000610d9661304e565b6001600160a01b039390931660009081526005909301602052506040909120805460ff1916911515919091179055565b6000610c75838361315b565b6000610ddc6131b5565b610de461320e565b6000610dee613254565b90506000610dfa613282565b3360009081526014840160205260409020549091508015610ea8576005820154610e2d906001600160a01b0316826132b0565b6005830154909150610e49906001600160a01b031682336132d5565b33600081815260148501602052604080822091909155600584015490517f80814eb170ced28dd8eb312180365462e4b9878baf473b6d4302dde21011a89f91610e9f916001600160a01b0390911690859061559e565b60405180910390a25b92505050610eb6600160c955565b90565b6000806000610ec6613254565b6001600160a01b039094166000908152600f850160209081526040808320546010909701909152902054939492505050565b610f006130fc565b73ab4eb71128d543c4beeabf5845d51e2e858abb9e63669c5bfe6040518060c00160405280896001600160a01b0316815260200188815260200187815260200186815260200185151581526020018415158152506040518263ffffffff1660e01b8152600401610f709190615313565b60006040518083038186803b158015610f8857600080fd5b505af4158015610f9c573d6000803e3d6000fd5b50505050505050505050565b60006060610fb461338d565b915091509091565b6000610b7d8261340b565b600080600080600080610fdc8a8a8a8a611314565b9050600080610ff58a846000015185604001518c6134de565b9150915060006110118d8d8d8d88600001518960600151613589565b905060006110208c8c87613609565b8051602090910151949f939e50919c50909a509198509650505050505050565b600061104d8484846136ad565b949350505050565b600061106360975460ff1690565b905090565b6110706130fc565b81518351148015611082575080518351145b61109e5760405162461bcd60e51b8152600401610cf2906155b7565b60005b8351811015611126578281815181106110bc576110bc6155e4565b602002602001015160001415806110ed57508181815181106110e0576110e06155e4565b6020026020010151600014155b1561111457611114848281518110611107576111076155e4565b6020026020010151612074565b8061111e81615610565b9150506110a1565b506040516320bac27760e11b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063417584ee9061116290869086908690600401615664565b60006040518083038186803b15801561117a57600080fd5b505af415801561118e573d6000803e3d6000fd5b50505050505050565b61119f6130fc565b604051631114e8dd60e21b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e90634453a374906111d890859085906004016156cf565b60006040518083038186803b1580156111f057600080fd5b505af4158015611204573d6000803e3d6000fd5b505050505050565b6112146131b5565b61121c61320e565b61122583611598565b156112425760405162461bcd60e51b8152600401610cf2906156ea565b6040805160a0810182526001600160a01b03878116825286811660208301908152868216838501908152606084018781528615156080860190815295516306109c4f60e31b8152945184166004860152915183166024850152519091166044830152516064820152905115156084820152738d8fb6320ab54f5ba37c532c91978f3b61f1487790633084e2789060a4015b60006040518083038186803b1580156112eb57600080fd5b505af41580156112ff573d6000803e3d6000fd5b5050505061130d600160c955565b5050505050565b6113636040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051634a3f088d60e01b81526001600160a01b0380871660048301528086166024830152841660448201528215156064820152738d8fb6320ab54f5ba37c532c91978f3b61f1487790634a3f088d9060840161012060405180830381865af41580156113d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f89190615719565b95945050505050565b60008061141086868686611314565b905060008160200151116114605760405162461bcd60e51b81526020600482015260176024820152762b30bab63a1d1034b73b30b634b2103837b9b4ba34b7b760491b6044820152606401610cf2565b602081015181516114749061271090615794565b61147e91906157c1565b9695505050505050565b60008061149361304e565b6001600160a01b03909316600090815260029093016020525050604090205460ff1690565b6000806114c3613020565b6001600160a01b03909316600090815260049093016020525050604090205490565b60008060008060006114f561304e565b5460ff62010000820481169763010000008304821697508183169650610100909204169350915050565b60008061152a613020565b6002015492915050565b60008061153f6137cf565b6001600160a01b0384166000908152600482016020526040902054909150610c7590600a6158c7565b60008061157361304e565b6001600160a01b03909316600090815260059093016020525050604090205460ff1690565b6000806115a361304e565b6001600160a01b03909316600090815260049093016020525050604090205460ff1690565b6115d06131b5565b6115d861320e565b604051635f7bc11960e01b81527377cdd46002cd7ae83a72622127acb2f7ae53a7da90635f7bc1199061160f908490600401615110565b60006040518083038186803b15801561162757600080fd5b505af415801561163b573d6000803e3d6000fd5b50505050611649600160c955565b50565b6116546131b5565b61165c61320e565b8151835114801561166e575080518351145b61168a5760405162461bcd60e51b8152600401610cf2906155b7565b6000805b84518110156118035760006116f0338784815181106116af576116af6155e4565b60200260200101518785815181106116c9576116c96155e4565b60200260200101518786815181106116e3576116e36155e4565b60200260200101516137fd565b905060006116fc613020565b600083815260088201602052604081208054929350919003611720575050506117f1565b60006117c5888681518110611737576117376155e4565b6020026020010151888781518110611751576117516155e4565b602002602001015184604051806101200160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815260200160078201548152602001600882015481525050613609565b90506117d13382613853565b6060810151600583015560208101516117ea90876158d3565b9550505050505b806117fb81615610565b91505061168e565b5060405181815233907f953615e1b3502c33b28f9e7bab58b4a721d74651f2a323a199ba094aae3b2f4c9060200160405180910390a250611844600160c955565b505050565b600080611854613254565b6001600160a01b03909316600090815260149093016020525050604090205490565b61187e61493a565b6000611888613020565b905061189261493a565b6001600160a01b039093166000818152600b8301602090815260408083205487528383526009850182528083205487830152838352600a850182528083205487820152838352600e85018252808320546060880152838352600c85018252808320546080880152928252600d90930190925290205460a08301525090565b600061191a6131b5565b61192261320e565b60405163234a0b6b60e01b81527377cdd46002cd7ae83a72622127acb2f7ae53a7da9063234a0b6b9061195b90869086906004016158e6565b602060405180830381865af4158015611978573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199c91906154f6565b9050610b7d600160c955565b6119b06130fc565b6119ba60006138af565b565b33806119c66127de565b6001600160a01b031614611a2e5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610cf2565b611649816138af565b600054610100900460ff1615808015611a575750600054600160ff909116105b80611a785750611a66306138c8565b158015611a78575060005460ff166001145b611adb5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610cf2565b6000805460ff191660011790558015611afe576000805461ff0019166101001790555b611b066138d7565b611b0e613906565b611b16613935565b8015611649576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b6000611b686131b5565b611b7061320e565b611b7983611598565b15611b965760405162461bcd60e51b8152600401610cf2906156ea565b604051639f2a556160e01b81527377cdd46002cd7ae83a72622127acb2f7ae53a7da90639f2a55619061195b90869086906004016158e6565b6000610b7d82613964565b6000611be46131b5565b611bec61320e565b6040805160e0810182526001600160a01b038a8116825289811660208301908152898216838501908152606084018a8152608085018a815289151560a0870190815289861660c0880190815297516335dde3a160e11b815296518616600488015293518516602487015291518416604486015251606485015251608484015251151560a4830152915190911660c4820152738d8fb6320ab54f5ba37c532c91978f3b61f1487790636bbbc7429060e401602060405180830381865af4158015611cb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cdd91906154f6565b9050611ce9600160c955565b979650505050505050565b611cfc6130fc565b6040516342c2fa6960e11b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e90638585f4d2906111d8908590859060040161559e565b600080611d40613020565b6001600160a01b03909316600090815260079093016020525050604090205490565b600080611d6d613254565b6001600160a01b03909316600090815260099093016020525050604090205490565b600082518451148015611da3575081518451145b611dbf5760405162461bcd60e51b8152600401610cf2906155b7565b6000805b8551811015611ea4576000611e1888888481518110611de457611de46155e4565b6020026020010151888581518110611dfe57611dfe6155e4565b60200260200101518886815181106116e3576116e36155e4565b90506000611e24613020565b600083815260088201602052604081208054929350919003611e4857505050611e92565b6000611e79898681518110611e5f57611e5f6155e4565b6020026020010151898781518110611751576117516155e4565b9050806020015186611e8b91906158d3565b9550505050505b80611e9c81615610565b915050611dc3565b5095945050505050565b600080611eb9613020565b6001015492915050565b611ecb6130fc565b6040516322d3cecb60e21b81526004810182905273ab4eb71128d543c4beeabf5845d51e2e858abb9e90638b4f3b2c906024015b60006040518083038186803b158015611f1757600080fd5b505af415801561130d573d6000803e3d6000fd5b6033546001600160a01b031690565b6000611f446131b5565b611f4c61320e565b611f5584611598565b158015611f685750611f6683611598565b155b611f845760405162461bcd60e51b8152600401610cf2906156ea565b6000611f8f856139c2565b60405160016276c04560e11b031981526001600160a01b0380881660048301528087166024830152604482018390528516606482015290915073ff6ec5be53b532e4b5aac66dab16fd54575e63239063ff127f7690608401602060405180830381865af4158015612004573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202891906154f6565b915050610c75600160c955565b6000806000612042613254565b6001600160a01b039094166000908152600d85016020908152604080832054600e909701909152902054939492505050565b61207c6131b5565b61208461320e565b6040516325e99d8360e21b815273a71a515de4acf04fb66e5923e5c0bd3146794c05906397a6760c9061160f908490600401615110565b6120c3614970565b60006120cd613282565b90506120d7614970565b81546001600160a01b0390811682526001830154811660208301526002830154811660408301526003830154811660608301526004830154811660808301526005830154811660a083015260069092015490911660c0820152919050565b61213d6130fc565b6040516352f4877760e11b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063a5e90eee906111d890859085906004016156cf565b6000806000612183613020565b6001600160a01b0385166000908152600c820160205260408120549192508190036121b5575060009485945092505050565b60006121c086613a7a565b6001600160a01b0387166000908152600d850160205260408120549192508282116121f4576121ef8284615900565b6121fe565b6121fe8383615900565b905060008261220d8387615794565b61221791906157c1565b93909211989297509195505050505050565b6122316130fc565b604051631395c1d560e31b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e90639cae0ea890611eff908490600401615167565b600080612273613254565b9050600061228387878787611314565b905060006122948260000151613abb565b905060006122ae8989898987600001518860600151613589565b905060006122bd888886613609565b600686015481519192506000916122d485876158d3565b6122de91906158d3565b6122e891906158d3565b9b9a5050505050505050505050565b6122ff6130fc565b801561230d57611649613b10565b611649613b64565b61231d6130fc565b60405163903fe8f160e01b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063903fe8f190611eff9084906004016153fd565b6040516330f1919d60e21b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063c3c64674906111d890859085906004016156cf565b6123956149ac565b600061239f6137cf565b90506123a96149ac565b6001600160a01b0390931680845260008181526004830160209081526040808320548288015283835260058501825280832054818801528383526006850182528083205460608801528383526007850182528083205460ff9081161515608089015293835260089094019052919091205416151560a08301525090565b60006124306120bb565b905061243a611f2b565b6001600160a01b0316336001600160a01b0316148061246e575080602001516001600160a01b0316336001600160a01b0316145b6124b25760405162461bcd60e51b81526020600482015260156024820152742b30bab63a1d1034b73b30b634b21031b0b63632b960591b6044820152606401610cf2565b60405163cb8d3b1f60e01b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063cb8d3b1f9061116290869086906004016156cf565b6124f36130fc565b60405163697d31af60e11b81526004810182905273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063d2fa635e90602401611eff565b6125336130fc565b60405163d3127e6360e01b81526004810182905273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063d3127e6390602401611eff565b6125736131b5565b61257b61320e565b6125858282613b9d565b61258f600160c955565b5050565b6000806125a38787878787613d0d565b915091505b9550959350505050565b6125ba6130fc565b60405163d66b000d60e01b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063d66b000d906111d8908590859060040161559e565b6125fb6130fc565b604051636c8f698560e11b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063d91ed30a90612638908790879087908790600401614eb0565b60006040518083038186803b15801561265057600080fd5b505af4158015612664573d6000803e3d6000fd5b5050505050505050565b6126766149ef565b6000612680613254565b905061268a6149ef565b8154815260018201546020820152600282015460408201526003820154606082015260048201546080820152600582015460a0820152600682015460c0820152600782015460ff16151560e0820152600890910154610100820152919050565b6126f26131b5565b6126fa61320e565b6040805160a0810182526001600160a01b03878116825286811660208301908152868216838501908152861515606085019081528684166080860190815295516317fd4e1d60e01b81529451841660048601529151831660248501525182166044840152511515606483015291519091166084820152738d8fb6320ab54f5ba37c532c91978f3b61f14877906317fd4e1d9060a4016112d3565b60008061279f61304e565b6001600160a01b03948516600090815260019190910160209081526040808320959096168252939093525050205460ff1690565b6000610b7d82613a7a565b6065546001600160a01b031690565b6127f56130fc565b60405163e67f59a760e01b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063e67f59a790611eff908490600401615110565b6128346130fc565b604051637789633f60e11b815273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063ef12c67e9061116290869086908690600401615664565b6128776130fc565b606580546001600160a01b0319166001600160a01b03831690811790915561289d611f2b565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6000806000806128e3613254565b600a810154600b820154600c9092015490969195509350915050565b60008061290a61304e565b6001600160a01b03909316600090815260039093016020525050604090205460ff1690565b6129376130fc565b60008060006129446128d5565b92509250925082600014158061295957508115155b8061296357508015155b1561298f576000612972613282565b600581015490915061298d906001600160a01b03168061256b565b505b60405163fe75443360e01b815260048101879052602481018690526044810185905273ab4eb71128d543c4beeabf5845d51e2e858abb9e9063fe75443390606401610f70565b6000806000612a2d604051806101200160405280600081526020016000151581526020016000151581526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6000612a37613254565b90506000612a43613020565b90506000612a4f613282565b600784015490915060ff16612a71578a60008096509650965050505050610c5d565b6001600160a01b038d16600090815260048301602052604090205460608501819052612a9e908d906158d3565b608085015288612add5783606001518c1115612ac7576000608085015260608401519b50612add565b8b8460600151612ad79190615900565b60808501525b612ae68d61340b565b60a0850152878015612af6575088155b15612b0d57612b078d8d60016136ad565b60a08501525b8360a00151600003612b2c578a60008096509650965050505050610c5d565b612b39846060015161404e565b612b468560a0015161404e565b612b509190615913565b60c0850152612b608d8d8b6136ad565b60e0850152878015612b70575088155b15612b8457612b7e8d61340b565b60e08501525b8360e00151600003612ba3578a60008096509650965050505050610c5d565b612bb0846080015161404e565b612bbd8560e0015161404e565b612bc79190615913565b6101008501528815612d8657612be08460c001516140bc565b612bee8561010001516140bc565b1015612ca05760008460e00151612c088660c001516140bc565b612c12908d615794565b612c1c91906157c1565b90508b8111612c3457612c2f818d615900565b612c37565b60005b855260c08501516000138015612c535750600085610100015113155b80612c73575060008560c00151138015612c735750600085610100015112155b15612c8b576001602086015260006040860152612c9a565b60006020860152600160408601525b50612f49565b60006002612cb28661010001516140bc565b612cbf8760c001516140bc565b612cc991906158d3565b612cd391906157c1565b90508460e00151811115612ce8575060e08401515b60e0850151600090612cfa838e615794565b612d0491906157c1565b905060008660c00151128015612d205750600086610100015113155b80612d40575060008660c00151138015612d405750600086610100015112155b15612d6457612d4f818e6158d3565b86526000602087018190526040870152612d7f565b612d6e818e6158d3565b865260006020870152600160408701525b5050612f49565b60008460c00151128015612da05750600084610100015113155b80612dc0575060008460c00151138015612dc05750600084610100015112155b15612ec657612dd28460c001516140bc565b612de08561010001516140bc565b1015612e3f5760008460e00151612dfa8660c001516140bc565b612e04908d615794565b612e0e91906157c1565b90508b8111612e2657612e21818d615900565b612e29565b60005b8552506000602085018190526040850152612f49565b60006002612e518661010001516140bc565b612e5e8760c001516140bc565b612e6891906158d3565b612e7291906157c1565b90508460e00151811115612e87575060e08401515b60e0850151600090612e99838e615794565b612ea391906157c1565b9050612eaf818e6158d3565b865250506000602085018190526040850152612f49565b60006002612ed88661010001516140bc565b612ee58760c001516140bc565b612eef91906158d3565b612ef991906157c1565b90508460e00151811115612f0e575060e08401515b60e0850151600090612f20838e615794565b612f2a91906157c1565b9050612f36818e6158d3565b8652505060006020850152600160408501525b60058101546001600160a01b038e8116911614612f6857600060208501525b88158015612f85575060058101546001600160a01b038e81169116145b15612fa257600883015484518590612f9e9083906158d3565b9052505b505081516020830151604090930151909c929b50995090975050505050505050565b600081600003612fd657506000610b7d565b6000612fe06137cf565b90506000612fed85613964565b6001600160a01b038616600090815260048401602052604090205490915061301681600a6158c7565b6114748387615794565b600080610b7d60017f0a6857889562f1d40df97cc84c0aafc7cd2f70e5ce2a65223fd89163f728a8d0615900565b600080610b7d60017fec44c653f648cabed39c0c4eda0c4e30c82628a3e671ccda53ec8daf9f3b79c7615900565b61308461490e565b600061308e6137cf565b604080516080810182526001600160a01b0390951660008181526004840160209081528382205488528282526003850181528382205460ff9081161515828a015283835260078601825284832054161515888501529181526006909301905290205460608401525090919050565b33613105611f2b565b6001600160a01b0316146119ba5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610cf2565b600080613166613282565b9050600061317385613a7a565b905060008161318e68327cb2734119d3b7a9601e1b87615794565b61319891906157c1565b600484015490915061147e9082906001600160a01b0316886140cf565b600260c954036132075760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cf2565b600260c955565b60975460ff16156119ba5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610cf2565b600080610b7d60017fd5ec53cc5875be7de9fa162234144bc5c71b4ebad2607fd6e72e68038a0e4eca615900565b600080610b7d60017ff2b245feeb42e92aedfd7870377f08ee43c2d83f1add271009599c7c6f1e7f04615900565b6000816000036132c257506000610b7d565b610c7583836132d086613a7a565b614188565b60006132df613020565b90506132f56001600160a01b03851683856141d8565b6040516370a0823160e01b81526001600160a01b038516906370a0823190613321903090600401615110565b602060405180830381865afa15801561333e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061336291906154f6565b6001600160a01b039094166000908152600390910160205260409020929092555050565b600160c955565b60006060600061339b6137cf565b9050806000015481600201808054806020026020016040519081016040528092919081815260200182805480156133fb57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116133dd575b5050505050905092509250509091565b600080613416613282565b905060006134226137cf565b905060008260040160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561347b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349f91906154f6565b9050806000036134b457506000949350505050565b6001600160a01b038516600090815260058301602052604090205460018301546114748383615794565b6000806135086000851160405180604001604052806002815260200161033360f41b81525061422e565b60008361351d5761351887613a7a565b613526565b61352687613964565b905060008186116135405761353b8683615900565b61354a565b61354a8287615900565b9050600086613559838a615794565b61356391906157c1565b905060008615613576575086831161357b565b508287115b999098509650505050505050565b60008260000361359b5750600061147e565b60006135a5613254565b6001600160a01b0388166000908152600d82016020526040812054919250906135cf908590615900565b9050806000036135e45760009250505061147e565b620f42406135f28287615794565b6135fc91906157c1565b9998505050505050505050565b613611614a3d565b600061361b613254565b9050613625614a3d565b6001600160a01b038616600081815260128401602090815260408083208915158085529083528184205486830190815294845260138701835281842090845290915290205460608301525160808501518551613684929190600161424d565b8152606081015160a0850151855161369f929190600061424d565b602082015295945050505050565b6000806136b8613282565b905060006136c46137cf565b905060008260040160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561371d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061374191906154f6565b9050841561375a5761375386826158d3565b905061377b565b8086111561376e5760009350505050610c75565b6137788682615900565b90505b8060000361378f5760009350505050610c75565b6001600160a01b038716600090815260058301602052604090205460018301546137b98383615794565b6137c391906157c1565b98975050505050505050565b600080610b7d60017f715b167b7990ed658f7189ec1ff00e4d03196ef2816956a21e1391dfc17fa859615900565b604080516001600160601b0319606096871b811660208084019190915295871b811660348301529390951b9092166048850152151560f81b605c8401528051808403603d018152605d9093019052815191012090565b600061385d613254565b602083015190915015611844578160200151816014016000856001600160a01b03166001600160a01b0316815260200190815260200160002060008282546138a591906158d3565b9091555050505050565b606580546001600160a01b03191690556116498161426f565b6001600160a01b03163b151590565b600054610100900460ff166138fe5760405162461bcd60e51b8152600401610cf29061593a565b6119ba6142c1565b600054610100900460ff1661392d5760405162461bcd60e51b8152600401610cf29061593a565b6119ba6142f1565b600054610100900460ff1661395c5760405162461bcd60e51b8152600401610cf29061593a565b6119ba614324565b60008061396f613282565b60038101546040516303b6b4bb60e51b81529192506001600160a01b0316906376d69760906139a59086906000906004016156cf565b602060405180830381865afa158015610d4f573d6000803e3d6000fd5b6000806139cd613020565b6001600160a01b03841660008181526003830160205260408082205490516370a0823160e01b8152939450929091906370a0823190613a10903090600401615110565b602060405180830381865afa158015613a2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a5191906154f6565b6001600160a01b0386166000908152600385016020526040902081905590506113f88282615900565b600080613a85613282565b60038101546040516303b6b4bb60e51b81529192506001600160a01b0316906376d69760906139a59086906001906004016156cf565b600080613ac6613254565b905082600003613ad95750600092915050565b60006127108260050154612710613af09190615900565b613afa9086615794565b613b0491906157c1565b905061104d8185615900565b613b1861320e565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613b4d3390565b604051613b5a9190615110565b60405180910390a1565b613b6c61434b565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33613b4d565b6000613ba7613254565b6001600160a01b0384166000908152600e8201602052604081205491925003613c0657600a810154613bd981426157c1565b613be39190615794565b6001600160a01b039093166000908152600e909101602052604090209190915550565b600a8101546001600160a01b0384166000908152600e830160205260409020544291613c31916158d3565b1115613c3c57505050565b6000613c4784614394565b6001600160a01b0385166000908152600d84016020526040902054909150613c709082906158d3565b6001600160a01b0385166000908152600d84016020526040902055600a820154613c9a81426157c1565b613ca49190615794565b6001600160a01b0385166000908152600e84016020908152604080832093909355600d850190528190205490517fb3adf30b9391ba27493eb9bebf178ba6471ef14184e403152c47ab1d6a5844b091613cff9187919061559e565b60405180910390a150505050565b6000806000613d1a613020565b90506000613d26613254565b90506000613d368a8a8a8a6137fd565b600081815260088501602052604081208054600282015493945090928291613d61918d91908d6134de565b915091506000613d748460000154613abb565b90506000613d8e8f8f8f8f89600001548a60030154613589565b90506000613e038e8e88604051806101200160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815260200160078201548152602001600882015481525050613609565b8051909150600090613e1584866158d3565b613e1f91906158d3565b905085158015613e325750848760010154105b15613e9c578c15613e855760405162461bcd60e51b815260206004820152601f60248201527f5661756c743a206c6f737365732065786365656420636f6c6c61746572616c006044820152606401610cf2565b600160009b509b50505050505050505050506125a8565b600187015486613eb957858860010154613eb69190615900565b90505b81811015613f25578d15613f0f5760405162461bcd60e51b815260206004820152601d60248201527f5661756c743a20666565732065786365656420636f6c6c61746572616c0000006044820152606401610cf2565b60019c509a506125a89950505050505050505050565b60068a0154613f3490836158d3565b811015613fb1578d15613f9b5760405162461bcd60e51b815260206004820152602960248201527f5661756c743a206c69717569646174696f6e20666565732065786365656420636044820152681bdb1b185d195c985b60ba1b6064820152608401610cf2565b5060019b5099506125a898505050505050505050565b8754613fc09061271090615794565b8b54613fcc9083615794565b1015614034578d1561401e5760405162461bcd60e51b815260206004820152601b60248201527a15985d5b1d0e881b585e13195d995c9859d948195e18d959591959602a1b6044820152606401610cf2565b5060029b5099506125a898505050505050505050565b5060009b5099505050505050505050509550959350505050565b60006001600160ff1b038211156140b85760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b6064820152608401610cf2565b5090565b6000808212156140b85781600003610b7d565b6000806140da613282565b905060006140e66137cf565b60048301549091506000906001600160a01b03878116911614614123576001600160a01b0386166000908152600483016020526040902054614126565b60125b60048401549091506000906001600160a01b03878116911614614163576001600160a01b0386166000908152600484016020526040902054614166565b60125b905061417382600a6158c7565b61417e82600a6158c7565b6137b9908a615794565b60008260000361419a57506000610c75565b60006141a46137cf565b6001600160a01b0386166000908152600482016020526040902054909150836141ce82600a6158c7565b6114749087615794565b6118448363a9059cbb60e01b84846040516024016141f792919061559e565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261459f565b80826118445760405162461bcd60e51b8152600401610cf291906159a9565b60008061425a8587615900565b905061147e848266038d7ea4c6800086614671565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166142e85760405162461bcd60e51b8152600401610cf29061593a565b6119ba336138af565b600054610100900460ff166143185760405162461bcd60e51b8152600401610cf29061593a565b6097805460ff19169055565b600054610100900460ff166133865760405162461bcd60e51b8152600401610cf29061593a565b60975460ff166119ba5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610cf2565b60008061439f613254565b905060006143ab613020565b905060006143b76137cf565b905060006143c3613282565b600a8501546001600160a01b0388166000908152600e8701602052604090205491925042916143f291906158d3565b11156144045750600095945050505050565b600a8401546001600160a01b0387166000908152600e860160205260408120549091906144319042615900565b61443b91906157c1565b6001600160a01b03881660009081526007850160205260408120549192509060ff1661446b5785600b0154614471565b85600c01545b600284015460405163019c8a3b60e11b8152600160048201529192506000916001600160a01b0390911690630339147690602401602060405180830381865afa1580156144c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144e691906154f6565b905060006144f38a613964565b6001600160a01b038b16600090815260048801602052604081205491925061451c82600a6158c7565b6001600160a01b038d16600090815260068b0160205260409020546145419085615794565b61454b91906157c1565b9050801580614558575083155b1561456f575060009b9a5050505050505050505050565b838661457b8388615794565b6145859190615794565b61458f91906157c1565b9c9b505050505050505050505050565b60006145f4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166146989092919063ffffffff16565b805190915015611844578080602001905181019061461291906159dc565b6118445760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610cf2565b6000811561468d5761468685858560016146a7565b905061104d565b6113f88585856146f8565b606061104d84846000856147a7565b6000806146b58686866146f8565b905060018360028111156146cb576146cb6159f9565b1480156146e85750600084806146e3576146e36157ab565b868809115b156113f85761147e6001826158d3565b600080806000198587098587029250828110838203039150508060000361473257838281614728576147286157ab565b0492505050610c75565b80841161473e57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6060824710156148085760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610cf2565b600080866001600160a01b031685876040516148249190615a0f565b60006040518083038185875af1925050503d8060008114614861576040519150601f19603f3d011682016040523d82523d6000602084013e614866565b606091505b5091509150611ce987838387606083156148df5782516000036148d85761488c856138c8565b6148d85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cf2565b508161104d565b61104d83838151156148f45781518083602001fd5b8060405162461bcd60e51b8152600401610cf291906159a9565b604051806080016040528060008152602001600015158152602001600015158152602001600081525090565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040518060c0016040528060006001600160a01b031681526020016000815260200160008152602001600081526020016000151581526020016000151581525090565b60405180610120016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600015158152602001600081525090565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b80356001600160a01b0381168114614a7c57600080fd5b919050565b600060208284031215614a9357600080fd5b610c7582614a65565b801515811461164957600080fd5b8035614a7c81614a9c565b60008060008060008060c08789031215614ace57600080fd5b614ad787614a65565b95506020870135945060408701359350606087013592506080870135614afc81614a9c565b915060a0870135614b0c81614a9c565b809150509295509295509295565b60008060408385031215614b2d57600080fd5b614b3683614a65565b946020939093013593505050565b60008060408385031215614b5757600080fd5b614b6083614a65565b91506020830135614b7081614a9c565b809150509250929050565b6000604082018483526020604081850152818551808452606086019150828701935060005b81811015614bc55784516001600160a01b031683529383019391830191600101614ba0565b5090979650505050505050565b60008060008060808587031215614be857600080fd5b614bf185614a65565b9350614bff60208601614a65565b9250614c0d60408601614a65565b91506060850135614c1d81614a9c565b939692955090935050565b600080600060608486031215614c3d57600080fd5b614c4684614a65565b9250602084013591506040840135614c5d81614a9c565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b0381118282101715614ca157614ca1614c68565b60405290565b604051601f8201601f191681016001600160401b0381118282101715614ccf57614ccf614c68565b604052919050565b60006001600160401b03821115614cf057614cf0614c68565b5060051b60200190565b600082601f830112614d0b57600080fd5b81356020614d20614d1b83614cd7565b614ca7565b82815260059290921b84018101918181019086841115614d3f57600080fd5b8286015b84811015614d6157614d5481614a65565b8352918301918301614d43565b509695505050505050565b600082601f830112614d7d57600080fd5b81356020614d8d614d1b83614cd7565b82815260059290921b84018101918181019086841115614dac57600080fd5b8286015b84811015614d615780358352918301918301614db0565b600080600060608486031215614ddc57600080fd5b83356001600160401b0380821115614df357600080fd5b614dff87838801614cfa565b94506020860135915080821115614e1557600080fd5b614e2187838801614d6c565b93506040860135915080821115614e3757600080fd5b50614e4486828701614d6c565b9150509250925092565b600080600080600060a08688031215614e6657600080fd5b614e6f86614a65565b9450614e7d60208701614a65565b9350614e8b60408701614a65565b9250606086013591506080860135614ea281614a9c565b809150509295509295909350565b93151584529115156020840152151560408301521515606082015260800190565b600082601f830112614ee257600080fd5b81356020614ef2614d1b83614cd7565b82815260059290921b84018101918181019086841115614f1157600080fd5b8286015b84811015614d61578035614f2881614a9c565b8352918301918301614f15565b600080600060608486031215614f4a57600080fd5b83356001600160401b0380821115614f6157600080fd5b614f6d87838801614cfa565b94506020860135915080821115614f8357600080fd5b614f8f87838801614cfa565b93506040860135915080821115614fa557600080fd5b50614e4486828701614ed1565b60008060408385031215614fc557600080fd5b614fce83614a65565b9150614fdc60208401614a65565b90509250929050565b600080600080600080600060e0888a03121561500057600080fd5b61500988614a65565b965061501760208901614a65565b955061502560408901614a65565b9450606088013593506080880135925060a088013561504381614a9c565b915061505160c08901614a65565b905092959891949750929550565b6000806000806080858703121561507557600080fd5b61507e85614a65565b935060208501356001600160401b038082111561509a57600080fd5b6150a688838901614cfa565b945060408701359150808211156150bc57600080fd5b6150c888838901614cfa565b935060608701359150808211156150de57600080fd5b506150eb87828801614ed1565b91505092959194509250565b60006020828403121561510957600080fd5b5035919050565b6001600160a01b0391909116815260200190565b60008060006060848603121561513957600080fd5b61514284614a65565b925061515060208501614a65565b915061515e60408501614a65565b90509250925092565b60e08101610b7d828480516001600160a01b03908116835260208083015182169084015260408083015182169084015260608083015182169084015260808083015182169084015260a08281015182169084015260c09182015116910152565b600060e082840312156151d957600080fd5b60405160e081016001600160401b03811182821017156151fb576151fb614c68565b60405261520783614a65565b815261521560208401614a65565b602082015261522660408401614a65565b604082015261523760608401614a65565b606082015261524860808401614a65565b608082015261525960a08401614a65565b60a082015261526a60c08401614a65565b60c08201529392505050565b60006020828403121561528857600080fd5b8135610c7581614a9c565b600061012082840312156152a657600080fd5b6152ae614c7e565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c08201526152fa60e08401614aaa565b60e0820152610100928301359281019290925250919050565b81516001600160a01b0316815260208083015190820152604080830151908201526060808301519082015260808083015115159082015260a08083015115159082015260c08101610b7d565b600080600080600060a0868803121561537757600080fd5b61538086614a65565b945061538e60208701614a65565b935061539c60408701614a65565b925060608601356153ac81614a9c565b91506080860135614ea281614a9c565b600080600080608085870312156153d257600080fd5b84356153dd81614a9c565b935060208501356153ed81614a9c565b92506040850135614c0d81614a9c565b6101208101610b7d8284805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e0810151151560e08301526101008082015181840152505050565b600080600080600060a0868803121561547b57600080fd5b61548486614a65565b945061549260208701614a65565b93506154a060408701614a65565b925060608601356154b081614a9c565b91506154be60808701614a65565b90509295509295909350565b6000806000606084860312156154df57600080fd5b505081359360208301359350604090920135919050565b60006020828403121561550857600080fd5b5051919050565b600061010080838503121561552357600080fd5b604051908101906001600160401b038211818310171561554557615545614c68565b81604052835181526020840151602082015260408401516040820152606084015160608201526080840151608082015260a084015160a082015260c084015160c082015260e084015160e0820152809250505092915050565b6001600160a01b03929092168252602082015260400190565b6020808252601390820152720d2dcc6dedce6d2e6e8cadce840d8cadccee8d606b1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201615622576156226155fa565b5060010190565b600081518084526020808501945080840160005b838110156156595781518752958201959082019060010161563d565b509495945050505050565b606080825284519082018190526000906020906080840190828801845b828110156156a65781516001600160a01b031684529284019290840190600101615681565b505050838103828501526156ba8187615629565b915050828103604084015261147e8185615629565b6001600160a01b039290921682521515602082015260400190565b60208082526015908201527415985d5b1d0e88185b1c9958591e481c185d5cd959605a1b604082015260600190565b6000610120828403121561572c57600080fd5b615734614c7e565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b8082028115828204841417610b7d57610b7d6155fa565b634e487b7160e01b600052601260045260246000fd5b6000826157de57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561581e578160001904821115615804576158046155fa565b8085161561581157918102915b93841c93908002906157e8565b509250929050565b60008261583557506001610b7d565b8161584257506000610b7d565b816001811461585857600281146158625761587e565b6001915050610b7d565b60ff841115615873576158736155fa565b50506001821b610b7d565b5060208310610133831016604e8410600b84101617156158a1575081810a610b7d565b6158ab83836157e3565b80600019048211156158bf576158bf6155fa565b029392505050565b6000610c758383615826565b80820180821115610b7d57610b7d6155fa565b6001600160a01b0392831681529116602082015260400190565b81810381811115610b7d57610b7d6155fa565b8181036000831280158383131683831282161715615933576159336155fa565b5092915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60005b838110156159a0578181015183820152602001615988565b50506000910152565b60208152600082518060208401526159c8816040850160208701615985565b601f01601f19169190910160400192915050565b6000602082840312156159ee57600080fd5b8151610c7581614a9c565b634e487b7160e01b600052602160045260246000fd5b60008251615a21818460208701615985565b919091019291505056fea26469706673582212207d0ff70aea193d611058345ada9a87535f03c734d7175dd3fc0237ad2bae319d64736f6c63430008130033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.