-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #102 from gammaswap/feat/lp-token-balance-viewer
publish package
- Loading branch information
Showing
5 changed files
with
784 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity >=0.8.0; | ||
|
||
/// @title Interface for LPViewer | ||
/// @author Daniel D. Alcarraz (https://github.com/0xDanr) | ||
/// @notice Interface used to send tokens and clear tokens and Ether from a contract | ||
interface ILPViewer { | ||
|
||
/// @dev NonStatic call to get total token balances in pools array belonging to a user. | ||
/// @dev The index of the tokenBalances array will match the index of the tokens array. | ||
/// @notice there may be more tokens than there are pools. E.g. WETH/USDC => 2 tokens and 1 pool | ||
/// @param user - address of user to get information for | ||
/// @param pools - array of addresses of pools to check token balance information in | ||
/// @return tokens - addresses of tokens in pools array | ||
/// @return tokenBalances - total balances of each token in tokens array belonging to user across all pools | ||
/// @return size - number of elements in the tokens array | ||
function tokenBalancesInPoolsNonStatic(address user, address[] calldata pools) external returns(address[] memory tokens, | ||
uint256[] memory tokenBalances, uint256 size); | ||
|
||
/// @dev Static call to get total token balances in pools array belonging to a user. | ||
/// @dev The index of the tokenBalances array will match the index of the tokens array. | ||
/// @notice there may be more tokens than there are pools. E.g. WETH/USDC => 2 tokens and 1 pool | ||
/// @param user - address of user to get information for | ||
/// @param pools - array of addresses of pools to check token balance information in | ||
/// @return tokens - addresses of tokens in pools array | ||
/// @return tokenBalances - total balances of each token in tokens array belonging to user across all pools | ||
/// @return size - number of elements in the tokens array | ||
function tokenBalancesInPools(address user, address[] calldata pools) external view returns(address[] memory tokens, | ||
uint256[] memory tokenBalances, uint256 size); | ||
|
||
/// @dev token quantity and GS LP balance information for a user in a given pool | ||
/// @param user - address of user to get information for | ||
/// @param pool - address of pool to get information for | ||
/// @return token0 - address of token0 in pool | ||
/// @return token1 - address of token1 in pool | ||
/// @return token0Balance - balance of token0 in pool belonging to user | ||
/// @return token1Balance - balance of token1 in pool belonging to user | ||
/// @return lpBalance - GS LP Balance of user | ||
function lpBalanceByPool(address user, address pool) external view returns(address token0, address token1, | ||
uint256 token0Balance, uint256 token1Balance, uint256 lpBalance); | ||
|
||
/// @dev token quantities and GS LP balance information for a user per pool | ||
/// @dev the index of each array matches the index of each pool in hte pools array | ||
/// @param user - address of user to get information for | ||
/// @param pools - addresses of pools to get information for | ||
/// @return token0 - addresses of token0 per pool | ||
/// @return token1 - addresses of token1 per pool | ||
/// @return token0Balance - array of balances of token0 per pool belonging to user | ||
/// @return token1Balance - array of balances of token1 per pool belonging to user | ||
/// @return lpBalance - array of GS LP Balances of user per pool | ||
function lpBalanceByPools(address user, address[] calldata pools) external view returns(address[] memory token0, address[] memory token1, | ||
uint256[] memory token0Balance, uint256[] memory token1Balance, uint256[] memory lpBalance); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity >=0.8.0; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
import "@gammaswap/v1-core/contracts/interfaces/IGammaPool.sol"; | ||
import "../interfaces/lens/ILPViewer.sol"; | ||
|
||
/// @title Interface for LPViewer | ||
/// @author Daniel D. Alcarraz (https://github.com/0xDanr) | ||
/// @notice Implementation contract of ILPViewer to get token balance information per user per pool | ||
/// @notice and across a given number of pools per user, aggregated or per pool | ||
contract LPViewer is ILPViewer { | ||
|
||
mapping(address => uint256) tokenIndex; | ||
|
||
constructor(){ | ||
} | ||
|
||
/// @inheritdoc ILPViewer | ||
function tokenBalancesInPoolsNonStatic(address user, address[] calldata pools) public virtual override returns(address[] memory tokens, uint256[] memory tokenBalances, uint256 size) { | ||
tokens = new address[](pools.length * 2); | ||
tokenBalances = new uint256[](pools.length * 2); | ||
size = 0; | ||
|
||
for(uint256 i; i < pools.length;) { | ||
address[] memory _tokens = IGammaPool(pools[i]).tokens(); | ||
if(tokenIndex[_tokens[0]] == 0) { | ||
tokenIndex[_tokens[0]] = size + 1; | ||
tokens[size] = _tokens[0]; | ||
unchecked{ | ||
++size; | ||
} | ||
} | ||
if(tokenIndex[_tokens[1]] == 0) { | ||
tokenIndex[_tokens[1]] = size + 1; | ||
tokens[size] = _tokens[1]; | ||
unchecked{ | ||
++size; | ||
} | ||
} | ||
unchecked{ | ||
++i; | ||
} | ||
} | ||
|
||
for(uint256 i; i < pools.length;) { | ||
(address token0, address token1, uint256 token0Balance, uint256 token1Balance,) = _lpBalanceByPool(user, pools[i]); | ||
tokenBalances[tokenIndex[token0] - 1] += token0Balance; | ||
tokenBalances[tokenIndex[token1] - 1] += token1Balance; | ||
unchecked{ | ||
++i; | ||
} | ||
} | ||
|
||
for(uint256 i; i < size;) { | ||
tokenIndex[tokens[i]] = 0; // clear the mapping | ||
unchecked{ | ||
++i; | ||
} | ||
} | ||
} | ||
|
||
/// @inheritdoc ILPViewer | ||
function tokenBalancesInPools(address user, address[] calldata pools) public virtual override view returns(address[] memory tokens, uint256[] memory tokenBalances, uint256 size) { | ||
tokens = new address[](pools.length * 2); | ||
tokenBalances = new uint256[](pools.length * 2); | ||
size = 0; | ||
for(uint256 i; i < pools.length;) { | ||
address[] memory _tokens = IGammaPool(pools[i]).tokens(); | ||
bool found0 = false; | ||
bool found1 = false; | ||
for(uint256 j; j < tokens.length;) { | ||
if(tokens[j] == _tokens[0]) { | ||
found0 = true; | ||
} else if(tokens[j] == _tokens[1]) { | ||
found1 = true; | ||
} else if(tokens[j] == address(0)) { | ||
if(!found0) { | ||
tokens[j] = _tokens[0]; | ||
found0 = true; | ||
unchecked { | ||
++size; | ||
} | ||
} else if(!found1) { | ||
tokens[j] = _tokens[1]; | ||
found1 = true; | ||
unchecked { | ||
++size; | ||
} | ||
} | ||
} | ||
if(found0 && found1) { | ||
break; | ||
} | ||
unchecked{ | ||
++j; | ||
} | ||
} | ||
unchecked{ | ||
++i; | ||
} | ||
} | ||
|
||
for(uint256 i; i < pools.length;) { | ||
(address token0, address token1, uint256 token0Balance, uint256 token1Balance,) = _lpBalanceByPool(user, pools[i]); | ||
uint256 found = 0; | ||
for(uint256 j; j < tokens.length;) { | ||
if(token0 == tokens[j]) { | ||
tokenBalances[j] += token0Balance; | ||
found++; | ||
} else if(token1 == tokens[j]) { | ||
tokenBalances[j] += token1Balance; | ||
found++; | ||
} | ||
if(found == 2) { | ||
break; | ||
} | ||
unchecked{ | ||
++j; | ||
} | ||
} | ||
unchecked{ | ||
++i; | ||
} | ||
} | ||
} | ||
|
||
/// @inheritdoc ILPViewer | ||
function lpBalanceByPool(address user, address pool) public virtual override view returns(address token0, address token1, | ||
uint256 token0Balance, uint256 token1Balance, uint256 lpBalance) { | ||
return _lpBalanceByPool(user, pool); | ||
} | ||
|
||
/// @dev token quantity and GS LP balance information for a user in a given pool | ||
/// @param user - address of user to get information for | ||
/// @param pool - address of pool to get information for | ||
/// @return token0 - address of token0 in pool | ||
/// @return token1 - address of token1 in pool | ||
/// @return token0Balance - balance of token0 in pool belonging to user | ||
/// @return token1Balance - balance of token1 in pool belonging to user | ||
/// @return lpBalance - GS LP Balance of user | ||
function _lpBalanceByPool(address user, address pool) internal virtual view returns(address token0, address token1, | ||
uint256 token0Balance, uint256 token1Balance, uint256 lpBalance) { | ||
lpBalance = IERC20(pool).balanceOf(user); | ||
uint256 lpTotalSupply = IERC20(pool).totalSupply(); | ||
|
||
address[] memory tokens = IGammaPool(pool).tokens(); | ||
token0 = tokens[0]; | ||
token1 = tokens[1]; | ||
|
||
(uint128[] memory cfmmReserves,, uint256 cfmmTotalSupply) = IGammaPool(pool).getLatestCFMMBalances(); | ||
(,uint256 lpTokenBalance,,,,) = IGammaPool(pool).getPoolBalances(); | ||
|
||
token0Balance = lpBalance * lpTokenBalance * uint256(cfmmReserves[0]) / (cfmmTotalSupply * lpTotalSupply); | ||
token1Balance = lpBalance * lpTokenBalance * uint256(cfmmReserves[1]) / (cfmmTotalSupply * lpTotalSupply); | ||
} | ||
|
||
/// @inheritdoc ILPViewer | ||
function lpBalanceByPools(address user, address[] calldata pools) public virtual override view returns(address[] memory token0, | ||
address[] memory token1, uint256[] memory token0Balance, uint256[] memory token1Balance, uint256[] memory lpBalance) { | ||
uint256 len = pools.length; | ||
token0 = new address[](len); | ||
token1 = new address[](len); | ||
token0Balance = new uint256[](len); | ||
token1Balance= new uint256[](len) ; | ||
lpBalance = new uint256[](len); | ||
for(uint256 i; i < len;) { | ||
(token0[i], token1[i], token0Balance[i], token1Balance[i], lpBalance[i]) = _lpBalanceByPool(user, pools[i]); | ||
unchecked{ | ||
++i; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity ^0.8.0; | ||
|
||
import "./TestGammaPool2.sol"; | ||
|
||
contract TestGammaPool3 is TestGammaPool2 { | ||
|
||
constructor(uint16 protocolId_, address factory_, address borrowStrategy_, address repayStrategy_, address rebalanceStrategy_, | ||
address shortStrategy_, address singleLiquidationStrategy_, address batchLiquidationStrategy_, address viewer_) | ||
TestGammaPool2(protocolId_, factory_, borrowStrategy_, repayStrategy_, rebalanceStrategy_, shortStrategy_, | ||
singleLiquidationStrategy_, batchLiquidationStrategy_, viewer_) { | ||
} | ||
|
||
function mintTo(address user, uint256 amount) external { | ||
_mint(user, amount); | ||
} | ||
|
||
function initialize(address _cfmm, address[] calldata _tokens, uint8[] calldata _decimals, uint72 _minBorrow, bytes calldata) external virtual override { | ||
cfmm = _cfmm; | ||
tokens_ = _tokens; | ||
decimals_ = _decimals; | ||
tester = msg.sender; | ||
owner = msg.sender; | ||
} | ||
|
||
function getLatestCFMMBalances() external virtual override view returns(uint128[] memory cfmmReserves, uint256 cfmmInvariant, uint256 cfmmTotalSupply) { | ||
cfmmReserves = new uint128[](2); | ||
cfmmReserves[0] = uint128(1000 * 1e18); | ||
cfmmReserves[1] = uint128(100000 * 1e18); | ||
cfmmInvariant = 10000 * 1e18; | ||
cfmmTotalSupply = 10000 * 1e18; | ||
} | ||
|
||
function getPoolBalances() external virtual override view returns(uint128[] memory tokenBalances, uint256 lpTokenBalance, uint256 lpTokenBorrowed, | ||
uint256 lpTokenBorrowedPlusInterest, uint256 borrowedInvariant, uint256 lpInvariant) { | ||
lpTokenBalance = 5000 * 1e18; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.