├── .gitignore ├── .solcover.js ├── README.md ├── STRATEGY.md ├── audits ├── Sherlock - Code Arena Jan 2022.pdf ├── Sherlock - Sherlock Audit October 2022.pdf ├── Sherlock - Trail of Bits Dec 2021.pdf └── Sherlock - Trail of Bits June 2022.pdf ├── contracts ├── SherBuy.sol ├── SherClaim.sol ├── Sherlock.sol ├── interfaces │ ├── ISherClaim.sol │ ├── ISherlock.sol │ ├── ISherlockGov.sol │ ├── ISherlockPayout.sol │ ├── ISherlockStake.sol │ ├── ISherlockStrategy.sol │ ├── UMAprotocol │ │ ├── OptimisticOracleInterface.sol │ │ ├── OptimisticRequester.sol │ │ └── SkinnyOptimisticOracleInterface.sol │ ├── aaveV2 │ │ ├── DataTypes.sol │ │ ├── IAToken.sol │ │ ├── IAaveDistributionManager.sol │ │ ├── IAaveGovernanceV2.sol │ │ ├── IAaveIncentivesController.sol │ │ ├── IExecutorWithTimelock.sol │ │ ├── IGovernanceV2Helper.sol │ │ ├── ILendingPool.sol │ │ ├── ILendingPoolAddressesProvider.sol │ │ ├── IProposalValidator.sol │ │ ├── IStakeAave.sol │ │ └── MockAave.sol │ ├── compound │ │ ├── ICToken.sol │ │ ├── IComptroller.sol │ │ └── InterestRateModel.sol │ ├── euler │ │ └── IEulerEToken.sol │ ├── managers │ │ ├── IManager.sol │ │ ├── ISherDistributionManager.sol │ │ ├── ISherlockClaimManager.sol │ │ ├── ISherlockProtocolManager.sol │ │ ├── IStrategyManager.sol │ │ └── callbacks │ │ │ └── ISherlockClaimManagerCallbackReceiver.sol │ ├── maple │ │ ├── IMplRewards.sol │ │ └── IPool.sol │ ├── strategy │ │ ├── IERC4626.sol │ │ ├── INode.sol │ │ └── IStrategy.sol │ ├── tempus │ │ └── ITempusController.sol │ └── truefi │ │ ├── ITrueFiPool2.sol │ │ └── ITrueMultiFarm.sol ├── managers │ ├── AaveV2Strategy.sol │ ├── Manager.sol │ ├── MasterStrategy.sol │ ├── SherDistributionManager.sol │ ├── SherDistributionManagerEmpty.sol │ ├── SherlockClaimManager.sol │ └── SherlockProtocolManager.sol ├── strategy │ ├── AaveStrategy.sol │ ├── CompoundStrategy.sol │ ├── EulerStrategy.sol │ ├── MapleStrategy.sol │ ├── TrueFiStrategy.sol │ ├── base │ │ ├── BaseMaster.sol │ │ ├── BaseNode.sol │ │ ├── BaseSplitter.sol │ │ └── BaseStrategy.sol │ ├── compound │ │ └── LibCompound.sol │ └── splitters │ │ ├── AlphaBetaEqualDepositMaxSplitter.sol │ │ ├── AlphaBetaEqualDepositSplitter.sol │ │ └── AlphaBetaSplitter.sol ├── test │ ├── AllowanceErrorTest.sol │ ├── ManagerTest.sol │ ├── PayableFail.sol │ ├── SherlockClaimManagerTest.sol │ ├── SherlockProtocolManagerTest.sol │ └── SherlockTest.sol └── util │ ├── CallbackMock.sol │ ├── ERC20Mock.sol │ ├── Import.sol │ ├── PausableMock.sol │ ├── SherDistributionMock.sol │ ├── SherlockMock.sol │ ├── SherlockProtocolManagerMock.sol │ ├── StrategyMock.sol │ ├── StrategyMockGoerli.sol │ ├── TreeSplitterMock.sol │ └── TreeStrategyMock.sol ├── funding.json ├── hardhat.config.js ├── package.json ├── scripts ├── 1_v2-deploy.js ├── 2_timelock.js ├── 3_fundraise.js ├── 4_start_fundraise.js ├── 5_verify.js ├── 6_sherdist.js ├── 6_strat.deploy.js ├── 8_strat_deploy.js ├── 9_strat_deploy.js ├── check-balance.js ├── compbalance.js ├── goeri-usdc.js ├── goerli_start.js ├── set_balance.js ├── set_hardhat.js ├── test.js ├── verify.js └── verify_2.js ├── test ├── AaveV2.js ├── BaseTreeStrategy.js ├── BaseTreeStrategyIntegration.js ├── ERC721.js ├── Manager.js ├── SherBuy.js ├── SherClaim.js ├── SherDistributionManager.js ├── Sherlock.js ├── SherlockClaimManager.js ├── SherlockProtocolManager.js ├── pausable.js ├── strategy │ ├── aave.js │ ├── compound.js │ ├── euler.js │ ├── mainnet.js │ ├── maple.js │ ├── splitters.js │ └── truefi.js └── utilities │ ├── index.js │ └── snapshot.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | 8 | coverage/ 9 | coverage.json 10 | .vscode/ 11 | -------------------------------------------------------------------------------- /.solcover.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mocha: { 3 | grep: '@skip-on-coverage', // Find everything with this tag 4 | invert: true, // Run the grep's inverse set. 5 | }, 6 | istanbulFolder: './coverage', 7 | istanbulReporter: ['html', 'text'], 8 | skipFiles: [ 9 | 'util/ERC20Mock.sol', 10 | 'util/SherDistributionMock.sol', 11 | 'util/SherlockMock.sol', 12 | 'util/SherlockProtocolManagerMock.sol', 13 | 'util/StrategyMock.sol', 14 | 'test/SherlockProtocolManagerTest.sol', 15 | 'test/SherlockTest.sol', 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sherlock V2 2 | 3 | Sherlock V2 is a multi contract protocol with upgradable parts. 4 | 5 | This README explains how the contracts are working together and what the tasks of every contract are. For a deep dive on the protocol mechanics please read our docs. 6 | 7 | ## Sherlock.sol 8 | 9 | > contracts/Sherlock.sol 10 | 11 | `Sherlock.sol` is the core contract which is not upgradable. It is the contract that holds and has access to all the capital. 12 | 13 | Stakers interact with this contract to create and manage positions in Sherlock. 14 | 15 | The owner (governance) will be able to update other logic parts of the protocol, these parts are 16 | 17 | - Claim Manager; is able to pull funds out of the Sherlock contract. 18 | - SHER Distribution Manager; contains the SHER tokens and logic to distribute among stakers. 19 | - Protocol Manager; manages covered protocols, balances and incoming premiums 20 | - NonStaker; is used by `Protocol Manager` to split premiums. 21 | - Yield Strategy; the capital can be deployed to earn extra yield in other protocols (Aave, Compound) 22 | 23 | ## Claim Manager 24 | 25 | > contracts/managers/SherlockClaimManager.sol 26 | 27 | The task of this contract is to expose a fully 'automated' claim process where governance is not step in between. 28 | 29 | Protocol agents are able to submit a claim that first passes by the Sherlock Protocol Claims Committee (SPCC), a multisig of security people in the space. In the SPCC denies the claim the protocol agent can escalate to UMA court, which gives UMA tokens holders (independent party) the final say in the validity of the claim. 30 | 31 | The UMA Halt Operator (UMAHO) is able to dismiss a validated claim by UMA. This role can be renounced by governance. 32 | 33 | If a claim is valid, funds are pulled out of the Sherlock contract and every staker is hit evenly. 34 | 35 | ## SHER distribution manager 36 | 37 | > contracts/managers/SherDistributionManager.sol 38 | 39 | The task of this contract is to distribute SHER tokens to stakers that are locking up their capital. 40 | 41 | The distribution curve is based on current TVL, using the time period as multiplier. 42 | 43 | The curve starts with a flat part to provide a fixed rate. It ends with a lineair slope all the way to a 0 rate. 44 | 45 | ## Protocol manager 46 | 47 | > contracts/managers/SherlockProtocolManager.sol 48 | 49 | Task of this contract is to manage the protocols that Sherlock covers. The contract is designed in a way where protocols are removed by arbs if their active balance runs out. 50 | 51 | Part of the premiums paid by the protocols go to non stakers. 52 | 53 | ## Non staker 54 | 55 | This address is able to pull funds out of the protocol manager contract. In the future a TBD contract will be used to compensate Watsons, reinsurers and potential other parties that provide value to this protocol relationship. 56 | 57 | ## Yield strategy 58 | 59 | > contracts/managers/AaveV2Strategy.sol 60 | 61 | Task of this contract is to allocate stakers fund to earn yield. 62 | -------------------------------------------------------------------------------- /audits/Sherlock - Code Arena Jan 2022.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sherlock-protocol/sherlock-v2-core/6d0ad29b504db57304ab74f942fe194e646dddb8/audits/Sherlock - Code Arena Jan 2022.pdf -------------------------------------------------------------------------------- /audits/Sherlock - Trail of Bits Dec 2021.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sherlock-protocol/sherlock-v2-core/6d0ad29b504db57304ab74f942fe194e646dddb8/audits/Sherlock - Trail of Bits Dec 2021.pdf -------------------------------------------------------------------------------- /audits/Sherlock - Trail of Bits June 2022.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sherlock-protocol/sherlock-v2-core/6d0ad29b504db57304ab74f942fe194e646dddb8/audits/Sherlock - Trail of Bits June 2022.pdf -------------------------------------------------------------------------------- /contracts/SherClaim.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 10 | import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; 11 | 12 | import './interfaces/ISherClaim.sol'; 13 | 14 | /// @title Claim SHER tokens send to the contract 15 | /// @author Evert Kors 16 | /// @dev This contract allows users to claim their bought SHER 17 | /// @dev The contract has two states seperated by the `_newEntryDeadline` timestamp (+ CLAIM_FREEZE_TIME_AFTER_DEADLINE) 18 | /// @dev Up until the timestamp, to be claimed SHER can be added using `add()` 19 | /// @dev After and including the timestamp, SHER can be claimed using `claim())` 20 | contract SherClaim is ISherClaim { 21 | using SafeERC20 for IERC20; 22 | 23 | // The state switch needs to be executed between BOTTOM and CEILING after deployment 24 | uint256 internal constant CLAIM_PERIOD_SANITY_BOTTOM = 7 days; 25 | uint256 internal constant CLAIM_PERIOD_SANITY_CEILING = 14 days; 26 | uint256 internal constant CLAIM_FREEZE_TIME_AFTER_DEADLINE = 26 weeks; 27 | 28 | // Timestamp up until new SHER entries can be added 29 | uint256 public immutable override newEntryDeadline; 30 | 31 | // SHER token address (18 decimals) 32 | IERC20 public immutable sher; 33 | 34 | // Mapping how much each user is able to claim 35 | mapping(address => uint256) public userClaims; 36 | 37 | /// @notice Construct claim contract 38 | /// @param _sher ERC20 contract for SHER token 39 | /// @param _newEntryDeadline Timestamp up until SHER entries can be added 40 | /// @dev _newEntryDeadline is between BOTTOM and CEILING after deployment 41 | constructor(IERC20 _sher, uint256 _newEntryDeadline) { 42 | if (address(_sher) == address(0)) revert ZeroArgument(); 43 | // Verify if _newEntryDeadline has a valid value 44 | if (_newEntryDeadline < block.timestamp + CLAIM_PERIOD_SANITY_BOTTOM) revert InvalidState(); 45 | if (_newEntryDeadline > block.timestamp + CLAIM_PERIOD_SANITY_CEILING) revert InvalidState(); 46 | 47 | sher = _sher; 48 | newEntryDeadline = _newEntryDeadline; 49 | } 50 | 51 | /// @notice Add `_amount` SHER to the timelock for `_user` 52 | /// @param _user The account that is able to claim the SHER 53 | /// @param _amount The amount of SHER that is added to the timelock 54 | function add(address _user, uint256 _amount) external override { 55 | if (_user == address(0)) revert ZeroArgument(); 56 | if (_amount == 0) revert ZeroArgument(); 57 | // Only allow new SHER to be added pre newEntryDeadline 58 | if (block.timestamp >= newEntryDeadline) revert InvalidState(); 59 | 60 | // Transfer SHER from caller to this contract 61 | sher.safeTransferFrom(msg.sender, address(this), _amount); 62 | // Account how much SHER the `_user` is able to claim 63 | userClaims[_user] += _amount; 64 | 65 | // Emit event about the new SHER tokens 66 | emit Add(msg.sender, _user, _amount); 67 | } 68 | 69 | /// @notice Allow caller to claim SHER tokens 70 | /// @dev Every account is able to call this once 71 | /// @dev Will revert in case the amount is 0 72 | /// @dev SHER tokens will be sent to caller 73 | function claim() external { 74 | // Only allow claim calls if claim period is active 75 | if (block.timestamp < newEntryDeadline + CLAIM_FREEZE_TIME_AFTER_DEADLINE) { 76 | revert InvalidState(); 77 | } 78 | 79 | // How much SHER the user will receive 80 | uint256 amount = userClaims[msg.sender]; 81 | // Dont proceed if it's 0 SHER 82 | if (amount == 0) revert InvalidAmount(); 83 | // If it is not 0, make sure it's 0 next time the user calls this function 84 | delete userClaims[msg.sender]; 85 | 86 | // Transfer SHER to user 87 | sher.safeTransfer(msg.sender, amount); 88 | 89 | // Emit event about the SHER claim 90 | emit Claim(msg.sender, amount); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /contracts/interfaces/ISherClaim.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | interface ISherClaim { 10 | error InvalidAmount(); 11 | error ZeroArgument(); 12 | error InvalidState(); 13 | 14 | // Event emitted when tokens have been added to the timelock 15 | event Add(address indexed sender, address indexed account, uint256 amount); 16 | // Event emitted when tokens have been claimed 17 | event Claim(address indexed account, uint256 amount); 18 | 19 | function add(address _user, uint256 _amount) external; 20 | 21 | function newEntryDeadline() external view returns (uint256); 22 | } 23 | -------------------------------------------------------------------------------- /contracts/interfaces/ISherlock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '@openzeppelin/contracts/token/ERC721/IERC721.sol'; 10 | import './ISherlockStake.sol'; 11 | import './ISherlockGov.sol'; 12 | import './ISherlockPayout.sol'; 13 | import './ISherlockStrategy.sol'; 14 | 15 | interface ISherlock is ISherlockStake, ISherlockGov, ISherlockPayout, ISherlockStrategy, IERC721 { 16 | // msg.sender is not authorized to call this function 17 | error Unauthorized(); 18 | 19 | // An address or other value passed in is equal to zero (and shouldn't be) 20 | error ZeroArgument(); 21 | 22 | // Occurs when a value already holds the desired property, or is not whitelisted 23 | error InvalidArgument(); 24 | 25 | // Required conditions are not true/met 26 | error InvalidConditions(); 27 | 28 | // If the SHER tokens held in a contract are not the value they are supposed to be 29 | error InvalidSherAmount(uint256 expected, uint256 actual); 30 | 31 | // Checks the ERC-721 functions _exists() to see if an NFT ID actually exists and errors if not 32 | error NonExistent(); 33 | 34 | event ArbRestaked(uint256 indexed tokenID, uint256 reward); 35 | 36 | event Restaked(uint256 indexed tokenID); 37 | } 38 | -------------------------------------------------------------------------------- /contracts/interfaces/ISherlockGov.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import './managers/ISherDistributionManager.sol'; 10 | import './managers/ISherlockProtocolManager.sol'; 11 | import './managers/ISherlockClaimManager.sol'; 12 | import './managers/IStrategyManager.sol'; 13 | 14 | /// @title Sherlock core interface for governance 15 | /// @author Evert Kors 16 | interface ISherlockGov { 17 | event ClaimPayout(address receiver, uint256 amount); 18 | event YieldStrategyUpdateWithdrawAllError(bytes error); 19 | event YieldStrategyUpdated(IStrategyManager previous, IStrategyManager current); 20 | event ProtocolManagerUpdated(ISherlockProtocolManager previous, ISherlockProtocolManager current); 21 | event ClaimManagerUpdated(ISherlockClaimManager previous, ISherlockClaimManager current); 22 | event NonStakerAddressUpdated(address previous, address current); 23 | event SherDistributionManagerUpdated( 24 | ISherDistributionManager previous, 25 | ISherDistributionManager current 26 | ); 27 | 28 | event StakingPeriodEnabled(uint256 period); 29 | 30 | event StakingPeriodDisabled(uint256 period); 31 | 32 | /// @notice Allows stakers to stake for `_period` of time 33 | /// @param _period Period of time, in seconds, 34 | /// @dev should revert if already enabled 35 | function enableStakingPeriod(uint256 _period) external; 36 | 37 | /// @notice Disallow stakers to stake for `_period` of time 38 | /// @param _period Period of time, in seconds, 39 | /// @dev should revert if already disabled 40 | function disableStakingPeriod(uint256 _period) external; 41 | 42 | /// @notice View if `_period` is a valid period 43 | /// @return Boolean indicating if period is valid 44 | function stakingPeriods(uint256 _period) external view returns (bool); 45 | 46 | /// @notice Update SHER distribution manager contract 47 | /// @param _sherDistributionManager New adddress of the manager 48 | function updateSherDistributionManager(ISherDistributionManager _sherDistributionManager) 49 | external; 50 | 51 | /// @notice Deletes the SHER distribution manager altogether (if Sherlock decides to no longer pay out SHER rewards) 52 | function removeSherDistributionManager() external; 53 | 54 | /// @notice Read SHER distribution manager 55 | /// @return Address of current SHER distribution manager 56 | function sherDistributionManager() external view returns (ISherDistributionManager); 57 | 58 | /// @notice Update address eligible for non staker rewards from protocol premiums 59 | /// @param _nonStakers Address eligible for non staker rewards 60 | function updateNonStakersAddress(address _nonStakers) external; 61 | 62 | /// @notice View current non stakers address 63 | /// @return Current non staker address 64 | /// @dev Is able to pull funds out of the contract 65 | function nonStakersAddress() external view returns (address); 66 | 67 | /// @notice View current address able to manage protocols 68 | /// @return Protocol manager implemenation 69 | function sherlockProtocolManager() external view returns (ISherlockProtocolManager); 70 | 71 | /// @notice Transfer protocol manager implementation address 72 | /// @param _protocolManager new implementation address 73 | function updateSherlockProtocolManager(ISherlockProtocolManager _protocolManager) external; 74 | 75 | /// @notice View current address able to pull payouts 76 | /// @return Address able to pull payouts 77 | function sherlockClaimManager() external view returns (ISherlockClaimManager); 78 | 79 | /// @notice Transfer claim manager role to different address 80 | /// @param _claimManager New address of claim manager 81 | function updateSherlockClaimManager(ISherlockClaimManager _claimManager) external; 82 | 83 | /// @notice Update yield strategy 84 | /// @param _yieldStrategy New address of the strategy 85 | /// @dev try a yieldStrategyWithdrawAll() on old, ignore failure 86 | function updateYieldStrategy(IStrategyManager _yieldStrategy) external; 87 | 88 | /// @notice Update yield strategy ignoring current state 89 | /// @param _yieldStrategy New address of the strategy 90 | /// @dev tries a yieldStrategyWithdrawAll() on old strategy, ignore failure 91 | function updateYieldStrategyForce(IStrategyManager _yieldStrategy) external; 92 | 93 | /// @notice Read current strategy 94 | /// @return Address of current strategy 95 | /// @dev can never be address(0) 96 | function yieldStrategy() external view returns (IStrategyManager); 97 | } 98 | -------------------------------------------------------------------------------- /contracts/interfaces/ISherlockPayout.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | /// @title Sherlock interface for payout manager 10 | /// @author Evert Kors 11 | interface ISherlockPayout { 12 | /// @notice Initiate a payout of `_amount` to `_receiver` 13 | /// @param _receiver Receiver of payout 14 | /// @param _amount Amount to send 15 | /// @dev only payout manager should call this 16 | /// @dev should pull money out of strategy 17 | function payoutClaim(address _receiver, uint256 _amount) external; 18 | } 19 | -------------------------------------------------------------------------------- /contracts/interfaces/ISherlockStake.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | /// @title Sherlock core interface for stakers 10 | /// @author Evert Kors 11 | interface ISherlockStake { 12 | /// @notice View the current lockup end timestamp of `_tokenID` 13 | /// @return Timestamp when NFT position unlocks 14 | function lockupEnd(uint256 _tokenID) external view returns (uint256); 15 | 16 | /// @notice View the current SHER reward of `_tokenID` 17 | /// @return Amount of SHER rewarded to owner upon reaching the end of the lockup 18 | function sherRewards(uint256 _tokenID) external view returns (uint256); 19 | 20 | /// @notice View the current token balance claimable upon reaching end of the lockup 21 | /// @return Amount of tokens assigned to owner when unstaking position 22 | function tokenBalanceOf(uint256 _tokenID) external view returns (uint256); 23 | 24 | /// @notice View the current TVL for all stakers 25 | /// @return Total amount of tokens staked 26 | /// @dev Adds principal + strategy + premiums 27 | /// @dev Will calculate the most up to date value for each piece 28 | function totalTokenBalanceStakers() external view returns (uint256); 29 | 30 | /// @notice Stakes `_amount` of tokens and locks up for `_period` seconds, `_receiver` will receive the NFT receipt 31 | /// @param _amount Amount of tokens to stake 32 | /// @param _period Period of time, in seconds, to lockup your funds 33 | /// @param _receiver Address that will receive the NFT representing the position 34 | /// @return _id ID of the position 35 | /// @return _sher Amount of SHER tokens to be released to this ID after `_period` ends 36 | /// @dev `_period` needs to be whitelisted 37 | function initialStake( 38 | uint256 _amount, 39 | uint256 _period, 40 | address _receiver 41 | ) external returns (uint256 _id, uint256 _sher); 42 | 43 | /// @notice Redeem NFT `_id` and receive `_amount` of tokens 44 | /// @param _id TokenID of the position 45 | /// @return _amount Amount of tokens (USDC) owed to NFT ID 46 | /// @dev Only the owner of `_id` will be able to redeem their position 47 | /// @dev The SHER rewards are sent to the NFT owner 48 | /// @dev Can only be called after lockup `_period` has ended 49 | function redeemNFT(uint256 _id) external returns (uint256 _amount); 50 | 51 | /// @notice Owner restakes position with ID: `_id` for `_period` seconds 52 | /// @param _id ID of the position 53 | /// @param _period Period of time, in seconds, to lockup your funds 54 | /// @return _sher Amount of SHER tokens to be released to owner address after `_period` ends 55 | /// @dev Only the owner of `_id` will be able to restake their position using this call 56 | /// @dev `_period` needs to be whitelisted 57 | /// @dev Can only be called after lockup `_period` has ended 58 | function ownerRestake(uint256 _id, uint256 _period) external returns (uint256 _sher); 59 | 60 | /// @notice Allows someone who doesn't own the position (an arbitrager) to restake the position for 26 weeks (ARB_RESTAKE_PERIOD) 61 | /// @param _id ID of the position 62 | /// @return _sher Amount of SHER tokens to be released to position owner on expiry of the 26 weeks lockup 63 | /// @return _arbReward Amount of tokens (USDC) sent to caller (the arbitrager) in return for calling the function 64 | /// @dev Can only be called after lockup `_period` is more than 2 weeks in the past (assuming ARB_RESTAKE_WAIT_TIME is 2 weeks) 65 | /// @dev Max 20% (ARB_RESTAKE_MAX_PERCENTAGE) of tokens associated with a position are used to incentivize arbs (x) 66 | /// @dev During a 2 week period the reward ratio will move from 0% to 100% (* x) 67 | function arbRestake(uint256 _id) external returns (uint256 _sher, uint256 _arbReward); 68 | } 69 | -------------------------------------------------------------------------------- /contracts/interfaces/ISherlockStrategy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import './managers/IStrategyManager.sol'; 10 | 11 | /// @title Sherlock core interface for yield strategy 12 | /// @author Evert Kors 13 | interface ISherlockStrategy { 14 | /// @notice Deposit `_amount` into active strategy 15 | /// @param _amount Amount of tokens 16 | /// @dev gov only 17 | function yieldStrategyDeposit(uint256 _amount) external; 18 | 19 | /// @notice Withdraw `_amount` from active strategy 20 | /// @param _amount Amount of tokens 21 | /// @dev gov only 22 | function yieldStrategyWithdraw(uint256 _amount) external; 23 | 24 | /// @notice Withdraw all funds from active strategy 25 | /// @dev gov only 26 | function yieldStrategyWithdrawAll() external; 27 | } 28 | -------------------------------------------------------------------------------- /contracts/interfaces/UMAprotocol/OptimisticRequester.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0-only 2 | pragma solidity ^0.8.0; 3 | 4 | import './SkinnyOptimisticOracleInterface.sol'; 5 | 6 | /** 7 | * @title Optimistic Requester. 8 | * @notice Optional interface that requesters can implement to receive callbacks. 9 | * @dev This contract does _not_ work with ERC777 collateral currencies or any others that call into the receiver on 10 | * transfer(). Using an ERC777 token would allow a user to maliciously grief other participants (while also losing 11 | * money themselves). 12 | */ 13 | interface OptimisticRequester { 14 | /** 15 | * @notice Callback for proposals. 16 | * @param identifier price identifier being requested. 17 | * @param timestamp timestamp of the price being requested. 18 | * @param ancillaryData ancillary data of the price being requested. 19 | * @param request request params after proposal. 20 | */ 21 | function priceProposed( 22 | bytes32 identifier, 23 | uint32 timestamp, 24 | bytes memory ancillaryData, 25 | SkinnyOptimisticOracleInterface.Request memory request 26 | ) external; 27 | 28 | /** 29 | * @notice Callback for disputes. 30 | * @param identifier price identifier being requested. 31 | * @param timestamp timestamp of the price being requested. 32 | * @param ancillaryData ancillary data of the price being requested. 33 | * @param request request params after dispute. 34 | */ 35 | function priceDisputed( 36 | bytes32 identifier, 37 | uint32 timestamp, 38 | bytes memory ancillaryData, 39 | SkinnyOptimisticOracleInterface.Request memory request 40 | ) external; 41 | 42 | /** 43 | * @notice Callback for settlement. 44 | * @param identifier price identifier being requested. 45 | * @param timestamp timestamp of the price being requested. 46 | * @param ancillaryData ancillary data of the price being requested. 47 | * @param request request params after settlement. 48 | */ 49 | function priceSettled( 50 | bytes32 identifier, 51 | uint32 timestamp, 52 | bytes memory ancillaryData, 53 | SkinnyOptimisticOracleInterface.Request memory request 54 | ) external; 55 | } 56 | -------------------------------------------------------------------------------- /contracts/interfaces/aaveV2/DataTypes.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity 0.8.10; 3 | 4 | library DataTypes { 5 | // refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties. 6 | struct ReserveData { 7 | //stores the reserve configuration 8 | ReserveConfigurationMap configuration; 9 | //the liquidity index. Expressed in ray 10 | uint128 liquidityIndex; 11 | //variable borrow index. Expressed in ray 12 | uint128 variableBorrowIndex; 13 | //the current supply rate. Expressed in ray 14 | uint128 currentLiquidityRate; 15 | //the current variable borrow rate. Expressed in ray 16 | uint128 currentVariableBorrowRate; 17 | //the current stable borrow rate. Expressed in ray 18 | uint128 currentStableBorrowRate; 19 | uint40 lastUpdateTimestamp; 20 | //tokens addresses 21 | address aTokenAddress; 22 | address stableDebtTokenAddress; 23 | address variableDebtTokenAddress; 24 | //address of the interest rate strategy 25 | address interestRateStrategyAddress; 26 | //the id of the reserve. Represents the position in the list of the active reserves 27 | uint8 id; 28 | } 29 | 30 | struct ReserveConfigurationMap { 31 | //bit 0-15: LTV 32 | //bit 16-31: Liq. threshold 33 | //bit 32-47: Liq. bonus 34 | //bit 48-55: Decimals 35 | //bit 56: Reserve is active 36 | //bit 57: reserve is frozen 37 | //bit 58: borrowing is enabled 38 | //bit 59: stable rate borrowing enabled 39 | //bit 60-63: reserved 40 | //bit 64-79: reserve factor 41 | uint256 data; 42 | } 43 | 44 | struct UserConfigurationMap { 45 | uint256 data; 46 | } 47 | 48 | enum InterestRateMode { 49 | NONE, 50 | STABLE, 51 | VARIABLE 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /contracts/interfaces/aaveV2/IAToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity 0.8.10; 3 | 4 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 5 | import './IAaveIncentivesController.sol'; 6 | 7 | interface IAToken is IERC20 { 8 | /** 9 | * @dev Emitted after the mint action 10 | * @param from The address performing the mint 11 | * @param value The amount being 12 | * @param index The new liquidity index of the reserve 13 | **/ 14 | event Mint(address indexed from, uint256 value, uint256 index); 15 | 16 | /** 17 | * @dev Mints `amount` aTokens to `user` 18 | * @param user The address receiving the minted tokens 19 | * @param amount The amount of tokens getting minted 20 | * @param index The new liquidity index of the reserve 21 | * @return `true` if the the previous balance of the user was 0 22 | */ 23 | function mint( 24 | address user, 25 | uint256 amount, 26 | uint256 index 27 | ) external returns (bool); 28 | 29 | /** 30 | * @dev Emitted after aTokens are burned 31 | * @param from The owner of the aTokens, getting them burned 32 | * @param target The address that will receive the underlying 33 | * @param value The amount being burned 34 | * @param index The new liquidity index of the reserve 35 | **/ 36 | event Burn(address indexed from, address indexed target, uint256 value, uint256 index); 37 | 38 | /** 39 | * @dev Emitted during the transfer action 40 | * @param from The user whose tokens are being transferred 41 | * @param to The recipient 42 | * @param value The amount being transferred 43 | * @param index The new liquidity index of the reserve 44 | **/ 45 | event BalanceTransfer(address indexed from, address indexed to, uint256 value, uint256 index); 46 | 47 | /** 48 | * @dev Burns aTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying` 49 | * @param user The owner of the aTokens, getting them burned 50 | * @param receiverOfUnderlying The address that will receive the underlying 51 | * @param amount The amount being burned 52 | * @param index The new liquidity index of the reserve 53 | **/ 54 | function burn( 55 | address user, 56 | address receiverOfUnderlying, 57 | uint256 amount, 58 | uint256 index 59 | ) external; 60 | 61 | /** 62 | * @dev Mints aTokens to the reserve treasury 63 | * @param amount The amount of tokens getting minted 64 | * @param index The new liquidity index of the reserve 65 | */ 66 | function mintToTreasury(uint256 amount, uint256 index) external; 67 | 68 | /** 69 | * @dev Transfers aTokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken 70 | * @param from The address getting liquidated, current owner of the aTokens 71 | * @param to The recipient 72 | * @param value The amount of tokens getting transferred 73 | **/ 74 | function transferOnLiquidation( 75 | address from, 76 | address to, 77 | uint256 value 78 | ) external; 79 | 80 | /** 81 | * @dev Transfers the underlying asset to `target`. Used by the LendingPool to transfer 82 | * assets in borrow(), withdraw() and flashLoan() 83 | * @param user The recipient of the underlying 84 | * @param amount The amount getting transferred 85 | * @return The amount transferred 86 | **/ 87 | function transferUnderlyingTo(address user, uint256 amount) external returns (uint256); 88 | 89 | /** 90 | * @dev Invoked to execute actions on the aToken side after a repayment. 91 | * @param user The user executing the repayment 92 | * @param amount The amount getting repaid 93 | **/ 94 | function handleRepayment(address user, uint256 amount) external; 95 | 96 | /** 97 | * @dev Returns the address of the incentives controller contract 98 | **/ 99 | function getIncentivesController() external view returns (IAaveIncentivesController); 100 | 101 | /** 102 | * @dev Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH) 103 | **/ 104 | function UNDERLYING_ASSET_ADDRESS() external view returns (address); 105 | } 106 | -------------------------------------------------------------------------------- /contracts/interfaces/aaveV2/IAaveDistributionManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity 0.8.10; 3 | pragma experimental ABIEncoderV2; 4 | 5 | library DistributionTypes { 6 | struct AssetConfigInput { 7 | uint104 emissionPerSecond; 8 | uint256 totalStaked; 9 | address underlyingAsset; 10 | } 11 | 12 | struct UserStakeInput { 13 | address underlyingAsset; 14 | uint256 stakedByUser; 15 | uint256 totalStaked; 16 | } 17 | } 18 | 19 | interface IAaveDistributionManager { 20 | event AssetConfigUpdated(address indexed asset, uint256 emission); 21 | event AssetIndexUpdated(address indexed asset, uint256 index); 22 | event UserIndexUpdated(address indexed user, address indexed asset, uint256 index); 23 | event DistributionEndUpdated(uint256 newDistributionEnd); 24 | 25 | /** 26 | * @dev Sets the end date for the distribution 27 | * @param distributionEnd The end date timestamp 28 | **/ 29 | function setDistributionEnd(uint256 distributionEnd) external; 30 | 31 | /** 32 | * @dev Gets the end date for the distribution 33 | * @return The end of the distribution 34 | **/ 35 | function getDistributionEnd() external view returns (uint256); 36 | 37 | /** 38 | * @dev for backwards compatibility with the previous DistributionManager used 39 | * @return The end of the distribution 40 | **/ 41 | function DISTRIBUTION_END() external view returns (uint256); 42 | 43 | /** 44 | * @dev Returns the data of an user on a distribution 45 | * @param user Address of the user 46 | * @param asset The address of the reference asset of the distribution 47 | * @return The new index 48 | **/ 49 | function getUserAssetData(address user, address asset) external view returns (uint256); 50 | 51 | /** 52 | * @dev Returns the configuration of the distribution for a certain asset 53 | * @param asset The address of the reference asset of the distribution 54 | * @return The asset index, the emission per second and the last updated timestamp 55 | **/ 56 | function getAssetData(address asset) 57 | external 58 | view 59 | returns ( 60 | uint256, 61 | uint256, 62 | uint256 63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /contracts/interfaces/aaveV2/IAaveIncentivesController.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity 0.8.10; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | import { IAaveDistributionManager } from './IAaveDistributionManager.sol'; 7 | 8 | interface IAaveIncentivesController is IAaveDistributionManager { 9 | event RewardsAccrued(address indexed user, uint256 amount); 10 | 11 | event RewardsClaimed( 12 | address indexed user, 13 | address indexed to, 14 | address indexed claimer, 15 | uint256 amount 16 | ); 17 | 18 | event ClaimerSet(address indexed user, address indexed claimer); 19 | 20 | /** 21 | * @dev Whitelists an address to claim the rewards on behalf of another address 22 | * @param user The address of the user 23 | * @param claimer The address of the claimer 24 | */ 25 | function setClaimer(address user, address claimer) external; 26 | 27 | /** 28 | * @dev Returns the whitelisted claimer for a certain address (0x0 if not set) 29 | * @param user The address of the user 30 | * @return The claimer address 31 | */ 32 | function getClaimer(address user) external view returns (address); 33 | 34 | /** 35 | * @dev Configure assets for a certain rewards emission 36 | * @param assets The assets to incentivize 37 | * @param emissionsPerSecond The emission for each asset 38 | */ 39 | function configureAssets(address[] calldata assets, uint256[] calldata emissionsPerSecond) 40 | external; 41 | 42 | /** 43 | * @dev Called by the corresponding asset on any update that affects the rewards distribution 44 | * @param asset The address of the user 45 | * @param userBalance The balance of the user of the asset in the lending pool 46 | * @param totalSupply The total supply of the asset in the lending pool 47 | **/ 48 | function handleAction( 49 | address asset, 50 | uint256 userBalance, 51 | uint256 totalSupply 52 | ) external; 53 | 54 | /** 55 | * @dev Returns the total of rewards of an user, already accrued + not yet accrued 56 | * @param user The address of the user 57 | * @return The rewards 58 | **/ 59 | function getRewardsBalance(address[] calldata assets, address user) 60 | external 61 | view 62 | returns (uint256); 63 | 64 | /** 65 | * @dev Claims reward for an user, on all the assets of the lending pool, accumulating the pending rewards 66 | * @param amount Amount of rewards to claim 67 | * @param to Address that will be receiving the rewards 68 | * @return Rewards claimed 69 | **/ 70 | function claimRewards( 71 | address[] calldata assets, 72 | uint256 amount, 73 | address to 74 | ) external returns (uint256); 75 | 76 | /** 77 | * @dev Claims reward for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards. The caller must 78 | * be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager 79 | * @param amount Amount of rewards to claim 80 | * @param user Address to check and claim rewards 81 | * @param to Address that will be receiving the rewards 82 | * @return Rewards claimed 83 | **/ 84 | function claimRewardsOnBehalf( 85 | address[] calldata assets, 86 | uint256 amount, 87 | address user, 88 | address to 89 | ) external returns (uint256); 90 | 91 | /** 92 | * @dev returns the unclaimed rewards of the user 93 | * @param user the address of the user 94 | * @return the unclaimed user rewards 95 | */ 96 | function getUserUnclaimedRewards(address user) external view returns (uint256); 97 | 98 | /** 99 | * @dev for backward compatibility with previous implementation of the Incentives controller 100 | */ 101 | function REWARD_TOKEN() external view returns (address); 102 | } 103 | -------------------------------------------------------------------------------- /contracts/interfaces/aaveV2/IGovernanceV2Helper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity 0.8.10; 3 | pragma abicoder v2; 4 | 5 | import { IAaveGovernanceV2 } from './IAaveGovernanceV2.sol'; 6 | import { IExecutorWithTimelock } from './IExecutorWithTimelock.sol'; 7 | 8 | interface IGovernanceV2Helper { 9 | struct ProposalStats { 10 | uint256 totalVotingSupply; 11 | uint256 minimumQuorum; 12 | uint256 minimumDiff; 13 | uint256 executionTimeWithGracePeriod; 14 | uint256 proposalCreated; 15 | uint256 id; 16 | address creator; 17 | IExecutorWithTimelock executor; 18 | address[] targets; 19 | uint256[] values; 20 | string[] signatures; 21 | bytes[] calldatas; 22 | bool[] withDelegatecalls; 23 | uint256 startBlock; 24 | uint256 endBlock; 25 | uint256 executionTime; 26 | uint256 forVotes; 27 | uint256 againstVotes; 28 | bool executed; 29 | bool canceled; 30 | address strategy; 31 | bytes32 ipfsHash; 32 | IAaveGovernanceV2.ProposalState proposalState; 33 | } 34 | 35 | struct Power { 36 | uint256 votingPower; 37 | address delegatedAddressVotingPower; 38 | uint256 propositionPower; 39 | address delegatedAddressPropositionPower; 40 | } 41 | 42 | function getProposals( 43 | uint256 skip, 44 | uint256 limit, 45 | IAaveGovernanceV2 governance 46 | ) external view virtual returns (ProposalStats[] memory proposalsStats); 47 | 48 | function getProposal(uint256 id, IAaveGovernanceV2 governance) 49 | external 50 | view 51 | virtual 52 | returns (ProposalStats memory proposalStats); 53 | 54 | function getTokensPower(address user, address[] memory tokens) 55 | external 56 | view 57 | virtual 58 | returns (Power[] memory power); 59 | } 60 | -------------------------------------------------------------------------------- /contracts/interfaces/aaveV2/ILendingPoolAddressesProvider.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity 0.8.10; 3 | 4 | /** 5 | * @title LendingPoolAddressesProvider contract 6 | * @dev Main registry of addresses part of or connected to the protocol, including permissioned roles 7 | * - Acting also as factory of proxies and admin of those, so with right to change its implementations 8 | * - Owned by the Aave Governance 9 | * @author Aave 10 | **/ 11 | interface ILendingPoolAddressesProvider { 12 | event MarketIdSet(string newMarketId); 13 | event LendingPoolUpdated(address indexed newAddress); 14 | event ConfigurationAdminUpdated(address indexed newAddress); 15 | event EmergencyAdminUpdated(address indexed newAddress); 16 | event LendingPoolConfiguratorUpdated(address indexed newAddress); 17 | event LendingPoolCollateralManagerUpdated(address indexed newAddress); 18 | event PriceOracleUpdated(address indexed newAddress); 19 | event LendingRateOracleUpdated(address indexed newAddress); 20 | event ProxyCreated(bytes32 id, address indexed newAddress); 21 | event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy); 22 | 23 | function getMarketId() external view returns (string memory); 24 | 25 | function setMarketId(string calldata marketId) external; 26 | 27 | function setAddress(bytes32 id, address newAddress) external; 28 | 29 | function setAddressAsProxy(bytes32 id, address impl) external; 30 | 31 | function getAddress(bytes32 id) external view returns (address); 32 | 33 | function getLendingPool() external view returns (address); 34 | 35 | function setLendingPoolImpl(address pool) external; 36 | 37 | function getLendingPoolConfigurator() external view returns (address); 38 | 39 | function setLendingPoolConfiguratorImpl(address configurator) external; 40 | 41 | function getLendingPoolCollateralManager() external view returns (address); 42 | 43 | function setLendingPoolCollateralManager(address manager) external; 44 | 45 | function getPoolAdmin() external view returns (address); 46 | 47 | function setPoolAdmin(address admin) external; 48 | 49 | function getEmergencyAdmin() external view returns (address); 50 | 51 | function setEmergencyAdmin(address admin) external; 52 | 53 | function getPriceOracle() external view returns (address); 54 | 55 | function setPriceOracle(address priceOracle) external; 56 | 57 | function getLendingRateOracle() external view returns (address); 58 | 59 | function setLendingRateOracle(address lendingRateOracle) external; 60 | } 61 | -------------------------------------------------------------------------------- /contracts/interfaces/aaveV2/IProposalValidator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity 0.8.10; 3 | pragma abicoder v2; 4 | 5 | import { IAaveGovernanceV2 } from './IAaveGovernanceV2.sol'; 6 | 7 | interface IProposalValidator { 8 | /** 9 | * @dev Called to validate a proposal (e.g when creating new proposal in Governance) 10 | * @param governance Governance Contract 11 | * @param user Address of the proposal creator 12 | * @param blockNumber Block Number against which to make the test (e.g proposal creation block -1). 13 | * @return boolean, true if can be created 14 | **/ 15 | function validateCreatorOfProposal( 16 | IAaveGovernanceV2 governance, 17 | address user, 18 | uint256 blockNumber 19 | ) external view returns (bool); 20 | 21 | /** 22 | * @dev Called to validate the cancellation of a proposal 23 | * @param governance Governance Contract 24 | * @param user Address of the proposal creator 25 | * @param blockNumber Block Number against which to make the test (e.g proposal creation block -1). 26 | * @return boolean, true if can be cancelled 27 | **/ 28 | function validateProposalCancellation( 29 | IAaveGovernanceV2 governance, 30 | address user, 31 | uint256 blockNumber 32 | ) external view returns (bool); 33 | 34 | /** 35 | * @dev Returns whether a user has enough Proposition Power to make a proposal. 36 | * @param governance Governance Contract 37 | * @param user Address of the user to be challenged. 38 | * @param blockNumber Block Number against which to make the challenge. 39 | * @return true if user has enough power 40 | **/ 41 | function isPropositionPowerEnough( 42 | IAaveGovernanceV2 governance, 43 | address user, 44 | uint256 blockNumber 45 | ) external view returns (bool); 46 | 47 | /** 48 | * @dev Returns the minimum Proposition Power needed to create a proposition. 49 | * @param governance Governance Contract 50 | * @param blockNumber Blocknumber at which to evaluate 51 | * @return minimum Proposition Power needed 52 | **/ 53 | function getMinimumPropositionPowerNeeded(IAaveGovernanceV2 governance, uint256 blockNumber) 54 | external 55 | view 56 | returns (uint256); 57 | 58 | /** 59 | * @dev Returns whether a proposal passed or not 60 | * @param governance Governance Contract 61 | * @param proposalId Id of the proposal to set 62 | * @return true if proposal passed 63 | **/ 64 | function isProposalPassed(IAaveGovernanceV2 governance, uint256 proposalId) 65 | external 66 | view 67 | returns (bool); 68 | 69 | /** 70 | * @dev Check whether a proposal has reached quorum, ie has enough FOR-voting-power 71 | * Here quorum is not to understand as number of votes reached, but number of for-votes reached 72 | * @param governance Governance Contract 73 | * @param proposalId Id of the proposal to verify 74 | * @return voting power needed for a proposal to pass 75 | **/ 76 | function isQuorumValid(IAaveGovernanceV2 governance, uint256 proposalId) 77 | external 78 | view 79 | returns (bool); 80 | 81 | /** 82 | * @dev Check whether a proposal has enough extra FOR-votes than AGAINST-votes 83 | * FOR VOTES - AGAINST VOTES > VOTE_DIFFERENTIAL * voting supply 84 | * @param governance Governance Contract 85 | * @param proposalId Id of the proposal to verify 86 | * @return true if enough For-Votes 87 | **/ 88 | function isVoteDifferentialValid(IAaveGovernanceV2 governance, uint256 proposalId) 89 | external 90 | view 91 | returns (bool); 92 | 93 | /** 94 | * @dev Calculates the minimum amount of Voting Power needed for a proposal to Pass 95 | * @param votingSupply Total number of oustanding voting tokens 96 | * @return voting power needed for a proposal to pass 97 | **/ 98 | function getMinimumVotingPowerNeeded(uint256 votingSupply) external view returns (uint256); 99 | 100 | /** 101 | * @dev Get proposition threshold constant value 102 | * @return the proposition threshold value (100 <=> 1%) 103 | **/ 104 | function PROPOSITION_THRESHOLD() external view returns (uint256); 105 | 106 | /** 107 | * @dev Get voting duration constant value 108 | * @return the voting duration value in seconds 109 | **/ 110 | function VOTING_DURATION() external view returns (uint256); 111 | 112 | /** 113 | * @dev Get the vote differential threshold constant value 114 | * to compare with % of for votes/total supply - % of against votes/total supply 115 | * @return the vote differential threshold value (100 <=> 1%) 116 | **/ 117 | function VOTE_DIFFERENTIAL() external view returns (uint256); 118 | 119 | /** 120 | * @dev Get quorum threshold constant value 121 | * to compare with % of for votes/total supply 122 | * @return the quorum threshold value (100 <=> 1%) 123 | **/ 124 | function MINIMUM_QUORUM() external view returns (uint256); 125 | 126 | /** 127 | * @dev precision helper: 100% = 10000 128 | * @return one hundred percents with our chosen precision 129 | **/ 130 | function ONE_HUNDRED_WITH_PRECISION() external view returns (uint256); 131 | } 132 | -------------------------------------------------------------------------------- /contracts/interfaces/aaveV2/IStakeAave.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 5 | 6 | interface IStakeAave is IERC20 { 7 | function cooldown() external; 8 | 9 | function claimRewards(address to, uint256 amount) external; 10 | 11 | function redeem(address to, uint256 amount) external; 12 | 13 | function getTotalRewardsBalance(address staker) external view returns (uint256); 14 | } 15 | -------------------------------------------------------------------------------- /contracts/interfaces/aaveV2/MockAave.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity 0.8.10; 3 | 4 | interface MockAave { 5 | function mint(address receiver, uint256 amount) external; 6 | } 7 | -------------------------------------------------------------------------------- /contracts/interfaces/compound/ICToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity 0.8.10; 3 | 4 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 5 | import { InterestRateModel } from './InterestRateModel.sol'; 6 | 7 | /** 8 | * Interface for Compound's cToken. 9 | */ 10 | 11 | interface ICToken is IERC20 { 12 | function mint(uint256) external returns (uint256); 13 | 14 | function borrow(uint256) external returns (uint256); 15 | 16 | function underlying() external view returns (IERC20); 17 | 18 | function totalBorrows() external view returns (uint256); 19 | 20 | function totalFuseFees() external view returns (uint256); 21 | 22 | function repayBorrow(uint256) external returns (uint256); 23 | 24 | function totalReserves() external view returns (uint256); 25 | 26 | function exchangeRateCurrent() external returns (uint256); 27 | 28 | function totalAdminFees() external view returns (uint256); 29 | 30 | function fuseFeeMantissa() external view returns (uint256); 31 | 32 | function adminFeeMantissa() external view returns (uint256); 33 | 34 | function exchangeRateStored() external view returns (uint256); 35 | 36 | function accrualBlockNumber() external view returns (uint256); 37 | 38 | function redeem(uint256) external returns (uint256); 39 | 40 | function redeemUnderlying(uint256) external returns (uint256); 41 | 42 | function balanceOfUnderlying(address) external returns (uint256); 43 | 44 | function reserveFactorMantissa() external view returns (uint256); 45 | 46 | function borrowBalanceCurrent(address) external returns (uint256); 47 | 48 | function interestRateModel() external view returns (InterestRateModel); 49 | 50 | function initialExchangeRateMantissa() external view returns (uint256); 51 | 52 | function repayBorrowBehalf(address, uint256) external returns (uint256); 53 | } 54 | -------------------------------------------------------------------------------- /contracts/interfaces/compound/IComptroller.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity 0.8.10; 3 | 4 | import './ICToken.sol'; 5 | 6 | interface IComptroller is IERC20 { 7 | function compAccrued(address _address) external view returns (uint256); 8 | 9 | function claimComp( 10 | address[] memory holders, 11 | ICToken[] memory cTokens, 12 | bool borrowers, 13 | bool suppliers 14 | ) external; 15 | } 16 | -------------------------------------------------------------------------------- /contracts/interfaces/compound/InterestRateModel.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | interface InterestRateModel { 5 | function getBorrowRate( 6 | uint256, 7 | uint256, 8 | uint256 9 | ) external view returns (uint256); 10 | 11 | function getSupplyRate( 12 | uint256, 13 | uint256, 14 | uint256, 15 | uint256 16 | ) external view returns (uint256); 17 | } 18 | -------------------------------------------------------------------------------- /contracts/interfaces/euler/IEulerEToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity 0.8.10; 3 | 4 | interface IEulerEToken { 5 | function balanceOfUnderlying(address account) external view returns (uint256); 6 | 7 | function balanceOf(address account) external view returns (uint256); 8 | 9 | function withdraw(uint256 subAccountId, uint256 amount) external; 10 | 11 | function deposit(uint256 subAccountId, uint256 amount) external; 12 | } 13 | -------------------------------------------------------------------------------- /contracts/interfaces/managers/IManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '../ISherlock.sol'; 10 | 11 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 12 | 13 | interface IManager { 14 | // An address or other value passed in is equal to zero (and shouldn't be) 15 | error ZeroArgument(); 16 | 17 | // Occurs when a value already holds the desired property, or is not whitelisted 18 | error InvalidArgument(); 19 | 20 | // If a required condition for executing the function is not met, it reverts and throws this error 21 | error InvalidConditions(); 22 | 23 | // Throws if the msg.sender is not the required address 24 | error InvalidSender(); 25 | 26 | event SherlockCoreSet(ISherlock sherlock); 27 | 28 | /// @notice Set sherlock core address where premiums should be send too 29 | /// @param _sherlock Current core contract 30 | /// @dev Only deployer is able to set core address on all chains except Hardhat network 31 | /// @dev One time function, will revert once `sherlock` != address(0) 32 | /// @dev This contract will be deployed first, passed on as argument in core constuctor 33 | /// @dev ^ that's needed for tvl accounting, once core is deployed this function is called 34 | /// @dev emits `SherlockCoreSet` 35 | function setSherlockCoreAddress(ISherlock _sherlock) external; 36 | 37 | /// @notice Pause external functions in contract 38 | function pause() external; 39 | 40 | /// @notice Unpause external functions in contract 41 | function unpause() external; 42 | } 43 | -------------------------------------------------------------------------------- /contracts/interfaces/managers/ISherDistributionManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 10 | import './IManager.sol'; 11 | 12 | interface ISherDistributionManager is IManager { 13 | // anyone can just send token to this contract to fund rewards 14 | 15 | event Initialized(uint256 maxRewardsEndTVL, uint256 zeroRewardsStartTVL, uint256 maxRewardRate); 16 | 17 | /// @notice Caller will receive `_sher` SHER tokens based on `_amount` and `_period` 18 | /// @param _amount Amount of tokens (in USDC) staked 19 | /// @param _period Period of time for stake, in seconds 20 | /// @param _id ID for this NFT position 21 | /// @param _receiver Address that will be linked to this position 22 | /// @return _sher Amount of SHER tokens sent to Sherlock core contract 23 | /// @dev Calling contract will depend on before + after balance diff and return value 24 | /// @dev INCLUDES stake in calculation, function expects the `_amount` to be deposited already 25 | /// @dev If tvl=50 and amount=50, this means it is calculating SHER rewards for the first 50 tokens going in 26 | function pullReward( 27 | uint256 _amount, 28 | uint256 _period, 29 | uint256 _id, 30 | address _receiver 31 | ) external returns (uint256 _sher); 32 | 33 | /// @notice Calculates how many `_sher` SHER tokens are owed to a stake position based on `_amount` and `_period` 34 | /// @param _tvl TVL to use for reward calculation (pre-stake TVL) 35 | /// @param _amount Amount of tokens (USDC) staked 36 | /// @param _period Stake period (in seconds) 37 | /// @return _sher Amount of SHER tokens owed to this stake position 38 | /// @dev EXCLUDES `_amount` of stake, this will be added on top of TVL (_tvl is excluding _amount) 39 | /// @dev If tvl=0 and amount=50, it would calculate for the first 50 tokens going in (different from pullReward()) 40 | function calcReward( 41 | uint256 _tvl, 42 | uint256 _amount, 43 | uint256 _period 44 | ) external view returns (uint256 _sher); 45 | 46 | /// @notice Function used to check if this is the current active distribution manager 47 | /// @return Boolean indicating it's active 48 | /// @dev If inactive the owner can pull all ERC20s and ETH 49 | /// @dev Will be checked by calling the sherlock contract 50 | function isActive() external view returns (bool); 51 | } 52 | -------------------------------------------------------------------------------- /contracts/interfaces/managers/IStrategyManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import './IManager.sol'; 10 | 11 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 12 | 13 | interface IStrategyManager is IManager { 14 | /// @return Returns the token type being deposited into a strategy 15 | function want() external view returns (IERC20); 16 | 17 | /// @notice Withdraws all USDC from the strategy back into the Sherlock core contract 18 | /// @dev Only callable by the Sherlock core contract 19 | /// @return The final amount withdrawn 20 | function withdrawAll() external returns (uint256); 21 | 22 | /// @notice Withdraws a specific amount of USDC from the strategy back into the Sherlock core contract 23 | /// @param _amount Amount of USDC to withdraw 24 | function withdraw(uint256 _amount) external; 25 | 26 | /// @notice Deposits all USDC held in this contract into the strategy 27 | function deposit() external; 28 | 29 | /// @return Returns the USDC balance in this contract 30 | function balanceOf() external view returns (uint256); 31 | } 32 | -------------------------------------------------------------------------------- /contracts/interfaces/managers/callbacks/ISherlockClaimManagerCallbackReceiver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | interface ISherlockClaimManagerCallbackReceiver { 10 | /// @notice Calls this function on approved contracts and passes args 11 | /// @param _protocol The protocol that is receiving the payout 12 | /// @param _claimID The claim ID that is receiving the payout 13 | /// @param _amount The amount of USDC being paid out for this claim 14 | function PreCorePayoutCallback( 15 | bytes32 _protocol, 16 | uint256 _claimID, 17 | uint256 _amount 18 | ) external; 19 | } 20 | -------------------------------------------------------------------------------- /contracts/interfaces/maple/IPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity 0.8.10; 3 | 4 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 5 | 6 | interface IPool is IERC20 { 7 | // https://github.com/maple-labs/maple-core/blob/main/contracts/token/interfaces/IBaseFDT.sol 8 | function withdrawableFundsOf(address owner) external view returns (uint256); 9 | 10 | // https://github.com/maple-labs/maple-core/blob/main/contracts/token/interfaces/IExtendedFDT.sol 11 | function recognizableLossesOf(address) external view returns (uint256); 12 | 13 | function poolDelegate() external view returns (address); 14 | 15 | function poolAdmins(address) external view returns (bool); 16 | 17 | function deposit(uint256) external; 18 | 19 | function increaseCustodyAllowance(address, uint256) external; 20 | 21 | function transferByCustodian( 22 | address, 23 | address, 24 | uint256 25 | ) external; 26 | 27 | function poolState() external view returns (uint256); 28 | 29 | function deactivate() external; 30 | 31 | function finalize() external; 32 | 33 | function claim(address, address) external returns (uint256[7] memory); 34 | 35 | function setLockupPeriod(uint256) external; 36 | 37 | function setStakingFee(uint256) external; 38 | 39 | function setPoolAdmin(address, bool) external; 40 | 41 | function fundLoan( 42 | address, 43 | address, 44 | uint256 45 | ) external; 46 | 47 | function withdraw(uint256) external; 48 | 49 | function superFactory() external view returns (address); 50 | 51 | function triggerDefault(address, address) external; 52 | 53 | function isPoolFinalized() external view returns (bool); 54 | 55 | function setOpenToPublic(bool) external; 56 | 57 | function setAllowList(address, bool) external; 58 | 59 | function allowedLiquidityProviders(address) external view returns (bool); 60 | 61 | function openToPublic() external view returns (bool); 62 | 63 | function intendToWithdraw() external; 64 | 65 | function DL_FACTORY() external view returns (uint8); 66 | 67 | function liquidityAsset() external view returns (IERC20); 68 | 69 | function liquidityLocker() external view returns (address); 70 | 71 | function stakeAsset() external view returns (address); 72 | 73 | function stakeLocker() external view returns (address); 74 | 75 | function stakingFee() external view returns (uint256); 76 | 77 | function delegateFee() external view returns (uint256); 78 | 79 | function principalOut() external view returns (uint256); 80 | 81 | function liquidityCap() external view returns (uint256); 82 | 83 | function lockupPeriod() external view returns (uint256); 84 | 85 | function depositDate(address) external view returns (uint256); 86 | 87 | function debtLockers(address, address) external view returns (address); 88 | 89 | function withdrawCooldown(address) external view returns (uint256); 90 | 91 | function setLiquidityCap(uint256) external; 92 | 93 | function cancelWithdraw() external; 94 | 95 | function reclaimERC20(address) external; 96 | 97 | function BPTVal( 98 | address, 99 | address, 100 | address, 101 | address 102 | ) external view returns (uint256); 103 | 104 | function isDepositAllowed(uint256) external view returns (bool); 105 | 106 | function getInitialStakeRequirements() 107 | external 108 | view 109 | returns ( 110 | uint256, 111 | uint256, 112 | bool, 113 | uint256, 114 | uint256 115 | ); 116 | } 117 | -------------------------------------------------------------------------------- /contracts/interfaces/strategy/IERC4626.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | import '@openzeppelin/contracts/token/ERC20/ERC20.sol'; 5 | 6 | /// @title ERC4626 interface 7 | /// See: https://eips.ethereum.org/EIPS/eip-4626 8 | abstract contract IERC4626 is ERC20 { 9 | /*//////////////////////////////////////////////////////// 10 | Events 11 | ////////////////////////////////////////////////////////*/ 12 | 13 | /// @notice `sender` has exchanged `assets` for `shares`, 14 | /// and transferred those `shares` to `receiver`. 15 | event Deposit(address indexed sender, address indexed receiver, uint256 assets, uint256 shares); 16 | 17 | /// @notice `sender` has exchanged `shares` for `assets`, 18 | /// and transferred those `assets` to `receiver`. 19 | event Withdraw(address indexed sender, address indexed receiver, uint256 assets, uint256 shares); 20 | 21 | /*//////////////////////////////////////////////////////// 22 | Vault properties 23 | ////////////////////////////////////////////////////////*/ 24 | 25 | /// @notice The address of the underlying ERC20 token used for 26 | /// the Vault for accounting, depositing, and withdrawing. 27 | function asset() external view virtual returns (address asset); 28 | 29 | /// @notice Total amount of the underlying asset that 30 | /// is "managed" by Vault. 31 | function totalAssets() external view virtual returns (uint256 totalAssets); 32 | 33 | /*//////////////////////////////////////////////////////// 34 | Deposit/Withdrawal Logic 35 | ////////////////////////////////////////////////////////*/ 36 | 37 | /// @notice Mints `shares` Vault shares to `receiver` by 38 | /// depositing exactly `assets` of underlying tokens. 39 | function deposit(uint256 assets, address receiver) external virtual returns (uint256 shares); 40 | 41 | /// @notice Mints exactly `shares` Vault shares to `receiver` 42 | /// by depositing `assets` of underlying tokens. 43 | function mint(uint256 shares, address receiver) external virtual returns (uint256 assets); 44 | 45 | /// @notice Redeems `shares` from `owner` and sends `assets` 46 | /// of underlying tokens to `receiver`. 47 | function withdraw( 48 | uint256 assets, 49 | address receiver, 50 | address owner 51 | ) external virtual returns (uint256 shares); 52 | 53 | /// @notice Redeems `shares` from `owner` and sends `assets` 54 | /// of underlying tokens to `receiver`. 55 | function redeem( 56 | uint256 shares, 57 | address receiver, 58 | address owner 59 | ) external virtual returns (uint256 assets); 60 | 61 | /*//////////////////////////////////////////////////////// 62 | Vault Accounting Logic 63 | ////////////////////////////////////////////////////////*/ 64 | 65 | /// @notice The amount of shares that the vault would 66 | /// exchange for the amount of assets provided, in an 67 | /// ideal scenario where all the conditions are met. 68 | function convertToShares(uint256 assets) external view virtual returns (uint256 shares); 69 | 70 | /// @notice The amount of assets that the vault would 71 | /// exchange for the amount of shares provided, in an 72 | /// ideal scenario where all the conditions are met. 73 | function convertToAssets(uint256 shares) external view virtual returns (uint256 assets); 74 | 75 | /// @notice Total number of underlying assets that can 76 | /// be deposited by `owner` into the Vault, where `owner` 77 | /// corresponds to the input parameter `receiver` of a 78 | /// `deposit` call. 79 | function maxDeposit(address owner) external view virtual returns (uint256 maxAssets); 80 | 81 | /// @notice Allows an on-chain or off-chain user to simulate 82 | /// the effects of their deposit at the current block, given 83 | /// current on-chain conditions. 84 | function previewDeposit(uint256 assets) external view virtual returns (uint256 shares); 85 | 86 | /// @notice Total number of underlying shares that can be minted 87 | /// for `owner`, where `owner` corresponds to the input 88 | /// parameter `receiver` of a `mint` call. 89 | function maxMint(address owner) external view virtual returns (uint256 maxShares); 90 | 91 | /// @notice Allows an on-chain or off-chain user to simulate 92 | /// the effects of their mint at the current block, given 93 | /// current on-chain conditions. 94 | function previewMint(uint256 shares) external view virtual returns (uint256 assets); 95 | 96 | /// @notice Total number of underlying assets that can be 97 | /// withdrawn from the Vault by `owner`, where `owner` 98 | /// corresponds to the input parameter of a `withdraw` call. 99 | function maxWithdraw(address owner) external view virtual returns (uint256 maxAssets); 100 | 101 | /// @notice Allows an on-chain or off-chain user to simulate 102 | /// the effects of their withdrawal at the current block, 103 | /// given current on-chain conditions. 104 | function previewWithdraw(uint256 assets) external view virtual returns (uint256 shares); 105 | 106 | /// @notice Total number of underlying shares that can be 107 | /// redeemed from the Vault by `owner`, where `owner` corresponds 108 | /// to the input parameter of a `redeem` call. 109 | function maxRedeem(address owner) external view virtual returns (uint256 maxShares); 110 | 111 | /// @notice Allows an on-chain or off-chain user to simulate 112 | /// the effects of their redeemption at the current block, 113 | /// given current on-chain conditions. 114 | function previewRedeem(uint256 shares) external view virtual returns (uint256 assets); 115 | } 116 | -------------------------------------------------------------------------------- /contracts/interfaces/strategy/INode.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 10 | 11 | interface INode { 12 | event AdminWithdraw(uint256 amount); 13 | event ReplaceAsChild(); 14 | event ParentUpdate(IMaster previous, IMaster current); 15 | event Obsolete(INode implementation); 16 | event ForceReplace(); 17 | event Replace(INode newAddress); 18 | 19 | error NotImplemented(bytes4 func); 20 | error SenderNotParent(); 21 | error SenderNotChild(); 22 | error InvalidParent(); 23 | error InvalidCore(); 24 | error InvalidWant(); 25 | error InvalidState(); 26 | error ZeroArg(); 27 | error InvalidArg(); 28 | error NotSetup(); 29 | error IsMaster(); 30 | error BothChild(); 31 | error NotChild(); 32 | error InvalidParentAddress(); 33 | error SetupNotCompleted(INode instance); 34 | error NonZeroBalance(); 35 | 36 | /*////////////////////////////////////////////////////////////// 37 | CONSTRUCTOR VARIABLES 38 | //////////////////////////////////////////////////////////////*/ 39 | 40 | /// @return Returns the token type being deposited into a node 41 | function want() external view returns (IERC20); 42 | 43 | /// @notice Parent will always inherit IMaster interface. 44 | /// @notice Parent of root node will inherit IStrategyManager 45 | function parent() external view returns (IMaster); 46 | 47 | /// @notice View core controller of funds 48 | function core() external view returns (address); 49 | 50 | /*////////////////////////////////////////////////////////////// 51 | TREE STRUCTURE LOGIC 52 | //////////////////////////////////////////////////////////////*/ 53 | 54 | /// @notice Replace the node 55 | /// @notice If this is executed on a strategy, the funds will be withdrawn 56 | /// @notice If this is executed on a splitter, the children are expected to be the same 57 | function replace(INode _node) external; 58 | 59 | /// @notice Replace the node 60 | /// @notice If this is executed on a strategy, attempt is made to withdraw the funds 61 | /// @notice If this is executed on a splitter, check of children is skipped 62 | function replaceForce(INode _node) external; 63 | 64 | function setupCompleted() external view returns (bool); 65 | 66 | /// @notice Move the current node as the child of `_node` 67 | function replaceAsChild(ISplitter _node) external; 68 | 69 | /// @notice Update parent of node 70 | /// @dev Can only be called by current parent 71 | function updateParent(IMaster _node) external; 72 | 73 | function siblingRemoved() external; 74 | 75 | /*////////////////////////////////////////////////////////////// 76 | YIELD STRATEGY LOGIC 77 | //////////////////////////////////////////////////////////////*/ 78 | 79 | /// @return Returns the token balance managed by this contract 80 | /// @dev For Splitter this will be the sum of balances of the children 81 | function balanceOf() external view returns (uint256); 82 | 83 | /// @notice Withdraws all tokens back into core. 84 | /// @return The final amount withdrawn 85 | function withdrawAll() external returns (uint256); 86 | 87 | /// @notice Withdraws all token from the node back into core 88 | /// @return The final amount withdrawn 89 | function withdrawAllByAdmin() external returns (uint256); 90 | 91 | /// @notice Withdraws a specific amount of tokens from the node back into core 92 | /// @param _amount Amount of tokens to withdraw 93 | function withdraw(uint256 _amount) external; 94 | 95 | /// @notice Withdraws a specific amount of tokens from the node back into core 96 | /// @param _amount Amount of tokens to withdraw 97 | function withdrawByAdmin(uint256 _amount) external; 98 | 99 | /// @notice Deposits all tokens held in this contract into the children on strategy 100 | /// @dev Splitter will deposit the tokens in their children 101 | /// @dev Strategy will deposit the tokens into a yield strategy 102 | function deposit() external; 103 | 104 | function prepareBalanceCache() external returns (uint256); 105 | 106 | function expireBalanceCache() external; 107 | } 108 | 109 | interface IMaster is INode { 110 | event ChildOneUpdate(INode previous, INode current); 111 | 112 | /// @notice Call by child if it's needs to be updated 113 | function updateChild(INode _node) external; 114 | 115 | /// @notice Call by child if removed 116 | function childRemoved() external; 117 | 118 | function isMaster() external view returns (bool); 119 | 120 | function childOne() external view returns (INode); 121 | 122 | function setInitialChildOne(INode _child) external; 123 | } 124 | 125 | interface ISplitter is IMaster { 126 | event ChildTwoUpdate(INode previous, INode current); 127 | 128 | error InvalidChildOne(); 129 | error InvalidChildTwo(); 130 | 131 | function childTwo() external view returns (INode); 132 | 133 | function setInitialChildTwo(INode _child) external; 134 | } 135 | -------------------------------------------------------------------------------- /contracts/interfaces/strategy/IStrategy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import './INode.sol'; 10 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 11 | 12 | interface IStrategy is INode { 13 | /// @notice remove a strategy 14 | function remove() external; 15 | } 16 | -------------------------------------------------------------------------------- /contracts/interfaces/truefi/ITrueFiPool2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity 0.8.10; 3 | 4 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 5 | import '@openzeppelin/contracts/token/ERC20/ERC20.sol'; 6 | 7 | interface ITrueLender2Deprecated {} 8 | 9 | interface IFixedTermLoanAgency {} 10 | 11 | interface ILoanToken2Deprecated {} 12 | 13 | interface IDebtToken {} 14 | 15 | interface ITrueFiPoolOracle {} 16 | 17 | interface ISAFU {} 18 | 19 | interface ILoanFactory2 {} 20 | 21 | interface ITrueFiPool2 is IERC20 { 22 | function initialize( 23 | ERC20 _token, 24 | IFixedTermLoanAgency _ftlAgency, 25 | ISAFU safu, 26 | ILoanFactory2 _loanFactory, 27 | address __owner 28 | ) external; 29 | 30 | function singleBorrowerInitialize( 31 | ERC20 _token, 32 | IFixedTermLoanAgency _ftlAgency, 33 | ISAFU safu, 34 | ILoanFactory2 _loanFactory, 35 | address __owner, 36 | string memory borrowerName, 37 | string memory borrowerSymbol 38 | ) external; 39 | 40 | function token() external view returns (ERC20); 41 | 42 | function oracle() external view returns (ITrueFiPoolOracle); 43 | 44 | function poolValue() external view returns (uint256); 45 | 46 | /** 47 | * @dev Ratio of liquid assets in the pool after lending 48 | * @param afterAmountLent Amount of asset being lent 49 | */ 50 | function liquidRatio(uint256 afterAmountLent) external view returns (uint256); 51 | 52 | /** 53 | * @dev Join the pool by depositing tokens 54 | * @param amount amount of tokens to deposit 55 | */ 56 | function join(uint256 amount) external; 57 | 58 | /** 59 | * @dev borrow from pool 60 | * 1. Transfer TUSD to sender 61 | * 2. Only lending pool should be allowed to call this 62 | */ 63 | function borrow(uint256 amount) external; 64 | 65 | /** 66 | * @dev pay borrowed money back to pool 67 | * 1. Transfer TUSD from sender 68 | * 2. Only lending pool should be allowed to call this 69 | */ 70 | function repay(uint256 currencyAmount) external; 71 | 72 | function liquidateLegacyLoan(ILoanToken2Deprecated loan) external; 73 | 74 | /** 75 | * @dev SAFU buys DebtTokens from the pool 76 | */ 77 | function liquidateDebt(IDebtToken debtToken) external; 78 | 79 | function addDebt(IDebtToken debtToken, uint256 amount) external; 80 | 81 | function liquidExit(uint256 amount) external; 82 | 83 | function liquidExitPenalty(uint256 amount) external view returns (uint256); 84 | } 85 | -------------------------------------------------------------------------------- /contracts/interfaces/truefi/ITrueMultiFarm.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.10; 3 | 4 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 5 | 6 | interface ITrueDistributor {} 7 | 8 | interface ITrueMultiFarm { 9 | function trueDistributor() external view returns (ITrueDistributor); 10 | 11 | function stake(IERC20 token, uint256 amount) external; 12 | 13 | function unstake(IERC20 token, uint256 amount) external; 14 | 15 | function claim(IERC20[] calldata tokens) external; 16 | 17 | function exit(IERC20[] calldata tokens) external; 18 | 19 | function staked(IERC20 token, address staker) external view returns (uint256); 20 | 21 | function claimable(IERC20 token, address account) external view returns (uint256); 22 | 23 | function getShare(IERC20 token) external view returns (uint256); 24 | 25 | function setShares(IERC20[] calldata tokens, uint256[] calldata updatedShares) external; 26 | } 27 | -------------------------------------------------------------------------------- /contracts/managers/AaveV2Strategy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import './Manager.sol'; 10 | import '../interfaces/managers/IStrategyManager.sol'; 11 | 12 | import '../interfaces/aaveV2/ILendingPool.sol'; 13 | import '../interfaces/aaveV2/ILendingPoolAddressesProvider.sol'; 14 | import '../interfaces/aaveV2/IAaveIncentivesController.sol'; 15 | import '../interfaces/aaveV2/IStakeAave.sol'; 16 | import '../interfaces/aaveV2/IAToken.sol'; 17 | 18 | // This contract contains logic for depositing staker funds into Aave V2 as a yield strategy 19 | 20 | contract AaveV2Strategy is IStrategyManager, Manager { 21 | using SafeERC20 for IERC20; 22 | 23 | // Need to call a provider because Aave has the ability to change the lending pool address 24 | ILendingPoolAddressesProvider public constant LP_ADDRESS_PROVIDER = 25 | ILendingPoolAddressesProvider(0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5); 26 | 27 | // Aave contract that controls stkAAVE rewards 28 | IAaveIncentivesController public immutable aaveIncentivesController; 29 | 30 | // This is the token being deposited (USDC) 31 | IERC20 public immutable override want; 32 | // This is the receipt token Aave gives in exchange for a token deposit (aUSDC) 33 | IAToken public immutable aWant; 34 | 35 | // Address to receive stkAAVE rewards 36 | address public immutable aaveLmReceiver; 37 | 38 | // Constructor takes the aUSDC address and the rewards receiver address (a Sherlock address) as args 39 | constructor(IAToken _aWant, address _aaveLmReceiver) { 40 | if (address(_aWant) == address(0)) revert ZeroArgument(); 41 | if (_aaveLmReceiver == address(0)) revert ZeroArgument(); 42 | 43 | aWant = _aWant; 44 | // This gets the underlying token associated with aUSDC (USDC) 45 | want = IERC20(_aWant.UNDERLYING_ASSET_ADDRESS()); 46 | // Gets the specific rewards controller for this token type 47 | aaveIncentivesController = _aWant.getIncentivesController(); 48 | 49 | aaveLmReceiver = _aaveLmReceiver; 50 | } 51 | 52 | // Returns the current Aave lending pool address that should be used 53 | function getLp() internal view returns (ILendingPool) { 54 | return ILendingPool(LP_ADDRESS_PROVIDER.getLendingPool()); 55 | } 56 | 57 | /// @notice Checks the aUSDC balance in this contract 58 | function balanceOf() public view override returns (uint256) { 59 | return aWant.balanceOf(address(this)); 60 | } 61 | 62 | /// @notice Deposits all USDC held in this contract into Aave's lending pool 63 | function deposit() external override whenNotPaused { 64 | ILendingPool lp = getLp(); 65 | // Checking the USDC balance of this contract 66 | uint256 amount = want.balanceOf(address(this)); 67 | if (amount == 0) revert InvalidConditions(); 68 | 69 | // If allowance for this contract is too low, approve the max allowance 70 | if (want.allowance(address(this), address(lp)) < amount) { 71 | want.safeIncreaseAllowance(address(lp), type(uint256).max); 72 | } 73 | 74 | // Deposits the full balance of USDC held in this contract into Aave's lending pool 75 | lp.deposit(address(want), amount, address(this), 0); 76 | } 77 | 78 | /// @notice Withdraws all USDC from Aave's lending pool back into the Sherlock core contract 79 | /// @dev Only callable by the Sherlock core contract 80 | /// @return The final amount withdrawn 81 | function withdrawAll() external override onlySherlockCore returns (uint256) { 82 | ILendingPool lp = getLp(); 83 | if (balanceOf() == 0) { 84 | return 0; 85 | } 86 | // Withdraws all USDC from Aave's lending pool and sends it to the Sherlock core contract (msg.sender) 87 | return lp.withdraw(address(want), type(uint256).max, msg.sender); 88 | } 89 | 90 | /// @notice Withdraws a specific amount of USDC from Aave's lending pool back into the Sherlock core contract 91 | /// @param _amount Amount of USDC to withdraw 92 | function withdraw(uint256 _amount) external override onlySherlockCore { 93 | // Ensures that it doesn't execute a withdrawAll() call 94 | // AAVE V2 uses uint256.max as a magic number to withdraw max amount 95 | if (_amount == type(uint256).max) revert InvalidArgument(); 96 | 97 | ILendingPool lp = getLp(); 98 | // Withdraws _amount of USDC and sends it to the Sherlock core contract 99 | // If the amount withdrawn is not equal to _amount, it reverts 100 | if (lp.withdraw(address(want), _amount, msg.sender) != _amount) revert InvalidConditions(); 101 | } 102 | 103 | // Claims the stkAAVE rewards and sends them to the receiver address 104 | function claimRewards() external whenNotPaused { 105 | // Creates an array with one slot 106 | address[] memory assets = new address[](1); 107 | // Sets the slot equal to the address of aUSDC 108 | assets[0] = address(aWant); 109 | 110 | // Claims all the rewards on aUSDC and sends them to the aaveLmReceiver (an address controlled by governance) 111 | // Tokens are NOT meant to be (directly) distributed to stakers. 112 | aaveIncentivesController.claimRewards(assets, type(uint256).max, aaveLmReceiver); 113 | } 114 | 115 | /// @notice Function used to check if this is the current active yield strategy 116 | /// @return Boolean indicating it's active 117 | /// @dev If inactive the owner can pull all ERC20s and ETH 118 | /// @dev Will be checked by calling the sherlock contract 119 | function isActive() public view returns (bool) { 120 | return address(sherlockCore.yieldStrategy()) == address(this); 121 | } 122 | 123 | // Only contract owner can call this 124 | // Sends all specified tokens in this contract to the receiver's address (as well as ETH) 125 | function sweep(address _receiver, IERC20[] memory _extraTokens) external onlyOwner { 126 | if (_receiver == address(0)) revert ZeroArgument(); 127 | // This contract must NOT be the current assigned yield strategy contract 128 | if (isActive()) revert InvalidConditions(); 129 | // Executes the sweep for ERC-20s specified in _extraTokens as well as for ETH 130 | _sweep(_receiver, _extraTokens); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /contracts/managers/Manager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; 10 | import '@openzeppelin/contracts/access/Ownable.sol'; 11 | import '@openzeppelin/contracts/security/Pausable.sol'; 12 | 13 | import '../interfaces/managers/IManager.sol'; 14 | 15 | abstract contract Manager is IManager, Ownable, Pausable { 16 | using SafeERC20 for IERC20; 17 | 18 | address private constant DEPLOYER = 0x1C11bE636415973520DdDf1b03822b4e2930D94A; 19 | ISherlock internal sherlockCore; 20 | 21 | modifier onlySherlockCore() { 22 | if (msg.sender != address(sherlockCore)) revert InvalidSender(); 23 | _; 24 | } 25 | 26 | /// @notice Set sherlock core address 27 | /// @param _sherlock Current core contract 28 | /// @dev Only deployer is able to set core address on all chains except Hardhat network 29 | /// @dev One time function, will revert once `sherlock` != address(0) 30 | /// @dev This contract will be deployed first, passed on as argument in core constuctor 31 | /// @dev emits `SherlockCoreSet` 32 | function setSherlockCoreAddress(ISherlock _sherlock) external override { 33 | if (address(_sherlock) == address(0)) revert ZeroArgument(); 34 | // 31337 is of the Hardhat network blockchain 35 | if (block.chainid != 31337 && msg.sender != DEPLOYER) revert InvalidSender(); 36 | 37 | if (address(sherlockCore) != address(0)) revert InvalidConditions(); 38 | sherlockCore = _sherlock; 39 | 40 | emit SherlockCoreSet(_sherlock); 41 | } 42 | 43 | // Internal function to send tokens remaining in a contract to the receiver address 44 | function _sweep(address _receiver, IERC20[] memory _extraTokens) internal { 45 | // Loops through the extra tokens (ERC20) provided and sends all of them to the receiver address 46 | for (uint256 i; i < _extraTokens.length; i++) { 47 | IERC20 token = _extraTokens[i]; 48 | token.safeTransfer(_receiver, token.balanceOf(address(this))); 49 | } 50 | // Sends any remaining ETH to the receiver address (as long as receiver address is payable) 51 | (bool success, ) = _receiver.call{ value: address(this).balance }(''); 52 | if (success == false) revert InvalidConditions(); 53 | } 54 | 55 | function pause() external virtual onlySherlockCore { 56 | _pause(); 57 | } 58 | 59 | function unpause() external virtual onlySherlockCore { 60 | _unpause(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /contracts/managers/MasterStrategy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import './Manager.sol'; 10 | import '../interfaces/managers/IStrategyManager.sol'; 11 | import '../interfaces/strategy/IStrategy.sol'; 12 | import '../interfaces/strategy/INode.sol'; 13 | import '../strategy/base/BaseMaster.sol'; 14 | 15 | import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; 16 | 17 | contract InfoStorage { 18 | IERC20 public immutable want; 19 | address public immutable core; 20 | 21 | constructor(IERC20 _want, address _core) { 22 | want = _want; 23 | core = _core; 24 | } 25 | } 26 | 27 | // This contract is not desgined to hold funds (except during runtime) 28 | // If it does (by someone sending funds directly) it will not be reflected in the balanceOf() 29 | // On `deposit()` the funds will be added to the balance 30 | // As an observer, if the TVL is 10m and this contract contains 10m, you can easily double your money if you 31 | // enter the pool before `deposit()` is called. 32 | contract MasterStrategy is 33 | BaseMaster, 34 | Manager /* IStrategyManager */ 35 | { 36 | using SafeERC20 for IERC20; 37 | 38 | constructor(IMaster _initialParent) BaseNode(_initialParent) { 39 | sherlockCore = ISherlock(core); 40 | 41 | emit SherlockCoreSet(ISherlock(core)); 42 | } 43 | 44 | /*////////////////////////////////////////////////////////////// 45 | TREE STRUCTURE LOGIC 46 | //////////////////////////////////////////////////////////////*/ 47 | 48 | function isMaster() external view override returns (bool) { 49 | return true; 50 | } 51 | 52 | function setupCompleted() external view override returns (bool) { 53 | return address(childOne) != address(0); 54 | } 55 | 56 | function childRemoved() external override { 57 | // not implemented as the system can not function without `childOne` in this contract 58 | revert NotImplemented(msg.sig); 59 | } 60 | 61 | function replaceAsChild(ISplitter _newParent) external override { 62 | revert NotImplemented(msg.sig); 63 | } 64 | 65 | function replace(INode _node) external override { 66 | revert NotImplemented(msg.sig); 67 | } 68 | 69 | function replaceForce(INode _node) external override { 70 | revert NotImplemented(msg.sig); 71 | } 72 | 73 | function updateChild(INode _newChild) external override { 74 | address _childOne = address(childOne); 75 | if (_childOne == address(0)) revert NotSetup(); 76 | if (_childOne != msg.sender) revert InvalidSender(); 77 | 78 | _verifySetChild(INode(msg.sender), _newChild); 79 | _setChildOne(INode(msg.sender), _newChild); 80 | } 81 | 82 | function updateParent(IMaster _node) external override { 83 | // not implemented as the parent can not be updated by the tree system 84 | revert NotImplemented(msg.sig); 85 | } 86 | 87 | /*////////////////////////////////////////////////////////////// 88 | YIELD STRATEGY LOGIC 89 | //////////////////////////////////////////////////////////////*/ 90 | 91 | modifier balanceCache() { 92 | childOne.prepareBalanceCache(); 93 | _; 94 | childOne.expireBalanceCache(); 95 | } 96 | 97 | function prepareBalanceCache() external override returns (uint256) { 98 | revert NotImplemented(msg.sig); 99 | } 100 | 101 | function expireBalanceCache() external override { 102 | revert NotImplemented(msg.sig); 103 | } 104 | 105 | function balanceOf() 106 | public 107 | view 108 | override( 109 | /*IStrategyManager, */ 110 | INode 111 | ) 112 | returns (uint256) 113 | { 114 | return childOne.balanceOf(); 115 | } 116 | 117 | function deposit() 118 | external 119 | override( 120 | /*IStrategyManager, */ 121 | INode 122 | ) 123 | whenNotPaused 124 | onlySherlockCore 125 | balanceCache 126 | { 127 | uint256 balance = want.balanceOf(address(this)); 128 | if (balance == 0) revert InvalidConditions(); 129 | 130 | want.safeTransfer(address(childOne), balance); 131 | 132 | childOne.deposit(); 133 | } 134 | 135 | function withdrawAllByAdmin() external override onlyOwner balanceCache returns (uint256 amount) { 136 | amount = childOne.withdrawAll(); 137 | emit AdminWithdraw(amount); 138 | } 139 | 140 | function withdrawAll() 141 | external 142 | override( 143 | /*IStrategyManager, */ 144 | INode 145 | ) 146 | onlySherlockCore 147 | balanceCache 148 | returns (uint256) 149 | { 150 | return childOne.withdrawAll(); 151 | } 152 | 153 | function withdrawByAdmin(uint256 _amount) external override onlyOwner balanceCache { 154 | if (_amount == 0) revert ZeroArg(); 155 | 156 | childOne.withdraw(_amount); 157 | emit AdminWithdraw(_amount); 158 | } 159 | 160 | function withdraw(uint256 _amount) 161 | external 162 | override( 163 | /*IStrategyManager, */ 164 | INode 165 | ) 166 | onlySherlockCore 167 | balanceCache 168 | { 169 | if (_amount == 0) revert ZeroArg(); 170 | 171 | childOne.withdraw(_amount); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /contracts/managers/SherDistributionManagerEmpty.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '../interfaces/managers/ISherDistributionManager.sol'; 10 | import './Manager.sol'; 11 | 12 | /// @dev dummy contract that doesn't distribute SHER 13 | contract SherDistributionManagerEmpty is ISherDistributionManager, Manager { 14 | constructor() {} 15 | 16 | function pullReward( 17 | uint256 _amount, 18 | uint256 _period, 19 | uint256 _id, 20 | address _receiver 21 | ) external override returns (uint256 _sher) { 22 | return 0; 23 | } 24 | 25 | function calcReward( 26 | uint256 _tvl, 27 | uint256 _amount, 28 | uint256 _period 29 | ) external view returns (uint256 _sher) { 30 | return 0; 31 | } 32 | 33 | /// @notice Function used to check if this is the current active distribution manager 34 | /// @return Boolean indicating it's active 35 | /// @dev Will be checked by calling the sherlock contract 36 | function isActive() public view override returns (bool) { 37 | return address(sherlockCore.sherDistributionManager()) == address(this); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /contracts/strategy/AaveStrategy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import './base/BaseStrategy.sol'; 10 | 11 | import '../interfaces/aaveV2/ILendingPool.sol'; 12 | import '../interfaces/aaveV2/ILendingPoolAddressesProvider.sol'; 13 | import '../interfaces/aaveV2/IAaveIncentivesController.sol'; 14 | import '../interfaces/aaveV2/IStakeAave.sol'; 15 | import '../interfaces/aaveV2/IAToken.sol'; 16 | 17 | // This contract contains logic for depositing staker funds into Aave as a yield strategy 18 | 19 | contract AaveStrategy is BaseStrategy { 20 | using SafeERC20 for IERC20; 21 | 22 | // Need to call a provider because Aave has the ability to change the lending pool address 23 | ILendingPoolAddressesProvider public constant LP_ADDRESS_PROVIDER = 24 | ILendingPoolAddressesProvider(0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5); 25 | 26 | // Aave contract that controls stkAAVE rewards 27 | IAaveIncentivesController public immutable aaveIncentivesController; 28 | 29 | // This is the receipt token Aave gives in exchange for a token deposit (aUSDC) 30 | IAToken public immutable aWant; 31 | 32 | // Address to receive stkAAVE rewards 33 | address public immutable aaveLmReceiver; 34 | 35 | // Constructor takes the aUSDC address and the rewards receiver address (a Sherlock address) as args 36 | /// @param _initialParent Contract that will be the parent in the tree structure 37 | /// @param _aWant aUSDC addresss 38 | /// @param _aaveLmReceiver Receiving address of the stkAAVE tokens earned by staking 39 | constructor( 40 | IMaster _initialParent, 41 | IAToken _aWant, 42 | address _aaveLmReceiver 43 | ) BaseNode(_initialParent) { 44 | if (address(_aWant) == address(0)) revert ZeroArg(); 45 | if (_aaveLmReceiver == address(0)) revert ZeroArg(); 46 | 47 | aWant = _aWant; 48 | // Gets the specific rewards controller for this token type 49 | aaveIncentivesController = _aWant.getIncentivesController(); 50 | 51 | aaveLmReceiver = _aaveLmReceiver; 52 | } 53 | 54 | /// @notice Signal if strategy is ready to be used 55 | /// @return Boolean indicating if strategy is ready 56 | function setupCompleted() external view override returns (bool) { 57 | return true; 58 | } 59 | 60 | /// @return The current Aave lending pool address that should be used 61 | function getLp() internal view returns (ILendingPool) { 62 | return ILendingPool(LP_ADDRESS_PROVIDER.getLendingPool()); 63 | } 64 | 65 | /// @notice View the current balance of this strategy in USDC 66 | /// @dev Will return wrong balance if this contract somehow has USDC instead of only aUSDC 67 | /// @return Amount of USDC in this strategy 68 | function _balanceOf() internal view override returns (uint256) { 69 | // 1 aUSDC = 1 USDC 70 | return aWant.balanceOf(address(this)); 71 | } 72 | 73 | /// @notice Deposits all USDC held in this contract into Aave's lending pool 74 | /// @notice Works under the assumption this contract contains USDC 75 | function _deposit() internal override whenNotPaused { 76 | ILendingPool lp = getLp(); 77 | // Checking the USDC balance of this contract 78 | uint256 amount = want.balanceOf(address(this)); 79 | if (amount == 0) revert InvalidState(); 80 | 81 | // If allowance for this contract is too low, approve the max allowance 82 | // Will occur if the `lp` address changes 83 | if (want.allowance(address(this), address(lp)) < amount) { 84 | // `safeIncreaseAllowance` can fail if it adds `type(uint256).max` to a non-zero value 85 | // This is very unlikely as we have to have an ungodly amount of USDC pass this system for 86 | // The allowance to reach a human interpretable number 87 | want.safeIncreaseAllowance(address(lp), type(uint256).max); 88 | } 89 | 90 | // Deposits the full balance of USDC held in this contract into Aave's lending pool 91 | lp.deposit(address(want), amount, address(this), 0); 92 | } 93 | 94 | /// @notice Withdraws all USDC from Aave's lending pool back into core 95 | /// @return Amount of USDC withdrawn 96 | function _withdrawAll() internal override returns (uint256) { 97 | ILendingPool lp = getLp(); 98 | if (_balanceOf() == 0) { 99 | return 0; 100 | } 101 | // Withdraws all USDC from Aave's lending pool and sends it to core 102 | return lp.withdraw(address(want), type(uint256).max, core); 103 | } 104 | 105 | /// @notice Withdraws a specific amount of USDC from Aave's lending pool back into core 106 | /// @param _amount Amount of USDC to withdraw 107 | function _withdraw(uint256 _amount) internal override { 108 | // Ensures that it doesn't execute a withdrawAll() call 109 | // AAVE uses uint256.max as a magic number to withdraw max amount 110 | if (_amount == type(uint256).max) revert InvalidArg(); 111 | 112 | ILendingPool lp = getLp(); 113 | // Withdraws _amount of USDC and sends it to core 114 | // If the amount withdrawn is not equal to _amount, it reverts 115 | if (lp.withdraw(address(want), _amount, core) != _amount) revert InvalidState(); 116 | } 117 | 118 | // Claims the stkAAVE rewards and sends them to the receiver address 119 | function claimReward() external { 120 | // Creates an array with one slot 121 | address[] memory assets = new address[](1); 122 | // Sets the slot equal to the address of aUSDC 123 | assets[0] = address(aWant); 124 | 125 | // Claims all the rewards on aUSDC and sends them to the aaveLmReceiver (an address controlled by governance) 126 | // Tokens are NOT meant to be (directly) distributed to stakers. 127 | aaveIncentivesController.claimRewards(assets, type(uint256).max, aaveLmReceiver); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /contracts/strategy/CompoundStrategy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Fran Rimoldi (https://twitter.com/fran_rimoldi) 6 | * Author: Evert Kors (https://twitter.com/evert0x) 7 | * Sherlock Protocol: https://sherlock.xyz 8 | /******************************************************************************/ 9 | 10 | import './base/BaseStrategy.sol'; 11 | import '../interfaces/compound/ICToken.sol'; 12 | import '../interfaces/compound/IComptroller.sol'; 13 | import { FixedPointMathLib } from '@rari-capital/solmate/src/utils/FixedPointMathLib.sol'; 14 | import { LibCompound } from './compound/LibCompound.sol'; 15 | 16 | /** 17 | * This contract implements the logic to deposit and withdraw funds from Compound as a yield strategy. 18 | * Docs: https://compound.finance/docs 19 | */ 20 | 21 | contract CompoundStrategy is BaseStrategy { 22 | using SafeERC20 for IERC20; 23 | using FixedPointMathLib for uint256; 24 | 25 | // This is the receipt token Compound gives in exchange for a token deposit (cUSDC) 26 | // https://compound.finance/docs#protocol-math 27 | // https://github.com/compound-finance/compound-protocol/blob/master/contracts/CErc20.sol 28 | // https://github.com/compound-finance/compound-protocol/blob/master/contracts/CToken.sol 29 | 30 | // https://compound.finance/docs#networks 31 | // CUSDC address 32 | ICToken public constant CUSDC = ICToken(0x39AA39c021dfbaE8faC545936693aC917d5E7563); 33 | IComptroller public constant COMPTROLLER = 34 | IComptroller(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B); 35 | IERC20 internal constant COMP = IERC20(0xc00e94Cb662C3520282E6f5717214004A7f26888); 36 | 37 | // Address to receive rewards 38 | address public constant LIQUIDITY_MINING_RECEIVER = 0x666B8EbFbF4D5f0CE56962a25635CfF563F13161; 39 | 40 | /// @param _initialParent Contract that will be the parent in the tree structure 41 | constructor(IMaster _initialParent) BaseNode(_initialParent) { 42 | // Approve max USDC to cUSDC 43 | want.safeIncreaseAllowance(address(CUSDC), type(uint256).max); 44 | } 45 | 46 | /// @notice Signal if strategy is ready to be used 47 | /// @return Boolean indicating if strategy is ready 48 | function setupCompleted() external view override returns (bool) { 49 | return true; 50 | } 51 | 52 | /// @notice View the current balance of this strategy in USDC 53 | /// @dev Since balanceOf() is pure, we can't use Compound's balanceOfUnderlying(adress) function 54 | /// @dev We calculate the exchange rate ourselves instead using LibCompound 55 | /// @dev Will return wrong balance if this contract somehow has USDC instead of only cUSDC 56 | /// @return Amount of USDC in this strategy 57 | function _balanceOf() internal view override returns (uint256) { 58 | return LibCompound.viewUnderlyingBalanceOf(CUSDC, address(this)); 59 | } 60 | 61 | /// @notice Deposit all USDC in this contract into Compound 62 | /// @notice Works under the assumption this contract contains USDC 63 | function _deposit() internal override whenNotPaused { 64 | uint256 amount = want.balanceOf(address(this)); 65 | 66 | // https://compound.finance/docs/ctokens#mint 67 | if (CUSDC.mint(amount) != 0) revert InvalidState(); 68 | } 69 | 70 | /// @notice Withdraw all USDC from Compound and send all USDC in contract to core 71 | /// @return amount Amount of USDC withdrawn 72 | function _withdrawAll() internal override returns (uint256 amount) { 73 | uint256 cUSDCAmount = CUSDC.balanceOf(address(this)); 74 | 75 | // If cUSDC.balanceOf(this) != 0, we can start to withdraw the eUSDC 76 | if (cUSDCAmount != 0) { 77 | // Revert if redeem function returns error code 78 | if (CUSDC.redeem(cUSDCAmount) != 0) revert InvalidState(); 79 | } 80 | 81 | // Amount of USDC in the contract 82 | // This can be >0 even if cUSDC balance = 0 83 | // As it could have been transferred to this contract by accident 84 | amount = want.balanceOf(address(this)); 85 | 86 | // Transfer USDC to core 87 | if (amount != 0) want.safeTransfer(core, amount); 88 | } 89 | 90 | /// @notice Withdraw `_amount` USDC from Compound and send to core 91 | /// @param _amount Amount of USDC to withdraw 92 | function _withdraw(uint256 _amount) internal override { 93 | // Revert if redeem function returns error code 94 | if (CUSDC.redeemUnderlying(_amount) != 0) revert InvalidState(); 95 | 96 | // Transfer USDC to core 97 | want.safeTransfer(core, _amount); 98 | } 99 | 100 | /// @notice Claim COMP tokens earned by supplying 101 | /// @dev COMP tokens will be send to LIQUIDITY_MINING_RECEIVER 102 | function claimReward() external { 103 | // Claim COMP for address(this) 104 | address[] memory holders = new address[](1); 105 | holders[0] = address(this); 106 | 107 | // Claim COMP for CUSDC 108 | ICToken[] memory tokens = new ICToken[](1); 109 | tokens[0] = CUSDC; 110 | 111 | // Claim COMP tokens for CUSDC 112 | // https://github.com/compound-finance/compound-protocol/blob/master/contracts/Comptroller.sol#L1341 113 | COMPTROLLER.claimComp(holders, tokens, false, true); 114 | 115 | // How much COMP tokens does this contract hold 116 | uint256 rewardBalance = COMP.balanceOf(address(this)); 117 | 118 | // Send all COMP tokens to LIQUIDITY_MINING_RECEIVER 119 | if (rewardBalance != 0) COMP.safeTransfer(LIQUIDITY_MINING_RECEIVER, rewardBalance); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /contracts/strategy/EulerStrategy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import './base/BaseStrategy.sol'; 10 | 11 | import '../interfaces/euler/IEulerEToken.sol'; 12 | 13 | // This contract contains logic for depositing staker funds into Euler as a yield strategy 14 | // https://docs.euler.finance/developers/integration-guide#deposit-and-withdraw 15 | 16 | // EUL rewards are not integrated as it's only for accounts that borrow. 17 | // We don't borrow in this strategy. 18 | 19 | contract EulerStrategy is BaseStrategy { 20 | using SafeERC20 for IERC20; 21 | 22 | // Sub account used for Euler interactions 23 | uint256 private constant SUB_ACCOUNT = 0; 24 | 25 | // https://docs.euler.finance/protocol/addresses 26 | address public constant EULER = 0x27182842E098f60e3D576794A5bFFb0777E025d3; 27 | // https://github.com/euler-xyz/euler-contracts/blob/master/contracts/modules/EToken.sol 28 | IEulerEToken public constant EUSDC = IEulerEToken(0xEb91861f8A4e1C12333F42DCE8fB0Ecdc28dA716); 29 | 30 | /// @param _initialParent Contract that will be the parent in the tree structure 31 | constructor(IMaster _initialParent) BaseNode(_initialParent) { 32 | // Approve Euler max amount of USDC 33 | want.safeIncreaseAllowance(EULER, type(uint256).max); 34 | } 35 | 36 | /// @notice Signal if strategy is ready to be used 37 | /// @return Boolean indicating if strategy is ready 38 | function setupCompleted() external view override returns (bool) { 39 | return true; 40 | } 41 | 42 | /// @notice View the current balance of this strategy in USDC 43 | /// @dev Will return wrong balance if this contract somehow has USDC instead of only eUSDC 44 | /// @return Amount of USDC in this strategy 45 | function _balanceOf() internal view override returns (uint256) { 46 | return EUSDC.balanceOfUnderlying(address(this)); 47 | } 48 | 49 | /// @notice Deposit all USDC in this contract in Euler 50 | /// @notice Works under the assumption this contract contains USDC 51 | function _deposit() internal override whenNotPaused { 52 | // Deposit all current balance into euler 53 | // https://github.com/euler-xyz/euler-contracts/blob/master/contracts/modules/EToken.sol#L148 54 | EUSDC.deposit(SUB_ACCOUNT, type(uint256).max); 55 | } 56 | 57 | /// @notice Withdraw all USDC from Euler and send all USDC in contract to core 58 | /// @return amount Amount of USDC withdrawn 59 | function _withdrawAll() internal override returns (uint256 amount) { 60 | // If eUSDC.balanceOf(this) != 0, we can start to withdraw the eUSDC 61 | if (EUSDC.balanceOf(address(this)) != 0) { 62 | // Withdraw all underlying using max, this will translate to the full balance 63 | // https://github.com/euler-xyz/euler-contracts/blob/master/contracts/BaseLogic.sol#L387 64 | EUSDC.withdraw(SUB_ACCOUNT, type(uint256).max); 65 | } 66 | 67 | // Amount of USDC in the contract 68 | // This can be >0 even if eUSDC balance = 0 69 | // As it could have been transferred to this contract by accident 70 | amount = want.balanceOf(address(this)); 71 | // Transfer USDC to core 72 | if (amount != 0) want.safeTransfer(core, amount); 73 | } 74 | 75 | /// @notice Withdraw `_amount` USDC from Euler and send to core 76 | /// @param _amount Amount of USDC to withdraw 77 | function _withdraw(uint256 _amount) internal override { 78 | // Don't allow to withdraw max (reserved with withdrawAll call) 79 | if (_amount == type(uint256).max) revert InvalidArg(); 80 | 81 | // Call withdraw with underlying amount of tokens (USDC instead of eUSDC) 82 | // https://github.com/euler-xyz/euler-contracts/blob/master/contracts/modules/EToken.sol#L177 83 | EUSDC.withdraw(SUB_ACCOUNT, _amount); 84 | 85 | // Transfer USDC to core 86 | want.safeTransfer(core, _amount); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /contracts/strategy/base/BaseMaster.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '@openzeppelin/contracts/access/Ownable.sol'; 10 | 11 | import '../../interfaces/strategy/INode.sol'; 12 | import '../../interfaces/strategy/INode.sol'; 13 | import './BaseNode.sol'; 14 | 15 | // Interface used by the MasterStrategy, the contract core will reference as `yieldStrategy` 16 | abstract contract BaseMaster is IMaster, BaseNode { 17 | // ChildNode 18 | INode public override childOne; 19 | 20 | /// @notice Verify if `_newChild` is able to replace `_currentChild` without doing same parent check 21 | /// @param _currentChild Node that is the current child 22 | /// @param _newChild Node that is the new child 23 | function _verifySetChildSkipParentCheck(INode _currentChild, INode _newChild) internal { 24 | if (address(_newChild) == address(0)) revert ZeroArg(); 25 | if (_newChild.setupCompleted() == false) revert SetupNotCompleted(_newChild); 26 | 27 | if (_newChild == _currentChild) revert InvalidArg(); 28 | if (core != _newChild.core()) revert InvalidCore(); 29 | if (want != _newChild.want()) revert InvalidWant(); 30 | } 31 | 32 | /// @notice Verify if `_newChild` is able to replace `_currentChild` 33 | /// @param _currentChild Node that is the current child 34 | /// @param _newChild Node that is the new child 35 | function _verifySetChild(INode _currentChild, INode _newChild) internal { 36 | _verifySetChildSkipParentCheck(_currentChild, _newChild); 37 | // NOTE this check is basically one here for the `updateChild` call in splitter 38 | if (address(_newChild.parent()) != address(this)) revert InvalidParent(); 39 | } 40 | 41 | /// @notice Set childOne in storage 42 | /// @param _currentChild The `childOne` currently stored 43 | /// @param _newChild The `childOne` that is stored after this call 44 | function _setChildOne(INode _currentChild, INode _newChild) internal { 45 | childOne = _newChild; 46 | emit ChildOneUpdate(_currentChild, _newChild); 47 | } 48 | 49 | /// @notice Set initial childOne 50 | /// @param _newChild Address of the initial child 51 | function setInitialChildOne(INode _newChild) external override onlyOwner { 52 | if (address(childOne) != address(0)) revert InvalidState(); 53 | 54 | _verifySetChild(INode(address(0)), _newChild); 55 | _setChildOne(INode(address(0)), _newChild); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /contracts/strategy/base/BaseStrategy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '@openzeppelin/contracts/access/Ownable.sol'; 10 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 11 | import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; 12 | import '@openzeppelin/contracts/security/Pausable.sol'; 13 | 14 | import '../../interfaces/strategy/INode.sol'; 15 | import '../../interfaces/strategy/IStrategy.sol'; 16 | import './BaseNode.sol'; 17 | 18 | abstract contract BaseStrategy is IStrategy, BaseNode, Pausable { 19 | using SafeERC20 for IERC20; 20 | 21 | /// @dev Return balance of this strategy 22 | function prepareBalanceCache() external override onlyParent returns (uint256) { 23 | return _balanceOf(); 24 | } 25 | 26 | /// @dev No cache is used in strategies 27 | function expireBalanceCache() external override onlyParent {} 28 | 29 | function pause() external virtual onlyOwner { 30 | _pause(); 31 | } 32 | 33 | function unpause() external virtual onlyOwner { 34 | _unpause(); 35 | } 36 | 37 | function remove() external virtual override onlyOwner { 38 | _withdrawAll(); 39 | if (_balanceOf() != 0) revert NonZeroBalance(); 40 | parent.childRemoved(); 41 | } 42 | 43 | function replace(INode _newNode) external virtual override onlyOwner { 44 | _withdrawAll(); 45 | if (_balanceOf() != 0) revert NonZeroBalance(); 46 | _replace(_newNode); 47 | } 48 | 49 | function replaceForce(INode _newNode) external virtual override onlyOwner { 50 | _replace(_newNode); 51 | emit ForceReplace(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /contracts/strategy/compound/LibCompound.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0-only 2 | pragma solidity 0.8.10; 3 | 4 | import { FixedPointMathLib } from '@rari-capital/solmate/src/utils/FixedPointMathLib.sol'; 5 | import { ICToken as CERC20 } from '../../interfaces/compound/ICToken.sol'; 6 | 7 | /// @notice Get up to date cToken data without mutating state. 8 | /// @author Transmissions11 (https://github.com/transmissions11/libcompound) 9 | library LibCompound { 10 | using FixedPointMathLib for uint256; 11 | 12 | function viewUnderlyingBalanceOf(CERC20 cToken, address user) internal view returns (uint256) { 13 | return cToken.balanceOf(user).mulWadDown(viewExchangeRate(cToken)); 14 | } 15 | 16 | function viewExchangeRate(CERC20 cToken) internal view returns (uint256) { 17 | uint256 accrualBlockNumberPrior = cToken.accrualBlockNumber(); 18 | 19 | if (accrualBlockNumberPrior == block.number) return cToken.exchangeRateStored(); 20 | 21 | uint256 totalCash = cToken.underlying().balanceOf(address(cToken)); 22 | uint256 borrowsPrior = cToken.totalBorrows(); 23 | uint256 reservesPrior = cToken.totalReserves(); 24 | 25 | uint256 borrowRateMantissa = cToken.interestRateModel().getBorrowRate( 26 | totalCash, 27 | borrowsPrior, 28 | reservesPrior 29 | ); 30 | 31 | require(borrowRateMantissa <= 0.0005e16, 'RATE_TOO_HIGH'); // Same as borrowRateMaxMantissa in Compound's CTokenInterfaces.sol 32 | 33 | uint256 interestAccumulated = (borrowRateMantissa * (block.number - accrualBlockNumberPrior)) 34 | .mulWadDown(borrowsPrior); 35 | 36 | uint256 totalReserves = cToken.reserveFactorMantissa().mulWadDown(interestAccumulated) + 37 | reservesPrior; 38 | uint256 totalBorrows = interestAccumulated + borrowsPrior; 39 | uint256 totalSupply = cToken.totalSupply(); 40 | 41 | return 42 | totalSupply == 0 43 | ? cToken.initialExchangeRateMantissa() 44 | : (totalCash + totalBorrows - totalReserves).divWadDown(totalSupply); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /contracts/strategy/splitters/AlphaBetaEqualDepositMaxSplitter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import './AlphaBetaEqualDepositSplitter.sol'; 10 | 11 | /** 12 | ChildOne is the first node that is being used to withdraw from 13 | Only when ChildOne balance = 0 it will start withdrawing from ChildTwo 14 | 15 | If the deposit amount is at least `MIN_AMOUNT_FOR_EQUAL_SPLIT` of USDC 16 | It will try to balance out the childs by havng the option to deposit in both 17 | 18 | If the deposit amount is less then `MIN_AMOUNT_FOR_EQUAL_SPLIT` of USDC 19 | It will deposit in the child that returns the lowest balance 20 | 21 | Either childOne or childTwo can have a limit for the amount of USDC to receive 22 | 23 | Note: the child without a limit can receive two `deposit()` calls 24 | if the initial amount is at least `MIN_AMOUNT_FOR_EQUAL_SPLIT` USDC 25 | */ 26 | contract AlphaBetaEqualDepositMaxSplitter is AlphaBetaEqualDepositSplitter { 27 | uint256 private constant NO_LIMIT = type(uint256).max; 28 | // Max amount of USDC childOne can hold (type(uint256).max = no limit) 29 | uint256 public immutable MAX_AMOUNT_FOR_CHILD_ONE; 30 | // Max amount of USDC childTwo can hold (type(uint256).max = no limit) 31 | uint256 public immutable MAX_AMOUNT_FOR_CHILD_TWO; 32 | 33 | /// @param _initialParent Contract that will be the parent in the tree structure 34 | /// @param _initialChildOne Contract that will be the initial childOne in the tree structure 35 | /// @param _initialChildTwo Contract that will be the initial childTwo in the tree structure 36 | /// @param _MIN_AMOUNT_FOR_EQUAL_SPLIT Min USDC deposit amount to activate logic to equal out balances 37 | /// @param _MAX_AMOUNT_FOR_CHILD_ONE Max amount of USDC childOne can hold (type(uint256).max = no limit) 38 | /// @param _MAX_AMOUNT_FOR_CHILD_TWO Max amount of USDC childTwo can hold (type(uint256).max = no limit) 39 | /// @notice Either `_MAX_AMOUNT_FOR_CHILD_ONE` or `_MAX_AMOUNT_FOR_CHILD_TWO` has to be type(uint256).max 40 | constructor( 41 | IMaster _initialParent, 42 | INode _initialChildOne, 43 | INode _initialChildTwo, 44 | uint256 _MIN_AMOUNT_FOR_EQUAL_SPLIT, 45 | uint256 _MAX_AMOUNT_FOR_CHILD_ONE, 46 | uint256 _MAX_AMOUNT_FOR_CHILD_TWO 47 | ) 48 | AlphaBetaEqualDepositSplitter( 49 | _initialParent, 50 | _initialChildOne, 51 | _initialChildTwo, 52 | _MIN_AMOUNT_FOR_EQUAL_SPLIT 53 | ) 54 | { 55 | // Either `_MAX_AMOUNT_FOR_CHILD_ONE` or `_MAX_AMOUNT_FOR_CHILD_TWO` has to be type(uint256).max 56 | if (_MAX_AMOUNT_FOR_CHILD_ONE != NO_LIMIT && _MAX_AMOUNT_FOR_CHILD_TWO != NO_LIMIT) { 57 | revert InvalidArg(); 58 | } 59 | 60 | // Either `_MAX_AMOUNT_FOR_CHILD_ONE` or `_MAX_AMOUNT_FOR_CHILD_TWO` has to be non type(uint256).max 61 | if (_MAX_AMOUNT_FOR_CHILD_ONE == NO_LIMIT && _MAX_AMOUNT_FOR_CHILD_TWO == NO_LIMIT) { 62 | revert InvalidArg(); 63 | } 64 | 65 | // Write variables to storage 66 | MAX_AMOUNT_FOR_CHILD_ONE = _MAX_AMOUNT_FOR_CHILD_ONE; 67 | MAX_AMOUNT_FOR_CHILD_TWO = _MAX_AMOUNT_FOR_CHILD_TWO; 68 | } 69 | 70 | /// @notice Transfer USDC to one or both childs based on `MAX_AMOUNT_FOR_CHILD_ONE` 71 | /// @param _amount Amount of USDC to deposit 72 | function _childOneDeposit(uint256 _amount) internal virtual override { 73 | // Cache balance in memory 74 | uint256 childOneBalance = cachedChildOneBalance; 75 | 76 | // Do we want to deposit into childOne at all? If yes, continue 77 | if (childOneBalance < MAX_AMOUNT_FOR_CHILD_ONE) { 78 | // Will depositing the full amount result in exceeding the MAX? If yes, continue 79 | if (childOneBalance + _amount > MAX_AMOUNT_FOR_CHILD_ONE) { 80 | // How much room if left to hit the USDC cap in childOne 81 | uint256 childOneAmount = MAX_AMOUNT_FOR_CHILD_ONE - childOneBalance; 82 | 83 | // Deposit amount that will make us hit the cap for childOne 84 | AlphaBetaSplitter._childOneDeposit(childOneAmount); 85 | 86 | // Deposit leftover USDC into childTwo 87 | AlphaBetaSplitter._childTwoDeposit(_amount - childOneAmount); 88 | } else { 89 | // Deposit all in childOne if depositing full amount will not make us exceed the cap 90 | AlphaBetaSplitter._childOneDeposit(_amount); 91 | } 92 | } else { 93 | // Deposit all in childTwo (childOne deposit isn't used at all) 94 | AlphaBetaSplitter._childTwoDeposit(_amount); 95 | } 96 | } 97 | 98 | /// @notice Transfer USDC to one or both childs based on `MAX_AMOUNT_FOR_CHILD_TWO` 99 | /// @param _amount Amount of USDC to deposit 100 | function _childTwoDeposit(uint256 _amount) internal virtual override { 101 | // Cache balance in memory 102 | uint256 childTwoBalance = cachedChildTwoBalance; 103 | 104 | // Do we want to deposit into childTwo at all? If yes, continue 105 | if (childTwoBalance < MAX_AMOUNT_FOR_CHILD_TWO) { 106 | // Will depositing the full amount result in exceeding the MAX? If yes, continue 107 | if (childTwoBalance + _amount > MAX_AMOUNT_FOR_CHILD_TWO) { 108 | // How much room if left to hit the USDC cap in childTwo 109 | uint256 childTwoAmount = MAX_AMOUNT_FOR_CHILD_TWO - childTwoBalance; 110 | 111 | // Deposit amount that will make us hit the cap for childTwo 112 | AlphaBetaSplitter._childTwoDeposit(childTwoAmount); 113 | 114 | // Deposit leftover USDC into childOne 115 | AlphaBetaSplitter._childOneDeposit(_amount - childTwoAmount); 116 | } else { 117 | // Deposit all in childTwo if depositing full amount will not make us exceed the cap 118 | AlphaBetaSplitter._childTwoDeposit(_amount); 119 | } 120 | } else { 121 | // Deposit all in childOne (childTwo deposit isn't used at all) 122 | AlphaBetaSplitter._childOneDeposit(_amount); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /contracts/strategy/splitters/AlphaBetaEqualDepositSplitter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import './AlphaBetaSplitter.sol'; 10 | 11 | /** 12 | ChildOne is the first node that is being used to withdraw from 13 | Only when ChildOne balance = 0 it will start withdrawing from ChildTwo 14 | 15 | If the deposit amount is at least `MIN_AMOUNT_FOR_EQUAL_SPLIT` of USDC 16 | It will try to balance out the childs by havng the option to deposit in both 17 | 18 | If the deposit amount is less then `MIN_AMOUNT_FOR_EQUAL_SPLIT` of USDC 19 | It will deposit in the child that returns the lowest balance 20 | */ 21 | contract AlphaBetaEqualDepositSplitter is AlphaBetaSplitter { 22 | // Min USDC deposit amount to activate logic to equal out balances 23 | uint256 public immutable MIN_AMOUNT_FOR_EQUAL_SPLIT; 24 | 25 | /// @param _initialParent Contract that will be the parent in the tree structure 26 | /// @param _initialChildOne Contract that will be the initial childOne in the tree structure 27 | /// @param _initialChildTwo Contract that will be the initial childTwo in the tree structure 28 | /// @param _MIN_AMOUNT_FOR_EQUAL_SPLIT Min USDC deposit amount to activate logic to equal out balances 29 | constructor( 30 | IMaster _initialParent, 31 | INode _initialChildOne, 32 | INode _initialChildTwo, 33 | uint256 _MIN_AMOUNT_FOR_EQUAL_SPLIT 34 | ) AlphaBetaSplitter(_initialParent, _initialChildOne, _initialChildTwo) { 35 | // Write variable to storage 36 | MIN_AMOUNT_FOR_EQUAL_SPLIT = _MIN_AMOUNT_FOR_EQUAL_SPLIT; 37 | } 38 | 39 | /// @notice Deposit USDC into one or both childs 40 | function _deposit() internal virtual override { 41 | // Amount of USDC in the contract 42 | uint256 amount = want.balanceOf(address(this)); 43 | 44 | // Try to balance out childs if at least `MIN_AMOUNT_FOR_EQUAL_SPLIT` USDC is deposited 45 | if (amount >= MIN_AMOUNT_FOR_EQUAL_SPLIT) { 46 | // Cache balances in memory 47 | uint256 childOneBalance = cachedChildOneBalance; 48 | uint256 childTwoBalance = cachedChildTwoBalance; 49 | 50 | if (childOneBalance <= childTwoBalance) { 51 | // How much extra balance does childTWo have? 52 | // Can be 0 53 | uint256 childTwoBalanceExtra = childTwoBalance - childOneBalance; 54 | 55 | // If the difference exceeds the amount we can deposit it all in childOne 56 | // As this brings the two balances close to each other 57 | if (childTwoBalanceExtra >= amount) { 58 | // Deposit all USDC into childOne 59 | _childOneDeposit(amount); 60 | } else { 61 | // Depositing in a single child will not make the balances equal 62 | // So we have to deposit in both childs 63 | 64 | // We know childTwo has a bigger balance 65 | // Calculting how much to deposit in childTwo 66 | /** 67 | Example 68 | 69 | One = 180k USDC 70 | Two = 220k USDC 71 | amount = 100k USDC 72 | 73 | childTwoAdd = (100 - (220 - 180)) / 2 = 30k 74 | childOneAdd = 100k - 30k = 70k 75 | ---+ 76 | One = 250k USDC 77 | Two = 250k USDC 78 | */ 79 | uint256 childTwoAdd = (amount - childTwoBalanceExtra) / 2; 80 | // Deposit USDC into childTwo 81 | _childTwoDeposit(childTwoAdd); 82 | // Deposit leftover USDC into childOne 83 | _childOneDeposit(amount - childTwoAdd); 84 | } 85 | } else { 86 | // Do same logic as above but for the scenario childOne has a bigger balance 87 | 88 | uint256 childOneBalanceExtra = childOneBalance - childTwoBalance; 89 | 90 | if (childOneBalanceExtra >= amount) { 91 | // Deposit all USDC into childTwo 92 | _childTwoDeposit(amount); 93 | } else { 94 | uint256 childOneAdd = (amount - childOneBalanceExtra) / 2; 95 | // Deposit USDC into childOne 96 | _childOneDeposit(childOneAdd); 97 | // Deposit leftover USDC into childTwo 98 | _childTwoDeposit(amount - childOneAdd); 99 | } 100 | } 101 | } else { 102 | // Use deposit function based on balance 103 | AlphaBetaSplitter._deposit(); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /contracts/strategy/splitters/AlphaBetaSplitter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '../base/BaseSplitter.sol'; 10 | 11 | /** 12 | ChildOne is the first node that is being used to withdraw from 13 | Only when ChildOne balance = 0 it will start withdrawing from ChildTwo 14 | 15 | It will deposit in the child that returns the lowest balance (childOne first) 16 | */ 17 | contract AlphaBetaSplitter is BaseSplitter { 18 | using SafeERC20 for IERC20; 19 | 20 | /// @param _initialParent Contract that will be the parent in the tree structure 21 | /// @param _initialChildOne Contract that will be the initial childOne in the tree structure 22 | /// @param _initialChildTwo Contract that will be the initial childTwo in the tree structure 23 | constructor( 24 | IMaster _initialParent, 25 | INode _initialChildOne, 26 | INode _initialChildTwo 27 | ) BaseSplitter(_initialParent, _initialChildOne, _initialChildTwo) {} 28 | 29 | /// @notice Signal to withdraw `_amount` of USDC from the underlying nodes into core 30 | /// @param _amount Amount of USDC to withdraw 31 | function _withdraw(uint256 _amount) internal virtual override { 32 | // First in line for liquidations 33 | uint256 childOneBalance = cachedChildOneBalance; 34 | 35 | // If the amount exceeds childOne balance, it will start withdrawing from childTwo 36 | if (_amount > childOneBalance) { 37 | // Withdraw all USDC from childOne 38 | if (childOneBalance != 0) childOne.withdrawAll(); 39 | 40 | // Withdraw USDC from childTwo when childOne balance hits zero 41 | childTwo.withdraw(_amount - childOneBalance); 42 | } else { 43 | // Withdraw from childOne 44 | childOne.withdraw(_amount); 45 | } 46 | } 47 | 48 | /// @notice Transfer USDC to childOne and call deposit 49 | /// @param _amount Amount of USDC to deposit 50 | function _childOneDeposit(uint256 _amount) internal virtual { 51 | // Transfer USDC to childOne 52 | want.safeTransfer(address(childOne), _amount); 53 | 54 | // Signal childOne it received a deposit 55 | childOne.deposit(); 56 | } 57 | 58 | /// @notice Transfer USDC to childTwo and call deposit 59 | /// @param _amount Amount of USDC to deposit 60 | function _childTwoDeposit(uint256 _amount) internal virtual { 61 | // Transfer USDC to childTwo 62 | want.safeTransfer(address(childTwo), _amount); 63 | 64 | // Signal childOne it received a deposit 65 | childTwo.deposit(); 66 | } 67 | 68 | /// @notice Deposit USDC into one child 69 | function _deposit() internal virtual override { 70 | // Deposit USDC into strategy that has the lowest balance 71 | if (cachedChildOneBalance <= cachedChildTwoBalance) { 72 | _childOneDeposit(want.balanceOf(address(this))); 73 | } else { 74 | _childTwoDeposit(want.balanceOf(address(this))); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /contracts/test/AllowanceErrorTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '../managers/Manager.sol'; 10 | 11 | contract AllowanceErrorTest is Manager { 12 | using SafeERC20 for IERC20; 13 | 14 | constructor(IERC20 _token) { 15 | _token.safeIncreaseAllowance(address(0x1), 1); 16 | _token.safeIncreaseAllowance(address(0x1), type(uint256).max); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/test/ManagerTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '../managers/Manager.sol'; 10 | 11 | /// @notice this contract is used for testing to view all storage variables 12 | contract ManagerTest is Manager { 13 | function revertsIfNotCore() external onlySherlockCore {} 14 | 15 | function viewSherlockCore() external view returns (address) { 16 | return address(sherlockCore); 17 | } 18 | 19 | function sweep(address _receiver, IERC20[] memory _extraTokens) external { 20 | _sweep(_receiver, _extraTokens); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contracts/test/PayableFail.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | contract PayableFail { 10 | receive() external payable { 11 | require(false, 'PAYABLE_FAIL'); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /contracts/test/SherlockClaimManagerTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '../managers/SherlockClaimManager.sol'; 10 | 11 | /// @notice this contract is used for testing to view all storage variables 12 | contract SherlockClaimManagerTest is SherlockClaimManager { 13 | constructor(address _umaho, address _spcc) SherlockClaimManager(_umaho, _spcc) {} 14 | 15 | function viewPublicToInternalID(uint256 id) external view returns (bytes32) { 16 | return publicToInternalID[id]; 17 | } 18 | 19 | function viewInternalToPublicID(bytes32 id) external view returns (uint256) { 20 | return internalToPublicID[id]; 21 | } 22 | 23 | function viewClaims(bytes32 id) external view returns (Claim memory) { 24 | return claims_[id]; 25 | } 26 | 27 | function viewLastClaimID() external view returns (uint256) { 28 | return lastClaimID; 29 | } 30 | 31 | function isPayoutState(State _oldState, uint256 updated) external view returns (bool) { 32 | return _isPayoutState(_oldState, updated); 33 | } 34 | 35 | function isEscalateState(State _oldState, uint256 updated) external view returns (bool) { 36 | return _isEscalateState(_oldState, updated); 37 | } 38 | 39 | function isCleanupState(State _oldState) external view returns (bool) { 40 | return _isCleanupState(_oldState); 41 | } 42 | 43 | function _setClaimUpdate(uint256 _claimID, uint256 _updated) external { 44 | claims_[publicToInternalID[_claimID]].updated = _updated; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /contracts/test/SherlockProtocolManagerTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '../managers/SherlockProtocolManager.sol'; 10 | 11 | /// @notice this contract is used for testing to view all storage variables 12 | contract SherlockProtocolManagerTest is SherlockProtocolManager { 13 | constructor(IERC20 _token) SherlockProtocolManager(_token) {} 14 | 15 | function privateSettleTotalDebt() external { 16 | _settleTotalDebt(); 17 | } 18 | 19 | function privatesetMinActiveBalance(uint256 _min) external { 20 | minActiveBalance = _min; 21 | } 22 | 23 | function viewMinActiveBalance() external view returns (uint256) { 24 | return minActiveBalance; 25 | } 26 | 27 | function viewProtocolAgent(bytes32 _protocol) external view returns (address) { 28 | return protocolAgent_[_protocol]; 29 | } 30 | 31 | function viewRemovedProtocolAgent(bytes32 _protocol) external view returns (address) { 32 | return removedProtocolAgent[_protocol]; 33 | } 34 | 35 | function viewRemovedProtocolClaimDeadline(bytes32 _protocol) external view returns (uint256) { 36 | return removedProtocolClaimDeadline[_protocol]; 37 | } 38 | 39 | function viewNonStakersPercentage(bytes32 _protocol) external view returns (uint256) { 40 | return nonStakersPercentage[_protocol]; 41 | } 42 | 43 | function viewPremium(bytes32 _protocol) external view returns (uint256) { 44 | return premiums_[_protocol]; 45 | } 46 | 47 | function viewCurrentCoverage(bytes32 _protocol) external view returns (uint256) { 48 | return currentCoverage[_protocol]; 49 | } 50 | 51 | function viewPreviousCoverage(bytes32 _protocol) external view returns (uint256) { 52 | return previousCoverage[_protocol]; 53 | } 54 | 55 | function viewLastAccountedEachProtocol(bytes32 _protocol) external view returns (uint256) { 56 | return lastAccountedEachProtocol[_protocol]; 57 | } 58 | 59 | function viewNonStakersClaimableByProtocol(bytes32 _protocol) external view returns (uint256) { 60 | return nonStakersClaimableByProtocol[_protocol]; 61 | } 62 | 63 | function viewLastAccountedGlobal() external view returns (uint256) { 64 | return lastAccountedGlobal; 65 | } 66 | 67 | function viewAllPremiumsPerSecToStakers() external view returns (uint256) { 68 | return allPremiumsPerSecToStakers; 69 | } 70 | 71 | function viewLastClaimablePremiumsForStakers() external view returns (uint256) { 72 | return lastClaimablePremiumsForStakers; 73 | } 74 | 75 | function viewActiveBalance(bytes32 _protocol) external view returns (uint256) { 76 | return activeBalances[_protocol]; 77 | } 78 | 79 | function viewCalcForceRemoveBySecondsOfCoverage(bytes32 _protocol) 80 | external 81 | view 82 | returns (uint256, bool) 83 | { 84 | return _calcForceRemoveBySecondsOfCoverage(_protocol); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /contracts/test/SherlockTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '../Sherlock.sol'; 10 | 11 | /// @notice this contract is used for testing to view all storage variables 12 | contract SherlockTest is Sherlock { 13 | constructor( 14 | IERC20 _token, 15 | IERC20 _sher, 16 | string memory _name, 17 | string memory _symbol, 18 | IStrategyManager _strategy, 19 | ISherDistributionManager _sherDistributionManager, 20 | address _nonStakersAddress, 21 | ISherlockProtocolManager _sherlockProtocolManager, 22 | ISherlockClaimManager _sherlockClaimManager, 23 | uint256[] memory _initialPeriods 24 | ) 25 | Sherlock( 26 | _token, 27 | _sher, 28 | _name, 29 | _symbol, 30 | _strategy, 31 | _sherDistributionManager, 32 | _nonStakersAddress, 33 | _sherlockProtocolManager, 34 | _sherlockClaimManager, 35 | _initialPeriods 36 | ) 37 | {} 38 | 39 | function viewStakeShares(uint256 _id) external view returns (uint256) { 40 | return stakeShares[_id]; 41 | } 42 | 43 | function viewTotalStakeShares() external view returns (uint256) { 44 | return totalStakeShares; 45 | } 46 | 47 | function transfer(address _receiver, uint256 _amount) external { 48 | require(token.transfer(_receiver, _amount), 'F'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /contracts/util/CallbackMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 10 | import '../interfaces/managers/callbacks/ISherlockClaimManagerCallbackReceiver.sol'; 11 | 12 | contract CallbackMock is ISherlockClaimManagerCallbackReceiver { 13 | IERC20 constant TOKEN = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); 14 | 15 | function PreCorePayoutCallback( 16 | bytes32 _protocol, 17 | uint256 _claimID, 18 | uint256 _amount 19 | ) external override { 20 | TOKEN.transfer(msg.sender, TOKEN.balanceOf(address(this))); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contracts/util/ERC20Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '@openzeppelin/contracts/token/ERC20/ERC20.sol'; 10 | 11 | contract ERC20Mock6d is ERC20 { 12 | constructor( 13 | string memory _name, 14 | string memory _symbol, 15 | uint256 _amount 16 | ) ERC20(_name, _symbol) { 17 | _mint(msg.sender, _amount); 18 | } 19 | 20 | function decimals() public view virtual override returns (uint8) { 21 | return 6; 22 | } 23 | } 24 | 25 | contract ERC20Mock18d is ERC20 { 26 | constructor( 27 | string memory _name, 28 | string memory _symbol, 29 | uint256 _amount 30 | ) ERC20(_name, _symbol) { 31 | _mint(msg.sender, _amount); 32 | } 33 | 34 | function decimals() public view virtual override returns (uint8) { 35 | return 18; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/util/Import.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '@openzeppelin/contracts/governance/TimelockController.sol'; 10 | 11 | // Get the compiler to pick up these facets 12 | contract Imports { 13 | TimelockController public tc; 14 | } 15 | -------------------------------------------------------------------------------- /contracts/util/PausableMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '@openzeppelin/contracts/security/Pausable.sol'; 10 | 11 | contract PausableMock is Pausable { 12 | function pause() external { 13 | _pause(); 14 | } 15 | 16 | function unpause() external { 17 | _unpause(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/util/SherDistributionMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '../managers/Manager.sol'; 10 | import '../interfaces/managers/ISherDistributionManager.sol'; 11 | 12 | contract SherDistributionMock is ISherDistributionManager, Manager { 13 | uint256 reward; 14 | IERC20 token; 15 | IERC20 sher; 16 | 17 | uint256 public lastAmount; 18 | uint256 public lastPeriod; 19 | uint256 public value; 20 | 21 | bool public revertReward; 22 | 23 | constructor(IERC20 _token, IERC20 _sher) { 24 | token = _token; 25 | sher = _sher; 26 | 27 | value = type(uint256).max; 28 | } 29 | 30 | function setReward(uint256 _reward) external { 31 | reward = _reward; 32 | } 33 | 34 | function setRewardRevert(bool _revert) external { 35 | revertReward = _revert; 36 | } 37 | 38 | function setCustomRewardReturnValue(uint256 _value) external { 39 | value = _value; 40 | } 41 | 42 | function pullReward( 43 | uint256 _amount, 44 | uint256 _period, 45 | uint256 _id, 46 | address _receiver 47 | ) external override returns (uint256 _sher) { 48 | require(_amount != 0, 'ZERO'); 49 | require(!revertReward, 'REV'); 50 | _sher = reward; 51 | sher.transfer(msg.sender, reward); 52 | 53 | lastAmount = _amount; 54 | lastPeriod = _period; 55 | 56 | if (value != type(uint256).max) _sher = value; 57 | } 58 | 59 | function calcReward( 60 | uint256 _tvl, 61 | uint256 _amount, 62 | uint256 _period 63 | ) external view override returns (uint256 _sher) {} 64 | 65 | function isActive() external view override returns (bool) {} 66 | } 67 | -------------------------------------------------------------------------------- /contracts/util/SherlockMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 10 | import '@openzeppelin/contracts/token/ERC721/ERC721.sol'; 11 | import '@openzeppelin/contracts/access/Ownable.sol'; 12 | import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; 13 | 14 | import '../interfaces/ISherlock.sol'; 15 | 16 | contract SherlockMock is ISherlock, ERC721, Ownable { 17 | mapping(uint256 => bool) public override stakingPeriods; 18 | 19 | mapping(uint256 => uint256) public override lockupEnd; 20 | mapping(uint256 => uint256) public override sherRewards; 21 | 22 | IStrategyManager public override yieldStrategy; 23 | ISherDistributionManager public override sherDistributionManager; 24 | address public override nonStakersAddress; 25 | ISherlockProtocolManager public override sherlockProtocolManager; 26 | ISherlockClaimManager public override sherlockClaimManager; 27 | 28 | IERC20 token; 29 | 30 | constructor() ERC721('mock', 'm') {} 31 | 32 | function setNonStakersAddress(address _a) external { 33 | nonStakersAddress = _a; 34 | } 35 | 36 | // 37 | // View functions 38 | // 39 | function tokenBalanceOf(uint256 _tokenID) public view override returns (uint256) {} 40 | 41 | function setToken(IERC20 _token) external { 42 | token = _token; 43 | } 44 | 45 | function totalTokenBalanceStakers() public view override returns (uint256) { 46 | return token.balanceOf(address(this)); 47 | } 48 | 49 | // 50 | // Gov functions 51 | // 52 | 53 | function _setStakingPeriod(uint256 _period) internal {} 54 | 55 | function enableStakingPeriod(uint256 _period) external override onlyOwner {} 56 | 57 | function disableStakingPeriod(uint256 _period) external override onlyOwner {} 58 | 59 | function pullSherReward( 60 | uint256 _amount, 61 | uint256 _period, 62 | uint256 _id, 63 | address _receiver 64 | ) external { 65 | sherDistributionManager.pullReward(_amount, _period, _id, _receiver); 66 | } 67 | 68 | function updateSherDistributionManager(ISherDistributionManager _manager) 69 | external 70 | override 71 | onlyOwner 72 | { 73 | sherDistributionManager = _manager; 74 | } 75 | 76 | function removeSherDistributionManager() external override onlyOwner {} 77 | 78 | function updateNonStakersAddress(address _nonStakers) external override onlyOwner { 79 | nonStakersAddress = _nonStakers; 80 | } 81 | 82 | function updateSherlockProtocolManager(ISherlockProtocolManager _protocolManager) 83 | external 84 | override 85 | onlyOwner 86 | { 87 | sherlockProtocolManager = _protocolManager; 88 | } 89 | 90 | function updateSherlockClaimManager(ISherlockClaimManager _sherlockClaimManager) 91 | external 92 | override 93 | onlyOwner 94 | { 95 | sherlockClaimManager = _sherlockClaimManager; 96 | } 97 | 98 | function updateYieldStrategy(IStrategyManager _yieldStrategy) external override onlyOwner {} 99 | 100 | function updateYieldStrategyForce(IStrategyManager _yieldStrategy) external override onlyOwner {} 101 | 102 | function yieldStrategyDeposit(uint256 _amount) external override onlyOwner {} 103 | 104 | function yieldStrategyWithdraw(uint256 _amount) external override onlyOwner {} 105 | 106 | function yieldStrategyWithdrawAll() external override onlyOwner {} 107 | 108 | // 109 | // Access control functions 110 | // 111 | 112 | function payoutClaim(address _receiver, uint256 _amount) external override {} 113 | 114 | // 115 | // Non-access control functions 116 | // 117 | 118 | function _stake( 119 | uint256 _amount, 120 | uint256 _period, 121 | uint256 _id 122 | ) internal returns (uint256 _sher) {} 123 | 124 | function _verifyUnlockableByOwner(uint256 _id) internal view returns (address _nftOwner) {} 125 | 126 | function _sendSherRewardsToOwner(uint256 _id, address _nftOwner) internal {} 127 | 128 | function _transferTokensOut(address _receiver, uint256 _amount) internal {} 129 | 130 | function _redeemSharesCalc(uint256 _stakeShares) internal view returns (uint256) {} 131 | 132 | function _redeemShares( 133 | uint256 _id, 134 | uint256 _stakeShares, 135 | address _receiver 136 | ) internal returns (uint256 _amount) {} 137 | 138 | function _restake( 139 | uint256 _id, 140 | uint256 _period, 141 | address _nftOwner 142 | ) internal returns (uint256 _sher) {} 143 | 144 | function initialStake( 145 | uint256 _amount, 146 | uint256 _period, 147 | address _receiver 148 | ) external override returns (uint256 _id, uint256 _sher) {} 149 | 150 | function redeemNFT(uint256 _id) external override returns (uint256 _amount) {} 151 | 152 | function ownerRestake(uint256 _id, uint256 _period) external override returns (uint256 _sher) {} 153 | 154 | function _calcSharesForArbRestake(uint256 _id) internal view returns (uint256) {} 155 | 156 | function viewRewardForArbRestake(uint256 _id) external view returns (uint256) {} 157 | 158 | function arbRestake(uint256 _id) external override returns (uint256 _sher, uint256 _arbReward) {} 159 | } 160 | -------------------------------------------------------------------------------- /contracts/util/SherlockProtocolManagerMock.sol: -------------------------------------------------------------------------------- 1 | // include claimPremiums func() 2 | 3 | // SPDX-License-Identifier: GPL-2.0-or-later 4 | pragma solidity 0.8.10; 5 | 6 | /******************************************************************************\ 7 | * Author: Evert Kors (https://twitter.com/evert0x) 8 | * Sherlock Protocol: https://sherlock.xyz 9 | /******************************************************************************/ 10 | 11 | import '../managers/Manager.sol'; 12 | import '../interfaces/managers/ISherlockProtocolManager.sol'; 13 | 14 | contract SherlockProtocolManagerMock is ISherlockProtocolManager, Manager { 15 | uint256 amount; 16 | 17 | uint256 public claimCalled; 18 | 19 | IERC20 token; 20 | 21 | constructor(IERC20 _token) { 22 | token = _token; 23 | } 24 | 25 | function setAmount(uint256 _amount) external { 26 | amount = _amount; 27 | } 28 | 29 | function claimablePremiums() external view override returns (uint256) {} 30 | 31 | function claimPremiumsForStakers() external override { 32 | token.transfer(msg.sender, amount); 33 | claimCalled++; 34 | } 35 | 36 | function protocolAgent(bytes32 _protocol) external view override returns (address) {} 37 | 38 | function premium(bytes32 _protocol) external view override returns (uint256) {} 39 | 40 | function activeBalance(bytes32 _protocol) external view override returns (uint256) {} 41 | 42 | function secondsOfCoverageLeft(bytes32 _protocol) external view override returns (uint256) {} 43 | 44 | function protocolAdd( 45 | bytes32 _protocol, 46 | address _protocolAgent, 47 | bytes32 _coverage, 48 | uint256 _nonStakers, 49 | uint256 _coverageAmount 50 | ) external override {} 51 | 52 | function protocolUpdate( 53 | bytes32 _protocol, 54 | bytes32 _coverage, 55 | uint256 _nonStakers, 56 | uint256 _coverageAmount 57 | ) external override {} 58 | 59 | function protocolRemove(bytes32 _protocol) external override {} 60 | 61 | function forceRemoveByActiveBalance(bytes32 _protocol) external override {} 62 | 63 | function forceRemoveBySecondsOfCoverage(bytes32 _protocol) external override {} 64 | 65 | function minActiveBalance() external view override returns (uint256) {} 66 | 67 | function setMinActiveBalance(uint256 _minBalance) external override {} 68 | 69 | function setProtocolPremium(bytes32 _protocol, uint256 _premium) external override {} 70 | 71 | function setProtocolPremiums(bytes32[] calldata _protocol, uint256[] calldata _premium) 72 | external 73 | override 74 | {} 75 | 76 | function depositToActiveBalance(bytes32 _protocol, uint256 _amount) external override {} 77 | 78 | function withdrawActiveBalance(bytes32 _protocol, uint256 _amount) external override {} 79 | 80 | function transferProtocolAgent(bytes32 _protocol, address _protocolAgent) external override {} 81 | 82 | function nonStakersClaimable(bytes32 _protocol) external view override returns (uint256) {} 83 | 84 | function nonStakersClaim( 85 | bytes32 _protocol, 86 | uint256 _amount, 87 | address _receiver 88 | ) external override {} 89 | 90 | function coverageAmounts(bytes32 _protocol) 91 | external 92 | view 93 | override 94 | returns (uint256 current, uint256 previous) 95 | {} 96 | 97 | function isActive() external view override returns (bool) {} 98 | } 99 | -------------------------------------------------------------------------------- /contracts/util/StrategyMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '../managers/Manager.sol'; 10 | import '../interfaces/managers/IStrategyManager.sol'; 11 | 12 | contract StrategyMock is IStrategyManager, Manager { 13 | IERC20 public override want; 14 | uint256 public depositCalled; 15 | uint256 public withdrawCalled; 16 | uint256 public withdrawAllCalled; 17 | bool public fail; 18 | 19 | constructor(IERC20 _token) { 20 | want = _token; 21 | } 22 | 23 | function setFail() external { 24 | fail = true; 25 | } 26 | 27 | function withdrawAll() external override returns (uint256 b) { 28 | b = balanceOf(); 29 | if (b != 0) want.transfer(msg.sender, b); 30 | withdrawAllCalled++; 31 | require(!fail, 'FAIL'); 32 | } 33 | 34 | function withdraw(uint256 _amount) external override { 35 | want.transfer(msg.sender, _amount); 36 | withdrawCalled++; 37 | } 38 | 39 | function deposit() external override { 40 | depositCalled++; 41 | } 42 | 43 | function balanceOf() public view override returns (uint256) { 44 | return want.balanceOf(address(this)); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /contracts/util/StrategyMockGoerli.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '../managers/Manager.sol'; 10 | import '../interfaces/managers/IStrategyManager.sol'; 11 | 12 | contract StrategyMockGoerli is IStrategyManager, Manager { 13 | IERC20 public override want; 14 | 15 | constructor(IERC20 _token, address _mock) {} 16 | 17 | function withdrawAll() external override returns (uint256 b) {} 18 | 19 | function withdraw(uint256 _amount) external override {} 20 | 21 | function deposit() external override {} 22 | 23 | function balanceOf() public view override returns (uint256) {} 24 | } 25 | -------------------------------------------------------------------------------- /contracts/util/TreeSplitterMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '../strategy/base/BaseSplitter.sol'; 10 | 11 | contract TreeSplitterMock is BaseSplitter { 12 | constructor( 13 | IMaster _initialParent, 14 | INode _initialChildOne, 15 | INode _initialChildTwo 16 | ) BaseSplitter(_initialParent, _initialChildOne, _initialChildTwo) {} 17 | 18 | function _withdraw(uint256 _amount) internal virtual override { 19 | if (_amount % (2 * 10**6) == 0) { 20 | // if USDC amount is even 21 | childOne.withdraw(_amount); 22 | } else if (_amount % (1 * 10**6) == 0) { 23 | // if USDC amount is uneven 24 | childTwo.withdraw(_amount); 25 | } else { 26 | // if USDC has decimals 27 | revert('WITHDRAW'); 28 | } 29 | } 30 | 31 | function _deposit() internal virtual override { 32 | uint256 balance = want.balanceOf(address(this)); 33 | 34 | if (balance % (2 * 10**6) == 0) { 35 | // if USDC amount is even 36 | want.transfer(address(childOne), balance); 37 | childOne.deposit(); 38 | } else if (balance % (1 * 10**6) == 0) { 39 | // if USDC amount is uneven 40 | want.transfer(address(childTwo), balance); 41 | childTwo.deposit(); 42 | } else { 43 | // if USDC has decimals 44 | revert('DEPOSIT'); 45 | } 46 | } 47 | } 48 | 49 | contract TreeSplitterMockCustom is ISplitter { 50 | address public override core; 51 | IERC20 public override want; 52 | IMaster public override parent; 53 | uint256 public depositCalled; 54 | uint256 public withdrawCalled; 55 | uint256 public withdrawByAdminCalled; 56 | uint256 public withdrawAllCalled; 57 | uint256 public withdrawAllByAdminCalled; 58 | uint256 public childRemovedCalled; 59 | INode public updateChildCalled; 60 | INode public override childOne; 61 | INode public override childTwo; 62 | bool public override setupCompleted; 63 | 64 | function prepareBalanceCache() external override returns (uint256) { 65 | } 66 | 67 | function expireBalanceCache() external override { 68 | } 69 | 70 | function balanceOf() external view override returns (uint256) {} 71 | 72 | function setSetupCompleted(bool _completed) external { 73 | setupCompleted = _completed; 74 | } 75 | 76 | function setChildOne(INode _child) external { 77 | childOne = _child; 78 | } 79 | 80 | function setChildTwo(INode _child) external { 81 | childTwo = _child; 82 | } 83 | 84 | function setCore(address _core) external { 85 | core = _core; 86 | } 87 | 88 | function setWant(IERC20 _want) external { 89 | want = _want; 90 | } 91 | 92 | function setParent(IMaster _parent) external { 93 | parent = _parent; 94 | } 95 | 96 | function deposit() external override { 97 | depositCalled++; 98 | } 99 | 100 | function replace(INode _node) external override {} 101 | 102 | function replaceAsChild(ISplitter _node) external override {} 103 | 104 | function replaceForce(INode _node) external override {} 105 | 106 | function updateParent(IMaster _node) external override {} 107 | 108 | function withdraw(uint256 _amount) external override { 109 | withdrawCalled++; 110 | } 111 | 112 | function withdrawAll() external override returns (uint256) { 113 | withdrawAllCalled++; 114 | return type(uint256).max; 115 | } 116 | 117 | function withdrawAllByAdmin() external override returns (uint256) { 118 | withdrawAllByAdminCalled++; 119 | } 120 | 121 | function withdrawByAdmin(uint256 _amount) external override { 122 | withdrawByAdminCalled++; 123 | } 124 | 125 | /// @notice Call by child if it's needs to be updated 126 | function updateChild(INode _node) external override { 127 | updateChildCalled = _node; 128 | } 129 | 130 | /// @notice Call by child if removed 131 | function childRemoved() external override { 132 | childRemovedCalled++; 133 | } 134 | 135 | function isMaster() external view override returns (bool) {} 136 | 137 | function setInitialChildOne(INode _child) external override {} 138 | 139 | function setInitialChildTwo(INode _child) external override {} 140 | 141 | function siblingRemoved() external override {} 142 | } 143 | 144 | contract TreeSplitterMockTest { 145 | address public core; 146 | IERC20 public want; 147 | 148 | function setCore(address _core) external { 149 | core = _core; 150 | } 151 | 152 | function setWant(IERC20 _want) external { 153 | want = _want; 154 | } 155 | 156 | function deposit(INode _strategy) external { 157 | _strategy.deposit(); 158 | } 159 | 160 | function withdraw(INode _strategy, uint256 _amount) external { 161 | _strategy.withdraw(_amount); 162 | } 163 | 164 | function withdrawAll(INode _strategy) external { 165 | _strategy.withdrawAll(); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /contracts/util/TreeStrategyMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity 0.8.10; 3 | 4 | /******************************************************************************\ 5 | * Author: Evert Kors (https://twitter.com/evert0x) 6 | * Sherlock Protocol: https://sherlock.xyz 7 | /******************************************************************************/ 8 | 9 | import '../strategy/base/BaseStrategy.sol'; 10 | 11 | abstract contract BaseStrategyMock { 12 | function mockUpdateChild(IMaster _parent, INode _newNode) external { 13 | _parent.updateChild(_newNode); 14 | } 15 | } 16 | 17 | contract TreeStrategyMock is BaseStrategyMock, BaseStrategy { 18 | event WithdrawAll(); 19 | event Withdraw(uint256 amount); 20 | event Deposit(); 21 | 22 | uint256 public internalWithdrawAllCalled; 23 | uint256 public internalWithdrawCalled; 24 | uint256 public internalDepositCalled; 25 | bool public notWithdraw; 26 | 27 | function setupCompleted() external view override returns (bool) { 28 | return true; 29 | } 30 | 31 | constructor(IMaster _initialParent) BaseNode(_initialParent) {} 32 | 33 | function _balanceOf() internal view override returns (uint256) { 34 | return want.balanceOf(address(this)); 35 | } 36 | 37 | function _withdrawAll() internal override returns (uint256 amount) { 38 | if (notWithdraw) return 0; 39 | amount = _balanceOf(); 40 | want.transfer(msg.sender, amount); 41 | 42 | internalWithdrawAllCalled++; 43 | 44 | emit WithdrawAll(); 45 | } 46 | 47 | function _withdraw(uint256 _amount) internal override { 48 | want.transfer(msg.sender, _amount); 49 | 50 | internalWithdrawCalled++; 51 | 52 | emit Withdraw(_amount); 53 | } 54 | 55 | function _deposit() internal override { 56 | internalDepositCalled++; 57 | emit Deposit(); 58 | } 59 | 60 | function mockSetParent(IMaster _newParent) external { 61 | parent = _newParent; 62 | } 63 | 64 | function setNotWithdraw(bool _do) external { 65 | notWithdraw = _do; 66 | } 67 | } 68 | 69 | contract TreeStrategyMockCustom is BaseStrategyMock, IStrategy { 70 | address public override core; 71 | IERC20 public override want; 72 | IMaster public override parent; 73 | uint256 public depositCalled; 74 | uint256 public withdrawCalled; 75 | uint256 public withdrawByAdminCalled; 76 | uint256 public withdrawAllCalled; 77 | uint256 public withdrawAllByAdminCalled; 78 | uint256 public siblingRemovedCalled; 79 | bool public override setupCompleted; 80 | 81 | function prepareBalanceCache() external override returns (uint256) { 82 | return want.balanceOf(address(this)); 83 | } 84 | 85 | function expireBalanceCache() external override {} 86 | 87 | function balanceOf() external view override returns (uint256) {} 88 | 89 | function setSetupCompleted(bool _completed) external { 90 | setupCompleted = _completed; 91 | } 92 | 93 | function setCore(address _core) external { 94 | core = _core; 95 | } 96 | 97 | function setWant(IERC20 _want) external { 98 | want = _want; 99 | } 100 | 101 | function setParent(IMaster _parent) external { 102 | parent = _parent; 103 | } 104 | 105 | function deposit() external override { 106 | depositCalled++; 107 | } 108 | 109 | function remove() external override {} 110 | 111 | function replace(INode _node) external override {} 112 | 113 | function replaceAsChild(ISplitter _node) external override {} 114 | 115 | function replaceForce(INode _node) external override {} 116 | 117 | function updateParent(IMaster _node) external override {} 118 | 119 | function withdraw(uint256 _amount) external override { 120 | withdrawCalled++; 121 | if (want.balanceOf(address(this)) != 0) { 122 | want.transfer(address(core), _amount); 123 | } 124 | } 125 | 126 | function withdrawAll() external override returns (uint256) { 127 | withdrawAllCalled++; 128 | 129 | uint256 b = want.balanceOf(address(this)); 130 | if (b != 0) { 131 | want.transfer(address(core), b); 132 | return b; 133 | } 134 | 135 | return type(uint256).max; 136 | } 137 | 138 | function withdrawAllByAdmin() external override returns (uint256) { 139 | withdrawAllByAdminCalled++; 140 | } 141 | 142 | function withdrawByAdmin(uint256 _amount) external override { 143 | withdrawByAdminCalled++; 144 | } 145 | 146 | function siblingRemoved() external override { 147 | siblingRemovedCalled++; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /funding.json: -------------------------------------------------------------------------------- 1 | { 2 | "opRetro": { 3 | "projectId": "0x28a8b14613c3a5790b2d0c7b7d32384ecd187b3b86fc66ba9d9244944d20b422" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | require('@nomiclabs/hardhat-waffle'); 2 | require('solidity-coverage'); 3 | require('hardhat-gas-reporter'); 4 | require('hardhat-contract-sizer'); 5 | require('@nomiclabs/hardhat-etherscan'); 6 | require('dotenv').config(); 7 | const { DefenderRelaySigner, DefenderRelayProvider } = require('defender-relay-client/lib/ethers'); 8 | const rp = require('request-promise'); 9 | 10 | const Sherlock = '0x0865a889183039689034dA55c1Fd12aF5083eabF'; 11 | const TWO_WEEKS = 12096e5; 12 | const FOUR_HOURS_IN_SECONDS = 4 * 60 * 60; 13 | 14 | const ETHERSCAN_API = process.env.ETHERSCAN_API || ''; 15 | const ALCHEMY_API_KEY_MAINNET = process.env.ALCHEMY_API_KEY_MAINNET || ''; 16 | const ALCHEMY_API_KEY_GOERLI = process.env.ALCHEMY_API_KEY_GOERLI || ''; 17 | const PRIVATE_KEY_GOERLI = process.env.PRIVATE_KEY_GOERLI || ''; 18 | const PRIVATE_KEY_MAINNET = process.env.PRIVATE_KEY_MAINNET || ''; 19 | const RELAY_CREDENTIALS = { 20 | apiKey: process.env.RELAY_API_KEY, 21 | apiSecret: process.env.RELAY_API_SECRET, 22 | }; 23 | const RELAY_PROVIDER = new DefenderRelayProvider(RELAY_CREDENTIALS); 24 | const RELAY_SIGNER = new DefenderRelaySigner(RELAY_CREDENTIALS, RELAY_PROVIDER, { 25 | speed: 'fast', 26 | validForSeconds: FOUR_HOURS_IN_SECONDS, 27 | }); 28 | 29 | /** 30 | * @type import('hardhat/config').HardhatUserConfig 31 | */ 32 | 33 | task('restake', 'Send restaking transaction').setAction(async (taskArgs) => { 34 | const sherlock = await ethers.getContractAt('Sherlock', Sherlock); 35 | const NOW = Date.now(); 36 | 37 | const response = await rp({ uri: 'http://mainnet.indexer.sherlock.xyz/status', json: true }); 38 | if (!response['ok']) { 39 | console.log('Invalid response'); 40 | return; 41 | } 42 | for (const element of response['data']['staking_positions']) { 43 | // lockup_end (in milisecond) + TWO WEEKS 44 | const ARB_RESTAKE = element['lockup_end'] * 1000 + TWO_WEEKS; 45 | if (NOW < ARB_RESTAKE) { 46 | continue; 47 | } 48 | 49 | const result = await sherlock.viewRewardForArbRestake(element['id']); 50 | if (!result[1]) { 51 | console.log('Not able to restake', element['id']); 52 | continue; 53 | } 54 | 55 | console.log('restaking.. ', element['id']); 56 | try { 57 | await sherlock.connect(RELAY_SIGNER).arbRestake(element['id']); 58 | } catch (err) { 59 | console.log(err); 60 | } 61 | } 62 | }); 63 | 64 | module.exports = { 65 | solidity: { 66 | version: '0.8.10', 67 | settings: { 68 | optimizer: { 69 | enabled: true, 70 | runs: 20000, 71 | }, 72 | }, 73 | }, 74 | networks: { 75 | hardhat: { 76 | accounts: { 77 | mnemonic: 78 | 'apart turn peace asthma useful mother tank math engine usage prefer orphan exile fold squirrel', 79 | }, 80 | }, 81 | localhost: { 82 | timeout: 999999999, 83 | gasPrice: 1600000000000, 84 | //accounts: [PRIVATE_KEY].filter(item => item !== ''), 85 | }, 86 | local: { 87 | url: 'http://127.0.0.1:8545', 88 | gasPrice: 500000000000, 89 | }, 90 | mainnet: { 91 | timeout: 999999999, 92 | url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_API_KEY_MAINNET}`, 93 | gasPrice: 32000000000, 94 | accounts: [PRIVATE_KEY_MAINNET].filter((item) => item !== ''), 95 | }, 96 | goerli: { 97 | url: `https://eth-goerli.alchemyapi.io/v2/${ALCHEMY_API_KEY_GOERLI}`, 98 | gasPrice: 9000000000, 99 | accounts: [PRIVATE_KEY_GOERLI].filter((item) => item !== ''), 100 | }, 101 | }, 102 | gasReporter: { 103 | enabled: process.env.REPORT_GAS ? true : false, 104 | currency: 'USD', 105 | gasPrice: 100, 106 | coinmarketcap: process.env.COINMARKETCAP, 107 | }, 108 | etherscan: { 109 | // Your API key for Etherscan 110 | // Obtain one at https://etherscan.io/ 111 | apiKey: ETHERSCAN_API, 112 | }, 113 | }; 114 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "scripts": { 4 | "prettier": "prettier --write contracts/*.sol contracts/**/*.sol", 5 | "gas": "export REPORT_GAS=1; npx hardhat test; export REPORT_GAS=" 6 | }, 7 | "devDependencies": { 8 | "@nomiclabs/hardhat-ethers": "^2.0.2", 9 | "@nomiclabs/hardhat-waffle": "^2.0.1", 10 | "chai": "^4.3.4", 11 | "ethereum-waffle": "^3.4.0", 12 | "ethers": "^5.5.1", 13 | "hardhat": "^2.9.3", 14 | "hardhat-contract-sizer": "^2.1.1" 15 | }, 16 | "prettier": { 17 | "tabWidth": 2, 18 | "singleQuote": true, 19 | "bracketSpacing": true, 20 | "printWidth": 100, 21 | "trailingComma": "all", 22 | "quoteProps": "consistent", 23 | "semi": true 24 | }, 25 | "dependencies": { 26 | "@nomiclabs/hardhat-etherscan": "^3.0.1", 27 | "@openzeppelin/contracts": "^4.4.2", 28 | "@rari-capital/solmate": "https://github.com/Rari-Capital/solmate#e802bcf2fb24dda2bf7e513bea86d15c48b57486", 29 | "defender-relay-client": "^1.27.1", 30 | "dotenv": "^8.2.0", 31 | "hardhat-gas-reporter": "^1.0.4", 32 | "prettier-plugin-solidity": "^1.0.0-beta.18", 33 | "request-promise": "^4.2.6", 34 | "solidity-coverage": "^0.7.17" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /scripts/1_v2-deploy.js: -------------------------------------------------------------------------------- 1 | const { parseUnits, id, parseEther } = require('ethers/lib/utils'); 2 | 3 | const WEEK = parseInt(60 * 60 * 24 * 7); 4 | 5 | async function main() { 6 | // 7 | // CONFIG 8 | // 9 | [signer] = await ethers.getSigners(); 10 | if (signer.address != '0x1C11bE636415973520DdDf1b03822b4e2930D94A') { 11 | throw Error('DEPLOYER ' + signer.address); 12 | } 13 | 14 | const MULTISIG = '0x666B8EbFbF4D5f0CE56962a25635CfF563F13161'; 15 | const MIN_ACTIVE_BALANCE = parseUnits('500', 6); 16 | 17 | let USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; 18 | let aUSDC = '0xbcca60bb61934080951369a648fb03df4f96263c'; 19 | let SHER = '0x63E9aD95D09ae88614e0b0F462A3A96994c9b6CF'; 20 | 21 | if (network.name == 'goerli') { 22 | SHER = '0x63E9aD95D09ae88614e0b0F462A3A96994c9b6CF'; 23 | USDC = '0xfe193C63e15A54ac500f3038fce00193Ff141139'; 24 | } else if (network.name != 'mainnet') { 25 | throw Error('Invalid network'); 26 | } 27 | 28 | const UMAHO = '0x8fCC879036Fc8e45395AdE7D4eF739200037695c'; 29 | const SPCC = '0x4Fcf6AA323a92EB92a58025E821f393da6C41bD6'; 30 | const NON_STAKER = '0x666B8EbFbF4D5f0CE56962a25635CfF563F13161'; 31 | const NFT_NAME = 'Sherlock Staking Position NFT-V1'; 32 | const NFT_SYMBOL = 'SHER-POS'; 33 | 34 | const STAKING_PERIODS = [WEEK * 26, WEEK * 52]; 35 | 36 | // 37 | // END CONFIG 38 | // 39 | 40 | this.Sherlock = await ethers.getContractFactory('Sherlock'); 41 | this.AaveV2Strategy = await ethers.getContractFactory('AaveV2Strategy'); 42 | if (network.name == 'goerli') { 43 | this.AaveV2Strategy = await ethers.getContractFactory('StrategyMockGoerli'); 44 | } 45 | 46 | this.SherDistributionManager = await ethers.getContractFactory('SherDistributionManagerEmpty'); 47 | this.SherlockProtocolManager = await ethers.getContractFactory('SherlockProtocolManager'); 48 | this.SherlockClaimManager = await ethers.getContractFactory('SherlockClaimManager'); 49 | 50 | console.log('0 - Start'); 51 | 52 | const aaveV2Strategy = await this.AaveV2Strategy.deploy(aUSDC, MULTISIG); 53 | await aaveV2Strategy.deployed(); 54 | console.log('1 - Deployed aaveV2Strategy @', aaveV2Strategy.address); 55 | 56 | const sherDistributionManager = await this.SherDistributionManager.deploy(); 57 | await sherDistributionManager.deployed(); 58 | console.log('2 - Deployed sherDistributionManager @', sherDistributionManager.address); 59 | 60 | const sherlockProtocolManager = await this.SherlockProtocolManager.deploy(USDC); 61 | await sherlockProtocolManager.deployed(); 62 | console.log('3 - Deployed sherlockProtocolManager @', sherlockProtocolManager.address); 63 | 64 | await sherlockProtocolManager.setMinActiveBalance(MIN_ACTIVE_BALANCE); 65 | console.log('3.1 setMinActiveBalance'); 66 | 67 | const sherlockClaimManager = await this.SherlockClaimManager.deploy(UMAHO, SPCC); 68 | await sherlockClaimManager.deployed(); 69 | console.log('4 - Deployed sherlockClaimManager @', sherlockClaimManager.address); 70 | 71 | const sherlock = await this.Sherlock.deploy( 72 | USDC, 73 | SHER, 74 | NFT_NAME, 75 | NFT_SYMBOL, 76 | aaveV2Strategy.address, 77 | sherDistributionManager.address, 78 | NON_STAKER, 79 | sherlockProtocolManager.address, 80 | sherlockClaimManager.address, 81 | STAKING_PERIODS, 82 | ); 83 | await sherlock.deployed(); 84 | console.log('5 - Deployed sherlock @', sherlock.address); 85 | 86 | await (await aaveV2Strategy.setSherlockCoreAddress(sherlock.address)).wait(); 87 | console.log('6 - Set aaveV2Strategy core'); 88 | await (await sherDistributionManager.setSherlockCoreAddress(sherlock.address)).wait(); 89 | console.log('7 - Set sherDistributionManager core'); 90 | await (await sherlockProtocolManager.setSherlockCoreAddress(sherlock.address)).wait(); 91 | console.log('8 - Set sherlockProtocolManager core'); 92 | await (await sherlockClaimManager.setSherlockCoreAddress(sherlock.address)).wait(); 93 | console.log('9 - Set sherlockClaimManager core'); 94 | 95 | console.log("const Sherlock = '" + sherlock.address + "';"); 96 | console.log("const AaveV2Strategy = '" + aaveV2Strategy.address + "';"); 97 | console.log("const SherDistributionManager = '" + sherDistributionManager.address + "';"); 98 | console.log("const SherlockProtocolManager = '" + sherlockProtocolManager.address + "';"); 99 | console.log("const SherlockClaimManager = '" + sherlockClaimManager.address + "';"); 100 | } 101 | 102 | main() 103 | .then(() => process.exit(0)) 104 | .catch((error) => { 105 | console.error(error); 106 | process.exit(1); 107 | }); 108 | -------------------------------------------------------------------------------- /scripts/2_timelock.js: -------------------------------------------------------------------------------- 1 | const { parseUnits, id, keccak256 } = require('ethers/lib/utils'); 2 | const { constants } = require('ethers'); 3 | 4 | const TIMELOCK_ADMIN_ROLE = '0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5'; 5 | const PROPOSER_ROLE = '0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1'; 6 | const EXECUTOR_ROLE = '0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63'; 7 | 8 | async function main() { 9 | // 10 | // CONFIG 11 | // 12 | 13 | [signer] = await ethers.getSigners(); 14 | 15 | let MULTISIG = '0x666B8EbFbF4D5f0CE56962a25635CfF563F13161'; 16 | let EOA_ONE = '0xE400820f3D60d77a3EC8018d44366ed0d334f93C'; 17 | let EOA_TWO = '0x4cf5F3EcD6303F6a04480F75ac394D4bB3816F83'; 18 | const DELAY = 1; // 1 second FOR INITIAL TWO WEEKS 19 | 20 | if (network.name == 'goerli') { 21 | MULTISIG = '0x34EDB6fD102578De64CaEbe82f540fB3E47a05EA'; 22 | EOA_ONE = '0xE400820f3D60d77a3EC8018d44366ed0d334f93C'; 23 | EOA_TWO = '0x4cf5F3EcD6303F6a04480F75ac394D4bB3816F83'; 24 | } 25 | 26 | const Sherlock = '0x0865a889183039689034dA55c1Fd12aF5083eabF'; 27 | const AaveV2Strategy = '0xF02d3A6288D998B412ce749cfF244c8ef799f582'; 28 | const SherDistributionManager = '0x5775F32787656E77dd99f20F4E478DdC85fdB31b'; 29 | const SherlockProtocolManager = '0x3d0b8A0A10835Ab9b0f0BeB54C5400B8aAcaa1D3'; 30 | const SherlockClaimManager = '0xFeEDD254ae4B7c44A0472Bb836b813Ce4625Eb84'; 31 | 32 | // 33 | // END CONFIG 34 | // 35 | const sherlock = await ethers.getContractAt('Sherlock', Sherlock); 36 | const aaveV2Strategy = await ethers.getContractAt('AaveV2Strategy', AaveV2Strategy); 37 | const sherDistributionManager = await ethers.getContractAt( 38 | 'SherDistributionManager', 39 | SherDistributionManager, 40 | ); 41 | const sherlockProtocolManager = await ethers.getContractAt( 42 | 'SherlockProtocolManager', 43 | SherlockProtocolManager, 44 | ); 45 | const sherlockClaimManager = await ethers.getContractAt( 46 | 'SherlockClaimManager', 47 | SherlockClaimManager, 48 | ); 49 | 50 | const timelock = await ( 51 | await ethers.getContractFactory('TimelockController') 52 | ).deploy(DELAY, [MULTISIG], [MULTISIG, EOA_ONE, EOA_TWO]); 53 | await timelock.deployed(); 54 | 55 | console.log('1 - Deployed timelockController @', timelock.address); 56 | await timelock.revokeRole(TIMELOCK_ADMIN_ROLE, signer.address); 57 | 58 | await (await sherlock.transferOwnership(timelock.address)).wait(); 59 | console.log('2 - Transferred sherlock ownership'); 60 | 61 | await (await aaveV2Strategy.transferOwnership(timelock.address)).wait(); 62 | console.log('3 - Transferred aaveV2Strategy ownership'); 63 | 64 | await (await sherDistributionManager.transferOwnership(timelock.address)).wait(); 65 | console.log('4 - Transferred sherDistributionManager ownership'); 66 | 67 | await (await sherlockProtocolManager.transferOwnership(timelock.address)).wait(); 68 | console.log('5 - Transferred sherlockProtocolManager ownership'); 69 | 70 | await (await sherlockClaimManager.transferOwnership(timelock.address)).wait(); 71 | console.log('6 - Transferred sherlockClaimManager ownership'); 72 | 73 | console.log( 74 | 'Does signer have TIMELOCK_ADMIN_ROLE?', 75 | await timelock.hasRole(TIMELOCK_ADMIN_ROLE, signer.address), 76 | ); 77 | console.log( 78 | 'Does signer have PROPOSER_ROLE?', 79 | await timelock.hasRole(PROPOSER_ROLE, signer.address), 80 | ); 81 | console.log( 82 | 'Does signer have EXECUTOR_ROLE?', 83 | await timelock.hasRole(EXECUTOR_ROLE, signer.address), 84 | ); 85 | } 86 | 87 | main() 88 | .then(() => process.exit(0)) 89 | .catch((error) => { 90 | console.error(error); 91 | process.exit(1); 92 | }); 93 | -------------------------------------------------------------------------------- /scripts/3_fundraise.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require('ethers'); 2 | const { parseUnits } = require('ethers/lib/utils'); 3 | 4 | async function main() { 5 | // 6 | // CONFIG 7 | // 8 | let MULTISIG = '0x666B8EbFbF4D5f0CE56962a25635CfF563F13161'; 9 | let USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; 10 | let SHER = '0x63E9aD95D09ae88614e0b0F462A3A96994c9b6CF'; 11 | let SHERLOCK = '0x0865a889183039689034dA55c1Fd12aF5083eabF'; 12 | 13 | if (network.name == 'goerli') { 14 | SHER = '0x63E9aD95D09ae88614e0b0F462A3A96994c9b6CF'; 15 | USDC = '0xfe193C63e15A54ac500f3038fce00193Ff141139'; 16 | SHERLOCK = '0x0865a889183039689034dA55c1Fd12aF5083eabF'; 17 | } 18 | 19 | const END_RAISE = '1647100800'; 20 | 21 | const STAKE_RATE = parseUnits('9', 6); 22 | const BUY_RATE = parseUnits('1', 6); 23 | // 24 | // END CONFIG 25 | // 26 | 27 | this.SherClaim = await ethers.getContractFactory('SherClaim'); 28 | this.SherBuy = await ethers.getContractFactory('SherBuy'); 29 | 30 | const sherClaim = await this.SherClaim.deploy(SHER, END_RAISE); 31 | await sherClaim.deployed(); 32 | console.log('0 - Deployed SherClaim'); 33 | 34 | const sherBuy = await this.SherBuy.deploy( 35 | SHER, 36 | USDC, 37 | STAKE_RATE, 38 | BUY_RATE, 39 | SHERLOCK, 40 | MULTISIG, 41 | sherClaim.address, 42 | ); 43 | await sherBuy.deployed(); 44 | console.log('1 - Deployed SherBuy'); 45 | 46 | console.log(`const SherClaim = "${sherClaim.address}";`); 47 | console.log(`const SherBuy = "${sherBuy.address}";`); 48 | } 49 | 50 | main() 51 | .then(() => process.exit(0)) 52 | .catch((error) => { 53 | console.error(error); 54 | process.exit(1); 55 | }); 56 | -------------------------------------------------------------------------------- /scripts/4_start_fundraise.js: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// USE MULTISIG 5 | /// 6 | /// 7 | /// 8 | -------------------------------------------------------------------------------- /scripts/6_sherdist.js: -------------------------------------------------------------------------------- 1 | const { parseUnits, id, parseEther } = require('ethers/lib/utils'); 2 | 3 | const WEEK = parseInt(60 * 60 * 24 * 7); 4 | 5 | async function main() { 6 | // 7 | // CONFIG 8 | // 9 | // [signer] = await ethers.getSigners(); 10 | // if (signer.address != '0x1C11bE636415973520DdDf1b03822b4e2930D94A') { 11 | // throw Error('DEPLOYER ' + signer.address); 12 | // } 13 | 14 | const MAX = 12718762718; 15 | const FLAT = parseUnits('20000000', 6); 16 | const DROP = parseUnits('35000000', 6); 17 | const SHER = '0x46D2A90153cd8F09464CA3a5605B6BBeC9C2fF01'; 18 | 19 | this.SherDistributionManager = await ethers.getContractFactory('SherDistributionManager'); 20 | 21 | const sherDistributionManager = await this.SherDistributionManager.deploy(FLAT, DROP, MAX, SHER); 22 | await sherDistributionManager.deployed(); 23 | console.log('2 - Deployed sherDistributionManager @', sherDistributionManager.address); 24 | 25 | // set core address 26 | // transer ownership 27 | 28 | const x = await sherDistributionManager.calcReward( 29 | parseUnits('0', 6), 30 | parseUnits('3000000000000000000', 6), 31 | WEEK * 26, 32 | ); 33 | console.log(x.toString()); 34 | 35 | await hre.run('verify:verify', { 36 | address: '0xE91693D47E88A0f17a827F2d4B1e7e9716326740', //sherDistributionManager.address, 37 | constructorArguments: [FLAT, DROP, MAX, SHER], 38 | }); 39 | } 40 | 41 | main() 42 | .then(() => process.exit(0)) 43 | .catch((error) => { 44 | console.error(error); 45 | process.exit(1); 46 | }); 47 | -------------------------------------------------------------------------------- /scripts/6_strat.deploy.js: -------------------------------------------------------------------------------- 1 | const { parseUnits, id, keccak256 } = require('ethers/lib/utils'); 2 | const { constants } = require('ethers'); 3 | 4 | const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; 5 | const CORE = '0x0865a889183039689034dA55c1Fd12aF5083eabF'; 6 | const aUSDC = '0xbcca60bb61934080951369a648fb03df4f96263c'; 7 | const MULTISIG = '0x666B8EbFbF4D5f0CE56962a25635CfF563F13161'; 8 | const Maven11 = '0x7C57bF654Bc16B0C9080F4F75FF62876f50B8259'; 9 | const TIMELOCK = '0x92AEffFfaD9fff820f7FCaf1563d8467aFe358c4'; 10 | 11 | if (network.name != 'mainnet') { 12 | throw Error('Invalid network'); 13 | } 14 | 15 | // ![Initial tree strategy](https://i.imgur.com/R4SdF14.png) 16 | 17 | async function main() { 18 | this.InfoStorage = await ethers.getContractFactory('InfoStorage'); 19 | this.MasterStrategy = await ethers.getContractFactory('MasterStrategy'); 20 | // Splitters used 21 | this.splitterMax = await ethers.getContractFactory('AlphaBetaEqualDepositMaxSplitter'); 22 | this.splitterEqual = await ethers.getContractFactory('AlphaBetaEqualDepositSplitter'); 23 | 24 | // Strategies used 25 | this.aave = await ethers.getContractFactory('AaveStrategy'); 26 | this.compound = await ethers.getContractFactory('CompoundStrategy'); 27 | this.euler = await ethers.getContractFactory('EulerStrategy'); 28 | 29 | // Deploy store 30 | const infoStorage = await this.InfoStorage.deploy(USDC, CORE); 31 | await infoStorage.deployed(); 32 | console.log('0 - Deployed infoStorage @', infoStorage.address); 33 | 34 | // Deploy master 35 | const master = await this.MasterStrategy.deploy(infoStorage.address); 36 | await master.deployed(); 37 | console.log('1 - Deployed master @', master.address); 38 | 39 | // Deploy AAVE 40 | /* 41 | 42 | m 43 | | 44 | aave 45 | 46 | */ 47 | const aave = await this.aave.deploy(master.address, aUSDC, MULTISIG); 48 | await aave.deployed(); 49 | 50 | await (await master.setInitialChildOne(aave.address)).wait(); 51 | 52 | console.log('2 - Deployed aave @', aave.address); 53 | 54 | // Deploy COMPOUND 55 | /* 56 | 57 | m 58 | | 59 | 1 60 | / \ 61 | aave comp 62 | 63 | */ 64 | const splitter1 = await this.splitterEqual.deploy( 65 | master.address, 66 | constants.AddressZero, 67 | aave.address, 68 | parseUnits('500000', 6), // 500k USDC 69 | ); 70 | await splitter1.deployed(); 71 | 72 | const comp = await this.compound.deploy(splitter1.address); 73 | await comp.deployed(); 74 | 75 | await splitter1.setInitialChildOne(comp.address); 76 | await aave.replaceAsChild(splitter1.address); 77 | 78 | console.log('!!(3) - Deployed splitter1 @', splitter1.address); 79 | console.log('3 - Deployed comp @', comp.address); 80 | 81 | // Deploy EULER 82 | /* 83 | 84 | m 85 | | 86 | 0 87 | / \ 88 | eul 1 89 | / \ 90 | comp aave 91 | 92 | */ 93 | const splitter0 = await this.splitterMax.deploy( 94 | master.address, 95 | splitter1.address, 96 | constants.AddressZero, 97 | parseUnits('10000000', 6), // 10m USDC 98 | constants.MaxUint256, 99 | parseUnits('2000000', 6), // 2m USDC 100 | ); 101 | await splitter0.deployed(); 102 | 103 | const euler = await this.euler.deploy(splitter0.address); 104 | await euler.deployed(); 105 | 106 | await splitter0.setInitialChildTwo(euler.address); 107 | await splitter1.replaceAsChild(splitter0.address); 108 | 109 | console.log('!!(0) - Deployed splitter0 @', splitter0.address); 110 | console.log('4 - Deployed euler @', euler.address); 111 | 112 | console.log('--------------------------------------------'); 113 | console.log('-------------DEPLOY = DONE------------------'); 114 | console.log('--------------------------------------------'); 115 | 116 | /* 117 | Transfering ownerships 118 | */ 119 | 120 | await (await master.transferOwnership(TIMELOCK)).wait(); 121 | console.log('0 - Transferred master ownership'); 122 | 123 | await (await aave.transferOwnership(TIMELOCK)).wait(); 124 | console.log('1 - Transferred aave ownership'); 125 | 126 | await (await comp.transferOwnership(TIMELOCK)).wait(); 127 | console.log('3 - Transferred comp ownership'); 128 | 129 | await (await splitter0.transferOwnership(TIMELOCK)).wait(); 130 | console.log('4 - Transferred splitter0 ownership'); 131 | 132 | await (await euler.transferOwnership(TIMELOCK)).wait(); 133 | console.log('5 - Transferred euler ownership'); 134 | 135 | await (await splitter1.transferOwnership(TIMELOCK)).wait(); 136 | console.log('6 - Transferred splitter1 ownership'); 137 | 138 | console.log('--------------------------------------------'); 139 | console.log('------------TRANSFER = DONE-----------------'); 140 | console.log('--------------------------------------------'); 141 | 142 | /* 143 | View 144 | */ 145 | console.log('master > childOne - ', await master.childOne()); 146 | 147 | console.log('splitter0 > childOne - ', await splitter0.childOne()); 148 | console.log('splitter0 > childTwo - ', await splitter0.childTwo()); 149 | console.log('splitter0 > parent - ', await splitter0.parent()); 150 | 151 | console.log('splitter1 > childOne - ', await splitter1.childOne()); 152 | console.log('splitter1 > childTwo - ', await splitter1.childTwo()); 153 | console.log('splitter1 > parent - ', await splitter1.parent()); 154 | 155 | console.log('aave > parent - ', await aave.parent()); 156 | console.log('comp > parent - ', await comp.parent()); 157 | console.log('euler > parent - ', await euler.parent()); 158 | 159 | /* 160 | Finally 161 | */ 162 | // call updateYieldStrategy on core 163 | } 164 | 165 | main() 166 | .then(() => process.exit(0)) 167 | .catch((error) => { 168 | console.error(error); 169 | process.exit(1); 170 | }); 171 | -------------------------------------------------------------------------------- /scripts/8_strat_deploy.js: -------------------------------------------------------------------------------- 1 | const { parseUnits, id, keccak256 } = require('ethers/lib/utils'); 2 | const { constants } = require('ethers'); 3 | 4 | const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; 5 | const CORE = '0x0865a889183039689034dA55c1Fd12aF5083eabF'; 6 | const aUSDC = '0xbcca60bb61934080951369a648fb03df4f96263c'; 7 | const MULTISIG = '0x666B8EbFbF4D5f0CE56962a25635CfF563F13161'; 8 | const Maven11 = '0x7C57bF654Bc16B0C9080F4F75FF62876f50B8259'; 9 | const TIMELOCK = '0x92AEffFfaD9fff820f7FCaf1563d8467aFe358c4'; 10 | 11 | const Splitter1 = '0x7E0049866879151480d9Ec01391Bbf713F7705b1'; 12 | const EulerStrategy = '0xC124A8088c39625f125655152A168baA86b49026'; 13 | const MasterStrategy = '0x1E8bE946370a99019E323998Acd37A1206bdD507'; 14 | 15 | // if (network.name != 'mainnet') { 16 | // throw Error('Invalid network'); 17 | // } 18 | 19 | // ![Initial tree strategy](https://i.imgur.com/R4SdF14.png) 20 | 21 | async function main() { 22 | this.splitterMax = await ethers.getContractFactory('AlphaBetaEqualDepositMaxSplitter'); 23 | this.splitterEqual = await ethers.getContractFactory('AlphaBetaEqualDepositSplitter'); 24 | const euler = await ethers.getContractAt('EulerStrategy', EulerStrategy); 25 | const splitter1 = await ethers.getContractAt('AlphaBetaEqualDepositSplitter', Splitter1); 26 | 27 | // Strategies used 28 | this.maple = await ethers.getContractFactory('MapleStrategy'); 29 | this.truefi = await ethers.getContractFactory('TrueFiStrategy'); 30 | 31 | await network.provider.request({ 32 | method: 'hardhat_impersonateAccount', 33 | params: [TIMELOCK], 34 | }); 35 | await network.provider.request({ 36 | method: 'hardhat_setBalance', 37 | params: [TIMELOCK, '0x100000000000000000000000000'], 38 | }); 39 | this.timelock = await ethers.provider.getSigner(TIMELOCK); 40 | 41 | // Deploy Splitter 0 42 | /* 43 | (live structure) 44 | m 45 | | 46 | 1 47 | / \ 48 | aave comp 49 | 50 | (non-live structure) 51 | m 52 | | (0 --> m conn) 53 | 0 54 | / \ (0 --> 1 conn) 55 | 1 56 | / \ 57 | aave comp 58 | */ 59 | 60 | const splitter0 = await this.splitterMax.deploy( 61 | MasterStrategy, 62 | splitter1.address, 63 | constants.AddressZero, 64 | parseUnits('10000000', 6), // 10m USDC 65 | constants.MaxUint256, 66 | parseUnits('5000000', 6), // 5m USDC (5m maple) 67 | ); 68 | await splitter0.deployed(); 69 | console.log('Splitter 0', splitter0.address); 70 | 71 | // Deploy Maple & Truefi 72 | const maple = await this.maple.deploy(splitter0.address, Maven11); 73 | await maple.deployed(); 74 | console.log('Maple', maple.address); 75 | 76 | await splitter0.setInitialChildTwo(maple.address); 77 | 78 | /* 79 | Transfering ownerships 80 | */ 81 | 82 | await (await splitter0.transferOwnership(TIMELOCK)).wait(); 83 | console.log('0 - Transferred splitter0 ownership'); 84 | 85 | await (await maple.transferOwnership(TIMELOCK)).wait(); 86 | console.log('3 - Transferred maple ownership'); 87 | 88 | console.log('--------------------------------------------'); 89 | console.log('------------TRANSFER = DONE-----------------'); 90 | console.log('--------------------------------------------'); 91 | 92 | // !!!!!!!!!!!!!!!!!!!!!! 93 | // !!! ADMIN FUNCTION !!! 94 | // !!!!!!!!!!!!!!!!!!!!!! 95 | await splitter1.connect(this.timelock).replaceAsChild(splitter0.address); 96 | 97 | /* 98 | View 99 | */ 100 | const master = await ethers.getContractAt( 101 | 'ISplitter', 102 | '0x1E8bE946370a99019E323998Acd37A1206bdD507', 103 | ); 104 | const aave = await ethers.getContractAt( 105 | 'ISplitter', 106 | '0x75C5d2d8D54254476239a5c1e1F23ec48Df8779E', 107 | ); 108 | const comp = await ethers.getContractAt( 109 | 'ISplitter', 110 | '0x5b7a52b6d75Fb3105c3c37fcc6007Eb7ac78F1B8', 111 | ); 112 | 113 | console.log('master > childOne - ', await master.childOne()); 114 | 115 | console.log('splitter0 > childOne - ', await splitter0.childOne()); 116 | console.log('splitter0 > childTwo - ', await splitter0.childTwo()); 117 | console.log('splitter0 > parent - ', await splitter0.parent()); 118 | 119 | console.log('splitter1 > childOne - ', await splitter1.childOne()); 120 | console.log('splitter1 > childTwo - ', await splitter1.childTwo()); 121 | console.log('splitter1 > parent - ', await splitter1.parent()); 122 | 123 | console.log('comp > parent - ', await comp.parent()); 124 | console.log('aave > parent - ', await aave.parent()); 125 | console.log('maple > parent - ', await maple.parent()); 126 | 127 | const core = await ethers.getContractAt('Sherlock', '0x0865a889183039689034dA55c1Fd12aF5083eabF'); 128 | 129 | await core.connect(this.timelock).yieldStrategyWithdraw(parseUnits('20300000', 6)); // 10m 130 | await core.connect(this.timelock).yieldStrategyDeposit(parseUnits('20360000', 6)); // 10m + 60k 131 | 132 | const mapleBalance = await maple.balanceOf(); 133 | console.log('maple', mapleBalance.toString()); 134 | 135 | const aaveB = await aave.balanceOf(); 136 | console.log('aaveB', aaveB.toString()); 137 | 138 | const compB = await comp.balanceOf(); 139 | console.log('compB', compB.toString()); 140 | } 141 | 142 | main() 143 | .then(() => process.exit(0)) 144 | .catch((error) => { 145 | console.error(error); 146 | process.exit(1); 147 | }); 148 | -------------------------------------------------------------------------------- /scripts/9_strat_deploy.js: -------------------------------------------------------------------------------- 1 | const { parseUnits, id, keccak256 } = require('ethers/lib/utils'); 2 | const { constants } = require('ethers'); 3 | 4 | const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; 5 | const CORE = '0x0865a889183039689034dA55c1Fd12aF5083eabF'; 6 | const aUSDC = '0xbcca60bb61934080951369a648fb03df4f96263c'; 7 | const MULTISIG = '0x666B8EbFbF4D5f0CE56962a25635CfF563F13161'; 8 | const Maven11 = '0x7C57bF654Bc16B0C9080F4F75FF62876f50B8259'; 9 | const TIMELOCK = '0x92AEffFfaD9fff820f7FCaf1563d8467aFe358c4'; 10 | 11 | const Splitter0 = '0x3b5560b01b6A413Ec8A9AFE2C5eABB073790D77D'; 12 | const Splitter1 = '0x7E0049866879151480d9Ec01391Bbf713F7705b1'; 13 | const EulerStrategy = '0xC124A8088c39625f125655152A168baA86b49026'; 14 | const MapleStrategy = '0xee4b70AE96fFC70563f70964ebDD8635033Bc6b4'; 15 | const MasterStrategy = '0x1E8bE946370a99019E323998Acd37A1206bdD507'; 16 | 17 | // if (network.name != 'mainnet') { 18 | // throw Error('Invalid network'); 19 | // } 20 | 21 | // ![Initial tree strategy](https://i.imgur.com/R4SdF14.png) 22 | 23 | async function main() { 24 | this.splitterMax = await ethers.getContractFactory('AlphaBetaEqualDepositMaxSplitter'); 25 | this.splitterEqual = await ethers.getContractFactory('AlphaBetaEqualDepositSplitter'); 26 | const euler = await ethers.getContractAt('EulerStrategy', EulerStrategy); 27 | const maple = await ethers.getContractAt('MapleStrategy', MapleStrategy); 28 | const splitter1 = await ethers.getContractAt('AlphaBetaEqualDepositSplitter', Splitter1); 29 | const splitter0 = await ethers.getContractAt('AlphaBetaEqualDepositSplitter', Splitter0); 30 | 31 | // Strategies used 32 | this.truefi = await ethers.getContractFactory('TrueFiStrategy'); 33 | 34 | await network.provider.request({ 35 | method: 'hardhat_impersonateAccount', 36 | params: [TIMELOCK], 37 | }); 38 | await network.provider.request({ 39 | method: 'hardhat_setBalance', 40 | params: [TIMELOCK, '0x100000000000000000000000000'], 41 | }); 42 | this.timelock = await ethers.provider.getSigner(TIMELOCK); 43 | 44 | // Deploy Splitter 0 45 | /* 46 | (live structure) 47 | m 48 | | 49 | 1 50 | / \ 51 | aave comp 52 | 53 | (non-live structure) 54 | m 55 | | (0 --> m conn) 56 | 0 57 | / \ (0 --> 1 conn) 58 | 1 59 | / \ 60 | aave comp 61 | */ 62 | 63 | const splitter0new = await this.splitterMax.deploy( 64 | MasterStrategy, 65 | splitter1.address, 66 | MapleStrategy, 67 | parseUnits('10000000', 6), // 10m USDC 68 | constants.MaxUint256, 69 | parseUnits('10000000', 6), // 10m USDC (5m maple + 5m truefi) 70 | ); 71 | await splitter0new.deployed(); 72 | await splitter0.connect(this.timelock).replace(splitter0new.address); 73 | console.log('Splitter 0 (new)', splitter0new.address); 74 | 75 | const splitter2 = await this.splitterEqual.deploy( 76 | splitter0new.address, 77 | constants.AddressZero, 78 | MapleStrategy, 79 | parseUnits('100000', 6), // 100k USDC 80 | ); 81 | await splitter2.deployed(); 82 | console.log('Splitter 2', splitter2.address); 83 | 84 | // Deploy Maple & Truefi 85 | const truefi = await this.truefi.deploy(splitter2.address); 86 | await truefi.deployed(); 87 | console.log('Truefi', truefi.address); 88 | 89 | await splitter2.setInitialChildOne(truefi.address); 90 | 91 | /* 92 | Transfering ownerships 93 | */ 94 | 95 | await (await splitter0new.transferOwnership(TIMELOCK)).wait(); 96 | console.log('0 - Transferred splitter0 (new) ownership'); 97 | 98 | await (await splitter2.transferOwnership(TIMELOCK)).wait(); 99 | console.log('1 - Transferred splitter2 ownership'); 100 | 101 | await (await truefi.transferOwnership(TIMELOCK)).wait(); 102 | console.log('2 - Transferred truefi ownership'); 103 | 104 | console.log('--------------------------------------------'); 105 | console.log('------------TRANSFER = DONE-----------------'); 106 | console.log('--------------------------------------------'); 107 | 108 | // !!!!!!!!!!!!!!!!!!!!!! 109 | // !!! ADMIN FUNCTION !!! 110 | // !!!!!!!!!!!!!!!!!!!!!! 111 | await maple.connect(this.timelock).replaceAsChild(splitter2.address); 112 | 113 | /* 114 | View 115 | */ 116 | const master = await ethers.getContractAt( 117 | 'ISplitter', 118 | '0x1E8bE946370a99019E323998Acd37A1206bdD507', 119 | ); 120 | const aave = await ethers.getContractAt( 121 | 'ISplitter', 122 | '0x75C5d2d8D54254476239a5c1e1F23ec48Df8779E', 123 | ); 124 | const comp = await ethers.getContractAt( 125 | 'ISplitter', 126 | '0x5b7a52b6d75Fb3105c3c37fcc6007Eb7ac78F1B8', 127 | ); 128 | 129 | console.log('master > childOne - ', await master.childOne()); 130 | 131 | console.log('splitter0 > childOne - ', await splitter0new.childOne()); 132 | console.log('splitter0 > childTwo - ', await splitter0new.childTwo()); 133 | console.log('splitter0 > parent - ', await splitter0new.parent()); 134 | 135 | console.log('splitter1 > childOne - ', await splitter1.childOne()); 136 | console.log('splitter1 > childTwo - ', await splitter1.childTwo()); 137 | console.log('splitter1 > parent - ', await splitter1.parent()); 138 | 139 | console.log('splitter2 > childOne - ', await splitter2.childOne()); 140 | console.log('splitter2 > childTwo - ', await splitter2.childTwo()); 141 | console.log('splitter2 > parent - ', await splitter2.parent()); 142 | 143 | console.log('comp > parent - ', await comp.parent()); 144 | console.log('aave > parent - ', await aave.parent()); 145 | console.log('maple > parent - ', await maple.parent()); 146 | console.log('truefi > parent - ', await truefi.parent()); 147 | 148 | const core = await ethers.getContractAt('Sherlock', '0x0865a889183039689034dA55c1Fd12aF5083eabF'); 149 | 150 | await core.connect(this.timelock).yieldStrategyWithdraw(parseUnits('15000000', 6)); // 10m 151 | await core.connect(this.timelock).yieldStrategyDeposit(parseUnits('15000000', 6)); // 10m + 60k 152 | 153 | const mapleBalance = await maple.balanceOf(); 154 | console.log('maple', mapleBalance.toString()); 155 | 156 | const tfBalance = await truefi.balanceOf(); 157 | console.log('truefi', tfBalance.toString()); 158 | 159 | const aaveB = await aave.balanceOf(); 160 | console.log('aaveB', aaveB.toString()); 161 | 162 | const compB = await comp.balanceOf(); 163 | console.log('compB', compB.toString()); 164 | } 165 | 166 | main() 167 | .then(() => process.exit(0)) 168 | .catch((error) => { 169 | console.error(error); 170 | process.exit(1); 171 | }); 172 | -------------------------------------------------------------------------------- /scripts/check-balance.js: -------------------------------------------------------------------------------- 1 | async function main() { 2 | [this.gov] = await ethers.getSigners(); 3 | this.gov.address = await this.gov.getAddress(); 4 | 5 | console.log(this.gov.address); 6 | 7 | const b = await this.gov.getBalance(); 8 | console.log(b.toString()); 9 | } 10 | 11 | main() 12 | .then(() => process.exit(0)) 13 | .catch((error) => { 14 | console.error(error); 15 | process.exit(1); 16 | }); 17 | -------------------------------------------------------------------------------- /scripts/compbalance.js: -------------------------------------------------------------------------------- 1 | const { parseUnits, id } = require('ethers/lib/utils'); 2 | 3 | async function main() { 4 | const comp = await ethers.getContractAt( 5 | 'CompoundStrategy', 6 | '0x5b7a52b6d75fb3105c3c37fcc6007eb7ac78f1b8', 7 | ); 8 | 9 | const startblock = 15135844; 10 | 11 | // await network.provider.send('evm_setAutomine', [false]); 12 | // await network.provider.send('evm_setIntervalMining', [13325]); 13 | 14 | for (var i = 0; i < 1000; i += 5) { 15 | const t = await comp.balanceOf({ blockTag: startblock + i }); 16 | console.log('t' + i.toString() + ',' + t.toString()); 17 | await network.provider.send('evm_mine', []); 18 | } 19 | } 20 | 21 | main() 22 | .then(() => process.exit(0)) 23 | .catch((error) => { 24 | console.error(error); 25 | process.exit(1); 26 | }); 27 | -------------------------------------------------------------------------------- /scripts/goeri-usdc.js: -------------------------------------------------------------------------------- 1 | const { parseUnits, id } = require('ethers/lib/utils'); 2 | 3 | async function main() { 4 | this.Usdc = await ethers.getContractFactory('ERC20Mock6d'); 5 | USDC = await this.Usdc.deploy('USD Coin', 'USDC', parseUnits('100000000000', 6)); 6 | await USDC.deployed(); 7 | console.log('S - Deployed usdc @', USDC.address); 8 | } 9 | 10 | main() 11 | .then(() => process.exit(0)) 12 | .catch((error) => { 13 | console.error(error); 14 | process.exit(1); 15 | }); 16 | -------------------------------------------------------------------------------- /scripts/goerli_start.js: -------------------------------------------------------------------------------- 1 | const { parseUnits, id, parseEther } = require('ethers/lib/utils'); 2 | 3 | const SHER_MINTER = '0x92AEffFfaD9fff820f7FCaf1563d8467aFe358c4'; // timelock controller 4 | const SHER = '0x63E9aD95D09ae88614e0b0F462A3A96994c9b6CF'; 5 | const SHER_BUY = '0xf8583f22C2f6f8cd27f62879A0fB4319bce262a6'; 6 | 7 | async function main() { 8 | // get access to mint function 9 | const sher = await ethers.getContractAt('MockAave', SHER); 10 | 11 | await network.provider.request({ 12 | method: 'hardhat_impersonateAccount', 13 | params: [SHER_MINTER], 14 | }); 15 | await network.provider.request({ 16 | method: 'hardhat_setBalance', 17 | params: [SHER_MINTER, '0x100000000000000000000000000'], 18 | }); 19 | 20 | this.minter = await ethers.provider.getSigner(SHER_MINTER); 21 | 22 | await sher.connect(this.minter).mint(SHER_BUY, parseEther('10000000')); 23 | } 24 | 25 | main() 26 | .then(() => process.exit(0)) 27 | .catch((error) => { 28 | console.error(error); 29 | process.exit(1); 30 | }); 31 | -------------------------------------------------------------------------------- /scripts/set_balance.js: -------------------------------------------------------------------------------- 1 | const { parseEther } = require('ethers/lib/utils'); 2 | 3 | async function main() { 4 | [this.gov] = await ethers.getSigners(); 5 | this.gov.address = await this.gov.getAddress(); 6 | 7 | console.log(this.gov.address); 8 | 9 | // 50 ETH 10 | await network.provider.send('hardhat_setBalance', [this.gov.address, '0x2b5e3af16b1880000']); 11 | } 12 | 13 | main() 14 | .then(() => process.exit(0)) 15 | .catch((error) => { 16 | console.error(error); 17 | process.exit(1); 18 | }); 19 | -------------------------------------------------------------------------------- /scripts/set_hardhat.js: -------------------------------------------------------------------------------- 1 | const { parseEther } = require('ethers/lib/utils'); 2 | 3 | async function main() { 4 | await network.provider.send('evm_setAutomine', [false]); 5 | await network.provider.send('evm_setIntervalMining', [60000]); 6 | } 7 | 8 | main() 9 | .then(() => process.exit(0)) 10 | .catch((error) => { 11 | console.error(error); 12 | process.exit(1); 13 | }); 14 | -------------------------------------------------------------------------------- /scripts/test.js: -------------------------------------------------------------------------------- 1 | const { parseEther, id, keccak256, sha256, toUtf8Bytes } = require('ethers/lib/utils'); 2 | 3 | async function main() { 4 | const x = id('euler'); 5 | const xx = sha256(toUtf8Bytes('euler')); 6 | 7 | console.log(x); 8 | console.log(xx); 9 | } 10 | 11 | main() 12 | .then(() => process.exit(0)) 13 | .catch((error) => { 14 | console.error(error); 15 | process.exit(1); 16 | }); 17 | -------------------------------------------------------------------------------- /scripts/verify.js: -------------------------------------------------------------------------------- 1 | const hre = require('hardhat'); 2 | const { parseUnits } = require('ethers/lib/utils'); 3 | 4 | const WEEK = parseInt(60 * 60 * 24 * 7); 5 | 6 | async function main() { 7 | let MULTISIG = '0x666B8EbFbF4D5f0CE56962a25635CfF563F13161'; 8 | let EOA_ONE = '0xE400820f3D60d77a3EC8018d44366ed0d334f93C'; 9 | let EOA_TWO = '0x4cf5F3EcD6303F6a04480F75ac394D4bB3816F83'; 10 | 11 | if (network.name == 'goerli') { 12 | MULTISIG = '0x34EDB6fD102578De64CaEbe82f540fB3E47a05EA'; 13 | EOA_ONE = '0xE400820f3D60d77a3EC8018d44366ed0d334f93C'; 14 | EOA_TWO = '0x4cf5F3EcD6303F6a04480F75ac394D4bB3816F83'; 15 | } 16 | 17 | let USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; 18 | let aUSDC = '0xbcca60bb61934080951369a648fb03df4f96263c'; 19 | let SHER = '0x63E9aD95D09ae88614e0b0F462A3A96994c9b6CF'; 20 | 21 | if (network.name == 'goerli') { 22 | SHER = '0x63E9aD95D09ae88614e0b0F462A3A96994c9b6CF'; 23 | USDC = '0xfe193C63e15A54ac500f3038fce00193Ff141139'; 24 | } else if (network.name != 'mainnet') { 25 | throw Error('Invalid network'); 26 | } 27 | 28 | const UMAHO = '0x8fCC879036Fc8e45395AdE7D4eF739200037695c'; 29 | const SPCC = '0x4Fcf6AA323a92EB92a58025E821f393da6C41bD6'; 30 | const NON_STAKER = '0x666B8EbFbF4D5f0CE56962a25635CfF563F13161'; 31 | const NFT_NAME = 'Sherlock Staking Position NFT-V1'; 32 | const NFT_SYMBOL = 'SHER-POS'; 33 | const END_RAISE = '1647100800'; 34 | 35 | const STAKE_RATE = parseUnits('9', 6); 36 | const BUY_RATE = parseUnits('1', 6); 37 | const STAKING_PERIODS = [WEEK * 26, WEEK * 52]; 38 | 39 | const TimelockController = '0x92AEffFfaD9fff820f7FCaf1563d8467aFe358c4'; 40 | const Sherlock = '0x0865a889183039689034dA55c1Fd12aF5083eabF'; 41 | const AaveV2Strategy = '0xF02d3A6288D998B412ce749cfF244c8ef799f582'; 42 | const SherDistributionManager = '0x5775F32787656E77dd99f20F4E478DdC85fdB31b'; 43 | const SherlockProtocolManager = '0x3d0b8A0A10835Ab9b0f0BeB54C5400B8aAcaa1D3'; 44 | const SherlockClaimManager = '0xFeEDD254ae4B7c44A0472Bb836b813Ce4625Eb84'; 45 | const SherClaim = '0x7289C61C75dCdB8Fe4DF0b937c08c9c40902BDd3'; 46 | const SherBuy = '0xf8583f22C2f6f8cd27f62879A0fB4319bce262a6'; 47 | 48 | // verify sherlock 49 | await hre.run('verify:verify', { 50 | address: Sherlock, 51 | constructorArguments: [ 52 | USDC, 53 | SHER, 54 | NFT_NAME, 55 | NFT_SYMBOL, 56 | AaveV2Strategy, 57 | SherDistributionManager, 58 | NON_STAKER, 59 | SherlockProtocolManager, 60 | SherlockClaimManager, 61 | STAKING_PERIODS, 62 | ], 63 | }); 64 | 65 | await hre.run('verify:verify', { 66 | address: TimelockController, 67 | constructorArguments: [1, [MULTISIG], [MULTISIG, EOA_ONE, EOA_TWO]], 68 | }); 69 | 70 | await hre.run('verify:verify', { 71 | address: AaveV2Strategy, 72 | constructorArguments: [aUSDC, NON_STAKER], 73 | }); 74 | 75 | await hre.run('verify:verify', { 76 | address: SherDistributionManager, 77 | constructorArguments: [], 78 | }); 79 | 80 | await hre.run('verify:verify', { 81 | address: SherlockProtocolManager, 82 | constructorArguments: [USDC], 83 | }); 84 | 85 | await hre.run('verify:verify', { 86 | address: SherlockClaimManager, 87 | constructorArguments: [UMAHO, SPCC], 88 | }); 89 | 90 | await hre.run('verify:verify', { 91 | address: SherClaim, 92 | constructorArguments: [SHER, END_RAISE], 93 | }); 94 | 95 | await hre.run('verify:verify', { 96 | address: SherBuy, 97 | constructorArguments: [SHER, USDC, STAKE_RATE, BUY_RATE, Sherlock, NON_STAKER, SherClaim], 98 | }); 99 | } 100 | 101 | main() 102 | .then(() => process.exit(0)) 103 | .catch((error) => { 104 | console.error(error); 105 | process.exit(1); 106 | }); 107 | -------------------------------------------------------------------------------- /scripts/verify_2.js: -------------------------------------------------------------------------------- 1 | const hre = require('hardhat'); 2 | const { parseUnits } = require('ethers/lib/utils'); 3 | const { constants } = require('ethers'); 4 | 5 | const WEEK = parseInt(60 * 60 * 24 * 7); 6 | 7 | async function main() { 8 | const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; 9 | const CORE = '0x0865a889183039689034dA55c1Fd12aF5083eabF'; 10 | const aUSDC = '0xbcca60bb61934080951369a648fb03df4f96263c'; 11 | const MULTISIG = '0x666B8EbFbF4D5f0CE56962a25635CfF563F13161'; 12 | const TIMELOCK = '0x92AEffFfaD9fff820f7FCaf1563d8467aFe358c4'; 13 | 14 | const infoStorage = '0xbFa53D098d7063DdCc39a45ea6F8c290FcD7FC70'; 15 | const master = '0x1E8bE946370a99019E323998Acd37A1206bdD507'; 16 | const aave = '0x75C5d2d8D54254476239a5c1e1F23ec48Df8779E'; 17 | const splitter1 = '0x7E0049866879151480d9Ec01391Bbf713F7705b1'; 18 | const comp = '0x5b7a52b6d75Fb3105c3c37fcc6007Eb7ac78F1B8'; 19 | const splitter0 = '0x71B6BC6c70E27DCfD7d0b7AE8EbA6a76D518D88A'; 20 | const euler = '0xC124A8088c39625f125655152A168baA86b49026'; 21 | 22 | // verify sherlock 23 | // await hre.run('verify:verify', { 24 | // address: infoStorage, 25 | // constructorArguments: [USDC, CORE], 26 | // }); 27 | 28 | // await hre.run('verify:verify', { 29 | // address: master, 30 | // constructorArguments: [infoStorage], 31 | // }); 32 | 33 | // await hre.run('verify:verify', { 34 | // address: aave, 35 | // constructorArguments: [master, aUSDC, MULTISIG], 36 | // }); 37 | 38 | // await hre.run('verify:verify', { 39 | // address: splitter1, 40 | // constructorArguments: [master, constants.AddressZero, aave, parseUnits('500000', 6)], 41 | // }); 42 | 43 | // await hre.run('verify:verify', { 44 | // address: comp, 45 | // constructorArguments: [splitter1], 46 | // }); 47 | 48 | // await hre.run('verify:verify', { 49 | // address: splitter0, 50 | // constructorArguments: [ 51 | // master, 52 | // splitter1, 53 | // constants.AddressZero, 54 | // parseUnits('10000000', 6), // 10m USDC 55 | // constants.MaxUint256, 56 | // parseUnits('2000000', 6), // 2m USDC]], 57 | // ], 58 | // }); 59 | 60 | await hre.run('verify:verify', { 61 | address: euler, 62 | constructorArguments: [splitter0], 63 | }); 64 | } 65 | 66 | main() 67 | .then(() => process.exit(0)) 68 | .catch((error) => { 69 | console.error(error); 70 | process.exit(1); 71 | }); 72 | -------------------------------------------------------------------------------- /test/ERC721.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { parseEther, parseUnits } = require('ethers/lib/utils'); 3 | 4 | const { prepare, deploy, solution, timestamp, Uint16Max, meta } = require('./utilities'); 5 | const { constants, BigNumber } = require('ethers'); 6 | const { TimeTraveler } = require('./utilities/snapshot'); 7 | const { id } = require('ethers/lib/utils'); 8 | 9 | const maxTokens = parseUnits('100000000000', 6); 10 | const maxTokens2 = parseEther('100000000000', 18); 11 | 12 | const weeks1 = 60 * 60 * 24 * 7 * 1; 13 | const weeks2 = 60 * 60 * 24 * 7 * 2; 14 | const weeks12 = 60 * 60 * 24 * 7 * 12; 15 | const weeks26 = 60 * 60 * 24 * 7 * 26; 16 | 17 | describe('Sherlock ─ ERC721', function () { 18 | before(async function () { 19 | await prepare(this, [ 20 | 'StrategyMock', 21 | 'SherlockProtocolManagerMock', 22 | 'SherDistributionMock', 23 | 'ERC20Mock6d', 24 | 'ERC20Mock18d', 25 | 'Sherlock', 26 | ]); 27 | 28 | this.claimManager = this.carol; 29 | this.nonStaker = this.bob; 30 | 31 | await deploy(this, [['token', this.ERC20Mock6d, ['USDC Token', 'USDC', maxTokens]]]); 32 | await deploy(this, [['sher', this.ERC20Mock18d, ['SHER Token', 'SHER', maxTokens]]]); 33 | 34 | await deploy(this, [['strategy', this.StrategyMock, [this.token.address]]]); 35 | await deploy(this, [['strategy2', this.StrategyMock, [this.token.address]]]); 36 | await deploy(this, [['protmanager', this.SherlockProtocolManagerMock, [this.token.address]]]); 37 | await deploy(this, [['protmanager2', this.SherlockProtocolManagerMock, [this.token.address]]]); 38 | await deploy(this, [ 39 | ['sherdist', this.SherDistributionMock, [this.token.address, this.sher.address]], 40 | ]); 41 | await deploy(this, [ 42 | ['sherdist2', this.SherDistributionMock, [this.token.address, this.sher.address]], 43 | ]); 44 | 45 | await deploy(this, [ 46 | [ 47 | 'sherlock', 48 | this.Sherlock, 49 | [ 50 | this.token.address, 51 | this.sher.address, 52 | 'SHER POSITION', 53 | 'SPS', 54 | this.strategy.address, 55 | this.sherdist.address, 56 | this.nonStaker.address, 57 | this.protmanager.address, 58 | this.claimManager.address, 59 | [10, 20], 60 | ], 61 | ], 62 | ]); 63 | 64 | await this.token.approve(this.sherlock.address, maxTokens); 65 | }); 66 | 67 | describe('tokenURI', function () { 68 | before(async function () {}); 69 | it('Initial state', async function () { 70 | await expect(this.sherlock.tokenURI(1)).to.be.revertedWith( 71 | 'ERC721Metadata: URI query for nonexistent token', 72 | ); 73 | 74 | await expect(this.sherlock.tokenURI(2)).to.be.revertedWith( 75 | 'ERC721Metadata: URI query for nonexistent token', 76 | ); 77 | }); 78 | it('Do 1', async function () { 79 | await this.sherlock.initialStake(parseUnits('100', 6), 10, this.bob.address); 80 | 81 | expect(await this.sherlock.tokenURI(1)).to.be.eq('https://nft.sherlock.xyz/api/mainnet/1'); 82 | await expect(this.sherlock.tokenURI(2)).to.be.revertedWith( 83 | 'ERC721Metadata: URI query for nonexistent token', 84 | ); 85 | }); 86 | it('Do 2', async function () { 87 | await this.sherlock.initialStake(parseUnits('100', 6), 10, this.bob.address); 88 | 89 | expect(await this.sherlock.tokenURI(1)).to.be.eq('https://nft.sherlock.xyz/api/mainnet/1'); 90 | expect(await this.sherlock.tokenURI(2)).to.be.eq('https://nft.sherlock.xyz/api/mainnet/2'); 91 | }); 92 | }); 93 | }); 94 | -------------------------------------------------------------------------------- /test/Manager.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { parseEther, parseUnits, hexConcat } = require('ethers/lib/utils'); 3 | 4 | const { 5 | prepare, 6 | deploy, 7 | solution, 8 | timestamp, 9 | Uint16Max, 10 | meta, 11 | fork, 12 | unfork, 13 | } = require('./utilities'); 14 | const { constants, BigNumber } = require('ethers'); 15 | const { TimeTraveler } = require('./utilities/snapshot'); 16 | const { id, formatBytes32String, keccak256 } = require('ethers/lib/utils'); 17 | 18 | const RANDOM_ADDRESS = '0xD4Ae0DD720f1690AB506A22c6e7da6408c5e2313'; 19 | 20 | const maxTokens = parseUnits('100000000000', 6); 21 | describe('Manager', function () { 22 | before(async function () { 23 | timeTraveler = new TimeTraveler(network.provider); 24 | 25 | await prepare(this, ['ManagerTest', 'ERC20Mock6d', 'PayableFail']); 26 | 27 | await deploy(this, [['manager', this.ManagerTest, []]]); 28 | await deploy(this, [['payableFail', this.PayableFail, []]]); 29 | 30 | await deploy(this, [['token1', this.ERC20Mock6d, ['USDC Token', 'USDC', maxTokens]]]); 31 | await deploy(this, [['token2', this.ERC20Mock6d, ['USDC Token', 'USDC', maxTokens]]]); 32 | 33 | await timeTraveler.snapshot(); 34 | }); 35 | describe('Test set core', async function () { 36 | before(async function () { 37 | await timeTraveler.revertSnapshot(); 38 | }); 39 | it('Not setup', async function () { 40 | expect(await this.manager.viewSherlockCore()).to.eq(constants.AddressZero); 41 | await expect(this.manager.revertsIfNotCore()).to.be.revertedWith('InvalidSender()'); 42 | }); 43 | it('Set core fail', async function () { 44 | await expect(this.manager.setSherlockCoreAddress(constants.AddressZero)).to.be.revertedWith( 45 | 'ZeroArgument()', 46 | ); 47 | }); 48 | it('Set core', async function () { 49 | this.t1 = await meta(this.manager.setSherlockCoreAddress(this.alice.address)); 50 | 51 | expect(this.t1.events.length).to.eq(1); 52 | expect(this.t1.events[0].event).to.eq('SherlockCoreSet'); 53 | expect(this.t1.events[0].args.sherlock).to.eq(this.alice.address); 54 | }); 55 | it('Setup', async function () { 56 | expect(await this.manager.viewSherlockCore()).to.eq(this.alice.address); 57 | await this.manager.revertsIfNotCore(); 58 | await expect(this.manager.connect(this.bob).revertsIfNotCore()).to.be.revertedWith( 59 | 'InvalidSender()', 60 | ); 61 | }); 62 | it('Set core again', async function () { 63 | await expect(this.manager.setSherlockCoreAddress(this.alice.address)).to.be.revertedWith( 64 | 'InvalidConditions()', 65 | ); 66 | }); 67 | }); 68 | describe('Test sweep', async function () { 69 | before(async function () { 70 | await timeTraveler.revertSnapshot(); 71 | 72 | this.amount = parseEther('1'); 73 | await network.provider.send('hardhat_setBalance', [ 74 | this.manager.address, 75 | '0xDE0B6B3A7640000', 76 | ]); 77 | await this.token1.transfer(this.manager.address, maxTokens); 78 | await this.token2.transfer(this.manager.address, maxTokens); 79 | }); 80 | it('Initial state', async function () { 81 | expect(await this.token1.balanceOf(RANDOM_ADDRESS)).to.eq(0); 82 | expect(await this.token2.balanceOf(RANDOM_ADDRESS)).to.eq(0); 83 | expect(await ethers.provider.getBalance(RANDOM_ADDRESS)).to.eq(0); 84 | }); 85 | it('Do', async function () { 86 | await this.manager.sweep(RANDOM_ADDRESS, [this.token1.address]); 87 | }); 88 | it('Verify state', async function () { 89 | expect(await this.token1.balanceOf(RANDOM_ADDRESS)).to.eq(maxTokens); 90 | expect(await this.token2.balanceOf(RANDOM_ADDRESS)).to.eq(0); 91 | expect(await ethers.provider.getBalance(RANDOM_ADDRESS)).to.eq(this.amount); 92 | }); 93 | it('Do again', async function () { 94 | await this.manager.sweep(RANDOM_ADDRESS, [this.token2.address]); 95 | }); 96 | it('Verify state', async function () { 97 | expect(await this.token1.balanceOf(RANDOM_ADDRESS)).to.eq(maxTokens); 98 | expect(await this.token2.balanceOf(RANDOM_ADDRESS)).to.eq(maxTokens); 99 | expect(await ethers.provider.getBalance(RANDOM_ADDRESS)).to.eq(this.amount); 100 | }); 101 | it('Do fail', async function () { 102 | await expect(this.manager.sweep(this.payableFail.address, [])).to.be.revertedWith( 103 | 'InvalidConditions()', 104 | ); 105 | }); 106 | }); 107 | }); 108 | -------------------------------------------------------------------------------- /test/strategy/mainnet.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { parseEther, parseUnits, hexConcat } = require('ethers/lib/utils'); 3 | 4 | const { 5 | prepare, 6 | deploy, 7 | solution, 8 | timestamp, 9 | Uint16Max, 10 | meta, 11 | fork, 12 | unfork, 13 | } = require('../utilities'); 14 | const { constants, BigNumber } = require('ethers'); 15 | const { TimeTraveler } = require('../utilities/snapshot'); 16 | const { id, formatBytes32String, keccak256 } = require('ethers/lib/utils'); 17 | 18 | // steps to run 19 | // npx hardhat node --fork mainnet --fork-block-number 15056000 20 | // npx hardhat run --network local scripts/6_strat.deploy.js 21 | // npx hardhat --network local test 22 | const masterStrategy = '0xee4b70AE96fFC70563f70964ebDD8635033Bc6b4'; 23 | const aave = '0xE3C37e951F1404b162DFA71A13F0c99c9798Db82'; 24 | const comp = '0x8AEA96da625791103a29a16C06c5cfC8B25f6832'; 25 | const euler = '0x9a902e8Aae5f1aB423c7aFB29C0Af50e0d3Fea7e'; 26 | 27 | // Mainnet addresses 28 | const sherlock = '0x0865a889183039689034dA55c1Fd12aF5083eabF'; 29 | const ownerAddress = '0x92AEffFfaD9fff820f7FCaf1563d8467aFe358c4'; 30 | const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; 31 | 32 | const MILLIE = parseUnits('1000000', 6); 33 | 34 | // make .only() when running against mainnet fork 35 | describe.skip('Deployment strategy test', function () { 36 | before(async function () { 37 | this.core = this.carol; 38 | this.usdc = await ethers.getContractAt('ERC20', USDC); 39 | this.strategy = await ethers.getContractAt('MasterStrategy', masterStrategy); 40 | this.sherlock = await ethers.getContractAt('Sherlock', sherlock); 41 | this.aave = await ethers.getContractAt('BaseStrategy', aave); 42 | this.comp = await ethers.getContractAt('BaseStrategy', comp); 43 | this.euler = await ethers.getContractAt('BaseStrategy', euler); 44 | 45 | this.mintUSDC = async (target, amount) => { 46 | const usdcWhale = await ethers.provider.getSigner(usdcWhaleAddress); 47 | await this.usdc.connect(usdcWhale).transfer(target, amount); 48 | }; 49 | 50 | await network.provider.request({ 51 | method: 'hardhat_setBalance', 52 | params: [ownerAddress, '0x100000000000000000000000000'], 53 | }); 54 | await timeTraveler.request({ 55 | method: 'hardhat_impersonateAccount', 56 | params: [ownerAddress], 57 | }); 58 | owner = await ethers.provider.getSigner(ownerAddress); 59 | }); 60 | it('Update', async function () { 61 | expect(await this.sherlock.totalTokenBalanceStakers()).to.be.closeTo( 62 | parseUnits('20224000', 6), // 20.24m 63 | parseUnits('10000', 6), 64 | ); 65 | expect(await this.usdc.balanceOf(this.sherlock.address)).to.be.closeTo( 66 | parseUnits('59000', 6), // 59k 67 | parseUnits('5000', 6), 68 | ); 69 | 70 | await this.sherlock.connect(owner).updateYieldStrategy(this.strategy.address); 71 | 72 | expect(await this.sherlock.totalTokenBalanceStakers()).to.be.closeTo( 73 | parseUnits('20224000', 6), // 20.24m 74 | parseUnits('10000', 6), 75 | ); 76 | // All usdc withdrawn 77 | expect(await this.usdc.balanceOf(this.sherlock.address)).to.be.closeTo( 78 | parseUnits('20134000', 6), // 20.13m - premiums 79 | parseUnits('10000', 6), 80 | ); 81 | }); 82 | it('Deposit', async function () { 83 | // deposit 20 million USDC 84 | await this.sherlock.connect(owner).yieldStrategyDeposit(MILLIE.mul(20)); 85 | 86 | expect(await this.sherlock.totalTokenBalanceStakers()).to.be.closeTo( 87 | parseUnits('20224000', 6), 88 | parseUnits('10000', 6), 89 | ); 90 | expect(await this.usdc.balanceOf(this.sherlock.address)).to.be.closeTo( 91 | parseUnits('225000', 6), // 225k (it claimPremiumsForStakers) 92 | parseUnits('10000', 6), 93 | ); 94 | }); 95 | it('Verify balances', async function () { 96 | expect(await this.aave.balanceOf()).to.be.closeTo( 97 | parseUnits('9000000', 6), // 9m 98 | parseUnits('10000', 6), 99 | ); 100 | 101 | expect(await this.comp.balanceOf()).to.be.closeTo( 102 | parseUnits('9000000', 6), // 9m 103 | parseUnits('10000', 6), 104 | ); 105 | 106 | expect(await this.euler.balanceOf()).to.be.closeTo( 107 | parseUnits('2000000', 6), // 2m 108 | parseUnits('10000', 6), 109 | ); 110 | }); 111 | }); 112 | -------------------------------------------------------------------------------- /test/utilities/index.js: -------------------------------------------------------------------------------- 1 | const { utils } = require('ethers/lib'); 2 | const { BigNumber } = require('ethers'); 3 | 4 | module.exports = { 5 | prepare: async (thisObject, contracts) => { 6 | for (let i in contracts) { 7 | let contract = contracts[i]; 8 | thisObject[contract] = await ethers.getContractFactory(contract); 9 | } 10 | thisObject.signers = await ethers.getSigners(); 11 | 12 | thisObject.alice = thisObject.signers[0]; 13 | thisObject.bob = thisObject.signers[1]; 14 | thisObject.carol = thisObject.signers[2]; 15 | thisObject.gov = thisObject.signers[3]; 16 | 17 | thisObject.alice.address = await thisObject.signers[0].getAddress(); 18 | thisObject.bob.address = await thisObject.signers[1].getAddress(); 19 | thisObject.carol.address = await thisObject.signers[2].getAddress(); 20 | thisObject.gov.address = await thisObject.signers[3].getAddress(); 21 | 22 | thisObject.alice.key = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'; 23 | thisObject.bob.key = '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d'; 24 | thisObject.carol.key = '0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a'; 25 | thisObject.gov.key = '0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6'; 26 | 27 | thisObject.protocolX = '0x561ca898cce9f021c15a441ef41899706e923541cee724530075d1a1144761c7'; 28 | thisObject.protocolY = '0x561ca898cce9f021c15a441ef41899706e923541cee724530075d1a1144761c8'; 29 | thisObject.protocolZ = '0x561ca898cce9f021c15a441ef41899706e923541cee724530075d1a1144761c9'; 30 | 31 | thisObject.nonProtocol1 = '0x561ca898cce9f021c15a441ef41899706e923541cee724530075d1a1144761c1'; 32 | thisObject.nonProtocol2 = '0x561ca898cce9f021c15a441ef41899706e923541cee724530075d1a1144761c2'; 33 | }, 34 | deploy: async (thisObject, contracts) => { 35 | for (let i in contracts) { 36 | let contract = contracts[i]; 37 | thisObject[contract[0]] = await contract[1].deploy(...(contract[2] || [])); 38 | try { 39 | const decimals = await thisObject[contract[0]].decimals(); 40 | thisObject[contract[0]].dec = decimals; 41 | thisObject[contract[0]].usdDec = 18 + (18 - decimals); 42 | } catch (err) {} 43 | await thisObject[contract[0]].deployed(); 44 | } 45 | }, 46 | blockNumber: async (tx) => { 47 | return BigNumber.from(await (await tx).blockNumber); 48 | }, 49 | meta: async (tx) => { 50 | data = await tx; 51 | const block = data.blockNumber; 52 | 53 | data = await data.wait(); 54 | const events = data.events; 55 | 56 | data = await ethers.provider.getBlock(block); 57 | return { 58 | time: BigNumber.from(data.timestamp), 59 | block: BigNumber.from(block), 60 | events: events, 61 | }; 62 | }, 63 | events: async (tx) => { 64 | return (await (await tx).wait()).events; 65 | }, 66 | Uint16Fragment: function (fragment) { 67 | const f = BigNumber.from(fragment * 10000); 68 | return BigNumber.from(2 ** 16 - 1) 69 | .mul(f) 70 | .div(10000); 71 | }, 72 | Uint16Max: BigNumber.from(2 ** 16 - 1), 73 | Uint32Max: BigNumber.from(2 ** 32 - 1), 74 | }; 75 | -------------------------------------------------------------------------------- /test/utilities/snapshot.js: -------------------------------------------------------------------------------- 1 | class TimeTraveler { 2 | constructor(ethereum) { 3 | this.ethereum = ethereum; 4 | } 5 | 6 | async snapshot() { 7 | const snapshot = await this.ethereum.send('evm_snapshot', []); 8 | await this.mine(1); 9 | this.snapshotID = snapshot; 10 | return; 11 | } 12 | 13 | async revertSnapshot() { 14 | await this.ethereum.send('evm_revert', [this.snapshotID]); 15 | //await this.mine(1); 16 | await this.snapshot(); 17 | return; 18 | } 19 | 20 | async mine(amount) { 21 | for (let i = 0; i < amount; i++) { 22 | await this.ethereum.send('evm_mine', []); 23 | } 24 | } 25 | 26 | async hardhatMine(amount) { 27 | await this.ethereum.send('hardhat_mine', [`0x${amount.toString(16)}`]) 28 | } 29 | 30 | async increaseTime(amount) { 31 | await this.ethereum.send('evm_increaseTime', [amount]); 32 | } 33 | 34 | async setNextBlockTimestamp(timestamp) { 35 | await this.ethereum.send('evm_setNextBlockTimestamp', [timestamp]); 36 | } 37 | 38 | async request(request) { 39 | await this.ethereum.request(request); 40 | } 41 | 42 | async fork(block) { 43 | await this.ethereum.send('hardhat_reset', [ 44 | { 45 | forking: { 46 | jsonRpcUrl: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY_MAINNET}`, 47 | blockNumber: block, 48 | }, 49 | }, 50 | ]); 51 | } 52 | 53 | async unfork() { 54 | await this.ethereum.send('hardhat_reset', []); 55 | } 56 | } 57 | 58 | module.exports.TimeTraveler = TimeTraveler; 59 | --------------------------------------------------------------------------------