Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
contract Governable {
address public gov;
constructor() public {
gov = msg.sender;
}
modifier onlyGov() {
require(msg.sender == gov, "Governable: forbidden");
_;
}
function setGov(address _gov) external onlyGov {
gov = _gov;
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
import "./IVaultUtils.sol";
interface IVault {
function isInitialized() external view returns (bool);
function isSwapEnabled() external view returns (bool);
function isLeverageEnabled() external view returns (bool);
function setVaultUtils(IVaultUtils _vaultUtils) external;
function setError(uint256 _errorCode, string calldata _error) external;
function router() external view returns (address);
function usdq() external view returns (address);
function gov() external view returns (address);
function vaultUtils() external view returns (IVaultUtils);
function whitelistedTokenCount() external view returns (uint256);
function maxLeverage() external view returns (uint256);
function minProfitTime() external view returns (uint256);
function hasDynamicFees() external view returns (bool);
function fundingInterval() external view returns (uint256);
function totalTokenWeights() external view returns (uint256);
function getTargetUsdqAmount(address _token) external view returns (uint256);
function inManagerMode() external view returns (bool);
function inPrivateLiquidationMode() external view returns (bool);
function maxGasPrice() external view returns (uint256);
function approvedRouters(address _account, address _router) external view returns (bool);
function isLiquidator(address _account) external view returns (bool);
function isManager(address _account) external view returns (bool);
function minProfitBasisPoints(address _token) external view returns (uint256);
function tokenBalances(address _token) external view returns (uint256);
function lastFundingTimes(address _token) external view returns (uint256);
function setMaxLeverage(uint256 _maxLeverage) external;
function setInManagerMode(bool _inManagerMode) external;
function setManager(address _manager, bool _isManager) external;
function setIsSwapEnabled(bool _isSwapEnabled) external;
function setIsLeverageEnabled(bool _isLeverageEnabled) external;
function setMaxGasPrice(uint256 _maxGasPrice) external;
function setUsdqAmount(address _token, uint256 _amount) external;
function setBufferAmount(address _token, uint256 _amount) external;
function setMaxGlobalShortSize(address _token, uint256 _amount) external;
function setInPrivateLiquidationMode(bool _inPrivateLiquidationMode) external;
function setLiquidator(address _liquidator, bool _isActive) external;
function setFundingRate(uint256 _fundingInterval, uint256 _fundingRateFactor, uint256 _stableFundingRateFactor) external;
function setFees(
uint256 _taxBasisPoints,
uint256 _stableTaxBasisPoints,
uint256 _mintBurnFeeBasisPoints,
uint256 _swapFeeBasisPoints,
uint256 _stableSwapFeeBasisPoints,
uint256 _marginFeeBasisPoints,
uint256 _liquidationFeeUsd,
uint256 _minProfitTime,
bool _hasDynamicFees
) external;
function setTokenConfig(
address _token,
uint256 _tokenDecimals,
uint256 _redemptionBps,
uint256 _minProfitBps,
uint256 _maxUsdqAmount,
bool _isStable,
bool _isShortable
) external;
function setPriceFeed(address _priceFeed) external;
function withdrawFees(address _token, address _receiver) external returns (uint256);
function directPoolDeposit(address _token) external;
function buyUSDQ(address _token, address _receiver) external returns (uint256);
function sellUSDQ(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 validateLiquidation(address _account, address _collateralToken, address _indexToken, bool _isLong, bool _raise) external view returns (uint256, uint256);
function liquidatePosition(address _account, address _collateralToken, address _indexToken, bool _isLong, address _feeReceiver) external;
function tokenToUsdMin(address _token, uint256 _tokenAmount) external view returns (uint256);
function priceFeed() external view returns (address);
function fundingRateFactor() external view returns (uint256);
function stableFundingRateFactor() external view returns (uint256);
function cumulativeFundingRates(address _token) external view returns (uint256);
function getNextFundingRate(address _token) external view returns (uint256);
function getFeeBasisPoints(address _token, uint256 _usdqDelta, uint256 _feeBasisPoints, uint256 _taxBasisPoints, bool _increment) external view returns (uint256);
function liquidationFeeUsd() external view returns (uint256);
function taxBasisPoints() external view returns (uint256);
function stableTaxBasisPoints() external view returns (uint256);
function mintBurnFeeBasisPoints() external view returns (uint256);
function swapFeeBasisPoints() external view returns (uint256);
function stableSwapFeeBasisPoints() external view returns (uint256);
function marginFeeBasisPoints() external view returns (uint256);
function allWhitelistedTokensLength() external view returns (uint256);
function allWhitelistedTokens(uint256) external view returns (address);
function whitelistedTokens(address _token) external view returns (bool);
function stableTokens(address _token) external view returns (bool);
function shortableTokens(address _token) external view returns (bool);
function feeReserves(address _token) external view returns (uint256);
function globalShortSizes(address _token) external view returns (uint256);
function globalShortAveragePrices(address _token) external view returns (uint256);
function maxGlobalShortSizes(address _token) external view returns (uint256);
function tokenDecimals(address _token) external view returns (uint256);
function tokenWeights(address _token) external view returns (uint256);
function guaranteedUsd(address _token) external view returns (uint256);
function poolAmounts(address _token) external view returns (uint256);
function bufferAmounts(address _token) external view returns (uint256);
function reservedAmounts(address _token) external view returns (uint256);
function usdqAmounts(address _token) external view returns (uint256);
function maxUsdqAmounts(address _token) external view returns (uint256);
function getRedemptionAmount(address _token, uint256 _usdqAmount) external view returns (uint256);
function getMaxPrice(address _token) external view returns (uint256);
function getMinPrice(address _token) external view returns (uint256);
function getDelta(address _indexToken, uint256 _size, uint256 _averagePrice, bool _isLong, uint256 _lastIncreasedTime) external view returns (bool, uint256);
function getPosition(address _account, address _collateralToken, address _indexToken, bool _isLong) external view returns (uint256, uint256, uint256, uint256, uint256, uint256, bool, uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IVaultPriceFeed {
function adjustmentBasisPoints(address _token)
external
view
returns (uint256);
function isAdjustmentAdditive(address _token) external view returns (bool);
function setAdjustment(
address _token,
bool _isAdditive,
uint256 _adjustmentBps
) external;
function setIsSecondaryPriceEnabled(bool _isEnabled) external;
function setSpreadBasisPoints(address _token, uint256 _spreadBasisPoints)
external;
function setSpreadThresholdBasisPoints(uint256 _spreadThresholdBasisPoints)
external;
function setFavorPrimaryPrice(bool _favorPrimaryPrice) external;
function setPriceSampleSpace(uint256 _priceSampleSpace) external;
function setMaxStrictPriceDeviation(uint256 _maxStrictPriceDeviation)
external;
function getPrice(
address _token,
bool _maximise,
bool _includeAmmPrice,
bool _useSwapPricing
) 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;
function getLatestPrimaryPrice(address _token) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IVaultUtils {
function updateCumulativeFundingRate(address _collateralToken, address _indexToken) external returns (bool);
function validateIncreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _sizeDelta, bool _isLong) external view;
function validateDecreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _collateralDelta, uint256 _sizeDelta, bool _isLong, address _receiver) external view;
function validateLiquidation(address _account, address _collateralToken, address _indexToken, bool _isLong, bool _raise) external view returns (uint256, uint256);
function getEntryFundingRate(address _collateralToken, address _indexToken, bool _isLong) external view returns (uint256);
function getPositionFee(address _account, address _collateralToken, address _indexToken, bool _isLong, uint256 _sizeDelta) external view returns (uint256);
function getFundingFee(address _account, address _collateralToken, address _indexToken, bool _isLong, uint256 _size, uint256 _entryFundingRate) external view returns (uint256);
function getBuyUsdqFeeBasisPoints(address _token, uint256 _usdqAmount) external view returns (uint256);
function getSellUsdqFeeBasisPoints(address _token, uint256 _usdqAmount) external view returns (uint256);
function getSwapFeeBasisPoints(address _tokenIn, address _tokenOut, uint256 _usdqAmount) external view returns (uint256);
function getFeeBasisPoints(address _token, uint256 _usdqDelta, uint256 _feeBasisPoints, uint256 _taxBasisPoints, bool _increment) external view returns (uint256);
function getMaxAmountIn(
address _tokenIn,
address _tokenOut
) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when 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.
*/
library SafeMath {
/**
* @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) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @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 sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @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) {
// 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 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts 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) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts 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) {
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts 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 mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message 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,
string memory errorMessage
) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
import "../libraries/token/IERC20.sol";
import "../libraries/math/SafeMath.sol";
import "../core/interfaces/IVault.sol";
import "../core/interfaces/IVaultPriceFeed.sol";
import "../tokens/interfaces/IYieldTracker.sol";
import "../tokens/interfaces/IYieldToken.sol";
import "../access/Governable.sol";
contract Reader is Governable {
using SafeMath for uint256;
uint256 public constant BASIS_POINTS_DIVISOR = 10000;
uint256 public constant POSITION_PROPS_LENGTH = 9;
uint256 public constant PRICE_PRECISION = 10**30;
uint256 public constant USDQ_DECIMALS = 18;
bool public hasMaxGlobalShortSizes;
function setConfig(bool _hasMaxGlobalShortSizes) public onlyGov {
hasMaxGlobalShortSizes = _hasMaxGlobalShortSizes;
}
function getMaxAmountIn(
IVault _vault,
address _tokenIn,
address _tokenOut
) public view returns (uint256) {
uint256 priceIn = _vault.getMinPrice(_tokenIn);
uint256 priceOut = _vault.getMaxPrice(_tokenOut);
uint256 tokenInDecimals = _vault.tokenDecimals(_tokenIn);
uint256 tokenOutDecimals = _vault.tokenDecimals(_tokenOut);
uint256 amountIn;
{
uint256 poolAmount = _vault.poolAmounts(_tokenOut);
uint256 reservedAmount = _vault.reservedAmounts(_tokenOut);
uint256 bufferAmount = _vault.bufferAmounts(_tokenOut);
uint256 subAmount = reservedAmount > bufferAmount ? reservedAmount : bufferAmount;
if (subAmount >= poolAmount) {
return 0;
}
uint256 availableAmount = poolAmount.sub(subAmount);
amountIn = availableAmount.mul(priceOut).div(priceIn).mul(10**tokenInDecimals).div(10**tokenOutDecimals);
}
uint256 maxUsdqAmount = _vault.maxUsdqAmounts(_tokenIn);
if (maxUsdqAmount != 0) {
if (maxUsdqAmount < _vault.usdqAmounts(_tokenIn)) {
return 0;
}
uint256 maxAmountIn = maxUsdqAmount.sub(_vault.usdqAmounts(_tokenIn));
maxAmountIn = maxAmountIn.mul(10**tokenInDecimals).div(10**USDQ_DECIMALS);
maxAmountIn = maxAmountIn.mul(PRICE_PRECISION).div(priceIn);
if (amountIn > maxAmountIn) {
return maxAmountIn;
}
}
return amountIn;
}
function getAmountOut(
IVault _vault,
address _tokenIn,
address _tokenOut,
uint256 _amountIn
) public view returns (uint256, uint256) {
uint256 priceIn = _vault.getMinPrice(_tokenIn);
uint256 tokenInDecimals = _vault.tokenDecimals(_tokenIn);
uint256 tokenOutDecimals = _vault.tokenDecimals(_tokenOut);
uint256 feeBasisPoints;
{
uint256 usdqAmount = _amountIn.mul(priceIn).div(PRICE_PRECISION);
usdqAmount = usdqAmount.mul(10**USDQ_DECIMALS).div(10**tokenInDecimals);
bool isStableSwap = _vault.stableTokens(_tokenIn) && _vault.stableTokens(_tokenOut);
uint256 baseBps = isStableSwap ? _vault.stableSwapFeeBasisPoints() : _vault.swapFeeBasisPoints();
uint256 taxBps = isStableSwap ? _vault.stableTaxBasisPoints() : _vault.taxBasisPoints();
uint256 feesBasisPoints0 = _vault.getFeeBasisPoints(_tokenIn, usdqAmount, baseBps, taxBps, true);
uint256 feesBasisPoints1 = _vault.getFeeBasisPoints(_tokenOut, usdqAmount, baseBps, taxBps, false);
// use the higher of the two fee basis points
feeBasisPoints = feesBasisPoints0 > feesBasisPoints1 ? feesBasisPoints0 : feesBasisPoints1;
}
uint256 priceOut = _vault.getMaxPrice(_tokenOut);
uint256 amountOut = _amountIn.mul(priceIn).div(priceOut);
amountOut = amountOut.mul(10**tokenOutDecimals).div(10**tokenInDecimals);
uint256 amountOutAfterFees = amountOut.mul(BASIS_POINTS_DIVISOR.sub(feeBasisPoints)).div(BASIS_POINTS_DIVISOR);
uint256 feeAmount = amountOut.sub(amountOutAfterFees);
return (amountOutAfterFees, feeAmount);
}
function getFeeBasisPoints(
IVault _vault,
address _tokenIn,
address _tokenOut,
uint256 _amountIn
)
public
view
returns (
uint256,
uint256,
uint256
)
{
uint256 priceIn = _vault.getMinPrice(_tokenIn);
uint256 tokenInDecimals = _vault.tokenDecimals(_tokenIn);
uint256 usdqAmount = _amountIn.mul(priceIn).div(PRICE_PRECISION);
usdqAmount = usdqAmount.mul(10**USDQ_DECIMALS).div(10**tokenInDecimals);
bool isStableSwap = _vault.stableTokens(_tokenIn) && _vault.stableTokens(_tokenOut);
uint256 baseBps = isStableSwap ? _vault.stableSwapFeeBasisPoints() : _vault.swapFeeBasisPoints();
uint256 taxBps = isStableSwap ? _vault.stableTaxBasisPoints() : _vault.taxBasisPoints();
uint256 feesBasisPoints0 = _vault.getFeeBasisPoints(_tokenIn, usdqAmount, baseBps, taxBps, true);
uint256 feesBasisPoints1 = _vault.getFeeBasisPoints(_tokenOut, usdqAmount, baseBps, taxBps, false);
// use the higher of the two fee basis points
uint256 feeBasisPoints = feesBasisPoints0 > feesBasisPoints1 ? feesBasisPoints0 : feesBasisPoints1;
return (feeBasisPoints, feesBasisPoints0, feesBasisPoints1);
}
function getFees(address _vault, address[] memory _tokens) public view returns (uint256[] memory) {
uint256[] memory amounts = new uint256[](_tokens.length);
for (uint256 i = 0; i < _tokens.length; i++) {
amounts[i] = IVault(_vault).feeReserves(_tokens[i]);
}
return amounts;
}
function getTotalStaked(address[] memory _yieldTokens) public view returns (uint256[] memory) {
uint256[] memory amounts = new uint256[](_yieldTokens.length);
for (uint256 i = 0; i < _yieldTokens.length; i++) {
IYieldToken yieldToken = IYieldToken(_yieldTokens[i]);
amounts[i] = yieldToken.totalStaked();
}
return amounts;
}
function getStakingInfo(address _account, address[] memory _yieldTrackers) public view returns (uint256[] memory) {
uint256 propsLength = 2;
uint256[] memory amounts = new uint256[](_yieldTrackers.length * propsLength);
for (uint256 i = 0; i < _yieldTrackers.length; i++) {
IYieldTracker yieldTracker = IYieldTracker(_yieldTrackers[i]);
amounts[i * propsLength] = yieldTracker.claimable(_account);
amounts[i * propsLength + 1] = yieldTracker.getTokensPerInterval();
}
return amounts;
}
function getFundingRates(
address _vault,
address _weth,
address[] memory _tokens
) public view returns (uint256[] memory) {
uint256 propsLength = 2;
uint256[] memory fundingRates = new uint256[](_tokens.length * propsLength);
IVault vault = IVault(_vault);
for (uint256 i = 0; i < _tokens.length; i++) {
address token = _tokens[i];
if (token == address(0)) {
token = _weth;
}
uint256 fundingRateFactor = vault.stableTokens(token) ? vault.stableFundingRateFactor() : vault.fundingRateFactor();
uint256 reservedAmount = vault.reservedAmounts(token);
uint256 poolAmount = vault.poolAmounts(token);
if (poolAmount > 0) {
fundingRates[i * propsLength] = fundingRateFactor.mul(reservedAmount).div(poolAmount);
}
if (vault.cumulativeFundingRates(token) > 0) {
uint256 nextRate = vault.getNextFundingRate(token);
uint256 baseRate = vault.cumulativeFundingRates(token);
fundingRates[i * propsLength + 1] = baseRate.add(nextRate);
}
}
return fundingRates;
}
function getTokenSupply(IERC20 _token, address[] memory _excludedAccounts) public view returns (uint256) {
uint256 supply = _token.totalSupply();
for (uint256 i = 0; i < _excludedAccounts.length; i++) {
address account = _excludedAccounts[i];
uint256 balance = _token.balanceOf(account);
supply = supply.sub(balance);
}
return supply;
}
function getTotalBalance(IERC20 _token, address[] memory _accounts) public view returns (uint256) {
uint256 totalBalance = 0;
for (uint256 i = 0; i < _accounts.length; i++) {
address account = _accounts[i];
uint256 balance = _token.balanceOf(account);
totalBalance = totalBalance.add(balance);
}
return totalBalance;
}
function getTokenBalances(address _account, address[] memory _tokens) public view returns (uint256[] memory) {
uint256[] memory balances = new uint256[](_tokens.length);
for (uint256 i = 0; i < _tokens.length; i++) {
address token = _tokens[i];
if (token == address(0)) {
balances[i] = _account.balance;
continue;
}
balances[i] = IERC20(token).balanceOf(_account);
}
return balances;
}
function getTokenBalancesWithSupplies(address _account, address[] memory _tokens) public view returns (uint256[] memory) {
uint256 propsLength = 2;
uint256[] memory balances = new uint256[](_tokens.length * propsLength);
for (uint256 i = 0; i < _tokens.length; i++) {
address token = _tokens[i];
if (token == address(0)) {
balances[i * propsLength] = _account.balance;
balances[i * propsLength + 1] = 0;
continue;
}
balances[i * propsLength] = IERC20(token).balanceOf(_account);
balances[i * propsLength + 1] = IERC20(token).totalSupply();
}
return balances;
}
function getPrices(IVaultPriceFeed _priceFeed, address[] memory _tokens) public view returns (uint256[] memory) {
uint256 propsLength = 6;
uint256[] memory amounts = new uint256[](_tokens.length * propsLength);
for (uint256 i = 0; i < _tokens.length; i++) {
address token = _tokens[i];
amounts[i * propsLength] = _priceFeed.getPrice(token, true, true, false);
amounts[i * propsLength + 1] = _priceFeed.getPrice(token, false, true, false);
amounts[i * propsLength + 2] = _priceFeed.getPrimaryPrice(token, true);
amounts[i * propsLength + 3] = _priceFeed.getPrimaryPrice(token, false);
amounts[i * propsLength + 4] = _priceFeed.isAdjustmentAdditive(token) ? 1 : 0;
amounts[i * propsLength + 5] = _priceFeed.adjustmentBasisPoints(token);
}
return amounts;
}
function getVaultTokenInfo(
address _vault,
address _weth,
uint256 _usdqAmount,
address[] memory _tokens
) public view returns (uint256[] memory) {
uint256 propsLength = 10;
IVault vault = IVault(_vault);
IVaultPriceFeed priceFeed = IVaultPriceFeed(vault.priceFeed());
uint256[] memory amounts = new uint256[](_tokens.length * propsLength);
for (uint256 i = 0; i < _tokens.length; i++) {
address token = _tokens[i];
if (token == address(0)) {
token = _weth;
}
amounts[i * propsLength] = vault.poolAmounts(token);
amounts[i * propsLength + 1] = vault.reservedAmounts(token);
amounts[i * propsLength + 2] = vault.usdqAmounts(token);
amounts[i * propsLength + 3] = vault.getRedemptionAmount(token, _usdqAmount);
amounts[i * propsLength + 4] = vault.tokenWeights(token);
amounts[i * propsLength + 5] = vault.getMinPrice(token);
amounts[i * propsLength + 6] = vault.getMaxPrice(token);
amounts[i * propsLength + 7] = vault.guaranteedUsd(token);
amounts[i * propsLength + 8] = priceFeed.getPrimaryPrice(token, false);
amounts[i * propsLength + 9] = priceFeed.getPrimaryPrice(token, true);
}
return amounts;
}
function getFullVaultTokenInfo(
address _vault,
address _weth,
uint256 _usdqAmount,
address[] memory _tokens
) public view returns (uint256[] memory) {
uint256 propsLength = 12;
IVault vault = IVault(_vault);
IVaultPriceFeed priceFeed = IVaultPriceFeed(vault.priceFeed());
uint256[] memory amounts = new uint256[](_tokens.length * propsLength);
for (uint256 i = 0; i < _tokens.length; i++) {
address token = _tokens[i];
if (token == address(0)) {
token = _weth;
}
amounts[i * propsLength] = vault.poolAmounts(token);
amounts[i * propsLength + 1] = vault.reservedAmounts(token);
amounts[i * propsLength + 2] = vault.usdqAmounts(token);
amounts[i * propsLength + 3] = vault.getRedemptionAmount(token, _usdqAmount);
amounts[i * propsLength + 4] = vault.tokenWeights(token);
amounts[i * propsLength + 5] = vault.bufferAmounts(token);
amounts[i * propsLength + 6] = vault.maxUsdqAmounts(token);
amounts[i * propsLength + 7] = vault.getMinPrice(token);
amounts[i * propsLength + 8] = vault.getMaxPrice(token);
amounts[i * propsLength + 9] = vault.guaranteedUsd(token);
amounts[i * propsLength + 10] = priceFeed.getPrimaryPrice(token, false);
amounts[i * propsLength + 11] = priceFeed.getPrimaryPrice(token, true);
}
return amounts;
}
function getVaultTokenInfoV2(
address _vault,
address _weth,
uint256 _usdqAmount,
address[] memory _tokens
) public view returns (uint256[] memory) {
uint256 propsLength = 14;
IVault vault = IVault(_vault);
IVaultPriceFeed priceFeed = IVaultPriceFeed(vault.priceFeed());
uint256[] memory amounts = new uint256[](_tokens.length * propsLength);
for (uint256 i = 0; i < _tokens.length; i++) {
address token = _tokens[i];
if (token == address(0)) {
token = _weth;
}
uint256 maxGlobalShortSize = hasMaxGlobalShortSizes ? vault.maxGlobalShortSizes(token) : 0;
amounts[i * propsLength] = vault.poolAmounts(token);
amounts[i * propsLength + 1] = vault.reservedAmounts(token);
amounts[i * propsLength + 2] = vault.usdqAmounts(token);
amounts[i * propsLength + 3] = vault.getRedemptionAmount(token, _usdqAmount);
amounts[i * propsLength + 4] = vault.tokenWeights(token);
amounts[i * propsLength + 5] = vault.bufferAmounts(token);
amounts[i * propsLength + 6] = vault.maxUsdqAmounts(token);
amounts[i * propsLength + 7] = vault.globalShortSizes(token);
amounts[i * propsLength + 8] = maxGlobalShortSize;
amounts[i * propsLength + 9] = vault.getMinPrice(token);
amounts[i * propsLength + 10] = vault.getMaxPrice(token);
amounts[i * propsLength + 11] = vault.guaranteedUsd(token);
amounts[i * propsLength + 12] = priceFeed.getPrimaryPrice(token, false);
amounts[i * propsLength + 13] = priceFeed.getPrimaryPrice(token, true);
}
return amounts;
}
function getPositions(
address _vault,
address _account,
address[] memory _collateralTokens,
address[] memory _indexTokens,
bool[] memory _isLong
) public view returns (uint256[] memory) {
uint256[] memory amounts = new uint256[](_collateralTokens.length * POSITION_PROPS_LENGTH);
for (uint256 i = 0; i < _collateralTokens.length; i++) {
{
(
uint256 size,
uint256 collateral,
uint256 averagePrice,
uint256 entryFundingRate,
,
/* reserveAmount */
uint256 realisedPnl,
bool hasRealisedProfit,
uint256 lastIncreasedTime
) = IVault(_vault).getPosition(_account, _collateralTokens[i], _indexTokens[i], _isLong[i]);
amounts[i * POSITION_PROPS_LENGTH] = size;
amounts[i * POSITION_PROPS_LENGTH + 1] = collateral;
amounts[i * POSITION_PROPS_LENGTH + 2] = averagePrice;
amounts[i * POSITION_PROPS_LENGTH + 3] = entryFundingRate;
amounts[i * POSITION_PROPS_LENGTH + 4] = hasRealisedProfit ? 1 : 0;
amounts[i * POSITION_PROPS_LENGTH + 5] = realisedPnl;
amounts[i * POSITION_PROPS_LENGTH + 6] = lastIncreasedTime;
}
uint256 size = amounts[i * POSITION_PROPS_LENGTH];
uint256 averagePrice = amounts[i * POSITION_PROPS_LENGTH + 2];
uint256 lastIncreasedTime = amounts[i * POSITION_PROPS_LENGTH + 6];
if (averagePrice > 0) {
(bool hasProfit, uint256 delta) = IVault(_vault).getDelta(_indexTokens[i], size, averagePrice, _isLong[i], lastIncreasedTime);
amounts[i * POSITION_PROPS_LENGTH + 7] = hasProfit ? 1 : 0;
amounts[i * POSITION_PROPS_LENGTH + 8] = delta;
}
}
return amounts;
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IYieldToken {
function totalStaked() external view returns (uint256);
function stakedBalance(address _account) external view returns (uint256);
function removeAdmin(address _account) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IYieldTracker {
function claim(address _account, address _receiver) external returns (uint256);
function updateRewards(address _account) external;
function getTokensPerInterval() external view returns (uint256);
function claimable(address _account) external view returns (uint256);
}