├── .codecov.yml ├── .env_example ├── .github └── workflows │ └── test.yml ├── .gitignore ├── .mocharc.json ├── .solcover.js ├── .solhint.json ├── .solhintignore ├── LICENSE ├── README.md ├── codechecks.yml ├── contracts ├── TetuBridgedProcessing.sol ├── TetuTokenMainnet.sol ├── infrastructure │ ├── ControllerV2.sol │ ├── ForwarderV3.sol │ ├── ForwarderV4.sol │ ├── InvestFundV2.sol │ └── PlatformVoter.sol ├── interfaces │ ├── IBVault.sol │ ├── IBribe.sol │ ├── IControllable.sol │ ├── IController.sol │ ├── IERC165.sol │ ├── IERC20.sol │ ├── IERC20Metadata.sol │ ├── IERC20Permit.sol │ ├── IERC4626.sol │ ├── IERC721.sol │ ├── IERC721Metadata.sol │ ├── IERC721Receiver.sol │ ├── IForwarder.sol │ ├── IGauge.sol │ ├── IMultiPool.sol │ ├── IPlatformVoter.sol │ ├── IPriceOracle.sol │ ├── IProxyControlled.sol │ ├── ISmartVault.sol │ ├── ISplitter.sol │ ├── IStrategyStrict.sol │ ├── IStrategyV2.sol │ ├── IStrategyV3.sol │ ├── ITetuLiquidator.sol │ ├── ITetuVaultV2.sol │ ├── IVaultInsurance.sol │ ├── IVeDistributor.sol │ ├── IVeDistributorV2.sol │ ├── IVeTetu.sol │ ├── IVeVotable.sol │ └── IVoter.sol ├── lib │ ├── Base64.sol │ ├── InterfaceIds.sol │ ├── SlotsLib.sol │ └── StringLib.sol ├── openzeppelin │ ├── Address.sol │ ├── Clones.sol │ ├── Context.sol │ ├── ContextUpgradeable.sol │ ├── Counters.sol │ ├── CountersUpgradeable.sol │ ├── ECDSA.sol │ ├── ECDSAUpgradeable.sol │ ├── EIP712.sol │ ├── EIP712Upgradeable.sol │ ├── ERC165.sol │ ├── ERC20.sol │ ├── ERC20Permit.sol │ ├── ERC20PermitUpgradeable.sol │ ├── ERC20Upgradeable.sol │ ├── EnumerableMap.sol │ ├── EnumerableSet.sol │ ├── Initializable.sol │ ├── Math.sol │ ├── Proxy.sol │ ├── ReentrancyGuard.sol │ ├── SafeERC20.sol │ └── Strings.sol ├── proxy │ ├── ControllableV3.sol │ ├── ProxyControlled.sol │ └── UpgradeableProxy.sol ├── reward │ ├── MultiBribe.sol │ ├── MultiGauge.sol │ ├── MultiGaugeNoBoost.sol │ └── StakelessMultiPoolBase.sol ├── strategy │ ├── StrategyBaseV2.sol │ ├── StrategyBaseV3.sol │ ├── StrategyLib.sol │ ├── StrategyLib2.sol │ └── StrategyStrictBase.sol ├── test │ ├── Base64Test.sol │ ├── ControllableTest.sol │ ├── ControllerMinimal.sol │ ├── IControllerV1.sol │ ├── IMockToken.sol │ ├── MockBribe.sol │ ├── MockForwarder.sol │ ├── MockGauge.sol │ ├── MockLiquidator.sol │ ├── MockPawnshop.sol │ ├── MockPool.sol │ ├── MockSplitter.sol │ ├── MockStakingToken.sol │ ├── MockStrategy.sol │ ├── MockStrategySimple.sol │ ├── MockStrategyStrict.sol │ ├── MockStrategyV3.sol │ ├── MockToken.sol │ ├── MockVault.sol │ ├── MockVaultSimple.sol │ ├── MockVeDist.sol │ ├── MockVoter.sol │ ├── Multicall.sol │ ├── SlotsTest.sol │ ├── StakelessMultiPoolMock.sol │ ├── StrategyV2BaseEmpty.sol │ ├── StrategyV3BaseEmpty.sol │ ├── StringLibFacade.sol │ ├── TetuERC165Test.sol │ └── WrongNFTReceiver.sol ├── tools │ ├── ArbitragePoolSolidly.sol │ ├── ArbitrageVaultSolidly.sol │ ├── ArbitrageVaultUni3._sol │ ├── BribeDistribution.sol │ ├── DepositHelperAbstract.sol │ ├── DepositHelperBaseChain.sol │ ├── DepositHelperPolygon.sol │ ├── DepositHelperSimplified.sol │ ├── ForwarderDistributeResolver.sol │ ├── HardWorkResolver.sol │ ├── ISolidlyPair.sol │ ├── PerfFeeTreasury.sol │ ├── RewardsRedirector.sol │ ├── SplitterRebalanceResolver.sol │ └── TetuERC165.sol ├── vault │ ├── ERC4626.sol │ ├── ERC4626Strict.sol │ ├── ERC4626Upgradeable.sol │ ├── StrategySplitterV2.sol │ ├── TetuVaultV2.sol │ ├── VaultFactory.sol │ └── VaultInsurance.sol └── ve │ ├── TetuEmitter.sol │ ├── TetuVoter.sol │ ├── TetuVoterSimplified.sol │ ├── VeDistributor.sol │ ├── VeDistributorV2.sol │ ├── VeTetu.sol │ └── VeTetuLib.sol ├── hardhat.config.ts ├── log_settings.ts ├── package-lock.json ├── package.json ├── scripts ├── addresses │ ├── addresses.ts │ ├── base.ts │ ├── goerli.ts │ ├── polygon.ts │ ├── sepolia.ts │ └── zkevm.ts ├── deploy │ ├── DeployAllProd.ts │ ├── DeployAllProdSimplified.ts │ ├── DeployAllTestnet.ts │ ├── DeployBribeDistribution.ts │ ├── DeployContract.ts │ ├── DeployDepositHelperBaseChain.ts │ ├── DeployDepositHelperPolygon.ts │ ├── DeployForwarderResolver.ts │ ├── DeployHardworkResolver.ts │ ├── DeployInvestFund.ts │ ├── DeployMockStrategy.ts │ ├── DeployMockToken.ts │ ├── DeployPerfFeeTreasury.ts │ ├── DeployRewardsRedirector.ts │ ├── DeploySplitterRebalanceResolver.ts │ ├── DeployTetuBridgedProcessing.ts │ ├── DeployVault.ts │ └── DeployVaultFactory.ts ├── gov │ ├── execute-upgrades.ts │ ├── poke-gauge-voter.ts │ ├── poke-platform-voter.ts │ └── simulate-remove-all-platform-votes.ts ├── models │ ├── CoreAddresses.ts │ └── ToolsAddresses.ts ├── test │ ├── CreateMockPair.ts │ └── MakeNoizeOnTestnet.ts └── utils │ ├── DeployerUtils.ts │ ├── Misc.ts │ ├── RunHelper.ts │ ├── UpdateBlock.ts │ ├── VerifyUtils.ts │ └── Web3Utils.ts ├── slither.config.json ├── slither.db.json ├── test ├── TestAsserts.ts ├── TetuBridgedProcessingTest.ts ├── TimeUtils.ts ├── TokenUtils.ts ├── infrastructure │ ├── ControllerV2Test.ts │ ├── ForwarderTest.ts │ ├── InvestFundV2Test.ts │ └── PlatformVoterTest.ts ├── lib │ ├── Base64Test.ts │ ├── SlotsTest.ts │ └── StringLibTest.ts ├── proxy │ ├── ControllableTest.ts │ └── ProxyTest.ts ├── reward │ ├── MultiBribeTest.ts │ ├── MultiGaugeTest.ts │ └── MultiPoolTest.ts ├── test-utils.ts ├── tools │ ├── ArbitragePoolSolidlyTest.ts │ ├── ArbitrageVaultSolidlyTest.ts │ ├── BribeDistributorTest.ts │ ├── DepositHelperTests.ts │ ├── DepositHelperTestsBase.ts │ ├── DepositHelperTestsPolygon.ts │ ├── DepositHelperTestsSimplified.ts │ ├── HardWorkResolverTest.ts │ ├── PerfFeeTreasuryTest.ts │ ├── RewardsRedirectorTest.ts │ ├── SplitterRebalanceResolverTest.ts │ └── TetuERC165Test.ts ├── vault │ ├── BaseVaultTests.ts │ ├── CheckWithdrawImpactTest.ts │ ├── ERC4626StrictTests.ts │ ├── SplitterForBaseStrategyV3Tests.ts │ ├── SplitterTests.ts │ ├── StrategyBaseV2Tests.ts │ ├── StrategyBaseV3Tests.ts │ ├── TetuVaultV2Tests.ts │ ├── VaultFactoryPolygonTests.ts │ └── VaultFactoryTests.ts └── ve │ ├── TetuEmitterTest.ts │ ├── TetuVoterSimplifiedTest.ts │ ├── TetuVoterTest.ts │ ├── VeDistributorTest.ts │ ├── VeDistributorV2Test.ts │ ├── VeDistributorWithAlwaysMaxLockTest.ts │ ├── VeTetuIntegrationTestPolygon.ts │ └── VeTetuTest.ts ├── tetu_contracts.svg ├── tsconfig.json ├── tslint.json └── veTETU.svg /.codecov.yml: -------------------------------------------------------------------------------- 1 | comment: 2 | layout: "reach,diff,flags,files,footer" 3 | behavior: default 4 | require_changes: false 5 | github_checks: 6 | comment: true 7 | annotations: true 8 | coverage: 9 | status: 10 | patch: 11 | default: 12 | target: 100% 13 | ignore: 14 | - "contracts/test" 15 | - "contracts/integrations" 16 | - "contracts/openzeppelin" 17 | - "contracts/tools" 18 | -------------------------------------------------------------------------------- /.env_example: -------------------------------------------------------------------------------- 1 | TETU_MATIC_RPC_URL=https://polygon-mainnet.g.alchemy.com/v2/key 2 | TETU_FTM_RPC_URL=rpc_url 3 | 4 | ___not_necessary_if_you_dont_want_to_deploy___ 5 | 6 | TETU_PRIVATE_KEY=deployer_key 7 | 8 | TETU_NETWORK_SCAN_KEY=key 9 | TETU_NETWORK_SCAN_KEY_MATIC= 10 | TETU_NETWORK_SCAN_KEY_FTM= 11 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Unit tests + coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - release-* 8 | pull_request: { } 9 | workflow_dispatch: { } 10 | 11 | jobs: 12 | 13 | coverage: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | with: 18 | fetch-depth: 2 19 | - uses: actions/setup-node@v2 20 | with: 21 | node-version: 18.x 22 | - uses: actions/cache@v2 23 | id: cache 24 | with: 25 | path: '**/node_modules' 26 | key: npm-v2-${{ hashFiles('**/package-lock.json') }} 27 | restore-keys: npm-v2- 28 | - run: npm ci 29 | if: steps.cache.outputs.cache-hit != 'true' 30 | - run: npm run coverage 31 | env: 32 | NODE_OPTIONS: --max_old_space_size=4096 33 | - uses: codecov/codecov-action@v2 34 | with: 35 | token: ${{secrets.CODECOV_TOKEN}} 36 | fail_ci_if_error: true 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | deployments 8 | typechain 9 | coverage 10 | coverage.json 11 | dist 12 | 13 | .idea 14 | .hardhat 15 | secrets.ts 16 | .openzeppelin 17 | .tenderly 18 | arguments-*.js 19 | sh 20 | tmp 21 | settings.ts 22 | token_addresses.txt 23 | core_addresses.txt 24 | tool_addresses.txt 25 | .env 26 | docs 27 | abi 28 | -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": "ts-node/register/files", 3 | "timeout": 9999999999999 4 | } 5 | -------------------------------------------------------------------------------- /.solcover.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | skipFiles: ['test', 'integrations', 'openzeppelin', 'tools'] 3 | }; 4 | -------------------------------------------------------------------------------- /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:recommended", 3 | "plugins": [], 4 | "rules": { 5 | "compiler-version": [ 6 | "error", 7 | "^0.8.4" 8 | ], 9 | "func-visibility": [ 10 | "off", 11 | { 12 | "ignoreConstructors": true 13 | } 14 | ], 15 | "avoid-tx-origin": "off", 16 | "not-rely-on-time": "off", 17 | "no-empty-blocks": "off", 18 | "no-inline-assembly": "off", 19 | "avoid-low-level-calls": "off", 20 | "avoid-suicide": "error", 21 | "code-complexity": [ 22 | "warn", 23 | 20 24 | ], 25 | "function-max-lines": [ 26 | "warn", 27 | 150 28 | ], 29 | "max-line-length": [ 30 | "error", 31 | 120 32 | ], 33 | "constructor-syntax": "warn", 34 | "avoid-sha3": "warn", 35 | "indent": "off", 36 | "bracket-align": "off", 37 | "expression-indent": "off", 38 | "mark-callable-contracts": "off", 39 | "comprehensive-interface": "warn" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.solhintignore: -------------------------------------------------------------------------------- 1 | contracts/test 2 | contracts/integrations 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tetu.io 2 | [![codecov](https://codecov.io/gh/tetu-io/tetu-contracts-v2/branch/master/graph/badge.svg?token=6hsHxPxtGc)](https://codecov.io/gh/tetu-io/tetu-contracts-v2) 3 | 4 | ## Links 5 | 6 | Web: https://tetu.io/ 7 | 8 | Docs: https://docs.tetu.io/ 9 | 10 | Discord: https://discord.gg/DSUKVEYuax 11 | 12 | Twitter: https://twitter.com/tetu_io 13 | 14 | 15 | TETU mainnet https://etherscan.io/address/0x0F72964Fa4b766521d84107991E837c30D0EF2b1#code 16 | -------------------------------------------------------------------------------- /codechecks.yml: -------------------------------------------------------------------------------- 1 | checks: 2 | - name: eth-gas-reporter/codechecks 3 | -------------------------------------------------------------------------------- /contracts/TetuBridgedProcessing.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "./interfaces/IERC20.sol"; 6 | 7 | /// @title Contract for handling TETU from mainnet bridged via Polygon native bridge. 8 | /// @author belbix 9 | contract TetuBridgedProcessing { 10 | 11 | //////////// EVENTS /////////////// 12 | 13 | event OfferAdmin(address newAdmin); 14 | event AcceptAdmin(address newAdmin); 15 | event PauseOn(); 16 | event PauseOff(); 17 | event BridgeTetu(address user, uint amount); 18 | event ClaimTetu(address user, uint amount); 19 | 20 | //////////// VARIABLES /////////////// 21 | 22 | IERC20 public immutable tetu; 23 | IERC20 public immutable tetuBridged; 24 | address public admin; 25 | address public pendingAdmin; 26 | bool public paused; 27 | 28 | constructor(address _tetu, address _tetuBridged, address _admin) { 29 | tetu = IERC20(_tetu); 30 | tetuBridged = IERC20(_tetuBridged); 31 | admin = _admin; 32 | } 33 | 34 | //////////// ADMIN ACTIONS /////////////// 35 | 36 | function offerAdmin(address adr) external { 37 | require(msg.sender == admin, "!admin"); 38 | pendingAdmin = adr; 39 | emit OfferAdmin(adr); 40 | } 41 | 42 | function acceptAdmin() external { 43 | require(msg.sender == pendingAdmin, "!admin"); 44 | admin = msg.sender; 45 | pendingAdmin = address(0); 46 | emit AcceptAdmin(msg.sender); 47 | } 48 | 49 | function pauseOn() external { 50 | require(msg.sender == admin, "!admin"); 51 | paused = true; 52 | emit PauseOn(); 53 | } 54 | 55 | function pauseOff() external { 56 | require(msg.sender == admin, "!admin"); 57 | paused = false; 58 | emit PauseOff(); 59 | } 60 | 61 | //////////// MAIN ACTIONS /////////////// 62 | 63 | function bridgeTetuToMainnet(uint amount) external { 64 | require(!paused, "paused"); 65 | tetu.transferFrom(msg.sender, address(this), amount); 66 | tetuBridged.transfer(msg.sender, amount); 67 | emit BridgeTetu(msg.sender, amount); 68 | } 69 | 70 | function claimBridgedTetu(uint amount) external { 71 | require(!paused, "paused"); 72 | tetuBridged.transferFrom(msg.sender, address(this), amount); 73 | tetu.transfer(msg.sender, amount); 74 | emit ClaimTetu(msg.sender, amount); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /contracts/TetuTokenMainnet.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "./openzeppelin/ERC20Permit.sol"; 6 | 7 | contract TetuTokenMainnet is ERC20Permit { 8 | 9 | constructor() ERC20("Tetu Token", "TETU") ERC20Permit("Tetu Token") { 10 | // premint max possible supply for using them in a bridging process 11 | _mint(msg.sender, 1_000_000_000e18); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /contracts/interfaces/IBribe.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface IBribe { 6 | 7 | function epoch() external view returns (uint); 8 | 9 | function getReward( 10 | address vault, 11 | uint veId, 12 | address[] memory tokens 13 | ) external; 14 | 15 | function getAllRewards( 16 | address vault, 17 | uint veId 18 | ) external; 19 | 20 | function getAllRewardsForTokens( 21 | address[] memory vaults, 22 | uint veId 23 | ) external; 24 | 25 | function deposit(address vault, uint amount, uint tokenId) external; 26 | 27 | function withdraw(address vault, uint amount, uint tokenId) external; 28 | 29 | function notifyRewardAmount(address vault, address token, uint amount) external; 30 | 31 | function notifyForNextEpoch(address vault, address token, uint amount) external; 32 | 33 | function notifyDelayedRewards(address vault, address token, uint _epoch) external; 34 | 35 | function increaseEpoch() external; 36 | 37 | function rewardsQueue(address vault, address rt, uint epoch) external view returns (uint); 38 | } 39 | -------------------------------------------------------------------------------- /contracts/interfaces/IControllable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface IControllable { 6 | 7 | function isController(address _contract) external view returns (bool); 8 | 9 | function isGovernance(address _contract) external view returns (bool); 10 | 11 | function created() external view returns (uint256); 12 | 13 | function createdBlock() external view returns (uint256); 14 | 15 | function controller() external view returns (address); 16 | 17 | function increaseRevision(address oldLogic) external; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /contracts/interfaces/IController.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface IController { 6 | 7 | // --- DEPENDENCY ADDRESSES 8 | function governance() external view returns (address); 9 | 10 | function voter() external view returns (address); 11 | 12 | function liquidator() external view returns (address); 13 | 14 | function forwarder() external view returns (address); 15 | 16 | function investFund() external view returns (address); 17 | 18 | // deprecated 19 | // function veDistributor() external view returns (address); 20 | 21 | function platformVoter() external view returns (address); 22 | 23 | // --- VAULTS 24 | 25 | function vaults(uint id) external view returns (address); 26 | 27 | function vaultsList() external view returns (address[] memory); 28 | 29 | function vaultsListLength() external view returns (uint); 30 | 31 | function isValidVault(address _vault) external view returns (bool); 32 | 33 | // --- restrictions 34 | 35 | function isOperator(address _adr) external view returns (bool); 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC165.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | /** 6 | * @dev Interface of the ERC165 standard, as defined in the 7 | * https://eips.ethereum.org/EIPS/eip-165[EIP]. 8 | * 9 | * Implementers can declare support of contract interfaces, which can then be 10 | * queried by others ({ERC165Checker}). 11 | * 12 | * For an implementation, see {ERC165}. 13 | */ 14 | interface IERC165 { 15 | /** 16 | * @dev Returns true if this contract implements the interface defined by 17 | * `interfaceId`. See the corresponding 18 | * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] 19 | * to learn more about how these ids are created. 20 | * 21 | * This function call must use less than 30 000 gas. 22 | */ 23 | function supportsInterface(bytes4 interfaceId) external view returns (bool); 24 | } 25 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | /** 6 | * @dev Interface of the ERC20 standard as defined in the EIP. 7 | */ 8 | interface IERC20 { 9 | /** 10 | * @dev Returns the amount of tokens in existence. 11 | */ 12 | function totalSupply() external view returns (uint); 13 | 14 | /** 15 | * @dev Returns the amount of tokens owned by `account`. 16 | */ 17 | function balanceOf(address account) external view returns (uint); 18 | 19 | /** 20 | * @dev Moves `amount` tokens from the caller's account to `recipient`. 21 | * 22 | * Returns a boolean value indicating whether the operation succeeded. 23 | * 24 | * Emits a {Transfer} event. 25 | */ 26 | function transfer(address recipient, uint amount) external returns (bool); 27 | 28 | /** 29 | * @dev Returns the remaining number of tokens that `spender` will be 30 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 31 | * zero by default. 32 | * 33 | * This value changes when {approve} or {transferFrom} are called. 34 | */ 35 | function allowance(address owner, address spender) external view returns (uint); 36 | 37 | /** 38 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 39 | * 40 | * Returns a boolean value indicating whether the operation succeeded. 41 | * 42 | * IMPORTANT: Beware that changing an allowance with this method brings the risk 43 | * that someone may use both the old and the new allowance by unfortunate 44 | * transaction ordering. One possible solution to mitigate this race 45 | * condition is to first reduce the spender's allowance to 0 and set the 46 | * desired value afterwards: 47 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 48 | * 49 | * Emits an {Approval} event. 50 | */ 51 | function approve(address spender, uint amount) external returns (bool); 52 | 53 | /** 54 | * @dev Moves `amount` tokens from `sender` to `recipient` using the 55 | * allowance mechanism. `amount` is then deducted from the caller's 56 | * allowance. 57 | * 58 | * Returns a boolean value indicating whether the operation succeeded. 59 | * 60 | * Emits a {Transfer} event. 61 | */ 62 | function transferFrom( 63 | address sender, 64 | address recipient, 65 | uint amount 66 | ) external returns (bool); 67 | 68 | /** 69 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 70 | * another (`to`). 71 | * 72 | * Note that `value` may be zero. 73 | */ 74 | event Transfer(address indexed from, address indexed to, uint value); 75 | 76 | /** 77 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 78 | * a call to {approve}. `value` is the new allowance. 79 | */ 80 | event Approval(address indexed owner, address indexed spender, uint value); 81 | } 82 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC20Metadata.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) 3 | 4 | pragma solidity 0.8.17; 5 | 6 | import "./IERC20.sol"; 7 | 8 | /** 9 | * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol 10 | * @dev Interface for the optional metadata functions from the ERC20 standard. 11 | * 12 | * _Available since v4.1._ 13 | */ 14 | interface IERC20Metadata is IERC20 { 15 | /** 16 | * @dev Returns the name of the token. 17 | */ 18 | function name() external view returns (string memory); 19 | 20 | /** 21 | * @dev Returns the symbol of the token. 22 | */ 23 | function symbol() external view returns (string memory); 24 | 25 | /** 26 | * @dev Returns the decimals places of the token. 27 | */ 28 | function decimals() external view returns (uint8); 29 | } 30 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC20Permit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol) 3 | 4 | pragma solidity 0.8.17; 5 | 6 | /** 7 | * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in 8 | * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. 9 | * 10 | * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by 11 | * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't 12 | * need to send a transaction, and thus is not required to hold Ether at all. 13 | */ 14 | interface IERC20Permit { 15 | /** 16 | * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, 17 | * given ``owner``'s signed approval. 18 | * 19 | * IMPORTANT: The same issues {IERC20-approve} has related to transaction 20 | * ordering also apply here. 21 | * 22 | * Emits an {Approval} event. 23 | * 24 | * Requirements: 25 | * 26 | * - `spender` cannot be the zero address. 27 | * - `deadline` must be a timestamp in the future. 28 | * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` 29 | * over the EIP712-formatted function arguments. 30 | * - the signature must use ``owner``'s current nonce (see {nonces}). 31 | * 32 | * For more information on the signature format, see the 33 | * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP 34 | * section]. 35 | */ 36 | function permit( 37 | address owner, 38 | address spender, 39 | uint256 value, 40 | uint256 deadline, 41 | uint8 v, 42 | bytes32 r, 43 | bytes32 s 44 | ) external; 45 | 46 | /** 47 | * @dev Returns the current nonce for `owner`. This value must be 48 | * included whenever a signature is generated for {permit}. 49 | * 50 | * Every successful call to {permit} increases ``owner``'s nonce by one. This 51 | * prevents a signature from being used multiple times. 52 | */ 53 | function nonces(address owner) external view returns (uint256); 54 | 55 | /** 56 | * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. 57 | */ 58 | // solhint-disable-next-line func-name-mixedcase 59 | function DOMAIN_SEPARATOR() external view returns (bytes32); 60 | } 61 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC721Metadata.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "./IERC721.sol"; 6 | 7 | /** 8 | * @title ERC-721 Non-Fungible Token Standard, optional metadata extension 9 | * @dev See https://eips.ethereum.org/EIPS/eip-721 10 | */ 11 | interface IERC721Metadata is IERC721 { 12 | /** 13 | * @dev Returns the token collection name. 14 | */ 15 | function name() external view returns (string memory); 16 | 17 | /** 18 | * @dev Returns the token collection symbol. 19 | */ 20 | function symbol() external view returns (string memory); 21 | 22 | /** 23 | * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. 24 | */ 25 | function tokenURI(uint tokenId) external view returns (string memory); 26 | } 27 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC721Receiver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | /** 6 | * @title ERC721 token receiver interface 7 | * @dev Interface for any contract that wants to support safeTransfers 8 | * from ERC721 asset contracts. 9 | */ 10 | interface IERC721Receiver { 11 | /** 12 | * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} 13 | * by `operator` from `from`, this function is called. 14 | * 15 | * It must return its Solidity selector to confirm the token transfer. 16 | * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. 17 | * 18 | * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. 19 | */ 20 | function onERC721Received( 21 | address operator, 22 | address from, 23 | uint256 tokenId, 24 | bytes calldata data 25 | ) external returns (bytes4); 26 | } 27 | -------------------------------------------------------------------------------- /contracts/interfaces/IForwarder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface IForwarder { 6 | 7 | function tetu() external view returns (address); 8 | function tetuThreshold() external view returns (uint); 9 | 10 | function tokenPerDestinationLength(address destination) external view returns (uint); 11 | 12 | function tokenPerDestinationAt(address destination, uint i) external view returns (address); 13 | 14 | function amountPerDestination(address token, address destination) external view returns (uint amount); 15 | 16 | function registerIncome( 17 | address[] memory tokens, 18 | uint[] memory amounts, 19 | address vault, 20 | bool isDistribute 21 | ) external; 22 | 23 | function distributeAll(address destination) external; 24 | 25 | function distribute(address token) external; 26 | 27 | function setInvestFundRatio(uint value) external; 28 | 29 | function setGaugesRatio(uint value) external; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /contracts/interfaces/IGauge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface IGauge { 6 | 7 | function veIds(address stakingToken, address account) external view returns (uint); 8 | 9 | function getReward( 10 | address stakingToken, 11 | address account, 12 | address[] memory tokens 13 | ) external; 14 | 15 | function getAllRewards( 16 | address stakingToken, 17 | address account 18 | ) external; 19 | 20 | function getAllRewardsForTokens( 21 | address[] memory stakingTokens, 22 | address account 23 | ) external; 24 | 25 | function attachVe(address stakingToken, address account, uint veId) external; 26 | 27 | function detachVe(address stakingToken, address account, uint veId) external; 28 | 29 | function handleBalanceChange(address account) external; 30 | 31 | function notifyRewardAmount(address stakingToken, address token, uint amount) external; 32 | 33 | function addStakingToken(address token) external; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /contracts/interfaces/IMultiPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface IMultiPool { 6 | 7 | function totalSupply(address stakingToken) external view returns (uint); 8 | 9 | function derivedSupply(address stakingToken) external view returns (uint); 10 | 11 | function derivedBalances(address stakingToken, address account) external view returns (uint); 12 | 13 | function balanceOf(address stakingToken, address account) external view returns (uint); 14 | 15 | function rewardTokens(address stakingToken, uint id) external view returns (address); 16 | 17 | function isRewardToken(address stakingToken, address token) external view returns (bool); 18 | 19 | function rewardTokensLength(address stakingToken) external view returns (uint); 20 | 21 | function derivedBalance(address stakingToken, address account) external view returns (uint); 22 | 23 | function left(address stakingToken, address token) external view returns (uint); 24 | 25 | function earned(address stakingToken, address token, address account) external view returns (uint); 26 | 27 | function registerRewardToken(address stakingToken, address token) external; 28 | 29 | function removeRewardToken(address stakingToken, address token) external; 30 | 31 | function isStakeToken(address token) external view returns (bool); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /contracts/interfaces/IPlatformVoter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "./IVeVotable.sol"; 6 | 7 | interface IPlatformVoter is IVeVotable { 8 | 9 | enum AttributeType { 10 | UNKNOWN, 11 | INVEST_FUND_RATIO, 12 | GAUGE_RATIO, 13 | STRATEGY_COMPOUND 14 | } 15 | 16 | struct Vote { 17 | AttributeType _type; 18 | address target; 19 | uint weight; 20 | uint weightedValue; 21 | uint timestamp; 22 | } 23 | 24 | function veVotesLength(uint veId) external view returns (uint); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /contracts/interfaces/IPriceOracle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface IPriceOracle { 6 | 7 | /// @notice Return asset price in USD, decimals 18 8 | function getAssetPrice(address asset) external view returns (uint256); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /contracts/interfaces/IProxyControlled.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface IProxyControlled { 6 | 7 | function initProxy(address _logic) external; 8 | 9 | function upgrade(address _newImplementation) external; 10 | 11 | function implementation() external view returns (address); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /contracts/interfaces/ISplitter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.17; 3 | 4 | interface ISplitter { 5 | 6 | function init(address controller_, address _asset, address _vault) external; 7 | 8 | // *************** ACTIONS ************** 9 | 10 | function withdrawAllToVault() external; 11 | 12 | function withdrawToVault(uint256 amount) external; 13 | 14 | function coverPossibleStrategyLoss(uint earned, uint lost) external; 15 | 16 | function doHardWork() external; 17 | 18 | function investAll() external; 19 | 20 | // **************** VIEWS *************** 21 | 22 | function asset() external view returns (address); 23 | 24 | function vault() external view returns (address); 25 | 26 | function totalAssets() external view returns (uint256); 27 | 28 | function isHardWorking() external view returns (bool); 29 | 30 | function strategies(uint i) external view returns (address); 31 | 32 | function strategiesLength() external view returns (uint); 33 | 34 | function HARDWORK_DELAY() external view returns (uint); 35 | 36 | function lastHardWorks(address strategy) external view returns (uint); 37 | 38 | function pausedStrategies(address strategy) external view returns (bool); 39 | 40 | function pauseInvesting(address strategy) external; 41 | 42 | function continueInvesting(address strategy, uint apr) external; 43 | 44 | function rebalance(uint percent, uint lossTolerance) external; 45 | 46 | function getStrategyCapacity(address strategy) external view returns (uint capacity); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /contracts/interfaces/IStrategyStrict.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.17; 3 | 4 | interface IStrategyStrict { 5 | 6 | function NAME() external view returns (string memory); 7 | 8 | function PLATFORM() external view returns (string memory); 9 | 10 | function STRATEGY_VERSION() external view returns (string memory); 11 | 12 | function asset() external view returns (address); 13 | 14 | function vault() external view returns (address); 15 | 16 | function compoundRatio() external view returns (uint); 17 | 18 | function totalAssets() external view returns (uint); 19 | 20 | /// @dev Usually, indicate that claimable rewards have reasonable amount. 21 | function isReadyToHardWork() external view returns (bool); 22 | 23 | function withdrawAllToVault() external; 24 | 25 | function withdrawToVault(uint amount) external; 26 | 27 | function investAll() external; 28 | 29 | function doHardWork() external returns (uint earned, uint lost); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /contracts/interfaces/IStrategyV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.17; 3 | 4 | interface IStrategyV2 { 5 | 6 | function NAME() external view returns (string memory); 7 | 8 | function strategySpecificName() external view returns (string memory); 9 | 10 | function PLATFORM() external view returns (string memory); 11 | 12 | function STRATEGY_VERSION() external view returns (string memory); 13 | 14 | function asset() external view returns (address); 15 | 16 | function splitter() external view returns (address); 17 | 18 | function compoundRatio() external view returns (uint); 19 | 20 | function totalAssets() external view returns (uint); 21 | 22 | /// @dev Usually, indicate that claimable rewards have reasonable amount. 23 | function isReadyToHardWork() external view returns (bool); 24 | 25 | /// @return strategyLoss Loss should be covered from Insurance 26 | function withdrawAllToSplitter() external returns (uint strategyLoss); 27 | 28 | /// @return strategyLoss Loss should be covered from Insurance 29 | function withdrawToSplitter(uint amount) external returns (uint strategyLoss); 30 | 31 | /// @notice Stakes everything the strategy holds into the reward pool. 32 | /// @param amount_ Amount transferred to the strategy balance just before calling this function 33 | /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing. 34 | /// It can be false if we know exactly, that the amount is already actual. 35 | /// @return strategyLoss Loss should be covered from Insurance 36 | function investAll( 37 | uint amount_, 38 | bool updateTotalAssetsBeforeInvest_ 39 | ) external returns ( 40 | uint strategyLoss 41 | ); 42 | 43 | function doHardWork() external returns (uint earned, uint lost); 44 | 45 | function setCompoundRatio(uint value) external; 46 | 47 | /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593. 48 | /// 0 means no deposit is allowed at this moment 49 | function capacity() external view returns (uint); 50 | 51 | /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding 52 | function performanceReceiver() external view returns (address); 53 | 54 | /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding 55 | /// @dev use FEE_DENOMINATOR 56 | function performanceFee() external view returns (uint); 57 | } 58 | -------------------------------------------------------------------------------- /contracts/interfaces/IStrategyV3.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.17; 3 | 4 | import "./IStrategyV2.sol"; 5 | 6 | interface IStrategyV3 is IStrategyV2 { 7 | struct BaseState { 8 | /// @dev Underlying asset 9 | address asset; 10 | 11 | /// @dev Linked splitter 12 | address splitter; 13 | 14 | /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding 15 | /// @dev governance by default 16 | address performanceReceiver; 17 | 18 | /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding 19 | /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used 20 | uint performanceFee; 21 | 22 | /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000] 23 | /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance. 24 | uint performanceFeeRatio; 25 | 26 | /// @dev Percent of profit for autocompound inside this strategy. 27 | uint compoundRatio; 28 | 29 | /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault. 30 | string strategySpecificName; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /contracts/interfaces/ITetuLiquidator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface ITetuLiquidator { 6 | 7 | struct PoolData { 8 | address pool; 9 | address swapper; 10 | address tokenIn; 11 | address tokenOut; 12 | } 13 | 14 | function addLargestPools(PoolData[] memory _pools, bool rewrite) external; 15 | 16 | function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external; 17 | 18 | function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint); 19 | 20 | function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint); 21 | 22 | function isRouteExist(address tokenIn, address tokenOut) external view returns (bool); 23 | 24 | function buildRoute( 25 | address tokenIn, 26 | address tokenOut 27 | ) external view returns (PoolData[] memory route, string memory errorMessage); 28 | 29 | function liquidate( 30 | address tokenIn, 31 | address tokenOut, 32 | uint amount, 33 | uint slippage 34 | ) external; 35 | 36 | function liquidateWithRoute( 37 | PoolData[] memory route, 38 | uint amount, 39 | uint slippage 40 | ) external; 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /contracts/interfaces/ITetuVaultV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "./IVaultInsurance.sol"; 6 | import "./IERC20.sol"; 7 | import "./ISplitter.sol"; 8 | 9 | interface ITetuVaultV2 { 10 | 11 | function splitter() external view returns (ISplitter); 12 | 13 | function insurance() external view returns (IVaultInsurance); 14 | 15 | function depositFee() external view returns (uint); 16 | 17 | function withdrawFee() external view returns (uint); 18 | 19 | function init( 20 | address controller_, 21 | IERC20 _asset, 22 | string memory _name, 23 | string memory _symbol, 24 | address _gauge, 25 | uint _buffer 26 | ) external; 27 | 28 | function setSplitter(address _splitter) external; 29 | 30 | function coverLoss(uint amount) external; 31 | 32 | function initInsurance(IVaultInsurance _insurance) external; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /contracts/interfaces/IVaultInsurance.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface IVaultInsurance { 6 | 7 | function init(address _vault, address _asset) external; 8 | 9 | function vault() external view returns (address); 10 | 11 | function asset() external view returns (address); 12 | 13 | function transferToVault(uint amount) external; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /contracts/interfaces/IVeDistributor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface IVeDistributor { 6 | 7 | function rewardToken() external view returns (address); 8 | 9 | function checkpoint() external; 10 | 11 | function checkpointTotalSupply() external; 12 | 13 | function claim(uint _tokenId) external returns (uint); 14 | 15 | function claimable(uint _tokenId) external view returns (uint); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /contracts/interfaces/IVeDistributorV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "./IVeDistributor.sol"; 6 | 7 | interface IVeDistributorV2 is IVeDistributor { 8 | 9 | function epoch() external view returns (uint); 10 | 11 | function lastPaidEpoch(uint veId) external view returns (uint); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /contracts/interfaces/IVeTetu.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "./IERC721Metadata.sol"; 6 | 7 | interface IVeTetu is IERC721Metadata { 8 | 9 | enum DepositType { 10 | DEPOSIT_FOR_TYPE, 11 | CREATE_LOCK_TYPE, 12 | INCREASE_LOCK_AMOUNT, 13 | INCREASE_UNLOCK_TIME, 14 | MERGE_TYPE 15 | } 16 | 17 | struct Point { 18 | int128 bias; 19 | int128 slope; // # -dweight / dt 20 | uint ts; 21 | uint blk; // block 22 | } 23 | /* We cannot really do block numbers per se b/c slope is per time, not per block 24 | * and per block could be fairly bad b/c Ethereum changes blocktimes. 25 | * What we can do is to extrapolate ***At functions */ 26 | 27 | function attachments(uint tokenId) external view returns (uint); 28 | 29 | function lockedAmounts(uint veId, address stakingToken) external view returns (uint); 30 | 31 | function lockedDerivedAmount(uint veId) external view returns (uint); 32 | 33 | function lockedEnd(uint veId) external view returns (uint); 34 | 35 | // function voted(uint tokenId) external view returns (uint); 36 | function isVoted(uint tokenId) external view returns (bool); 37 | 38 | function tokens(uint idx) external view returns (address); 39 | 40 | function balanceOfNFT(uint) external view returns (uint); 41 | 42 | function isApprovedOrOwner(address, uint) external view returns (bool); 43 | 44 | function createLockFor(address _token, uint _value, uint _lockDuration, address _to) external returns (uint); 45 | 46 | function userPointEpoch(uint tokenId) external view returns (uint); 47 | 48 | function epoch() external view returns (uint); 49 | 50 | function checkpoint() external; 51 | 52 | function increaseAmount(address _token, uint _tokenId, uint _value) external; 53 | 54 | function attachToken(uint tokenId) external; 55 | 56 | function detachToken(uint tokenId) external; 57 | 58 | function voting(uint tokenId) external; 59 | 60 | function abstain(uint tokenId) external; 61 | 62 | function totalSupply() external view returns (uint); 63 | } 64 | -------------------------------------------------------------------------------- /contracts/interfaces/IVeVotable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface IVeVotable { 6 | 7 | function isVotesExist(uint veId) external view returns (bool); 8 | 9 | function detachTokenFromAll(uint tokenId, address owner) external; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /contracts/interfaces/IVoter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "./IVeVotable.sol"; 6 | 7 | interface IVoter is IVeVotable { 8 | 9 | function ve() external view returns (address); 10 | 11 | function attachTokenToGauge(address stakingToken, uint _tokenId, address account) external; 12 | 13 | function detachTokenFromGauge(address stakingToken, uint _tokenId, address account) external; 14 | 15 | function distribute(address stakingToken) external; 16 | 17 | function distributeAll() external; 18 | 19 | function notifyRewardAmount(uint amount) external; 20 | 21 | function votedVaultsLength(uint veId) external view returns (uint); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /contracts/lib/Base64.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | /// @title Base64 6 | /// @notice Provides a function for encoding some bytes in base64 7 | /// @author Brecht Devos 8 | library Base64 { 9 | bytes internal constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 10 | 11 | /// @notice Encodes some bytes to the base64 representation 12 | function encode(bytes memory data) internal pure returns (string memory) { 13 | uint len = data.length; 14 | if (len == 0) return ""; 15 | 16 | // multiply by 4/3 rounded up 17 | uint encodedLen = 4 * ((len + 2) / 3); 18 | 19 | // Add some extra buffer at the end 20 | bytes memory result = new bytes(encodedLen + 32); 21 | 22 | bytes memory table = TABLE; 23 | 24 | assembly { 25 | let tablePtr := add(table, 1) 26 | let resultPtr := add(result, 32) 27 | 28 | for { 29 | let i := 0 30 | } lt(i, len) { 31 | 32 | } { 33 | i := add(i, 3) 34 | let input := and(mload(add(data, i)), 0xffffff) 35 | 36 | let out := mload(add(tablePtr, and(shr(18, input), 0x3F))) 37 | out := shl(8, out) 38 | out := add(out, and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF)) 39 | out := shl(8, out) 40 | out := add(out, and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF)) 41 | out := shl(8, out) 42 | out := add(out, and(mload(add(tablePtr, and(input, 0x3F))), 0xFF)) 43 | out := shl(224, out) 44 | 45 | mstore(resultPtr, out) 46 | 47 | resultPtr := add(resultPtr, 4) 48 | } 49 | 50 | switch mod(len, 3) 51 | case 1 { 52 | mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) 53 | } 54 | case 2 { 55 | mstore(sub(resultPtr, 1), shl(248, 0x3d)) 56 | } 57 | 58 | mstore(result, encodedLen) 59 | } 60 | 61 | return string(result); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /contracts/lib/InterfaceIds.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | /// @title Library for interface IDs 6 | /// @author bogdoslav 7 | library InterfaceIds { 8 | 9 | /// @notice Version of the contract 10 | /// @dev Should be incremented when contract changed 11 | string public constant INTERFACE_IDS_LIB_VERSION = "1.0.1"; 12 | 13 | /// default notation: 14 | /// bytes4 public constant I_VOTER = type(IVoter).interfaceId; 15 | 16 | /// As type({Interface}).interfaceId can be changed, 17 | /// when some functions changed at the interface, 18 | /// so used hardcoded interface identifiers 19 | 20 | bytes4 public constant I_VOTER = bytes4(keccak256("IVoter")); 21 | bytes4 public constant I_BRIBE = bytes4(keccak256("IBribe")); 22 | bytes4 public constant I_GAUGE = bytes4(keccak256("IGauge")); 23 | bytes4 public constant I_VE_TETU = bytes4(keccak256("IVeTetu")); 24 | bytes4 public constant I_SPLITTER = bytes4(keccak256("ISplitter")); 25 | bytes4 public constant I_FORWARDER = bytes4(keccak256("IForwarder")); 26 | bytes4 public constant I_MULTI_POOL = bytes4(keccak256("IMultiPool")); 27 | bytes4 public constant I_CONTROLLER = bytes4(keccak256("IController")); 28 | bytes4 public constant I_TETU_ERC165 = bytes4(keccak256("ITetuERC165")); 29 | bytes4 public constant I_STRATEGY_V2 = bytes4(keccak256("IStrategyV2")); 30 | bytes4 public constant I_STRATEGY_V3 = bytes4(keccak256("IStrategyV3")); 31 | bytes4 public constant I_CONTROLLABLE = bytes4(keccak256("IControllable")); 32 | bytes4 public constant I_TETU_VAULT_V2 = bytes4(keccak256("ITetuVaultV2")); 33 | bytes4 public constant I_PLATFORM_VOTER = bytes4(keccak256("IPlatformVoter")); 34 | bytes4 public constant I_VE_DISTRIBUTOR = bytes4(keccak256("IVeDistributor")); 35 | bytes4 public constant I_TETU_CONVERTER = bytes4(keccak256("ITetuConverter")); 36 | bytes4 public constant I_VAULT_INSURANCE = bytes4(keccak256("IVaultInsurance")); 37 | bytes4 public constant I_STRATEGY_STRICT = bytes4(keccak256("IStrategyStrict")); 38 | bytes4 public constant I_ERC4626 = bytes4(keccak256("IERC4626")); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /contracts/lib/StringLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | 6 | library StringLib { 7 | 8 | /// @dev Inspired by OraclizeAPI's implementation - MIT license 9 | /// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol 10 | function toString(uint value) external pure returns (string memory) { 11 | return _toString(value); 12 | } 13 | 14 | function _toString(uint value) internal pure returns (string memory) { 15 | if (value == 0) { 16 | return "0"; 17 | } 18 | uint temp = value; 19 | uint digits; 20 | while (temp != 0) { 21 | digits++; 22 | temp /= 10; 23 | } 24 | bytes memory buffer = new bytes(digits); 25 | while (value != 0) { 26 | digits -= 1; 27 | buffer[digits] = bytes1(uint8(48 + uint(value % 10))); 28 | value /= 10; 29 | } 30 | return string(buffer); 31 | } 32 | 33 | function toAsciiString(address x) external pure returns (string memory) { 34 | return _toAsciiString(x); 35 | } 36 | 37 | function _toAsciiString(address x) internal pure returns (string memory) { 38 | bytes memory s = new bytes(40); 39 | for (uint i = 0; i < 20; i++) { 40 | bytes1 b = bytes1(uint8(uint(uint160(x)) / (2 ** (8 * (19 - i))))); 41 | bytes1 hi = bytes1(uint8(b) / 16); 42 | bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi)); 43 | s[2 * i] = _char(hi); 44 | s[2 * i + 1] = _char(lo); 45 | } 46 | return string(s); 47 | } 48 | 49 | function char(bytes1 b) external pure returns (bytes1 c) { 50 | return _char(b); 51 | } 52 | 53 | function _char(bytes1 b) internal pure returns (bytes1 c) { 54 | if (uint8(b) < 10) return bytes1(uint8(b) + 0x30); 55 | else return bytes1(uint8(b) + 0x57); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /contracts/openzeppelin/Context.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) 3 | 4 | pragma solidity 0.8.17; 5 | 6 | /** 7 | * @dev Provides information about the current execution context, including the 8 | * sender of the transaction and its data. While these are generally available 9 | * via msg.sender and msg.data, they should not be accessed in such a direct 10 | * manner, since when dealing with meta-transactions the account sending and 11 | * paying for execution may not be the actual sender (as far as an application 12 | * is concerned). 13 | * 14 | * This contract is only required for intermediate, library-like contracts. 15 | */ 16 | abstract contract Context { 17 | function _msgSender() internal view virtual returns (address) { 18 | return msg.sender; 19 | } 20 | 21 | function _msgData() internal view virtual returns (bytes calldata) { 22 | return msg.data; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/openzeppelin/ContextUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) 3 | 4 | pragma solidity 0.8.17; 5 | import "./Initializable.sol"; 6 | 7 | /** 8 | * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/utils/ContextUpgradeable.sol 9 | * @dev Provides information about the current execution context, including the 10 | * sender of the transaction and its data. While these are generally available 11 | * via msg.sender and msg.data, they should not be accessed in such a direct 12 | * manner, since when dealing with meta-transactions the account sending and 13 | * paying for execution may not be the actual sender (as far as an application 14 | * is concerned). 15 | * 16 | * This contract is only required for intermediate, library-like contracts. 17 | */ 18 | abstract contract ContextUpgradeable is Initializable { 19 | function __Context_init() internal onlyInitializing { 20 | } 21 | 22 | function __Context_init_unchained() internal onlyInitializing { 23 | } 24 | function _msgSender() internal view virtual returns (address) { 25 | return msg.sender; 26 | } 27 | 28 | function _msgData() internal view virtual returns (bytes calldata) { 29 | return msg.data; 30 | } 31 | 32 | /** 33 | * @dev This empty reserved space is put in place to allow future versions to add new 34 | * variables without shifting down storage in the inheritance chain. 35 | * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps 36 | */ 37 | uint[50] private __gap; 38 | } 39 | -------------------------------------------------------------------------------- /contracts/openzeppelin/Counters.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) 3 | 4 | pragma solidity 0.8.17; 5 | 6 | /** 7 | * @title Counters 8 | * @author Matt Condon (@shrugs) 9 | * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number 10 | * of elements in a mapping, issuing ERC721 ids, or counting request ids. 11 | * 12 | * Include with `using Counters for Counters.Counter;` 13 | */ 14 | library Counters { 15 | struct Counter { 16 | // This variable should never be directly accessed by users of the library: interactions must be restricted to 17 | // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add 18 | // this feature: see https://github.com/ethereum/solidity/issues/4637 19 | uint256 _value; // default: 0 20 | } 21 | 22 | function current(Counter storage counter) internal view returns (uint256) { 23 | return counter._value; 24 | } 25 | 26 | function increment(Counter storage counter) internal { 27 | unchecked { 28 | counter._value += 1; 29 | } 30 | } 31 | 32 | function decrement(Counter storage counter) internal { 33 | uint256 value = counter._value; 34 | require(value > 0, "Counter: decrement overflow"); 35 | unchecked { 36 | counter._value = value - 1; 37 | } 38 | } 39 | 40 | function reset(Counter storage counter) internal { 41 | counter._value = 0; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/openzeppelin/CountersUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) 3 | 4 | pragma solidity 0.8.17; 5 | 6 | /** 7 | * @title Counters 8 | * @author Matt Condon (@shrugs) 9 | * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number 10 | * of elements in a mapping, issuing ERC721 ids, or counting request ids. 11 | * 12 | * Include with `using Counters for Counters.Counter;` 13 | */ 14 | library CountersUpgradeable { 15 | struct Counter { 16 | // This variable should never be directly accessed by users of the library: interactions must be restricted to 17 | // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add 18 | // this feature: see https://github.com/ethereum/solidity/issues/4637 19 | uint256 _value; // default: 0 20 | } 21 | 22 | function current(Counter storage counter) internal view returns (uint256) { 23 | return counter._value; 24 | } 25 | 26 | function increment(Counter storage counter) internal { 27 | unchecked { 28 | counter._value += 1; 29 | } 30 | } 31 | 32 | function decrement(Counter storage counter) internal { 33 | uint256 value = counter._value; 34 | require(value > 0, "Counter: decrement overflow"); 35 | unchecked { 36 | counter._value = value - 1; 37 | } 38 | } 39 | 40 | function reset(Counter storage counter) internal { 41 | counter._value = 0; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/openzeppelin/ERC165.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) 3 | 4 | pragma solidity 0.8.17; 5 | 6 | import "../interfaces/IERC165.sol"; 7 | 8 | /** 9 | * @dev Implementation of the {IERC165} interface. 10 | * 11 | * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check 12 | * for the additional interface id that will be supported. For example: 13 | * 14 | * ```solidity 15 | * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 16 | * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); 17 | * } 18 | * ``` 19 | * 20 | * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. 21 | */ 22 | abstract contract ERC165 is IERC165 { 23 | /** 24 | * @dev See {IERC165-supportsInterface}. 25 | */ 26 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 27 | return interfaceId == type(IERC165).interfaceId; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contracts/openzeppelin/ERC20Permit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol) 3 | 4 | pragma solidity 0.8.17; 5 | 6 | import "../interfaces/IERC20Permit.sol"; 7 | import "./ERC20.sol"; 8 | import "./ECDSA.sol"; 9 | import "./EIP712.sol"; 10 | import "./Counters.sol"; 11 | 12 | /** 13 | * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in 14 | * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. 15 | * 16 | * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by 17 | * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't 18 | * need to send a transaction, and thus is not required to hold Ether at all. 19 | * 20 | * _Available since v3.4._ 21 | */ 22 | abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 { 23 | using Counters for Counters.Counter; 24 | 25 | mapping(address => Counters.Counter) private _nonces; 26 | 27 | // solhint-disable-next-line var-name-mixedcase 28 | bytes32 private constant _PERMIT_TYPEHASH = 29 | keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); 30 | /** 31 | * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`. 32 | * However, to ensure consistency with the upgradeable transpiler, we will continue 33 | * to reserve a slot. 34 | * @custom:oz-renamed-from _PERMIT_TYPEHASH 35 | */ 36 | // solhint-disable-next-line var-name-mixedcase 37 | bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT; 38 | 39 | /** 40 | * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. 41 | * 42 | * It's a good idea to use the same `name` that is defined as the ERC20 token name. 43 | */ 44 | constructor(string memory name) EIP712(name, "1") {} 45 | 46 | /** 47 | * @dev See {IERC20Permit-permit}. 48 | */ 49 | function permit( 50 | address owner, 51 | address spender, 52 | uint256 value, 53 | uint256 deadline, 54 | uint8 v, 55 | bytes32 r, 56 | bytes32 s 57 | ) public virtual override { 58 | require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); 59 | 60 | bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); 61 | 62 | bytes32 hash = _hashTypedDataV4(structHash); 63 | 64 | address signer = ECDSA.recover(hash, v, r, s); 65 | require(signer == owner, "ERC20Permit: invalid signature"); 66 | 67 | _approve(owner, spender, value); 68 | } 69 | 70 | /** 71 | * @dev See {IERC20Permit-nonces}. 72 | */ 73 | function nonces(address owner) public view virtual override returns (uint256) { 74 | return _nonces[owner].current(); 75 | } 76 | 77 | /** 78 | * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. 79 | */ 80 | // solhint-disable-next-line func-name-mixedcase 81 | function DOMAIN_SEPARATOR() external view override returns (bytes32) { 82 | return _domainSeparatorV4(); 83 | } 84 | 85 | /** 86 | * @dev "Consume a nonce": return the current value and increment. 87 | * 88 | * _Available since v4.1._ 89 | */ 90 | function _useNonce(address owner) internal virtual returns (uint256 current) { 91 | Counters.Counter storage nonce = _nonces[owner]; 92 | current = nonce.current(); 93 | nonce.increment(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /contracts/openzeppelin/Proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol) 3 | 4 | pragma solidity 0.8.17; 5 | 6 | /** 7 | * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM 8 | * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to 9 | * be specified by overriding the virtual {_implementation} function. 10 | * 11 | * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a 12 | * different contract through the {_delegate} function. 13 | * 14 | * The success and return data of the delegated call will be returned back to the caller of the proxy. 15 | */ 16 | abstract contract Proxy { 17 | /** 18 | * @dev Delegates the current call to `implementation`. 19 | * 20 | * This function does not return to its internal call site, it will return directly to the external caller. 21 | */ 22 | function _delegate(address implementation) internal virtual { 23 | assembly { 24 | // Copy msg.data. We take full control of memory in this inline assembly 25 | // block because it will not return to Solidity code. We overwrite the 26 | // Solidity scratch pad at memory position 0. 27 | calldatacopy(0, 0, calldatasize()) 28 | 29 | // Call the implementation. 30 | // out and outsize are 0 because we don't know the size yet. 31 | let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) 32 | 33 | // Copy the returned data. 34 | returndatacopy(0, 0, returndatasize()) 35 | 36 | switch result 37 | // delegatecall returns 0 on error. 38 | case 0 { 39 | revert(0, returndatasize()) 40 | } 41 | default { 42 | return (0, returndatasize()) 43 | } 44 | } 45 | } 46 | 47 | /** 48 | * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function 49 | * and {_fallback} should delegate. 50 | */ 51 | function _implementation() internal view virtual returns (address); 52 | 53 | /** 54 | * @dev Delegates the current call to the address returned by `_implementation()`. 55 | * 56 | * This function does not return to its internal call site, it will return directly to the external caller. 57 | */ 58 | function _fallback() internal virtual { 59 | _beforeFallback(); 60 | _delegate(_implementation()); 61 | } 62 | 63 | /** 64 | * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other 65 | * function in the contract matches the call data. 66 | */ 67 | fallback() external payable virtual { 68 | _fallback(); 69 | } 70 | 71 | /** 72 | * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data 73 | * is empty. 74 | */ 75 | receive() external payable virtual { 76 | _fallback(); 77 | } 78 | 79 | /** 80 | * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` 81 | * call, or as part of the Solidity `fallback` or `receive` functions. 82 | * 83 | * If overridden should call `super._beforeFallback()`. 84 | */ 85 | function _beforeFallback() internal virtual {} 86 | } 87 | -------------------------------------------------------------------------------- /contracts/openzeppelin/ReentrancyGuard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) 3 | 4 | pragma solidity 0.8.17; 5 | 6 | /** 7 | * @dev Contract module that helps prevent reentrant calls to a function. 8 | * 9 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier 10 | * available, which can be applied to functions to make sure there are no nested 11 | * (reentrant) calls to them. 12 | * 13 | * Note that because there is a single `nonReentrant` guard, functions marked as 14 | * `nonReentrant` may not call one another. This can be worked around by making 15 | * those functions `private`, and then adding `external` `nonReentrant` entry 16 | * points to them. 17 | * 18 | * TIP: If you would like to learn more about reentrancy and alternative ways 19 | * to protect against it, check out our blog post 20 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. 21 | */ 22 | abstract contract ReentrancyGuard { 23 | // Booleans are more expensive than uint256 or any type that takes up a full 24 | // word because each write operation emits an extra SLOAD to first read the 25 | // slot's contents, replace the bits taken up by the boolean, and then write 26 | // back. This is the compiler's defense against contract upgrades and 27 | // pointer aliasing, and it cannot be disabled. 28 | 29 | // The values being non-zero value makes deployment a bit more expensive, 30 | // but in exchange the refund on every call to nonReentrant will be lower in 31 | // amount. Since refunds are capped to a percentage of the total 32 | // transaction's gas, it is best to keep them low in cases like this one, to 33 | // increase the likelihood of the full refund coming into effect. 34 | uint256 private constant _NOT_ENTERED = 1; 35 | uint256 private constant _ENTERED = 2; 36 | 37 | uint256 private _status; 38 | 39 | constructor() { 40 | _status = _NOT_ENTERED; 41 | } 42 | 43 | /** 44 | * @dev Prevents a contract from calling itself, directly or indirectly. 45 | * Calling a `nonReentrant` function from another `nonReentrant` 46 | * function is not supported. It is possible to prevent this from happening 47 | * by making the `nonReentrant` function external, and making it call a 48 | * `private` function that does the actual work. 49 | */ 50 | modifier nonReentrant() { 51 | _nonReentrantBefore(); 52 | _; 53 | _nonReentrantAfter(); 54 | } 55 | 56 | function _nonReentrantBefore() private { 57 | // On the first call to nonReentrant, _status will be _NOT_ENTERED 58 | require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); 59 | 60 | // Any calls to nonReentrant after this point will fail 61 | _status = _ENTERED; 62 | } 63 | 64 | function _nonReentrantAfter() private { 65 | // By storing the original value once again, a refund is triggered (see 66 | // https://eips.ethereum.org/EIPS/eip-2200) 67 | _status = _NOT_ENTERED; 68 | } 69 | 70 | /** 71 | * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a 72 | * `nonReentrant` function in the call stack. 73 | */ 74 | function _reentrancyGuardEntered() internal view returns (bool) { 75 | return _status == _ENTERED; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /contracts/openzeppelin/Strings.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "./Math.sol"; 7 | 8 | /** 9 | * @dev String operations. 10 | */ 11 | library Strings { 12 | bytes16 private constant _SYMBOLS = "0123456789abcdef"; 13 | uint8 private constant _ADDRESS_LENGTH = 20; 14 | 15 | /** 16 | * @dev Converts a `uint256` to its ASCII `string` decimal representation. 17 | */ 18 | function toString(uint256 value) internal pure returns (string memory) { 19 | unchecked { 20 | uint256 length = Math.log10(value) + 1; 21 | string memory buffer = new string(length); 22 | uint256 ptr; 23 | /// @solidity memory-safe-assembly 24 | assembly { 25 | ptr := add(buffer, add(32, length)) 26 | } 27 | while (true) { 28 | ptr--; 29 | /// @solidity memory-safe-assembly 30 | assembly { 31 | mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) 32 | } 33 | value /= 10; 34 | if (value == 0) break; 35 | } 36 | return buffer; 37 | } 38 | } 39 | 40 | /** 41 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. 42 | */ 43 | function toHexString(uint256 value) internal pure returns (string memory) { 44 | unchecked { 45 | return toHexString(value, Math.log256(value) + 1); 46 | } 47 | } 48 | 49 | /** 50 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. 51 | */ 52 | function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { 53 | bytes memory buffer = new bytes(2 * length + 2); 54 | buffer[0] = "0"; 55 | buffer[1] = "x"; 56 | for (uint256 i = 2 * length + 1; i > 1; --i) { 57 | buffer[i] = _SYMBOLS[value & 0xf]; 58 | value >>= 4; 59 | } 60 | require(value == 0, "Strings: hex length insufficient"); 61 | return string(buffer); 62 | } 63 | 64 | /** 65 | * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. 66 | */ 67 | function toHexString(address addr) internal pure returns (string memory) { 68 | return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /contracts/proxy/ProxyControlled.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../interfaces/IControllable.sol"; 6 | import "../interfaces/IProxyControlled.sol"; 7 | import "./UpgradeableProxy.sol"; 8 | import "../interfaces/IERC165.sol"; 9 | import "../lib/InterfaceIds.sol"; 10 | 11 | /// @title EIP1967 Upgradable proxy implementation. 12 | /// @dev Only Controller has access and should implement time-lock for upgrade action. 13 | /// @author belbix 14 | contract ProxyControlled is UpgradeableProxy, IProxyControlled { 15 | 16 | /// @notice Version of the contract 17 | /// @dev Should be incremented when contract changed 18 | string public constant PROXY_CONTROLLED_VERSION = "1.0.1"; 19 | 20 | /// @dev Initialize proxy implementation. Need to call after deploy new proxy. 21 | function initProxy(address _logic) external override { 22 | //make sure that given logic is controllable and not inited 23 | require(IERC165(_logic).supportsInterface(InterfaceIds.I_CONTROLLABLE), "Proxy: Wrong implementation"); 24 | _init(_logic); 25 | } 26 | 27 | /// @notice Upgrade contract logic 28 | /// @dev Upgrade allowed only for Controller and should be done only after time-lock period 29 | /// @param _newImplementation Implementation address 30 | function upgrade(address _newImplementation) external override { 31 | require(IERC165(_newImplementation).supportsInterface(InterfaceIds.I_CONTROLLABLE), "Proxy: Wrong implementation"); 32 | require(IControllable(address(this)).isController(msg.sender), "Proxy: Forbidden"); 33 | IControllable(address(this)).increaseRevision(_implementation()); 34 | _upgradeTo(_newImplementation); 35 | // the new contract must have the same ABI and you must have the power to change it again 36 | require(IControllable(address(this)).isController(msg.sender), "Proxy: Wrong implementation"); 37 | } 38 | 39 | /// @notice Return current logic implementation 40 | function implementation() external override view returns (address) { 41 | return _implementation(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/proxy/UpgradeableProxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../openzeppelin/Proxy.sol"; 6 | import "../openzeppelin/Address.sol"; 7 | 8 | /// @title OpenZeppelin https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.4/contracts/proxy/UpgradeableProxy.sol 9 | /// @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an 10 | /// implementation address that can be changed. This address is stored in storage in the location specified by 11 | /// https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the 12 | /// implementation behind the proxy. 13 | /// Upgradeability is only provided internally through {_upgradeTo}. For an externally upgradeable proxy see 14 | /// {TransparentUpgradeableProxy}. 15 | abstract contract UpgradeableProxy is Proxy { 16 | 17 | /// @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`. 18 | /// If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded 19 | /// function call, and allows initializating the storage of the proxy like a Solidity constructor. 20 | constructor() payable { 21 | assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)); 22 | } 23 | 24 | /// @dev Emitted when the implementation is upgraded. 25 | event Upgraded(address indexed implementation); 26 | 27 | ///@dev Storage slot with the address of the current implementation. 28 | /// This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is 29 | /// validated in the constructor. 30 | bytes32 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; 31 | 32 | /// @dev Post deploy initialisation for compatability with EIP-1167 factory 33 | function _init(address _logic) internal { 34 | require(_implementation() == address(0), "Already inited"); 35 | _setImplementation(_logic); 36 | } 37 | 38 | /// @dev Returns the current implementation address. 39 | function _implementation() internal view virtual override returns (address impl) { 40 | bytes32 slot = _IMPLEMENTATION_SLOT; 41 | // solhint-disable-next-line no-inline-assembly 42 | assembly { 43 | impl := sload(slot) 44 | } 45 | } 46 | 47 | /// @dev Upgrades the proxy to a new implementation. 48 | /// Emits an {Upgraded} event. 49 | function _upgradeTo(address newImplementation) internal virtual { 50 | _setImplementation(newImplementation); 51 | emit Upgraded(newImplementation); 52 | } 53 | 54 | /// @dev Stores a new address in the EIP1967 implementation slot. 55 | function _setImplementation(address newImplementation) private { 56 | require(Address.isContract(newImplementation), "UpgradeableProxy: new implementation is not a contract"); 57 | 58 | bytes32 slot = _IMPLEMENTATION_SLOT; 59 | 60 | // solhint-disable-next-line no-inline-assembly 61 | assembly { 62 | sstore(slot, newImplementation) 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /contracts/test/Base64Test.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../lib/Base64.sol"; 6 | 7 | contract Base64Test { 8 | 9 | function encode(bytes memory data) external pure returns (string memory) { 10 | return Base64.encode(data); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /contracts/test/ControllableTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../proxy/ControllableV3.sol"; 6 | 7 | contract ControllableTest is ControllableV3 { 8 | 9 | uint private _variable; 10 | 11 | function init(address controller_) external initializer { 12 | ControllableV3.__Controllable_init(controller_); 13 | _variable = 333; 14 | } 15 | 16 | function increase() external { 17 | this.increaseRevision(address(this)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/test/ControllerMinimal.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../tools/TetuERC165.sol"; 6 | import "../interfaces/IProxyControlled.sol"; 7 | import "../interfaces/IController.sol"; 8 | import "../lib/InterfaceIds.sol"; 9 | 10 | contract ControllerMinimal is TetuERC165, IController { 11 | 12 | address public override governance; 13 | address public override voter; 14 | address public override liquidator; 15 | address public override forwarder; 16 | address public override investFund; 17 | address public veDistributor; 18 | address public override platformVoter; 19 | address[] public override vaults; 20 | mapping(address => bool) public operators; 21 | 22 | constructor (address governance_) { 23 | governance = governance_; 24 | operators[governance_] = true; 25 | } 26 | 27 | function setVoter(address _voter) external { 28 | voter = _voter; 29 | } 30 | 31 | function setPlatformVoter(address _voter) external { 32 | platformVoter = _voter; 33 | } 34 | 35 | function setLiquidator(address value) external { 36 | liquidator = value; 37 | } 38 | 39 | function setInvestFund(address value) external { 40 | investFund = value; 41 | } 42 | 43 | function setForwarder(address value) external { 44 | forwarder = value; 45 | } 46 | 47 | function setVeDistributor(address value) external { 48 | veDistributor = value; 49 | } 50 | 51 | function addVault(address vault) external { 52 | vaults.push(vault); 53 | } 54 | 55 | function addOperator(address operator) external { 56 | operators[operator] = true; 57 | } 58 | 59 | function updateProxies(address[] memory proxies, address[] memory newLogics) external { 60 | require(proxies.length == newLogics.length, "Wrong arrays"); 61 | for (uint i; i < proxies.length; i++) { 62 | IProxyControlled(proxies[i]).upgrade(newLogics[i]); 63 | } 64 | } 65 | 66 | function vaultsList() external view override returns (address[] memory) { 67 | return vaults; 68 | } 69 | 70 | function vaultsListLength() external override view returns (uint) { 71 | return vaults.length; 72 | } 73 | 74 | function isValidVault(address _vault) external view override returns (bool) { 75 | for (uint i; i < vaults.length; i++) { 76 | if (_vault == vaults[i]) { 77 | return true; 78 | } 79 | } 80 | return false; 81 | } 82 | 83 | function isOperator(address _adr) external view override returns (bool) { 84 | return operators[_adr]; 85 | } 86 | 87 | /// @dev See {IERC165-supportsInterface}. 88 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 89 | return interfaceId == InterfaceIds.I_CONTROLLER || super.supportsInterface(interfaceId); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /contracts/test/IMockToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface IMockToken { 6 | 7 | function decimals() external view returns (uint8); 8 | 9 | function mint(address to, uint amount) external; 10 | 11 | function burn(address from, uint amount) external; 12 | } 13 | -------------------------------------------------------------------------------- /contracts/test/MockBribe.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../proxy/ControllableV3.sol"; 6 | 7 | contract MockBribe is ControllableV3 { 8 | 9 | uint public epoch; 10 | mapping(address => mapping(address => bool)) internal rewardTokens; 11 | 12 | function init(address controller_) external initializer { 13 | __Controllable_init(controller_); 14 | } 15 | 16 | function isRewardToken(address st, address rt) external view returns (bool) { 17 | return rewardTokens[st][rt]; 18 | } 19 | 20 | function registerRewardToken(address st, address rt) external { 21 | rewardTokens[st][rt] = true; 22 | } 23 | 24 | function notifyRewardAmount(address, address token, uint amount) external { 25 | IERC20(token).transferFrom(msg.sender, address(this), amount); 26 | } 27 | 28 | function notifyForNextEpoch(address, address token, uint amount) external { 29 | IERC20(token).transferFrom(msg.sender, address(this), amount); 30 | } 31 | 32 | function notifyDelayedRewards(address, address, uint) external { 33 | // noop 34 | } 35 | 36 | /// @dev See {IERC165-supportsInterface}. 37 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 38 | return interfaceId == InterfaceIds.I_BRIBE || super.supportsInterface(interfaceId); 39 | } 40 | 41 | function increaseEpoch() external { 42 | epoch++; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /contracts/test/MockForwarder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../lib/InterfaceIds.sol"; 6 | 7 | contract MockForwarder { 8 | 9 | function registerIncome( 10 | address[] memory, 11 | uint[] memory, 12 | address, 13 | bool 14 | ) external { 15 | // noop 16 | } 17 | 18 | function distributeAll(address) external { 19 | // noop 20 | } 21 | 22 | function distribute(address) external pure { 23 | // noop 24 | } 25 | 26 | /// @dev See {IERC165-supportsInterface}. 27 | function supportsInterface(bytes4 interfaceId) public pure returns (bool) { 28 | return interfaceId == InterfaceIds.I_FORWARDER; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /contracts/test/MockGauge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../proxy/ControllableV3.sol"; 6 | 7 | contract MockGauge is ControllableV3 { 8 | 9 | function init(address controller_) external initializer { 10 | __Controllable_init(controller_); 11 | } 12 | 13 | function handleBalanceChange(address) external { 14 | // noop 15 | } 16 | 17 | /// @dev See {IERC165-supportsInterface}. 18 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 19 | return interfaceId == InterfaceIds.I_GAUGE || super.supportsInterface(interfaceId); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /contracts/test/MockLiquidator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../interfaces/ITetuLiquidator.sol"; 6 | import "../interfaces/IERC20.sol"; 7 | 8 | contract MockLiquidator is ITetuLiquidator { 9 | 10 | uint internal price = 100_000 * 1e18; 11 | string internal error = ""; 12 | uint internal routeLength = 1; 13 | bool internal useTokensToCalculatePrice; 14 | 15 | function setPrice(uint value) external { 16 | price = value; 17 | } 18 | 19 | function setUseTokensToCalculatePrice(bool value) external { 20 | useTokensToCalculatePrice = value; 21 | } 22 | 23 | function setError(string memory value) external { 24 | error = value; 25 | } 26 | 27 | function setRouteLength(uint value) external { 28 | routeLength = value; 29 | } 30 | 31 | function getPrice(address, address, uint tokens) external view override returns (uint) { 32 | return useTokensToCalculatePrice 33 | ? price * tokens 34 | : price; 35 | } 36 | 37 | function getPriceForRoute(PoolData[] memory, uint) external view override returns (uint) { 38 | return price; 39 | } 40 | 41 | function isRouteExist(address, address) external pure override returns (bool) { 42 | return true; 43 | } 44 | 45 | function buildRoute( 46 | address tokenIn, 47 | address tokenOut 48 | ) external view override returns (PoolData[] memory route, string memory errorMessage) { 49 | if (routeLength == 1) { 50 | route = new PoolData[](1); 51 | route[0].tokenIn = tokenIn; 52 | route[0].tokenOut = tokenOut; 53 | } else { 54 | route = new PoolData[](0); 55 | } 56 | return (route, error); 57 | } 58 | 59 | function liquidate( 60 | address, 61 | address tokenOut, 62 | uint amount, 63 | uint 64 | ) external override { 65 | IERC20(tokenOut).transfer(msg.sender, amount); 66 | } 67 | 68 | function liquidateWithRoute( 69 | PoolData[] memory route, 70 | uint amount, 71 | uint 72 | ) external override { 73 | IERC20(route[0].tokenIn).transferFrom(msg.sender, address(this), amount); 74 | IERC20(route[route.length - 1].tokenOut).transfer(msg.sender, amount); 75 | } 76 | 77 | function addLargestPools(PoolData[] memory /*_pools*/, bool /*rewrite*/) external pure { 78 | // noop 79 | } 80 | 81 | function addBlueChipsPools(PoolData[] memory /*_pools*/, bool /*rewrite*/) external pure { 82 | // noop 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /contracts/test/MockPawnshop.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../interfaces/IERC721.sol"; 6 | import "../interfaces/IVeTetu.sol"; 7 | import "../interfaces/IERC721Receiver.sol"; 8 | 9 | contract MockPawnshop is IERC721Receiver{ 10 | 11 | function transfer(address nft, address from, address to, uint id) external { 12 | IERC721(nft).safeTransferFrom(from, to, id); 13 | } 14 | 15 | function transferAndGetBalance(address nft, address from, address to, uint id) external returns (uint){ 16 | IERC721(nft).safeTransferFrom(from, to, id); 17 | return IVeTetu(nft).balanceOfNFT(id); 18 | } 19 | 20 | function doubleTransfer(address nft, address from, address to, uint id) external { 21 | IERC721(nft).safeTransferFrom(from, to, id); 22 | IERC721(nft).safeTransferFrom(to, from, id); 23 | IERC721(nft).safeTransferFrom(from, to, id); 24 | } 25 | 26 | function veFlashTransfer(address ve, uint tokenId) external { 27 | IERC721(ve).safeTransferFrom(msg.sender, address(this), tokenId); 28 | require(IVeTetu(ve).balanceOfNFT(tokenId) == 0, "not zero balance"); 29 | IVeTetu(ve).checkpoint(); 30 | IVeTetu(ve).checkpoint(); 31 | IVeTetu(ve).checkpoint(); 32 | IVeTetu(ve).checkpoint(); 33 | IERC721(ve).safeTransferFrom(address(this), msg.sender, tokenId); 34 | } 35 | 36 | function onERC721Received( 37 | address, 38 | address, 39 | uint256, 40 | bytes memory 41 | ) public virtual override returns (bytes4) { 42 | return this.onERC721Received.selector; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /contracts/test/MockPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../interfaces/IERC20.sol"; 6 | 7 | contract MockPool { 8 | 9 | function withdraw(address token, uint amount) external { 10 | IERC20(token).transfer(msg.sender, amount); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /contracts/test/MockSplitter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../interfaces/ISplitter.sol"; 6 | import "../interfaces/IERC20.sol"; 7 | import "../interfaces/ITetuVaultV2.sol"; 8 | import "../proxy/ControllableV3.sol"; 9 | 10 | contract MockSplitter is ISplitter, ControllableV3 { 11 | 12 | address public override asset; 13 | address public override vault; 14 | uint public slippage; 15 | address[] public strategies; 16 | uint public constant HARDWORK_DELAY = 12 hours; 17 | mapping(address => bool) public pausedStrategies; 18 | mapping(address => uint) public lastHardWorks; 19 | 20 | function init(address controller_, address _asset, address _vault) external initializer override { 21 | __Controllable_init(controller_); 22 | asset = _asset; 23 | vault = _vault; 24 | } 25 | 26 | function coverPossibleStrategyLoss(uint /*earned*/, uint /*lost*/) external pure { 27 | // noop 28 | } 29 | 30 | function pauseInvesting(address strategy) external { 31 | require(!pausedStrategies[strategy], "SS: Paused"); 32 | pausedStrategies[strategy] = true; 33 | } 34 | 35 | function continueInvesting(address strategy, uint /*apr*/) external { 36 | require(pausedStrategies[strategy], "SS: Not paused"); 37 | pausedStrategies[strategy] = false; 38 | } 39 | 40 | function setSlippage(uint value) external { 41 | slippage = value; 42 | } 43 | 44 | function withdrawAllToVault() external override { 45 | withdrawToVault(IERC20(asset).balanceOf(address(this))); 46 | } 47 | 48 | function withdrawToVault(uint256 amount) public override { 49 | uint toSend = amount - amount * slippage / 1000; 50 | if (slippage != 0) { 51 | IERC20(asset).transfer(controller(), amount - toSend); 52 | } 53 | IERC20(asset).transfer(vault, toSend); 54 | } 55 | 56 | function doHardWork() external override { 57 | // noop 58 | } 59 | 60 | function investAll() external override { 61 | // noop 62 | } 63 | 64 | function totalAssets() external view override returns (uint256) { 65 | return IERC20(asset).balanceOf(address(this)); 66 | } 67 | 68 | function isHardWorking() external pure override returns (bool) { 69 | return false; 70 | } 71 | 72 | function lost(uint amount) external { 73 | IERC20(asset).transfer(msg.sender, amount); 74 | } 75 | 76 | function coverLoss(uint amount) external { 77 | ITetuVaultV2(vault).coverLoss(amount); 78 | } 79 | 80 | /// @dev See {IERC165-supportsInterface}. 81 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 82 | return interfaceId == InterfaceIds.I_SPLITTER || super.supportsInterface(interfaceId); 83 | } 84 | 85 | function strategiesLength() external view returns (uint) { 86 | return strategies.length; 87 | } 88 | 89 | function rebalance(uint /*percent*/, uint /*lossTolerance*/) external pure override {} 90 | function getStrategyCapacity(address /*strategy*/) external pure override returns (uint) {return 0;} 91 | } 92 | -------------------------------------------------------------------------------- /contracts/test/MockStakingToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../openzeppelin/ERC20Upgradeable.sol"; 6 | import "../interfaces/IGauge.sol"; 7 | 8 | contract MockStakingToken is ERC20Upgradeable { 9 | 10 | uint8 internal immutable _decimals; 11 | IGauge internal immutable gauge; 12 | 13 | constructor( 14 | string memory name_, 15 | string memory symbol_, 16 | uint8 decimals_, 17 | address gauge_ 18 | ) { 19 | _decimals = decimals_; 20 | gauge = IGauge(gauge_); 21 | _init(name_, symbol_); 22 | } 23 | 24 | function _init( 25 | string memory name_, 26 | string memory symbol_ 27 | ) internal initializer { 28 | __ERC20_init(name_, symbol_); 29 | } 30 | 31 | function decimals() public view override returns (uint8) { 32 | return _decimals; 33 | } 34 | 35 | function mint(address to, uint amount) external { 36 | _mint(to, amount); 37 | } 38 | 39 | function _afterTokenTransfer( 40 | address from, 41 | address to, 42 | uint 43 | ) internal override { 44 | gauge.handleBalanceChange(from); 45 | gauge.handleBalanceChange(to); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/test/MockStrategySimple.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../proxy/ControllableV3.sol"; 6 | import "../interfaces/IStrategyV2.sol"; 7 | import "../interfaces/IERC20.sol"; 8 | 9 | contract MockStrategySimple is ControllableV3, IStrategyV2 { 10 | 11 | string public constant override NAME = "mock strategy"; 12 | string public override strategySpecificName = "mock strategy1"; 13 | string public constant override PLATFORM = "test"; 14 | string public constant override STRATEGY_VERSION = "1.0.0"; 15 | 16 | address public override splitter; 17 | address public override asset; 18 | bool public override isReadyToHardWork; 19 | uint public override compoundRatio; 20 | 21 | uint internal slippage; 22 | uint internal lastEarned; 23 | uint internal lastLost; 24 | 25 | uint internal _capacity; 26 | address public override performanceReceiver; 27 | uint public override performanceFee; 28 | 29 | function init( 30 | address controller_, 31 | address _splitter, 32 | address _asset 33 | ) external initializer { 34 | __Controllable_init(controller_); 35 | splitter = _splitter; 36 | asset = _asset; 37 | isReadyToHardWork = true; 38 | _capacity = type(uint).max; // unlimited capacity by default 39 | performanceReceiver = IController(controller_).governance(); 40 | performanceFee = 10_000; 41 | } 42 | 43 | function totalAssets() public view override returns (uint) { 44 | return IERC20(asset).balanceOf(address(this)); 45 | } 46 | 47 | function withdrawAllToSplitter() external override returns (uint strategyLoss) { 48 | return withdrawToSplitter(totalAssets()); 49 | } 50 | 51 | function withdrawToSplitter(uint amount) public override returns (uint strategyLoss) { 52 | uint _slippage = amount * slippage / 100; 53 | if (_slippage != 0) { 54 | IERC20(asset).transfer(controller(), _slippage); 55 | } 56 | IERC20(asset).transfer(splitter, amount - _slippage); 57 | return _slippage; 58 | } 59 | 60 | function investAll( 61 | uint amount_, 62 | bool updateTotalAssetsBeforeInvest_ 63 | ) external pure override returns ( 64 | uint strategyLoss 65 | ) { 66 | amount_; // hide warning 67 | updateTotalAssetsBeforeInvest_; // hide warning 68 | // noop 69 | return strategyLoss; 70 | } 71 | 72 | function doHardWork() external view override returns (uint earned, uint lost) { 73 | return (lastEarned, lastLost); 74 | } 75 | 76 | function setLast(uint earned, uint lost) external { 77 | lastEarned = earned; 78 | lastLost = lost; 79 | } 80 | 81 | function setSlippage(uint value) external { 82 | slippage = value; 83 | } 84 | 85 | function setCompoundRatio(uint value) external override { 86 | compoundRatio = value; 87 | } 88 | 89 | /// @notice Max amount that can be deposited to the strategy, see SCB-593 90 | function capacity() external view override returns (uint) { 91 | return _capacity; 92 | } 93 | 94 | function setCapacity(uint capacity_) external { 95 | _capacity = capacity_; 96 | } 97 | 98 | /// @notice Set performance fee and receiver 99 | function setupPerformanceFee(uint fee_, address receiver_) external { 100 | performanceFee = fee_; 101 | performanceReceiver = receiver_; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /contracts/test/MockStrategyStrict.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../interfaces/IERC20.sol"; 6 | import "../strategy/StrategyStrictBase.sol"; 7 | import "./MockPool.sol"; 8 | 9 | contract MockStrategyStrict is StrategyStrictBase { 10 | 11 | string public constant override NAME = "mock strategy strict"; 12 | string public constant override PLATFORM = "test"; 13 | string public constant override STRATEGY_VERSION = "1.0.0"; 14 | 15 | bool public override isReadyToHardWork; 16 | 17 | uint internal slippage; 18 | uint internal slippageDeposit; 19 | uint internal lastEarned; 20 | uint internal lastLost; 21 | 22 | MockPool public pool; 23 | 24 | constructor() { 25 | isReadyToHardWork = true; 26 | pool = new MockPool(); 27 | } 28 | 29 | function doHardWork() external view override returns (uint earned, uint lost) { 30 | return (lastEarned, lastLost); 31 | } 32 | 33 | /// @dev Amount of underlying assets invested to the pool. 34 | function investedAssets() public view override returns (uint) { 35 | return IERC20(asset).balanceOf(address(pool)); 36 | } 37 | 38 | /// @dev Deposit given amount to the pool. 39 | function _depositToPool(uint amount) internal override { 40 | uint _slippage = amount * slippageDeposit / 100_000; 41 | if (_slippage != 0) { 42 | IERC20(asset).transfer(vault, _slippage); 43 | } 44 | if (amount - _slippage != 0) { 45 | IERC20(asset).transfer(address(pool), amount - _slippage); 46 | } 47 | } 48 | 49 | /// @dev Withdraw given amount from the pool. 50 | function _withdrawFromPool(uint amount) internal override returns (uint investedAssetsUSD, uint assetPrice) { 51 | assetPrice = 1e18; 52 | investedAssetsUSD = amount; 53 | pool.withdraw(asset, amount); 54 | uint _slippage = amount * slippage / 100_000; 55 | if (_slippage != 0) { 56 | IERC20(asset).transfer(vault, _slippage); 57 | } 58 | } 59 | 60 | /// @dev Withdraw all from the pool. 61 | function _withdrawAllFromPool() internal override returns (uint investedAssetsUSD, uint assetPrice) { 62 | assetPrice = 1e18; 63 | investedAssetsUSD = investedAssets(); 64 | pool.withdraw(asset, investedAssets()); 65 | uint _slippage = totalAssets() * slippage / 100_000; 66 | if (_slippage != 0) { 67 | IERC20(asset).transfer(vault, _slippage); 68 | } 69 | return (0, 0); 70 | } 71 | 72 | /// @dev If pool support emergency withdraw need to call it for emergencyExit() 73 | function _emergencyExitFromPool() internal override { 74 | pool.withdraw(asset, investedAssets()); 75 | } 76 | 77 | /// @dev Claim all possible rewards. 78 | function _claim() internal override { 79 | // noop 80 | } 81 | 82 | function setSlippage(uint value) external { 83 | slippage = value; 84 | } 85 | 86 | function setSlippageDeposit(uint value) external { 87 | slippageDeposit = value; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /contracts/test/MockToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../openzeppelin/ERC20Upgradeable.sol"; 6 | 7 | contract MockToken is ERC20Upgradeable { 8 | 9 | uint8 internal _decimals; 10 | 11 | constructor( 12 | string memory name_, 13 | string memory symbol_, 14 | uint8 decimals_ 15 | ) { 16 | _init(name_, symbol_, decimals_); 17 | } 18 | 19 | function _init( 20 | string memory name_, 21 | string memory symbol_, 22 | uint8 decimals_ 23 | ) internal initializer { 24 | __ERC20_init(name_, symbol_); 25 | _decimals = decimals_; 26 | } 27 | 28 | function decimals() public view override returns (uint8) { 29 | return _decimals; 30 | } 31 | 32 | function mint(address to, uint amount) external { 33 | _mint(to, amount); 34 | } 35 | 36 | function burn(address from, uint amount) external { 37 | _burn(from, amount); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /contracts/test/MockVaultSimple.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../proxy/ControllableV3.sol"; 6 | import "../vault/ERC4626Upgradeable.sol"; 7 | 8 | contract MockVaultSimple is ERC4626Upgradeable, ControllableV3 { 9 | using SafeERC20 for IERC20; 10 | 11 | uint constant public FEE_DENOMINATOR = 100; 12 | 13 | 14 | function init( 15 | address controller_, 16 | IERC20 _asset, 17 | string memory _name, 18 | string memory _symbol 19 | ) external initializer { 20 | __ERC4626_init(_asset, _name, _symbol); 21 | __Controllable_init(controller_); 22 | } 23 | 24 | function totalAssets() public view override returns (uint) { 25 | return _asset.balanceOf(address(this)); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /contracts/test/MockVeDist.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../proxy/ControllableV3.sol"; 6 | 7 | contract MockVeDist { 8 | 9 | function checkpoint() external { 10 | // noop 11 | } 12 | 13 | function checkpointTotalSupply() external { 14 | // noop 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /contracts/test/MockVoter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../interfaces/IVeTetu.sol"; 6 | import "../interfaces/IVoter.sol"; 7 | import "../interfaces/IERC20.sol"; 8 | 9 | contract MockVoter is IVoter { 10 | 11 | address public override ve; 12 | mapping(uint => uint) public mockVotes; 13 | 14 | constructor(address _ve) { 15 | ve = _ve; 16 | } 17 | 18 | function votedVaultsLength(uint veId) external view override returns (uint) { 19 | return mockVotes[veId]; 20 | } 21 | 22 | function attachTokenToGauge(address, uint tokenId, address) external override { 23 | if (tokenId > 0) { 24 | IVeTetu(ve).attachToken(tokenId); 25 | } 26 | } 27 | 28 | function detachTokenFromGauge(address, uint tokenId, address) external override { 29 | if (tokenId > 0) { 30 | IVeTetu(ve).detachToken(tokenId); 31 | } 32 | } 33 | 34 | function distribute(address) external override { 35 | // noop 36 | } 37 | 38 | function distributeAll() external override { 39 | // noop 40 | } 41 | 42 | function voting(uint id) external { 43 | mockVotes[id]++; 44 | } 45 | 46 | function abstain(uint id) external { 47 | mockVotes[id]--; 48 | } 49 | 50 | function detachTokenFromAll(uint tokenId, address) external override { 51 | while (IVeTetu(ve).attachments(tokenId) > 0) { 52 | IVeTetu(ve).detachToken(tokenId); 53 | } 54 | mockVotes[tokenId] = 0; 55 | } 56 | 57 | function notifyRewardAmount(uint amount) external override { 58 | IERC20(IVeTetu(ve).tokens(0)).transferFrom(msg.sender, address(this), amount); 59 | } 60 | 61 | function isVotesExist(uint veId) external view override returns (bool) { 62 | return mockVotes[veId] > 0; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /contracts/test/Multicall.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | ////// /nix/store/im7ll7dx8gsw2da9k5xwbf8pbjfli2hc-multicall-df1e59d/src/Multicall.sol 6 | /* pragma solidity >=0.5.0; */ 7 | /* pragma experimental ABIEncoderV2; */ 8 | 9 | /// @title Multicall - Aggregate results from multiple read-only function calls 10 | /// @author Michael Elliot 11 | /// @author Joshua Levine 12 | /// @author Nick Johnson 13 | contract Multicall { 14 | struct Call { 15 | address target; 16 | bytes callData; 17 | } 18 | 19 | function aggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes[] memory returnData) { 20 | blockNumber = block.number; 21 | returnData = new bytes[](calls.length); 22 | for (uint256 i = 0; i < calls.length; i++) { 23 | (bool success, bytes memory ret) = calls[i].target.call(calls[i].callData); 24 | require(success); 25 | returnData[i] = ret; 26 | } 27 | } 28 | 29 | // Helper functions 30 | function getEthBalance(address addr) public view returns (uint256 balance) { 31 | balance = addr.balance; 32 | } 33 | 34 | function getBlockHash(uint256 blockNumber) public view returns (bytes32 blockHash) { 35 | blockHash = blockhash(blockNumber); 36 | } 37 | 38 | function getLastBlockHash() public view returns (bytes32 blockHash) { 39 | blockHash = blockhash(block.number - 1); 40 | } 41 | 42 | function getCurrentBlockTimestamp() public view returns (uint256 timestamp) { 43 | timestamp = block.timestamp; 44 | } 45 | 46 | function getCurrentBlockDifficulty() public view returns (uint256 difficulty) { 47 | difficulty = block.difficulty; 48 | } 49 | 50 | function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) { 51 | gaslimit = block.gaslimit; 52 | } 53 | 54 | function getCurrentBlockCoinbase() public view returns (address coinbase) { 55 | coinbase = block.coinbase; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /contracts/test/SlotsTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../proxy/ControllableV3.sol"; 6 | 7 | contract SlotsTest is ControllableV3 { 8 | struct SomeStruct { 9 | uint a; 10 | uint b; 11 | } 12 | 13 | bytes32 internal constant _SLOT = bytes32(uint256(keccak256("slot")) - 1); 14 | 15 | mapping(uint => SomeStruct) public map; 16 | 17 | function initialize(address controller_) external initializer { 18 | __Controllable_init(controller_); 19 | } 20 | 21 | function setMapA(uint index, uint a) external { 22 | map[index].a = a; 23 | } 24 | 25 | function getBytes32() external view returns (bytes32 result) { 26 | return SlotsLib.getBytes32(_SLOT); 27 | } 28 | 29 | function getAddress() external view returns (address result) { 30 | return SlotsLib.getAddress(_SLOT); 31 | } 32 | 33 | function getUint() external view returns (uint result) { 34 | return SlotsLib.getUint(_SLOT); 35 | } 36 | 37 | function arrayLength() external view returns (uint result) { 38 | return SlotsLib.arrayLength(_SLOT); 39 | } 40 | 41 | function addressAt(uint index) external view returns (address result) { 42 | return SlotsLib.addressAt(_SLOT, index); 43 | } 44 | 45 | function uintAt(uint index) external view returns (uint result) { 46 | return SlotsLib.uintAt(_SLOT, index); 47 | } 48 | 49 | function setByte32(bytes32 value) external { 50 | SlotsLib.set(_SLOT, value); 51 | } 52 | 53 | function setAddress(address value) external { 54 | SlotsLib.set(_SLOT, value); 55 | } 56 | 57 | function setUint(uint value) external { 58 | SlotsLib.set(_SLOT, value); 59 | } 60 | 61 | function setAt(uint index, address value) external { 62 | SlotsLib.setAt(_SLOT, index, value); 63 | } 64 | 65 | function setAt(uint index, uint value) external { 66 | SlotsLib.setAt(_SLOT, index, value); 67 | } 68 | 69 | function setLength(uint length) external { 70 | SlotsLib.setLength(_SLOT, length); 71 | } 72 | 73 | function push(address value) external { 74 | SlotsLib.push(_SLOT, value); 75 | } 76 | 77 | } 78 | 79 | 80 | /// @dev extending SomeStruct with new member 81 | contract SlotsTest2 is ControllableV3 { 82 | struct SomeStruct { 83 | uint a; 84 | uint b; 85 | } 86 | 87 | mapping(uint => SomeStruct) public map; 88 | 89 | function initialize(address controller_) external initializer { 90 | __Controllable_init(controller_); 91 | } 92 | 93 | function setMapA(uint index, uint a) external { 94 | map[index].a = a; 95 | } 96 | 97 | function setMapB(uint index, uint b) external { 98 | map[index].b = b; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /contracts/test/StakelessMultiPoolMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../reward/StakelessMultiPoolBase.sol"; 6 | 7 | contract StakelessMultiPoolMock is StakelessMultiPoolBase { 8 | 9 | mapping(address => bool) public stakingTokens; 10 | 11 | function init( 12 | address controller_, 13 | address[] memory _stakingTokens, 14 | address _defaultRewardToken, 15 | uint duration_ 16 | ) external initializer { 17 | __MultiPool_init(controller_, _defaultRewardToken, duration_); 18 | for (uint i; i < _stakingTokens.length; i++) { 19 | stakingTokens[_stakingTokens[i]] = true; 20 | } 21 | } 22 | 23 | // for test 2 deposits in one tx 24 | function testDoubleDeposit(address stakingToken, uint amount) external { 25 | uint amount0 = amount / 2; 26 | uint amount1 = amount - amount0; 27 | _registerBalanceIncreasing(stakingToken, msg.sender, amount0); 28 | _registerBalanceIncreasing(stakingToken, msg.sender, amount1); 29 | } 30 | 31 | // for test 2 withdraws in one tx 32 | function testDoubleWithdraw(address stakingToken, uint amount) external { 33 | uint amount0 = amount / 2; 34 | uint amount1 = amount - amount0; 35 | _registerBalanceDecreasing(stakingToken, msg.sender, amount0); 36 | _registerBalanceDecreasing(stakingToken, msg.sender, amount1); 37 | } 38 | 39 | function deposit(address stakingToken, uint amount) external { 40 | _registerBalanceIncreasing(stakingToken, msg.sender, amount); 41 | } 42 | 43 | function withdraw(address stakingToken, uint amount) external { 44 | _registerBalanceDecreasing(stakingToken, msg.sender, amount); 45 | } 46 | 47 | function getReward(address stakingToken, address account, address[] memory tokens) external { 48 | _getReward(stakingToken, account, tokens, account); 49 | } 50 | 51 | function notifyRewardAmount(address stakingToken, address token, uint amount) external { 52 | _notifyRewardAmount(stakingToken, token, amount, true); 53 | } 54 | 55 | function isStakeToken(address token) public view override returns (bool) { 56 | return stakingTokens[token]; 57 | } 58 | 59 | /// @dev See {IERC165-supportsInterface}. 60 | function supportsInterface(bytes4 interfaceId) public view virtual override(StakelessMultiPoolBase) returns (bool) { 61 | return interfaceId == InterfaceIds.I_MULTI_POOL || super.supportsInterface(interfaceId); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /contracts/test/StrategyV2BaseEmpty.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity 0.8.17; 3 | 4 | import "../strategy/StrategyBaseV2.sol"; 5 | 6 | contract StrategyV2BaseEmpty is StrategyBaseV2 { 7 | string public constant override NAME = "empty strategy"; 8 | string public constant override PLATFORM = "test"; 9 | string public constant override STRATEGY_VERSION = "1.0.0"; 10 | 11 | function init() external { 12 | __StrategyBase_init(address(0), address(0)); 13 | } 14 | 15 | function _claim() internal pure override returns (address[] memory rewardTokens, uint[] memory amounts) {} 16 | 17 | function _depositToPool(uint amount, bool /*updateTotalAssetsBeforeInvest_*/) internal override returns (uint strategyLoss) {} 18 | 19 | function _emergencyExitFromPool() internal virtual override {} 20 | 21 | function _withdrawAllFromPool() internal override returns (uint expectedWithdrewUSD, uint assetPrice, uint strategyLoss) {} 22 | 23 | function _withdrawFromPool(uint amount) internal override returns (uint expectedWithdrewUSD, uint assetPrice, uint strategyLoss) {} 24 | 25 | function capacity() external view returns (uint) {} 26 | 27 | function doHardWork() external returns (uint earned, uint lost) {} 28 | 29 | function isReadyToHardWork() external view returns (bool) {} 30 | 31 | function investedAssets() public view virtual override returns (uint) {} 32 | } 33 | -------------------------------------------------------------------------------- /contracts/test/StrategyV3BaseEmpty.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity 0.8.17; 3 | 4 | import "../strategy/StrategyBaseV3.sol"; 5 | 6 | contract StrategyV3BaseEmpty is StrategyBaseV3 { 7 | string public constant override NAME = "empty strategy"; 8 | string public constant override PLATFORM = "test"; 9 | string public constant override STRATEGY_VERSION = "1.0.0"; 10 | 11 | function init() external { 12 | __StrategyBase_init(address(0), address(0)); 13 | } 14 | 15 | function _claim() internal pure override returns (address[] memory rewardTokens, uint[] memory amounts) {} 16 | 17 | function _depositToPool(uint amount, bool /*updateTotalAssetsBeforeInvest_*/) internal override returns (uint strategyLoss) {} 18 | 19 | function _emergencyExitFromPool() internal virtual override {} 20 | 21 | function _withdrawAllFromPool() internal override returns (uint expectedWithdrewUSD, uint assetPrice, uint strategyLoss) {} 22 | 23 | function _withdrawFromPool(uint amount) internal override returns (uint expectedWithdrewUSD, uint assetPrice, uint strategyLoss) {} 24 | 25 | function capacity() external view returns (uint) {} 26 | 27 | function doHardWork() external returns (uint earned, uint lost) {} 28 | 29 | function isReadyToHardWork() external view returns (bool) {} 30 | 31 | function investedAssets() public view virtual override returns (uint) {} 32 | } 33 | -------------------------------------------------------------------------------- /contracts/test/StringLibFacade.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity 0.8.17; 3 | 4 | import "../lib/StringLib.sol"; 5 | 6 | contract StringLibFacade { 7 | 8 | function uintToString(uint value) external pure returns (string memory) { 9 | return StringLib.toString(value); 10 | } 11 | 12 | function toAsciiString(address x) external pure returns (string memory) { 13 | return StringLib.toAsciiString(x); 14 | } 15 | 16 | function char(bytes1 b) external pure returns (bytes1 c) { 17 | return StringLib.char(b); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /contracts/test/TetuERC165Test.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity 0.8.17; 3 | 4 | import "../tools/TetuERC165.sol"; 5 | 6 | /// @author bogdoslav 7 | contract TetuERC165Test is TetuERC165 { 8 | 9 | // ************************************************************* 10 | // EXTERNAL FUNCTIONS 11 | // ************************************************************* 12 | 13 | function isInterfaceSupported(address contractAddress, bytes4 interfaceId) external view returns (bool) { 14 | return _isInterfaceSupported(contractAddress, interfaceId); 15 | } 16 | 17 | function requireInterface(address contractAddress, bytes4 interfaceId) external view { 18 | _requireInterface(contractAddress, interfaceId); 19 | } 20 | 21 | function isERC20(address contractAddress) external view returns (bool) { 22 | return _isERC20(contractAddress); 23 | } 24 | 25 | function requireERC20(address contractAddress) external view { 26 | _requireERC20(contractAddress); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /contracts/test/WrongNFTReceiver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | contract WrongNFTReceiver { 6 | 7 | function onERC721Received( 8 | address, 9 | address, 10 | uint256, 11 | bytes calldata 12 | ) external pure returns (bytes4) { 13 | revert("stub revert"); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /contracts/tools/BribeDistribution.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../interfaces/IERC20.sol"; 6 | import "../interfaces/IVeDistributor.sol"; 7 | 8 | contract BribeDistribution { 9 | // 10 | // string public constant VERSION = "1.0.0"; 11 | // 12 | // address public owner; 13 | // address public pendingOwner; 14 | // address public operator; 15 | // 16 | // IVeDistributor public immutable veDist; 17 | // address public immutable token; 18 | // uint public round; 19 | // 20 | // constructor(address veDist_, address _token) { 21 | // veDist = IVeDistributor(veDist_); 22 | // token = _token; 23 | // owner = msg.sender; 24 | // } 25 | // 26 | // modifier onlyOwner() { 27 | // require(msg.sender == owner, "NOT_OWNER"); 28 | // _; 29 | // } 30 | // 31 | // modifier onlyOperator() { 32 | // require(msg.sender == operator || msg.sender == owner, "NOT_OPERATOR"); 33 | // _; 34 | // } 35 | // 36 | // function offerOwnership(address newOwner) external onlyOwner { 37 | // require(newOwner != address(0), "ZERO_ADDRESS"); 38 | // pendingOwner = newOwner; 39 | // } 40 | // 41 | // function acceptOwnership() external { 42 | // require(msg.sender == pendingOwner, "NOT_OWNER"); 43 | // owner = pendingOwner; 44 | // } 45 | // 46 | // function setOperator(address operator_) external onlyOwner { 47 | // operator = operator_; 48 | // } 49 | // 50 | // ////////////////// MAIN LOGIC ////////////////////// 51 | // 52 | // function autoNotify() external onlyOperator { 53 | // _notify(IERC20(token).balanceOf(msg.sender), round % 2 == 0); 54 | // round++; 55 | // } 56 | // 57 | // function manualNotify(uint amount, bool fresh) external onlyOperator { 58 | // _notify(amount, fresh); 59 | // } 60 | // 61 | // function _notify(uint amount, bool fresh) internal { 62 | // if (amount != 0) { 63 | // IERC20(token).transferFrom(msg.sender, address(this), amount); 64 | // } 65 | // 66 | // uint toRewards = IERC20(token).balanceOf(address(this)); 67 | // require(toRewards != 0, "ZERO_BALANCE"); 68 | // 69 | // // assume we will have bribes once per 2 weeks. Need to use a half of the current balance in case of start of new 2 weeks epoch. 70 | // if (fresh) { 71 | // toRewards = toRewards / 2; 72 | // } 73 | // 74 | // IVeDistributor _veDist = veDist; 75 | // 76 | // IERC20(token).transfer(address(_veDist), toRewards); 77 | // _veDist.checkpoint(); 78 | // _veDist.checkpointTotalSupply(); 79 | // } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /contracts/tools/DepositHelperBaseChain.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "./DepositHelperAbstract.sol"; 6 | 7 | interface IRouter { 8 | function addLiquidity( 9 | address tokenA, 10 | address tokenB, 11 | bool stable, 12 | uint amountADesired, 13 | uint amountBDesired, 14 | uint amountAMin, 15 | uint amountBMin, 16 | address to, 17 | uint deadline 18 | ) external returns (uint amountA, uint amountB, uint liquidity); 19 | } 20 | 21 | contract DepositHelperBaseChain is DepositHelperAbstract { 22 | using SafeERC20 for IERC20; 23 | 24 | address public constant TETU_tUSDbC_AERODROME_LP = 0x924bb74AD42314E4434af5df984cca28b0529337; 25 | address public constant ASSET0 = 0x5E42c17CAEab64527D9d80d506a3FE01179afa02; // TETU 26 | address public constant ASSET1 = 0x68f0a05FDc8773d9a5Fd1304ca411ACc234ce22c; // tUSDbC 27 | IRouter public constant AERODROME_ROUTER = IRouter(0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43); 28 | 29 | constructor(address _oneInchRouter) DepositHelperAbstract(_oneInchRouter) { 30 | } 31 | 32 | function _convertToVeTetuLpUnderlying( 33 | bytes memory asset0SwapData, 34 | bytes memory asset1SwapData, 35 | address tokenIn, 36 | uint amountIn 37 | ) internal override returns (uint lpBalance, address pool){ 38 | pool = TETU_tUSDbC_AERODROME_LP; 39 | 40 | IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn); 41 | _approveIfNeeds(tokenIn, amountIn, oneInchRouter); 42 | 43 | if (tokenIn != ASSET0) { 44 | (bool success,bytes memory result) = oneInchRouter.call(asset0SwapData); 45 | require(success, string(result)); 46 | } 47 | 48 | if (tokenIn != ASSET1) { 49 | (bool success,bytes memory result) = oneInchRouter.call(asset1SwapData); 50 | require(success, string(result)); 51 | } 52 | 53 | uint amount0 = IERC20(ASSET0).balanceOf(address(this)); 54 | uint amount1 = IERC20(ASSET1).balanceOf(address(this)); 55 | 56 | _approveIfNeeds(ASSET0, amount0, address(AERODROME_ROUTER)); 57 | _approveIfNeeds(ASSET1, amount1, address(AERODROME_ROUTER)); 58 | 59 | AERODROME_ROUTER.addLiquidity( 60 | ASSET0, 61 | ASSET1, 62 | false, 63 | amount0, 64 | amount1, 65 | 0, 66 | 0, 67 | address(this), 68 | block.timestamp 69 | ); 70 | 71 | _sendRemainingToken(tokenIn); 72 | _sendRemainingToken(ASSET0); 73 | _sendRemainingToken(ASSET1); 74 | 75 | 76 | lpBalance = IERC20(pool).balanceOf(address(this)); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /contracts/tools/DepositHelperPolygon.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "./DepositHelperAbstract.sol"; 6 | 7 | 8 | contract DepositHelperPolygon is DepositHelperAbstract { 9 | using SafeERC20 for IERC20; 10 | 11 | address public constant BALANCER_VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; 12 | bytes32 public constant BALANCER_POOL_ID = 0xe2f706ef1f7240b803aae877c9c762644bb808d80002000000000000000008c2; // poolId of 80TETU-20USDC 13 | address public constant BALANCER_POOL_TOKEN = 0xE2f706EF1f7240b803AAe877C9C762644bb808d8; // 80TETU-20USDC 14 | address public constant ASSET0 = 0x255707B70BF90aa112006E1b07B9AeA6De021424; // TETU 15 | address public constant ASSET1 = 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174; // USDC 16 | 17 | constructor(address _oneInchRouter) DepositHelperAbstract(_oneInchRouter) { 18 | } 19 | 20 | function _convertToVeTetuLpUnderlying( 21 | bytes memory asset0SwapData, 22 | bytes memory asset1SwapData, 23 | address tokenIn, 24 | uint amountIn 25 | ) internal override returns (uint bptBalance, address pool){ 26 | address asset0 = ASSET0; 27 | address asset1 = ASSET1; 28 | IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn); 29 | 30 | _approveIfNeeds(tokenIn, amountIn, oneInchRouter); 31 | if (tokenIn != asset0) { 32 | (bool success,bytes memory result) = oneInchRouter.call(asset0SwapData); 33 | require(success, string(result)); 34 | } 35 | 36 | if (tokenIn != asset1) { 37 | (bool success,bytes memory result) = oneInchRouter.call(asset1SwapData); 38 | require(success, string(result)); 39 | } 40 | 41 | // add liquidity 42 | _joinBalancerPool(BALANCER_VAULT, BALANCER_POOL_ID, ASSET0, ASSET1, IERC20(ASSET0).balanceOf(address(this)), IERC20(ASSET1).balanceOf(address(this))); 43 | 44 | _sendRemainingToken(tokenIn); 45 | _sendRemainingToken(ASSET0); 46 | _sendRemainingToken(ASSET1); 47 | 48 | bptBalance = IERC20(BALANCER_POOL_TOKEN).balanceOf(address(this)); 49 | pool = BALANCER_POOL_TOKEN; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /contracts/tools/ISolidlyPair.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | interface ISolidlyPair { 6 | 7 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; 8 | 9 | function getReserves() external view returns (uint _reserve0, uint _reserve1, uint32 _blockTimestampLast); 10 | 11 | function getAmountOut(uint, address) external view returns (uint); 12 | 13 | function tokens() external view returns (address, address); 14 | 15 | function factory() external view returns (address); 16 | 17 | function stable() external view returns (bool); 18 | } 19 | -------------------------------------------------------------------------------- /contracts/tools/PerfFeeTreasury.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../openzeppelin/SafeERC20.sol"; 6 | 7 | contract PerfFeeTreasury { 8 | using SafeERC20 for IERC20; 9 | 10 | address public governance; 11 | address public pendingGovernance; 12 | 13 | constructor(address _governance) { 14 | governance = _governance; 15 | } 16 | 17 | modifier onlyGovernance() { 18 | require(msg.sender == governance, "NOT_GOV"); 19 | _; 20 | } 21 | 22 | function offerOwnership(address newOwner) external onlyGovernance { 23 | require(newOwner != address(0), "ZERO_ADDRESS"); 24 | pendingGovernance = newOwner; 25 | } 26 | 27 | function acceptOwnership() external { 28 | require(msg.sender == pendingGovernance, "NOT_GOV"); 29 | governance = pendingGovernance; 30 | } 31 | 32 | function claim(address[] memory tokens) external onlyGovernance { 33 | address _governance = governance; 34 | for (uint i = 0; i < tokens.length; ++i) { 35 | IERC20(tokens[i]).safeTransfer(_governance, IERC20(tokens[i]).balanceOf(address(this))); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /contracts/tools/RewardsRedirector.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../openzeppelin/SafeERC20.sol"; 6 | import "../interfaces/IGauge.sol"; 7 | import "../openzeppelin/EnumerableSet.sol"; 8 | 9 | contract RewardsRedirector { 10 | using SafeERC20 for IERC20; 11 | using EnumerableSet for EnumerableSet.AddressSet; 12 | 13 | string public constant VERSION = "1.0.0"; 14 | 15 | address public owner; 16 | address public pendingOwner; 17 | address public gauge; 18 | EnumerableSet.AddressSet internal operators; 19 | EnumerableSet.AddressSet internal redirected; 20 | mapping(address => address[]) public redirectedVaults; 21 | 22 | constructor(address _owner, address _gauge) { 23 | owner = _owner; 24 | gauge = _gauge; 25 | operators.add(_owner); 26 | } 27 | 28 | modifier onlyOwner() { 29 | require(msg.sender == owner, "!owner"); 30 | _; 31 | } 32 | 33 | modifier onlyOperator() { 34 | require(operators.contains(msg.sender), "!operator"); 35 | _; 36 | } 37 | 38 | /////////////////// VIEWS //////////////////// 39 | 40 | function getOperators() external view returns (address[] memory) { 41 | return operators.values(); 42 | } 43 | 44 | function getRedirected() external view returns (address[] memory) { 45 | return redirected.values(); 46 | } 47 | 48 | function getRedirectedVaults(address adr) external view returns (address[] memory) { 49 | return redirectedVaults[adr]; 50 | } 51 | 52 | /////////////////// GOV //////////////////// 53 | 54 | function offerOwnership(address newOwner) external onlyOwner { 55 | require(newOwner != address(0), "zero"); 56 | pendingOwner = newOwner; 57 | } 58 | 59 | function acceptOwnership() external { 60 | require(msg.sender == pendingOwner, "!owner"); 61 | owner = pendingOwner; 62 | } 63 | 64 | function changeOperator(address adr, bool status) external onlyOwner { 65 | if (status) { 66 | operators.add(adr); 67 | } else { 68 | operators.remove(adr); 69 | } 70 | } 71 | 72 | function changeRedirected(address adr, address[] calldata vaults, bool status) external onlyOwner { 73 | if (status) { 74 | redirected.add(adr); 75 | redirectedVaults[adr] = vaults; 76 | } else { 77 | redirected.remove(adr); 78 | delete redirectedVaults[adr]; 79 | } 80 | } 81 | 82 | /////////////////// MAIN LOGIC //////////////////// 83 | 84 | function claimRewards() external onlyOperator { 85 | address _gauge = gauge; 86 | address[] memory _redirected = redirected.values(); 87 | for (uint j; j < _redirected.length; ++j) { 88 | address[] memory _vaults = redirectedVaults[_redirected[j]]; 89 | for (uint i; i < _vaults.length; ++i) { 90 | IGauge(_gauge).getAllRewards(_vaults[i], _redirected[j]); 91 | } 92 | } 93 | } 94 | 95 | function withdraw(address token) external onlyOperator { 96 | IERC20(token).safeTransfer(msg.sender, IERC20(token).balanceOf(address(this))); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /contracts/tools/TetuERC165.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity 0.8.17; 3 | 4 | import "../openzeppelin/ERC165.sol"; 5 | import "../interfaces/IERC20.sol"; 6 | import "../lib/InterfaceIds.sol"; 7 | 8 | /// @dev Tetu Implementation of the {IERC165} interface extended with helper functions. 9 | /// @author bogdoslav 10 | abstract contract TetuERC165 is ERC165 { 11 | 12 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 13 | return interfaceId == InterfaceIds.I_TETU_ERC165 || super.supportsInterface(interfaceId); 14 | } 15 | 16 | // ************************************************************* 17 | // HELPER FUNCTIONS 18 | // ************************************************************* 19 | /// @author bogdoslav 20 | 21 | /// @dev Checks what interface with id is supported by contract. 22 | /// @return bool. Do not throws 23 | function _isInterfaceSupported(address contractAddress, bytes4 interfaceId) internal view returns (bool) { 24 | require(contractAddress != address(0), "Zero address"); 25 | // check what address is contract 26 | uint codeSize; 27 | assembly { 28 | codeSize := extcodesize(contractAddress) 29 | } 30 | if (codeSize == 0) return false; 31 | 32 | try IERC165(contractAddress).supportsInterface(interfaceId) returns (bool isSupported) { 33 | return isSupported; 34 | } catch { 35 | } 36 | return false; 37 | } 38 | 39 | /// @dev Checks what interface with id is supported by contract and reverts otherwise 40 | function _requireInterface(address contractAddress, bytes4 interfaceId) internal view { 41 | require(_isInterfaceSupported(contractAddress, interfaceId), "Interface is not supported"); 42 | } 43 | 44 | /// @dev Checks what address is ERC20. 45 | /// @return bool. Do not throws 46 | function _isERC20(address contractAddress) internal view returns (bool) { 47 | require(contractAddress != address(0), "Zero address"); 48 | // check what address is contract 49 | uint codeSize; 50 | assembly { 51 | codeSize := extcodesize(contractAddress) 52 | } 53 | if (codeSize == 0) return false; 54 | 55 | bool totalSupplySupported; 56 | try IERC20(contractAddress).totalSupply() returns (uint) { 57 | totalSupplySupported = true; 58 | } catch { 59 | } 60 | 61 | bool balanceSupported; 62 | try IERC20(contractAddress).balanceOf(address(this)) returns (uint) { 63 | balanceSupported = true; 64 | } catch { 65 | } 66 | 67 | return totalSupplySupported && balanceSupported; 68 | } 69 | 70 | 71 | /// @dev Checks what interface with id is supported by contract and reverts otherwise 72 | function _requireERC20(address contractAddress) internal view { 73 | require(_isERC20(contractAddress), "Not ERC20"); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /contracts/vault/VaultInsurance.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | 3 | pragma solidity 0.8.17; 4 | 5 | import "../openzeppelin/SafeERC20.sol"; 6 | import "../tools/TetuERC165.sol"; 7 | import "../interfaces/IERC20.sol"; 8 | import "../interfaces/IVaultInsurance.sol"; 9 | import "../interfaces/ITetuVaultV2.sol"; 10 | import "../lib/InterfaceIds.sol"; 11 | 12 | /// @title Simple dedicated contract for store vault fees 13 | /// @author belbix 14 | contract VaultInsurance is TetuERC165, IVaultInsurance { 15 | using SafeERC20 for IERC20; 16 | 17 | /// @dev Vault address 18 | address public override vault; 19 | /// @dev Vault underlying asset 20 | address public override asset; 21 | 22 | /// @dev Init contract with given attributes. 23 | /// Should be called from factory during creation process. 24 | function init(address _vault, address _asset) external override { 25 | require(vault == address(0) && asset == address(0), "INITED"); 26 | _requireInterface(_vault, InterfaceIds.I_TETU_VAULT_V2); 27 | _requireERC20(_asset); 28 | 29 | vault = _vault; 30 | asset = _asset; 31 | } 32 | 33 | /// @dev Transfer tokens to vault in case of covering need. 34 | function transferToVault(uint amount) external override { 35 | require(msg.sender == vault, "!VAULT"); 36 | IERC20(asset).safeTransfer(msg.sender, amount); 37 | } 38 | 39 | /// @dev See {IERC165-supportsInterface}. 40 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 41 | return interfaceId == InterfaceIds.I_VAULT_INSURANCE || super.supportsInterface(interfaceId); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /log_settings.ts: -------------------------------------------------------------------------------- 1 | import {ISettingsParam} from "tslog"; 2 | 3 | // tslint:disable-next-line:ban-ts-ignore 4 | // @ts-ignore 5 | const logSettings: ISettingsParam = { 6 | colorizePrettyLogs: false, 7 | dateTimeTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone, 8 | displayLogLevel: false, 9 | displayLoggerName: false, 10 | displayFunctionName: false, 11 | displayFilePath: 'hidden', 12 | } 13 | 14 | export default (logSettings); 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tetu_io/tetu-contracts-v2", 3 | "version": "2.1.6", 4 | "description": "TETU solidity base contracts V2", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "directories": { 8 | "contracts": "contracts", 9 | "dist": "dist" 10 | }, 11 | "scripts": { 12 | "build-module": "npm run build && tsc", 13 | "prepare": "npm run build-module", 14 | "build": "npm run clean && npm run compile", 15 | "clean": "npx hardhat clean", 16 | "compile": "npx hardhat compile", 17 | "test": "npm run build && npx hardhat test", 18 | "coverage": "npm run build && npx cross-env NODE_OPTIONS=\"--max_old_space_size=8192\" hardhat coverage --temp artifacts --max-memory 4096", 19 | "slither": "npm run build && slither .", 20 | "lint": "tslint -p tsconfig.json", 21 | "lint-fix": "tslint --fix -p tsconfig.json", 22 | "publish-npm": "npm publish --access public", 23 | "up": "hardhat run scripts/gov/execute-upgrades.ts --network matic" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/tetu-io/tetu-contracts-v2.git" 28 | }, 29 | "author": "TETU team ", 30 | "license": "MIT", 31 | "homepage": "https://tetu.io", 32 | "dependencies": { 33 | "@nomiclabs/hardhat-ethers": "^2.2.1", 34 | "@nomiclabs/hardhat-etherscan": "^3.1.3", 35 | "@nomiclabs/hardhat-solhint": "^2.0.1", 36 | "@nomiclabs/hardhat-waffle": "^2.0.3", 37 | "@nomiclabs/hardhat-web3": "^2.0.0", 38 | "@typechain/ethers-v5": "^10.2.0", 39 | "@typechain/hardhat": "^6.1.5", 40 | "@types/chai": "^4.3.4", 41 | "@types/chai-as-promised": "^7.1.5", 42 | "@types/chai-string": "^1.4.2", 43 | "@types/mocha": "^10.0.1", 44 | "@types/node": "^18.11.14", 45 | "axios": "^1.2.1", 46 | "chai": "^4.3.7", 47 | "chai-as-promised": "^7.1.1", 48 | "dotenv": "^16.0.3", 49 | "ethereum-waffle": "^3.4.4", 50 | "ethereumjs-tx": "^2.1.2", 51 | "ethers": "^5.7.2", 52 | "graphql": "^16.6.0", 53 | "graphql-request": "^5.1.0", 54 | "hardhat": "2.14.1", 55 | "hardhat-abi-exporter": "^2.10.1", 56 | "hardhat-contract-sizer": "^2.6.1", 57 | "hardhat-deploy": "^0.11.22", 58 | "hardhat-gas-reporter": "^1.0.9", 59 | "mocha": "^10.2.0", 60 | "solidity-coverage": "^0.8.2", 61 | "ts-generator": "^0.1.1", 62 | "ts-node": "^10.9.1", 63 | "tslint": "^6.1.3", 64 | "tslog": "^4.4.4", 65 | "typechain": "^8.1.1", 66 | "typescript": "^4.9.4", 67 | "yargs": "^17.6.2" 68 | }, 69 | "engines": { 70 | "node": "18.x.x" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /scripts/addresses/addresses.ts: -------------------------------------------------------------------------------- 1 | import {CoreAddresses} from "../models/CoreAddresses"; 2 | import {GoerliAddresses} from "./goerli"; 3 | import {PolygonAddresses} from "./polygon"; 4 | import {SepoliaAddresses} from "./sepolia"; 5 | import {ToolsAddresses} from "../models/ToolsAddresses"; 6 | import {BaseAddresses} from "./base"; 7 | import {ZkEvmAddresses} from "./zkevm"; 8 | 9 | // tslint:disable-next-line:no-var-requires 10 | const hre = require("hardhat"); 11 | 12 | export class Addresses { 13 | 14 | public static CORE = new Map([ 15 | [5, GoerliAddresses.CORE_ADDRESSES], 16 | [11155111, SepoliaAddresses.CORE_ADDRESSES], 17 | [137, PolygonAddresses.CORE_ADDRESSES], 18 | [8453, BaseAddresses.CORE_ADDRESSES], 19 | [1101, ZkEvmAddresses.CORE_ADDRESSES], 20 | ]); 21 | 22 | public static TOOLS = new Map([ 23 | [137, PolygonAddresses.TOOLS_ADDRESSES], 24 | [8453, BaseAddresses.TOOLS_ADDRESSES], 25 | [1101, ZkEvmAddresses.TOOLS_ADDRESSES], 26 | ]); 27 | 28 | public static getCore(): CoreAddresses { 29 | return Addresses.CORE.get(hre.network.config.chainId) as CoreAddresses; 30 | } 31 | 32 | public static getTools(): ToolsAddresses { 33 | return Addresses.TOOLS.get(hre.network.config.chainId) as ToolsAddresses; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /scripts/addresses/base.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:variable-name */ 2 | // noinspection JSUnusedGlobalSymbols 3 | 4 | import {CoreAddresses} from "../models/CoreAddresses"; 5 | import {ToolsAddresses} from "../models/ToolsAddresses"; 6 | 7 | // noinspection SpellCheckingInspection 8 | export class BaseAddresses { 9 | 10 | public static CORE_ADDRESSES = new CoreAddresses( 11 | "0x5E42c17CAEab64527D9d80d506a3FE01179afa02", // tetu 12 | "0x255707B70BF90aa112006E1b07B9AeA6De021424", // controller 13 | "0xb8bA82F19A9Be6CbF6DAF9BF4FBCC5bDfCF8bEe6", // ve 14 | "0xA2c5911b6EcB4Da440C93F8b7dAa90c68F53E26a", // veDist old 0x875976AeF383Fe4135B93C3989671056c4dEcDFF 15 | "0xD8a4054d63fCb0030BC73E2323344Ae59A19E92b", // gauge 16 | "0x0B62ad43837A69Ad60289EEea7C6e907e759F6E8", // bribe 17 | "0xFC9b894D0b4a34AB41278Df5F2aBEEb5de95c9e4", // tetuVoter 18 | "0xCa9C8Fba773caafe19E6140eC0A7a54d996030Da", // platformVoter 19 | "0xdfB765935D7f4e38641457c431F89d20Db571674", // forwarder 20 | "0xdc08482Fe34ccf74300e996966030cAc0F81F271", // vaultFactory 21 | "0x27af55366a339393865FC5943C04bc2600F55C9F", // investFundV2 22 | ); 23 | 24 | public static TOOLS_ADDRESSES = new ToolsAddresses( 25 | "0x22e2625F9d8c28CB4BcE944E9d64efb4388ea991", 26 | "0x51002Cad5e6FbE3856311f431E1c41c46Acc5D47", 27 | "0x1Ae75D0A2AFE092b1aC417c5c43515E54eE12E51", 28 | ); 29 | 30 | public static GOVERNANCE = "0x3f5075195b96B60d7D26b5cDe93b64A6D9bF33e2".toLowerCase(); 31 | 32 | // Additional TETU contracts 33 | public static HARDWORK_RESOLVER = "".toLowerCase(); 34 | public static FORWARDER_RESOLVER = "".toLowerCase(); 35 | public static SPLITTER_REBALANCE_RESOLVER = "".toLowerCase(); 36 | public static PERF_FEE_TREASURY = "0xc4B7b554af7a82595e7e6Fab932562d5d2e273b4".toLowerCase(); 37 | public static TETU_BRIDGED_PROCESSING = "".toLowerCase(); 38 | public static REWARDS_REDIRECTOR = "0x57577b27814f4166E2340580C49c9726549677e0".toLowerCase(); 39 | public static BRIBE_DISTRIBUTION = "".toLowerCase(); 40 | public static DEPOSIT_HELPER_V2 = "0x6efecCc5112c778bD3bA6ce496Cc6816aBbE187C".toLowerCase(); 41 | public static ONE_INCH_ROUTER_V5 = "0x1111111254EEB25477B68fb85Ed929f73A960582".toLowerCase(); 42 | 43 | // Tetu V2 vaults and strategies 44 | 45 | public static tUSDbC = "0x68f0a05FDc8773d9a5Fd1304ca411ACc234ce22c".toLowerCase(); 46 | 47 | 48 | // tokens 49 | public static TETU_TOKEN = "0x5E42c17CAEab64527D9d80d506a3FE01179afa02".toLowerCase(); 50 | public static TETU_tUSDbC_AERODROME_LP = "0x924bb74AD42314E4434af5df984cca28b0529337".toLowerCase(); 51 | public static USDbC_tUSDbC_AERODROME_LP = "0x07Eca3F678C86B89e428F452B9d5bbcb38B749Cd".toLowerCase(); 52 | public static USDbC_tUSDbC_UNI3_POOL = "0x99a17985111FcB2B0544b0A19d4585ab671681C9".toLowerCase(); 53 | 54 | public static WETH_TOKEN = '0x4200000000000000000000000000000000000006'.toLowerCase(); 55 | 56 | public static USDC_TOKEN = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'.toLowerCase(); 57 | public static USDbC_TOKEN = '0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA'.toLowerCase(); 58 | public static axlUSDC_TOKEN = '0xEB466342C4d449BC9f53A865D5Cb90586f405215'.toLowerCase(); 59 | public static crvUSD_TOKEN = '0x417Ac0e078398C154EdFadD9Ef675d30Be60Af93'.toLowerCase(); 60 | public static USDT_TOKEN = ''.toLowerCase(); 61 | 62 | public static WBTC_TOKEN = ''.toLowerCase(); 63 | public static DAI_TOKEN = ''.toLowerCase(); 64 | public static CRV_TOKEN = '0x8Ee73c484A26e0A5df2Ee2a4960B789967dd0415'.toLowerCase(); 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /scripts/addresses/goerli.ts: -------------------------------------------------------------------------------- 1 | import {CoreAddresses} from "../models/CoreAddresses"; 2 | 3 | export class GoerliAddresses { 4 | 5 | public static CORE_ADDRESSES = new CoreAddresses( 6 | "0x88a12B7b6525c0B46c0c200405f49cE0E72D71Aa", // tetu 7 | "0x0EFc2D2D054383462F2cD72eA2526Ef7687E1016", // controller 8 | "0xA43eA51b3251f96bB48c48567A93b15e7e4b99F6", // ve 9 | "0x6B2e0fACD2F2A8f407aC591067Ac06b5d29247E4", // veDist 10 | "0x7AD5935EA295c4E743e4f2f5B4CDA951f41223c2", // gauge 11 | "0x81367059892aa1D8503a79a0Af9254DD0a09afBF", // bribe 12 | "0x225084D30cc297F3b177d9f93f5C3Ab8fb6a1454", // tetuVoter 13 | "0x422282F18CFE573e7dc6BEcC7242ffad43340aF8", // platformVoter 14 | "0xeFBc16b8c973DecA383aAAbAB07153D2EB676556", // forwarder 15 | "0xCF66857b468740d6dbF9cE11929A9c03DDA12988", // vaultFactory 16 | "", // investFundV2 17 | ); 18 | 19 | } 20 | 21 | 22 | // usdc: 0x308A756B4f9aa3148CaD7ccf8e72c18C758b2EF2 23 | // btc: 0x27af55366a339393865FC5943C04bc2600F55C9F 24 | // weth: 0xbf1e638871c59859db851674c7f94efcb0f40954 25 | // liquidator: 0x3bDbd2Ed1A214Ca4ba4421ddD7236ccA3EF088b6 26 | // factory: 0xB6Ca119F30B3E7F6589F8a053c2a10B753846e78 27 | // uniSwapper: 0xF9E426dF37D75875b136d9D25CB9f27Ee9E43C4f 28 | // usdcBtc: 0x53cBAb0D7E5e2B44216B1AB597D85E33C23Fe1Db 29 | // usdcWeth: 0x9B09fc5Efb7a16b15F53130f06AE21f1fC106680 30 | // btcWeth: 0x01490bd35C56766dD20D2b347EF73b6E40562779 31 | // usdcTetu: 0x58639D7ab0E26373205B9f54585c719a3F652650 32 | -------------------------------------------------------------------------------- /scripts/addresses/sepolia.ts: -------------------------------------------------------------------------------- 1 | import {CoreAddresses} from "../models/CoreAddresses"; 2 | 3 | export class SepoliaAddresses { 4 | 5 | public static CORE_ADDRESSES = new CoreAddresses( 6 | "0x549aE613Bb492CCf68A6620848C80262709a1fb4", // tetu 7 | "0xbf1fc29668e5f5Eaa819948599c9Ac1B1E03E75F", // controller 8 | "0x286c02C93f3CF48BB759A93756779A1C78bCF833", // ve 9 | "0x0A0846c978a56D6ea9D2602eeb8f977B21F3207F", // veDist 10 | "0x00379dD90b2A337C4652E286e4FBceadef940a21", // gauge 11 | "0x57Cf87b92E38f619bBeB2F13800730e668d69d7D", // bribe 12 | "0xB5A5D5fE893bC26C6E70CEbb8a193f764A438fd5", // tetuVoter 13 | "0x13d862a01d0AB241509A2e47e31d0db04e9b9F49", // platformVoter 14 | "0xbEB411eAD71713E7f2814326498Ff2a054242206", // forwarder 15 | "0xFC9b894D0b4a34AB41278Df5F2aBEEb5de95c9e4", // vaultFactory 16 | "", // investFundV2 17 | ); 18 | 19 | } 20 | 21 | // deposit helper 0x6d85966b5280Bfbb479E0EBA00Ac5ceDfe8760D3 22 | 23 | // usdc: 0x27af55366a339393865FC5943C04bc2600F55C9F 24 | // btc: 0x0ed08c9A2EFa93C4bF3C8878e61D2B6ceD89E9d7 25 | // weth: 0x078b7c9304eBA754e916016E8A8939527076f991 26 | // liquidator: 0x8d6479dF2c152F99C23493c8ebbaf63DC586024b 27 | // factory: 0xB393cA1442621c3356600e5B10B3510B5180d948 28 | // uniSwapper: 0x01D0b17AC7B72cD4b051840e27A2134F25C53265 29 | // usdcBtc: 0xB4747653510E8a4DE0A03E2bAb09Dd5150DAad34 30 | // usdcWeth: 0xf210A6B37ddf47517c5d9E5AE3d24Bea5E398fa8 31 | // btcWeth: 0x55BC8E9C917CEB8D9195198c5F4972C2E443280A 32 | // usdcTetu: 0x27AaD9E67Ad9596D6f3f23c71D4cB5ef2080CE2F 33 | -------------------------------------------------------------------------------- /scripts/addresses/zkevm.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:variable-name */ 2 | // noinspection JSUnusedGlobalSymbols 3 | 4 | import {CoreAddresses} from "../models/CoreAddresses"; 5 | import {ToolsAddresses} from "../models/ToolsAddresses"; 6 | 7 | // noinspection SpellCheckingInspection 8 | export class ZkEvmAddresses { 9 | 10 | public static CORE_ADDRESSES = new CoreAddresses( 11 | "0x7C1B24c139a3EdA18Ab77C8Fa04A0F816C23e6D4", // tetu 12 | "0x35B0329118790B8c8FC36262812D92a4923C6795", // controller 13 | "0x0000000000000000000000000000000000000000", // ve 14 | "0x0000000000000000000000000000000000000000", // veDist 15 | "0xd353254872E8797B159594c1E528b8Be9a6cb1F8", // gauge 16 | "0x0000000000000000000000000000000000000000", // bribe 17 | "0x099C314F792e1F91f53765Fc64AaDCcf4dCf1538", // tetuVoter 18 | "0x0000000000000000000000000000000000000000", // platformVoter 19 | "0x255707B70BF90aa112006E1b07B9AeA6De021424", // forwarder 20 | "0xeFBc16b8c973DecA383aAAbAB07153D2EB676556", // vaultFactory 21 | "0x5373C3d09C39D8F256f88E08aa61402FE14A3792", // investFundV2 22 | ); 23 | 24 | public static TOOLS_ADDRESSES = new ToolsAddresses( 25 | "0xBcda73B7184D5974F77721db79ff8BA190b342ce", 26 | "0x60E684643d546b657bfeE9c01Cb40E62EC1fe1e2", 27 | "0x914F48367E54033Be83d939ed20e6611e23DDB99", 28 | ); 29 | 30 | public static GOVERNANCE = "".toLowerCase(); // todo 31 | 32 | // Additional TETU contracts 33 | public static HARDWORK_RESOLVER = "".toLowerCase(); 34 | public static FORWARDER_RESOLVER = "".toLowerCase(); 35 | public static SPLITTER_REBALANCE_RESOLVER = "".toLowerCase(); 36 | public static PERF_FEE_TREASURY = "".toLowerCase(); // todo 37 | public static TETU_BRIDGED_PROCESSING = "".toLowerCase(); 38 | public static REWARDS_REDIRECTOR = "".toLowerCase(); // todo 39 | public static BRIBE_DISTRIBUTION = "".toLowerCase(); 40 | public static DEPOSIT_HELPER_V2 = "".toLowerCase(); // todo 41 | 42 | public static ONE_INCH_ROUTER_V5 = "TODO:0x1111111254EEB25477B68fb85Ed929f73A960582".toLowerCase(); // todo there is no 1inch on zkEvm 43 | public static OPENOCEAN_ROUTER = "0x6dd434082EAB5Cd134B33719ec1FF05fE985B97b".toLowerCase(); 44 | 45 | // Tetu V2 vaults and strategies 46 | 47 | public static tUSDC = "0x3650823873F34a019533db164f492e09365cfa7E".toLowerCase(); 48 | 49 | 50 | // tokens 51 | public static TETU_TOKEN = "0x7C1B24c139a3EdA18Ab77C8Fa04A0F816C23e6D4".toLowerCase(); 52 | 53 | public static WETH_TOKEN = '0x4F9A0e7FD2Bf6067db6994CF12E4495Df938E6e9'.toLowerCase(); 54 | 55 | public static USDC_TOKEN = '0xA8CE8aee21bC2A48a5EF670afCc9274C7bbbC035'.toLowerCase(); 56 | public static USDT_TOKEN = '0x1E4a5963aBFD975d8c9021ce480b42188849D41d'.toLowerCase(); 57 | 58 | public static WBTC_TOKEN = '0xEA034fb02eB1808C2cc3adbC15f447B93CbE08e1'.toLowerCase(); 59 | public static DAI_TOKEN = '0xC5015b9d9161Dca7e18e32f6f25C4aD850731Fd4'.toLowerCase(); 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /scripts/deploy/DeployAllProdSimplified.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {InvestFundV2__factory} from "../../typechain"; 4 | import {RunHelper} from "../utils/RunHelper"; 5 | import {Addresses} from "../addresses/addresses"; 6 | import {Misc} from "../utils/Misc"; 7 | 8 | async function main() { 9 | const signer = (await ethers.getSigners())[0]; 10 | const core = Addresses.getCore(); 11 | const tools = Addresses.getTools(); 12 | 13 | const tetu = core.tetu; 14 | const controller = await DeployerUtils.deployController(signer); 15 | const gauge = await DeployerUtils.deployMultiGaugeNoBoost(signer, controller.address, tetu); 16 | const tetuVoter = await DeployerUtils.deployTetuVoterSimplified(signer, controller.address, tetu, gauge.address); 17 | const forwarder = await DeployerUtils.deployForwarderSimplified(signer, controller.address, tetu); 18 | const fundAdr = await DeployerUtils.deployProxy(signer, 'InvestFundV2'); 19 | const investFund = InvestFundV2__factory.connect(fundAdr, signer); 20 | await RunHelper.runAndWait2(investFund.populateTransaction.init(controller.address)); 21 | 22 | const vaultImpl = await DeployerUtils.deployContract(signer, 'TetuVaultV2'); 23 | const vaultInsuranceImpl = await DeployerUtils.deployContract(signer, 'VaultInsurance'); 24 | const splitterImpl = await DeployerUtils.deployContract(signer, 'StrategySplitterV2'); 25 | 26 | const vaultFactory = await DeployerUtils.deployVaultFactory( 27 | signer, 28 | controller.address, 29 | vaultImpl.address, 30 | vaultInsuranceImpl.address, 31 | splitterImpl.address, 32 | ); 33 | 34 | await RunHelper.runAndWait2(controller.populateTransaction.announceAddressChange(2, tetuVoter.address)); 35 | await RunHelper.runAndWait2(controller.populateTransaction.announceAddressChange(4, tools.liquidator)); 36 | await RunHelper.runAndWait2(controller.populateTransaction.announceAddressChange(5, forwarder.address)); 37 | await RunHelper.runAndWait2(controller.populateTransaction.announceAddressChange(6, fundAdr)); 38 | 39 | 40 | await RunHelper.runAndWait2(controller.populateTransaction.changeAddress(2)); // TETU_VOTER 41 | await RunHelper.runAndWait2(controller.populateTransaction.changeAddress(4)); // LIQUIDATOR 42 | await RunHelper.runAndWait2(controller.populateTransaction.changeAddress(5)); // FORWARDER 43 | await RunHelper.runAndWait2(controller.populateTransaction.changeAddress(6)); // INVEST_FUND 44 | 45 | const result = ` public static CORE_ADDRESSES = new CoreAddresses( 46 | "${tetu}", // tetu 47 | "${controller.address}", // controller 48 | "${Misc.ZERO_ADDRESS}", // ve 49 | "${Misc.ZERO_ADDRESS}", // veDist 50 | "${gauge.address}", // gauge 51 | "${Misc.ZERO_ADDRESS}", // bribe 52 | "${tetuVoter.address}", // tetuVoter 53 | "${Misc.ZERO_ADDRESS}", // platformVoter 54 | "${forwarder.address}", // forwarder 55 | "${vaultFactory.address}", // vaultFactory 56 | "${investFund.address}", // investFund 57 | );` 58 | 59 | DeployerUtils.createFolderAndWriteFileSync('tmp/deployed/core.txt', result); 60 | } 61 | 62 | main() 63 | .then(() => { 64 | console.log('Script finished successfully'); 65 | process.exit(0); 66 | }) 67 | .catch(error => { 68 | console.error(error); 69 | process.exit(1); 70 | }); 71 | -------------------------------------------------------------------------------- /scripts/deploy/DeployAllTestnet.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {writeFileSync} from "fs"; 4 | import {InvestFundV2__factory} from "../../typechain"; 5 | import {RunHelper} from "../utils/RunHelper"; 6 | 7 | async function main() { 8 | const signer = (await ethers.getSigners())[0]; 9 | 10 | const tetu = await DeployerUtils.deployMockToken(signer, 'TETU'); 11 | const controller = await DeployerUtils.deployController(signer); 12 | const ve = await DeployerUtils.deployVeTetu(signer, tetu.address, controller.address); 13 | const gauge = await DeployerUtils.deployMultiGauge(signer, controller.address, ve.address, tetu.address); 14 | const bribe = await DeployerUtils.deployMultiBribe(signer, controller.address, ve.address, tetu.address); 15 | const tetuVoter = await DeployerUtils.deployTetuVoter(signer, controller.address, ve.address, tetu.address, gauge.address, bribe.address); 16 | const platformVoter = await DeployerUtils.deployPlatformVoter(signer, controller.address, ve.address); 17 | const forwarder = await DeployerUtils.deployForwarder(signer, controller.address, tetu.address, bribe.address); 18 | const fundAdr = await DeployerUtils.deployProxy(signer, 'InvestFundV2'); 19 | const investFund = InvestFundV2__factory.connect(fundAdr, signer); 20 | await RunHelper.runAndWait(() => investFund.init(controller.address)); 21 | 22 | const vaultImpl = await DeployerUtils.deployContract(signer, 'TetuVaultV2'); 23 | const vaultInsuranceImpl = await DeployerUtils.deployContract(signer, 'VaultInsurance'); 24 | const splitterImpl = await DeployerUtils.deployContract(signer, 'StrategySplitterV2'); 25 | 26 | const vaultFactory = await DeployerUtils.deployVaultFactory( 27 | signer, 28 | controller.address, 29 | vaultImpl.address, 30 | vaultInsuranceImpl.address, 31 | splitterImpl.address, 32 | ); 33 | 34 | await RunHelper.runAndWait(() => controller.announceAddressChange(2, tetuVoter.address)); // TETU_VOTER 35 | await RunHelper.runAndWait(() => controller.announceAddressChange(3, platformVoter.address)); // PLATFORM_VOTER 36 | // await controller.announceAddressChange(4, .address); // LIQUIDATOR 37 | await RunHelper.runAndWait(() => controller.announceAddressChange(5, forwarder.address)); // FORWARDER 38 | await RunHelper.runAndWait(() => controller.announceAddressChange(6, fundAdr)); // INVEST_FUND 39 | await RunHelper.runAndWait(() => controller.announceAddressChange(7, signer.address)); // VE_DIST 40 | 41 | 42 | await RunHelper.runAndWait(() => controller.changeAddress(2)); // TETU_VOTER 43 | await RunHelper.runAndWait(() => controller.changeAddress(3)); // PLATFORM_VOTER 44 | // await controller.changeAddress(4); // LIQUIDATOR 45 | await RunHelper.runAndWait(() => controller.changeAddress(5)); // FORWARDER 46 | await RunHelper.runAndWait(() => controller.changeAddress(6)); // INVEST_FUND 47 | await RunHelper.runAndWait(() => controller.changeAddress(7)); // VE_DIST 48 | 49 | const result = ` 50 | tetu: ${tetu.address} 51 | controller: ${controller.address} 52 | ve: ${ve.address} 53 | veDist: ${veDist.address} 54 | gauge: ${gauge.address} 55 | bribe: ${bribe.address} 56 | tetuVoter: ${tetuVoter.address} 57 | platformVoter: ${platformVoter.address} 58 | forwarder: ${forwarder.address} 59 | vaultFactory: ${vaultFactory.address} 60 | `; 61 | writeFileSync('tmp/deployed/core.txt', result, 'utf8'); 62 | } 63 | 64 | main() 65 | .then(() => process.exit(0)) 66 | .catch(error => { 67 | console.error(error); 68 | process.exit(1); 69 | }); 70 | -------------------------------------------------------------------------------- /scripts/deploy/DeployBribeDistribution.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {Addresses} from "../addresses/addresses"; 4 | import {BribeDistribution} from "../../typechain"; 5 | 6 | async function main() { 7 | const signer = (await ethers.getSigners())[0]; 8 | const core = Addresses.getCore(); 9 | await DeployerUtils.deployContract(signer, "BribeDistribution", core.veDist, core.tetu); 10 | } 11 | 12 | main() 13 | .then(() => process.exit(0)) 14 | .catch(error => { 15 | console.error(error); 16 | process.exit(1); 17 | }); 18 | -------------------------------------------------------------------------------- /scripts/deploy/DeployDepositHelperBaseChain.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {BaseAddresses} from "../addresses/base"; 4 | 5 | async function main() { 6 | const signer = (await ethers.getSigners())[0]; 7 | await DeployerUtils.deployContract(signer, 'DepositHelperBaseChain', BaseAddresses.ONE_INCH_ROUTER_V5); 8 | } 9 | 10 | main() 11 | .then(() => process.exit(0)) 12 | .catch(error => { 13 | console.error(error); 14 | process.exit(1); 15 | }); 16 | -------------------------------------------------------------------------------- /scripts/deploy/DeployDepositHelperPolygon.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {PolygonAddresses} from "../addresses/polygon"; 4 | 5 | async function main() { 6 | const signer = (await ethers.getSigners())[0]; 7 | await DeployerUtils.deployContract(signer, 'DepositHelperPolygon', PolygonAddresses.ONE_INCH_ROUTER_V5); 8 | } 9 | 10 | main() 11 | .then(() => process.exit(0)) 12 | .catch(error => { 13 | console.error(error); 14 | process.exit(1); 15 | }); 16 | -------------------------------------------------------------------------------- /scripts/deploy/DeployForwarderResolver.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {appendFileSync} from "fs"; 4 | import {Addresses} from "../addresses/addresses"; 5 | import {ForwarderDistributeResolver__factory, HardWorkResolver__factory} from "../../typechain"; 6 | import {RunHelper} from "../utils/RunHelper"; 7 | 8 | 9 | async function main() { 10 | const signer = (await ethers.getSigners())[0]; 11 | const core = Addresses.getCore(); 12 | const contract = await DeployerUtils.deployProxy(signer, 'ForwarderDistributeResolver'); 13 | await RunHelper.runAndWait(() => ForwarderDistributeResolver__factory.connect(contract, signer).init(core.controller)); 14 | } 15 | 16 | main() 17 | .then(() => process.exit(0)) 18 | .catch(error => { 19 | console.error(error); 20 | process.exit(1); 21 | }); 22 | -------------------------------------------------------------------------------- /scripts/deploy/DeployHardworkResolver.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {appendFileSync} from "fs"; 4 | import {Addresses} from "../addresses/addresses"; 5 | import {HardWorkResolver__factory} from "../../typechain"; 6 | import {RunHelper} from "../utils/RunHelper"; 7 | 8 | 9 | async function main() { 10 | const signer = (await ethers.getSigners())[0]; 11 | const core = Addresses.getCore(); 12 | const contract = await DeployerUtils.deployProxy(signer, 'HardWorkResolver'); 13 | await RunHelper.runAndWait(() => HardWorkResolver__factory.connect(contract, signer).init(core.controller)); 14 | } 15 | 16 | main() 17 | .then(() => process.exit(0)) 18 | .catch(error => { 19 | console.error(error); 20 | process.exit(1); 21 | }); 22 | -------------------------------------------------------------------------------- /scripts/deploy/DeployInvestFund.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {InvestFundV2__factory} from "../../typechain"; 4 | import {Addresses} from "../addresses/addresses"; 5 | 6 | 7 | async function main() { 8 | const signer = (await ethers.getSigners())[0]; 9 | const core = Addresses.getCore(); 10 | const fundAdr = await DeployerUtils.deployProxy(signer, 'InvestFundV2'); 11 | const investFund = InvestFundV2__factory.connect(fundAdr, signer); 12 | await investFund.init(core.controller); 13 | } 14 | 15 | main() 16 | .then(() => process.exit(0)) 17 | .catch(error => { 18 | console.error(error); 19 | process.exit(1); 20 | }); 21 | -------------------------------------------------------------------------------- /scripts/deploy/DeployMockStrategy.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {RunHelper} from "../utils/RunHelper"; 4 | import {MockStrategy, MockStrategy__factory, StrategySplitterV2__factory} from "../../typechain"; 5 | import {Addresses} from "../addresses/addresses"; 6 | 7 | const SPLITTER = '0x24dc9f1b9ae0fA62acb120Ea77D7fC89C6814F72'; 8 | 9 | async function main() { 10 | const signer = (await ethers.getSigners())[0]; 11 | 12 | const strategy1 = MockStrategy__factory.connect(await DeployerUtils.deployProxy(signer, 'MockStrategy'), signer); 13 | await setupStrategy(strategy1) 14 | 15 | const strategy2 = MockStrategy__factory.connect(await DeployerUtils.deployProxy(signer, 'MockStrategy'), signer); 16 | await setupStrategy(strategy2) 17 | 18 | const strategy3 = MockStrategy__factory.connect(await DeployerUtils.deployProxy(signer, 'MockStrategy'), signer); 19 | await setupStrategy(strategy3) 20 | 21 | const splitter = StrategySplitterV2__factory.connect(SPLITTER, signer); 22 | await RunHelper.runAndWait(() => splitter.addStrategies( 23 | [strategy1.address, strategy2.address, strategy3.address], 24 | [Math.round(Math.random() * 100), Math.round(Math.random() * 200), Math.round(Math.random() * 2)], 25 | [0, 0, 0] 26 | )); 27 | } 28 | 29 | main() 30 | .then(() => process.exit(0)) 31 | .catch(error => { 32 | console.error(error); 33 | process.exit(1); 34 | }); 35 | 36 | 37 | async function setupStrategy(strategy: MockStrategy) { 38 | const core = Addresses.getCore(); 39 | await RunHelper.runAndWait(() => strategy.init( 40 | core.controller, 41 | SPLITTER 42 | )); 43 | 44 | await RunHelper.runAndWait(() => strategy.setSlippage(Math.round(Math.random() * 500))); 45 | await RunHelper.runAndWait(() => strategy.setSlippageDeposit(Math.round(Math.random() * 500))); 46 | await RunHelper.runAndWait(() => strategy.setSlippageHardWork(Math.round(Math.random() * 500))); 47 | await RunHelper.runAndWait(() => strategy.setLast(Math.round(Math.random() * 1000_000), 0)); 48 | } 49 | -------------------------------------------------------------------------------- /scripts/deploy/DeployMockToken.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {appendFileSync} from "fs"; 4 | 5 | 6 | async function main() { 7 | const signer = (await ethers.getSigners())[0]; 8 | await DeployerUtils.deployMockToken(signer, 'WETH', 18); 9 | } 10 | 11 | main() 12 | .then(() => process.exit(0)) 13 | .catch(error => { 14 | console.error(error); 15 | process.exit(1); 16 | }); 17 | -------------------------------------------------------------------------------- /scripts/deploy/DeployPerfFeeTreasury.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {PolygonAddresses} from "../addresses/polygon"; 4 | 5 | async function main() { 6 | const signer = (await ethers.getSigners())[0]; 7 | await DeployerUtils.deployContract(signer, 'PerfFeeTreasury', '0x0644141dd9c2c34802d28d334217bd2034206bf7'); 8 | } 9 | 10 | main() 11 | .then(() => process.exit(0)) 12 | .catch(error => { 13 | console.error(error); 14 | process.exit(1); 15 | }); 16 | -------------------------------------------------------------------------------- /scripts/deploy/DeployRewardsRedirector.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {appendFileSync} from "fs"; 4 | import {Addresses} from "../addresses/addresses"; 5 | import {ForwarderDistributeResolver__factory, HardWorkResolver__factory} from "../../typechain"; 6 | import {RunHelper} from "../utils/RunHelper"; 7 | 8 | 9 | async function main() { 10 | const signer = (await ethers.getSigners())[0]; 11 | const core = Addresses.getCore(); 12 | await DeployerUtils.deployContract(signer, 'RewardsRedirector', '0x0644141dd9c2c34802d28d334217bd2034206bf7', core.gauge); 13 | } 14 | 15 | main() 16 | .then(() => process.exit(0)) 17 | .catch(error => { 18 | console.error(error); 19 | process.exit(1); 20 | }); 21 | -------------------------------------------------------------------------------- /scripts/deploy/DeploySplitterRebalanceResolver.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {appendFileSync} from "fs"; 4 | import {Addresses} from "../addresses/addresses"; 5 | import {HardWorkResolver__factory, SplitterRebalanceResolver__factory} from "../../typechain"; 6 | import {RunHelper} from "../utils/RunHelper"; 7 | 8 | 9 | async function main() { 10 | const signer = (await ethers.getSigners())[0]; 11 | const core = Addresses.getCore(); 12 | const contract = await DeployerUtils.deployProxy(signer, 'SplitterRebalanceResolver'); 13 | await RunHelper.runAndWait(() => SplitterRebalanceResolver__factory.connect(contract, signer).init(core.controller)); 14 | } 15 | 16 | main() 17 | .then(() => process.exit(0)) 18 | .catch(error => { 19 | console.error(error); 20 | process.exit(1); 21 | }); 22 | -------------------------------------------------------------------------------- /scripts/deploy/DeployTetuBridgedProcessing.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {TetuBridgedProcessing} from "../../typechain"; 4 | import {PolygonAddresses} from "../addresses/polygon"; 5 | 6 | 7 | async function main() { 8 | const signer = (await ethers.getSigners())[0]; 9 | await DeployerUtils.deployContract(signer, 'TetuBridgedProcessing', PolygonAddresses.TETU_TOKEN, PolygonAddresses.fxTETU_TOKEN, PolygonAddresses.GOVERNANCE); 10 | } 11 | 12 | main() 13 | .then(() => process.exit(0)) 14 | .catch(error => { 15 | console.error(error); 16 | process.exit(1); 17 | }); 18 | -------------------------------------------------------------------------------- /scripts/deploy/DeployVault.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {Addresses} from "../addresses/addresses"; 3 | import { 4 | ControllerV2__factory, 5 | IERC20Metadata__factory, 6 | MultiGauge__factory, 7 | TetuVaultV2__factory, 8 | VaultFactory__factory 9 | } from "../../typechain"; 10 | import {RunHelper} from "../utils/RunHelper"; 11 | import {BaseAddresses} from "../addresses/base"; 12 | import {ZkEvmAddresses} from "../addresses/zkevm"; 13 | 14 | 15 | const ASSET = ZkEvmAddresses.USDC_TOKEN; 16 | const BUFFER = 1000; // 1% 17 | const DEPOSIT_FEE = 300; // 0.3% 18 | const WITHDRAW_FEE = 300; // 0.3% 19 | 20 | async function main() { 21 | const signer = (await ethers.getSigners())[0]; 22 | const core = Addresses.getCore(); 23 | 24 | const symbol = await IERC20Metadata__factory.connect(ASSET, signer).symbol(); 25 | const vaultSymbol = "t" + symbol; 26 | 27 | const factory = VaultFactory__factory.connect(core.vaultFactory, signer) 28 | 29 | await RunHelper.runAndWait2(factory.populateTransaction.createVault( 30 | ASSET, 31 | 'Tetu V2 ' + vaultSymbol, 32 | vaultSymbol, 33 | core.gauge, 34 | BUFFER 35 | )); 36 | const l = (await factory.deployedVaultsLength()).toNumber(); 37 | const vault = await factory.deployedVaults(l - 1); 38 | console.log(l, 'VAULT: ', vault) 39 | 40 | await RunHelper.runAndWait2(TetuVaultV2__factory.connect(vault, signer).populateTransaction.setFees(DEPOSIT_FEE, WITHDRAW_FEE)); 41 | await RunHelper.runAndWait2(ControllerV2__factory.connect(core.controller, signer).populateTransaction.registerVault(vault)); 42 | await RunHelper.runAndWait2(MultiGauge__factory.connect(core.gauge, signer).populateTransaction.addStakingToken(vault)); 43 | } 44 | 45 | main() 46 | .then(() => process.exit(0)) 47 | .catch(error => { 48 | console.error(error); 49 | process.exit(1); 50 | }); 51 | -------------------------------------------------------------------------------- /scripts/deploy/DeployVaultFactory.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {DeployerUtils} from "../utils/DeployerUtils"; 3 | import {appendFileSync} from "fs"; 4 | import {Addresses} from "../addresses/addresses"; 5 | 6 | 7 | async function main() { 8 | const signer = (await ethers.getSigners())[0]; 9 | const core = Addresses.getCore(); 10 | await DeployerUtils.deployVaultFactory( 11 | signer, 12 | core.controller, 13 | '0xa2c5911b6ecb4da440c93f8b7daa90c68f53e26a', 14 | '0x6d85966b5280bfbb479e0eba00ac5cedfe8760d3', 15 | '0x27af55366a339393865fc5943c04bc2600f55c9f', 16 | ); 17 | } 18 | 19 | main() 20 | .then(() => process.exit(0)) 21 | .catch(error => { 22 | console.error(error); 23 | process.exit(1); 24 | }); 25 | -------------------------------------------------------------------------------- /scripts/gov/execute-upgrades.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {Addresses} from "../addresses/addresses"; 3 | import {ControllerV2__factory} from "../../typechain"; 4 | import {RunHelper} from "../utils/RunHelper"; 5 | 6 | // tslint:disable-next-line:no-var-requires 7 | const hre = require("hardhat"); 8 | 9 | 10 | async function main() { 11 | const [signer] = await ethers.getSigners(); 12 | const core = Addresses.getCore(); 13 | const toUpdate = await ControllerV2__factory.connect(core.controller, signer).proxyAnnouncesList() 14 | 15 | if (toUpdate.length === 0) { 16 | return; 17 | } 18 | 19 | for (const u of toUpdate) { 20 | console.log('Update ', u.proxy, ' to ', u.implementation, new Date(u.timeLockAt.toNumber() * 1000)); 21 | } 22 | 23 | const proxiesReadyToUpgrade = toUpdate 24 | .filter(u => u.timeLockAt.toNumber() * 1000 < Date.now()) 25 | .map(u => u.proxy); 26 | 27 | for (const u of proxiesReadyToUpgrade) { 28 | console.log('READY to Update ', u); 29 | } 30 | 31 | console.log('Ready to Update ', proxiesReadyToUpgrade); 32 | if (proxiesReadyToUpgrade.length !== 0) { 33 | await RunHelper.runAndWait2(ControllerV2__factory.connect(core.controller, signer).populateTransaction.upgradeProxy(proxiesReadyToUpgrade)); 34 | } 35 | 36 | 37 | } 38 | 39 | main() 40 | .then(() => process.exit(0)) 41 | .catch(error => { 42 | console.error(error); 43 | process.exit(1); 44 | }); 45 | -------------------------------------------------------------------------------- /scripts/gov/poke-gauge-voter.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {Addresses} from "../addresses/addresses"; 3 | import {TetuVoter__factory} from "../../typechain"; 4 | import {RunHelper} from "../utils/RunHelper"; 5 | import {txParams} from "../deploy/DeployContract"; 6 | 7 | // tslint:disable-next-line:no-var-requires 8 | const {request, gql} = require('graphql-request') 9 | 10 | // tslint:disable-next-line:no-var-requires 11 | const hre = require("hardhat"); 12 | 13 | async function main() { 14 | const [signer] = await ethers.getSigners(); 15 | const core = Addresses.getCore(); 16 | 17 | // const gov = await Misc.impersonate('0xcc16d636dD05b52FF1D8B9CE09B09BC62b11412B') 18 | // const logic = await deployContract(hre, signer, 'TetuVoter'); 19 | // await ControllerV2__factory.connect(core.controller, gov).announceProxyUpgrade([core.tetuVoter], [logic.address]); 20 | // await TimeUtils.advanceBlocksOnTs(60 * 60 * 24 * 2); 21 | // await ControllerV2__factory.connect(core.controller, gov).upgradeProxy([core.tetuVoter]); 22 | 23 | const voter = TetuVoter__factory.connect(core.tetuVoter, signer); 24 | 25 | const data = await request('https://api.thegraph.com/subgraphs/name/tetu-io/tetu-v2', gql` 26 | query tetuVoterUserVotes { 27 | tetuVoterUserVotes { 28 | date 29 | percent 30 | weight 31 | user { 32 | veNFT { 33 | veNFTId 34 | } 35 | } 36 | } 37 | } 38 | `); 39 | 40 | const votes = data.tetuVoterUserVotes; 41 | 42 | const minDate = new Map() 43 | let totalWeight = 0; 44 | for (const vote of votes) { 45 | // console.log(vote) 46 | const veId = vote.user.veNFT.veNFTId; 47 | console.log(new Date(vote.date * 1000), 'percent: ', (+vote.percent).toFixed(2), 'weight: ', Number(vote.weight).toFixed(), 've: ', veId); 48 | const md = minDate.get(+veId) ?? Date.now(); 49 | totalWeight += +vote.weight; 50 | if (md > +vote.date && +vote.weight > 10_000) { 51 | minDate.set(+veId, +vote.date); 52 | } 53 | } 54 | 55 | console.log('total ve voted', totalWeight.toFixed(), minDate.size); 56 | 57 | const vePokes: number[] = []; 58 | for (const [veId, md] of minDate.entries()) { 59 | console.log('ve: ', veId, 'min date: ', new Date(md * 1000)); 60 | const time = Date.now() - 60 * 60 * 24 * 21 * 1000; 61 | if (md * 1000 < time) { 62 | vePokes.push(veId); 63 | } 64 | } 65 | 66 | console.log('total ve pokes', vePokes.length); 67 | 68 | const skipVe = new Set([]); 69 | 70 | for (const veId of vePokes) { 71 | console.log('poke ve: ', veId); 72 | if (skipVe.has(veId)) { 73 | continue; 74 | } 75 | const params = await txParams(hre, ethers.provider); 76 | await RunHelper.runAndWait(() => voter.poke(veId, {...params})); 77 | } 78 | 79 | } 80 | 81 | main() 82 | .then(() => process.exit(0)) 83 | .catch(error => { 84 | console.error(error); 85 | process.exit(1); 86 | }); 87 | -------------------------------------------------------------------------------- /scripts/gov/poke-platform-voter.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {Addresses} from "../addresses/addresses"; 3 | import {ControllerV2__factory, PlatformVoter__factory} from "../../typechain"; 4 | import {RunHelper} from "../utils/RunHelper"; 5 | import {deployContract, txParams} from "../deploy/DeployContract"; 6 | import {Misc} from "../utils/Misc"; 7 | import {TimeUtils} from "../../test/TimeUtils"; 8 | 9 | // tslint:disable-next-line:no-var-requires 10 | const {request, gql} = require('graphql-request') 11 | 12 | // tslint:disable-next-line:no-var-requires 13 | const hre = require("hardhat"); 14 | 15 | async function main() { 16 | const [signer] = await ethers.getSigners(); 17 | const core = Addresses.getCore(); 18 | 19 | // const gov = await Misc.impersonate('0xcc16d636dD05b52FF1D8B9CE09B09BC62b11412B') 20 | // const logic = await deployContract(hre, signer, 'PlatformVoter'); 21 | // await ControllerV2__factory.connect(core.controller, gov).announceProxyUpgrade([core.platformVoter], [logic.address]); 22 | // await TimeUtils.advanceBlocksOnTs(60 * 60 * 24 * 2); 23 | // await ControllerV2__factory.connect(core.controller, gov).upgradeProxy([core.platformVoter]); 24 | 25 | 26 | const voter = PlatformVoter__factory.connect(core.platformVoter, signer); 27 | 28 | const data = await request('https://api.thegraph.com/subgraphs/name/tetu-io/tetu-v2', gql` 29 | query { 30 | platformVoterEntities { 31 | votes(first: 1000) { 32 | desiredValue 33 | date 34 | newValue 35 | percent 36 | target 37 | voteType 38 | veWeightedValue 39 | vePower 40 | veNFT { 41 | veNFTId 42 | } 43 | } 44 | } 45 | } 46 | `); 47 | 48 | const votes = data.platformVoterEntities[0].votes; 49 | 50 | const minDate = new Map() 51 | for (const vote of votes) { 52 | const md = minDate.get(+vote.veNFT.veNFTId) ?? Date.now(); 53 | if (md > +vote.date) { 54 | // console.log(new Date(vote.date * 1000), 'value: ', vote.newValue, 'power: ', Number(vote.vePower).toFixed(), 've: ', vote.veNFT.veNFTId); 55 | minDate.set(+vote.veNFT.veNFTId, +vote.date); 56 | } 57 | } 58 | 59 | console.log('total ve voted', minDate.size); 60 | 61 | const vePokes: number[] = []; 62 | for (const [veId, md] of minDate.entries()) { 63 | const time = Date.now() - 60 * 60 * 24 * 21 * 1000; 64 | if (md * 1000 < time) { 65 | console.log('ve: ', veId, 'min date: ', new Date(md * 1000)); 66 | vePokes.push(veId); 67 | } 68 | } 69 | 70 | console.log('total ve pokes', vePokes.length); 71 | 72 | const skipVe = new Set([]); 73 | 74 | for (const veId of vePokes) { 75 | console.log('poke ve: ', veId); 76 | if (skipVe.has(veId)) { 77 | continue; 78 | } 79 | const params = await txParams(hre, ethers.provider); 80 | await RunHelper.runAndWait(() => voter.poke(veId, {...params})); 81 | } 82 | 83 | } 84 | 85 | main() 86 | .then(() => process.exit(0)) 87 | .catch(error => { 88 | console.error(error); 89 | process.exit(1); 90 | }); 91 | -------------------------------------------------------------------------------- /scripts/models/CoreAddresses.ts: -------------------------------------------------------------------------------- 1 | export class CoreAddresses { 2 | 3 | public readonly tetu: string; 4 | public readonly controller: string; 5 | public readonly ve: string; 6 | public readonly veDist: string; 7 | public readonly gauge: string; 8 | public readonly bribe: string; 9 | public readonly tetuVoter: string; 10 | public readonly platformVoter: string; 11 | public readonly forwarder: string; 12 | public readonly vaultFactory: string; 13 | public readonly investFundV2: string; 14 | 15 | 16 | constructor(tetu: string, controller: string, ve: string, veDist: string, gauge: string, bribe: string, tetuVoter: string, platformVoter: string, forwarder: string, vaultFactory: string, investFundV2: string) { 17 | this.tetu = tetu; 18 | this.controller = controller; 19 | this.ve = ve; 20 | this.veDist = veDist; 21 | this.gauge = gauge; 22 | this.bribe = bribe; 23 | this.tetuVoter = tetuVoter; 24 | this.platformVoter = platformVoter; 25 | this.forwarder = forwarder; 26 | this.vaultFactory = vaultFactory; 27 | this.investFundV2 = investFundV2; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /scripts/models/ToolsAddresses.ts: -------------------------------------------------------------------------------- 1 | export class ToolsAddresses { 2 | 3 | public readonly liquidator: string; 4 | public readonly converter: string; 5 | public readonly multicall: string; 6 | 7 | 8 | constructor(liquidator: string, converter: string, multicall: string) { 9 | this.liquidator = liquidator; 10 | this.converter = converter; 11 | this.multicall = multicall; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /scripts/test/CreateMockPair.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {Addresses} from "../addresses/addresses"; 3 | import { 4 | ControllerV2__factory, 5 | IERC20Metadata__factory, 6 | MultiGauge__factory, 7 | VaultFactory__factory 8 | } from "../../typechain"; 9 | import {RunHelper} from "../utils/RunHelper"; 10 | 11 | 12 | const TOKEN0 = '0x27af55366a339393865FC5943C04bc2600F55C9F'; 13 | const TOKEN1 = '0x0ed08c9A2EFa93C4bF3C8878e61D2B6ceD89E9d7'; 14 | const FACTORY = '0xB6Ca119F30B3E7F6589F8a053c2a10B753846e78'; 15 | 16 | async function main() { 17 | const signer = (await ethers.getSigners())[0]; 18 | 19 | } 20 | 21 | main() 22 | .then(() => process.exit(0)) 23 | .catch(error => { 24 | console.error(error); 25 | process.exit(1); 26 | }); 27 | -------------------------------------------------------------------------------- /scripts/test/MakeNoizeOnTestnet.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import { 3 | ControllerV2__factory, 4 | IERC20__factory, 5 | MultiBribe__factory, 6 | MultiGauge__factory, 7 | StakelessMultiPoolBase__factory, 8 | TetuVoter__factory, 9 | VeTetu__factory 10 | } from "../../typechain"; 11 | import {Addresses} from "../addresses/addresses"; 12 | import {formatUnits, parseUnits} from "ethers/lib/utils"; 13 | import {RunHelper} from "../utils/RunHelper"; 14 | import {Misc} from "../utils/Misc"; 15 | import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; 16 | 17 | const USDC = '0x27af55366a339393865FC5943C04bc2600F55C9F'; 18 | const BTC = '0x0ed08c9A2EFa93C4bF3C8878e61D2B6ceD89E9d7'; 19 | const WETH = '0x078b7c9304eBA754e916016E8A8939527076f991'; 20 | 21 | async function main() { 22 | const signer = (await ethers.getSigners())[0]; 23 | const core = Addresses.getCore(); 24 | 25 | const vaults = await ControllerV2__factory.connect(core.controller, signer).vaultsList(); 26 | 27 | const bribe = MultiBribe__factory.connect(core.bribe, signer); 28 | const gauge = MultiGauge__factory.connect(core.gauge, signer); 29 | 30 | for (const vault of vaults) { 31 | 32 | await registerTokenIfnOtExist(signer, gauge.address, vault, USDC); 33 | const gaugeLeft = await gauge.left(vault, USDC) 34 | if (gaugeLeft.lt(parseUnits('1', 6))) { 35 | await RunHelper.runAndWait(() => gauge.notifyRewardAmount(vault, USDC, parseUnits('1', 6))); 36 | } 37 | 38 | await registerTokenIfnOtExist(signer, bribe.address, vault, WETH); 39 | const bribeLeft = await bribe.left(vault, WETH) 40 | if (bribeLeft.lt(parseUnits('1'))) { 41 | await RunHelper.runAndWait(() => bribe.notifyRewardAmount(vault, WETH, parseUnits('1'))) 42 | } 43 | const veBalance = await VeTetu__factory.connect(core.ve, signer).balanceOf(signer.address); 44 | console.log('ve balance', veBalance.toString()); 45 | for (let i = 0; i < veBalance.toNumber(); i++) { 46 | if (!veBalance.isZero()) { 47 | const veId = (await VeTetu__factory.connect(core.ve, signer).tokenOfOwnerByIndex(signer.address, i)).toNumber() 48 | const power = await VeTetu__factory.connect(core.ve, signer).balanceOfNFT(veId) 49 | console.log('veId', veId, formatUnits(power)) 50 | if (!power.isZero()) { 51 | 52 | const voter = TetuVoter__factory.connect(core.tetuVoter, signer); 53 | const lastVote = (await voter.lastVote(veId)).toNumber(); 54 | console.log('lastVote', new Date(lastVote * 1000)) 55 | if ((lastVote + 60 * 60 * 24 * 7) < (Date.now() / 1000)) { 56 | await RunHelper.runAndWait(() => voter.vote(veId, [vault], [100])); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | } 64 | 65 | async function registerTokenIfnOtExist(signer: SignerWithAddress, pool: string, vault: string, token: string) { 66 | const poolCtr = StakelessMultiPoolBase__factory.connect(pool, signer); 67 | const rtLength = (await poolCtr.rewardTokensLength(vault)).toNumber(); 68 | const rts = new Set(); 69 | for (let i = 0; i < rtLength; i++) { 70 | const rt = await poolCtr.rewardTokens(vault, i); 71 | rts.add(rt.toLowerCase()); 72 | } 73 | if (!rts.has(token.toLowerCase())) { 74 | await RunHelper.runAndWait(() => poolCtr.registerRewardToken(vault, token)); 75 | } 76 | 77 | const allowance = await IERC20__factory.connect(token, signer).allowance(signer.address, pool) 78 | if (allowance.lt(parseUnits('100'))) { 79 | await RunHelper.runAndWait(() => IERC20__factory.connect(token, signer).approve(pool, Misc.MAX_UINT)); 80 | } 81 | } 82 | 83 | main() 84 | .then(() => process.exit(0)) 85 | .catch(error => { 86 | console.error(error); 87 | process.exit(1); 88 | }); 89 | -------------------------------------------------------------------------------- /scripts/utils/Misc.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {Logger} from "tslog"; 3 | import Common from "ethereumjs-common"; 4 | import logSettings from "../../log_settings"; 5 | 6 | const log: Logger = new Logger(logSettings); 7 | 8 | const MATIC_CHAIN = Common.forCustomChain( 9 | 'mainnet', { 10 | name: 'matic', 11 | networkId: 137, 12 | chainId: 137 13 | }, 14 | 'petersburg' 15 | ); 16 | 17 | const FANTOM_CHAIN = Common.forCustomChain( 18 | 'mainnet', { 19 | name: 'fantom', 20 | networkId: 250, 21 | chainId: 250 22 | }, 23 | 'petersburg' 24 | ); 25 | 26 | // tslint:disable-next-line:no-var-requires 27 | const hre = require("hardhat"); 28 | 29 | export class Misc { 30 | public static readonly SECONDS_OF_DAY = 60 * 60 * 24; 31 | public static readonly SECONDS_OF_YEAR = Misc.SECONDS_OF_DAY * 365; 32 | public static readonly ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; 33 | public static readonly MAX_UINT = '115792089237316195423570985008687907853269984665640564039457584007913129639935'; 34 | public static readonly MAX_UINT_MINUS_ONE = '115792089237316195423570985008687907853269984665640564039457584007913129639934'; 35 | 36 | public static printDuration(text: string, start: number) { 37 | log.info('>>>' + text, ((Date.now() - start) / 1000).toFixed(1), 'sec'); 38 | } 39 | 40 | // public static async getBlockTsFromChain(): Promise { 41 | // const signer = (await ethers.getSigners())[0]; 42 | // const tools = await DeployerUtils.getToolsAddresses(); 43 | // const ctr = await DeployerUtils.connectInterface(signer, 'Multicall', tools.multicall) as Multicall; 44 | // const ts = await ctr.getCurrentBlockTimestamp(); 45 | // return ts.toNumber(); 46 | // } 47 | 48 | public static async getChainConfig() { 49 | const net = await ethers.provider.getNetwork(); 50 | switch (net.chainId) { 51 | case 137: 52 | return MATIC_CHAIN; 53 | case 250: 54 | return FANTOM_CHAIN; 55 | default: 56 | throw new Error('Unknown net ' + net.chainId) 57 | } 58 | } 59 | 60 | // ************** ADDRESSES ********************** 61 | 62 | public static async impersonate(address: string) { 63 | await hre.network.provider.request({ 64 | method: "hardhat_impersonateAccount", 65 | params: [address], 66 | }); 67 | 68 | await hre.network.provider.request({ 69 | method: "hardhat_setBalance", 70 | params: [address, "0x1431E0FAE6D7217CAA0000000"], 71 | }); 72 | // console.log('address impersonated', address); 73 | return ethers.getSigner(address); 74 | } 75 | 76 | public static isNotNetwork(id: number) { 77 | return hre.network.config.chainId !== id; 78 | } 79 | 80 | public static async getStorageAt(address: string, index: string) { 81 | return ethers.provider.getStorageAt(address, index); 82 | } 83 | 84 | public static async setStorageAt(address: string, index: string, value: string) { 85 | await ethers.provider.send("hardhat_setStorageAt", [address, index, value]); 86 | await ethers.provider.send("evm_mine", []); // Just mines to the next block 87 | } 88 | 89 | // ****************** WAIT ****************** 90 | 91 | public static async delay(ms: number) { 92 | return new Promise(resolve => setTimeout(resolve, ms)); 93 | } 94 | 95 | public static async wait(blocks: number) { 96 | if (hre.network.name === 'hardhat') { 97 | return; 98 | } 99 | const start = ethers.provider.blockNumber; 100 | while (true) { 101 | log.info('wait 10sec'); 102 | await Misc.delay(10000); 103 | if (ethers.provider.blockNumber >= start + blocks) { 104 | break; 105 | } 106 | } 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /scripts/utils/UpdateBlock.ts: -------------------------------------------------------------------------------- 1 | import {fetchJson} from "ethers/lib/utils"; 2 | import * as fs from "fs"; 3 | 4 | const _getBlockUrl = 'https://api.polygonscan.com/api?module=proxy&action=eth_blockNumber'; 5 | const _envFilename = '.env' 6 | const _envParamName = 'TETU_MATIC_FORK_BLOCK'; 7 | 8 | async function updateBlockNumber(url: string, envFilename: string, envParamName: string) { 9 | const blockData = await fetchJson({url}); 10 | const blockNumber = Number(blockData.result) - 32; // hardhat needs block that has at least 32 confirmations 11 | replaceParamInEnvFile(envFilename, envParamName, blockNumber.toString()); 12 | console.log(_envParamName, 'replaced to', blockNumber, 'in file', envFilename); 13 | } 14 | 15 | function replaceParamInEnvFile(envFileName: string,envParamName: string, newValue: string) { 16 | const envContent = fs.readFileSync(envFileName).toString(); 17 | const pattern = new RegExp(`^${envParamName}=.+$`, 'm'); 18 | const newContent = envContent.replace(pattern, envParamName+'='+newValue); 19 | fs.writeFileSync(envFileName, newContent); 20 | } 21 | 22 | updateBlockNumber(_getBlockUrl, _envFilename, _envParamName).then(); 23 | -------------------------------------------------------------------------------- /scripts/utils/VerifyUtils.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import axios from "axios"; 3 | import {config as dotEnvConfig} from "dotenv"; 4 | import logSettings from "../../log_settings"; 5 | import {Logger} from "tslog"; 6 | 7 | // tslint:disable-next-line:no-var-requires 8 | const hre = require("hardhat"); 9 | const log: Logger = new Logger(logSettings); 10 | 11 | 12 | dotEnvConfig(); 13 | // tslint:disable-next-line:no-var-requires 14 | const argv = require('yargs/yargs')() 15 | .env('TETU') 16 | .options({ 17 | networkScanKey: { 18 | type: "string", 19 | }, 20 | }).argv; 21 | 22 | 23 | export class VerifyUtils { 24 | 25 | 26 | public static async verify(address: string) { 27 | try { 28 | await hre.run("verify:verify", { 29 | address 30 | }) 31 | } catch (e) { 32 | log.info('error verify ' + e); 33 | } 34 | } 35 | 36 | // tslint:disable-next-line:no-any 37 | public static async verifyWithArgs(address: string, args: any[]) { 38 | try { 39 | await hre.run("verify:verify", { 40 | address, constructorArguments: args 41 | }) 42 | } catch (e) { 43 | log.info('error verify ' + e); 44 | } 45 | } 46 | 47 | // tslint:disable-next-line:no-any 48 | public static async verifyWithContractName(address: string, contractPath: string, args?: any[]) { 49 | try { 50 | await hre.run("verify:verify", { 51 | address, contract: contractPath, constructorArguments: args 52 | }) 53 | } catch (e) { 54 | log.info('error verify ' + e); 55 | } 56 | } 57 | 58 | // tslint:disable-next-line:no-any 59 | public static async verifyWithArgsAndContractName(address: string, args: any[], contractPath: string) { 60 | try { 61 | await hre.run("verify:verify", { 62 | address, constructorArguments: args, contract: contractPath 63 | }) 64 | } catch (e) { 65 | log.info('error verify ' + e); 66 | } 67 | } 68 | 69 | public static async verifyProxy(adr: string) { 70 | try { 71 | 72 | const resp = 73 | await axios.post( 74 | (await VerifyUtils.getNetworkScanUrl()) + 75 | `?module=contract&action=verifyproxycontract&apikey=${argv.networkScanKey}`, 76 | `address=${adr}`); 77 | // log.info("proxy verify resp", resp.data); 78 | } catch (e) { 79 | log.info('error proxy verify ' + adr + e); 80 | } 81 | } 82 | 83 | public static async getNetworkScanUrl(): Promise { 84 | const net = (await ethers.provider.getNetwork()); 85 | if (net.name === 'ropsten') { 86 | return 'https://api-ropsten.etherscan.io/api'; 87 | } else if (net.name === 'kovan') { 88 | return 'https://api-kovan.etherscan.io/api'; 89 | } else if (net.name === 'rinkeby') { 90 | return 'https://api-rinkeby.etherscan.io/api'; 91 | } else if (net.name === 'ethereum') { 92 | return 'https://api.etherscan.io/api'; 93 | } else if (net.name === 'matic') { 94 | return 'https://api.polygonscan.com/api' 95 | } else if (net.chainId === 80001) { 96 | return 'https://api-testnet.polygonscan.com/api' 97 | } else if (net.chainId === 250) { 98 | return 'https://api.ftmscan.com//api' 99 | } else { 100 | throw Error('network not found ' + net); 101 | } 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /scripts/utils/Web3Utils.ts: -------------------------------------------------------------------------------- 1 | import {web3} from "hardhat"; 2 | import {DeployerUtils} from "./DeployerUtils"; 3 | 4 | export class Web3Utils { 5 | 6 | 7 | public static async parseLogs(contract: string, topics: string[], start: number, end: number, step = 3_000) { 8 | const logs = []; 9 | 10 | console.log('parseLogs', start, end); 11 | let from = start; 12 | let to = start + step; 13 | while (true) { 14 | try { 15 | logs.push(...(await web3.eth.getPastLogs({ 16 | fromBlock: from, 17 | toBlock: to, 18 | address: contract, 19 | "topics": topics 20 | }))); 21 | 22 | console.log('logs', from, to, logs.length); 23 | 24 | from = to; 25 | to = Math.min(from + step, end); 26 | 27 | if (from >= end) { 28 | break; 29 | } 30 | } catch (e) { 31 | console.log('Error fetch logs', e); 32 | await DeployerUtils.delay(1000); 33 | } 34 | } 35 | 36 | return logs; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /slither.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "detectors_to_exclude": "naming-convention,low-level-calls,assembly,reentrancy-events,reentrancy-benign,divide-before-multiply,reentrancy-eth,reentrancy-no-eth,reentrancy-unlimited-gas,incorrect-equality,costly-loop,timestamp,similar-names,too-many-digits,calls-loop,solc-version", 3 | "disable_color": true, 4 | "filter_paths": "(node_modules/|contracts/test/|contracts/openzeppelin/)", 5 | "ignore_compile": true 6 | } 7 | -------------------------------------------------------------------------------- /test/TestAsserts.ts: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import {BigNumber, ContractTransaction, Event, utils} from "ethers"; 3 | import chaiAsPromised from "chai-as-promised"; 4 | 5 | const {expect} = chai; 6 | chai.use(chaiAsPromised); 7 | 8 | export class TestAsserts { 9 | 10 | public static async assertEvent( 11 | tx: ContractTransaction, 12 | eventName: string, 13 | // tslint:disable-next-line:no-any 14 | args: any[], 15 | eIdx = 0 16 | ) { 17 | const receipt = await tx.wait(); 18 | 19 | const events = receipt.events?.filter((e) => e.event === eventName) as Event[]; 20 | expect(events !== undefined).is.eq(true, `Event ${eventName} not found`); 21 | const event = events[eIdx]; 22 | event.args?.forEach((value, i) => { 23 | if (i + 1 > args.length) { 24 | return; 25 | } 26 | if (typeof value === 'string') { 27 | expect(typeof args[i]).is.eq('string', `Arg ${i} is not string`); 28 | expect(value.toLowerCase()).is.eq(args[i].toLowerCase(), `Arg ${i} is not equal`); 29 | } else if (value instanceof BigNumber) { 30 | expect(value.toString()).is.eq(BigNumber.from(args[i]).toString(), `Arg ${i} is not equal`); 31 | } else { 32 | expect(value).is.eq(args[i], `Arg ${i} is not equal`); 33 | } 34 | }); 35 | } 36 | 37 | public static closeTo(actual: BigNumber, expected: BigNumber, deltaFactor: number, dec = 18) { 38 | const actualN = +utils.formatUnits(actual); 39 | const expectedN = +utils.formatUnits(expected); 40 | expect(actualN).to.be.closeTo(expectedN, expectedN * deltaFactor); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /test/TimeUtils.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {Misc} from "../scripts/utils/Misc"; 3 | import {Multicall} from "../typechain"; 4 | 5 | export const LOCK_PERIOD = 60 * 60 * 24 * 7 * 16; 6 | 7 | export class TimeUtils { 8 | 9 | public static async advanceBlocksOnTs(add: number) { 10 | const start = Date.now(); 11 | // const block = await TimeUtils.currentBlock(); 12 | await ethers.provider.send('evm_increaseTime', [add]); 13 | await ethers.provider.send('evm_mine', []); 14 | // await TimeUtils.mineAndCheck(); 15 | Misc.printDuration('advanceBlocksOnTs ' + add + ' completed', start); 16 | } 17 | 18 | public static async advanceNBlocks(n: number) { 19 | const start = Date.now(); 20 | await ethers.provider.send('evm_increaseTime', [+(n * 2.35).toFixed(0)]); 21 | for (let i = 0; i < n; i++) { 22 | await ethers.provider.send('evm_mine', []); 23 | } 24 | Misc.printDuration('advanceNBlocks ' + n + ' completed', start); 25 | } 26 | 27 | public static async mineAndCheck() { 28 | const start = ethers.provider.blockNumber; 29 | while (true) { 30 | await ethers.provider.send('evm_mine', []); 31 | if (ethers.provider.blockNumber > start) { 32 | break; 33 | } 34 | console.log('waite mine 10sec'); 35 | await Misc.delay(10000); 36 | } 37 | } 38 | 39 | public static async setBlock(blockNumber: number) { 40 | await ethers.provider.send('evm_setNextBlockTimestamp', [blockNumber]); 41 | } 42 | 43 | public static async setNextBlockTime(ts: number) { 44 | await ethers.provider.send('evm_setNextBlockTimestamp', [ts]); 45 | await ethers.provider.send('evm_mine', []); 46 | } 47 | 48 | // // doesn't work, need to investigate 49 | // public static async currentBlock() { 50 | // const tools = await DeployerUtils.getToolsAddresses(); 51 | // const multicall = Multicall__factory.connect(tools.multicall, ethers.provider); 52 | // const blockHash = await multicall.getLastBlockHash(); 53 | // return (await ethers.provider.getBlock(blockHash)).number; 54 | // } 55 | 56 | public static async getBlockTime(multicall: Multicall, block?: number | null): Promise { 57 | if (block) { 58 | return (await multicall.getCurrentBlockTimestamp({blockTag: block})).toNumber(); 59 | } else { 60 | return (await multicall.getCurrentBlockTimestamp()).toNumber(); 61 | } 62 | } 63 | 64 | public static async snapshot() { 65 | const id = await ethers.provider.send("evm_snapshot", []); 66 | console.log("made snapshot", id); 67 | return id; 68 | } 69 | 70 | public static async rollback(id: string) { 71 | console.log("restore snapshot", id); 72 | return ethers.provider.send("evm_revert", [id]); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /test/TokenUtils.ts: -------------------------------------------------------------------------------- 1 | import {IERC20__factory, MockToken__factory} from "../typechain"; 2 | import {BigNumber} from "ethers"; 3 | import {PolygonAddresses as MaticAddresses} from "../scripts/addresses/polygon"; 4 | import {parseUnits} from "ethers/lib/utils"; 5 | import {Misc} from "../scripts/utils/Misc"; 6 | import {BaseAddresses} from "../scripts/addresses/base"; 7 | 8 | export class TokenUtils { 9 | 10 | // use the most neutral place, some contracts (like swap pairs) can be used in tests and direct transfer ruin internal logic 11 | public static TOKEN_HOLDERS = new Map([ 12 | [MaticAddresses.WMATIC_TOKEN, '0x8df3aad3a84da6b69a4da8aec3ea40d9091b2ac4'.toLowerCase()], // aave 13 | [MaticAddresses.WETH_TOKEN, '0x28424507fefb6f7f8e9d3860f56504e4e5f5f390'.toLowerCase()], // aave 14 | [MaticAddresses.WBTC_TOKEN, '0x5c2ed810328349100a66b82b78a1791b101c9d61'.toLowerCase()], // aave v2 15 | [MaticAddresses.USDC_TOKEN, '0x1a13f4ca1d028320a707d99520abfefca3998b7f'.toLowerCase()], // aave 16 | [MaticAddresses.USDT_TOKEN, '0x0D0707963952f2fBA59dD06f2b425ace40b492Fe'.toLowerCase()], // adr 17 | [MaticAddresses.TETU_TOKEN, '0x7ad5935ea295c4e743e4f2f5b4cda951f41223c2'.toLowerCase()], // fund keeper 18 | [MaticAddresses.AAVE_TOKEN, '0x1d2a0e5ec8e5bbdca5cb219e649b565d8e5c3360'.toLowerCase()], // aave 19 | [MaticAddresses.DAI_TOKEN, '0xBA12222222228d8Ba445958a75a0704d566BF2C8'.toLowerCase()], // balancer 20 | [MaticAddresses.LINK_TOKEN, '0xBA12222222228d8Ba445958a75a0704d566BF2C8'.toLowerCase()], // balancer 21 | [MaticAddresses.BAL_TOKEN, '0xBA12222222228d8Ba445958a75a0704d566BF2C8'.toLowerCase()], // balancer 22 | [MaticAddresses.QI_TOKEN, '0x3FEACf904b152b1880bDE8BF04aC9Eb636fEE4d8'.toLowerCase()], // qidao gov 23 | [MaticAddresses.xTETU, '0x352f9fa490a86f625f53e581f0ec3bd649fd8bc9'.toLowerCase()], 24 | [MaticAddresses.BALANCER_TETU_USDC, '0x2F5294b805f6c0b4B7942c88111d8fB3c0597051'.toLowerCase()], 25 | 26 | [BaseAddresses.USDbC_TOKEN, '0x4c80e24119cfb836cdf0a6b53dc23f04f7e652ca'.toLowerCase()], 27 | [BaseAddresses.TETU_TOKEN, '0x0644141dd9c2c34802d28d334217bd2034206bf7'.toLowerCase()], 28 | [BaseAddresses.tUSDbC, '0x0644141dd9c2c34802d28d334217bd2034206bf7'.toLowerCase()], 29 | ]); 30 | 31 | public static async getToken(token: string, to: string, amount?: BigNumber) { 32 | const start = Date.now(); 33 | const holder = TokenUtils.TOKEN_HOLDERS.get(token.toLowerCase()) as string; 34 | if (!holder) { 35 | throw new Error('Please add holder for ' + token); 36 | } 37 | const signer = await Misc.impersonate(holder); 38 | const name = await MockToken__factory.connect(token, signer).name(); 39 | console.log('transfer token from biggest holder', name, token, amount?.toString()); 40 | 41 | if (name.endsWith('_MOCK_TOKEN')) { 42 | const amount0 = amount || parseUnits('100'); 43 | await MockToken__factory.connect(token, signer).mint(to, amount0); 44 | return amount0; 45 | } 46 | 47 | const balance = (await IERC20__factory.connect(token, signer).balanceOf(holder)).div(100); 48 | console.log('holder balance', balance.toString()); 49 | if (amount) { 50 | await IERC20__factory.connect(token, signer).transfer(to, amount) 51 | } else { 52 | await IERC20__factory.connect(token, signer).transfer(to, balance) 53 | } 54 | Misc.printDuration('getToken completed', start); 55 | return balance; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /test/infrastructure/InvestFundV2Test.ts: -------------------------------------------------------------------------------- 1 | import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; 2 | import {ethers} from "hardhat"; 3 | import chai from "chai"; 4 | import {TimeUtils} from "../TimeUtils"; 5 | import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; 6 | import {Misc} from "../../scripts/utils/Misc"; 7 | import {ControllerV2, InvestFundV2, InvestFundV2__factory, MockToken, ProxyControlled__factory} from "../../typechain"; 8 | import {parseUnits} from "ethers/lib/utils"; 9 | 10 | 11 | const {expect} = chai; 12 | 13 | describe("invest fund v2 tests", function () { 14 | 15 | let snapshotBefore: string; 16 | let snapshot: string; 17 | 18 | let signer: SignerWithAddress; 19 | let signer2: SignerWithAddress; 20 | 21 | let fund: InvestFundV2; 22 | let tetu: MockToken; 23 | 24 | 25 | before(async function () { 26 | snapshotBefore = await TimeUtils.snapshot(); 27 | [signer, signer2] = await ethers.getSigners(); 28 | 29 | const controller = await DeployerUtils.deployController(signer); 30 | tetu = await DeployerUtils.deployMockToken(signer, 'TETU'); 31 | const fundAdr = await DeployerUtils.deployProxy(signer, 'InvestFundV2'); 32 | fund = InvestFundV2__factory.connect(fundAdr, signer); 33 | await fund.init(controller.address); 34 | }); 35 | 36 | after(async function () { 37 | await TimeUtils.rollback(snapshotBefore); 38 | }); 39 | 40 | 41 | beforeEach(async function () { 42 | snapshot = await TimeUtils.snapshot(); 43 | }); 44 | 45 | afterEach(async function () { 46 | await TimeUtils.rollback(snapshot); 47 | }); 48 | 49 | it("withdraw test", async function () { 50 | const bal = await tetu.balanceOf(signer.address); 51 | await tetu.transfer(fund.address, parseUnits('1')); 52 | await fund.withdraw(tetu.address, parseUnits('1')) 53 | expect(await tetu.balanceOf(signer.address)).eq(bal); 54 | }); 55 | 56 | it("withdraw not gov revert", async function () { 57 | await expect(fund.connect(signer2).withdraw(tetu.address, parseUnits('1'))).revertedWith('!gov'); 58 | }); 59 | 60 | it("deposit test", async function () { 61 | await tetu.approve(fund.address, parseUnits('1')) 62 | await fund.deposit(tetu.address, parseUnits('1')) 63 | expect(await tetu.balanceOf(fund.address)).eq(parseUnits('1')) 64 | expect((await fund.tokens())[0]).eq(tetu.address) 65 | }); 66 | 67 | it("deposit zero test", async function () { 68 | await fund.deposit(tetu.address, 0) 69 | expect((await fund.tokens())[0]).eq(tetu.address) 70 | }); 71 | 72 | }); 73 | -------------------------------------------------------------------------------- /test/lib/Base64Test.ts: -------------------------------------------------------------------------------- 1 | import {ethers, network} from "hardhat"; 2 | import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; 3 | import {expect} from "chai"; 4 | import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; 5 | import { 6 | Base64Test, 7 | SlotsTest, 8 | SlotsTest2, 9 | SlotsTest2__factory, 10 | SlotsTest__factory 11 | } from "../../typechain"; 12 | import {TimeUtils} from "../TimeUtils"; 13 | 14 | describe("Base64 Tests", function () { 15 | let snapshotBefore: string; 16 | let snapshot: string; 17 | let signer: SignerWithAddress; 18 | 19 | let helper: Base64Test; 20 | 21 | before(async function () { 22 | snapshotBefore = await TimeUtils.snapshot(); 23 | [signer] = await ethers.getSigners(); 24 | helper = await DeployerUtils.deployContract(signer, 'Base64Test') as Base64Test; 25 | }); 26 | 27 | after(async function () { 28 | await TimeUtils.rollback(snapshotBefore); 29 | }); 30 | 31 | 32 | beforeEach(async function () { 33 | snapshot = await TimeUtils.snapshot(); 34 | }); 35 | 36 | afterEach(async function () { 37 | await TimeUtils.rollback(snapshot); 38 | }); 39 | 40 | 41 | it("empty data test", async () => { 42 | await helper.encode('0x') 43 | }); 44 | 45 | }) 46 | -------------------------------------------------------------------------------- /test/lib/StringLibTest.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; 3 | import {expect} from "chai"; 4 | import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; 5 | import { 6 | ControllerMinimal, ProxyControlled, ProxyControlled__factory, 7 | SlotsTest, 8 | SlotsTest2, 9 | SlotsTest2__factory, 10 | SlotsTest__factory, StringLibFacade 11 | } from "../../typechain"; 12 | import {formatBytes32String} from "ethers/lib/utils"; 13 | import {TimeUtils} from "../TimeUtils"; 14 | import {Addresses} from "../../scripts/addresses/addresses"; 15 | import {Misc} from "../../scripts/utils/Misc"; 16 | import {utils} from "ethers"; 17 | 18 | describe("StringLibTest", function () { 19 | let snapshotBefore: string; 20 | let snapshot: string; 21 | let signer: SignerWithAddress; 22 | let lib: StringLibFacade; 23 | 24 | before(async function () { 25 | snapshotBefore = await TimeUtils.snapshot(); 26 | [signer] = await ethers.getSigners(); 27 | 28 | lib = await DeployerUtils.deployContract(signer, 'StringLibFacade') as StringLibFacade; 29 | }); 30 | 31 | after(async function () { 32 | await TimeUtils.rollback(snapshotBefore); 33 | }); 34 | 35 | 36 | beforeEach(async function () { 37 | snapshot = await TimeUtils.snapshot(); 38 | }); 39 | 40 | afterEach(async function () { 41 | await TimeUtils.rollback(snapshot); 42 | }); 43 | 44 | 45 | it("toString", async () => { 46 | expect(await lib.uintToString(100)).eq('100') 47 | }); 48 | 49 | it("toAsciiString", async () => { 50 | expect(await lib.toAsciiString(Misc.ZERO_ADDRESS)).eq('0000000000000000000000000000000000000000') 51 | }); 52 | 53 | it("char", async () => { 54 | expect(await lib.char(utils.toUtf8Bytes('z'))).eq('0xd1') 55 | }); 56 | 57 | 58 | }) 59 | -------------------------------------------------------------------------------- /test/proxy/ControllableTest.ts: -------------------------------------------------------------------------------- 1 | import {ethers, network} from "hardhat"; 2 | import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; 3 | import {expect} from "chai"; 4 | import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; 5 | import { 6 | Base64Test, ControllableTest, ControllableTest__factory, ControllerMinimal, 7 | SlotsTest, 8 | SlotsTest2, 9 | SlotsTest2__factory, 10 | SlotsTest__factory 11 | } from "../../typechain"; 12 | import {TimeUtils} from "../TimeUtils"; 13 | import {Misc} from "../../scripts/utils/Misc"; 14 | 15 | describe("Controllable Tests", function () { 16 | let snapshotBefore: string; 17 | let snapshot: string; 18 | let signer: SignerWithAddress; 19 | 20 | let helper: ControllableTest; 21 | 22 | before(async function () { 23 | snapshotBefore = await TimeUtils.snapshot(); 24 | [signer] = await ethers.getSigners(); 25 | helper = ControllableTest__factory.connect(await DeployerUtils.deployProxy(signer, 'ControllableTest'), signer); 26 | }); 27 | 28 | after(async function () { 29 | await TimeUtils.rollback(snapshotBefore); 30 | }); 31 | 32 | 33 | beforeEach(async function () { 34 | snapshot = await TimeUtils.snapshot(); 35 | }); 36 | 37 | afterEach(async function () { 38 | await TimeUtils.rollback(snapshot); 39 | }); 40 | 41 | 42 | it("zero governance revert", async () => { 43 | const controller = await DeployerUtils.deployContract(signer, 'ControllerMinimal', Misc.ZERO_ADDRESS) as ControllerMinimal; 44 | await expect(helper.init(controller.address)).revertedWith('Zero governance'); 45 | }); 46 | 47 | it("zero controller revert", async () => { 48 | await expect(helper.init(Misc.ZERO_ADDRESS)).revertedWith('Zero controller'); 49 | }); 50 | 51 | it("revision test", async () => { 52 | await helper.increase(); 53 | expect(await helper.revision()).eq(1); 54 | }); 55 | 56 | it("prev impl test", async () => { 57 | await helper.increase(); 58 | expect(await helper.previousImplementation()).eq(helper.address); 59 | }); 60 | 61 | it("created block test", async () => { 62 | const controller = await DeployerUtils.deployContract(signer, 'ControllerMinimal', signer.address) as ControllerMinimal; 63 | await helper.init(controller.address); 64 | expect(await helper.createdBlock()).above(0); 65 | expect(await helper.created()).above(0); 66 | }); 67 | 68 | it("increase rev revert test", async () => { 69 | await expect(helper.increaseRevision(Misc.ZERO_ADDRESS)).revertedWith('Increase revision forbidden'); 70 | }); 71 | 72 | it("read private variable", async () => { 73 | const controller = await DeployerUtils.deployContract(signer, 'ControllerMinimal', signer.address) as ControllerMinimal; 74 | await helper.init(controller.address); 75 | const bytes32Result = await helper.getSlot(1) 76 | const bytes32Expected = ethers.utils.hexZeroPad(ethers.utils.hexlify(333), 32) 77 | expect(bytes32Result).eq(bytes32Expected); 78 | }); 79 | }) 80 | -------------------------------------------------------------------------------- /test/test-utils.ts: -------------------------------------------------------------------------------- 1 | import {VeTetu} from "../typechain"; 2 | import {formatUnits} from "ethers/lib/utils"; 3 | import chai from "chai"; 4 | 5 | const {expect} = chai; 6 | 7 | export const WEEK = 60 * 60 * 24 * 7; 8 | export const LOCK_PERIOD = 60 * 60 * 24 * 90; 9 | 10 | export async function currentEpochTS(ve: VeTetu) { 11 | const blockTs = await currentTS(ve) 12 | return Math.floor(blockTs / WEEK) * WEEK; 13 | } 14 | 15 | export async function currentTS(ve: VeTetu) { 16 | return (await ve.blockTimestamp()).toNumber(); 17 | } 18 | 19 | export async function checkTotalVeSupplyAtTS(ve: VeTetu, ts: number) { 20 | await ve.checkpoint(); 21 | 22 | console.log('additionalTotalSupply', formatUnits(await ve.additionalTotalSupply())) 23 | 24 | const total = +formatUnits(await ve.totalSupply()); 25 | console.log('total', total) 26 | const nftCount = (await ve.tokenId()).toNumber(); 27 | 28 | let sum = 0; 29 | for (let i = 1; i <= nftCount; ++i) { 30 | const bal = +formatUnits(await ve.balanceOfNFT(i)) 31 | console.log('bal', i, bal) 32 | sum += bal; 33 | } 34 | console.log('sum', sum) 35 | expect(sum).approximately(total, 0.0000000000001); 36 | console.log('total supply is fine') 37 | } 38 | -------------------------------------------------------------------------------- /test/tools/ArbitragePoolSolidlyTest.ts: -------------------------------------------------------------------------------- 1 | import hre, {ethers} from "hardhat"; 2 | import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; 3 | import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; 4 | import {ArbitragePoolSolidly, IERC20__factory, ISolidlyPair__factory, TetuVaultV2__factory} from "../../typechain"; 5 | import {TimeUtils} from "../TimeUtils"; 6 | import {BaseAddresses} from "../../scripts/addresses/base"; 7 | import {TokenUtils} from "../TokenUtils"; 8 | import {formatUnits, parseUnits} from "ethers/lib/utils"; 9 | import {Misc} from "../../scripts/utils/Misc"; 10 | 11 | describe("ArbitragePoolSolidlyTest", function () { 12 | let snapshotBefore: string; 13 | let snapshot: string; 14 | let signer: SignerWithAddress; 15 | 16 | let arb: ArbitragePoolSolidly; 17 | 18 | before(async function () { 19 | snapshotBefore = await TimeUtils.snapshot(); 20 | [signer] = await ethers.getSigners(); 21 | if (hre.network.config.chainId !== 8453) { 22 | return; 23 | } 24 | arb = await DeployerUtils.deployContract(signer, 'ArbitragePoolSolidly') as ArbitragePoolSolidly; 25 | }); 26 | 27 | after(async function () { 28 | await TimeUtils.rollback(snapshotBefore); 29 | }); 30 | 31 | 32 | beforeEach(async function () { 33 | snapshot = await TimeUtils.snapshot(); 34 | }); 35 | 36 | afterEach(async function () { 37 | await TimeUtils.rollback(snapshot); 38 | }); 39 | 40 | 41 | it("arbitrage test", async () => { 42 | if (hre.network.config.chainId !== 8453) { 43 | return; 44 | } 45 | 46 | const token0 = BaseAddresses.TETU_TOKEN; 47 | const token1 = BaseAddresses.tUSDbC; 48 | const pool = BaseAddresses.TETU_tUSDbC_AERODROME_LP; 49 | 50 | await TokenUtils.getToken(BaseAddresses.USDbC_TOKEN, signer.address, parseUnits('100000', 6)); 51 | await IERC20__factory.connect(BaseAddresses.USDbC_TOKEN, signer).approve(BaseAddresses.tUSDbC, Misc.MAX_UINT); 52 | // await TetuVaultV2__factory.connect(BaseAddresses.tUSDbC, signer).deposit(parseUnits('20000', 6), pool); 53 | await TetuVaultV2__factory.connect(BaseAddresses.tUSDbC, signer).deposit(parseUnits('20000', 6), arb.address); 54 | // await TokenUtils.getToken(token0, pool, parseUnits('1000000')); 55 | // await ISolidlyPair__factory.connect(pool, signer).swap(parseUnits('1', 6), 0, signer.address, '0x'); 56 | 57 | const rr = await ISolidlyPair__factory.connect(pool, signer).getReserves(); 58 | console.log('r0', rr[0].toString()) 59 | console.log('r1', rr[1].toString()) 60 | 61 | // await TokenUtils.getToken(token0, signer.address, parseUnits('1000')); 62 | // await TokenUtils.getToken(token1, signer.address, parseUnits('1000', 6)); 63 | 64 | await TokenUtils.getToken(token0, arb.address, parseUnits('100000')); 65 | 66 | 67 | 68 | await arb.arbitrage(pool, '5575'); 69 | 70 | console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!', formatUnits(await arb.getCurrentPrice(pool), 6)) 71 | 72 | await arb.arbitrage(pool, '9999'); 73 | 74 | console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!', formatUnits(await arb.getCurrentPrice(pool), 6)) 75 | 76 | await arb.arbitrage(pool, '3000'); 77 | 78 | console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!', formatUnits(await arb.getCurrentPrice(pool), 6)) 79 | 80 | await arb.arbitrage(pool, '15000'); 81 | 82 | console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!', formatUnits(await arb.getCurrentPrice(pool), 6)) 83 | 84 | await arb.arbitrage(pool, '15000'); 85 | }); 86 | 87 | 88 | }) 89 | -------------------------------------------------------------------------------- /test/tools/BribeDistributorTest.ts: -------------------------------------------------------------------------------- 1 | // import chai from "chai"; 2 | // import chaiAsPromised from "chai-as-promised"; 3 | // import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; 4 | // import {BribeDistribution, MockToken,} from "../../typechain"; 5 | // import {TimeUtils} from "../TimeUtils"; 6 | // import {ethers} from "hardhat"; 7 | // import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; 8 | // 9 | // const {expect} = chai; 10 | // chai.use(chaiAsPromised); 11 | // 12 | // describe("BribeDistributorTest", function () { 13 | // let snapshotBefore: string; 14 | // let snapshot: string; 15 | // let signer: SignerWithAddress; 16 | // let signer2: SignerWithAddress; 17 | // 18 | // let distr: BribeDistribution; 19 | // let token: MockToken; 20 | // 21 | // 22 | // before(async function () { 23 | // this.timeout(1200000); 24 | // snapshotBefore = await TimeUtils.snapshot(); 25 | // [signer, signer2] = await ethers.getSigners(); 26 | // 27 | // token = await DeployerUtils.deployMockToken(signer, 'TETU', 18); 28 | // const controller = await DeployerUtils.deployMockController(signer); 29 | // const ve = await DeployerUtils.deployVeTetu(signer, token.address, controller.address); 30 | // 31 | // const veDist = await DeployerUtils.deployVeDistributor( 32 | // signer, 33 | // controller.address, 34 | // ve.address, 35 | // token.address, 36 | // ); 37 | // 38 | // distr = await DeployerUtils.deployContract(signer, "BribeDistribution", veDist.address, token.address) as BribeDistribution; 39 | // }) 40 | // 41 | // after(async function () { 42 | // await TimeUtils.rollback(snapshotBefore); 43 | // }); 44 | // 45 | // beforeEach(async function () { 46 | // snapshot = await TimeUtils.snapshot(); 47 | // }); 48 | // 49 | // afterEach(async function () { 50 | // await TimeUtils.rollback(snapshot); 51 | // }); 52 | // 53 | // it("set new owner test", async () => { 54 | // await expect(distr.connect(signer2).offerOwnership(signer2.address)).revertedWith('NOT_OWNER'); 55 | // await distr.offerOwnership(signer2.address) 56 | // await expect(distr.acceptOwnership()).revertedWith('NOT_OWNER'); 57 | // await distr.connect(signer2).acceptOwnership() 58 | // expect(await distr.owner()).eq(signer2.address) 59 | // await expect(distr.offerOwnership(signer2.address)).revertedWith('NOT_OWNER'); 60 | // }) 61 | // 62 | // it("manualNotify test", async () => { 63 | // await token.approve(distr.address, 1000) 64 | // const veDist = await distr.veDist(); 65 | // 66 | // await distr.manualNotify(1000, true) 67 | // expect(await token.balanceOf(veDist)).eq(500); 68 | // 69 | // await distr.manualNotify(0, false) 70 | // expect(await token.balanceOf(veDist)).eq(1000); 71 | // }) 72 | // 73 | // it("autoNotify test", async () => { 74 | // const bal = await token.balanceOf(signer.address); 75 | // await token.approve(distr.address, bal) 76 | // const veDist = await distr.veDist(); 77 | // 78 | // await distr.autoNotify() 79 | // expect(await token.balanceOf(veDist)).eq(bal.div(2)); 80 | // 81 | // await distr.autoNotify() 82 | // expect(await token.balanceOf(veDist)).eq(bal); 83 | // }) 84 | // }) 85 | -------------------------------------------------------------------------------- /test/tools/DepositHelperTests.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; 3 | import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; 4 | import {DepositHelperPolygon, IERC20__factory, MockToken, MockVault, VeTetu} from "../../typechain"; 5 | import {TimeUtils} from "../TimeUtils"; 6 | import {expect} from "chai"; 7 | import {Misc} from "../../scripts/utils/Misc"; 8 | 9 | describe("Deposit helper Tests", function () { 10 | let snapshotBefore: string; 11 | let snapshot: string; 12 | let signer: SignerWithAddress; 13 | let signer2: SignerWithAddress; 14 | let strategy: SignerWithAddress; 15 | 16 | 17 | let token: MockToken; 18 | let token2: MockToken; 19 | let vault: MockVault; 20 | let helper: DepositHelperPolygon; 21 | let ve: VeTetu; 22 | 23 | before(async function () { 24 | snapshotBefore = await TimeUtils.snapshot(); 25 | [signer, strategy, signer2] = await ethers.getSigners(); 26 | 27 | const controller = await DeployerUtils.deployMockController(signer); 28 | token = await DeployerUtils.deployMockToken(signer); 29 | token2 = await DeployerUtils.deployMockToken(signer); 30 | vault = await DeployerUtils.deployMockVault(signer, controller.address, token.address, 'V', strategy.address, 1); 31 | helper = await DeployerUtils.deployContract(signer, 'DepositHelperPolygon', token.address) as DepositHelperPolygon; 32 | 33 | ve = await DeployerUtils.deployVeTetu(signer, token.address, controller.address); 34 | 35 | await token.connect(strategy).approve(vault.address, 99999999999); 36 | 37 | await token.approve(vault.address, 10000); 38 | await vault.deposit(10000, signer.address); 39 | }); 40 | 41 | after(async function () { 42 | await TimeUtils.rollback(snapshotBefore); 43 | }); 44 | 45 | 46 | beforeEach(async function () { 47 | snapshot = await TimeUtils.snapshot(); 48 | }); 49 | 50 | afterEach(async function () { 51 | await TimeUtils.rollback(snapshot); 52 | }); 53 | 54 | 55 | it("test deposit", async () => { 56 | await token.approve(helper.address, 100) 57 | await helper.deposit(vault.address, token.address, 100, 99) 58 | expect(await vault.balanceOf(signer.address)).eq(8999); 59 | 60 | await token.approve(helper.address, 100) 61 | await expect(helper.deposit(vault.address, token.address, 100, 101)).to.be.revertedWith('SLIPPAGE') 62 | 63 | await token.approve(helper.address, 100) 64 | await helper.deposit(vault.address, token.address, 100, 99) 65 | expect(await vault.balanceOf(signer.address)).eq(9098); 66 | 67 | await IERC20__factory.connect(vault.address, signer).approve(helper.address, 198) 68 | await expect(helper.withdraw(vault.address, 198, 199)).to.be.revertedWith('SLIPPAGE') 69 | 70 | const balanceBefore = await token.balanceOf(signer.address) 71 | await helper.withdraw(vault.address, 198, 198) 72 | expect((await token.balanceOf(signer.address)).sub(balanceBefore)).eq(198); 73 | }); 74 | 75 | it("test create lock", async () => { 76 | await token.approve(helper.address, 1000) 77 | await helper.createLock(ve.address, token.address, 1000, 60 * 60 * 24 * 30); 78 | expect((await ve.lockedAmounts(1, token.address))).eq(1000); 79 | }); 80 | 81 | it("test increase amount", async () => { 82 | await token.approve(helper.address, 1000) 83 | await helper.createLock(ve.address, token.address, 1000, 60 * 60 * 24 * 30); 84 | await token.approve(helper.address, 1000) 85 | await helper.increaseAmount(ve.address, token.address, 1, 1000); 86 | expect((await ve.lockedAmounts(1, token.address))).eq(2000); 87 | }); 88 | 89 | }) 90 | -------------------------------------------------------------------------------- /test/tools/PerfFeeTreasuryTest.ts: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import chaiAsPromised from "chai-as-promised"; 3 | import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; 4 | import {PerfFeeTreasury,} from "../../typechain"; 5 | import {TimeUtils} from "../TimeUtils"; 6 | import {ethers} from "hardhat"; 7 | import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; 8 | 9 | const {expect} = chai; 10 | chai.use(chaiAsPromised); 11 | 12 | describe("PerfFeeTreasuryTest", function () { 13 | let snapshotBefore: string; 14 | let snapshot: string; 15 | let signer: SignerWithAddress; 16 | let signer2: SignerWithAddress; 17 | 18 | let treasury: PerfFeeTreasury; 19 | 20 | 21 | before(async function () { 22 | this.timeout(1200000); 23 | snapshotBefore = await TimeUtils.snapshot(); 24 | [signer, signer2] = await ethers.getSigners(); 25 | 26 | treasury = await DeployerUtils.deployContract(signer, "PerfFeeTreasury", signer.address) as PerfFeeTreasury; 27 | }) 28 | 29 | after(async function () { 30 | await TimeUtils.rollback(snapshotBefore); 31 | }); 32 | 33 | beforeEach(async function () { 34 | snapshot = await TimeUtils.snapshot(); 35 | }); 36 | 37 | afterEach(async function () { 38 | await TimeUtils.rollback(snapshot); 39 | }); 40 | 41 | it("set new gov", async () => { 42 | await expect(treasury.connect(signer2).offerOwnership(signer2.address)).revertedWith('NOT_GOV'); 43 | await treasury.offerOwnership(signer2.address) 44 | await expect(treasury.acceptOwnership()).revertedWith('NOT_GOV'); 45 | await treasury.connect(signer2).acceptOwnership() 46 | expect(await treasury.governance()).eq(signer2.address) 47 | await expect(treasury.offerOwnership(signer2.address)).revertedWith('NOT_GOV'); 48 | }) 49 | 50 | it("claim", async () => { 51 | const token = await DeployerUtils.deployMockToken(signer); 52 | const token2 = await DeployerUtils.deployMockToken(signer); 53 | 54 | await token.transfer(treasury.address, 1000) 55 | await token2.transfer(treasury.address, 500) 56 | 57 | expect(await token.balanceOf(treasury.address)).eq(1000); 58 | expect(await token2.balanceOf(treasury.address)).eq(500); 59 | 60 | await expect(treasury.connect(signer2).claim([token.address, token2.address])).revertedWith('NOT_GOV'); 61 | await treasury.claim([token.address, token2.address]); 62 | 63 | expect(await token.balanceOf(treasury.address)).eq(0); 64 | expect(await token2.balanceOf(treasury.address)).eq(0); 65 | }) 66 | }) 67 | -------------------------------------------------------------------------------- /test/tools/TetuERC165Test.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "hardhat"; 2 | import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; 3 | import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; 4 | import {InterfaceIds, MockToken, TetuERC165Test} from "../../typechain"; 5 | import {TimeUtils} from "../TimeUtils"; 6 | import {expect} from "chai"; 7 | import {constants} from "ethers"; 8 | 9 | describe("TetuERC165Test", function () { 10 | let snapshotBefore: string; 11 | let snapshot: string; 12 | let signer: SignerWithAddress; 13 | 14 | let test: TetuERC165Test; 15 | let interfaceIds: InterfaceIds; 16 | let token: MockToken; 17 | 18 | before(async function () { 19 | snapshotBefore = await TimeUtils.snapshot(); 20 | [signer] = await ethers.getSigners(); 21 | 22 | interfaceIds = await DeployerUtils.deployContract(signer, 'InterfaceIds') as InterfaceIds; 23 | test = await DeployerUtils.deployContract(signer, 'TetuERC165Test') as TetuERC165Test; 24 | token = await DeployerUtils.deployMockToken(signer, 'TOKEN', 18); 25 | 26 | }); 27 | 28 | after(async function () { 29 | await TimeUtils.rollback(snapshotBefore); 30 | }); 31 | 32 | 33 | beforeEach(async function () { 34 | snapshot = await TimeUtils.snapshot(); 35 | }); 36 | 37 | afterEach(async function () { 38 | await TimeUtils.rollback(snapshot); 39 | }); 40 | 41 | 42 | it("is interface supported", async () => { 43 | await expect(test.isInterfaceSupported(constants.AddressZero, '0x00000000')).revertedWith('Zero address') 44 | expect(await test.isInterfaceSupported(signer.address, '0x00000000')).eq(false); 45 | expect(await test.isInterfaceSupported(test.address, '0x00000000')).eq(false); 46 | expect(await test.isInterfaceSupported(test.address, await interfaceIds.I_TETU_ERC165())).eq(true); 47 | expect(await test.isInterfaceSupported(token.address, await interfaceIds.I_CONTROLLER())).eq(false); 48 | }); 49 | 50 | it("require interface", async () => { 51 | const I_TETU_ERC165 = await interfaceIds.I_TETU_ERC165(); 52 | const I_CONTROLLER = await interfaceIds.I_CONTROLLER(); 53 | expect(await test.requireInterface(test.address, I_TETU_ERC165)).deep.eq([]); // executed without return values 54 | expect(test.requireInterface(test.address, '0x00000000')).revertedWith('Interface is not supported'); 55 | expect(test.requireInterface(test.address, I_CONTROLLER)).revertedWith('Interface is not supported'); 56 | }); 57 | 58 | it("is ERC20", async () => { 59 | await expect(test.isERC20(constants.AddressZero)).revertedWith('Zero address'); 60 | expect(await test.isERC20(signer.address)).eq(false); 61 | expect(await test.isERC20(test.address)).eq(false); 62 | expect(await test.isERC20(token.address)).eq(true); 63 | }); 64 | 65 | 66 | it("require ERC20", async () => { 67 | expect(await test.requireERC20(token.address)).deep.eq([]); // executed without return values 68 | expect(test.requireERC20(test.address)).revertedWith('Not ERC20'); 69 | expect(test.requireERC20(ethers.constants.AddressZero)).revertedWith('Not ERC20'); 70 | }); 71 | 72 | 73 | }) 74 | -------------------------------------------------------------------------------- /test/vault/VaultFactoryPolygonTests.ts: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import chaiAsPromised from "chai-as-promised"; 3 | import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; 4 | import hre, {ethers} from "hardhat"; 5 | import {TimeUtils} from "../TimeUtils"; 6 | import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; 7 | import {VaultFactory, VaultFactory__factory} from "../../typechain"; 8 | import {Misc} from "../../scripts/utils/Misc"; 9 | import {CoreAddresses} from "../../scripts/models/CoreAddresses"; 10 | import {Addresses} from "../../scripts/addresses/addresses"; 11 | import {PolygonAddresses} from "../../scripts/addresses/polygon"; 12 | 13 | 14 | const {expect} = chai; 15 | chai.use(chaiAsPromised); 16 | 17 | describe("Vault factory tests", function () { 18 | let snapshotBefore: string; 19 | let snapshot: string; 20 | let signer: SignerWithAddress; 21 | let gov: SignerWithAddress; 22 | let core: CoreAddresses; 23 | let factory: VaultFactory; 24 | 25 | 26 | before(async function () { 27 | [signer] = await ethers.getSigners() 28 | snapshotBefore = await TimeUtils.snapshot(); 29 | if (hre.network.config.chainId !== 137) { 30 | return; 31 | } 32 | 33 | gov = await Misc.impersonate(PolygonAddresses.GOVERNANCE); 34 | 35 | core = Addresses.getCore(); 36 | factory = VaultFactory__factory.connect(core.vaultFactory, gov); 37 | }); 38 | 39 | after(async function () { 40 | await TimeUtils.rollback(snapshotBefore); 41 | }); 42 | 43 | beforeEach(async function () { 44 | snapshot = await TimeUtils.snapshot(); 45 | }); 46 | 47 | afterEach(async function () { 48 | await TimeUtils.rollback(snapshot); 49 | }); 50 | 51 | it("set vault logic", async () => { 52 | if (hre.network.config.chainId !== 137) { 53 | return; 54 | } 55 | console.log('factory', factory.address); 56 | const vaultLogic = await DeployerUtils.deployContract(signer, 'TetuVaultV2'); 57 | await factory.setVaultImpl(vaultLogic.address); 58 | expect(await factory.vaultImpl()).to.be.eq(vaultLogic.address); 59 | }); 60 | 61 | it("set splitter logic", async () => { 62 | if (hre.network.config.chainId !== 137) { 63 | return; 64 | } 65 | const splitter = await DeployerUtils.deployContract(signer, 'StrategySplitterV2'); 66 | await factory.setSplitterImpl(splitter.address); 67 | expect(await factory.splitterImpl()).to.be.eq(splitter.address); 68 | }); 69 | 70 | 71 | }); 72 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "target": "es2019", 5 | "module": "commonjs", 6 | "strict": true, 7 | "esModuleInterop": true, 8 | "outDir": "dist", 9 | "resolveJsonModule": true, 10 | "declaration": true 11 | }, 12 | "include": [ 13 | "./scripts", 14 | "./test", 15 | "./typechain", 16 | "./tmp" 17 | ], 18 | "exclude": ["node_modules"], 19 | "files": [ 20 | "./hardhat.config.ts", 21 | "./scripts/addresses/addresses.ts" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint:latest" 4 | ], 5 | "rules": { 6 | "ban-ts-ignore": true, 7 | "no-any": true, 8 | "no-non-null-assertion": true, 9 | "object-literal-sort-keys": false, 10 | "promise-function-async": true, 11 | "await-promise": false, 12 | "no-submodule-imports": false, 13 | "interface-name": [true, "always-prefix"], 14 | "max-classes-per-file": [true, 1], 15 | "no-empty": false, 16 | "no-console": false, 17 | "only-arrow-functions": false, 18 | "variable-name": [ 19 | true, 20 | "check-format", 21 | "allow-leading-underscore", 22 | "allow-pascal-case" 23 | ], 24 | "ordered-imports": [ 25 | false 26 | ], 27 | "no-floating-promises": true, 28 | "prefer-conditional-expression": false, 29 | "no-implicit-dependencies": false, 30 | "indent": [ 31 | true, 32 | "spaces", 33 | 2 34 | ], 35 | "whitespace" : [false] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /veTETU.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 11 | ID: 12 | 3 13 | Balance: 14 | 333 15 | Until unlock: 16 | 88 days 17 | Power: 18 | 263 19 | 20 | --------------------------------------------------------------------------------