fluid-contracts-public/contracts/periphery/resolvers/vaultPositions/main.sol
2024-07-11 13:05:09 +00:00

164 lines
6.6 KiB
Solidity

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;
import { Variables } from "./variables.sol";
import { Structs } from "./structs.sol";
import { IFluidVaultFactory } from "../../../protocols/vault/interfaces/iVaultFactory.sol";
import { Structs as VaultResolverStructs } from "../vault/structs.sol";
import { IFluidVaultResolver } from "../vault/iVaultResolver.sol";
import { IFluidVaultT1 } from "../../../protocols/vault/interfaces/iVaultT1.sol";
import { TickMath } from "../../../libraries/tickMath.sol";
contract FluidVaultPositionsResolver is Variables, Structs {
/// @notice thrown if an input param address is zero
error FluidVaultPositionsResolver__AddressZero();
/// @notice constructor sets the immutable vault resolver and vault factory address
constructor(
IFluidVaultResolver vaultResolver_,
IFluidVaultFactory vaultFactory_
) Variables(vaultResolver_, vaultFactory_) {
if (address(vaultResolver_) == address(0) || address(vaultFactory_) == address(0)) {
revert FluidVaultPositionsResolver__AddressZero();
}
}
function getAllVaultNftIds(address vault_) public view returns (uint256[] memory nftIds_) {
uint256 totalPositions_ = FACTORY.totalSupply();
/// get total positions for vault: Next 32 bits => 210-241 => Total positions
uint256 totalVaultPositions_ = (VAULT_RESOLVER.getVaultVariablesRaw(vault_) >> 210) & 0xFFFFFFFF;
nftIds_ = new uint256[](totalVaultPositions_);
// get nft Ids belonging to the vault_
uint256 nftId_;
uint256 j;
for (uint256 i; i < totalPositions_; ) {
nftId_ = FACTORY.tokenByIndex(i);
unchecked {
++i;
}
if (_vaultByNftId(nftId_) == vault_) {
nftIds_[j] = nftId_;
unchecked {
++j;
}
}
}
}
function getPositionsForNftIds(uint256[] memory nftIds_) public view returns (UserPosition[] memory positions_) {
positions_ = new UserPosition[](nftIds_.length);
for (uint256 i; i < nftIds_.length; ++i) {
address vault_ = _vaultByNftId(nftIds_[i]);
if (vault_ == address(0)) {
// should never happen but make sure it wouldn't lead to a revert
positions_[i] = UserPosition({ nftId: nftIds_[i], owner: address(0), supply: 0, borrow: 0 });
} else {
(, , uint vaultSupplyExchangePrice_, uint vaultBorrowExchangePrice_) = IFluidVaultT1(vault_)
.updateExchangePrices(VAULT_RESOLVER.getVaultVariables2Raw(vault_));
positions_[i] = _getVaultPosition(
vault_,
nftIds_[i],
vaultSupplyExchangePrice_,
vaultBorrowExchangePrice_
);
}
}
}
function getAllVaultPositions(address vault_) public view returns (UserPosition[] memory positions_) {
if (vault_ != address(0)) {
// exchange prices are always the same for the same vault
(, , uint vaultSupplyExchangePrice_, uint vaultBorrowExchangePrice_) = IFluidVaultT1(vault_)
.updateExchangePrices(VAULT_RESOLVER.getVaultVariables2Raw(vault_));
uint256 totalPositions_ = FACTORY.totalSupply();
// get total positions for vault: Next 32 bits => 210-241 => Total positions
uint256 totalVaultPositions_ = (VAULT_RESOLVER.getVaultVariablesRaw(vault_) >> 210) & 0xFFFFFFFF;
positions_ = new UserPosition[](totalVaultPositions_);
uint256 nftId_;
uint256 j;
for (uint256 i; i < totalPositions_; ) {
nftId_ = FACTORY.tokenByIndex(i);
unchecked {
++i;
}
if (_vaultByNftId(nftId_) == vault_) {
positions_[j] = _getVaultPosition(
vault_,
nftId_,
vaultSupplyExchangePrice_,
vaultBorrowExchangePrice_
);
unchecked {
++j;
}
}
}
}
}
function _vaultByNftId(uint nftId_) internal view returns (address vault_) {
uint tokenConfig_ = FACTORY.readFromStorage(keccak256(abi.encode(nftId_, 3)));
vault_ = FACTORY.getVaultAddress((tokenConfig_ >> 192) & X32);
}
function _getVaultPosition(
address vault_,
uint nftId_,
uint vaultSupplyExchangePrice_,
uint vaultBorrowExchangePrice_
) internal view returns (UserPosition memory userPosition_) {
// @dev code below based on VaultResolver `positionByNftId()`
userPosition_.nftId = nftId_;
userPosition_.owner = FACTORY.ownerOf(nftId_);
uint positionData_ = VAULT_RESOLVER.getPositionDataRaw(vault_, nftId_);
userPosition_.supply = (positionData_ >> 45) & X64;
// Converting big number into normal number
userPosition_.supply = (userPosition_.supply >> 8) << (userPosition_.supply & X8);
if ((positionData_ & 1) != 1) {
// not just a supply position
int tick_ = (positionData_ & 2) == 2 ? int((positionData_ >> 2) & X19) : -int((positionData_ >> 2) & X19);
userPosition_.borrow = (TickMath.getRatioAtTick(int24(tick_)) * userPosition_.supply) >> 96;
uint tickData_ = VAULT_RESOLVER.getTickDataRaw(vault_, tick_);
uint tickId_ = (positionData_ >> 21) & X24;
if (((tickData_ & 1) == 1) || (((tickData_ >> 1) & X24) > tickId_)) {
(tick_, userPosition_.borrow, userPosition_.supply, , ) = IFluidVaultT1(vault_).fetchLatestPosition(
tick_,
tickId_,
userPosition_.borrow,
tickData_
);
}
uint dustBorrow_ = (positionData_ >> 109) & X64;
// Converting big number into normal number
dustBorrow_ = (dustBorrow_ >> 8) << (dustBorrow_ & X8);
if (userPosition_.borrow > dustBorrow_) {
userPosition_.borrow = userPosition_.borrow - dustBorrow_;
} else {
// TODO: Make sure this is right. If borrow is less than dust debt then both gets 0
userPosition_.borrow = 0;
}
userPosition_.borrow = (userPosition_.borrow * vaultBorrowExchangePrice_) / 1e12;
}
userPosition_.supply = (userPosition_.supply * vaultSupplyExchangePrice_) / 1e12;
}
}