From 5f96c0c259f0d7a44edfa147779e7a7111255255 Mon Sep 17 00:00:00 2001 From: defibrain88 Date: Tue, 30 Apr 2024 14:16:31 +1000 Subject: [PATCH 1/9] feat: new contract for deprecated pools. Farming deprecated pools list function added --- .../powerindex-mining/DeprecatedPoolsLens.sol | 159 ++++++++++++++++++ tasks/deployDeprecatedPoolsLens.js | 21 +++ test/DeprecatedPoolsLens.test.js | 24 +++ test/PoolsLens.test.js | 2 +- 4 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 contracts/powerindex-mining/DeprecatedPoolsLens.sol create mode 100644 tasks/deployDeprecatedPoolsLens.js create mode 100644 test/DeprecatedPoolsLens.test.js diff --git a/contracts/powerindex-mining/DeprecatedPoolsLens.sol b/contracts/powerindex-mining/DeprecatedPoolsLens.sol new file mode 100644 index 0000000..5dbfb8d --- /dev/null +++ b/contracts/powerindex-mining/DeprecatedPoolsLens.sol @@ -0,0 +1,159 @@ +/* +https://powerpool.finance/ + wrrrw r wrr + ppwr rrr wppr0 prwwwrp prwwwrp wr0 + rr 0rrrwrrprpwp0 pp pr prrrr0 pp 0r prrrr0 0rwrrr pp pr prrrr0 prrrr0 r0 + rrp pr wr00rrp prwww0 pp wr pp w00r prwwwpr 0rw prwww0 pp wr pp wr r0 + r0rprprwrrrp pr0 pp wr pr pp rwwr wr 0r pp wr pr wr pr r0 + prwr wrr0wpwr 00 www0 0w0ww www0 0w 00 www0 www0 0www0 + wrr ww0rrrr +*/ + +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.11; + +import "hardhat/console.sol"; + +interface IUniswapV2Router { + function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external view returns (uint256 amountB); +} + +interface IVestedLpMining { + function pools(uint256 index) external view returns (Pool calldata); + function users(uint256 poolId, address userAddress) external view returns (miningUserDataStruct calldata); + function cvpPerBlock() external view returns (uint96); + function totalAllocPoint() external view returns (uint256); + function vestableCvp(uint256 pId, address user) external view returns (uint256); + function poolBoostByLp(uint256 pId) external view returns (uint256, uint256, uint32, uint256, uint256); + + function poolLength() external view returns(uint); + function reservoir() external view returns(address); +} + +interface ILpToken { + function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32); + function totalSupply() external view returns (uint256); + function balanceOf(address wallet) external view returns (uint256); + function symbol() external view returns (string memory); +} + +interface ERC20 { + function balanceOf(address wallet) external view returns (uint256); + function allowance(address owner, address spender) external view returns(uint256); +} + +struct Pool { + address lpToken; // address of the LP token contract + bool votesEnabled; // if the pool is enabled to write votes + uint8 poolType; // pool type (1 - Uniswap, 2 - Balancer, 3 - custom, 4 - sushi) + uint32 allocPoint; // points assigned to the pool, which affect CVPs distribution between pools + uint32 lastUpdateBlock; // latest block when the pool params which follow was updated + uint256 accCvpPerLpt; // accumulated distributed CVPs per one deposited LP token, times 1e12 +} + +struct FarmingListItem { + address lpToken; + uint256 lpAtMiningAmount; + uint256 pendedCvp; + uint256 vestableCvp; + uint256 lockedCvp; + bool isBoosted; +} + +struct miningUserDataStruct { + uint32 lastUpdateBlock; + uint32 vestingBlock; + uint96 pendedCvp; + uint96 cvpAdjust; + uint256 lptAmount; +} + +contract DeprecatedPoolsLens { + IVestedLpMining public mining; + IUniswapV2Router public uniRouter; + + address public stableAddress; + address immutable public wethAddress; + address immutable public cvpAddress; + + constructor( + IVestedLpMining _mining, + IUniswapV2Router _router, + address _wethAddress, + address _stableAddress, + address _cvpAddress + ) { + mining = _mining; + uniRouter = _router; + wethAddress = _wethAddress; + cvpAddress = _cvpAddress; + } + + // + function getFarmingList(address _user) public view returns (FarmingListItem[] memory) { + Pool[] memory pools = new Pool[](8); + pools[0] = mining.pools(6); + pools[1] = mining.pools(7); + pools[2] = mining.pools(8); + pools[3] = mining.pools(9); + pools[4] = mining.pools(10); + pools[5] = mining.pools(11); + pools[6] = mining.pools(12); + pools[7] = mining.pools(13); +// lpBoostRate + + FarmingListItem[] memory farmingPools = new FarmingListItem[](8); + + for (uint256 i = 0; i < 8; i++) { + Pool memory pool = pools[i]; + + farmingPools[i] = FarmingListItem({ + lpToken: pool.lpToken, + lpAtMiningAmount: 0, + pendedCvp: 0, + vestableCvp: 0, + lockedCvp: 0, + isBoosted: false + }); + + FarmingListItem memory farmingPool = farmingPools[i]; + + // User total lp and balance + if (_user != address(0)) { + miningUserDataStruct memory data = mining.users(i + 6, _user); + farmingPool.lpAtMiningAmount = data.lptAmount; + farmingPool.pendedCvp = data.pendedCvp; + farmingPool.vestableCvp = mining.vestableCvp(i + 6, _user); + farmingPool.lockedCvp = farmingPool.pendedCvp - farmingPool.vestableCvp; + } + + // Check if pool is boostable + (uint256 lpBoostRate,,,,) = mining.poolBoostByLp(i + 6); + if (lpBoostRate > 0) { + farmingPool.isBoosted = true; + } + } + + return farmingPools; + } + + // TODO: Remove automatic 0 pool fetch and use TokenBAddress + // Accepts amount of token A from pair and returns corresponding amount of token B from pair. (You can switch both tokens) + function getTokenBAmount(uint256 tokenAAmountWei, address tokenAAddress, address) external view returns(uint256) { + Pool memory pool = mining.pools(0); + (uint112 reserve0, uint112 reserve1,) = ILpToken(pool.lpToken).getReserves(); + uint256 reserveA; + uint256 reserveB; + + if (tokenAAddress == cvpAddress) { + reserveA = reserve0; + reserveB = reserve1; + } else if (tokenAAddress == wethAddress) { + reserveB = reserve0; + reserveA = reserve1; + } + return uniRouter.quote(tokenAAmountWei, reserveA, reserveB); + } +} diff --git a/tasks/deployDeprecatedPoolsLens.js b/tasks/deployDeprecatedPoolsLens.js new file mode 100644 index 0000000..c7ec8fe --- /dev/null +++ b/tasks/deployDeprecatedPoolsLens.js @@ -0,0 +1,21 @@ +require('@nomiclabs/hardhat-truffle5'); + + +task('deploy-deprecated-pools-lens', 'Deploy deprecated pools lens').setAction(async (__, {network}) => { + const PoolsLens = artifacts.require('DeprecatedPoolsLens'); + + const { web3 } = PoolsLens; + + const [deployer] = await web3.eth.getAccounts(); + console.log('deployer', deployer); + const sendOptions = { from: deployer }; + const poolsLens = await PoolsLens.new( + '0xF09232320eBEAC33fae61b24bB8D7CA192E58507', + '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + '0xdAC17F958D2ee523a2206206994597C13D831ec7', + '0x38e4adB44ef08F22F5B5b76A8f0c2d0dCbE7DcA1', + sendOptions, + ); + console.log('Deprecated pools lens deployed address: ', poolsLens.address); +}); diff --git a/test/DeprecatedPoolsLens.test.js b/test/DeprecatedPoolsLens.test.js new file mode 100644 index 0000000..6c71d2e --- /dev/null +++ b/test/DeprecatedPoolsLens.test.js @@ -0,0 +1,24 @@ +// const { expectRevert, time } = require('@openzeppelin/test-helpers'); +const { ethers} = require('hardhat'); +const PoolsLens = artifacts.require('DeprecatedPoolsLens'); +const zeroAddress = '0x0000000000000000000000000000000000000000'; + +describe.only('DeprecatedPoolsLens', async () => { + try { + it('chore test pass', async () => { + this.poolsLens = await PoolsLens.new( + '0xF09232320eBEAC33fae61b24bB8D7CA192E58507', + '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + '0xdAC17F958D2ee523a2206206994597C13D831ec7', + '0x38e4adB44ef08F22F5B5b76A8f0c2d0dCbE7DcA1', + ); + // const result = await this.poolsLens.getPoolData(ethers.constants.AddressZero); + const result = await this.poolsLens.getFarmingList('0x8b19f6F51501dA80FCEFb578427907f223005F7A'); + // const result = await this.poolsLens.getMiningManager(ethers.constants.AddressZero); + console.log('result console: ', result); + }); + } catch (e) { + console.error(e) + } +}); diff --git a/test/PoolsLens.test.js b/test/PoolsLens.test.js index 0f57838..69aaf7d 100644 --- a/test/PoolsLens.test.js +++ b/test/PoolsLens.test.js @@ -4,7 +4,7 @@ const { ethers} = require('hardhat'); const PoolsLens = artifacts.require('PoolsLens'); const zeroAddress = '0x0000000000000000000000000000000000000000'; -describe.only('PoolsLens', async () => { +describe('PoolsLens', async () => { try { it('Zero pool is doing fine', async () => { this.poolsLens = await PoolsLens.new( From 9b1850c52287ac26944eb2cd634a5b3db373f95e Mon Sep 17 00:00:00 2001 From: defibrain88 Date: Thu, 2 May 2024 17:15:40 +1000 Subject: [PATCH 2/9] wip --- .../powerindex-mining/DeprecatedPoolsLens.sol | 136 ++++++++++++++++-- hardhat.config.js | 1 + test/DeprecatedPoolsLens.test.js | 4 +- 3 files changed, 128 insertions(+), 13 deletions(-) diff --git a/contracts/powerindex-mining/DeprecatedPoolsLens.sol b/contracts/powerindex-mining/DeprecatedPoolsLens.sol index 5dbfb8d..43cfae7 100644 --- a/contracts/powerindex-mining/DeprecatedPoolsLens.sol +++ b/contracts/powerindex-mining/DeprecatedPoolsLens.sol @@ -27,6 +27,7 @@ interface IVestedLpMining { function totalAllocPoint() external view returns (uint256); function vestableCvp(uint256 pId, address user) external view returns (uint256); function poolBoostByLp(uint256 pId) external view returns (uint256, uint256, uint32, uint256, uint256); + function usersPoolBoost(uint256 pId, address user) external view returns(uint256 balance, uint32 lastUpdateBlock); function poolLength() external view returns(uint); function reservoir() external view returns(address); @@ -34,14 +35,18 @@ interface IVestedLpMining { interface ILpToken { function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32); + function token0() external view returns (address); + function token1() external view returns (address); function totalSupply() external view returns (uint256); function balanceOf(address wallet) external view returns (uint256); function symbol() external view returns (string memory); + function factory() external view returns (address); } interface ERC20 { function balanceOf(address wallet) external view returns (uint256); function allowance(address owner, address spender) external view returns(uint256); + function decimals() external view returns (uint8); } struct Pool { @@ -55,13 +60,27 @@ struct Pool { struct FarmingListItem { address lpToken; + uint8 poolType; + uint256 pid; uint256 lpAtMiningAmount; - uint256 pendedCvp; uint256 vestableCvp; - uint256 lockedCvp; bool isBoosted; } +struct FarmingDetail { + address lpToken; + uint8 poolType; + uint256 pid; + uint256 lpMiningBalance; + uint256 lpTotalSupply; + uint256 vestableCvp; + uint256 lpTokenUserStakedAtMining; + uint256 boostedAmount; + bool isReservoirEnough; + bool isSushi; + bool isBalancer; +} + struct miningUserDataStruct { uint32 lastUpdateBlock; uint32 vestingBlock; @@ -70,6 +89,25 @@ struct miningUserDataStruct { uint256 lptAmount; } +struct tokenInfo { + address tokenAddress; + string tokenSymbol; + uint256 reserves; + uint8 decimals; + uint256 tokenAmountPerLPToken; +} + +struct tokenRemove { + address lpToken; + uint8 poolType; + uint256 pid; + uint256 lpTotalSupply; + uint256 balance; + uint256 allowance; + tokenInfo token1; + tokenInfo token2; +} + contract DeprecatedPoolsLens { IVestedLpMining public mining; IUniswapV2Router public uniRouter; @@ -91,8 +129,7 @@ contract DeprecatedPoolsLens { cvpAddress = _cvpAddress; } - // - function getFarmingList(address _user) public view returns (FarmingListItem[] memory) { + function getFarmingList(address _user) external view returns (FarmingListItem[] memory) { Pool[] memory pools = new Pool[](8); pools[0] = mining.pools(6); pools[1] = mining.pools(7); @@ -111,10 +148,10 @@ contract DeprecatedPoolsLens { farmingPools[i] = FarmingListItem({ lpToken: pool.lpToken, + poolType: pool.poolType, + pid: i + 6, lpAtMiningAmount: 0, - pendedCvp: 0, vestableCvp: 0, - lockedCvp: 0, isBoosted: false }); @@ -122,15 +159,13 @@ contract DeprecatedPoolsLens { // User total lp and balance if (_user != address(0)) { - miningUserDataStruct memory data = mining.users(i + 6, _user); - farmingPool.lpAtMiningAmount = data.lptAmount; - farmingPool.pendedCvp = data.pendedCvp; - farmingPool.vestableCvp = mining.vestableCvp(i + 6, _user); - farmingPool.lockedCvp = farmingPool.pendedCvp - farmingPool.vestableCvp; + uint256 vestableCvp = mining.vestableCvp(farmingPool.pid, _user); + farmingPool.lpAtMiningAmount = mining.users(farmingPool.pid, _user).lptAmount; + farmingPool.vestableCvp = vestableCvp; } // Check if pool is boostable - (uint256 lpBoostRate,,,,) = mining.poolBoostByLp(i + 6); + (uint256 lpBoostRate,,,,) = mining.poolBoostByLp(farmingPool.pid); if (lpBoostRate > 0) { farmingPool.isBoosted = true; } @@ -139,6 +174,83 @@ contract DeprecatedPoolsLens { return farmingPools; } + function getFarmingDetail(address _user, uint256 _pid) external view returns (FarmingDetail memory) { + Pool memory pool = mining.pools(_pid); + + // User total lp and balance + uint256 lpTokenUserStaked; + uint256 vestableCvp; + uint boostAmount; + if (_user != address(0)) { + lpTokenUserStaked = mining.users(_pid, _user).lptAmount; + vestableCvp = mining.vestableCvp(_pid, _user); + (boostAmount,) = mining.usersPoolBoost(_pid, _user); + } + + // Check if can claim cvp + bool isReservoirEnough = vestableCvp <= ERC20(cvpAddress).balanceOf(mining.reservoir()) || vestableCvp <= ERC20(cvpAddress).allowance(mining.reservoir(), address(mining)); + + // check if 3rd party pool involved (so later it can be unwrapped to one of PowerPool pool) + bool isSushi = _pid == 11 || _pid == 12; + bool isBalancer = _pid == 7 || _pid == 8; + + return FarmingDetail({ + lpToken: pool.lpToken, + poolType: pool.poolType, + pid: _pid, + lpMiningBalance: ILpToken(pool.lpToken).balanceOf(address(mining)), + lpTotalSupply: ILpToken(pool.lpToken).totalSupply(), + vestableCvp: vestableCvp, + lpTokenUserStakedAtMining: lpTokenUserStaked, + boostedAmount: boostAmount, + isReservoirEnough: isReservoirEnough, + isSushi: isSushi, + isBalancer: isBalancer + }); + } + + + function getSushiSecondaryLiquidityRemoveInfo(address _user, uint _pid) external view returns (tokenRemove memory) { + Pool memory pool = mining.pools(_pid); + bool isSushi = pool.poolType == 4; + + address routerContract; + if (isSushi) { // sushi + routerContract = 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F; + } else { // balancer + routerContract = pool.lpToken; + } + + (uint112 reserve0, uint112 reserve1,) = ILpToken(pool.lpToken).getReserves(); + + uint8 token1Decimals = ERC20(ILpToken(pool.lpToken).token0()).decimals(); + uint8 token2Decimals = ERC20(ILpToken(pool.lpToken).token1()).decimals(); + uint256 lpTotalSupply = ILpToken(pool.lpToken).totalSupply(); + + return tokenRemove({ + lpToken: pool.lpToken, + poolType: pool.poolType, + pid: _pid, + lpTotalSupply: lpTotalSupply, + balance: ERC20(pool.lpToken).balanceOf(_user), + allowance: ERC20(pool.lpToken).allowance(_user, routerContract), + token1: tokenInfo({ + tokenAddress: ILpToken(pool.lpToken).token0(), + tokenSymbol: ILpToken(ILpToken(pool.lpToken).token0()).symbol(), + decimals: token1Decimals, + reserves: reserve0, + tokenAmountPerLPToken: (((1 ether * 10**18) / lpTotalSupply) * (reserve0 * 10**(18 - token1Decimals))) / 10**18 + }), + token2: tokenInfo({ + tokenAddress: ILpToken(pool.lpToken).token1(), + tokenSymbol: ILpToken(ILpToken(pool.lpToken).token1()).symbol(), + decimals: token2Decimals, + reserves: reserve1, + tokenAmountPerLPToken: (((1 ether * 10**18) / lpTotalSupply) * (reserve1 * 10**(18 - token2Decimals))) / 10**18 + }) + }); + } + // TODO: Remove automatic 0 pool fetch and use TokenBAddress // Accepts amount of token A from pair and returns corresponding amount of token B from pair. (You can switch both tokens) function getTokenBAmount(uint256 tokenAAmountWei, address tokenAAddress, address) external view returns(uint256) { diff --git a/hardhat.config.js b/hardhat.config.js index 37c28e9..7444c79 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -11,6 +11,7 @@ require('./tasks/fetchVaultsData4'); require('./tasks/deployMainnetPowerIndexPool'); require('./tasks/deployErc20PiptSwap'); require('./tasks/deployPoolsLens'); +require('./tasks/deployDeprecatedPoolsLens'); require('./tasks/testMainnetErc20PiptSwap'); require('./tasks/deployPoolRestrictions'); require('./tasks/deployMainnetYeti'); diff --git a/test/DeprecatedPoolsLens.test.js b/test/DeprecatedPoolsLens.test.js index 6c71d2e..c282e44 100644 --- a/test/DeprecatedPoolsLens.test.js +++ b/test/DeprecatedPoolsLens.test.js @@ -14,7 +14,9 @@ describe.only('DeprecatedPoolsLens', async () => { '0x38e4adB44ef08F22F5B5b76A8f0c2d0dCbE7DcA1', ); // const result = await this.poolsLens.getPoolData(ethers.constants.AddressZero); - const result = await this.poolsLens.getFarmingList('0x8b19f6F51501dA80FCEFb578427907f223005F7A'); + // const result = await this.poolsLens.getFarmingList('0x8b19f6F51501dA80FCEFb578427907f223005F7A'); + const result = await this.poolsLens.getSushiSecondaryLiquidityRemoveInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 11); + // const result = await this.poolsLens.getFarmingDetail('0xCce0bca1365a02e5770390165E64d1F59238D92e', 10); // const result = await this.poolsLens.getMiningManager(ethers.constants.AddressZero); console.log('result console: ', result); }); From 5888892af0c384e6a94db8b3b68c43ae9c1f1db6 Mon Sep 17 00:00:00 2001 From: defibrain88 Date: Thu, 2 May 2024 18:44:04 +1000 Subject: [PATCH 3/9] feat: Deprecated products list for earn --- .../powerindex-mining/DeprecatedPoolsLens.sol | 66 ++++++++++++++++++- test/DeprecatedPoolsLens.test.js | 4 +- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/contracts/powerindex-mining/DeprecatedPoolsLens.sol b/contracts/powerindex-mining/DeprecatedPoolsLens.sol index 43cfae7..2371125 100644 --- a/contracts/powerindex-mining/DeprecatedPoolsLens.sol +++ b/contracts/powerindex-mining/DeprecatedPoolsLens.sol @@ -41,6 +41,8 @@ interface ILpToken { function balanceOf(address wallet) external view returns (uint256); function symbol() external view returns (string memory); function factory() external view returns (address); + function getFinalTokens() external view returns (address[] memory); + function getNormalizedWeight(address) external view returns (uint256); } interface ERC20 { @@ -67,6 +69,20 @@ struct FarmingListItem { bool isBoosted; } +struct EarnListItem { + address lpToken; + uint8 poolType; + uint256 pid; + uint256 totalSupply; + uint256 userTotalBalance; // user wallet balance + user mining balance + PartOfThePool[] tokensDistribution; +} + +struct PartOfThePool { + address tokenAddress; + uint256 percent; +} + struct FarmingDetail { address lpToken; uint8 poolType; @@ -115,6 +131,7 @@ contract DeprecatedPoolsLens { address public stableAddress; address immutable public wethAddress; address immutable public cvpAddress; + mapping(uint8 => uint8) public earnPidMap; constructor( IVestedLpMining _mining, @@ -127,6 +144,11 @@ contract DeprecatedPoolsLens { uniRouter = _router; wethAddress = _wethAddress; cvpAddress = _cvpAddress; + + earnPidMap[0] = 13; + earnPidMap[1] = 6; + earnPidMap[2] = 10; + earnPidMap[3] = 9; } function getFarmingList(address _user) external view returns (FarmingListItem[] memory) { @@ -139,7 +161,6 @@ contract DeprecatedPoolsLens { pools[5] = mining.pools(11); pools[6] = mining.pools(12); pools[7] = mining.pools(13); -// lpBoostRate FarmingListItem[] memory farmingPools = new FarmingListItem[](8); @@ -209,8 +230,7 @@ contract DeprecatedPoolsLens { }); } - - function getSushiSecondaryLiquidityRemoveInfo(address _user, uint _pid) external view returns (tokenRemove memory) { + function getSecondaryLiquidityRemoveInfo(address _user, uint _pid) external view returns (tokenRemove memory) { Pool memory pool = mining.pools(_pid); bool isSushi = pool.poolType == 4; @@ -251,6 +271,46 @@ contract DeprecatedPoolsLens { }); } + function getEarnList(address _user) external view returns (EarnListItem[] memory) { + Pool[] memory pools = new Pool[](4); + pools[0] = mining.pools(13); + pools[1] = mining.pools(6); + pools[2] = mining.pools(10); + pools[3] = mining.pools(9); + + EarnListItem[] memory earnPools = new EarnListItem[](4); + for (uint8 i = 0; i < 4; i++) { + Pool memory pool = pools[i]; + + earnPools[i] = EarnListItem({ + lpToken: pool.lpToken, + poolType: pool.poolType, + pid: earnPidMap[i], + totalSupply: ILpToken(pool.lpToken).totalSupply(), + tokensDistribution: new PartOfThePool[](ILpToken(pool.lpToken).getFinalTokens().length), + userTotalBalance: 0 + }); + + EarnListItem memory earnPool = earnPools[i]; + + // User balance + if (_user != address(0)) { + earnPool.userTotalBalance = ILpToken(pool.lpToken).balanceOf(_user) + mining.users(earnPool.pid, _user).lptAmount; + } + + // get tokens percents + address[] memory finalTokens = ILpToken(pool.lpToken).getFinalTokens(); + for (uint8 j = 0; j < finalTokens.length; j++) { + earnPool.tokensDistribution[j] = PartOfThePool({ + tokenAddress: finalTokens[j], + percent: ILpToken(pool.lpToken).getNormalizedWeight(finalTokens[j]) + }); + } + } + + return earnPools; + } + // TODO: Remove automatic 0 pool fetch and use TokenBAddress // Accepts amount of token A from pair and returns corresponding amount of token B from pair. (You can switch both tokens) function getTokenBAmount(uint256 tokenAAmountWei, address tokenAAddress, address) external view returns(uint256) { diff --git a/test/DeprecatedPoolsLens.test.js b/test/DeprecatedPoolsLens.test.js index c282e44..18aa82e 100644 --- a/test/DeprecatedPoolsLens.test.js +++ b/test/DeprecatedPoolsLens.test.js @@ -14,8 +14,8 @@ describe.only('DeprecatedPoolsLens', async () => { '0x38e4adB44ef08F22F5B5b76A8f0c2d0dCbE7DcA1', ); // const result = await this.poolsLens.getPoolData(ethers.constants.AddressZero); - // const result = await this.poolsLens.getFarmingList('0x8b19f6F51501dA80FCEFb578427907f223005F7A'); - const result = await this.poolsLens.getSushiSecondaryLiquidityRemoveInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 11); + const result = await this.poolsLens.getEarnList('0x8b19f6F51501dA80FCEFb578427907f223005F7A'); + // const result = await this.poolsLens.getSushiSecondaryLiquidityRemoveInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 11); // const result = await this.poolsLens.getFarmingDetail('0xCce0bca1365a02e5770390165E64d1F59238D92e', 10); // const result = await this.poolsLens.getMiningManager(ethers.constants.AddressZero); console.log('result console: ', result); From c01f29d51b41ffb7c11c37ffb326980a95f7c80f Mon Sep 17 00:00:00 2001 From: defibrain88 Date: Mon, 6 May 2024 09:55:55 +1000 Subject: [PATCH 4/9] feat: Sushi and Balancer liquidity drain lens added --- .../powerindex-mining/DeprecatedPoolsLens.sol | 91 ++++++++++++++----- test/DeprecatedPoolsLens.test.js | 9 +- 2 files changed, 76 insertions(+), 24 deletions(-) diff --git a/contracts/powerindex-mining/DeprecatedPoolsLens.sol b/contracts/powerindex-mining/DeprecatedPoolsLens.sol index 2371125..eac49a9 100644 --- a/contracts/powerindex-mining/DeprecatedPoolsLens.sol +++ b/contracts/powerindex-mining/DeprecatedPoolsLens.sol @@ -35,6 +35,7 @@ interface IVestedLpMining { interface ILpToken { function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32); + function getBalance(address tokenAddress) external view returns (uint256); function token0() external view returns (address); function token1() external view returns (address); function totalSupply() external view returns (uint256); @@ -80,6 +81,7 @@ struct EarnListItem { struct PartOfThePool { address tokenAddress; + string symbol; uint256 percent; } @@ -88,6 +90,7 @@ struct FarmingDetail { uint8 poolType; uint256 pid; uint256 lpMiningBalance; + uint256 lpUserBalance; uint256 lpTotalSupply; uint256 vestableCvp; uint256 lpTokenUserStakedAtMining; @@ -115,6 +118,7 @@ struct tokenInfo { struct tokenRemove { address lpToken; + address routerAddress; uint8 poolType; uint256 pid; uint256 lpTotalSupply; @@ -220,6 +224,7 @@ contract DeprecatedPoolsLens { poolType: pool.poolType, pid: _pid, lpMiningBalance: ILpToken(pool.lpToken).balanceOf(address(mining)), + lpUserBalance: ILpToken(pool.lpToken).balanceOf(_user), lpTotalSupply: ILpToken(pool.lpToken).totalSupply(), vestableCvp: vestableCvp, lpTokenUserStakedAtMining: lpTokenUserStaked, @@ -237,37 +242,79 @@ contract DeprecatedPoolsLens { address routerContract; if (isSushi) { // sushi routerContract = 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F; + return getSushiInfo(_user, _pid, routerContract, pool); } else { // balancer routerContract = pool.lpToken; + return getBalancerInfo(_user, _pid, routerContract, pool); } + } - (uint112 reserve0, uint112 reserve1,) = ILpToken(pool.lpToken).getReserves(); + // Returns specific for balancer data. Used when building interface for balancer redeem + function getBalancerInfo(address _user, uint _pid, address _router, Pool memory _pool) internal view returns (tokenRemove memory) { + // getBalance + // getFinalTokens + uint256 reserve0 = ILpToken(_pool.lpToken).getBalance(ILpToken(_pool.lpToken).getFinalTokens()[0]); + uint256 reserve1 = ILpToken(_pool.lpToken).getBalance(ILpToken(_pool.lpToken).getFinalTokens()[1]); - uint8 token1Decimals = ERC20(ILpToken(pool.lpToken).token0()).decimals(); - uint8 token2Decimals = ERC20(ILpToken(pool.lpToken).token1()).decimals(); - uint256 lpTotalSupply = ILpToken(pool.lpToken).totalSupply(); + uint8 token1Decimals = ERC20(ILpToken(_pool.lpToken).getFinalTokens()[0]).decimals(); + uint8 token2Decimals = ERC20(ILpToken(_pool.lpToken).getFinalTokens()[1]).decimals(); + uint256 lpTotalSupply = ILpToken(_pool.lpToken).totalSupply(); return tokenRemove({ - lpToken: pool.lpToken, - poolType: pool.poolType, + lpToken: _pool.lpToken, + routerAddress: _router, + poolType: _pool.poolType, + pid: _pid, + lpTotalSupply: lpTotalSupply, + balance: ERC20(_pool.lpToken).balanceOf(_user), + allowance: ERC20(_pool.lpToken).allowance(_user, _router), + token1: tokenInfo({ + tokenAddress: ILpToken(_pool.lpToken).getFinalTokens()[0], + tokenSymbol: ILpToken(ILpToken(_pool.lpToken).getFinalTokens()[0]).symbol(), + decimals: token1Decimals, + reserves: reserve0, + tokenAmountPerLPToken: (((1 ether * 10**18) / lpTotalSupply) * (reserve0 * 10**(18 - token1Decimals))) / 10**18 + }), + token2: tokenInfo({ + tokenAddress: ILpToken(_pool.lpToken).getFinalTokens()[1], + tokenSymbol: ILpToken(ILpToken(_pool.lpToken).getFinalTokens()[1]).symbol(), + decimals: token2Decimals, + reserves: reserve1, + tokenAmountPerLPToken: (((1 ether * 10**18) / lpTotalSupply) * (reserve1 * 10**(18 - token2Decimals))) / 10**18 + }) + }); + } + + // Returns specific for sushi data. Used when building interface for sushi redeem + function getSushiInfo(address _user, uint _pid, address _router, Pool memory _pool) internal view returns (tokenRemove memory) { + (uint112 reserve0, uint112 reserve1,) = ILpToken(_pool.lpToken).getReserves(); + + uint8 token1Decimals = ERC20(ILpToken(_pool.lpToken).token0()).decimals(); + uint8 token2Decimals = ERC20(ILpToken(_pool.lpToken).token1()).decimals(); + uint256 lpTotalSupply = ILpToken(_pool.lpToken).totalSupply(); + + return tokenRemove({ + lpToken: _pool.lpToken, + routerAddress: _router, + poolType: _pool.poolType, pid: _pid, lpTotalSupply: lpTotalSupply, - balance: ERC20(pool.lpToken).balanceOf(_user), - allowance: ERC20(pool.lpToken).allowance(_user, routerContract), + balance: ERC20(_pool.lpToken).balanceOf(_user), + allowance: ERC20(_pool.lpToken).allowance(_user, _router), token1: tokenInfo({ - tokenAddress: ILpToken(pool.lpToken).token0(), - tokenSymbol: ILpToken(ILpToken(pool.lpToken).token0()).symbol(), - decimals: token1Decimals, - reserves: reserve0, - tokenAmountPerLPToken: (((1 ether * 10**18) / lpTotalSupply) * (reserve0 * 10**(18 - token1Decimals))) / 10**18 - }), + tokenAddress: ILpToken(_pool.lpToken).token0(), + tokenSymbol: ILpToken(ILpToken(_pool.lpToken).token0()).symbol(), + decimals: token1Decimals, + reserves: reserve0, + tokenAmountPerLPToken: (((1 ether * 10**18) / lpTotalSupply) * (reserve0 * 10**(18 - token1Decimals))) / 10**18 + }), token2: tokenInfo({ - tokenAddress: ILpToken(pool.lpToken).token1(), - tokenSymbol: ILpToken(ILpToken(pool.lpToken).token1()).symbol(), - decimals: token2Decimals, - reserves: reserve1, - tokenAmountPerLPToken: (((1 ether * 10**18) / lpTotalSupply) * (reserve1 * 10**(18 - token2Decimals))) / 10**18 - }) + tokenAddress: ILpToken(_pool.lpToken).token1(), + tokenSymbol: ILpToken(ILpToken(_pool.lpToken).token1()).symbol(), + decimals: token2Decimals, + reserves: reserve1, + tokenAmountPerLPToken: (((1 ether * 10**18) / lpTotalSupply) * (reserve1 * 10**(18 - token2Decimals))) / 10**18 + }) }); } @@ -301,9 +348,11 @@ contract DeprecatedPoolsLens { // get tokens percents address[] memory finalTokens = ILpToken(pool.lpToken).getFinalTokens(); for (uint8 j = 0; j < finalTokens.length; j++) { + if (finalTokens[j] == 0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2) continue; // fcked up token symbol (bytes32), pass that earnPool.tokensDistribution[j] = PartOfThePool({ tokenAddress: finalTokens[j], - percent: ILpToken(pool.lpToken).getNormalizedWeight(finalTokens[j]) + symbol: ILpToken(finalTokens[j]).symbol(), + percent: ILpToken(pool.lpToken).getNormalizedWeight(finalTokens[j]) }); } } diff --git a/test/DeprecatedPoolsLens.test.js b/test/DeprecatedPoolsLens.test.js index 18aa82e..468292a 100644 --- a/test/DeprecatedPoolsLens.test.js +++ b/test/DeprecatedPoolsLens.test.js @@ -14,9 +14,12 @@ describe.only('DeprecatedPoolsLens', async () => { '0x38e4adB44ef08F22F5B5b76A8f0c2d0dCbE7DcA1', ); // const result = await this.poolsLens.getPoolData(ethers.constants.AddressZero); - const result = await this.poolsLens.getEarnList('0x8b19f6F51501dA80FCEFb578427907f223005F7A'); - // const result = await this.poolsLens.getSushiSecondaryLiquidityRemoveInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 11); - // const result = await this.poolsLens.getFarmingDetail('0xCce0bca1365a02e5770390165E64d1F59238D92e', 10); + // const result = await this.poolsLens.getEarnList('0x8b19f6F51501dA80FCEFb578427907f223005F7A'); + + const result = await this.poolsLens.getSecondaryLiquidityRemoveInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 7); // balancer + // const result = await this.poolsLens.getSecondaryLiquidityRemoveInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 11); // sushi + + // const result = await this.poolsLens.getFarmingDetail('0xCce0bca1365a02e5770390165E64d1F59238D92e', 7); // const result = await this.poolsLens.getMiningManager(ethers.constants.AddressZero); console.log('result console: ', result); }); From 410e4fd0e136f3aff51aa2e99179d4c269b0e535 Mon Sep 17 00:00:00 2001 From: defibrain88 Date: Mon, 6 May 2024 19:51:11 +1000 Subject: [PATCH 5/9] feat: Adds single exit amount calculation --- .../powerindex-mining/DeprecatedPoolsLens.sol | 105 +++++++++++++++--- test/DeprecatedPoolsLens.test.js | 6 +- 2 files changed, 92 insertions(+), 19 deletions(-) diff --git a/contracts/powerindex-mining/DeprecatedPoolsLens.sol b/contracts/powerindex-mining/DeprecatedPoolsLens.sol index eac49a9..746c941 100644 --- a/contracts/powerindex-mining/DeprecatedPoolsLens.sol +++ b/contracts/powerindex-mining/DeprecatedPoolsLens.sol @@ -44,6 +44,11 @@ interface ILpToken { function factory() external view returns (address); function getFinalTokens() external view returns (address[] memory); function getNormalizedWeight(address) external view returns (uint256); + function getDenormalizedWeight(address) external view returns (uint256); + function getTotalDenormalizedWeight() external view returns (uint256); + function getSwapFee() external view returns (uint256); + function getCommunityFee() external view returns (Fees memory); + function calcSingleOutGivenPoolIn(uint256, uint256, uint256, uint256, uint256, uint256) external view returns (uint256); } interface ERC20 { @@ -128,6 +133,34 @@ struct tokenRemove { tokenInfo token2; } +struct LiquidityTokens { + address tokenAddress; + uint256 balance; + uint8 decimals; + uint256 tokenAmountForOneLpSingle; + uint256 tokenAmountForOneLpMulti; +} + +struct Fees { + uint256 communitySwapFee; + uint256 communityJoinFee; + uint256 communityExitFee; + address communityFeeReceiver; +} + +struct RemoveLiquidityData { + address lpToken; + uint8 poolType; + uint256 pid; + uint256 balance; + address defaultWrapper; + address multiWrapper; + uint256 defaultAllowance; + uint256 multiAllowance; + Fees fees; + LiquidityTokens[] tokens; +} + contract DeprecatedPoolsLens { IVestedLpMining public mining; IUniswapV2Router public uniRouter; @@ -251,8 +284,6 @@ contract DeprecatedPoolsLens { // Returns specific for balancer data. Used when building interface for balancer redeem function getBalancerInfo(address _user, uint _pid, address _router, Pool memory _pool) internal view returns (tokenRemove memory) { - // getBalance - // getFinalTokens uint256 reserve0 = ILpToken(_pool.lpToken).getBalance(ILpToken(_pool.lpToken).getFinalTokens()[0]); uint256 reserve1 = ILpToken(_pool.lpToken).getBalance(ILpToken(_pool.lpToken).getFinalTokens()[1]); @@ -360,21 +391,61 @@ contract DeprecatedPoolsLens { return earnPools; } - // TODO: Remove automatic 0 pool fetch and use TokenBAddress - // Accepts amount of token A from pair and returns corresponding amount of token B from pair. (You can switch both tokens) - function getTokenBAmount(uint256 tokenAAmountWei, address tokenAAddress, address) external view returns(uint256) { - Pool memory pool = mining.pools(0); - (uint112 reserve0, uint112 reserve1,) = ILpToken(pool.lpToken).getReserves(); - uint256 reserveA; - uint256 reserveB; - - if (tokenAAddress == cvpAddress) { - reserveA = reserve0; - reserveB = reserve1; - } else if (tokenAAddress == wethAddress) { - reserveB = reserve0; - reserveA = reserve1; + function RemoveLiquidityInfo(address _user, uint256 _pid) external view returns (RemoveLiquidityData memory) { + Pool memory pool = mining.pools(_pid); + address defaultWrapper = pool.lpToken; + address multiWrapper = pool.lpToken; + uint256 exitFee = 0.001 ether; + + if (pool.lpToken == 0xFA2562da1Bba7B954f26C74725dF51fb62646313) { // ASSY token has it's wrapper hardcoded in configs + defaultWrapper = 0x43Fa8eF8E334720b80367Cf94e438Cf90c562aBE; + multiWrapper = 0x43Fa8eF8E334720b80367Cf94e438Cf90c562aBE; + } else if (pool.lpToken == 0x9ba60bA98413A60dB4C651D4afE5C937bbD8044B) { + defaultWrapper = 0x3D256E2468c36F15997E3bFc295eD5Ab3D6c0576; // YLA default wrapper is contract that handle USDC + } + + LiquidityTokens[] memory tokens = new LiquidityTokens[](ILpToken(pool.lpToken).getFinalTokens().length); + + for (uint8 i = 0; i < ILpToken(pool.lpToken).getFinalTokens().length; i++) { + LiquidityTokens memory token = tokens[i]; + + token.tokenAddress = ILpToken(pool.lpToken).getFinalTokens()[i]; + token.balance = ERC20(ILpToken(pool.lpToken).getFinalTokens()[i]).balanceOf(_user); + token.decimals = ERC20(ILpToken(pool.lpToken).getFinalTokens()[i]).decimals(); + token.tokenAmountForOneLpSingle = getSingleTokenOut(_pid, ILpToken(pool.lpToken).getFinalTokens()[i]); + token.tokenAmountForOneLpMulti = 0; + } + + return RemoveLiquidityData({ + lpToken: pool.lpToken, + poolType: pool.poolType, + pid: _pid, + balance: ILpToken(pool.lpToken).balanceOf(_user), + defaultWrapper: defaultWrapper, + multiWrapper: multiWrapper, + defaultAllowance: ERC20(pool.lpToken).allowance(_user, defaultWrapper), + multiAllowance: ERC20(pool.lpToken).allowance(_user, multiWrapper), + fees: ILpToken(pool.lpToken).getCommunityFee(), + tokens: tokens + }); + } + + function getSingleTokenOut(uint256 _pid, address _tokenAddress) internal view returns (uint256) { + Pool memory pool = mining.pools(_pid); + + if (_pid == 13) { + // usd handler. Disabled due to security breach + return 0; + } else { + uint256 communitySwapFee = ILpToken(pool.lpToken).getCommunityFee().communitySwapFee; + return ILpToken(pool.lpToken).calcSingleOutGivenPoolIn( + ILpToken(pool.lpToken).getBalance(_tokenAddress), + ILpToken(pool.lpToken).getDenormalizedWeight(_tokenAddress), + ILpToken(pool.lpToken).totalSupply(), + ILpToken(pool.lpToken).getTotalDenormalizedWeight(), + 1 ether - communitySwapFee, + ILpToken(pool.lpToken).getSwapFee() + ); } - return uniRouter.quote(tokenAAmountWei, reserveA, reserveB); } } diff --git a/test/DeprecatedPoolsLens.test.js b/test/DeprecatedPoolsLens.test.js index 468292a..736b719 100644 --- a/test/DeprecatedPoolsLens.test.js +++ b/test/DeprecatedPoolsLens.test.js @@ -16,12 +16,14 @@ describe.only('DeprecatedPoolsLens', async () => { // const result = await this.poolsLens.getPoolData(ethers.constants.AddressZero); // const result = await this.poolsLens.getEarnList('0x8b19f6F51501dA80FCEFb578427907f223005F7A'); - const result = await this.poolsLens.getSecondaryLiquidityRemoveInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 7); // balancer + const result = await this.poolsLens.RemoveLiquidityInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 10); // balancer + + // const result = await this.poolsLens.getSecondaryLiquidityRemoveInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 7); // balancer // const result = await this.poolsLens.getSecondaryLiquidityRemoveInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 11); // sushi // const result = await this.poolsLens.getFarmingDetail('0xCce0bca1365a02e5770390165E64d1F59238D92e', 7); // const result = await this.poolsLens.getMiningManager(ethers.constants.AddressZero); - console.log('result console: ', result); + console.log('main: ', result); }); } catch (e) { console.error(e) From 2896c6bc5720d04a2ae5eb5643c6ce73e90f3dfe Mon Sep 17 00:00:00 2001 From: defibrain88 Date: Tue, 7 May 2024 12:18:34 +1000 Subject: [PATCH 6/9] feat: Adds function for lp token to withdraw liquidity --- .../powerindex-mining/DeprecatedPoolsLens.sol | 44 ++++++++----------- test/DeprecatedPoolsLens.test.js | 2 +- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/contracts/powerindex-mining/DeprecatedPoolsLens.sol b/contracts/powerindex-mining/DeprecatedPoolsLens.sol index 746c941..5c43ac2 100644 --- a/contracts/powerindex-mining/DeprecatedPoolsLens.sol +++ b/contracts/powerindex-mining/DeprecatedPoolsLens.sol @@ -153,10 +153,7 @@ struct RemoveLiquidityData { uint8 poolType; uint256 pid; uint256 balance; - address defaultWrapper; - address multiWrapper; - uint256 defaultAllowance; - uint256 multiAllowance; + uint256 allowance; Fees fees; LiquidityTokens[] tokens; } @@ -393,16 +390,6 @@ contract DeprecatedPoolsLens { function RemoveLiquidityInfo(address _user, uint256 _pid) external view returns (RemoveLiquidityData memory) { Pool memory pool = mining.pools(_pid); - address defaultWrapper = pool.lpToken; - address multiWrapper = pool.lpToken; - uint256 exitFee = 0.001 ether; - - if (pool.lpToken == 0xFA2562da1Bba7B954f26C74725dF51fb62646313) { // ASSY token has it's wrapper hardcoded in configs - defaultWrapper = 0x43Fa8eF8E334720b80367Cf94e438Cf90c562aBE; - multiWrapper = 0x43Fa8eF8E334720b80367Cf94e438Cf90c562aBE; - } else if (pool.lpToken == 0x9ba60bA98413A60dB4C651D4afE5C937bbD8044B) { - defaultWrapper = 0x3D256E2468c36F15997E3bFc295eD5Ab3D6c0576; // YLA default wrapper is contract that handle USDC - } LiquidityTokens[] memory tokens = new LiquidityTokens[](ILpToken(pool.lpToken).getFinalTokens().length); @@ -412,21 +399,18 @@ contract DeprecatedPoolsLens { token.tokenAddress = ILpToken(pool.lpToken).getFinalTokens()[i]; token.balance = ERC20(ILpToken(pool.lpToken).getFinalTokens()[i]).balanceOf(_user); token.decimals = ERC20(ILpToken(pool.lpToken).getFinalTokens()[i]).decimals(); - token.tokenAmountForOneLpSingle = getSingleTokenOut(_pid, ILpToken(pool.lpToken).getFinalTokens()[i]); - token.tokenAmountForOneLpMulti = 0; + token.tokenAmountForOneLpSingle = getSingleTokenOut(_pid, token.tokenAddress); + token.tokenAmountForOneLpMulti = getMultiTokensOut(_pid, token.tokenAddress, token.decimals); } return RemoveLiquidityData({ - lpToken: pool.lpToken, - poolType: pool.poolType, - pid: _pid, - balance: ILpToken(pool.lpToken).balanceOf(_user), - defaultWrapper: defaultWrapper, - multiWrapper: multiWrapper, - defaultAllowance: ERC20(pool.lpToken).allowance(_user, defaultWrapper), - multiAllowance: ERC20(pool.lpToken).allowance(_user, multiWrapper), - fees: ILpToken(pool.lpToken).getCommunityFee(), - tokens: tokens + lpToken: pool.lpToken, + poolType: pool.poolType, + pid: _pid, + balance: ILpToken(pool.lpToken).balanceOf(_user), + allowance: ERC20(pool.lpToken).allowance(_user, pool.lpToken), + fees: ILpToken(pool.lpToken).getCommunityFee(), + tokens: tokens }); } @@ -448,4 +432,12 @@ contract DeprecatedPoolsLens { ); } } + + function getMultiTokensOut(uint256 _pid, address _tokenAddress, uint8 _decimals) internal view returns (uint256) { + Pool memory pool = mining.pools(_pid); + uint256 totalSupply = ILpToken(pool.lpToken).totalSupply(); + uint256 reserve = ILpToken(pool.lpToken).getBalance(_tokenAddress); + + return (((1 ether * 10**18) / totalSupply) * (reserve * 10**(18 - _decimals))) / 10**18; + } } diff --git a/test/DeprecatedPoolsLens.test.js b/test/DeprecatedPoolsLens.test.js index 736b719..6e7f5c9 100644 --- a/test/DeprecatedPoolsLens.test.js +++ b/test/DeprecatedPoolsLens.test.js @@ -16,7 +16,7 @@ describe.only('DeprecatedPoolsLens', async () => { // const result = await this.poolsLens.getPoolData(ethers.constants.AddressZero); // const result = await this.poolsLens.getEarnList('0x8b19f6F51501dA80FCEFb578427907f223005F7A'); - const result = await this.poolsLens.RemoveLiquidityInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 10); // balancer + const result = await this.poolsLens.RemoveLiquidityInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 6); // balancer // const result = await this.poolsLens.getSecondaryLiquidityRemoveInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 7); // balancer // const result = await this.poolsLens.getSecondaryLiquidityRemoveInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 11); // sushi From 8025e2fd04e4e6519f9bff9080a18f4f36217313 Mon Sep 17 00:00:00 2001 From: defibrain88 Date: Tue, 7 May 2024 14:11:24 +1000 Subject: [PATCH 7/9] chore --- contracts/powerindex-mining/DeprecatedPoolsLens.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/powerindex-mining/DeprecatedPoolsLens.sol b/contracts/powerindex-mining/DeprecatedPoolsLens.sol index 5c43ac2..93ba5f7 100644 --- a/contracts/powerindex-mining/DeprecatedPoolsLens.sol +++ b/contracts/powerindex-mining/DeprecatedPoolsLens.sol @@ -152,6 +152,7 @@ struct RemoveLiquidityData { address lpToken; uint8 poolType; uint256 pid; + string symbol; uint256 balance; uint256 allowance; Fees fees; @@ -388,7 +389,7 @@ contract DeprecatedPoolsLens { return earnPools; } - function RemoveLiquidityInfo(address _user, uint256 _pid) external view returns (RemoveLiquidityData memory) { + function removeLiquidityInfo(address _user, uint256 _pid) external view returns (RemoveLiquidityData memory) { Pool memory pool = mining.pools(_pid); LiquidityTokens[] memory tokens = new LiquidityTokens[](ILpToken(pool.lpToken).getFinalTokens().length); @@ -407,6 +408,7 @@ contract DeprecatedPoolsLens { lpToken: pool.lpToken, poolType: pool.poolType, pid: _pid, + symbol: ILpToken(pool.lpToken).symbol(), balance: ILpToken(pool.lpToken).balanceOf(_user), allowance: ERC20(pool.lpToken).allowance(_user, pool.lpToken), fees: ILpToken(pool.lpToken).getCommunityFee(), From 9be10f46462ab36e69ab7fdab54705cfbb049a1f Mon Sep 17 00:00:00 2001 From: defibrain88 Date: Wed, 8 May 2024 13:58:59 +1000 Subject: [PATCH 8/9] feat: Deprecated pools lens for mainnet --- .../powerindex-mining/DeprecatedPoolsLens.sol | 21 ++++++------------- hardhat.config.js | 2 +- tasks/deployDeprecatedPoolsLens.js | 3 --- test/DeprecatedPoolsLens.test.js | 7 ++----- verify-args.js | 5 +---- 5 files changed, 10 insertions(+), 28 deletions(-) diff --git a/contracts/powerindex-mining/DeprecatedPoolsLens.sol b/contracts/powerindex-mining/DeprecatedPoolsLens.sol index 93ba5f7..de9e892 100644 --- a/contracts/powerindex-mining/DeprecatedPoolsLens.sol +++ b/contracts/powerindex-mining/DeprecatedPoolsLens.sol @@ -13,13 +13,6 @@ https://powerpool.finance/ pragma solidity 0.8.11; -import "hardhat/console.sol"; - -interface IUniswapV2Router { - function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); - function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external view returns (uint256 amountB); -} - interface IVestedLpMining { function pools(uint256 index) external view returns (Pool calldata); function users(uint256 poolId, address userAddress) external view returns (miningUserDataStruct calldata); @@ -137,6 +130,7 @@ struct LiquidityTokens { address tokenAddress; uint256 balance; uint8 decimals; + string symbol; uint256 tokenAmountForOneLpSingle; uint256 tokenAmountForOneLpMulti; } @@ -161,23 +155,15 @@ struct RemoveLiquidityData { contract DeprecatedPoolsLens { IVestedLpMining public mining; - IUniswapV2Router public uniRouter; - address public stableAddress; - address immutable public wethAddress; address immutable public cvpAddress; mapping(uint8 => uint8) public earnPidMap; constructor( IVestedLpMining _mining, - IUniswapV2Router _router, - address _wethAddress, - address _stableAddress, address _cvpAddress ) { mining = _mining; - uniRouter = _router; - wethAddress = _wethAddress; cvpAddress = _cvpAddress; earnPidMap[0] = 13; @@ -400,6 +386,11 @@ contract DeprecatedPoolsLens { token.tokenAddress = ILpToken(pool.lpToken).getFinalTokens()[i]; token.balance = ERC20(ILpToken(pool.lpToken).getFinalTokens()[i]).balanceOf(_user); token.decimals = ERC20(ILpToken(pool.lpToken).getFinalTokens()[i]).decimals(); + if (ILpToken(pool.lpToken).getFinalTokens()[i] == 0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2) { + token.symbol = 'MKR'; + } else { + token.symbol = ILpToken(ILpToken(pool.lpToken).getFinalTokens()[i]).symbol(); + } token.tokenAmountForOneLpSingle = getSingleTokenOut(_pid, token.tokenAddress); token.tokenAmountForOneLpMulti = getMultiTokensOut(_pid, token.tokenAddress, token.decimals); } diff --git a/hardhat.config.js b/hardhat.config.js index 7444c79..f598d18 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -90,7 +90,7 @@ const config = { mainnet: { url: 'https://rough-compatible-hill.quiknode.pro/b7052dc47d31d455c2a770377f7db70735924fba/', accounts: getAccounts('mainnet'), - gasPrice: 9 * 10 ** 9, + gasPrice: 5 * 10 ** 9, gasMultiplier: 1.2, timeout: 2000000, }, diff --git a/tasks/deployDeprecatedPoolsLens.js b/tasks/deployDeprecatedPoolsLens.js index c7ec8fe..16e1898 100644 --- a/tasks/deployDeprecatedPoolsLens.js +++ b/tasks/deployDeprecatedPoolsLens.js @@ -11,9 +11,6 @@ task('deploy-deprecated-pools-lens', 'Deploy deprecated pools lens').setAction(a const sendOptions = { from: deployer }; const poolsLens = await PoolsLens.new( '0xF09232320eBEAC33fae61b24bB8D7CA192E58507', - '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', - '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - '0xdAC17F958D2ee523a2206206994597C13D831ec7', '0x38e4adB44ef08F22F5B5b76A8f0c2d0dCbE7DcA1', sendOptions, ); diff --git a/test/DeprecatedPoolsLens.test.js b/test/DeprecatedPoolsLens.test.js index 6e7f5c9..f705c60 100644 --- a/test/DeprecatedPoolsLens.test.js +++ b/test/DeprecatedPoolsLens.test.js @@ -8,15 +8,12 @@ describe.only('DeprecatedPoolsLens', async () => { it('chore test pass', async () => { this.poolsLens = await PoolsLens.new( '0xF09232320eBEAC33fae61b24bB8D7CA192E58507', - '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', - '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - '0xdAC17F958D2ee523a2206206994597C13D831ec7', '0x38e4adB44ef08F22F5B5b76A8f0c2d0dCbE7DcA1', ); // const result = await this.poolsLens.getPoolData(ethers.constants.AddressZero); + // const result = await this.poolsLens.getFarmingDetail('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 6); // const result = await this.poolsLens.getEarnList('0x8b19f6F51501dA80FCEFb578427907f223005F7A'); - - const result = await this.poolsLens.RemoveLiquidityInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 6); // balancer + // const result = await this.poolsLens.removeLiquidityInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 6); // balancer // const result = await this.poolsLens.getSecondaryLiquidityRemoveInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 7); // balancer // const result = await this.poolsLens.getSecondaryLiquidityRemoveInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 11); // sushi diff --git a/verify-args.js b/verify-args.js index fa40541..5e8019a 100644 --- a/verify-args.js +++ b/verify-args.js @@ -1,7 +1,4 @@ module.exports = [ '0xF09232320eBEAC33fae61b24bB8D7CA192E58507', - '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', - '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - '0xdAC17F958D2ee523a2206206994597C13D831ec7', - '0x38e4adB44ef08F22F5B5b76A8f0c2d0dCbE7DcA1' + '0x38e4adB44ef08F22F5B5b76A8f0c2d0dCbE7DcA1', ] From ee61947c51b7001c7733b8ecb051b26ec57e2bd1 Mon Sep 17 00:00:00 2001 From: defibrain88 Date: Thu, 9 May 2024 15:07:29 +1000 Subject: [PATCH 9/9] feat: Deprecated pools lens for binance --- .../DeprecatedBscPoolsLens.sol | 143 ++++++++++++++++++ hardhat.config.js | 12 +- tasks/deployBscDeprecatedPoolsLens.js | 17 +++ test/DeprecatedBscPoolsLens.test.js | 19 +++ test/DeprecatedPoolsLens.test.js | 2 +- verify-args.js | 3 +- 6 files changed, 191 insertions(+), 5 deletions(-) create mode 100644 contracts/powerindex-mining/DeprecatedBscPoolsLens.sol create mode 100644 tasks/deployBscDeprecatedPoolsLens.js create mode 100644 test/DeprecatedBscPoolsLens.test.js diff --git a/contracts/powerindex-mining/DeprecatedBscPoolsLens.sol b/contracts/powerindex-mining/DeprecatedBscPoolsLens.sol new file mode 100644 index 0000000..566ba64 --- /dev/null +++ b/contracts/powerindex-mining/DeprecatedBscPoolsLens.sol @@ -0,0 +1,143 @@ +/* +https://powerpool.finance/ + wrrrw r wrr + ppwr rrr wppr0 prwwwrp prwwwrp wr0 + rr 0rrrwrrprpwp0 pp pr prrrr0 pp 0r prrrr0 0rwrrr pp pr prrrr0 prrrr0 r0 + rrp pr wr00rrp prwww0 pp wr pp w00r prwwwpr 0rw prwww0 pp wr pp wr r0 + r0rprprwrrrp pr0 pp wr pr pp rwwr wr 0r pp wr pr wr pr r0 + prwr wrr0wpwr 00 www0 0w0ww www0 0w 00 www0 www0 0www0 + wrr ww0rrrr +*/ + +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.11; + +interface ILpToken { + function getBalance(address tokenAddress) external view returns (uint256); + function totalSupply() external view returns (uint256); + function allowance(address owner, address spender) external view returns(uint256); + function balanceOf(address wallet) external view returns (uint256); + function symbol() external view returns (string memory); + function decimals() external view returns (uint8); + function getFinalTokens() external view returns (address[] memory); + function getNormalizedWeight(address) external view returns (uint256); + function getSwapFee() external view returns (uint256); + function getCommunityFee() external view returns (Fees memory); +} + +struct EarnListItem { + address lpToken; + uint8 poolType; + uint256 pid; + uint256 totalSupply; + uint256 userTotalBalance; // user wallet balance + user mining balance + PartOfThePool[] tokensDistribution; +} + +struct PartOfThePool { + address tokenAddress; + string symbol; + uint256 percent; +} + +struct LiquidityTokens { + address tokenAddress; + uint256 balance; + uint8 decimals; + string symbol; + uint256 tokenAmountForOneLpMulti; +} + +struct Fees { + uint256 communitySwapFee; + uint256 communityJoinFee; + uint256 communityExitFee; + address communityFeeReceiver; +} + +struct RemoveLiquidityData { + address lpToken; + uint8 poolType; + uint256 pid; + string symbol; + uint256 balance; + uint256 allowance; + Fees fees; + LiquidityTokens[] tokens; +} + +contract DeprecatedBscPoolsLens { + ILpToken public singlePool; + + constructor(ILpToken _pool) { + singlePool = _pool; + } + + function getEarnList(address _user) external view returns (EarnListItem[] memory) { + EarnListItem[] memory earnPools = new EarnListItem[](1); + ILpToken pool = singlePool; + + earnPools[0] = EarnListItem({ + lpToken: address(pool), + poolType: 0, + pid: 0, + totalSupply: pool.totalSupply(), + tokensDistribution: new PartOfThePool[](pool.getFinalTokens().length), + userTotalBalance: 0 + }); + + EarnListItem memory earnPool = earnPools[0]; + + // User balance + if (_user != address(0)) { + earnPool.userTotalBalance = pool.balanceOf(_user); + } + + // get tokens percents + address[] memory finalTokens = pool.getFinalTokens(); + for (uint8 j = 0; j < finalTokens.length; j++) { + earnPool.tokensDistribution[j] = PartOfThePool({ + tokenAddress: finalTokens[j], + symbol: ILpToken(finalTokens[j]).symbol(), + percent: pool.getNormalizedWeight(finalTokens[j]) + }); + } + + return earnPools; + } + + function removeLiquidityInfo(address _user, uint256 _pid) external view returns (RemoveLiquidityData memory) { + ILpToken pool = singlePool; + LiquidityTokens[] memory tokens = new LiquidityTokens[](pool.getFinalTokens().length); + + for (uint8 i = 0; i < pool.getFinalTokens().length; i++) { + LiquidityTokens memory token = tokens[i]; + + token.tokenAddress = pool.getFinalTokens()[i]; + token.balance = ILpToken(pool.getFinalTokens()[i]).balanceOf(_user); + token.decimals = ILpToken(pool.getFinalTokens()[i]).decimals(); + token.symbol = ILpToken(pool.getFinalTokens()[i]).symbol(); + token.tokenAmountForOneLpMulti = getMultiTokensOut(token.tokenAddress, token.decimals); + } + + return RemoveLiquidityData({ + lpToken: address(pool), + poolType: 0, + pid: _pid, + symbol: pool.symbol(), + balance: pool.balanceOf(_user), + allowance: pool.allowance(_user, address(pool)), + fees: pool.getCommunityFee(), + tokens: tokens + }); + } + + function getMultiTokensOut(address _tokenAddress, uint8 _decimals) internal view returns (uint256) { + ILpToken pool = singlePool; + uint256 totalSupply = pool.totalSupply(); + uint256 reserve = pool.getBalance(_tokenAddress); + + return (((1 ether * 10**18) / totalSupply) * (reserve * 10**(18 - _decimals))) / 10**18; + } +} diff --git a/hardhat.config.js b/hardhat.config.js index f598d18..5e4356b 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -12,6 +12,7 @@ require('./tasks/deployMainnetPowerIndexPool'); require('./tasks/deployErc20PiptSwap'); require('./tasks/deployPoolsLens'); require('./tasks/deployDeprecatedPoolsLens'); +require('./tasks/deployBscDeprecatedPoolsLens'); require('./tasks/testMainnetErc20PiptSwap'); require('./tasks/deployPoolRestrictions'); require('./tasks/deployMainnetYeti'); @@ -72,14 +73,14 @@ const config = { }, networks: { hardhat: { - chainId: 1, + chainId: 56, accounts: testAccounts, allowUnlimitedContractSize: true, gas: 12000000, loggingEnabled: true, blockGasLimit: 12000000, forking: { - url: 'https://mainnet-eth.powerpool.finance', + url: 'https://divine-icy-yard.bsc.quiknode.pro/1ec99ee8099d558029e893df069f138441e17e80/', }, }, ganache: { @@ -94,6 +95,13 @@ const config = { gasMultiplier: 1.2, timeout: 2000000, }, + binance: { + url: 'https://divine-icy-yard.bsc.quiknode.pro/1ec99ee8099d558029e893df069f138441e17e80/', + accounts: getAccounts('binance'), + gasPrice: 10 ** 9, + gasMultiplier: 1.2, + timeout: 2000000, + }, sepolia: { url: 'https://rpc.sepolia.org', accounts: getAccounts('sepolia'), diff --git a/tasks/deployBscDeprecatedPoolsLens.js b/tasks/deployBscDeprecatedPoolsLens.js new file mode 100644 index 0000000..11e810f --- /dev/null +++ b/tasks/deployBscDeprecatedPoolsLens.js @@ -0,0 +1,17 @@ +require('@nomiclabs/hardhat-truffle5'); + + +task('deploy-bsc-deprecated-pools-lens', 'Deploy deprecated pools lens').setAction(async (__, {network}) => { + const PoolsLens = artifacts.require('DeprecatedBscPoolsLens'); + + const { web3 } = PoolsLens; + + const [deployer] = await web3.eth.getAccounts(); + console.log('deployer', deployer); + const sendOptions = { from: deployer }; + const poolsLens = await PoolsLens.new( + '0x40E46dE174dfB776BB89E04dF1C47d8a66855EB3', + sendOptions, + ); + console.log('Deprecated bsc pools lens deployed address: ', poolsLens.address); +}); diff --git a/test/DeprecatedBscPoolsLens.test.js b/test/DeprecatedBscPoolsLens.test.js new file mode 100644 index 0000000..8fb677b --- /dev/null +++ b/test/DeprecatedBscPoolsLens.test.js @@ -0,0 +1,19 @@ +// const { expectRevert, time } = require('@openzeppelin/test-helpers'); +const { ethers} = require('hardhat'); +const PoolsLens = artifacts.require('DeprecatedBscPoolsLens'); +const zeroAddress = '0x0000000000000000000000000000000000000000'; + +describe.only('DeprecatedBscPoolsLens', async () => { + try { + it('chore test pass', async () => { + this.poolsLens = await PoolsLens.new( + '0x40E46dE174dfB776BB89E04dF1C47d8a66855EB3' + ); + // const result = await this.poolsLens.getEarnList('0x8b19f6F51501dA80FCEFb578427907f223005F7A'); + const result = await this.poolsLens.removeLiquidityInfo('0x8b19f6F51501dA80FCEFb578427907f223005F7A', 0); + console.log('main: ', result); + }); + } catch (e) { + console.error(e) + } +}); diff --git a/test/DeprecatedPoolsLens.test.js b/test/DeprecatedPoolsLens.test.js index f705c60..83e9b72 100644 --- a/test/DeprecatedPoolsLens.test.js +++ b/test/DeprecatedPoolsLens.test.js @@ -3,7 +3,7 @@ const { ethers} = require('hardhat'); const PoolsLens = artifacts.require('DeprecatedPoolsLens'); const zeroAddress = '0x0000000000000000000000000000000000000000'; -describe.only('DeprecatedPoolsLens', async () => { +describe('DeprecatedPoolsLens', async () => { try { it('chore test pass', async () => { this.poolsLens = await PoolsLens.new( diff --git a/verify-args.js b/verify-args.js index 5e8019a..cdb9574 100644 --- a/verify-args.js +++ b/verify-args.js @@ -1,4 +1,3 @@ module.exports = [ - '0xF09232320eBEAC33fae61b24bB8D7CA192E58507', - '0x38e4adB44ef08F22F5B5b76A8f0c2d0dCbE7DcA1', + '0x40E46dE174dfB776BB89E04dF1C47d8a66855EB3' ]