-
Notifications
You must be signed in to change notification settings - Fork 53
Lm rewards refactor #435
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
smbsp
wants to merge
26
commits into
development
Choose a base branch
from
lm-rewards-refactor
base: development
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Lm rewards refactor #435
Changes from 17 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
9e0416b
feat: new liquidity mining that rewards in multiple tokens
swamp-thing-sovryn 37d79d0
Merge pull request #13 from swamp-thing-sovryn/multiple-LM-tokens-rew…
swamp-thing-sovryn 5018e83
fix:solhint fixes
py-ro 31e4a44
Merge pull request #15 from swamp-thing-sovryn/fix/solhint-fixes-on-LM
swamp-thing-sovryn c1c46e8
feat:allow lending with LM V2 during migration period
py-ro 1aebbc9
fix: increase github CI memory
py-ro b0dd685
fix: fix PR reviews
py-ro 4e4ca40
fix: increase github CI memory
py-ro 5bcaf08
Merge pull request #16 from swamp-thing-sovryn/feat/redirect-onTokenD…
swamp-thing-sovryn bb41967
ci: increased nodejs memory so it can run the tests properly on node …
swamp-thing-sovryn 574dbe7
Merge pull request #17 from swamp-thing-sovryn/fix/oom-when-running-t…
swamp-thing-sovryn 915dbb8
fix: LM contracts initialize only once
py-ro 44a2699
Merge pull request #18 from swamp-thing-sovryn/fix/PR-reviews
swamp-thing-sovryn dfee8c0
Merge branch 'development' of https://github.com/DistributedCollectiv…
smbsp f754f64
Ran Prettier
smbsp 3727c5a
Fixed tests - need to optimise
smbsp 68a20ee
Ran prettier
smbsp 4ba69d8
Merge branch 'development' of https://github.com/DistributedCollectiv…
smbsp bfe8a83
Minor changes
smbsp bc4b08c
Ran prettier
smbsp 5acc363
Merge branch 'development' of https://github.com/DistributedCollectiv…
smbsp 99c5b52
Added a new function and fixed coverage issues
smbsp cd27d29
Ran prettier
smbsp 8f1d918
Merge branch 'development' of https://github.com/DistributedCollectiv…
smbsp 97f2098
Modified lock file
smbsp 5add9b2
Modified all versions for coverage
smbsp File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
This file contains hidden or 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,41 @@ | ||
| pragma solidity 0.5.17; | ||
|
|
||
| import "./IRewardTransferLogic.sol"; | ||
| import "./ERC20TransferLogicStorage.sol"; | ||
| import "../interfaces/IERC20.sol"; | ||
| import "../openzeppelin/SafeERC20.sol"; | ||
|
|
||
| contract ERC20TransferLogic is IRewardTransferLogic, ERC20TransferLogicStorage { | ||
| using SafeERC20 for IERC20; | ||
|
|
||
| event TokenAddressUpdated(address _newTokenAddress); | ||
|
|
||
| /** | ||
| * @param _token Reward token to be distributed | ||
| */ | ||
| function initialize(address _token) external onlyAuthorized { | ||
| setTokenAddress(_token); | ||
| } | ||
|
|
||
| function setTokenAddress(address _token) public onlyAuthorized { | ||
| require(_token != address(0), "Invalid token address"); | ||
| token = IERC20(_token); | ||
| emit TokenAddressUpdated(_token); | ||
| } | ||
|
|
||
| function getRewardTokenAddress() external view returns (address) { | ||
| return address(token); | ||
| } | ||
|
|
||
| function senderToAuthorize() external view returns (address) { | ||
| return address(this); | ||
| } | ||
|
|
||
| function transferReward( | ||
| address _to, | ||
| uint256 _value, | ||
| bool // it doesn't matter if it's a withdrawal or not | ||
| ) external { | ||
| token.safeTransferFrom(msg.sender, _to, _value); | ||
| } | ||
| } | ||
This file contains hidden or 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,9 @@ | ||
| pragma solidity 0.5.17; | ||
|
|
||
| import "./IRewardTransferLogic.sol"; | ||
| import "../utils/AdminRole.sol"; | ||
| import "../interfaces/IERC20.sol"; | ||
|
|
||
| contract ERC20TransferLogicStorage is IRewardTransferLogic, AdminRole { | ||
| IERC20 public token; | ||
| } |
This file contains hidden or 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,43 @@ | ||
| pragma solidity 0.5.17; | ||
|
|
||
| interface ILiquidityMiningV1 { | ||
| function withdraw( | ||
| address _poolToken, | ||
| uint256 _amount, | ||
| address _user | ||
| ) external; | ||
|
|
||
| function onTokensDeposited(address _user, uint256 _amount) external; | ||
|
|
||
| function getUserPoolTokenBalance(address _poolToken, address _user) | ||
| external | ||
| view | ||
| returns (uint256); | ||
|
|
||
| function getPoolInfoListArray() | ||
| external | ||
| view | ||
| returns ( | ||
| address[] memory, | ||
| uint96[] memory, | ||
| uint256[] memory, | ||
| uint256[] memory | ||
| ); | ||
|
|
||
| function getUserInfoListArray(address _user) | ||
| external | ||
| view | ||
| returns ( | ||
| uint256[] memory, | ||
| uint256[] memory, | ||
| uint256[] memory | ||
| ); | ||
|
|
||
| function migrateFunds() external; | ||
|
|
||
| function finishMigrationGracePeriod() external; | ||
|
|
||
| function getTotalUsersBalance() external view returns (uint256); | ||
|
|
||
| function getStartBlock() external view returns (uint256); | ||
| } |
This file contains hidden or 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,47 @@ | ||
| pragma solidity 0.5.17; | ||
|
|
||
| interface ILiquidityMiningV2 { | ||
| function withdraw( | ||
| address _poolToken, | ||
| uint256 _amount, | ||
| address _user | ||
| ) external; | ||
|
|
||
| function onTokensDeposited(address _user, uint256 _amount) external; | ||
|
|
||
| function getUserPoolTokenBalance(address _poolToken, address _user) | ||
| external | ||
| view | ||
| returns (uint256); | ||
|
|
||
| function setPoolInfoRewardToken( | ||
| address _poolToken, | ||
| address _rewardToken, | ||
| uint256 _lastRewardBlock, | ||
| uint256 _accumulatedRewardPerShare | ||
| ) external; | ||
|
|
||
| function setRewardToken( | ||
| address _rewardToken, | ||
| uint256 _startBlock, | ||
| uint256 _totalUsersBalance | ||
| ) external; | ||
|
|
||
| function setUserInfo( | ||
| uint256 _poolId, | ||
| address _user, | ||
| address _rewardToken, | ||
| uint256 _amount, | ||
| uint256 _rewardDebt, | ||
| uint256 _accumulatedReward | ||
| ) external; | ||
|
|
||
| function add( | ||
| address _poolToken, | ||
| address[] calldata _rewardTokens, | ||
| uint96[] calldata _allocationPoints, | ||
| bool _withUpdate | ||
| ) external; | ||
|
|
||
| function finishMigration() external; | ||
| } |
This file contains hidden or 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,22 @@ | ||
| pragma solidity 0.5.17; | ||
|
|
||
| /// @title This interface helps decoupling the Liquidity Mining reward | ||
| /// @dev Implement this interface in order to transfer the rewards with different logic. For example: | ||
| /// SOV tokens | ||
| interface IRewardTransferLogic { | ||
| /// @dev Returns the reward token address this contract will transfer | ||
| function getRewardTokenAddress() external view returns (address); | ||
|
|
||
| /// @notice Transfers will be executed from this address so it must be approved before invoking | ||
| function senderToAuthorize() external view returns (address); | ||
|
|
||
| /// @notice Transfers the reward amount to the specified address | ||
| /// @param _to The address to transfer the reward to | ||
| /// @param _value The amount of the reward to transfer | ||
| /// @param _isWithdrawal If true, means that the reward and the LP deposited tokens are being compeltely withdrawn | ||
| function transferReward( | ||
| address _to, | ||
| uint256 _value, | ||
| bool _isWithdrawal | ||
| ) external; | ||
| } |
This file contains hidden or 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,182 @@ | ||
| pragma solidity 0.5.17; | ||
| pragma experimental ABIEncoderV2; | ||
|
|
||
| import "../openzeppelin/ERC20.sol"; | ||
| import "../openzeppelin/SafeERC20.sol"; | ||
| import "../openzeppelin/SafeMath.sol"; | ||
| import "../utils/AdminRole.sol"; | ||
| import "./ILiquidityMiningV1.sol"; | ||
| import "./ILiquidityMiningV2.sol"; | ||
|
|
||
| contract LMV1toLMV2Migrator is AdminRole { | ||
| using SafeMath for uint256; | ||
| using SafeERC20 for IERC20; | ||
| enum MigrationStates { MigratingPools, MigratingUsers, MigratingFunds, MigrationFinished } | ||
|
|
||
| //represents de migration state from LiquidityMiningV1 to LiquidityMiningV2 | ||
| MigrationStates public migrationState; | ||
|
|
||
| //LiquidityMiningV1 contract address | ||
| ILiquidityMiningV1 public liquidityMiningV1; | ||
|
|
||
| //LiquidityMiningV2 contract address | ||
| ILiquidityMiningV2 public liquidityMiningV2; | ||
|
|
||
| /// @dev it is true if the user has been already migrated | ||
| mapping(address => bool) public userMigrated; | ||
|
|
||
| /// @dev The SOV token | ||
| IERC20 public SOV; | ||
|
|
||
| event UserMigrated(address indexed user); | ||
|
|
||
| /* Modifiers */ | ||
| modifier onlyPoolsMigrationState() { | ||
| require( | ||
| migrationState == MigrationStates.MigratingPools, | ||
| "Wrong state: should be MigratingPools" | ||
| ); | ||
| _; | ||
| } | ||
|
|
||
| modifier onlyUsersMigrationState() { | ||
| require( | ||
| migrationState == MigrationStates.MigratingUsers, | ||
| "Wrong state: should be MigratingUsers" | ||
| ); | ||
| _; | ||
| } | ||
|
|
||
| modifier onlyFundsMigrationState() { | ||
| require( | ||
| migrationState == MigrationStates.MigratingFunds, | ||
| "Wrong state: should be MigratingFunds" | ||
| ); | ||
| _; | ||
| } | ||
|
|
||
| /** | ||
| * @notice Initialize migrator | ||
| * | ||
| * @param _SOV The SOV token address | ||
| * @param _liquidityMiningV1 The LiquidityMiningV1 contract address | ||
| * @param _liquidityMiningV2 The LiquidityMiningV2 contract address | ||
| */ | ||
| function initialize( | ||
| IERC20 _SOV, | ||
| ILiquidityMiningV1 _liquidityMiningV1, | ||
| ILiquidityMiningV2 _liquidityMiningV2 | ||
| ) external onlyAuthorized { | ||
| require(address(_SOV) != address(0), "invalid token address"); | ||
| require(address(_liquidityMiningV1) != address(0), "invalid contract address"); | ||
| require(address(_liquidityMiningV2) != address(0), "invalid contract address"); | ||
| require(address(SOV) == address(0), "Already initialized"); | ||
| liquidityMiningV1 = _liquidityMiningV1; | ||
| liquidityMiningV2 = _liquidityMiningV2; | ||
| SOV = _SOV; | ||
| migrationState = MigrationStates.MigratingPools; | ||
| } | ||
|
|
||
| function _finishPoolsMigration() internal onlyPoolsMigrationState { | ||
| migrationState = MigrationStates.MigratingUsers; | ||
| } | ||
|
|
||
| function finishUsersMigration() external onlyAuthorized onlyUsersMigrationState { | ||
| migrationState = MigrationStates.MigratingFunds; | ||
| } | ||
|
|
||
| function _finishFundsMigration() internal onlyFundsMigrationState { | ||
| migrationState = MigrationStates.MigrationFinished; | ||
| } | ||
|
|
||
| /** | ||
| * @notice read all pools from liquidity mining V1 contract and add them | ||
| */ | ||
| function migratePools() external onlyAuthorized onlyPoolsMigrationState { | ||
| ( | ||
| address[] memory _poolToken, | ||
| uint96[] memory _allocationPoints, | ||
| uint256[] memory _lastRewardBlock, | ||
| uint256[] memory _accumulatedRewardPerShare | ||
| ) = liquidityMiningV1.getPoolInfoListArray(); | ||
|
|
||
| require(_poolToken.length == _allocationPoints.length, "Arrays mismatch"); | ||
| require(_poolToken.length == _lastRewardBlock.length, "Arrays mismatch"); | ||
|
|
||
| _finishPoolsMigration(); | ||
| liquidityMiningV1.finishMigrationGracePeriod(); | ||
| for (uint256 i = 0; i < _poolToken.length; i++) { | ||
| address poolToken = _poolToken[i]; | ||
| uint96[] memory allocationPoints = new uint96[](1); | ||
| allocationPoints[0] = _allocationPoints[i]; | ||
| uint256 lastRewardBlock = _lastRewardBlock[i]; | ||
| uint256 accumulatedRewardPerShare = _accumulatedRewardPerShare[i]; | ||
| address[] memory SOVAddress = new address[](1); | ||
| SOVAddress[0] = address(SOV); | ||
| //add will revert if poolToken is invalid or if it was already added | ||
| liquidityMiningV2.add(poolToken, SOVAddress, allocationPoints, false); | ||
| //add pool function put lastRewardBlock with current block number value, so we need to retrieve the original | ||
| liquidityMiningV2.setPoolInfoRewardToken( | ||
| poolToken, | ||
| address(SOV), | ||
| lastRewardBlock, | ||
| accumulatedRewardPerShare | ||
| ); | ||
| } | ||
| uint256 _startblock = liquidityMiningV1.getStartBlock(); | ||
| uint256 _totalUsersBalance = liquidityMiningV1.getTotalUsersBalance(); | ||
| liquidityMiningV2.setRewardToken(address(SOV), _startblock, _totalUsersBalance); | ||
| } | ||
|
|
||
| /** | ||
| * @notice read all users of all the pools from liquidity mining V1 contract and copy their info | ||
| * @param _users a list of users to be copied | ||
| */ | ||
|
|
||
| function migrateUsers(address[] calldata _users) | ||
| external | ||
| onlyAuthorized | ||
| onlyUsersMigrationState | ||
| { | ||
| for (uint256 i = 0; i < _users.length; i++) { | ||
| ( | ||
| uint256[] memory _amount, | ||
| uint256[] memory _rewardDebt, | ||
| uint256[] memory _accumulatedReward | ||
| ) = liquidityMiningV1.getUserInfoListArray(_users[i]); | ||
|
|
||
| require(_amount.length == _rewardDebt.length, "Arrays mismatch"); | ||
| require(_amount.length == _accumulatedReward.length, "Arrays mismatch"); | ||
|
|
||
| address user = _users[i]; | ||
|
|
||
| if (!userMigrated[user]) { | ||
| userMigrated[user] = true; | ||
| for (uint256 j = 0; j < _amount.length; j++) { | ||
| uint256 poolId = j; | ||
| uint256 _userAmount = _amount[j]; | ||
| uint256 _userRewardDebt = _rewardDebt[j]; | ||
| uint256 _userAccumulatedReward = _accumulatedReward[j]; | ||
| liquidityMiningV2.setUserInfo( | ||
| poolId, | ||
| user, | ||
| address(SOV), | ||
| _userAmount, | ||
| _userRewardDebt, | ||
| _userAccumulatedReward | ||
| ); | ||
| } | ||
| emit UserMigrated(user); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @notice transfer all funds from liquidity mining V1 | ||
| */ | ||
| function migrateFunds() external onlyAuthorized onlyFundsMigrationState { | ||
| _finishFundsMigration(); | ||
| liquidityMiningV1.migrateFunds(); | ||
| liquidityMiningV2.finishMigration(); | ||
| } | ||
| } |
This file contains hidden or 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,11 @@ | ||
| pragma solidity ^0.5.17; | ||
|
|
||
| import "./LiquidityMiningStorageV2.sol"; | ||
| import "../proxy/UpgradableProxy.sol"; | ||
|
|
||
| /** | ||
| * @dev LiquidityMining contract should be upgradable, use UpgradableProxy | ||
| */ | ||
| contract LiquidityMiningProxyV2 is LiquidityMiningStorageV2, UpgradableProxy { | ||
|
|
||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.