├── contracts ├── yfiipool2 │ ├── readme.md │ └── StrategyYfiiPool2.sol ├── interface │ ├── IVault.sol │ ├── IBalancer.sol │ ├── IController.sol │ ├── IPool.sol │ ├── IUniswapRouter.sol │ └── IERC20.sol ├── dforce │ ├── readme.md │ ├── yVaultUSDC.sol │ ├── DTokenProxy.sol │ ├── StrategyDForceUSDC.sol │ └── StrategyDForce.sol ├── readme.md ├── standard │ ├── readme.md │ └── Controller.sol ├── library │ └── SafeERC20.sol ├── t │ ├── swap1.sol │ └── swap.sol ├── yfiicontract.sol ├── Controller.sol ├── crvContract │ ├── cCrvGauge.vy │ └── ycrvGauge.vy ├── yfiipool1 │ └── StrategyCurveYfii.sol ├── yamsnx │ └── StrategySNXYam.sol ├── yamcomp │ └── StrategyCompYam.sol ├── yamstandard │ └── StrategySNXYam.sol └── yamweth │ └── StrategyWETHYam.sol ├── scripts ├── flat.sh └── deploy.sh ├── README.md ├── package.json ├── py ├── cal.py └── deploy.py ├── truffle-config.js └── .gitignore /contracts/yfiipool2/readme.md: -------------------------------------------------------------------------------- 1 | # StrategyYfiiPool2 2 | 3 | 接受bpt来挖 yfii 4 | 5 | yvault内置了 dai2bpt,bpt2dai 来方便转换 -------------------------------------------------------------------------------- /contracts/interface/IVault.sol: -------------------------------------------------------------------------------- 1 | 2 | pragma solidity ^0.5.5; 3 | 4 | interface IVault{ 5 | function make_profit(uint256 amount) external; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /contracts/interface/IBalancer.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.5; 2 | 3 | contract IBalancer { 4 | function swapExactAmountIn( 5 | address tokenIn, 6 | uint tokenAmountIn, 7 | address tokenOut, 8 | uint minAmountOut, 9 | uint maxPrice 10 | ) external returns (uint tokenAmountOut, uint spotPriceAfter); 11 | } -------------------------------------------------------------------------------- /contracts/interface/IController.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.5; 2 | 3 | interface IController { 4 | function withdraw(address, uint) external; 5 | function balanceOf(address) external view returns (uint); 6 | function earn(address, uint) external; 7 | function vaults(address) external view returns (address); 8 | function rewards() external view returns (address); 9 | } -------------------------------------------------------------------------------- /scripts/flat.sh: -------------------------------------------------------------------------------- 1 | echo "deploy begin....." 2 | 3 | TF_CMD=node_modules/.bin/truffle-flattener 4 | 5 | TOKEN_LIST=( StrategyDForce) 6 | for contract in ${TOKEN_LIST[@]}; 7 | do 8 | echo $contract 9 | $TF_CMD ./contracts/dforce/$contract.sol > $contract.full.sol 10 | mv $contract.full.sol ./deployments/$contract.full.sol 11 | done 12 | 13 | echo "deploy end....." -------------------------------------------------------------------------------- /contracts/interface/IPool.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.5; 2 | 3 | interface IPool { 4 | function withdraw(uint) external; 5 | function getReward() external; 6 | function stake(uint) external; 7 | function balanceOf(address) external view returns (uint); 8 | function exit() external; 9 | function earned(address) external view returns (uint); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /contracts/dforce/readme.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 3 | StrategyDForce实现DForce的香槟塔池挖矿: https://staking.dforce.network/ 4 | 5 | 用户存入DAI/USDT/USDC到yVault中,策略逻辑会把这些token转为会想要的dDai/dUSDT/dUSDC,拿着这些token去pool里面质押,获得df 6 | 7 | 目录中的DTokenProxy.sol, DToken.sol 是dToken系列中dUSDC的一种实现,供参考和测试用。 8 | 9 | 另外,为了方便维护,把代码做了分拆,抽取了部分公共的Inteface和Library。 10 | 11 | 可以通过脚本: 12 | 13 | npm run flat 14 | 15 | 合并代码,放在目录/deployments下:StrategyDForce.full.sol 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## yVault 2 | 3 | 环境... 4 | solc 0.5.15 5 | 6 | ```shell 7 | brew install solidity@5 8 | ``` 9 | 10 | python 3 11 | 12 | `pip install web3` 13 | 14 | [ganache-cli](https://github.com/trufflesuite/ganache-cli) 15 | 16 | 17 | ----------------------- 18 | 19 | ## new 20 | 21 | by reed 2020.8.19 22 | 23 | npm install 24 | 25 | npm run flat # generate full contract in deployments directory 26 | 27 | truffle compile # compile contract 28 | 29 | -------------------------------------------------------------------------------- /contracts/interface/IUniswapRouter.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | 4 | interface IUniswapRouter { 5 | function swapExactTokensForTokens( 6 | uint amountIn, 7 | uint amountOutMin, 8 | address[] calldata path, 9 | address to, 10 | uint deadline 11 | ) external returns (uint[] memory amounts); 12 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 13 | external returns (uint[] memory amounts); 14 | } 15 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | echo "deploy begin....." 2 | 3 | TF_CMD=node_modules/.bin/truffle-flattener 4 | 5 | TOKEN_LIST=(yVaultUSDC StrategyDForceUSDC) 6 | for contract in ${TOKEN_LIST[@]}; 7 | do 8 | echo $contract 9 | $TF_CMD ./contracts/dforce/$contract.sol > $contract.full.sol 10 | solcjs --bin --abi --optimize $contract.full.sol 11 | mv $contract.full.sol ./deployments/$contract.full.sol 12 | mv $contract_full_sol_$contract.bin ./deployments/$contract.full.bin 13 | mv $contract_full_sol_$contract.abi ./deployments/$contract.full.abi 14 | done 15 | 16 | rm *_sol_* 17 | 18 | echo "deploy end....." -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yvault", 3 | "version": "1.0.0", 4 | "description": "solc 0.5.15", 5 | "main": "truffle-config.js", 6 | "dependencies": { 7 | "@openzeppelin/contracts": "^2.4.0", 8 | "truffle": "^5.0.43", 9 | "solc": "^0.5.12", 10 | "truffle-flattener": "^1.3.0" 11 | }, 12 | "devDependencies": {}, 13 | "scripts": { 14 | "test": "echo \"Error: no test specified\" && exit 1", 15 | "flat": "scripts/flat.sh" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/reed-hong/yvault.git" 20 | }, 21 | "author": "reedhong", 22 | "license": "ISC", 23 | "bugs": { 24 | "url": "https://github.com/reed-hong/yvault/issues" 25 | }, 26 | "homepage": "https://github.com/reed-hong/yvault#readme" 27 | } 28 | -------------------------------------------------------------------------------- /contracts/interface/IERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.5; 2 | 3 | interface IERC20 { 4 | function totalSupply() external view returns (uint256); 5 | function balanceOf(address account) external view returns (uint256); 6 | function transfer(address recipient, uint256 amount) external returns (bool); 7 | function allowance(address owner, address spender) external view returns (uint256); 8 | function decimals() external view returns (uint); 9 | function name() external view returns (string memory); 10 | function approve(address spender, uint256 amount) external returns (bool); 11 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 12 | event Transfer(address indexed from, address indexed to, uint256 value); 13 | event Approval(address indexed owner, address indexed spender, uint256 value); 14 | } -------------------------------------------------------------------------------- /contracts/readme.md: -------------------------------------------------------------------------------- 1 | # yVault 2 | 3 | 4 | ## Controller 5 | 6 | earn -> Strategy.deposit 7 | 8 | withdrawall-> Strategy.withdrawall 9 | 10 | withdraw -> Strategy.withdraw 11 | 12 | balanceOf -> Strategy.balanceOf 13 | 14 | 15 | ## yvault: 16 | 17 | earn -> Controller.earn 18 | 19 | deposit:用户存钱 20 | 21 | withdraw:用户取钱。(钱不够触发。 Controller.withdraw 22 | 23 | claim: 用户领取分红 24 | 25 | make_profit: Strategy.harvest 触发分红. 26 | 27 | cal_out: 某个用户可领取的分红 28 | 29 | cal_out_pending: 某个用户在路上的分红(也就是分红还没有从挖矿合约领取.只能看到,无法领取,等harvest触发后就可以领取了) 30 | 31 | balanceOf: token.balanceOf(address(this)) + Controller.balanceOf (也就是TVL) 32 | 33 | ## Strategy 34 | 35 | deposit: 存钱到某个合约 获取利息啥的 36 | 37 | withdraw: 从某个合约取钱出来 38 | 39 | withdrawall: 把所有的钱从挖矿合约退出. 40 | 41 | harvest: 领取分红. 42 | 43 | balanceOf: 存放在挖矿合约里面的钱 44 | 45 | balanceOfPendingReward:还未从挖矿合约领取的收益. 46 | 47 | 48 | ## yam 相关合约 49 | 50 | yam:0x0e2298E3B3390e3b945a5456fBf59eCc3f55DA16 51 | 52 | wethpool:0x587A07cE5c265A38Dd6d42def1566BA73eeb06F5 weth:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 53 | snxpool:0x6c3FC1FFDb14D92394f40eeC91D9Ce8B807f132D snx:0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F 54 | lendpool:0x6009A344C7F993B16EBa2c673fefd2e07f9be5FD lend:0x80fB784B7eD66730e8b1DBd9820aFD29931aab03 55 | mkrpool:0xcFe1E539AcB2D489a651cA011a6eB93d32f97E23 mkr:0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2 56 | amplpool:0x9EbB67687FEE2d265D7b824714DF13622D90E663 ampl_lp:0xc5be99A02C6857f9Eac67BbCE58DF5572498F40c 57 | yfipool:0xc5B6488c7D5BeD173B76Bd5DCA712f45fB9EaEaB yfi:0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e 58 | linkpool:0xFDC28897A1E32B595f1f4f1D3aE0Df93B1eee452 link:0x514910771AF9Ca656af840dff83E8264EcF986CA 59 | comppool:0x8538E5910c6F80419CD3170c26073Ff238048c9E comp:0xc00e94Cb662C3520282E6f5717214004A7f26888 60 | 61 | -------------------------------------------------------------------------------- /py/cal.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from web3 import Web3, HTTPProvider 4 | 5 | w3url = "https://mainnet.infura.io/v3/998f64f3627548bbaf2630599c1eefca" 6 | 7 | w3 = Web3(HTTPProvider(w3url)) 8 | 9 | with open("abi/Yvault.json") as f: 10 | data = json.loads(f.read()) 11 | abi = data["abi"] 12 | 13 | 14 | def get_total_out(contract_address): 15 | contract_address = w3.toChecksumAddress(contract_address) 16 | contract_instance = w3.eth.contract(abi=abi, address=contract_address) 17 | total_out = contract_instance.functions.global_(0).call()[1] 18 | return total_out 19 | 20 | 21 | if __name__ == "__main__": 22 | vaults_address = [ 23 | "0xf693705e79ccc8707D3FcB4D89381CaC28e45a22", 24 | "0xd4bEf8D8D8d7cBB89f63933Db6907439f9E6Fd0f", 25 | "0xA2D35bcDFc271767903f0Ed4aF56a066F6c99Ae7", 26 | "0x537350b9301fCf045Eaf1CEa2F225276C89D5f6D", 27 | "0x4BD410A06FBB3A22C31017964D13Cbc5867d3d61", 28 | "0xCda9230923FCb25e26a20D7D9D12e1744405C9fC", 29 | "0x7AEFB9DCE3700B7CE8B1f556043BB1D436C77e0d", 30 | "0x2f4Ae3a95C7B457DB53706EEE8979aEca4ec0082", 31 | "0xD2db1EF55549eCdacb4e7da081216AE96f0Eedcb", 32 | "0xf5a232b1325769E09B303D7292589a2C7AEe2Aa4", 33 | "0x804a3DBb6C1f4c379B3ee985488Ef37C4cBbac5C", 34 | "0x35a228bBe17F7c6D1ebaCc59fcA3aC6733135E63", 35 | "0x8FDD31b72Cc18c965E6a7BC85174994e72799732", 36 | "0xA9C7216650dA5A9bbC049ffa56008029344DB010", 37 | "0x956da37db508901294f62488e030ce0871293270", 38 | "0x5c8Bb2C9C0bC2655dE05198de50651820b95C541", 39 | "0xed288394e3086fb90e43f4919b5d3661c05278be", 40 | "0xD2db1EF55549eCdacb4e7da081216AE96f0Eedcb", 41 | "0x7b0f825efe96dd46f1460227d634ea37b10ca7c5", 42 | "0xd0249f2e69098029b2b37c888c061a0d95f989a2", 43 | "0xa407c685422d6b4bf07809216bb597125312a790", 44 | "0xab721be37a57b7f91098cb5f11ae423dc76350a9", 45 | ] 46 | 47 | total_out = sum([get_total_out(i) for i in vaults_address]) 48 | total_out = total_out/1e18 49 | print(total_out) 50 | -------------------------------------------------------------------------------- /contracts/dforce/yVaultUSDC.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-07-26 3 | */ 4 | pragma solidity ^0.5.5; 5 | 6 | import '@openzeppelin/contracts/token/ERC20/ERC20.sol'; 7 | import '@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol'; 8 | import '@openzeppelin/contracts/token/ERC20/SafeERC20.sol'; 9 | import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; 10 | import '@openzeppelin/contracts/math/SafeMath.sol'; 11 | import '@openzeppelin/contracts/utils/Address.sol'; 12 | 13 | import '../interface/IController.sol'; 14 | 15 | contract yVaultUSDC is ERC20, ERC20Detailed { 16 | using SafeERC20 for IERC20; 17 | using Address for address; 18 | using SafeMath for uint256; 19 | 20 | IERC20 public token; 21 | 22 | uint public min = 9500; 23 | uint public constant max = 10000; 24 | 25 | address public governance; 26 | address public controller; 27 | 28 | constructor (address _token, address _controller) public ERC20Detailed( 29 | string(abi.encodePacked("yearn ", ERC20Detailed(_token).name())), 30 | string(abi.encodePacked("y", ERC20Detailed(_token).symbol())), 31 | ERC20Detailed(_token).decimals() 32 | ) { 33 | token = IERC20(_token); 34 | governance = msg.sender; 35 | controller = _controller; 36 | } 37 | 38 | function balance() public view returns (uint) { 39 | return token.balanceOf(address(this)) 40 | .add(IController(controller).balanceOf(address(token))); 41 | } 42 | 43 | function setMin(uint _min) external { 44 | require(msg.sender == governance, "!governance"); 45 | min = _min; 46 | } 47 | 48 | function setGovernance(address _governance) public { 49 | require(msg.sender == governance, "!governance"); 50 | governance = _governance; 51 | } 52 | 53 | function setController(address _controller) public { 54 | require(msg.sender == governance, "!governance"); 55 | controller = _controller; 56 | } 57 | 58 | // Custom logic in here for how much the vault allows to be borrowed 59 | // Sets minimum required on-hand to keep small withdrawals cheap 60 | function available() public view returns (uint) { 61 | return token.balanceOf(address(this)).mul(min).div(max); 62 | } 63 | 64 | function earn() public { 65 | uint _bal = available(); 66 | token.safeTransfer(controller, _bal); 67 | IController(controller).earn(address(token), _bal); 68 | } 69 | 70 | function deposit(uint _amount) external { 71 | uint _pool = balance(); 72 | token.safeTransferFrom(msg.sender, address(this), _amount); 73 | uint shares = 0; 74 | if (_pool == 0) { 75 | shares = _amount; 76 | } else { 77 | shares = (_amount.mul(totalSupply())).div(_pool); 78 | } 79 | _mint(msg.sender, shares); 80 | } 81 | 82 | // No rebalance implementation for lower fees and faster swaps 83 | function withdraw(uint _shares) external { 84 | uint r = (balance().mul(_shares)).div(totalSupply()); 85 | _burn(msg.sender, _shares); 86 | 87 | // Check balance 88 | uint b = token.balanceOf(address(this)); 89 | if (b < r) { 90 | uint _withdraw = r.sub(b); 91 | IController(controller).withdraw(address(token), _withdraw); 92 | uint _after = token.balanceOf(address(this)); 93 | uint _diff = _after.sub(b); 94 | if (_diff < _withdraw) { 95 | r = b.add(_diff); 96 | } 97 | } 98 | 99 | token.safeTransfer(msg.sender, r); 100 | } 101 | 102 | function getPricePerFullShare() public view returns (uint) { 103 | return balance().mul(1e18).div(totalSupply()); 104 | } 105 | } -------------------------------------------------------------------------------- /contracts/standard/readme.md: -------------------------------------------------------------------------------- 1 | ## contract address 2 | 3 | Controller: 0xe14e60d0f7fb15b1a98fde88a3415c17b023bf36 4 | 5 | ## WETH 6 | 7 | token: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 8 | 9 | vault: 0xf693705e79ccc8707D3FcB4D89381CaC28e45a22 10 | 11 | strategy: 0x602ec22B362B0E8ae658D18f4435fE8c5c23cA0C 12 | 13 | ## SNX 14 | 15 | token: 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F 16 | 17 | vault: 0xd4bEf8D8D8d7cBB89f63933Db6907439f9E6Fd0f 18 | 19 | strategy: 20 | 21 | ## LEND 22 | 23 | token: 0x80fB784B7eD66730e8b1DBd9820aFD29931aab03 24 | 25 | vault: 0xA2D35bcDFc271767903f0Ed4aF56a066F6c99Ae7 26 | 27 | strategy: 28 | 29 | ## MKR 30 | 31 | token:0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2 32 | 33 | vault: 0x537350b9301fCf045Eaf1CEa2F225276C89D5f6D 34 | 35 | strategy: 36 | 37 | ## YFI 38 | 39 | token:0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e 40 | 41 | vault: 0x4BD410A06FBB3A22C31017964D13Cbc5867d3d61 42 | 43 | strategy: 44 | 45 | ## LINK 46 | 47 | token:0x514910771AF9Ca656af840dff83E8264EcF986CA 48 | 49 | vault: 0xCda9230923FCb25e26a20D7D9D12e1744405C9fC 50 | 51 | strategy: 0x780c2450632ecb4be69DA859987Be4875545E90b 52 | 53 | ## COMP 54 | 55 | token:0xc00e94Cb662C3520282E6f5717214004A7f26888 56 | 57 | vault: 0x7AEFB9DCE3700B7CE8B1f556043BB1D436C77e0d 58 | 59 | strategy: 60 | 61 | ## WBTC 62 | 63 | token:0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599 64 | 65 | vault: 0x2f4Ae3a95C7B457DB53706EEE8979aEca4ec0082 66 | 67 | strategy: 68 | 69 | 70 | 71 | ## YCRV 72 | 73 | token : 0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8 74 | 75 | Strategy: 0x9eFE9FB2010B2c5fa7D34E69e709DD296d9c0bD9 76 | 77 | vault: 0xD2db1EF55549eCdacb4e7da081216AE96f0Eedcb 78 | 79 | Controller: 0xDE60d11E7cDBaC266Ad332DF289AD9dE2EE32e68(和上面的不一样) 80 | 81 | ## YFII 82 | 83 | token: 0xa1d0E215a23d7030842FC67cE582a6aFa3CCaB83 84 | 85 | Strategy: 0xe9bA312991e76116879b484135D2b86Ea27d0A0f v2 86 | 87 | vault: 0xf5a232b1325769E09B303D7292589a2C7AEe2Aa4 88 | 89 | 90 | ## USDT 91 | 92 | token: 0xdAC17F958D2ee523a2206206994597C13D831ec7 93 | 94 | Strategy: 0x88D89Bc6dF5777ef762D8b7c841b1a4E179dcc83 dforce 95 | 96 | vault: 0x804a3DBb6C1f4c379B3ee985488Ef37C4cBbac5C 97 | 98 | ## USDC 99 | 100 | token: 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 101 | 102 | Strategy: 103 | 104 | vault: 0x35a228bBe17F7c6D1ebaCc59fcA3aC6733135E63 105 | 106 | 107 | ## DAI 108 | 109 | token: 0x6B175474E89094C44Da98b954EedeAC495271d0F 110 | 111 | Strategy: 0x6285FF6AEF7BA5Bddeb67B033dc75f6Da0980191 112 | 113 | vault: 0x8FDD31b72Cc18c965E6a7BC85174994e72799732 114 | 115 | ## Curve.fi: cCrv Token (cDAI+cUSDC) 116 | 117 | token: 0x845838DF265Dcd2c412A1Dc9e959c7d08537f8a2 118 | 119 | Strategy: 0xEfb684AB29371e701CCe3CA9e3FD8f5E33042eee 120 | 121 | vault: 0xf811c062D14fdF9Fda95D6A2C54e137afE80De45 122 | 123 | ## Strategy的标准接口 124 | 125 | ### deposit 126 | 127 | ```function deposit() external ``` 128 | 129 | 质押代币到目标挖矿合约 130 | 131 | 132 | 133 | ### withdraw 134 | 135 | ```function withdraw(uint _amount) external``` 136 | 137 | 从挖矿合约取出质押的钱 138 | 139 | ### withdrawAll 140 | 141 | ```function withdrawAll() public returns (uint balance) ``` 142 | 143 | 提取目标挖矿合约里面所有的钱 144 | 145 | 146 | ### harvest 147 | 148 | ```function harvest() public``` 149 | 150 | 从挖矿合约收取利息->换算成收益代币(yfii)->分钱 151 | 152 | ### balanceOf 153 | 154 | ``` function balanceOf() public view returns (uint)``` 155 | 156 | 在目标合约存了多少钱. 157 | 158 | ### balanceOfPendingReward 159 | 160 | ```function balanceOfPendingReward() public view returns(uint)``` 161 | 162 | 有多少分红没有领取 163 | 164 | ### harvertYFII 165 | 166 | ``` function harvertYFII() public view returns(uint[] memory amounts)``` 167 | 168 | balanceOfPendingReward 的数量换算成yfii的个数. 169 | -------------------------------------------------------------------------------- /contracts/library/SafeERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "../interface/IERC20.sol"; 4 | import '@openzeppelin/contracts/math/SafeMath.sol'; 5 | import '@openzeppelin/contracts/utils/Address.sol'; 6 | 7 | /** 8 | * @title SafeERC20 9 | * @dev Wrappers around ERC20 operations that throw on failure (when the token 10 | * contract returns false). Tokens that return no value (and instead revert or 11 | * throw on failure) are also supported, non-reverting calls are assumed to be 12 | * successful. 13 | * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, 14 | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. 15 | */ 16 | library SafeERC20 { 17 | using SafeMath for uint256; 18 | using Address for address; 19 | 20 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 21 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 22 | } 23 | 24 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 25 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 26 | } 27 | 28 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 29 | // safeApprove should only be called when setting an initial allowance, 30 | // or when resetting it to zero. To increase and decrease it, use 31 | // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' 32 | // solhint-disable-next-line max-line-length 33 | require((value == 0) || (token.allowance(address(this), spender) == 0), 34 | "SafeERC20: approve from non-zero to non-zero allowance" 35 | ); 36 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 37 | } 38 | 39 | function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { 40 | uint256 newAllowance = token.allowance(address(this), spender).add(value); 41 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 42 | } 43 | 44 | function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { 45 | uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); 46 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 47 | } 48 | 49 | /** 50 | * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement 51 | * on the return value: the return value is optional (but if data is returned, it must not be false). 52 | * @param token The token targeted by the call. 53 | * @param data The call data (encoded using abi.encode or one of its variants). 54 | */ 55 | function callOptionalReturn(IERC20 token, bytes memory data) private { 56 | // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since 57 | // we're implementing it ourselves. 58 | 59 | // A Solidity high level call has three parts: 60 | // 1. The target address is checked to verify it contains contract code 61 | // 2. The call itself is made, and success asserted 62 | // 3. The return value is decoded, which in turn checks the size of the returned data. 63 | // solhint-disable-next-line max-line-length 64 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 65 | 66 | // solhint-disable-next-line avoid-low-level-calls 67 | (bool success, bytes memory returndata) = address(token).call(data); 68 | require(success, "SafeERC20: low-level call failed"); 69 | 70 | if (returndata.length > 0) { // Return data is optional 71 | // solhint-disable-next-line max-line-length 72 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Use this file to configure your truffle project. It's seeded with some 3 | * common settings for different networks and features like migrations, 4 | * compilation and testing. Uncomment the ones you need or modify 5 | * them to suit your project as necessary. 6 | * 7 | * More information about configuration can be found at: 8 | * 9 | * truffleframework.com/docs/advanced/configuration 10 | * 11 | * To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider) 12 | * to sign your transactions before they're sent to a remote public node. Infura accounts 13 | * are available for free at: infura.io/register. 14 | * 15 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate 16 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this 17 | * phrase from a file you've .gitignored so it doesn't accidentally become public. 18 | * 19 | */ 20 | 21 | // const HDWalletProvider = require('@truffle/hdwallet-provider'); 22 | // const infuraKey = "fj4jll3k....."; 23 | // 24 | // const fs = require('fs'); 25 | // const mnemonic = fs.readFileSync(".secret").toString().trim(); 26 | 27 | module.exports = { 28 | /** 29 | * Networks define how you connect to your ethereum client and let you set the 30 | * defaults web3 uses to send transactions. If you don't specify one truffle 31 | * will spin up a development blockchain for you on port 9545 when you 32 | * run `develop` or `test`. You can ask a truffle command to use a specific 33 | * network from the command line, e.g 34 | * 35 | * $ truffle test --network 36 | */ 37 | 38 | networks: { 39 | // Useful for testing. The `development` name is special - truffle uses it by default 40 | // if it's defined here and no other network is specified at the command line. 41 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal 42 | // tab if you use this network and you must also set the `host`, `port` and `network_id` 43 | // options below to some value. 44 | // 45 | development: { 46 | host: "127.0.0.1", // Localhost (default: none) 47 | port: 8545, // Standard Ethereum port (default: none) 48 | network_id: "*", // Any network (default: none) 49 | }, 50 | 51 | // Another network with more advanced options... 52 | // advanced: { 53 | // port: 8777, // Custom port 54 | // network_id: 1342, // Custom network 55 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000) 56 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) 57 | // from:
, // Account to send txs from (default: accounts[0]) 58 | // websockets: true // Enable EventEmitter interface for web3 (default: false) 59 | // }, 60 | 61 | // Useful for deploying to a public network. 62 | // NB: It's important to wrap the provider as a function. 63 | // ropsten: { 64 | // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), 65 | // network_id: 3, // Ropsten's id 66 | // gas: 5500000, // Ropsten has a lower block limit than mainnet 67 | // confirmations: 2, // # of confs to wait between deployments. (default: 0) 68 | // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 69 | // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 70 | // }, 71 | 72 | // Useful for private networks 73 | // private: { 74 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), 75 | // network_id: 2111, // This network is yours, in the cloud. 76 | // production: true // Treats this network as if it was a public net. (default: false) 77 | // } 78 | }, 79 | 80 | // Set default mocha options here, use special reporters etc. 81 | mocha: { 82 | // timeout: 100000 83 | }, 84 | 85 | // Configure your compilers 86 | compilers: { 87 | solc: { 88 | version: "0.5.16", // Fetch exact version from solc-bin (default: truffle's version) 89 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) 90 | settings: { // See the solidity docs for advice about optimization and evmVersion 91 | optimizer: { 92 | enabled: true, 93 | runs: 200 94 | }, 95 | // evmVersion: "byzantium" 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /contracts/dforce/DTokenProxy.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-08-04 3 | */ 4 | // from https://etherscan.io/address/0x16c9cf62d8dac4a38fb50ae5fa5d51e9170f3179#writeContract 5 | pragma solidity ^0.5.12; 6 | 7 | contract Proxy { 8 | function() external payable { 9 | _fallback(); 10 | } 11 | 12 | function _implementation() internal view returns (address); 13 | 14 | function _delegate(address implementation) internal { 15 | assembly { 16 | calldatacopy(0, 0, calldatasize) 17 | 18 | let result := delegatecall( 19 | gas, 20 | implementation, 21 | 0, 22 | calldatasize, 23 | 0, 24 | 0 25 | ) 26 | returndatacopy(0, 0, returndatasize) 27 | 28 | switch result 29 | case 0 { 30 | revert(0, returndatasize) 31 | } 32 | default { 33 | return(0, returndatasize) 34 | } 35 | } 36 | } 37 | 38 | function _willFallback() internal {} 39 | 40 | function _fallback() internal { 41 | _willFallback(); 42 | _delegate(_implementation()); 43 | } 44 | } 45 | 46 | library AddressUtils { 47 | function isContract(address addr) internal view returns (bool) { 48 | uint256 size; 49 | 50 | assembly { 51 | size := extcodesize(addr) 52 | } 53 | return size > 0; 54 | } 55 | } 56 | 57 | contract UpgradeabilityProxy is Proxy { 58 | event Upgraded(address implementation); 59 | 60 | bytes32 61 | private constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3; 62 | 63 | constructor(address _implementation) public { 64 | assert( 65 | IMPLEMENTATION_SLOT == 66 | keccak256("org.zeppelinos.proxy.implementation") 67 | ); 68 | 69 | _setImplementation(_implementation); 70 | } 71 | 72 | function _implementation() internal view returns (address impl) { 73 | bytes32 slot = IMPLEMENTATION_SLOT; 74 | assembly { 75 | impl := sload(slot) 76 | } 77 | } 78 | 79 | function _upgradeTo(address newImplementation) internal { 80 | _setImplementation(newImplementation); 81 | emit Upgraded(newImplementation); 82 | } 83 | 84 | function _setImplementation(address newImplementation) private { 85 | require( 86 | AddressUtils.isContract(newImplementation), 87 | "Cannot set a proxy implementation to a non-contract address" 88 | ); 89 | 90 | bytes32 slot = IMPLEMENTATION_SLOT; 91 | 92 | assembly { 93 | sstore(slot, newImplementation) 94 | } 95 | } 96 | } 97 | 98 | contract AdminUpgradeabilityProxy is UpgradeabilityProxy { 99 | event AdminChanged(address previousAdmin, address newAdmin); 100 | event AdminUpdated(address newAdmin); 101 | 102 | bytes32 103 | private constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b; 104 | bytes32 105 | private constant PENDING_ADMIN_SLOT = 0x54ac2bd5363dfe95a011c5b5a153968d77d153d212e900afce8624fdad74525c; 106 | 107 | modifier ifAdmin() { 108 | if (msg.sender == _admin()) { 109 | _; 110 | } else { 111 | _fallback(); 112 | } 113 | } 114 | 115 | constructor(address _implementation) 116 | public 117 | UpgradeabilityProxy(_implementation) 118 | { 119 | assert(ADMIN_SLOT == keccak256("org.zeppelinos.proxy.admin")); 120 | 121 | _setAdmin(msg.sender); 122 | } 123 | 124 | function admin() external ifAdmin returns (address) { 125 | return _admin(); 126 | } 127 | 128 | function pendingAdmin() external ifAdmin returns (address) { 129 | return _pendingAdmin(); 130 | } 131 | 132 | function implementation() external ifAdmin returns (address) { 133 | return _implementation(); 134 | } 135 | 136 | function changeAdmin(address _newAdmin) external ifAdmin { 137 | require( 138 | _newAdmin != address(0), 139 | "Cannot change the admin of a proxy to the zero address" 140 | ); 141 | require( 142 | _newAdmin != _admin(), 143 | "The current and new admin cannot be the same ." 144 | ); 145 | require( 146 | _newAdmin != _pendingAdmin(), 147 | "Cannot set the newAdmin of a proxy to the same address ." 148 | ); 149 | _setPendingAdmin(_newAdmin); 150 | emit AdminChanged(_admin(), _newAdmin); 151 | } 152 | 153 | function updateAdmin() external { 154 | address _newAdmin = _pendingAdmin(); 155 | require( 156 | _newAdmin != address(0), 157 | "Cannot change the admin of a proxy to the zero address" 158 | ); 159 | require( 160 | msg.sender == _newAdmin, 161 | "msg.sender and newAdmin must be the same ." 162 | ); 163 | _setAdmin(_newAdmin); 164 | _setPendingAdmin(address(0)); 165 | emit AdminUpdated(_newAdmin); 166 | } 167 | 168 | function upgradeTo(address newImplementation) external ifAdmin { 169 | _upgradeTo(newImplementation); 170 | } 171 | 172 | function upgradeToAndCall(address newImplementation, bytes calldata data) 173 | external 174 | payable 175 | ifAdmin 176 | { 177 | _upgradeTo(newImplementation); 178 | (bool success, ) = address(this).call.value(msg.value)(data); 179 | require(success, "upgradeToAndCall-error"); 180 | } 181 | 182 | function _admin() internal view returns (address adm) { 183 | bytes32 slot = ADMIN_SLOT; 184 | assembly { 185 | adm := sload(slot) 186 | } 187 | } 188 | 189 | function _pendingAdmin() internal view returns (address pendingAdm) { 190 | bytes32 slot = PENDING_ADMIN_SLOT; 191 | assembly { 192 | pendingAdm := sload(slot) 193 | } 194 | } 195 | 196 | function _setAdmin(address newAdmin) internal { 197 | bytes32 slot = ADMIN_SLOT; 198 | 199 | assembly { 200 | sstore(slot, newAdmin) 201 | } 202 | } 203 | 204 | function _setPendingAdmin(address pendingAdm) internal { 205 | bytes32 slot = PENDING_ADMIN_SLOT; 206 | 207 | assembly { 208 | sstore(slot, pendingAdm) 209 | } 210 | } 211 | 212 | function _willFallback() internal { 213 | require( 214 | msg.sender != _admin(), 215 | "Cannot call fallback function from the proxy admin" 216 | ); 217 | super._willFallback(); 218 | } 219 | } 220 | 221 | contract DTokenProxy is AdminUpgradeabilityProxy { 222 | constructor(address _implementation) 223 | public 224 | AdminUpgradeabilityProxy(_implementation) 225 | {} 226 | 227 | // Allow anyone to view the implementation address 228 | function dTokenImplementation() external view returns (address) { 229 | return _implementation(); 230 | } 231 | } -------------------------------------------------------------------------------- /contracts/t/swap1.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-07-31 3 | */ 4 | 5 | // SPDX-License-Identifier: MIT 6 | 7 | pragma solidity ^0.5.15; 8 | 9 | interface IERC20 { 10 | function totalSupply() external view returns (uint256); 11 | function balanceOf(address account) external view returns (uint256); 12 | function transfer(address recipient, uint256 amount) external returns (bool); 13 | function allowance(address owner, address spender) external view returns (uint256); 14 | function decimals() external view returns (uint); 15 | function approve(address spender, uint256 amount) external returns (bool); 16 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 17 | event Transfer(address indexed from, address indexed to, uint256 value); 18 | event Approval(address indexed owner, address indexed spender, uint256 value); 19 | } 20 | 21 | library SafeMath { 22 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 23 | uint256 c = a + b; 24 | require(c >= a, "SafeMath: addition overflow"); 25 | 26 | return c; 27 | } 28 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 29 | return sub(a, b, "SafeMath: subtraction overflow"); 30 | } 31 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 32 | require(b <= a, errorMessage); 33 | uint256 c = a - b; 34 | 35 | return c; 36 | } 37 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 38 | if (a == 0) { 39 | return 0; 40 | } 41 | 42 | uint256 c = a * b; 43 | require(c / a == b, "SafeMath: multiplication overflow"); 44 | 45 | return c; 46 | } 47 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 48 | return div(a, b, "SafeMath: division by zero"); 49 | } 50 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 51 | // Solidity only automatically asserts when dividing by 0 52 | require(b > 0, errorMessage); 53 | uint256 c = a / b; 54 | 55 | return c; 56 | } 57 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 58 | return mod(a, b, "SafeMath: modulo by zero"); 59 | } 60 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 61 | require(b != 0, errorMessage); 62 | return a % b; 63 | } 64 | } 65 | 66 | library Address { 67 | function isContract(address account) internal view returns (bool) { 68 | bytes32 codehash; 69 | bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; 70 | // solhint-disable-next-line no-inline-assembly 71 | assembly { codehash := extcodehash(account) } 72 | return (codehash != 0x0 && codehash != accountHash); 73 | } 74 | function toPayable(address account) internal pure returns (address payable) { 75 | return address(uint160(account)); 76 | } 77 | function sendValue(address payable recipient, uint256 amount) internal { 78 | require(address(this).balance >= amount, "Address: insufficient balance"); 79 | 80 | // solhint-disable-next-line avoid-call-value 81 | (bool success, ) = recipient.call.value(amount)(""); 82 | require(success, "Address: unable to send value, recipient may have reverted"); 83 | } 84 | } 85 | 86 | library SafeERC20 { 87 | using SafeMath for uint256; 88 | using Address for address; 89 | 90 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 91 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 92 | } 93 | 94 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 95 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 96 | } 97 | 98 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 99 | require((value == 0) || (token.allowance(address(this), spender) == 0), 100 | "SafeERC20: approve from non-zero to non-zero allowance" 101 | ); 102 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 103 | } 104 | function callOptionalReturn(IERC20 token, bytes memory data) private { 105 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 106 | 107 | // solhint-disable-next-line avoid-low-level-calls 108 | (bool success, bytes memory returndata) = address(token).call(data); 109 | require(success, "SafeERC20: low-level call failed"); 110 | 111 | if (returndata.length > 0) { // Return data is optional 112 | // solhint-disable-next-line max-line-length 113 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 114 | } 115 | } 116 | } 117 | 118 | interface CrvYvault{ 119 | function withdraw(uint _shares) external; 120 | } 121 | 122 | 123 | interface UniswapRouter { 124 | function swapExactTokensForTokens( 125 | uint amountIn, 126 | uint amountOutMin, 127 | address[] calldata path, 128 | address to, 129 | uint deadline 130 | ) external returns (uint[] memory amounts); 131 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 132 | external returns (uint[] memory amounts); 133 | 134 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 135 | uint amountIn, 136 | uint amountOutMin, 137 | address[] calldata path, 138 | address to, 139 | uint deadline 140 | ) external; 141 | } 142 | 143 | contract Swap { 144 | using SafeERC20 for IERC20; 145 | using Address for address; 146 | using SafeMath for uint256; 147 | 148 | address public owner; 149 | 150 | constructor()public{ 151 | owner = tx.origin; 152 | } 153 | modifier onlyOwner(){ 154 | require(msg.sender == owner,"not owner"); 155 | _; 156 | } 157 | 158 | address constant public yfii = address(0xa1d0E215a23d7030842FC67cE582a6aFa3CCaB83); 159 | address constant public unirouter = address(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); 160 | address constant public weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); 161 | address constant public dai = address(0x6B175474E89094C44Da98b954EedeAC495271d0F); 162 | address constant public pasta = address(0x08A2E41FB99A7599725190B9C970Ad3893fa33CF); 163 | address constant public yycrv = address(0x5dbcF33D8c2E976c6b560249878e6F1491Bca25c); 164 | address constant public ycrv = address(0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8); 165 | 166 | 167 | 168 | function doswap(uint256 _amount) public { 169 | IERC20(pasta).safeApprove(unirouter, 0); 170 | IERC20(pasta).safeApprove(unirouter, uint(-1)); 171 | address[] memory path2 = new address[](2); 172 | path2[0] = address(pasta); 173 | path2[1] = address(yycrv); 174 | UniswapRouter(unirouter).swapExactTokensForTokensSupportingFeeOnTransferTokens(IERC20(pasta).balanceOf(address(this)), 0, path2, address(this), now.add(1800)); 175 | 176 | //yycrv-> yvault-> ycrv 177 | CrvYvault(yycrv).withdraw(IERC20(yycrv).balanceOf(address(this))); 178 | 179 | //ycrv -> weth-> yfii 180 | IERC20(ycrv).safeApprove(unirouter, 0); 181 | IERC20(ycrv).safeApprove(unirouter, uint(-1)); 182 | address[] memory path3 = new address[](3); 183 | path3[0] = address(ycrv); 184 | path3[1] = address(weth); 185 | path3[2] = address(yfii); 186 | UniswapRouter(unirouter).swapExactTokensForTokens(IERC20(ycrv).balanceOf(address(this)), 0, path3, address(this), now.add(1800)); 187 | 188 | } 189 | function inCaseTokenGetsStuck(IERC20 _TokenAddress) onlyOwner public { 190 | uint qty = _TokenAddress.balanceOf(address(this)); 191 | _TokenAddress.safeTransfer(msg.sender, qty); 192 | } 193 | 194 | // incase of half-way error 195 | function inCaseETHGetsStuck() onlyOwner public{ 196 | (bool result, ) = msg.sender.call.value(address(this).balance)(""); 197 | require(result, "transfer of ETH failed"); 198 | } 199 | } -------------------------------------------------------------------------------- /contracts/t/swap.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-07-31 3 | */ 4 | 5 | // SPDX-License-Identifier: MIT 6 | 7 | pragma solidity ^0.5.15; 8 | 9 | interface IERC20 { 10 | function totalSupply() external view returns (uint256); 11 | function balanceOf(address account) external view returns (uint256); 12 | function transfer(address recipient, uint256 amount) external returns (bool); 13 | function allowance(address owner, address spender) external view returns (uint256); 14 | function decimals() external view returns (uint); 15 | function approve(address spender, uint256 amount) external returns (bool); 16 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 17 | event Transfer(address indexed from, address indexed to, uint256 value); 18 | event Approval(address indexed owner, address indexed spender, uint256 value); 19 | } 20 | 21 | library SafeMath { 22 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 23 | uint256 c = a + b; 24 | require(c >= a, "SafeMath: addition overflow"); 25 | 26 | return c; 27 | } 28 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 29 | return sub(a, b, "SafeMath: subtraction overflow"); 30 | } 31 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 32 | require(b <= a, errorMessage); 33 | uint256 c = a - b; 34 | 35 | return c; 36 | } 37 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 38 | if (a == 0) { 39 | return 0; 40 | } 41 | 42 | uint256 c = a * b; 43 | require(c / a == b, "SafeMath: multiplication overflow"); 44 | 45 | return c; 46 | } 47 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 48 | return div(a, b, "SafeMath: division by zero"); 49 | } 50 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 51 | // Solidity only automatically asserts when dividing by 0 52 | require(b > 0, errorMessage); 53 | uint256 c = a / b; 54 | 55 | return c; 56 | } 57 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 58 | return mod(a, b, "SafeMath: modulo by zero"); 59 | } 60 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 61 | require(b != 0, errorMessage); 62 | return a % b; 63 | } 64 | } 65 | 66 | library Address { 67 | function isContract(address account) internal view returns (bool) { 68 | bytes32 codehash; 69 | bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; 70 | // solhint-disable-next-line no-inline-assembly 71 | assembly { codehash := extcodehash(account) } 72 | return (codehash != 0x0 && codehash != accountHash); 73 | } 74 | function toPayable(address account) internal pure returns (address payable) { 75 | return address(uint160(account)); 76 | } 77 | function sendValue(address payable recipient, uint256 amount) internal { 78 | require(address(this).balance >= amount, "Address: insufficient balance"); 79 | 80 | // solhint-disable-next-line avoid-call-value 81 | (bool success, ) = recipient.call.value(amount)(""); 82 | require(success, "Address: unable to send value, recipient may have reverted"); 83 | } 84 | } 85 | 86 | library SafeERC20 { 87 | using SafeMath for uint256; 88 | using Address for address; 89 | 90 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 91 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 92 | } 93 | 94 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 95 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 96 | } 97 | 98 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 99 | require((value == 0) || (token.allowance(address(this), spender) == 0), 100 | "SafeERC20: approve from non-zero to non-zero allowance" 101 | ); 102 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 103 | } 104 | function callOptionalReturn(IERC20 token, bytes memory data) private { 105 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 106 | 107 | // solhint-disable-next-line avoid-low-level-calls 108 | (bool success, bytes memory returndata) = address(token).call(data); 109 | require(success, "SafeERC20: low-level call failed"); 110 | 111 | if (returndata.length > 0) { // Return data is optional 112 | // solhint-disable-next-line max-line-length 113 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 114 | } 115 | } 116 | } 117 | 118 | 119 | 120 | contract Balancer { 121 | function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn) external; 122 | function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut) external; 123 | function swapExactAmountIn( 124 | address tokenIn, 125 | uint tokenAmountIn, 126 | address tokenOut, 127 | uint minAmountOut, 128 | uint maxPrice 129 | ) external returns (uint tokenAmountOut, uint spotPriceAfter); 130 | function swapExactAmountOut( 131 | address tokenIn, 132 | uint maxAmountIn, 133 | address tokenOut, 134 | uint tokenAmountOut, 135 | uint maxPrice 136 | ) external returns (uint tokenAmountIn, uint spotPriceAfter); 137 | function joinswapExternAmountIn(address tokenIn, uint tokenAmountIn, uint minPoolAmountOut) external returns (uint poolAmountOut); 138 | function exitswapPoolAmountIn(address tokenOut, uint poolAmountIn, uint minAmountOut) external returns (uint tokenAmountOut); 139 | } 140 | interface UniswapRouter { 141 | function swapExactTokensForTokens( 142 | uint amountIn, 143 | uint amountOutMin, 144 | address[] calldata path, 145 | address to, 146 | uint deadline 147 | ) external returns (uint[] memory amounts); 148 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 149 | external returns (uint[] memory amounts); 150 | } 151 | 152 | contract Swap { 153 | using SafeERC20 for IERC20; 154 | using Address for address; 155 | using SafeMath for uint256; 156 | 157 | address public owner; 158 | 159 | constructor()public{ 160 | owner = tx.origin; 161 | init(); 162 | } 163 | modifier onlyOwner(){ 164 | require(msg.sender == owner,"not owner"); 165 | _; 166 | } 167 | 168 | address constant public yfii = address(0xa1d0E215a23d7030842FC67cE582a6aFa3CCaB83); 169 | address constant public crv = address(0xD533a949740bb3306d119CC777fa900bA034cd52); 170 | address constant public unirouter = address(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); 171 | address constant public weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); 172 | address constant public dai = address(0x6B175474E89094C44Da98b954EedeAC495271d0F); 173 | address constant public balancer = address(0x16cAC1403377978644e78769Daa49d8f6B6CF565); 174 | 175 | function init () public{ 176 | IERC20(crv).safeApprove(unirouter, uint(-1)); 177 | IERC20(dai).safeApprove(balancer, uint(-1)); 178 | } 179 | 180 | function doswap(uint256 _amount) public { 181 | IERC20(crv).safeTransferFrom(msg.sender, address(this), _amount); 182 | 183 | // crv->weth->dai 184 | address[] memory path3 = new address[](3); 185 | path3[0] = address(crv); 186 | path3[1] = address(weth); 187 | path3[2] = address(dai); 188 | UniswapRouter(unirouter).swapExactTokensForTokens(IERC20(crv).balanceOf(address(this)), 0, path3, address(this), now.add(1800)); 189 | 190 | // dai ->yfii 191 | Balancer(balancer).swapExactAmountIn(dai, IERC20(dai).balanceOf(address(this)), yfii, 0, uint(-1)); 192 | 193 | IERC20(yfii).safeTransfer(msg.sender, IERC20(yfii).balanceOf(address(this))); 194 | 195 | } 196 | function inCaseTokenGetsStuck(IERC20 _TokenAddress) onlyOwner public { 197 | uint qty = _TokenAddress.balanceOf(address(this)); 198 | _TokenAddress.safeTransfer(msg.sender, qty); 199 | } 200 | 201 | // incase of half-way error 202 | function inCaseETHGetsStuck() onlyOwner public{ 203 | (bool result, ) = msg.sender.call.value(address(this).balance)(""); 204 | require(result, "transfer of ETH failed"); 205 | } 206 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/solidity,soliditytruffle 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=solidity,soliditytruffle 4 | 5 | ### Solidity ### 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (https://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # TypeScript v1 declaration files 50 | typings/ 51 | 52 | # TypeScript cache 53 | *.tsbuildinfo 54 | 55 | # Optional npm cache directory 56 | .npm 57 | 58 | # Optional eslint cache 59 | .eslintcache 60 | 61 | # Microbundle cache 62 | .rpt2_cache/ 63 | .rts2_cache_cjs/ 64 | .rts2_cache_es/ 65 | .rts2_cache_umd/ 66 | 67 | # Optional REPL history 68 | .node_repl_history 69 | 70 | # Output of 'npm pack' 71 | *.tgz 72 | 73 | # Yarn Integrity file 74 | .yarn-integrity 75 | 76 | # dotenv environment variables file 77 | .env 78 | .env.test 79 | 80 | # parcel-bundler cache (https://parceljs.org/) 81 | .cache 82 | 83 | # Next.js build output 84 | .next 85 | 86 | # Nuxt.js build / generate output 87 | .nuxt 88 | dist 89 | 90 | # Gatsby files 91 | .cache/ 92 | # Comment in the public line in if your project uses Gatsby and not Next.js 93 | # https://nextjs.org/blog/next-9-1#public-directory-support 94 | # public 95 | 96 | # vuepress build output 97 | .vuepress/dist 98 | 99 | # Serverless directories 100 | .serverless/ 101 | 102 | # FuseBox cache 103 | .fusebox/ 104 | 105 | # DynamoDB Local files 106 | .dynamodb/ 107 | 108 | # TernJS port file 109 | .tern-port 110 | 111 | # Stores VSCode versions used for testing VSCode extensions 112 | .vscode-test 113 | 114 | ### SolidityTruffle ### 115 | # depedencies 116 | node_modules 117 | 118 | # testing 119 | 120 | # production 121 | build 122 | build_webpack 123 | 124 | # misc 125 | .DS_Store 126 | npm-debug.log 127 | .truffle-solidity-loader 128 | .vagrant/** 129 | blockchain/geth/** 130 | blockchain/keystore/** 131 | blockchain/history 132 | 133 | #truffle 134 | yarn.lock 135 | package-lock.json 136 | 137 | # End of https://www.toptal.com/developers/gitignore/api/solidity,soliditytruffle 138 | 139 | # Created by https://www.toptal.com/developers/gitignore/api/soliditytruffle 140 | # Edit at https://www.toptal.com/developers/gitignore?templates=soliditytruffle 141 | 142 | ### SolidityTruffle ### 143 | # depedencies 144 | node_modules 145 | 146 | # testing 147 | coverage 148 | 149 | # production 150 | build 151 | build_webpack 152 | 153 | # misc 154 | .DS_Store 155 | .env 156 | npm-debug.log 157 | .truffle-solidity-loader 158 | .vagrant/** 159 | blockchain/geth/** 160 | blockchain/keystore/** 161 | blockchain/history 162 | 163 | #truffle 164 | .tern-port 165 | yarn.lock 166 | package-lock.json 167 | 168 | # End of https://www.toptal.com/developers/gitignore/api/soliditytruffle 169 | 170 | # Created by https://www.toptal.com/developers/gitignore/api/solidity 171 | # Edit at https://www.toptal.com/developers/gitignore?templates=solidity 172 | 173 | ### Solidity ### 174 | # Logs 175 | logs 176 | *.log 177 | npm-debug.log* 178 | yarn-debug.log* 179 | yarn-error.log* 180 | lerna-debug.log* 181 | 182 | # Diagnostic reports (https://nodejs.org/api/report.html) 183 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 184 | 185 | # Runtime data 186 | pids 187 | *.pid 188 | *.seed 189 | *.pid.lock 190 | 191 | # Directory for instrumented libs generated by jscoverage/JSCover 192 | lib-cov 193 | 194 | # Coverage directory used by tools like istanbul 195 | coverage 196 | *.lcov 197 | 198 | # nyc test coverage 199 | .nyc_output 200 | 201 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 202 | .grunt 203 | 204 | # Bower dependency directory (https://bower.io/) 205 | bower_components 206 | 207 | # node-waf configuration 208 | .lock-wscript 209 | 210 | # Compiled binary addons (https://nodejs.org/api/addons.html) 211 | build/Release 212 | 213 | # Dependency directories 214 | node_modules/ 215 | jspm_packages/ 216 | 217 | # TypeScript v1 declaration files 218 | typings/ 219 | 220 | # TypeScript cache 221 | *.tsbuildinfo 222 | 223 | # Optional npm cache directory 224 | .npm 225 | 226 | # Optional eslint cache 227 | .eslintcache 228 | 229 | # Microbundle cache 230 | .rpt2_cache/ 231 | .rts2_cache_cjs/ 232 | .rts2_cache_es/ 233 | .rts2_cache_umd/ 234 | 235 | # Optional REPL history 236 | .node_repl_history 237 | 238 | # Output of 'npm pack' 239 | *.tgz 240 | 241 | # Yarn Integrity file 242 | .yarn-integrity 243 | 244 | # dotenv environment variables file 245 | .env 246 | .env.test 247 | 248 | # parcel-bundler cache (https://parceljs.org/) 249 | .cache 250 | 251 | # Next.js build output 252 | .next 253 | 254 | # Nuxt.js build / generate output 255 | .nuxt 256 | dist 257 | 258 | # Gatsby files 259 | .cache/ 260 | # Comment in the public line in if your project uses Gatsby and not Next.js 261 | # https://nextjs.org/blog/next-9-1#public-directory-support 262 | # public 263 | 264 | # vuepress build output 265 | .vuepress/dist 266 | 267 | # Serverless directories 268 | .serverless/ 269 | 270 | # FuseBox cache 271 | .fusebox/ 272 | 273 | # DynamoDB Local files 274 | .dynamodb/ 275 | 276 | # TernJS port file 277 | .tern-port 278 | 279 | # Stores VSCode versions used for testing VSCode extensions 280 | .vscode-test 281 | 282 | # End of https://www.toptal.com/developers/gitignore/api/solidity 283 | 284 | # Created by https://www.toptal.com/developers/gitignore/api/python 285 | # Edit at https://www.toptal.com/developers/gitignore?templates=python 286 | 287 | ### Python ### 288 | # Byte-compiled / optimized / DLL files 289 | __pycache__/ 290 | *.py[cod] 291 | *$py.class 292 | 293 | # C extensions 294 | *.so 295 | 296 | # Distribution / packaging 297 | .Python 298 | build/ 299 | develop-eggs/ 300 | dist/ 301 | downloads/ 302 | eggs/ 303 | .eggs/ 304 | lib/ 305 | lib64/ 306 | parts/ 307 | sdist/ 308 | var/ 309 | wheels/ 310 | pip-wheel-metadata/ 311 | share/python-wheels/ 312 | *.egg-info/ 313 | .installed.cfg 314 | *.egg 315 | MANIFEST 316 | 317 | # PyInstaller 318 | # Usually these files are written by a python script from a template 319 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 320 | *.manifest 321 | *.spec 322 | 323 | # Installer logs 324 | pip-log.txt 325 | pip-delete-this-directory.txt 326 | 327 | # Unit test / coverage reports 328 | htmlcov/ 329 | .tox/ 330 | .nox/ 331 | .coverage 332 | .coverage.* 333 | .cache 334 | nosetests.xml 335 | coverage.xml 336 | *.cover 337 | *.py,cover 338 | .hypothesis/ 339 | .pytest_cache/ 340 | pytestdebug.log 341 | 342 | # Translations 343 | *.mo 344 | *.pot 345 | 346 | # Django stuff: 347 | *.log 348 | local_settings.py 349 | db.sqlite3 350 | db.sqlite3-journal 351 | 352 | # Flask stuff: 353 | instance/ 354 | .webassets-cache 355 | 356 | # Scrapy stuff: 357 | .scrapy 358 | 359 | # Sphinx documentation 360 | docs/_build/ 361 | doc/_build/ 362 | 363 | # PyBuilder 364 | target/ 365 | 366 | # Jupyter Notebook 367 | .ipynb_checkpoints 368 | 369 | # IPython 370 | profile_default/ 371 | ipython_config.py 372 | 373 | # pyenv 374 | .python-version 375 | 376 | # pipenv 377 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 378 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 379 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 380 | # install all needed dependencies. 381 | #Pipfile.lock 382 | 383 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 384 | __pypackages__/ 385 | 386 | # Celery stuff 387 | celerybeat-schedule 388 | celerybeat.pid 389 | 390 | # SageMath parsed files 391 | *.sage.py 392 | 393 | # Environments 394 | .env 395 | .venv 396 | env/ 397 | venv/ 398 | ENV/ 399 | env.bak/ 400 | venv.bak/ 401 | 402 | # Spyder project settings 403 | .spyderproject 404 | .spyproject 405 | 406 | # Rope project settings 407 | .ropeproject 408 | 409 | # mkdocs documentation 410 | /site 411 | 412 | # mypy 413 | .mypy_cache/ 414 | .dmypy.json 415 | dmypy.json 416 | 417 | # Pyre type checker 418 | .pyre/ 419 | 420 | # pytype static type analyzer 421 | .pytype/ 422 | 423 | # End of https://www.toptal.com/developers/gitignore/api/python 424 | -------------------------------------------------------------------------------- /contracts/yfiicontract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.15; 2 | 3 | interface IERC20 { 4 | function totalSupply() external view returns (uint); 5 | function balanceOf(address account) external view returns (uint); 6 | function transfer(address recipient, uint amount) external returns (bool); 7 | function allowance(address owner, address spender) external view returns (uint); 8 | function approve(address spender, uint amount) external returns (bool); 9 | function transferFrom(address sender, address recipient, uint amount) external returns (bool); 10 | event Transfer(address indexed from, address indexed to, uint value); 11 | event Approval(address indexed owner, address indexed spender, uint value); 12 | } 13 | 14 | contract Context { 15 | constructor () internal { } 16 | // solhint-disable-previous-line no-empty-blocks 17 | 18 | function _msgSender() internal view returns (address payable) { 19 | return msg.sender; 20 | } 21 | } 22 | 23 | contract ERC20 is Context, IERC20 { 24 | using SafeMath for uint; 25 | 26 | mapping (address => uint) private _balances; 27 | 28 | mapping (address => mapping (address => uint)) private _allowances; 29 | 30 | uint private _totalSupply; 31 | function totalSupply() public view returns (uint) { 32 | return _totalSupply; 33 | } 34 | function balanceOf(address account) public view returns (uint) { 35 | return _balances[account]; 36 | } 37 | function transfer(address recipient, uint amount) public returns (bool) { 38 | _transfer(_msgSender(), recipient, amount); 39 | return true; 40 | } 41 | function allowance(address owner, address spender) public view returns (uint) { 42 | return _allowances[owner][spender]; 43 | } 44 | function approve(address spender, uint amount) public returns (bool) { 45 | _approve(_msgSender(), spender, amount); 46 | return true; 47 | } 48 | function transferFrom(address sender, address recipient, uint amount) public returns (bool) { 49 | _transfer(sender, recipient, amount); 50 | _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); 51 | return true; 52 | } 53 | function increaseAllowance(address spender, uint addedValue) public returns (bool) { 54 | _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); 55 | return true; 56 | } 57 | function decreaseAllowance(address spender, uint subtractedValue) public returns (bool) { 58 | _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); 59 | return true; 60 | } 61 | function _transfer(address sender, address recipient, uint amount) internal { 62 | require(sender != address(0), "ERC20: transfer from the zero address"); 63 | require(recipient != address(0), "ERC20: transfer to the zero address"); 64 | 65 | _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); 66 | _balances[recipient] = _balances[recipient].add(amount); 67 | emit Transfer(sender, recipient, amount); 68 | } 69 | function _mint(address account, uint amount) internal { 70 | require(account != address(0), "ERC20: mint to the zero address"); 71 | 72 | _totalSupply = _totalSupply.add(amount); 73 | _balances[account] = _balances[account].add(amount); 74 | emit Transfer(address(0), account, amount); 75 | } 76 | function _burn(address account, uint amount) internal { 77 | require(account != address(0), "ERC20: burn from the zero address"); 78 | 79 | _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); 80 | _totalSupply = _totalSupply.sub(amount); 81 | emit Transfer(account, address(0), amount); 82 | } 83 | function _approve(address owner, address spender, uint amount) internal { 84 | require(owner != address(0), "ERC20: approve from the zero address"); 85 | require(spender != address(0), "ERC20: approve to the zero address"); 86 | 87 | _allowances[owner][spender] = amount; 88 | emit Approval(owner, spender, amount); 89 | } 90 | } 91 | 92 | contract ERC20Detailed is IERC20 { 93 | string private _name; 94 | string private _symbol; 95 | uint8 private _decimals; 96 | 97 | constructor (string memory name, string memory symbol, uint8 decimals) public { 98 | _name = name; 99 | _symbol = symbol; 100 | _decimals = decimals; 101 | } 102 | function name() public view returns (string memory) { 103 | return _name; 104 | } 105 | function symbol() public view returns (string memory) { 106 | return _symbol; 107 | } 108 | function decimals() public view returns (uint8) { 109 | return _decimals; 110 | } 111 | } 112 | 113 | library SafeMath { 114 | function add(uint a, uint b) internal pure returns (uint) { 115 | uint c = a + b; 116 | require(c >= a, "SafeMath: addition overflow"); 117 | 118 | return c; 119 | } 120 | function sub(uint a, uint b) internal pure returns (uint) { 121 | return sub(a, b, "SafeMath: subtraction overflow"); 122 | } 123 | function sub(uint a, uint b, string memory errorMessage) internal pure returns (uint) { 124 | require(b <= a, errorMessage); 125 | uint c = a - b; 126 | 127 | return c; 128 | } 129 | function mul(uint a, uint b) internal pure returns (uint) { 130 | if (a == 0) { 131 | return 0; 132 | } 133 | 134 | uint c = a * b; 135 | require(c / a == b, "SafeMath: multiplication overflow"); 136 | 137 | return c; 138 | } 139 | function div(uint a, uint b) internal pure returns (uint) { 140 | return div(a, b, "SafeMath: division by zero"); 141 | } 142 | function div(uint a, uint b, string memory errorMessage) internal pure returns (uint) { 143 | // Solidity only automatically asserts when dividing by 0 144 | require(b > 0, errorMessage); 145 | uint c = a / b; 146 | 147 | return c; 148 | } 149 | } 150 | 151 | library Address { 152 | function isContract(address account) internal view returns (bool) { 153 | bytes32 codehash; 154 | bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; 155 | // solhint-disable-next-line no-inline-assembly 156 | assembly { codehash := extcodehash(account) } 157 | return (codehash != 0x0 && codehash != accountHash); 158 | } 159 | } 160 | 161 | library SafeERC20 { 162 | using SafeMath for uint; 163 | using Address for address; 164 | 165 | function safeTransfer(IERC20 token, address to, uint value) internal { 166 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 167 | } 168 | 169 | function safeTransferFrom(IERC20 token, address from, address to, uint value) internal { 170 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 171 | } 172 | 173 | function safeApprove(IERC20 token, address spender, uint value) internal { 174 | require((value == 0) || (token.allowance(address(this), spender) == 0), 175 | "SafeERC20: approve from non-zero to non-zero allowance" 176 | ); 177 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 178 | } 179 | function callOptionalReturn(IERC20 token, bytes memory data) private { 180 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 181 | 182 | // solhint-disable-next-line avoid-low-level-calls 183 | (bool success, bytes memory returndata) = address(token).call(data); 184 | require(success, "SafeERC20: low-level call failed"); 185 | 186 | if (returndata.length > 0) { // Return data is optional 187 | // solhint-disable-next-line max-line-length 188 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 189 | } 190 | } 191 | } 192 | 193 | contract YFII is ERC20, ERC20Detailed { 194 | using SafeERC20 for IERC20; 195 | using Address for address; 196 | using SafeMath for uint; 197 | 198 | 199 | address public governance; 200 | mapping (address => bool) public minters; 201 | 202 | constructor (string memory name, string memory symbol) public ERC20Detailed(name, symbol, 18) { 203 | governance = tx.origin; 204 | } 205 | 206 | function mint(address account, uint256 amount) public { 207 | require(minters[msg.sender], "!minter"); 208 | _mint(account, amount); 209 | } 210 | 211 | function setGovernance(address _governance) public { 212 | require(msg.sender == governance, "!governance"); 213 | governance = _governance; 214 | } 215 | 216 | function addMinter(address _minter) public { 217 | require(msg.sender == governance, "!governance"); 218 | minters[_minter] = true; 219 | } 220 | 221 | function removeMinter(address _minter) public { 222 | require(msg.sender == governance, "!governance"); 223 | minters[_minter] = false; 224 | } 225 | } 226 | contract NewToken is ERC20, ERC20Detailed { 227 | using SafeERC20 for IERC20; 228 | using Address for address; 229 | using SafeMath for uint; 230 | 231 | 232 | address public governance; 233 | mapping (address => bool) public minters; 234 | 235 | constructor (string memory name, string memory symbol) public ERC20Detailed(name, symbol, 18) { 236 | governance = tx.origin; 237 | } 238 | 239 | function mint(address account, uint256 amount) public { 240 | require(minters[msg.sender], "!minter"); 241 | _mint(account, amount); 242 | } 243 | 244 | function setGovernance(address _governance) public { 245 | require(msg.sender == governance, "!governance"); 246 | governance = _governance; 247 | } 248 | 249 | function addMinter(address _minter) public { 250 | require(msg.sender == governance, "!governance"); 251 | minters[_minter] = true; 252 | } 253 | 254 | function removeMinter(address _minter) public { 255 | require(msg.sender == governance, "!governance"); 256 | minters[_minter] = false; 257 | } 258 | } -------------------------------------------------------------------------------- /contracts/dforce/StrategyDForceUSDC.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-08-13 3 | */ 4 | 5 | // SPDX-License-Identifier: MIT 6 | 7 | pragma solidity ^0.5.5; 8 | 9 | import '@openzeppelin/contracts/math/SafeMath.sol'; 10 | import '@openzeppelin/contracts/utils/Address.sol'; 11 | 12 | import '../interface/IUniswapRouter.sol'; 13 | import '../interface/IController.sol'; 14 | import '../interface/IVault.sol'; 15 | import '../interface/IPool.sol'; 16 | import '../interface/IERC20.sol'; 17 | import '../library/SafeERC20.sol'; 18 | 19 | /* 20 | 21 | A strategy must implement the following calls; 22 | 23 | - deposit() 24 | - withdraw(address) must exclude any tokens used in the yield - Controller role - withdraw should return to Controller 25 | - withdraw(uint) - Controller | Vault role - withdraw should always return to vault 26 | - withdrawAll() - Controller | Vault role - withdraw should always return to vault 27 | - balanceOf() 28 | 29 | Where possible, strategies must remain as immutable as possible, instead of updating variables, we update the contract by linking it in the controller 30 | 31 | */ 32 | 33 | 34 | // convet ycurv ,dai,usdt,... to dusdc, 传入dusdc的token地址 35 | interface dConvert { 36 | function mint(address, uint256) external; 37 | function redeem(address, uint) external; 38 | function getTokenBalance(address) external view returns (uint); 39 | function getExchangeRate() external view returns (uint); 40 | } 41 | 42 | 43 | contract StrategyDForceUSDC { 44 | using SafeERC20 for IERC20; 45 | using Address for address; 46 | using SafeMath for uint256; 47 | 48 | address public pool; 49 | address public output; 50 | string public getName; 51 | 52 | //ddress constant public want = address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); // USDC 53 | //address constant public pool = address(0xB71dEFDd6240c45746EC58314a01dd6D833fD3b5); // deforce 54 | address constant public dusdc = address(0x16c9cF62d8daC4a38FB50Ae5fa5d51E9170F3179); 55 | //address constant publict df = address(0x431ad2ff6a9C365805eBaD47Ee021148d6f7DBe0); // outpu 56 | address constant public unirouter = address(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); 57 | address constant public weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); // used for df <> weth <> usdc route 58 | address constant public yfii = address(0xa1d0E215a23d7030842FC67cE582a6aFa3CCaB83); 59 | 60 | 61 | uint public fee = 600; 62 | uint public burnfee = 300; 63 | uint public callfee = 100; 64 | uint constant public max = 10000; 65 | 66 | address public governance; 67 | address public controller; 68 | 69 | address public want; 70 | 71 | address[] public swapRouting; 72 | 73 | /* 74 | * @_output: df erc20 address 75 | * @_pool: 76 | * @_want: in [ycrv,dai, trueusd, dusdc, USDT ] 77 | */ 78 | 79 | constructor(address _output,address _pool,address _want) public { 80 | governance = tx.origin; 81 | controller = 0xe14e60d0F7fb15b1A98FDE88A3415C17b023bf36; 82 | output = _output; 83 | pool = _pool; 84 | want = _want; 85 | getName = string( 86 | abi.encodePacked("yfii:Strategy:", 87 | abi.encodePacked(IERC20(want).name(), 88 | abi.encodePacked(":",IERC20(output).name()) 89 | ) 90 | )); 91 | init(); 92 | swapRouting = [output,weth,yfii]; 93 | 94 | } 95 | 96 | function init () public{ 97 | IERC20(output).safeApprove(unirouter, uint(-1)); 98 | } 99 | 100 | 101 | function deposit() public { 102 | uint _wantBalance = IERC20(want).balanceOf(address(this)); 103 | if (_wantBalance > 0 && want != dusdc ) { // use stable coin mint usdc 104 | IERC20(want).safeApprove(dusdc, 0); 105 | IERC20(want).safeApprove(dusdc, _wantBalance); 106 | dConvert(dusdc).mint(address(this), _wantBalance); 107 | } 108 | 109 | uint _dusdcBalance = IERC20(dusdc).balanceOf(address(this)); 110 | 111 | if (_dusdcBalance > 0) { 112 | IERC20(dusdc).safeApprove(pool, 0); 113 | IERC20(dusdc).safeApprove(pool, _dusdcBalance); 114 | IPool(pool).stake(_dusdcBalance); 115 | } 116 | 117 | } 118 | 119 | // Controller only function for creating additional rewards from dust 120 | function withdraw(IERC20 _asset) external returns (uint balance) { 121 | require(msg.sender == controller, "!controller"); 122 | require(want != address(_asset), "want"); 123 | require(dusdc != address(_asset), "dusdc"); 124 | balance = _asset.balanceOf(address(this)); 125 | _asset.safeTransfer(controller, balance); 126 | } 127 | 128 | // Withdraw partial funds, normally used with a vault withdrawal 129 | function withdraw(uint _amount) external { 130 | require(msg.sender == controller, "!controller"); 131 | uint _balance = IERC20(want).balanceOf(address(this)); 132 | if (_balance < _amount) { 133 | _amount = _withdrawSome(_amount.sub(_balance)); 134 | _amount = _amount.add(_balance); 135 | } 136 | 137 | address _vault = IController(controller).vaults(address(want)); 138 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 139 | 140 | IERC20(want).safeTransfer(_vault, _amount); 141 | } 142 | 143 | // Withdraw all funds, normally used when migrating strategies 144 | function withdrawAll() public returns (uint balance) { 145 | require(msg.sender == controller||msg.sender==governance, "!controller"); 146 | _withdrawAll(); 147 | 148 | 149 | balance = IERC20(want).balanceOf(address(this)); 150 | 151 | address _vault = IController(controller).vaults(address(want)); 152 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 153 | IERC20(want).safeTransfer(_vault, balance); 154 | } 155 | 156 | function _withdrawAll() internal { 157 | IPool(pool).exit(); 158 | uint _dusdc = IERC20(dusdc).balanceOf(address(this)); 159 | 160 | // 如果不是usdc就,就可以取回来 161 | if (_dusdc > 0 && want != dusdc ) { 162 | dConvert(dusdc).redeem(address(this),_dusdc); 163 | } 164 | } 165 | 166 | function setNewPool(address _output,address _pool) public{ 167 | require(msg.sender == governance, "!governance"); 168 | //这边是切换池子以及挖到的代币 169 | //先退出之前的池子. 170 | harvest(); 171 | withdrawAll(); 172 | output = _output; 173 | pool = _pool; 174 | getName = string( 175 | abi.encodePacked("yfii:Strategy:", 176 | abi.encodePacked(IERC20(want).name(), 177 | abi.encodePacked(":",IERC20(output).name()) 178 | ) 179 | )); 180 | 181 | } 182 | 183 | 184 | function harvest() public { 185 | require(!Address.isContract(msg.sender),"!contract"); 186 | IPool(pool).getReward(); 187 | address _vault = IController(controller).vaults(address(want)); 188 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 189 | 190 | uint outputBalance = IERC20(output).balanceOf(address(this)); 191 | if (outputBalance > 0) { 192 | 193 | IUniswapRouter(unirouter).swapExactTokensForTokens(IERC20(output).balanceOf(address(this)), 0, swapRouting, address(this), now.add(1800)); 194 | 195 | // fee 196 | uint b = IERC20(yfii).balanceOf(address(this)); 197 | uint _fee = b.mul(fee).div(max); 198 | uint _callfee = b.mul(callfee).div(max); 199 | uint _burnfee = b.mul(burnfee).div(max); 200 | IERC20(yfii).safeTransfer(IController(controller).rewards(), _fee); //6% 5% team +1% insurance 201 | IERC20(yfii).safeTransfer(msg.sender, _callfee); //call fee 1% 202 | IERC20(yfii).safeTransfer(address(0x6666666666666666666666666666666666666666), _burnfee); //burn fee 3% 203 | 204 | //把yfii 存进去分红. 205 | IERC20(yfii).safeApprove(_vault, 0); 206 | IERC20(yfii).safeApprove(_vault, IERC20(yfii).balanceOf(address(this))); 207 | IVault(_vault).make_profit(IERC20(yfii).balanceOf(address(this))); 208 | } 209 | } 210 | 211 | function _withdrawSome(uint256 _amount) internal returns (uint) { 212 | uint _dusdc = _amount.mul(1e18).div(dConvert(dusdc).getExchangeRate()); 213 | uint _before = IERC20(dusdc).balanceOf(address(this)); 214 | IPool(pool).withdraw(_dusdc); 215 | uint _after = IERC20(dusdc).balanceOf(address(this)); 216 | uint _withdrew = _after.sub(_before); 217 | _before = IERC20(want).balanceOf(address(this)); 218 | 219 | // 如果不是usdc就,就可以取回来 220 | if ( want != dusdc ) { 221 | dConvert(dusdc).redeem(address(this), _withdrew); 222 | } 223 | 224 | 225 | 226 | _after = IERC20(want).balanceOf(address(this)); 227 | _withdrew = _after.sub(_before); 228 | return _withdrew; 229 | } 230 | 231 | function balanceOfWant() public view returns (uint) { 232 | return IERC20(want).balanceOf(address(this)); 233 | } 234 | 235 | function balanceOfPool() public view returns (uint) { 236 | return (IPool(pool).balanceOf(address(this))).mul(dConvert(dusdc).getExchangeRate()).div(1e18); 237 | } 238 | 239 | function getExchangeRate() public view returns (uint) { 240 | return dConvert(dusdc).getExchangeRate(); 241 | } 242 | 243 | function balanceOfDUSDC() public view returns (uint) { 244 | return dConvert(dusdc).getTokenBalance(address(this)); 245 | } 246 | 247 | function balanceOf() public view returns (uint) { 248 | return balanceOfWant() 249 | .add(balanceOfDUSDC()) 250 | .add(balanceOfPool()); 251 | } 252 | 253 | function balanceOfPendingReward() public view returns(uint){ //还没有领取的收益有多少... 254 | return IPool(pool).earned(address(this)); 255 | } 256 | 257 | function setGovernance(address _governance) external { 258 | require(msg.sender == governance, "!governance"); 259 | governance = _governance; 260 | } 261 | 262 | function setController(address _controller) external { 263 | require(msg.sender == governance, "!governance"); 264 | controller = _controller; 265 | } 266 | 267 | function setFee(uint256 _fee) external{ 268 | require(msg.sender == governance, "!governance"); 269 | fee = _fee; 270 | } 271 | function setCallFee(uint256 _fee) external{ 272 | require(msg.sender == governance, "!governance"); 273 | callfee = _fee; 274 | } 275 | function setBurnFee(uint256 _fee) external{ 276 | require(msg.sender == governance, "!governance"); 277 | burnfee = _fee; 278 | } 279 | function setSwapRouting(address[] memory _path) public{ 280 | require(msg.sender == governance, "!governance"); 281 | swapRouting = _path; 282 | } 283 | } -------------------------------------------------------------------------------- /py/deploy.py: -------------------------------------------------------------------------------- 1 | from web3.auto import w3 2 | from web3 import Web3 3 | from solc import compile_standard 4 | import os 5 | import json 6 | import random 7 | import decimal 8 | 9 | ctx = decimal.Context() 10 | ctx.prec = 50 11 | 12 | 13 | def float_to_str(f): 14 | """ 15 | Convert the given float to a string, 16 | without resorting to scientific notation 17 | """ 18 | d1 = ctx.create_decimal(repr(f)) 19 | return format(d1, "f") 20 | 21 | 22 | w3.eth.defaultAccount = w3.eth.accounts[0] 23 | 24 | 25 | def geneateCompiled_sol(sol_name, contract_name): 26 | basedir = "/Users/gaojin/Documents/GitHub/yvault/contracts" 27 | fname = os.path.join(basedir, sol_name) 28 | with open(fname) as f: 29 | content = f.read() 30 | _compile_standard = { 31 | "language": "Solidity", 32 | "sources": {sol_name: {"content": content}}, 33 | "settings": { 34 | "outputSelection": { 35 | "*": {"*": ["metadata", "evm.bytecode", "evm.bytecode.sourceMap"]} 36 | } 37 | }, 38 | } 39 | compiled_sol = compile_standard(_compile_standard) 40 | bytecode = compiled_sol["contracts"][sol_name][contract_name]["evm"]["bytecode"][ 41 | "object" 42 | ] 43 | abi = json.loads(compiled_sol["contracts"][sol_name][contract_name]["metadata"])[ 44 | "output" 45 | ]["abi"] 46 | 47 | c = w3.eth.contract(abi=abi, bytecode=bytecode) 48 | return c, abi 49 | 50 | 51 | def deploy(): 52 | ## Controller 53 | Controller, abi = geneateCompiled_sol("Controller.sol", "Controller") 54 | tx_hash = Controller.constructor().transact() 55 | tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) 56 | controller_instance = w3.eth.contract(address=tx_receipt.contractAddress, abi=abi) 57 | 58 | Yfii, abi = geneateCompiled_sol("yfiicontract.sol", "YFII") 59 | tx_hash = Yfii.constructor("YFII", "YFII").transact() 60 | tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) 61 | yfii_instance = w3.eth.contract(address=tx_receipt.contractAddress, abi=abi) 62 | print(yfii_instance.functions.name().call()) 63 | 64 | token, abi = geneateCompiled_sol("yfiicontract.sol", "NewToken") 65 | tx_hash = token.constructor("NewToken", "NewToken").transact() 66 | tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) 67 | token_instance = w3.eth.contract(address=tx_receipt.contractAddress, abi=abi) 68 | print(token_instance.functions.name().call()) 69 | 70 | StrategyYfii, abi = geneateCompiled_sol("yfiipool1/StrategyCurveYfii.sol", "StrategyYfii") 71 | tx_hash = StrategyYfii.constructor(controller_instance.address).transact() 72 | tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) 73 | strategyYfii_instance = w3.eth.contract(address=tx_receipt.contractAddress, abi=abi) 74 | # print(strategyYfii_instance.functions.controller().call()) 75 | assert ( 76 | strategyYfii_instance.functions.controller().call() 77 | == controller_instance.address 78 | ) 79 | 80 | yVault, abi = geneateCompiled_sol("yfiipool1/yvault.sol", "yVault") 81 | tx_hash = yVault.constructor( 82 | token_instance.address, controller_instance.address, yfii_instance.address 83 | ).transact() 84 | tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) 85 | yVault_instance = w3.eth.contract(address=tx_receipt.contractAddress, abi=abi) 86 | 87 | assert yVault_instance.functions.controller().call() == controller_instance.address 88 | assert yVault_instance.functions.Yfiitoken().call() == yfii_instance.address 89 | assert yVault_instance.functions.token().call() == token_instance.address 90 | 91 | return ( 92 | yfii_instance, 93 | token_instance, 94 | controller_instance, 95 | yVault_instance, 96 | strategyYfii_instance, 97 | ) 98 | 99 | 100 | ( 101 | yfii_instance, 102 | token_instance, 103 | controller_instance, 104 | yVault_instance, 105 | strategyYfii_instance, 106 | ) = deploy() 107 | from_0 = w3.eth.accounts[0] 108 | from_1 = w3.eth.accounts[1] 109 | from_2 = w3.eth.accounts[2] 110 | 111 | 112 | def run(): 113 | setup() 114 | 115 | # from_1 depost 116 | w3.eth.defaultAccount = from_1 117 | deposit_balance = w3.toWei("1000", "ether") 118 | yVault_instance.functions.deposit(deposit_balance).transact() 119 | # 检查 yVault的余额情况 120 | assert ( 121 | token_instance.functions.balanceOf(yVault_instance.address).call() 122 | == deposit_balance 123 | ) 124 | total_stake, total_out, earnings_per_share = yVault_instance.functions.global_( 125 | 0 126 | ).call() 127 | assert [total_stake, total_out, earnings_per_share] == [deposit_balance, 0, 0] 128 | 129 | # 检查 用户存入情况 130 | stake, payout, total_out = yVault_instance.functions.plyr_(from_1).call() 131 | assert [stake, payout, total_out] == [deposit_balance, 0, 0] 132 | 133 | # cal_out 134 | assert yVault_instance.functions.cal_out(from_1).call() == 0 135 | 136 | # make_profit 137 | w3.eth.defaultAccount = from_0 138 | make_profit_balance = w3.toWei("1", "ether") 139 | yVault_instance.functions.make_profit(make_profit_balance).transact() 140 | assert ( 141 | yfii_instance.functions.balanceOf(yVault_instance.address).call() 142 | == make_profit_balance 143 | ) 144 | 145 | _earnings_per_share = earnings_per_share + ( 146 | int(float_to_str(make_profit_balance * 10 ** 40 / total_stake)) 147 | ) 148 | _earnings_per_share = int(_earnings_per_share) 149 | total_stake, total_out, earnings_per_share = yVault_instance.functions.global_( 150 | 0 151 | ).call() 152 | assert [total_stake, total_out, earnings_per_share] == [ 153 | deposit_balance, 154 | make_profit_balance, 155 | _earnings_per_share, 156 | ] 157 | # 算出应该领取的分红 158 | # _calout = int(float_to_str(earnings_per_share * stake/10**40 )) - payout 159 | # assert yVault_instance.functions.cal_out(from_1).call() == make_profit_balance 160 | 161 | # 领取分红 162 | # w3.eth.defaultAccount = from_1 163 | # yVault_instance.functions.claim().transact() 164 | 165 | # stake, payout, total_out = yVault_instance.functions.plyr_(from_1).call() 166 | # assert [stake, payout, total_out] == [deposit_balance, _calout, make_profit_balance] 167 | 168 | # assert ( 169 | # yfii_instance.functions.balanceOf(yVault_instance.address).call() 170 | # == make_profit_balance - _calout 171 | # ) 172 | justRun() 173 | 174 | check() 175 | 176 | def justRun(): 177 | i = 0 178 | while True: 179 | i += 1 180 | print(i) 181 | random_deposit() 182 | random_make_profit() 183 | if i % 20 == 0: 184 | claim() 185 | if i % 10 == 0: 186 | random_withdraw() 187 | if i >= 1000: 188 | break 189 | 190 | def random_deposit(): 191 | w3.eth.defaultAccount = from_1 192 | deposit_balance = random.randint(1000, pow(2, 75)) 193 | yVault_instance.functions.deposit(deposit_balance).transact() 194 | 195 | w3.eth.defaultAccount = from_2 196 | deposit_balance = random.randint(1000, pow(2, 75)) 197 | yVault_instance.functions.deposit(deposit_balance).transact() 198 | 199 | 200 | def random_withdraw(): 201 | w3.eth.defaultAccount = from_1 202 | 203 | stake, payout, total_out = yVault_instance.functions.plyr_(from_1).call() 204 | # print(from_1,[stake, payout, total_out]) 205 | withdraw_balance = random.randint(1, stake // 2) 206 | yVault_instance.functions.withdraw(withdraw_balance).transact() 207 | 208 | w3.eth.defaultAccount = from_2 209 | 210 | stake, payout, total_out = yVault_instance.functions.plyr_(from_2).call() 211 | # print(from_2,[stake, payout, total_out]) 212 | 213 | withdraw_balance = random.randint(1, stake // 2) 214 | yVault_instance.functions.withdraw(withdraw_balance).transact() 215 | 216 | 217 | def random_make_profit(): 218 | w3.eth.defaultAccount = from_0 219 | make_profit_balance = random.randint(1, pow(10, 2)) 220 | yVault_instance.functions.make_profit(make_profit_balance).transact() 221 | 222 | 223 | def claim(): 224 | w3.eth.defaultAccount = from_1 225 | yVault_instance.functions.claim().transact() 226 | w3.eth.defaultAccount = from_2 227 | yVault_instance.functions.claim().transact() 228 | 229 | 230 | def check(): 231 | """ 232 | 最后检查各种分红是否正常... 233 | 234 | 先claim的话 235 | 那么理论上 yVault_instance上的yfii余额为0 236 | from_0+from_1+from_2的yfii 余额加起来为初始余额 237 | 238 | token的话,余额会到 yVault_instance 上面 239 | yVault_instance+from_1+from_2 的token 余额加起来为初始*2 240 | 241 | 242 | 243 | 244 | """ 245 | init_balance = w3.toWei(str(pow(2, 100)), "ether") # 初始化的余额 246 | claim() 247 | 248 | assert yfii_instance.functions.balanceOf(yVault_instance.address).call() == 0 249 | 250 | assert ( 251 | yfii_instance.functions.balanceOf(from_0).call() 252 | + yfii_instance.functions.balanceOf(from_1).call() 253 | + yfii_instance.functions.balanceOf(from_2).call() 254 | == init_balance 255 | ) 256 | assert ( 257 | token_instance.functions.balanceOf(yVault_instance.address).call() 258 | + token_instance.functions.balanceOf(from_1).call() 259 | + token_instance.functions.balanceOf(from_2).call() 260 | == init_balance * 2 261 | ) 262 | 263 | stake1, payout1, total_out1 = yVault_instance.functions.plyr_(from_1).call() 264 | 265 | stake2, payout2, total_out2 = yVault_instance.functions.plyr_(from_2).call() 266 | 267 | assert ( 268 | stake1 + stake2 269 | == token_instance.functions.balanceOf(yVault_instance.address).call() 270 | ) 271 | 272 | assert total_out1 == yfii_instance.functions.balanceOf(from_1).call() 273 | assert total_out2 == yfii_instance.functions.balanceOf(from_2).call() 274 | 275 | 276 | def setup(): 277 | 278 | w3.eth.defaultAccount = from_0 279 | ## yfii mint to from_0 280 | yfii_instance.functions.addMinter(from_0).transact() 281 | mint_balance = w3.toWei(str(pow(2, 100)), "ether") 282 | yfii_instance.functions.mint(from_0, mint_balance).transact() 283 | 284 | assert yfii_instance.functions.balanceOf(from_0).call() == mint_balance 285 | 286 | ## token mint to from_1,from_2 287 | token_instance.functions.addMinter(from_0).transact() 288 | token_instance.functions.mint(from_1, mint_balance).transact() 289 | token_instance.functions.mint(from_2, mint_balance).transact() 290 | 291 | assert token_instance.functions.balanceOf(from_1).call() == mint_balance 292 | assert token_instance.functions.balanceOf(from_2).call() == mint_balance 293 | 294 | ## approve 295 | approve_balance = w3.toWei(str(pow(2, 100) - 1), "ether") 296 | 297 | ## yfii: from_0 approve to yVault_instance 298 | yfii_instance.functions.approve( 299 | yVault_instance.address, approve_balance 300 | ).transact() ## make_profit 301 | 302 | ## token: from_1 approve to yVault_instance 303 | w3.eth.defaultAccount = from_1 304 | token_instance.functions.approve( 305 | yVault_instance.address, approve_balance 306 | ).transact() ## deposit 307 | 308 | ## token: from_2 approve to yVault_instance 309 | w3.eth.defaultAccount = from_2 310 | token_instance.functions.approve( 311 | yVault_instance.address, approve_balance 312 | ).transact() ## deposit 313 | 314 | 315 | if __name__ == "__main__": 316 | run() 317 | -------------------------------------------------------------------------------- /contracts/Controller.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-07-26 3 | */ 4 | 5 | // SPDX-License-Identifier: MIT 6 | 7 | pragma solidity ^0.5.15; 8 | 9 | interface IERC20 { 10 | function totalSupply() external view returns (uint256); 11 | function balanceOf(address account) external view returns (uint256); 12 | function transfer(address recipient, uint256 amount) external returns (bool); 13 | function allowance(address owner, address spender) external view returns (uint256); 14 | function approve(address spender, uint256 amount) external returns (bool); 15 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 16 | event Transfer(address indexed from, address indexed to, uint256 value); 17 | event Approval(address indexed owner, address indexed spender, uint256 value); 18 | } 19 | 20 | library SafeMath { 21 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 22 | uint256 c = a + b; 23 | require(c >= a, "SafeMath: addition overflow"); 24 | 25 | return c; 26 | } 27 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 28 | return sub(a, b, "SafeMath: subtraction overflow"); 29 | } 30 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 31 | require(b <= a, errorMessage); 32 | uint256 c = a - b; 33 | 34 | return c; 35 | } 36 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 37 | if (a == 0) { 38 | return 0; 39 | } 40 | 41 | uint256 c = a * b; 42 | require(c / a == b, "SafeMath: multiplication overflow"); 43 | 44 | return c; 45 | } 46 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 47 | return div(a, b, "SafeMath: division by zero"); 48 | } 49 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 50 | // Solidity only automatically asserts when dividing by 0 51 | require(b > 0, errorMessage); 52 | uint256 c = a / b; 53 | 54 | return c; 55 | } 56 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 57 | return mod(a, b, "SafeMath: modulo by zero"); 58 | } 59 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 60 | require(b != 0, errorMessage); 61 | return a % b; 62 | } 63 | } 64 | 65 | library Address { 66 | function isContract(address account) internal view returns (bool) { 67 | bytes32 codehash; 68 | bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; 69 | // solhint-disable-next-line no-inline-assembly 70 | assembly { codehash := extcodehash(account) } 71 | return (codehash != 0x0 && codehash != accountHash); 72 | } 73 | function toPayable(address account) internal pure returns (address payable) { 74 | return address(uint160(account)); 75 | } 76 | function sendValue(address payable recipient, uint256 amount) internal { 77 | require(address(this).balance >= amount, "Address: insufficient balance"); 78 | 79 | // solhint-disable-next-line avoid-call-value 80 | (bool success, ) = recipient.call.value(amount)(""); 81 | require(success, "Address: unable to send value, recipient may have reverted"); 82 | } 83 | } 84 | 85 | library SafeERC20 { 86 | using SafeMath for uint256; 87 | using Address for address; 88 | 89 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 90 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 91 | } 92 | 93 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 94 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 95 | } 96 | 97 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 98 | require((value == 0) || (token.allowance(address(this), spender) == 0), 99 | "SafeERC20: approve from non-zero to non-zero allowance" 100 | ); 101 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 102 | } 103 | function callOptionalReturn(IERC20 token, bytes memory data) private { 104 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 105 | 106 | // solhint-disable-next-line avoid-low-level-calls 107 | (bool success, bytes memory returndata) = address(token).call(data); 108 | require(success, "SafeERC20: low-level call failed"); 109 | 110 | if (returndata.length > 0) { // Return data is optional 111 | // solhint-disable-next-line max-line-length 112 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 113 | } 114 | } 115 | } 116 | 117 | interface Strategy { 118 | function want() external view returns (address); 119 | function deposit() external; 120 | function withdraw(address) external; 121 | function withdraw(uint) external; 122 | function withdrawAll() external returns (uint); 123 | function balanceOf() external view returns (uint); 124 | } 125 | 126 | interface Converter { 127 | function convert(address) external returns (uint); 128 | } 129 | 130 | interface OneSplitAudit { 131 | function swap( 132 | address fromToken, 133 | address destToken, 134 | uint256 amount, 135 | uint256 minReturn, 136 | uint256[] calldata distribution, 137 | uint256 flags 138 | ) 139 | external 140 | payable 141 | returns(uint256 returnAmount); 142 | 143 | function getExpectedReturn( 144 | address fromToken, 145 | address destToken, 146 | uint256 amount, 147 | uint256 parts, 148 | uint256 flags // See constants in IOneSplit.sol 149 | ) 150 | external 151 | view 152 | returns( 153 | uint256 returnAmount, 154 | uint256[] memory distribution 155 | ); 156 | } 157 | 158 | contract Controller { 159 | using SafeERC20 for IERC20; 160 | using Address for address; 161 | using SafeMath for uint256; 162 | 163 | address public governance; 164 | address public onesplit; 165 | address public rewards; 166 | address public factory; 167 | mapping(address => address) public vaults; 168 | mapping(address => address) public strategies; 169 | mapping(address => mapping(address => address)) public converters; 170 | 171 | uint public split = 5000; 172 | uint public constant max = 10000; 173 | 174 | constructor() public { 175 | governance = tx.origin; 176 | onesplit = address(0x50FDA034C0Ce7a8f7EFDAebDA7Aa7cA21CC1267e); 177 | rewards = 0x887F507EaAc58adD20263C6918538A9BdC882d47; 178 | } 179 | 180 | function setFactory(address _factory) public { 181 | require(msg.sender == governance, "!governance"); 182 | factory = _factory; 183 | } 184 | 185 | function setSplit(uint _split) public { 186 | require(msg.sender == governance, "!governance"); 187 | split = _split; 188 | } 189 | 190 | function setOneSplit(address _onesplit) public { 191 | require(msg.sender == governance, "!governance"); 192 | onesplit = _onesplit; 193 | } 194 | 195 | function setGovernance(address _governance) public { 196 | require(msg.sender == governance, "!governance"); 197 | governance = _governance; 198 | } 199 | 200 | function setVault(address _token, address _vault) public { 201 | require(msg.sender == governance, "!governance"); 202 | vaults[_token] = _vault; 203 | } 204 | 205 | function setConverter(address _input, address _output, address _converter) public { 206 | require(msg.sender == governance, "!governance"); 207 | converters[_input][_output] = _converter; 208 | } 209 | 210 | function setStrategy(address _token, address _strategy) public { 211 | //某个币对应一个策略,比如现在的ycrv就是挖 yfii 212 | require(msg.sender == governance, "!governance"); 213 | address _current = strategies[_token]; 214 | if (_current != address(0)) {//之前的策略存在的话,那么就先提取所有资金 215 | Strategy(_current).withdrawAll(); 216 | } 217 | strategies[_token] = _strategy; 218 | } 219 | 220 | // 221 | function earn(address _token, uint _amount) public { 222 | address _strategy = strategies[_token]; //获取策略的合约地址 223 | address _want = Strategy(_strategy).want();//策略需要的token地址 224 | if (_want != _token) {//如果策略需要的和输入的不一样,需要先转换 225 | address converter = converters[_token][_want];//转换器合约地址. 226 | IERC20(_token).safeTransfer(converter, _amount);//给转换器打钱 227 | _amount = Converter(converter).convert(_strategy);//执行转换... 228 | IERC20(_want).safeTransfer(_strategy, _amount); 229 | } else { 230 | IERC20(_token).safeTransfer(_strategy, _amount); 231 | } 232 | Strategy(_strategy).deposit();//存钱 233 | } 234 | 235 | function balanceOf(address _token) external view returns (uint) { 236 | return Strategy(strategies[_token]).balanceOf(); 237 | } 238 | 239 | function withdrawAll(address _token) public { 240 | require(msg.sender == governance, "!governance"); 241 | Strategy(strategies[_token]).withdrawAll(); 242 | } 243 | 244 | function inCaseTokensGetStuck(address _token, uint _amount) public {//转任意erc20 245 | require(msg.sender == governance, "!governance"); 246 | IERC20(_token).safeTransfer(governance, _amount); 247 | } 248 | 249 | function getExpectedReturn(address _strategy, address _token, uint parts) public view returns (uint expected) { 250 | uint _balance = IERC20(_token).balanceOf(_strategy);//获取策略器 某个代币的余额 251 | address _want = Strategy(_strategy).want();//策略器需要的代币. 252 | (expected,) = OneSplitAudit(onesplit).getExpectedReturn(_token, _want, _balance, parts, 0); 253 | } 254 | 255 | // Only allows to withdraw non-core strategy tokens ~ this is over and above normal yield 256 | function yearn(address _strategy, address _token, uint parts) public { 257 | // This contract should never have value in it, but just incase since this is a public call 258 | uint _before = IERC20(_token).balanceOf(address(this)); 259 | Strategy(_strategy).withdraw(_token); 260 | uint _after = IERC20(_token).balanceOf(address(this)); 261 | if (_after > _before) { 262 | uint _amount = _after.sub(_before); 263 | address _want = Strategy(_strategy).want(); 264 | uint[] memory _distribution; 265 | uint _expected; 266 | _before = IERC20(_want).balanceOf(address(this)); 267 | IERC20(_token).safeApprove(onesplit, 0); 268 | IERC20(_token).safeApprove(onesplit, _amount); 269 | (_expected, _distribution) = OneSplitAudit(onesplit).getExpectedReturn(_token, _want, _amount, parts, 0); 270 | OneSplitAudit(onesplit).swap(_token, _want, _amount, _expected, _distribution, 0); 271 | _after = IERC20(_want).balanceOf(address(this)); 272 | if (_after > _before) { 273 | _amount = _after.sub(_before); 274 | uint _reward = _amount.mul(split).div(max); 275 | earn(_want, _amount.sub(_reward)); 276 | IERC20(_want).safeTransfer(rewards, _reward); 277 | } 278 | } 279 | } 280 | 281 | function withdraw(address _token, uint _amount) public { 282 | require(msg.sender == vaults[_token], "!vault"); 283 | Strategy(strategies[_token]).withdraw(_amount); 284 | } 285 | } -------------------------------------------------------------------------------- /contracts/standard/Controller.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-07-26 3 | */ 4 | 5 | // SPDX-License-Identifier: MIT 6 | 7 | pragma solidity ^0.5.15; 8 | 9 | interface IERC20 { 10 | function totalSupply() external view returns (uint256); 11 | function balanceOf(address account) external view returns (uint256); 12 | function transfer(address recipient, uint256 amount) external returns (bool); 13 | function allowance(address owner, address spender) external view returns (uint256); 14 | function approve(address spender, uint256 amount) external returns (bool); 15 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 16 | event Transfer(address indexed from, address indexed to, uint256 value); 17 | event Approval(address indexed owner, address indexed spender, uint256 value); 18 | } 19 | 20 | library SafeMath { 21 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 22 | uint256 c = a + b; 23 | require(c >= a, "SafeMath: addition overflow"); 24 | 25 | return c; 26 | } 27 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 28 | return sub(a, b, "SafeMath: subtraction overflow"); 29 | } 30 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 31 | require(b <= a, errorMessage); 32 | uint256 c = a - b; 33 | 34 | return c; 35 | } 36 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 37 | if (a == 0) { 38 | return 0; 39 | } 40 | 41 | uint256 c = a * b; 42 | require(c / a == b, "SafeMath: multiplication overflow"); 43 | 44 | return c; 45 | } 46 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 47 | return div(a, b, "SafeMath: division by zero"); 48 | } 49 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 50 | // Solidity only automatically asserts when dividing by 0 51 | require(b > 0, errorMessage); 52 | uint256 c = a / b; 53 | 54 | return c; 55 | } 56 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 57 | return mod(a, b, "SafeMath: modulo by zero"); 58 | } 59 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 60 | require(b != 0, errorMessage); 61 | return a % b; 62 | } 63 | } 64 | 65 | library Address { 66 | function isContract(address account) internal view returns (bool) { 67 | bytes32 codehash; 68 | bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; 69 | // solhint-disable-next-line no-inline-assembly 70 | assembly { codehash := extcodehash(account) } 71 | return (codehash != 0x0 && codehash != accountHash); 72 | } 73 | function toPayable(address account) internal pure returns (address payable) { 74 | return address(uint160(account)); 75 | } 76 | function sendValue(address payable recipient, uint256 amount) internal { 77 | require(address(this).balance >= amount, "Address: insufficient balance"); 78 | 79 | // solhint-disable-next-line avoid-call-value 80 | (bool success, ) = recipient.call.value(amount)(""); 81 | require(success, "Address: unable to send value, recipient may have reverted"); 82 | } 83 | } 84 | 85 | library SafeERC20 { 86 | using SafeMath for uint256; 87 | using Address for address; 88 | 89 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 90 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 91 | } 92 | 93 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 94 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 95 | } 96 | 97 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 98 | require((value == 0) || (token.allowance(address(this), spender) == 0), 99 | "SafeERC20: approve from non-zero to non-zero allowance" 100 | ); 101 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 102 | } 103 | function callOptionalReturn(IERC20 token, bytes memory data) private { 104 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 105 | 106 | // solhint-disable-next-line avoid-low-level-calls 107 | (bool success, bytes memory returndata) = address(token).call(data); 108 | require(success, "SafeERC20: low-level call failed"); 109 | 110 | if (returndata.length > 0) { // Return data is optional 111 | // solhint-disable-next-line max-line-length 112 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 113 | } 114 | } 115 | } 116 | 117 | interface Strategy { 118 | function want() external view returns (address); 119 | function deposit() external; 120 | function withdraw(address) external; 121 | function withdraw(uint) external; 122 | function withdrawAll() external returns (uint); 123 | function balanceOf() external view returns (uint); 124 | } 125 | 126 | interface Converter { 127 | function convert(address) external returns (uint); 128 | } 129 | 130 | interface OneSplitAudit { 131 | function swap( 132 | address fromToken, 133 | address destToken, 134 | uint256 amount, 135 | uint256 minReturn, 136 | uint256[] calldata distribution, 137 | uint256 flags 138 | ) 139 | external 140 | payable 141 | returns(uint256 returnAmount); 142 | 143 | function getExpectedReturn( 144 | address fromToken, 145 | address destToken, 146 | uint256 amount, 147 | uint256 parts, 148 | uint256 flags // See constants in IOneSplit.sol 149 | ) 150 | external 151 | view 152 | returns( 153 | uint256 returnAmount, 154 | uint256[] memory distribution 155 | ); 156 | } 157 | 158 | contract Controller { 159 | using SafeERC20 for IERC20; 160 | using Address for address; 161 | using SafeMath for uint256; 162 | 163 | address public governance; 164 | address public onesplit; 165 | address public rewards; 166 | address public factory; 167 | mapping(address => address) public vaults; 168 | mapping(address => address) public strategies; 169 | mapping(address => mapping(address => address)) public converters; 170 | 171 | uint public split = 5000; 172 | uint public constant max = 10000; 173 | 174 | constructor() public { 175 | governance = tx.origin; 176 | onesplit = address(0x50FDA034C0Ce7a8f7EFDAebDA7Aa7cA21CC1267e); 177 | rewards = 0x887F507EaAc58adD20263C6918538A9BdC882d47; 178 | } 179 | 180 | function setFactory(address _factory) public { 181 | require(msg.sender == governance, "!governance"); 182 | factory = _factory; 183 | } 184 | 185 | function setSplit(uint _split) public { 186 | require(msg.sender == governance, "!governance"); 187 | split = _split; 188 | } 189 | 190 | function setOneSplit(address _onesplit) public { 191 | require(msg.sender == governance, "!governance"); 192 | onesplit = _onesplit; 193 | } 194 | 195 | function setGovernance(address _governance) public { 196 | require(msg.sender == governance, "!governance"); 197 | governance = _governance; 198 | } 199 | 200 | function setVault(address _token, address _vault) public { 201 | require(msg.sender == governance, "!governance"); 202 | vaults[_token] = _vault; 203 | } 204 | 205 | function setConverter(address _input, address _output, address _converter) public { 206 | require(msg.sender == governance, "!governance"); 207 | converters[_input][_output] = _converter; 208 | } 209 | 210 | function setStrategy(address _token, address _strategy) public { 211 | //某个币对应一个策略,比如现在的ycrv就是挖 yfii 212 | require(msg.sender == governance, "!governance"); 213 | address _current = strategies[_token]; 214 | if (_current != address(0)) {//之前的策略存在的话,那么就先提取所有资金 215 | Strategy(_current).withdrawAll(); 216 | } 217 | strategies[_token] = _strategy; 218 | } 219 | 220 | // 221 | function earn(address _token, uint _amount) public { 222 | address _strategy = strategies[_token]; //获取策略的合约地址 223 | address _want = Strategy(_strategy).want();//策略需要的token地址 224 | if (_want != _token) {//如果策略需要的和输入的不一样,需要先转换 225 | address converter = converters[_token][_want];//转换器合约地址. 226 | IERC20(_token).safeTransfer(converter, _amount);//给转换器打钱 227 | _amount = Converter(converter).convert(_strategy);//执行转换... 228 | IERC20(_want).safeTransfer(_strategy, _amount); 229 | } else { 230 | IERC20(_token).safeTransfer(_strategy, _amount); 231 | } 232 | Strategy(_strategy).deposit();//存钱 233 | } 234 | 235 | function balanceOf(address _token) external view returns (uint) { 236 | return Strategy(strategies[_token]).balanceOf(); 237 | } 238 | 239 | function withdrawAll(address _token) public { 240 | require(msg.sender == governance, "!governance"); 241 | Strategy(strategies[_token]).withdrawAll(); 242 | } 243 | 244 | function inCaseTokensGetStuck(address _token, uint _amount) public {//转任意erc20 245 | require(msg.sender == governance, "!governance"); 246 | IERC20(_token).safeTransfer(governance, _amount); 247 | } 248 | 249 | function getExpectedReturn(address _strategy, address _token, uint parts) public view returns (uint expected) { 250 | uint _balance = IERC20(_token).balanceOf(_strategy);//获取策略器 某个代币的余额 251 | address _want = Strategy(_strategy).want();//策略器需要的代币. 252 | (expected,) = OneSplitAudit(onesplit).getExpectedReturn(_token, _want, _balance, parts, 0); 253 | } 254 | 255 | // Only allows to withdraw non-core strategy tokens ~ this is over and above normal yield 256 | function yearn(address _strategy, address _token, uint parts) public { 257 | // This contract should never have value in it, but just incase since this is a public call 258 | uint _before = IERC20(_token).balanceOf(address(this)); 259 | Strategy(_strategy).withdraw(_token); 260 | uint _after = IERC20(_token).balanceOf(address(this)); 261 | if (_after > _before) { 262 | uint _amount = _after.sub(_before); 263 | address _want = Strategy(_strategy).want(); 264 | uint[] memory _distribution; 265 | uint _expected; 266 | _before = IERC20(_want).balanceOf(address(this)); 267 | IERC20(_token).safeApprove(onesplit, 0); 268 | IERC20(_token).safeApprove(onesplit, _amount); 269 | (_expected, _distribution) = OneSplitAudit(onesplit).getExpectedReturn(_token, _want, _amount, parts, 0); 270 | OneSplitAudit(onesplit).swap(_token, _want, _amount, _expected, _distribution, 0); 271 | _after = IERC20(_want).balanceOf(address(this)); 272 | if (_after > _before) { 273 | _amount = _after.sub(_before); 274 | uint _reward = _amount.mul(split).div(max); 275 | earn(_want, _amount.sub(_reward)); 276 | IERC20(_want).safeTransfer(rewards, _reward); 277 | } 278 | } 279 | } 280 | 281 | function withdraw(address _token, uint _amount) public { 282 | require(msg.sender == vaults[_token], "!vault"); 283 | Strategy(strategies[_token]).withdraw(_amount); 284 | } 285 | } -------------------------------------------------------------------------------- /contracts/crvContract/cCrvGauge.vy: -------------------------------------------------------------------------------- 1 | # @version 0.2.4 2 | """ 3 | @title Liquidity Gauge 4 | @author Curve Finance 5 | @license MIT 6 | @notice Used for measuring liquidity and insurance 7 | """ 8 | 9 | from vyper.interfaces import ERC20 10 | 11 | interface CRV20: 12 | def future_epoch_time_write() -> uint256: nonpayable 13 | def rate() -> uint256: view 14 | 15 | interface Controller: 16 | def period() -> int128: view 17 | def period_write() -> int128: nonpayable 18 | def period_timestamp(p: int128) -> uint256: view 19 | def gauge_relative_weight(addr: address, time: uint256) -> uint256: view 20 | def voting_escrow() -> address: view 21 | def checkpoint(): nonpayable 22 | def checkpoint_gauge(addr: address): nonpayable 23 | 24 | interface Minter: 25 | def token() -> address: view 26 | def controller() -> address: view 27 | def minted(user: address, gauge: address) -> uint256: view 28 | 29 | interface VotingEscrow: 30 | def user_point_epoch(addr: address) -> uint256: view 31 | def user_point_history__ts(addr: address, epoch: uint256) -> uint256: view 32 | 33 | 34 | event Deposit: 35 | provider: indexed(address) 36 | value: uint256 37 | 38 | event Withdraw: 39 | provider: indexed(address) 40 | value: uint256 41 | 42 | event UpdateLiquidityLimit: 43 | user: address 44 | original_balance: uint256 45 | original_supply: uint256 46 | working_balance: uint256 47 | working_supply: uint256 48 | 49 | 50 | TOKENLESS_PRODUCTION: constant(uint256) = 40 51 | BOOST_WARMUP: constant(uint256) = 2 * 7 * 86400 52 | WEEK: constant(uint256) = 604800 53 | 54 | minter: public(address) 55 | crv_token: public(address) 56 | lp_token: public(address) 57 | controller: public(address) 58 | voting_escrow: public(address) 59 | balanceOf: public(HashMap[address, uint256]) 60 | totalSupply: public(uint256) 61 | future_epoch_time: public(uint256) 62 | 63 | # caller -> recipient -> can deposit? 64 | approved_to_deposit: public(HashMap[address, HashMap[address, bool]]) 65 | 66 | working_balances: public(HashMap[address, uint256]) 67 | working_supply: public(uint256) 68 | 69 | # The goal is to be able to calculate ∫(rate * balance / totalSupply dt) from 0 till checkpoint 70 | # All values are kept in units of being multiplied by 1e18 71 | period: public(int128) 72 | period_timestamp: public(uint256[100000000000000000000000000000]) 73 | 74 | # 1e18 * ∫(rate(t) / totalSupply(t) dt) from 0 till checkpoint 75 | integrate_inv_supply: public(uint256[100000000000000000000000000000]) # bump epoch when rate() changes 76 | 77 | # 1e18 * ∫(rate(t) / totalSupply(t) dt) from (last_action) till checkpoint 78 | integrate_inv_supply_of: public(HashMap[address, uint256]) 79 | integrate_checkpoint_of: public(HashMap[address, uint256]) 80 | 81 | 82 | # ∫(balance * rate(t) / totalSupply(t) dt) from 0 till checkpoint 83 | # Units: rate * t = already number of coins per address to issue 84 | integrate_fraction: public(HashMap[address, uint256]) 85 | 86 | inflation_rate: public(uint256) 87 | 88 | 89 | @external 90 | def __init__(lp_addr: address, _minter: address): 91 | """ 92 | @notice Contract constructor 93 | @param lp_addr Liquidity Pool contract address 94 | @param _minter Minter contract address 95 | """ 96 | 97 | assert lp_addr != ZERO_ADDRESS 98 | assert _minter != ZERO_ADDRESS 99 | 100 | self.lp_token = lp_addr 101 | self.minter = _minter 102 | crv_addr: address = Minter(_minter).token() 103 | self.crv_token = crv_addr 104 | controller_addr: address = Minter(_minter).controller() 105 | self.controller = controller_addr 106 | self.voting_escrow = Controller(controller_addr).voting_escrow() 107 | self.period_timestamp[0] = block.timestamp 108 | self.inflation_rate = CRV20(crv_addr).rate() 109 | self.future_epoch_time = CRV20(crv_addr).future_epoch_time_write() 110 | 111 | 112 | @internal 113 | def _update_liquidity_limit(addr: address, l: uint256, L: uint256): 114 | """ 115 | @notice Calculate limits which depend on the amount of CRV token per-user. 116 | Effectively it calculates working balances to apply amplification 117 | of CRV production by CRV 118 | @param addr User address 119 | @param l User's amount of liquidity (LP tokens) 120 | @param L Total amount of liquidity (LP tokens) 121 | """ 122 | # To be called after totalSupply is updated 123 | _voting_escrow: address = self.voting_escrow 124 | voting_balance: uint256 = ERC20(_voting_escrow).balanceOf(addr) 125 | voting_total: uint256 = ERC20(_voting_escrow).totalSupply() 126 | 127 | lim: uint256 = l * TOKENLESS_PRODUCTION / 100 128 | if (voting_total > 0) and (block.timestamp > self.period_timestamp[0] + BOOST_WARMUP): 129 | lim += L * voting_balance / voting_total * (100 - TOKENLESS_PRODUCTION) / 100 130 | 131 | lim = min(l, lim) 132 | old_bal: uint256 = self.working_balances[addr] 133 | self.working_balances[addr] = lim 134 | _working_supply: uint256 = self.working_supply + lim - old_bal 135 | self.working_supply = _working_supply 136 | 137 | log UpdateLiquidityLimit(addr, l, L, lim, _working_supply) 138 | 139 | 140 | @internal 141 | def _checkpoint(addr: address): 142 | """ 143 | @notice Checkpoint for a user 144 | @param addr User address 145 | """ 146 | _token: address = self.crv_token 147 | _controller: address = self.controller 148 | _period: int128 = self.period 149 | _period_time: uint256 = self.period_timestamp[_period] 150 | _integrate_inv_supply: uint256 = self.integrate_inv_supply[_period] 151 | rate: uint256 = self.inflation_rate 152 | new_rate: uint256 = rate 153 | prev_future_epoch: uint256 = self.future_epoch_time 154 | if prev_future_epoch >= _period_time: 155 | self.future_epoch_time = CRV20(_token).future_epoch_time_write() 156 | new_rate = CRV20(_token).rate() 157 | self.inflation_rate = new_rate 158 | Controller(_controller).checkpoint_gauge(self) 159 | 160 | _working_balance: uint256 = self.working_balances[addr] 161 | _working_supply: uint256 = self.working_supply 162 | 163 | # Update integral of 1/supply 164 | if block.timestamp > _period_time: 165 | prev_week_time: uint256 = _period_time 166 | week_time: uint256 = min((_period_time + WEEK) / WEEK * WEEK, block.timestamp) 167 | 168 | for i in range(500): 169 | dt: uint256 = week_time - prev_week_time 170 | w: uint256 = Controller(_controller).gauge_relative_weight(self, prev_week_time / WEEK * WEEK) 171 | 172 | if _working_supply > 0: 173 | if prev_future_epoch >= prev_week_time and prev_future_epoch < week_time: 174 | # If we went across one or multiple epochs, apply the rate 175 | # of the first epoch until it ends, and then the rate of 176 | # the last epoch. 177 | # If more than one epoch is crossed - the gauge gets less, 178 | # but that'd meen it wasn't called for more than 1 year 179 | _integrate_inv_supply += rate * w * (prev_future_epoch - prev_week_time) / _working_supply 180 | rate = new_rate 181 | _integrate_inv_supply += rate * w * (week_time - prev_future_epoch) / _working_supply 182 | else: 183 | _integrate_inv_supply += rate * w * dt / _working_supply 184 | # On precisions of the calculation 185 | # rate ~= 10e18 186 | # last_weight > 0.01 * 1e18 = 1e16 (if pool weight is 1%) 187 | # _working_supply ~= TVL * 1e18 ~= 1e26 ($100M for example) 188 | # The largest loss is at dt = 1 189 | # Loss is 1e-9 - acceptable 190 | 191 | if week_time == block.timestamp: 192 | break 193 | prev_week_time = week_time 194 | week_time = min(week_time + WEEK, block.timestamp) 195 | 196 | _period += 1 197 | self.period = _period 198 | self.period_timestamp[_period] = block.timestamp 199 | self.integrate_inv_supply[_period] = _integrate_inv_supply 200 | 201 | # Update user-specific integrals 202 | self.integrate_fraction[addr] += _working_balance * (_integrate_inv_supply - self.integrate_inv_supply_of[addr]) / 10 ** 18 203 | self.integrate_inv_supply_of[addr] = _integrate_inv_supply 204 | self.integrate_checkpoint_of[addr] = block.timestamp 205 | 206 | 207 | @external 208 | def user_checkpoint(addr: address) -> bool: 209 | """ 210 | @notice Record a checkpoint for `addr` 211 | @param addr User address 212 | @return bool success 213 | """ 214 | assert (msg.sender == addr) or (msg.sender == self.minter) # dev: unauthorized 215 | self._checkpoint(addr) 216 | self._update_liquidity_limit(addr, self.balanceOf[addr], self.totalSupply) 217 | return True 218 | 219 | 220 | @external 221 | def claimable_tokens(addr: address) -> uint256: 222 | """ 223 | @notice Get the number of claimable tokens per user 224 | @dev This function should be manually changed to "view" in the ABI 225 | @return uint256 number of claimable tokens per user 226 | """ 227 | self._checkpoint(addr) 228 | return self.integrate_fraction[addr] - Minter(self.minter).minted(addr, self) 229 | 230 | 231 | @external 232 | def kick(addr: address): 233 | """ 234 | @notice Kick `addr` for abusing their boost 235 | @dev Only if either they had another voting event, or their voting escrow lock expired 236 | @param addr Address to kick 237 | """ 238 | _voting_escrow: address = self.voting_escrow 239 | t_last: uint256 = self.integrate_checkpoint_of[addr] 240 | t_ve: uint256 = VotingEscrow(_voting_escrow).user_point_history__ts( 241 | addr, VotingEscrow(_voting_escrow).user_point_epoch(addr) 242 | ) 243 | _balance: uint256 = self.balanceOf[addr] 244 | 245 | assert ERC20(self.voting_escrow).balanceOf(addr) == 0 or t_ve > t_last # dev: kick not allowed 246 | assert self.working_balances[addr] > _balance * TOKENLESS_PRODUCTION / 100 # dev: kick not needed 247 | 248 | self._checkpoint(addr) 249 | self._update_liquidity_limit(addr, self.balanceOf[addr], self.totalSupply) 250 | 251 | 252 | @external 253 | def set_approve_deposit(addr: address, can_deposit: bool): 254 | """ 255 | @notice Set whether `addr` can deposit tokens for `msg.sender` 256 | @param addr Address to set approval on 257 | @param can_deposit bool - can this account deposit for `msg.sender`? 258 | """ 259 | self.approved_to_deposit[addr][msg.sender] = can_deposit 260 | 261 | 262 | @external 263 | @nonreentrant('lock') 264 | def deposit(_value: uint256, addr: address = msg.sender): 265 | """ 266 | @notice Deposit `_value` LP tokens 267 | @param _value Number of tokens to deposit 268 | @param addr Address to deposit for 269 | """ 270 | if addr != msg.sender: 271 | assert self.approved_to_deposit[msg.sender][addr], "Not approved" 272 | 273 | self._checkpoint(addr) 274 | 275 | if _value != 0: 276 | _balance: uint256 = self.balanceOf[addr] + _value 277 | _supply: uint256 = self.totalSupply + _value 278 | self.balanceOf[addr] = _balance 279 | self.totalSupply = _supply 280 | 281 | self._update_liquidity_limit(addr, _balance, _supply) 282 | 283 | assert ERC20(self.lp_token).transferFrom(msg.sender, self, _value) 284 | 285 | log Deposit(addr, _value) 286 | 287 | 288 | @external 289 | @nonreentrant('lock') 290 | def withdraw(_value: uint256): 291 | """ 292 | @notice Withdraw `_value` LP tokens 293 | @param _value Number of tokens to withdraw 294 | """ 295 | self._checkpoint(msg.sender) 296 | 297 | _balance: uint256 = self.balanceOf[msg.sender] - _value 298 | _supply: uint256 = self.totalSupply - _value 299 | self.balanceOf[msg.sender] = _balance 300 | self.totalSupply = _supply 301 | 302 | self._update_liquidity_limit(msg.sender, _balance, _supply) 303 | 304 | assert ERC20(self.lp_token).transfer(msg.sender, _value) 305 | 306 | log Withdraw(msg.sender, _value) 307 | 308 | 309 | @external 310 | @view 311 | def integrate_checkpoint() -> uint256: 312 | return self.period_timestamp[self.period] -------------------------------------------------------------------------------- /contracts/crvContract/ycrvGauge.vy: -------------------------------------------------------------------------------- 1 | # @version 0.2.4 2 | """ 3 | @title Liquidity Gauge 4 | @author Curve Finance 5 | @license MIT 6 | @notice Used for measuring liquidity and insurance 7 | """ 8 | 9 | from vyper.interfaces import ERC20 10 | 11 | interface CRV20: 12 | def future_epoch_time_write() -> uint256: nonpayable 13 | def rate() -> uint256: view 14 | 15 | interface Controller: 16 | def period() -> int128: view 17 | def period_write() -> int128: nonpayable 18 | def period_timestamp(p: int128) -> uint256: view 19 | def gauge_relative_weight(addr: address, time: uint256) -> uint256: view 20 | def voting_escrow() -> address: view 21 | def checkpoint(): nonpayable 22 | def checkpoint_gauge(addr: address): nonpayable 23 | 24 | interface Minter: 25 | def token() -> address: view 26 | def controller() -> address: view 27 | def minted(user: address, gauge: address) -> uint256: view 28 | 29 | interface VotingEscrow: 30 | def user_point_epoch(addr: address) -> uint256: view 31 | def user_point_history__ts(addr: address, epoch: uint256) -> uint256: view 32 | 33 | 34 | event Deposit: 35 | provider: indexed(address) 36 | value: uint256 37 | 38 | event Withdraw: 39 | provider: indexed(address) 40 | value: uint256 41 | 42 | event UpdateLiquidityLimit: 43 | user: address 44 | original_balance: uint256 45 | original_supply: uint256 46 | working_balance: uint256 47 | working_supply: uint256 48 | 49 | 50 | TOKENLESS_PRODUCTION: constant(uint256) = 40 51 | BOOST_WARMUP: constant(uint256) = 2 * 7 * 86400 52 | WEEK: constant(uint256) = 604800 53 | 54 | minter: public(address) 55 | crv_token: public(address) 56 | lp_token: public(address) 57 | controller: public(address) 58 | voting_escrow: public(address) 59 | balanceOf: public(HashMap[address, uint256]) 60 | totalSupply: public(uint256) 61 | future_epoch_time: public(uint256) 62 | 63 | # caller -> recipient -> can deposit? 64 | approved_to_deposit: public(HashMap[address, HashMap[address, bool]]) 65 | 66 | working_balances: public(HashMap[address, uint256]) 67 | working_supply: public(uint256) 68 | 69 | # The goal is to be able to calculate ∫(rate * balance / totalSupply dt) from 0 till checkpoint 70 | # All values are kept in units of being multiplied by 1e18 71 | period: public(int128) 72 | period_timestamp: public(uint256[100000000000000000000000000000]) 73 | 74 | # 1e18 * ∫(rate(t) / totalSupply(t) dt) from 0 till checkpoint 75 | integrate_inv_supply: public(uint256[100000000000000000000000000000]) # bump epoch when rate() changes 76 | 77 | # 1e18 * ∫(rate(t) / totalSupply(t) dt) from (last_action) till checkpoint 78 | integrate_inv_supply_of: public(HashMap[address, uint256]) 79 | integrate_checkpoint_of: public(HashMap[address, uint256]) 80 | 81 | 82 | # ∫(balance * rate(t) / totalSupply(t) dt) from 0 till checkpoint 83 | # Units: rate * t = already number of coins per address to issue 84 | integrate_fraction: public(HashMap[address, uint256]) 85 | 86 | inflation_rate: public(uint256) 87 | 88 | 89 | @external 90 | def __init__(lp_addr: address, _minter: address): 91 | """ 92 | @notice Contract constructor 93 | @param lp_addr Liquidity Pool contract address 94 | @param _minter Minter contract address 95 | """ 96 | 97 | assert lp_addr != ZERO_ADDRESS 98 | assert _minter != ZERO_ADDRESS 99 | 100 | self.lp_token = lp_addr 101 | self.minter = _minter 102 | crv_addr: address = Minter(_minter).token() 103 | self.crv_token = crv_addr 104 | controller_addr: address = Minter(_minter).controller() 105 | self.controller = controller_addr 106 | self.voting_escrow = Controller(controller_addr).voting_escrow() 107 | self.period_timestamp[0] = block.timestamp 108 | self.inflation_rate = CRV20(crv_addr).rate() 109 | self.future_epoch_time = CRV20(crv_addr).future_epoch_time_write() 110 | 111 | 112 | @internal 113 | def _update_liquidity_limit(addr: address, l: uint256, L: uint256): 114 | """ 115 | @notice Calculate limits which depend on the amount of CRV token per-user. 116 | Effectively it calculates working balances to apply amplification 117 | of CRV production by CRV 118 | @param addr User address 119 | @param l User's amount of liquidity (LP tokens) 120 | @param L Total amount of liquidity (LP tokens) 121 | """ 122 | # To be called after totalSupply is updated 123 | _voting_escrow: address = self.voting_escrow 124 | voting_balance: uint256 = ERC20(_voting_escrow).balanceOf(addr) 125 | voting_total: uint256 = ERC20(_voting_escrow).totalSupply() 126 | 127 | lim: uint256 = l * TOKENLESS_PRODUCTION / 100 128 | if (voting_total > 0) and (block.timestamp > self.period_timestamp[0] + BOOST_WARMUP): 129 | lim += L * voting_balance / voting_total * (100 - TOKENLESS_PRODUCTION) / 100 130 | 131 | lim = min(l, lim) 132 | old_bal: uint256 = self.working_balances[addr] 133 | self.working_balances[addr] = lim 134 | _working_supply: uint256 = self.working_supply + lim - old_bal 135 | self.working_supply = _working_supply 136 | 137 | log UpdateLiquidityLimit(addr, l, L, lim, _working_supply) 138 | 139 | 140 | @internal 141 | def _checkpoint(addr: address): 142 | """ 143 | @notice Checkpoint for a user 144 | @param addr User address 145 | """ 146 | _token: address = self.crv_token 147 | _controller: address = self.controller 148 | _period: int128 = self.period 149 | _period_time: uint256 = self.period_timestamp[_period] 150 | _integrate_inv_supply: uint256 = self.integrate_inv_supply[_period] 151 | rate: uint256 = self.inflation_rate 152 | new_rate: uint256 = rate 153 | prev_future_epoch: uint256 = self.future_epoch_time 154 | if prev_future_epoch >= _period_time: 155 | self.future_epoch_time = CRV20(_token).future_epoch_time_write() 156 | new_rate = CRV20(_token).rate() 157 | self.inflation_rate = new_rate 158 | Controller(_controller).checkpoint_gauge(self) 159 | 160 | _working_balance: uint256 = self.working_balances[addr] 161 | _working_supply: uint256 = self.working_supply 162 | 163 | # Update integral of 1/supply 164 | if block.timestamp > _period_time: 165 | prev_week_time: uint256 = _period_time 166 | week_time: uint256 = min((_period_time + WEEK) / WEEK * WEEK, block.timestamp) 167 | 168 | for i in range(500): 169 | dt: uint256 = week_time - prev_week_time 170 | w: uint256 = Controller(_controller).gauge_relative_weight(self, prev_week_time / WEEK * WEEK) 171 | 172 | if _working_supply > 0: 173 | if prev_future_epoch >= prev_week_time and prev_future_epoch < week_time: 174 | # If we went across one or multiple epochs, apply the rate 175 | # of the first epoch until it ends, and then the rate of 176 | # the last epoch. 177 | # If more than one epoch is crossed - the gauge gets less, 178 | # but that'd meen it wasn't called for more than 1 year 179 | _integrate_inv_supply += rate * w * (prev_future_epoch - prev_week_time) / _working_supply 180 | rate = new_rate 181 | _integrate_inv_supply += rate * w * (week_time - prev_future_epoch) / _working_supply 182 | else: 183 | _integrate_inv_supply += rate * w * dt / _working_supply 184 | # On precisions of the calculation 185 | # rate ~= 10e18 186 | # last_weight > 0.01 * 1e18 = 1e16 (if pool weight is 1%) 187 | # _working_supply ~= TVL * 1e18 ~= 1e26 ($100M for example) 188 | # The largest loss is at dt = 1 189 | # Loss is 1e-9 - acceptable 190 | 191 | if week_time == block.timestamp: 192 | break 193 | prev_week_time = week_time 194 | week_time = min(week_time + WEEK, block.timestamp) 195 | 196 | _period += 1 197 | self.period = _period 198 | self.period_timestamp[_period] = block.timestamp 199 | self.integrate_inv_supply[_period] = _integrate_inv_supply 200 | 201 | # Update user-specific integrals 202 | self.integrate_fraction[addr] += _working_balance * (_integrate_inv_supply - self.integrate_inv_supply_of[addr]) / 10 ** 18 203 | self.integrate_inv_supply_of[addr] = _integrate_inv_supply 204 | self.integrate_checkpoint_of[addr] = block.timestamp 205 | 206 | 207 | @external 208 | def user_checkpoint(addr: address) -> bool: 209 | """ 210 | @notice Record a checkpoint for `addr` 211 | @param addr User address 212 | @return bool success 213 | """ 214 | assert (msg.sender == addr) or (msg.sender == self.minter) # dev: unauthorized 215 | self._checkpoint(addr) 216 | self._update_liquidity_limit(addr, self.balanceOf[addr], self.totalSupply) 217 | return True 218 | 219 | 220 | @external 221 | def claimable_tokens(addr: address) -> uint256: 222 | """ 223 | @notice Get the number of claimable tokens per user 224 | @dev This function should be manually changed to "view" in the ABI 225 | @return uint256 number of claimable tokens per user 226 | """ 227 | self._checkpoint(addr) 228 | return self.integrate_fraction[addr] - Minter(self.minter).minted(addr, self) 229 | 230 | 231 | @external 232 | def kick(addr: address): 233 | """ 234 | @notice Kick `addr` for abusing their boost 235 | @dev Only if either they had another voting event, or their voting escrow lock expired 236 | @param addr Address to kick 237 | """ 238 | _voting_escrow: address = self.voting_escrow 239 | t_last: uint256 = self.integrate_checkpoint_of[addr] 240 | t_ve: uint256 = VotingEscrow(_voting_escrow).user_point_history__ts( 241 | addr, VotingEscrow(_voting_escrow).user_point_epoch(addr) 242 | ) 243 | _balance: uint256 = self.balanceOf[addr] 244 | 245 | assert ERC20(self.voting_escrow).balanceOf(addr) == 0 or t_ve > t_last # dev: kick not allowed 246 | assert self.working_balances[addr] > _balance * TOKENLESS_PRODUCTION / 100 # dev: kick not needed 247 | 248 | self._checkpoint(addr) 249 | self._update_liquidity_limit(addr, self.balanceOf[addr], self.totalSupply) 250 | 251 | 252 | @external 253 | def set_approve_deposit(addr: address, can_deposit: bool): 254 | """ 255 | @notice Set whether `addr` can deposit tokens for `msg.sender` 256 | @param addr Address to set approval on 257 | @param can_deposit bool - can this account deposit for `msg.sender`? 258 | """ 259 | self.approved_to_deposit[addr][msg.sender] = can_deposit 260 | 261 | 262 | @external 263 | @nonreentrant('lock') 264 | def deposit(_value: uint256, addr: address = msg.sender): 265 | """ 266 | @notice Deposit `_value` LP tokens 267 | @param _value Number of tokens to deposit 268 | @param addr Address to deposit for 269 | """ 270 | if addr != msg.sender: 271 | assert self.approved_to_deposit[msg.sender][addr], "Not approved" 272 | 273 | self._checkpoint(addr) 274 | 275 | if _value != 0: 276 | _balance: uint256 = self.balanceOf[addr] + _value 277 | _supply: uint256 = self.totalSupply + _value 278 | self.balanceOf[addr] = _balance 279 | self.totalSupply = _supply 280 | 281 | self._update_liquidity_limit(addr, _balance, _supply) 282 | 283 | assert ERC20(self.lp_token).transferFrom(msg.sender, self, _value) 284 | 285 | log Deposit(addr, _value) 286 | 287 | 288 | @external 289 | @nonreentrant('lock') 290 | def withdraw(_value: uint256): 291 | """ 292 | @notice Withdraw `_value` LP tokens 293 | @param _value Number of tokens to withdraw 294 | """ 295 | self._checkpoint(msg.sender) 296 | 297 | _balance: uint256 = self.balanceOf[msg.sender] - _value 298 | _supply: uint256 = self.totalSupply - _value 299 | self.balanceOf[msg.sender] = _balance 300 | self.totalSupply = _supply 301 | 302 | self._update_liquidity_limit(msg.sender, _balance, _supply) 303 | 304 | assert ERC20(self.lp_token).transfer(msg.sender, _value) 305 | 306 | log Withdraw(msg.sender, _value) 307 | 308 | 309 | @external 310 | @view 311 | def integrate_checkpoint() -> uint256: 312 | return self.period_timestamp[self.period] -------------------------------------------------------------------------------- /contracts/dforce/StrategyDForce.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-08-13 3 | */ 4 | 5 | // SPDX-License-Identifier: MIT 6 | 7 | pragma solidity ^0.5.5; 8 | 9 | import '@openzeppelin/contracts/math/SafeMath.sol'; 10 | import '@openzeppelin/contracts/utils/Address.sol'; 11 | 12 | import '../interface/IUniswapRouter.sol'; 13 | import '../interface/IController.sol'; 14 | import '../interface/IVault.sol'; 15 | import '../interface/IPool.sol'; 16 | import '../interface/IERC20.sol'; 17 | import '../library/SafeERC20.sol'; 18 | 19 | /* 20 | 21 | A strategy must implement the following calls; 22 | 23 | - deposit() 24 | - withdraw(address) must exclude any tokens used in the yield - Controller role - withdraw should return to Controller 25 | - withdraw(uint) - Controller | Vault role - withdraw should always return to vault 26 | - withdrawAll() - Controller | Vault role - withdraw should always return to vault 27 | - balanceOf() 28 | 29 | Where possible, strategies must remain as immutable as possible, instead of updating variables, we update the contract by linking it in the controller 30 | 31 | */ 32 | 33 | 34 | // convet ycurv ,dai,usdt,... to dtoken, 传入dtoken的token地址 35 | interface dTokenConvert { 36 | function mint(address, uint256) external; 37 | function redeem(address, uint) external; 38 | function getTokenBalance(address) external view returns (uint); 39 | function getExchangeRate() external view returns (uint); 40 | } 41 | 42 | 43 | /* 44 | * forked from https://etherscan.io/address/0x01b354a9fb34760455ee9cbe7d71d2ce5c11ab5c#code 45 | */ 46 | contract StrategyDForce { 47 | using SafeERC20 for IERC20; 48 | using Address for address; 49 | using SafeMath for uint256; 50 | 51 | address public pool; 52 | address public dtoken; 53 | address public output; 54 | string public getName; 55 | 56 | 57 | address constant public df = address(0x431ad2ff6a9C365805eBaD47Ee021148d6f7DBe0); 58 | 59 | // vault 60 | 61 | address constant public dai = address(0x6B175474E89094C44Da98b954EedeAC495271d0F); 62 | address constant public usdt = address(0xdAC17F958D2ee523a2206206994597C13D831ec7); 63 | address constant public usdc = address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); 64 | 65 | address constant public unirouter = address(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); 66 | address constant public weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); // used for df <> weth <> usdc route 67 | address constant public yfii = address(0xa1d0E215a23d7030842FC67cE582a6aFa3CCaB83); 68 | 69 | 70 | uint public fee = 600; 71 | uint public burnfee = 300; 72 | uint public callfee = 100; 73 | uint constant public max = 10000; 74 | 75 | address public governance; 76 | address public controller; 77 | 78 | address public want; 79 | 80 | address[] public swapRouting; 81 | 82 | 83 | mapping(address => address) public dTokens; 84 | mapping(address => address) public dPools; 85 | 86 | /* 87 | * @_output: df erc20 address 88 | * @_pool: dforce pool 89 | * @_want: in [dai, dtoken, usdt ] 90 | */ 91 | 92 | constructor(address _output,address _want) public { 93 | governance = tx.origin; 94 | controller = 0xe14e60d0F7fb15b1A98FDE88A3415C17b023bf36; 95 | output = _output; 96 | //pool = _pool; 97 | want = _want; 98 | getName = string( 99 | abi.encodePacked("yfii:Strategy:", 100 | abi.encodePacked(IERC20(want).name(), 101 | abi.encodePacked(":",IERC20(output).name()) 102 | ) 103 | )); 104 | init(); 105 | swapRouting = [output,weth,yfii]; 106 | 107 | } 108 | 109 | function init () public{ 110 | IERC20(output).safeApprove(unirouter, uint(-1)); 111 | 112 | dTokens[dai] = address(0x02285AcaafEB533e03A7306C55EC031297df9224); 113 | dTokens[usdt] = address(0x868277d475E0e475E38EC5CdA2d9C83B5E1D9fc8); 114 | dTokens[usdc] = address(0x16c9cF62d8daC4a38FB50Ae5fa5d51E9170F3179); 115 | dtoken = dTokens[want]; 116 | require(dtoken != address(0x0), "error want address"); 117 | 118 | dPools[dai] = address(0xD2fA07cD6Cd4A5A96aa86BacfA6E50bB3aaDBA8B); 119 | dPools[usdt] = address(0x324EebDAa45829c6A8eE903aFBc7B61AF48538df); 120 | dPools[usdc] = address(0xB71dEFDd6240c45746EC58314a01dd6D833fD3b5); 121 | pool = dPools[want]; 122 | 123 | require(pool != address(0x0), "error want address"); 124 | } 125 | 126 | 127 | function deposit() public { 128 | uint _wantBalance = IERC20(want).balanceOf(address(this)); 129 | if (_wantBalance > 0) { // use stable coin mint usdc 130 | IERC20(want).safeApprove(dtoken, 0); 131 | IERC20(want).safeApprove(dtoken, _wantBalance); 132 | dTokenConvert(dtoken).mint(address(this), _wantBalance); 133 | } 134 | 135 | uint _dtokenBalance = IERC20(dtoken).balanceOf(address(this)); 136 | 137 | if (_dtokenBalance > 0) { 138 | IERC20(dtoken).safeApprove(pool, 0); 139 | IERC20(dtoken).safeApprove(pool, _dtokenBalance); 140 | IPool(pool).stake(_dtokenBalance); 141 | } 142 | 143 | } 144 | 145 | // Controller only function for creating additional rewards from dust 146 | function withdraw(IERC20 _asset) external returns (uint balance) { 147 | require(msg.sender == controller, "!controller"); 148 | require(want != address(_asset), "want"); 149 | require(dtoken != address(_asset), "dtoken"); 150 | balance = _asset.balanceOf(address(this)); 151 | _asset.safeTransfer(controller, balance); 152 | } 153 | 154 | // Withdraw partial funds, normally used with a vault withdrawal 155 | function withdraw(uint _amount) external { 156 | require(msg.sender == controller, "!controller"); 157 | uint _balance = IERC20(want).balanceOf(address(this)); 158 | if (_balance < _amount) { 159 | _amount = _withdrawSome(_amount.sub(_balance)); 160 | _amount = _amount.add(_balance); 161 | } 162 | 163 | address _vault = IController(controller).vaults(address(want)); 164 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 165 | 166 | IERC20(want).safeTransfer(_vault, _amount); 167 | } 168 | 169 | // Withdraw all funds, normally used when migrating strategies 170 | function withdrawAll() public returns (uint balance) { 171 | require(msg.sender == controller||msg.sender==governance, "!controller"); 172 | _withdrawAll(); 173 | 174 | 175 | balance = IERC20(want).balanceOf(address(this)); 176 | 177 | address _vault = IController(controller).vaults(address(want)); 178 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 179 | IERC20(want).safeTransfer(_vault, balance); 180 | } 181 | 182 | function _withdrawAll() internal { 183 | IPool(pool).exit(); 184 | uint _dtoken = IERC20(dtoken).balanceOf(address(this)); 185 | 186 | // 如果不是usdc就,就可以取回来 187 | if (_dtoken > 0 && want != dtoken ) { 188 | dTokenConvert(dtoken).redeem(address(this),_dtoken); 189 | } 190 | } 191 | 192 | function setNewPool(address _output,address _pool) public{ 193 | require(msg.sender == governance, "!governance"); 194 | //这边是切换池子以及挖到的代币 195 | //先退出之前的池子. 196 | harvest(); 197 | withdrawAll(); 198 | output = _output; 199 | pool = _pool; 200 | getName = string( 201 | abi.encodePacked("yfii:Strategy:", 202 | abi.encodePacked(IERC20(want).name(), 203 | abi.encodePacked(":",IERC20(output).name()) 204 | ) 205 | )); 206 | 207 | } 208 | 209 | 210 | function harvest() public { 211 | require(!Address.isContract(msg.sender),"!contract"); 212 | IPool(pool).getReward(); 213 | address _vault = IController(controller).vaults(address(want)); 214 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 215 | 216 | uint outputBalance = IERC20(output).balanceOf(address(this)); 217 | if (outputBalance > 0) { 218 | 219 | IUniswapRouter(unirouter).swapExactTokensForTokens(IERC20(output).balanceOf(address(this)), 0, swapRouting, address(this), now.add(1800)); 220 | 221 | // fee 222 | uint b = IERC20(yfii).balanceOf(address(this)); 223 | uint _fee = b.mul(fee).div(max); 224 | uint _callfee = b.mul(callfee).div(max); 225 | uint _burnfee = b.mul(burnfee).div(max); 226 | IERC20(yfii).safeTransfer(IController(controller).rewards(), _fee); //6% 5% team +1% insurance 227 | IERC20(yfii).safeTransfer(msg.sender, _callfee); //call fee 1% 228 | IERC20(yfii).safeTransfer(address(0x6666666666666666666666666666666666666666), _burnfee); //burn fee 3% 229 | 230 | //把yfii 存进去分红. 231 | IERC20(yfii).safeApprove(_vault, 0); 232 | IERC20(yfii).safeApprove(_vault, IERC20(yfii).balanceOf(address(this))); 233 | IVault(_vault).make_profit(IERC20(yfii).balanceOf(address(this))); 234 | } 235 | } 236 | 237 | function _withdrawSome(uint256 _amount) internal returns (uint) { 238 | uint _dtoken = _amount.mul(1e18).div(dTokenConvert(dtoken).getExchangeRate()); 239 | uint _before = IERC20(dtoken).balanceOf(address(this)); 240 | IPool(pool).withdraw(_dtoken); 241 | uint _after = IERC20(dtoken).balanceOf(address(this)); 242 | uint _withdrew = _after.sub(_before); 243 | _before = IERC20(want).balanceOf(address(this)); 244 | 245 | // 如果不是usdc就,就可以取回来 246 | if ( want != dtoken ) { 247 | dTokenConvert(dtoken).redeem(address(this), _withdrew); 248 | } 249 | 250 | 251 | 252 | _after = IERC20(want).balanceOf(address(this)); 253 | _withdrew = _after.sub(_before); 254 | return _withdrew; 255 | } 256 | 257 | function balanceOfWant() public view returns (uint) { 258 | return IERC20(want).balanceOf(address(this)); 259 | } 260 | 261 | function balanceOfPool() public view returns (uint) { 262 | return (IPool(pool).balanceOf(address(this))).mul(dTokenConvert(dtoken).getExchangeRate()).div(1e18); 263 | } 264 | 265 | function getExchangeRate() public view returns (uint) { 266 | return dTokenConvert(dtoken).getExchangeRate(); 267 | } 268 | 269 | function balanceOfDUSDC() public view returns (uint) { 270 | return dTokenConvert(dtoken).getTokenBalance(address(this)); 271 | } 272 | 273 | function balanceOf() public view returns (uint) { 274 | return balanceOfWant() 275 | .add(balanceOfDUSDC()) 276 | .add(balanceOfPool()); 277 | } 278 | 279 | function balanceOfPendingReward() public view returns(uint){ //还没有领取的收益有多少... 280 | return IPool(pool).earned(address(this)); 281 | } 282 | 283 | function setGovernance(address _governance) external { 284 | require(msg.sender == governance, "!governance"); 285 | governance = _governance; 286 | } 287 | 288 | function setController(address _controller) external { 289 | require(msg.sender == governance, "!governance"); 290 | controller = _controller; 291 | } 292 | 293 | function setFee(uint256 _fee) external{ 294 | require(msg.sender == governance, "!governance"); 295 | fee = _fee; 296 | } 297 | function setCallFee(uint256 _fee) external{ 298 | require(msg.sender == governance, "!governance"); 299 | callfee = _fee; 300 | } 301 | function setBurnFee(uint256 _fee) external{ 302 | require(msg.sender == governance, "!governance"); 303 | burnfee = _fee; 304 | } 305 | function setSwapRouting(address[] memory _path) public{ 306 | require(msg.sender == governance, "!governance"); 307 | swapRouting = _path; 308 | } 309 | } -------------------------------------------------------------------------------- /contracts/yfiipool1/StrategyCurveYfii.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-07-31 3 | */ 4 | 5 | // SPDX-License-Identifier: MIT 6 | 7 | pragma solidity ^0.5.15; 8 | 9 | interface IERC20 { 10 | function totalSupply() external view returns (uint256); 11 | function balanceOf(address account) external view returns (uint256); 12 | function transfer(address recipient, uint256 amount) external returns (bool); 13 | function allowance(address owner, address spender) external view returns (uint256); 14 | function decimals() external view returns (uint); 15 | function approve(address spender, uint256 amount) external returns (bool); 16 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 17 | event Transfer(address indexed from, address indexed to, uint256 value); 18 | event Approval(address indexed owner, address indexed spender, uint256 value); 19 | } 20 | 21 | library SafeMath { 22 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 23 | uint256 c = a + b; 24 | require(c >= a, "SafeMath: addition overflow"); 25 | 26 | return c; 27 | } 28 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 29 | return sub(a, b, "SafeMath: subtraction overflow"); 30 | } 31 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 32 | require(b <= a, errorMessage); 33 | uint256 c = a - b; 34 | 35 | return c; 36 | } 37 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 38 | if (a == 0) { 39 | return 0; 40 | } 41 | 42 | uint256 c = a * b; 43 | require(c / a == b, "SafeMath: multiplication overflow"); 44 | 45 | return c; 46 | } 47 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 48 | return div(a, b, "SafeMath: division by zero"); 49 | } 50 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 51 | // Solidity only automatically asserts when dividing by 0 52 | require(b > 0, errorMessage); 53 | uint256 c = a / b; 54 | 55 | return c; 56 | } 57 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 58 | return mod(a, b, "SafeMath: modulo by zero"); 59 | } 60 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 61 | require(b != 0, errorMessage); 62 | return a % b; 63 | } 64 | } 65 | 66 | library Address { 67 | function isContract(address account) internal view returns (bool) { 68 | bytes32 codehash; 69 | bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; 70 | // solhint-disable-next-line no-inline-assembly 71 | assembly { codehash := extcodehash(account) } 72 | return (codehash != 0x0 && codehash != accountHash); 73 | } 74 | function toPayable(address account) internal pure returns (address payable) { 75 | return address(uint160(account)); 76 | } 77 | function sendValue(address payable recipient, uint256 amount) internal { 78 | require(address(this).balance >= amount, "Address: insufficient balance"); 79 | 80 | // solhint-disable-next-line avoid-call-value 81 | (bool success, ) = recipient.call.value(amount)(""); 82 | require(success, "Address: unable to send value, recipient may have reverted"); 83 | } 84 | } 85 | 86 | library SafeERC20 { 87 | using SafeMath for uint256; 88 | using Address for address; 89 | 90 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 91 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 92 | } 93 | 94 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 95 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 96 | } 97 | 98 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 99 | require((value == 0) || (token.allowance(address(this), spender) == 0), 100 | "SafeERC20: approve from non-zero to non-zero allowance" 101 | ); 102 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 103 | } 104 | function callOptionalReturn(IERC20 token, bytes memory data) private { 105 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 106 | 107 | // solhint-disable-next-line avoid-low-level-calls 108 | (bool success, bytes memory returndata) = address(token).call(data); 109 | require(success, "SafeERC20: low-level call failed"); 110 | 111 | if (returndata.length > 0) { // Return data is optional 112 | // solhint-disable-next-line max-line-length 113 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 114 | } 115 | } 116 | } 117 | 118 | interface Controller { 119 | function vaults(address) external view returns (address); 120 | function rewards() external view returns (address); 121 | } 122 | 123 | /* 124 | 125 | A strategy must implement the following calls; 126 | 127 | - deposit() 128 | - withdraw(address) must exclude any tokens used in the yield - Controller role - withdraw should return to Controller 129 | - withdraw(uint) - Controller | Vault role - withdraw should always return to vault 130 | - withdrawAll() - Controller | Vault role - withdraw should always return to vault 131 | - balanceOf() 132 | 133 | Where possible, strategies must remain as immutable as possible, instead of updating variables, we update the contract by linking it in the controller 134 | 135 | */ 136 | 137 | interface Yfii { 138 | function withdraw(uint) external; 139 | function getReward() external; 140 | function stake(uint) external; 141 | function balanceOf(address) external view returns (uint); 142 | function exit() external; 143 | } 144 | 145 | contract Balancer { 146 | function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn) external; 147 | function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut) external; 148 | function swapExactAmountIn( 149 | address tokenIn, 150 | uint tokenAmountIn, 151 | address tokenOut, 152 | uint minAmountOut, 153 | uint maxPrice 154 | ) external returns (uint tokenAmountOut, uint spotPriceAfter); 155 | function swapExactAmountOut( 156 | address tokenIn, 157 | uint maxAmountIn, 158 | address tokenOut, 159 | uint tokenAmountOut, 160 | uint maxPrice 161 | ) external returns (uint tokenAmountIn, uint spotPriceAfter); 162 | function joinswapExternAmountIn(address tokenIn, uint tokenAmountIn, uint minPoolAmountOut) external returns (uint poolAmountOut); 163 | function exitswapPoolAmountIn(address tokenOut, uint poolAmountIn, uint minAmountOut) external returns (uint tokenAmountOut); 164 | } 165 | 166 | interface yERC20 { 167 | function deposit(uint256 _amount) external; 168 | function withdraw(uint256 _amount) external; 169 | } 170 | 171 | interface ICurveFi { 172 | 173 | function get_virtual_price() external view returns (uint); 174 | function add_liquidity( 175 | uint256[4] calldata amounts, 176 | uint256 min_mint_amount 177 | ) external; 178 | function remove_liquidity_imbalance( 179 | uint256[4] calldata amounts, 180 | uint256 max_burn_amount 181 | ) external; 182 | function remove_liquidity( 183 | uint256 _amount, 184 | uint256[4] calldata amounts 185 | ) external; 186 | function exchange( 187 | int128 from, int128 to, uint256 _from_amount, uint256 _min_to_amount 188 | ) external; 189 | } 190 | interface Yvault{ 191 | function make_profit(uint256 amount) external; 192 | } 193 | contract StrategyYfii { 194 | using SafeERC20 for IERC20; 195 | using Address for address; 196 | using SafeMath for uint256; 197 | 198 | address constant public want = address(0x49bD7631856078257d5Aef996Cb1218519eA1Db4); 199 | address constant public pool = address(0x343887B22FB4088ED3cFeDCdDb08c67C01ca639A); 200 | address constant public yfii = address(0xf2d645D45F0A46CDfa080595Df1d6C9D733296c3); 201 | 202 | 203 | uint constant public fee = 50; 204 | uint constant public max = 10000; 205 | 206 | address public governance; 207 | address public controller; 208 | 209 | constructor(address _controller) public { 210 | governance = msg.sender; 211 | controller = _controller; 212 | } 213 | 214 | function deposit() external { //把ycrv stake到 pool1 215 | IERC20(want).safeApprove(pool, 0); 216 | IERC20(want).safeApprove(pool, IERC20(want).balanceOf(address(this))); 217 | Yfii(pool).stake(IERC20(want).balanceOf(address(this))); 218 | } 219 | 220 | // Controller only function for creating additional rewards from dust 221 | function withdraw(IERC20 _asset) external returns (uint balance) { 222 | require(msg.sender == controller, "!controller"); 223 | require(want != address(_asset), "want"); 224 | balance = _asset.balanceOf(address(this)); 225 | _asset.safeTransfer(controller, balance); 226 | } 227 | 228 | // Withdraw partial funds, normally used with a vault withdrawal 229 | function withdraw(uint _amount) external { 230 | require(msg.sender == controller, "!controller"); 231 | uint _balance = IERC20(want).balanceOf(address(this)); 232 | if (_balance < _amount) { 233 | _amount = _withdrawSome(_amount.sub(_balance));//要提取的钱不够,从pool提缺少的出来 234 | _amount = _amount.add(_balance); 235 | } 236 | 237 | address _vault = Controller(controller).vaults(address(want));//金库的地址. 238 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 239 | IERC20(want).safeTransfer(_vault, _amount); 240 | } 241 | 242 | // Withdraw all funds, normally used when migrating strategies 243 | function withdrawAll() external returns (uint balance) { //把ycrv 还到金库 走人 244 | require(msg.sender == controller, "!controller"); 245 | _withdrawAll(); 246 | balance = IERC20(want).balanceOf(address(this)); 247 | 248 | address _vault = Controller(controller).vaults(address(want)); 249 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 250 | IERC20(want).safeTransfer(_vault, balance); 251 | 252 | } 253 | 254 | function _withdrawAll() internal { //退池子 已经领取收益. 收益换成ycrv 255 | Yfii(pool).exit(); 256 | harvest(); 257 | } 258 | 259 | function harvest() public {//砸盘yfii 260 | Yfii(pool).getReward(); //领取yfii 261 | address _vault = Controller(controller).vaults(address(want)); 262 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 263 | 264 | 265 | //把yfii 存进去分红. 266 | IERC20(yfii).safeApprove(_vault, 0); 267 | IERC20(yfii).safeApprove(_vault, IERC20(yfii).balanceOf(address(this))); 268 | Yvault(_vault).make_profit(IERC20(yfii).balanceOf(address(this))); 269 | } 270 | 271 | function _withdrawSome(uint256 _amount) internal returns (uint) { 272 | Yfii(pool).withdraw(_amount); 273 | return _amount; 274 | } 275 | 276 | function balanceOfCurve() public view returns (uint) { 277 | return IERC20(want).balanceOf(address(this)); 278 | } 279 | 280 | function balanceOfYfii() public view returns (uint) { 281 | return Yfii(pool).balanceOf(address(this)); 282 | } 283 | 284 | function balanceOf() public view returns (uint) { 285 | return balanceOfCurve(); 286 | 287 | } 288 | 289 | function setGovernance(address _governance) external { 290 | require(msg.sender == governance, "!governance"); 291 | governance = _governance; 292 | } 293 | 294 | function setController(address _controller) external { 295 | require(msg.sender == governance, "!governance"); 296 | controller = _controller; 297 | } 298 | } -------------------------------------------------------------------------------- /contracts/yfiipool2/StrategyYfiiPool2.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-07-31 3 | */ 4 | 5 | // SPDX-License-Identifier: MIT 6 | 7 | pragma solidity ^0.5.15; 8 | 9 | interface IERC20 { 10 | function totalSupply() external view returns (uint256); 11 | function balanceOf(address account) external view returns (uint256); 12 | function transfer(address recipient, uint256 amount) external returns (bool); 13 | function allowance(address owner, address spender) external view returns (uint256); 14 | function decimals() external view returns (uint); 15 | function approve(address spender, uint256 amount) external returns (bool); 16 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 17 | event Transfer(address indexed from, address indexed to, uint256 value); 18 | event Approval(address indexed owner, address indexed spender, uint256 value); 19 | } 20 | 21 | library SafeMath { 22 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 23 | uint256 c = a + b; 24 | require(c >= a, "SafeMath: addition overflow"); 25 | 26 | return c; 27 | } 28 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 29 | return sub(a, b, "SafeMath: subtraction overflow"); 30 | } 31 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 32 | require(b <= a, errorMessage); 33 | uint256 c = a - b; 34 | 35 | return c; 36 | } 37 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 38 | if (a == 0) { 39 | return 0; 40 | } 41 | 42 | uint256 c = a * b; 43 | require(c / a == b, "SafeMath: multiplication overflow"); 44 | 45 | return c; 46 | } 47 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 48 | return div(a, b, "SafeMath: division by zero"); 49 | } 50 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 51 | // Solidity only automatically asserts when dividing by 0 52 | require(b > 0, errorMessage); 53 | uint256 c = a / b; 54 | 55 | return c; 56 | } 57 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 58 | return mod(a, b, "SafeMath: modulo by zero"); 59 | } 60 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 61 | require(b != 0, errorMessage); 62 | return a % b; 63 | } 64 | } 65 | 66 | library Address { 67 | function isContract(address account) internal view returns (bool) { 68 | bytes32 codehash; 69 | bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; 70 | // solhint-disable-next-line no-inline-assembly 71 | assembly { codehash := extcodehash(account) } 72 | return (codehash != 0x0 && codehash != accountHash); 73 | } 74 | function toPayable(address account) internal pure returns (address payable) { 75 | return address(uint160(account)); 76 | } 77 | function sendValue(address payable recipient, uint256 amount) internal { 78 | require(address(this).balance >= amount, "Address: insufficient balance"); 79 | 80 | // solhint-disable-next-line avoid-call-value 81 | (bool success, ) = recipient.call.value(amount)(""); 82 | require(success, "Address: unable to send value, recipient may have reverted"); 83 | } 84 | } 85 | 86 | library SafeERC20 { 87 | using SafeMath for uint256; 88 | using Address for address; 89 | 90 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 91 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 92 | } 93 | 94 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 95 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 96 | } 97 | 98 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 99 | require((value == 0) || (token.allowance(address(this), spender) == 0), 100 | "SafeERC20: approve from non-zero to non-zero allowance" 101 | ); 102 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 103 | } 104 | function callOptionalReturn(IERC20 token, bytes memory data) private { 105 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 106 | 107 | // solhint-disable-next-line avoid-low-level-calls 108 | (bool success, bytes memory returndata) = address(token).call(data); 109 | require(success, "SafeERC20: low-level call failed"); 110 | 111 | if (returndata.length > 0) { // Return data is optional 112 | // solhint-disable-next-line max-line-length 113 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 114 | } 115 | } 116 | } 117 | 118 | interface Controller { 119 | function vaults(address) external view returns (address); 120 | function rewards() external view returns (address); 121 | } 122 | 123 | /* 124 | 125 | A strategy must implement the following calls; 126 | 127 | - deposit() 128 | - withdraw(address) must exclude any tokens used in the yield - Controller role - withdraw should return to Controller 129 | - withdraw(uint) - Controller | Vault role - withdraw should always return to vault 130 | - withdrawAll() - Controller | Vault role - withdraw should always return to vault 131 | - balanceOf() 132 | 133 | Where possible, strategies must remain as immutable as possible, instead of updating variables, we update the contract by linking it in the controller 134 | 135 | */ 136 | 137 | interface Yfii { 138 | function withdraw(uint) external; 139 | function getReward() external; 140 | function stake(uint) external; 141 | function balanceOf(address) external view returns (uint); 142 | function exit() external; 143 | } 144 | 145 | contract Balancer { 146 | function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn) external; 147 | function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut) external; 148 | function swapExactAmountIn( 149 | address tokenIn, 150 | uint tokenAmountIn, 151 | address tokenOut, 152 | uint minAmountOut, 153 | uint maxPrice 154 | ) external returns (uint tokenAmountOut, uint spotPriceAfter); 155 | function swapExactAmountOut( 156 | address tokenIn, 157 | uint maxAmountIn, 158 | address tokenOut, 159 | uint tokenAmountOut, 160 | uint maxPrice 161 | ) external returns (uint tokenAmountIn, uint spotPriceAfter); 162 | function joinswapExternAmountIn(address tokenIn, uint tokenAmountIn, uint minPoolAmountOut) external returns (uint poolAmountOut); 163 | function exitswapPoolAmountIn(address tokenOut, uint poolAmountIn, uint minAmountOut) external returns (uint tokenAmountOut); 164 | } 165 | 166 | interface yERC20 { 167 | function deposit(uint256 _amount) external; 168 | function withdraw(uint256 _amount) external; 169 | } 170 | 171 | interface ICurveFi { 172 | 173 | function get_virtual_price() external view returns (uint); 174 | function add_liquidity( 175 | uint256[4] calldata amounts, 176 | uint256 min_mint_amount 177 | ) external; 178 | function remove_liquidity_imbalance( 179 | uint256[4] calldata amounts, 180 | uint256 max_burn_amount 181 | ) external; 182 | function remove_liquidity( 183 | uint256 _amount, 184 | uint256[4] calldata amounts 185 | ) external; 186 | function exchange( 187 | int128 from, int128 to, uint256 _from_amount, uint256 _min_to_amount 188 | ) external; 189 | } 190 | interface Yvault{ 191 | function make_profit(uint256 amount) external; 192 | } 193 | contract StrategyYfiiPool2 { 194 | using SafeERC20 for IERC20; 195 | using Address for address; 196 | using SafeMath for uint256; 197 | 198 | address constant public want = address(0xB7402204753DD10FBfc74cF4Ee6FCA05017B716D); 199 | address constant public pool = address(0xFd14a4B51dE7297eb970aCcB9CDf82B5bA49d92b); 200 | address constant public yfii = address(0xf2d645D45F0A46CDfa080595Df1d6C9D733296c3); 201 | address constant public balancer = address(0xB7402204753DD10FBfc74cF4Ee6FCA05017B716D); 202 | 203 | 204 | uint constant public fee = 50; 205 | uint constant public max = 10000; 206 | 207 | address public governance; 208 | address public controller; 209 | 210 | constructor(address _controller) public { 211 | governance = msg.sender; 212 | controller = _controller; 213 | } 214 | 215 | function deposit() external { 216 | //bpt -> pool2 217 | IERC20(balancer).safeApprove(pool, 0); 218 | IERC20(balancer).safeApprove(pool, IERC20(balancer).balanceOf(address(this))); 219 | Yfii(pool).stake(IERC20(balancer).balanceOf(address(this))); 220 | } 221 | 222 | // Controller only function for creating additional rewards from dust 223 | function withdraw(IERC20 _asset) external returns (uint balance) { 224 | require(msg.sender == controller, "!controller"); 225 | require(want != address(_asset), "want"); 226 | balance = _asset.balanceOf(address(this)); 227 | _asset.safeTransfer(controller, balance); 228 | } 229 | 230 | // Withdraw partial funds, normally used with a vault withdrawal 231 | function withdraw(uint _amount) external { 232 | require(msg.sender == controller, "!controller"); 233 | uint _balance = IERC20(want).balanceOf(address(this)); 234 | if (_balance < _amount) { 235 | _amount = _withdrawSome(_amount.sub(_balance));//要提取的钱不够,从pool提缺少的出来 236 | _amount = _amount.add(_balance); 237 | } 238 | 239 | address _vault = Controller(controller).vaults(address(want));//金库的地址. 240 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 241 | IERC20(want).safeTransfer(_vault, _amount); 242 | } 243 | 244 | // Withdraw all funds, normally used when migrating strategies 245 | function withdrawAll() external returns (uint balance) { //把ycrv 还到金库 走人 246 | require(msg.sender == controller, "!controller"); 247 | _withdrawAll(); 248 | balance = IERC20(want).balanceOf(address(this)); 249 | 250 | address _vault = Controller(controller).vaults(address(want)); 251 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 252 | IERC20(want).safeTransfer(_vault, balance); 253 | 254 | } 255 | 256 | function _withdrawAll() internal { //退池子 已经领取收益. 收益换成ycrv 257 | Yfii(pool).exit(); 258 | harvest(); 259 | } 260 | 261 | function harvest() public {//砸盘yfii 262 | Yfii(pool).getReward(); //领取yfii 263 | address _vault = Controller(controller).vaults(address(want)); 264 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 265 | 266 | 267 | //把yfii 存进去分红. 268 | IERC20(yfii).safeApprove(_vault, 0); 269 | IERC20(yfii).safeApprove(_vault, IERC20(yfii).balanceOf(address(this))); 270 | Yvault(_vault).make_profit(IERC20(yfii).balanceOf(address(this))); 271 | } 272 | 273 | function _withdrawSome(uint256 _amount) internal returns (uint) { 274 | Yfii(pool).withdraw(_amount); 275 | return _amount; 276 | } 277 | 278 | function balanceOfbpt() public view returns (uint) { 279 | return IERC20(balancer).balanceOf(address(this)); 280 | } 281 | 282 | function balanceOfYfii() public view returns (uint) { 283 | return Yfii(pool).balanceOf(address(this)); 284 | } 285 | 286 | function balanceOf() public view returns (uint) { 287 | return balanceOfbpt(); 288 | 289 | } 290 | 291 | function setGovernance(address _governance) external { 292 | require(msg.sender == governance, "!governance"); 293 | governance = _governance; 294 | } 295 | 296 | function setController(address _controller) external { 297 | require(msg.sender == governance, "!governance"); 298 | controller = _controller; 299 | } 300 | } -------------------------------------------------------------------------------- /contracts/yamsnx/StrategySNXYam.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-07-31 3 | */ 4 | 5 | // SPDX-License-Identifier: MIT 6 | 7 | pragma solidity ^0.5.15; 8 | 9 | interface IERC20 { 10 | function totalSupply() external view returns (uint256); 11 | function balanceOf(address account) external view returns (uint256); 12 | function transfer(address recipient, uint256 amount) external returns (bool); 13 | function allowance(address owner, address spender) external view returns (uint256); 14 | function decimals() external view returns (uint); 15 | function approve(address spender, uint256 amount) external returns (bool); 16 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 17 | event Transfer(address indexed from, address indexed to, uint256 value); 18 | event Approval(address indexed owner, address indexed spender, uint256 value); 19 | } 20 | 21 | library SafeMath { 22 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 23 | uint256 c = a + b; 24 | require(c >= a, "SafeMath: addition overflow"); 25 | 26 | return c; 27 | } 28 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 29 | return sub(a, b, "SafeMath: subtraction overflow"); 30 | } 31 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 32 | require(b <= a, errorMessage); 33 | uint256 c = a - b; 34 | 35 | return c; 36 | } 37 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 38 | if (a == 0) { 39 | return 0; 40 | } 41 | 42 | uint256 c = a * b; 43 | require(c / a == b, "SafeMath: multiplication overflow"); 44 | 45 | return c; 46 | } 47 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 48 | return div(a, b, "SafeMath: division by zero"); 49 | } 50 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 51 | // Solidity only automatically asserts when dividing by 0 52 | require(b > 0, errorMessage); 53 | uint256 c = a / b; 54 | 55 | return c; 56 | } 57 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 58 | return mod(a, b, "SafeMath: modulo by zero"); 59 | } 60 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 61 | require(b != 0, errorMessage); 62 | return a % b; 63 | } 64 | } 65 | 66 | library Address { 67 | function isContract(address account) internal view returns (bool) { 68 | bytes32 codehash; 69 | bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; 70 | // solhint-disable-next-line no-inline-assembly 71 | assembly { codehash := extcodehash(account) } 72 | return (codehash != 0x0 && codehash != accountHash); 73 | } 74 | function toPayable(address account) internal pure returns (address payable) { 75 | return address(uint160(account)); 76 | } 77 | function sendValue(address payable recipient, uint256 amount) internal { 78 | require(address(this).balance >= amount, "Address: insufficient balance"); 79 | 80 | // solhint-disable-next-line avoid-call-value 81 | (bool success, ) = recipient.call.value(amount)(""); 82 | require(success, "Address: unable to send value, recipient may have reverted"); 83 | } 84 | } 85 | 86 | library SafeERC20 { 87 | using SafeMath for uint256; 88 | using Address for address; 89 | 90 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 91 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 92 | } 93 | 94 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 95 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 96 | } 97 | 98 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 99 | require((value == 0) || (token.allowance(address(this), spender) == 0), 100 | "SafeERC20: approve from non-zero to non-zero allowance" 101 | ); 102 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 103 | } 104 | function callOptionalReturn(IERC20 token, bytes memory data) private { 105 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 106 | 107 | // solhint-disable-next-line avoid-low-level-calls 108 | (bool success, bytes memory returndata) = address(token).call(data); 109 | require(success, "SafeERC20: low-level call failed"); 110 | 111 | if (returndata.length > 0) { // Return data is optional 112 | // solhint-disable-next-line max-line-length 113 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 114 | } 115 | } 116 | } 117 | 118 | interface Controller { 119 | function vaults(address) external view returns (address); 120 | function rewards() external view returns (address); 121 | } 122 | 123 | /* 124 | 125 | A strategy must implement the following calls; 126 | 127 | - deposit() 128 | - withdraw(address) must exclude any tokens used in the yield - Controller role - withdraw should return to Controller 129 | - withdraw(uint) - Controller | Vault role - withdraw should always return to vault 130 | - withdrawAll() - Controller | Vault role - withdraw should always return to vault 131 | - balanceOf() 132 | 133 | Where possible, strategies must remain as immutable as possible, instead of updating variables, we update the contract by linking it in the controller 134 | 135 | */ 136 | 137 | interface Yam { 138 | function withdraw(uint) external; 139 | function getReward() external; 140 | function stake(uint) external; 141 | function balanceOf(address) external view returns (uint); 142 | function exit() external; 143 | } 144 | 145 | contract Balancer { 146 | function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn) external; 147 | function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut) external; 148 | function swapExactAmountIn( 149 | address tokenIn, 150 | uint tokenAmountIn, 151 | address tokenOut, 152 | uint minAmountOut, 153 | uint maxPrice 154 | ) external returns (uint tokenAmountOut, uint spotPriceAfter); 155 | function swapExactAmountOut( 156 | address tokenIn, 157 | uint maxAmountIn, 158 | address tokenOut, 159 | uint tokenAmountOut, 160 | uint maxPrice 161 | ) external returns (uint tokenAmountIn, uint spotPriceAfter); 162 | function joinswapExternAmountIn(address tokenIn, uint tokenAmountIn, uint minPoolAmountOut) external returns (uint poolAmountOut); 163 | function exitswapPoolAmountIn(address tokenOut, uint poolAmountIn, uint minAmountOut) external returns (uint tokenAmountOut); 164 | } 165 | interface UniswapRouter { 166 | function swapExactTokensForTokens( 167 | uint amountIn, 168 | uint amountOutMin, 169 | address[] calldata path, 170 | address to, 171 | uint deadline 172 | ) external returns (uint[] memory amounts); 173 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 174 | external returns (uint[] memory amounts); 175 | } 176 | 177 | 178 | interface Yvault{ 179 | function make_profit(uint256 amount) external; 180 | } 181 | interface IFreeFromUpTo { 182 | function freeFromUpTo(address from, uint256 value) external returns (uint256 freed); 183 | } 184 | contract StrategySNXYam { 185 | using SafeERC20 for IERC20; 186 | using Address for address; 187 | using SafeMath for uint256; 188 | 189 | address constant public want = address(0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F); 190 | address constant public pool = address(0x6c3FC1FFDb14D92394f40eeC91D9Ce8B807f132D); 191 | address constant public yfii = address(0xa1d0E215a23d7030842FC67cE582a6aFa3CCaB83); 192 | address constant public yam = address(0x0e2298E3B3390e3b945a5456fBf59eCc3f55DA16); 193 | address constant public unirouter = address(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); 194 | address constant public weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); 195 | address constant public dai = address(0x6B175474E89094C44Da98b954EedeAC495271d0F); 196 | address constant public balancer = address(0x16cAC1403377978644e78769Daa49d8f6B6CF565); 197 | 198 | IFreeFromUpTo public constant chi = IFreeFromUpTo(0x0000000000004946c0e9F43F4Dee607b0eF1fA1c); 199 | 200 | 201 | 202 | uint constant public fee = 50; 203 | uint constant public max = 10000; 204 | 205 | address public governance; 206 | address public controller; 207 | 208 | modifier discountCHI { 209 | uint256 gasStart = gasleft(); 210 | _; 211 | uint256 gasSpent = 21000 + gasStart - gasleft() + 16 * msg.data.length; 212 | chi.freeFromUpTo(msg.sender, (gasSpent + 14154) / 41130); 213 | } 214 | 215 | constructor(address _controller) public { 216 | governance = tx.origin; 217 | controller = _controller; 218 | } 219 | 220 | function deposit() external { 221 | IERC20(want).safeApprove(pool, 0); 222 | IERC20(want).safeApprove(pool, IERC20(want).balanceOf(address(this))); 223 | Yam(pool).stake(IERC20(want).balanceOf(address(this))); 224 | } 225 | 226 | // Controller only function for creating additional rewards from dust 227 | function withdraw(IERC20 _asset) external returns (uint balance) { 228 | require(msg.sender == controller, "!controller"); 229 | require(want != address(_asset), "want"); 230 | balance = _asset.balanceOf(address(this)); 231 | _asset.safeTransfer(controller, balance); 232 | } 233 | 234 | // Withdraw partial funds, normally used with a vault withdrawal 235 | function withdraw(uint _amount) external { 236 | require(msg.sender == controller, "!controller"); 237 | uint _balance = IERC20(want).balanceOf(address(this)); 238 | if (_balance < _amount) { 239 | _amount = _withdrawSome(_amount.sub(_balance)); 240 | _amount = _amount.add(_balance); 241 | } 242 | 243 | address _vault = Controller(controller).vaults(address(want)); 244 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 245 | IERC20(want).safeTransfer(_vault, _amount); 246 | } 247 | 248 | // Withdraw all funds, normally used when migrating strategies 249 | function withdrawAll() external returns (uint balance) { 250 | require(msg.sender == controller, "!controller"); 251 | _withdrawAll(); 252 | balance = IERC20(want).balanceOf(address(this)); 253 | 254 | address _vault = Controller(controller).vaults(address(want)); 255 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 256 | IERC20(want).safeTransfer(_vault, balance); 257 | 258 | } 259 | 260 | function _withdrawAll() internal { 261 | Yam(pool).exit(); 262 | harvest(); 263 | } 264 | 265 | function harvest() public discountCHI{ 266 | Yam(pool).getReward(); 267 | address _vault = Controller(controller).vaults(address(want)); 268 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 269 | 270 | // yam->weth->dai 271 | IERC20(yam).approve(unirouter, uint(-1)); 272 | address[] memory path3 = new address[](3); 273 | path3[0] = address(yam); 274 | path3[1] = address(weth); 275 | path3[2] = address(dai); 276 | UniswapRouter(unirouter).swapExactTokensForTokens(IERC20(yam).balanceOf(address(this)), 0, path3, address(this), now.add(1800)); 277 | 278 | // dai ->yfii 279 | IERC20(dai).safeApprove(balancer, 0); 280 | IERC20(dai).safeApprove(balancer, IERC20(dai).balanceOf(address(this))); 281 | Balancer(balancer).swapExactAmountIn(dai, IERC20(dai).balanceOf(address(this)), yfii, 0, uint(-1)); 282 | 283 | // fee 284 | uint b = IERC20(yfii).balanceOf(address(this)); 285 | uint _fee = b.mul(fee).div(max); 286 | IERC20(yfii).safeTransfer(Controller(controller).rewards(), _fee); 287 | 288 | //把yfii 存进去分红. 289 | IERC20(yfii).safeApprove(_vault, 0); 290 | IERC20(yfii).safeApprove(_vault, IERC20(yfii).balanceOf(address(this))); 291 | Yvault(_vault).make_profit(IERC20(yfii).balanceOf(address(this))); 292 | } 293 | 294 | function _withdrawSome(uint256 _amount) internal returns (uint) { 295 | Yam(pool).withdraw(_amount); 296 | return _amount; 297 | } 298 | 299 | function balanceOfWant() public view returns (uint) { 300 | return IERC20(want).balanceOf(address(this)); 301 | } 302 | 303 | function balanceOfYam() public view returns (uint) { 304 | return Yam(pool).balanceOf(address(this)); 305 | } 306 | 307 | function balanceOf() public view returns (uint) { 308 | return balanceOfWant(); 309 | 310 | } 311 | 312 | function setGovernance(address _governance) external { 313 | require(msg.sender == governance, "!governance"); 314 | governance = _governance; 315 | } 316 | 317 | function setController(address _controller) external { 318 | require(msg.sender == governance, "!governance"); 319 | controller = _controller; 320 | } 321 | } -------------------------------------------------------------------------------- /contracts/yamcomp/StrategyCompYam.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-07-31 3 | */ 4 | 5 | // SPDX-License-Identifier: MIT 6 | 7 | pragma solidity ^0.5.15; 8 | 9 | interface IERC20 { 10 | function totalSupply() external view returns (uint256); 11 | function balanceOf(address account) external view returns (uint256); 12 | function transfer(address recipient, uint256 amount) external returns (bool); 13 | function allowance(address owner, address spender) external view returns (uint256); 14 | function decimals() external view returns (uint); 15 | function approve(address spender, uint256 amount) external returns (bool); 16 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 17 | event Transfer(address indexed from, address indexed to, uint256 value); 18 | event Approval(address indexed owner, address indexed spender, uint256 value); 19 | } 20 | 21 | library SafeMath { 22 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 23 | uint256 c = a + b; 24 | require(c >= a, "SafeMath: addition overflow"); 25 | 26 | return c; 27 | } 28 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 29 | return sub(a, b, "SafeMath: subtraction overflow"); 30 | } 31 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 32 | require(b <= a, errorMessage); 33 | uint256 c = a - b; 34 | 35 | return c; 36 | } 37 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 38 | if (a == 0) { 39 | return 0; 40 | } 41 | 42 | uint256 c = a * b; 43 | require(c / a == b, "SafeMath: multiplication overflow"); 44 | 45 | return c; 46 | } 47 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 48 | return div(a, b, "SafeMath: division by zero"); 49 | } 50 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 51 | // Solidity only automatically asserts when dividing by 0 52 | require(b > 0, errorMessage); 53 | uint256 c = a / b; 54 | 55 | return c; 56 | } 57 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 58 | return mod(a, b, "SafeMath: modulo by zero"); 59 | } 60 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 61 | require(b != 0, errorMessage); 62 | return a % b; 63 | } 64 | } 65 | 66 | library Address { 67 | function isContract(address account) internal view returns (bool) { 68 | bytes32 codehash; 69 | bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; 70 | // solhint-disable-next-line no-inline-assembly 71 | assembly { codehash := extcodehash(account) } 72 | return (codehash != 0x0 && codehash != accountHash); 73 | } 74 | function toPayable(address account) internal pure returns (address payable) { 75 | return address(uint160(account)); 76 | } 77 | function sendValue(address payable recipient, uint256 amount) internal { 78 | require(address(this).balance >= amount, "Address: insufficient balance"); 79 | 80 | // solhint-disable-next-line avoid-call-value 81 | (bool success, ) = recipient.call.value(amount)(""); 82 | require(success, "Address: unable to send value, recipient may have reverted"); 83 | } 84 | } 85 | 86 | library SafeERC20 { 87 | using SafeMath for uint256; 88 | using Address for address; 89 | 90 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 91 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 92 | } 93 | 94 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 95 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 96 | } 97 | 98 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 99 | require((value == 0) || (token.allowance(address(this), spender) == 0), 100 | "SafeERC20: approve from non-zero to non-zero allowance" 101 | ); 102 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 103 | } 104 | function callOptionalReturn(IERC20 token, bytes memory data) private { 105 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 106 | 107 | // solhint-disable-next-line avoid-low-level-calls 108 | (bool success, bytes memory returndata) = address(token).call(data); 109 | require(success, "SafeERC20: low-level call failed"); 110 | 111 | if (returndata.length > 0) { // Return data is optional 112 | // solhint-disable-next-line max-line-length 113 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 114 | } 115 | } 116 | } 117 | 118 | interface Controller { 119 | function vaults(address) external view returns (address); 120 | function rewards() external view returns (address); 121 | } 122 | 123 | /* 124 | 125 | A strategy must implement the following calls; 126 | 127 | - deposit() 128 | - withdraw(address) must exclude any tokens used in the yield - Controller role - withdraw should return to Controller 129 | - withdraw(uint) - Controller | Vault role - withdraw should always return to vault 130 | - withdrawAll() - Controller | Vault role - withdraw should always return to vault 131 | - balanceOf() 132 | 133 | Where possible, strategies must remain as immutable as possible, instead of updating variables, we update the contract by linking it in the controller 134 | 135 | */ 136 | 137 | interface Yam { 138 | function withdraw(uint) external; 139 | function getReward() external; 140 | function stake(uint) external; 141 | function balanceOf(address) external view returns (uint); 142 | function exit() external; 143 | } 144 | 145 | contract Balancer { 146 | function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn) external; 147 | function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut) external; 148 | function swapExactAmountIn( 149 | address tokenIn, 150 | uint tokenAmountIn, 151 | address tokenOut, 152 | uint minAmountOut, 153 | uint maxPrice 154 | ) external returns (uint tokenAmountOut, uint spotPriceAfter); 155 | function swapExactAmountOut( 156 | address tokenIn, 157 | uint maxAmountIn, 158 | address tokenOut, 159 | uint tokenAmountOut, 160 | uint maxPrice 161 | ) external returns (uint tokenAmountIn, uint spotPriceAfter); 162 | function joinswapExternAmountIn(address tokenIn, uint tokenAmountIn, uint minPoolAmountOut) external returns (uint poolAmountOut); 163 | function exitswapPoolAmountIn(address tokenOut, uint poolAmountIn, uint minAmountOut) external returns (uint tokenAmountOut); 164 | } 165 | interface UniswapRouter { 166 | function swapExactTokensForTokens( 167 | uint amountIn, 168 | uint amountOutMin, 169 | address[] calldata path, 170 | address to, 171 | uint deadline 172 | ) external returns (uint[] memory amounts); 173 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 174 | external returns (uint[] memory amounts); 175 | } 176 | 177 | 178 | interface Yvault{ 179 | function make_profit(uint256 amount) external; 180 | } 181 | interface IFreeFromUpTo { 182 | function freeFromUpTo(address from, uint256 value) external returns (uint256 freed); 183 | } 184 | contract StrategyCOMPYam { 185 | using SafeERC20 for IERC20; 186 | using Address for address; 187 | using SafeMath for uint256; 188 | 189 | address constant public want = address(0xc00e94Cb662C3520282E6f5717214004A7f26888); 190 | address constant public pool = address(0x8538E5910c6F80419CD3170c26073Ff238048c9E); 191 | address constant public yfii = address(0xa1d0E215a23d7030842FC67cE582a6aFa3CCaB83); 192 | address constant public yam = address(0x0e2298E3B3390e3b945a5456fBf59eCc3f55DA16); 193 | address constant public unirouter = address(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); 194 | address constant public weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); 195 | address constant public dai = address(0x6B175474E89094C44Da98b954EedeAC495271d0F); 196 | address constant public balancer = address(0x16cAC1403377978644e78769Daa49d8f6B6CF565); 197 | 198 | IFreeFromUpTo public constant chi = IFreeFromUpTo(0x0000000000004946c0e9F43F4Dee607b0eF1fA1c); 199 | 200 | 201 | 202 | uint constant public fee = 50; 203 | uint constant public max = 10000; 204 | 205 | address public governance; 206 | address public controller; 207 | 208 | modifier discountCHI { 209 | uint256 gasStart = gasleft(); 210 | _; 211 | uint256 gasSpent = 21000 + gasStart - gasleft() + 16 * msg.data.length; 212 | chi.freeFromUpTo(msg.sender, (gasSpent + 14154) / 41130); 213 | } 214 | 215 | constructor(address _controller) public { 216 | governance = tx.origin; 217 | controller = _controller; 218 | } 219 | 220 | function deposit() external { 221 | IERC20(want).safeApprove(pool, 0); 222 | IERC20(want).safeApprove(pool, IERC20(want).balanceOf(address(this))); 223 | Yam(pool).stake(IERC20(want).balanceOf(address(this))); 224 | } 225 | 226 | // Controller only function for creating additional rewards from dust 227 | function withdraw(IERC20 _asset) external returns (uint balance) { 228 | require(msg.sender == controller, "!controller"); 229 | require(want != address(_asset), "want"); 230 | balance = _asset.balanceOf(address(this)); 231 | _asset.safeTransfer(controller, balance); 232 | } 233 | 234 | // Withdraw partial funds, normally used with a vault withdrawal 235 | function withdraw(uint _amount) external { 236 | require(msg.sender == controller, "!controller"); 237 | uint _balance = IERC20(want).balanceOf(address(this)); 238 | if (_balance < _amount) { 239 | _amount = _withdrawSome(_amount.sub(_balance)); 240 | _amount = _amount.add(_balance); 241 | } 242 | 243 | address _vault = Controller(controller).vaults(address(want)); 244 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 245 | IERC20(want).safeTransfer(_vault, _amount); 246 | } 247 | 248 | // Withdraw all funds, normally used when migrating strategies 249 | function withdrawAll() external returns (uint balance) { 250 | require(msg.sender == controller, "!controller"); 251 | _withdrawAll(); 252 | balance = IERC20(want).balanceOf(address(this)); 253 | 254 | address _vault = Controller(controller).vaults(address(want)); 255 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 256 | IERC20(want).safeTransfer(_vault, balance); 257 | 258 | } 259 | 260 | function _withdrawAll() internal { 261 | Yam(pool).exit(); 262 | harvest(); 263 | } 264 | 265 | function harvest() public discountCHI{ 266 | Yam(pool).getReward(); 267 | address _vault = Controller(controller).vaults(address(want)); 268 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 269 | 270 | // yam->weth->dai 271 | IERC20(yam).approve(unirouter, uint(-1)); 272 | address[] memory path3 = new address[](3); 273 | path3[0] = address(yam); 274 | path3[1] = address(weth); 275 | path3[2] = address(dai); 276 | UniswapRouter(unirouter).swapExactTokensForTokens(IERC20(yam).balanceOf(address(this)), 0, path3, address(this), now.add(1800)); 277 | 278 | // dai ->yfii 279 | IERC20(dai).safeApprove(balancer, 0); 280 | IERC20(dai).safeApprove(balancer, IERC20(dai).balanceOf(address(this))); 281 | Balancer(balancer).swapExactAmountIn(dai, IERC20(dai).balanceOf(address(this)), yfii, 0, uint(-1)); 282 | 283 | // fee 284 | uint b = IERC20(yfii).balanceOf(address(this)); 285 | uint _fee = b.mul(fee).div(max); 286 | IERC20(yfii).safeTransfer(Controller(controller).rewards(), _fee); 287 | 288 | //把yfii 存进去分红. 289 | IERC20(yfii).safeApprove(_vault, 0); 290 | IERC20(yfii).safeApprove(_vault, IERC20(yfii).balanceOf(address(this))); 291 | Yvault(_vault).make_profit(IERC20(yfii).balanceOf(address(this))); 292 | } 293 | 294 | function _withdrawSome(uint256 _amount) internal returns (uint) { 295 | Yam(pool).withdraw(_amount); 296 | return _amount; 297 | } 298 | 299 | function balanceOfWant() public view returns (uint) { 300 | return IERC20(want).balanceOf(address(this)); 301 | } 302 | 303 | function balanceOfYam() public view returns (uint) { 304 | return Yam(pool).balanceOf(address(this)); 305 | } 306 | 307 | function balanceOf() public view returns (uint) { 308 | return balanceOfWant(); 309 | 310 | } 311 | 312 | function setGovernance(address _governance) external { 313 | require(msg.sender == governance, "!governance"); 314 | governance = _governance; 315 | } 316 | 317 | function setController(address _controller) external { 318 | require(msg.sender == governance, "!governance"); 319 | controller = _controller; 320 | } 321 | } -------------------------------------------------------------------------------- /contracts/yamstandard/StrategySNXYam.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-07-31 3 | */ 4 | 5 | // SPDX-License-Identifier: MIT 6 | 7 | pragma solidity ^0.5.15; 8 | 9 | interface IERC20 { 10 | function totalSupply() external view returns (uint256); 11 | function balanceOf(address account) external view returns (uint256); 12 | function transfer(address recipient, uint256 amount) external returns (bool); 13 | function allowance(address owner, address spender) external view returns (uint256); 14 | function decimals() external view returns (uint); 15 | function approve(address spender, uint256 amount) external returns (bool); 16 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 17 | event Transfer(address indexed from, address indexed to, uint256 value); 18 | event Approval(address indexed owner, address indexed spender, uint256 value); 19 | } 20 | 21 | library SafeMath { 22 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 23 | uint256 c = a + b; 24 | require(c >= a, "SafeMath: addition overflow"); 25 | 26 | return c; 27 | } 28 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 29 | return sub(a, b, "SafeMath: subtraction overflow"); 30 | } 31 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 32 | require(b <= a, errorMessage); 33 | uint256 c = a - b; 34 | 35 | return c; 36 | } 37 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 38 | if (a == 0) { 39 | return 0; 40 | } 41 | 42 | uint256 c = a * b; 43 | require(c / a == b, "SafeMath: multiplication overflow"); 44 | 45 | return c; 46 | } 47 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 48 | return div(a, b, "SafeMath: division by zero"); 49 | } 50 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 51 | // Solidity only automatically asserts when dividing by 0 52 | require(b > 0, errorMessage); 53 | uint256 c = a / b; 54 | 55 | return c; 56 | } 57 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 58 | return mod(a, b, "SafeMath: modulo by zero"); 59 | } 60 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 61 | require(b != 0, errorMessage); 62 | return a % b; 63 | } 64 | } 65 | 66 | library Address { 67 | function isContract(address account) internal view returns (bool) { 68 | bytes32 codehash; 69 | bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; 70 | // solhint-disable-next-line no-inline-assembly 71 | assembly { codehash := extcodehash(account) } 72 | return (codehash != 0x0 && codehash != accountHash); 73 | } 74 | function toPayable(address account) internal pure returns (address payable) { 75 | return address(uint160(account)); 76 | } 77 | function sendValue(address payable recipient, uint256 amount) internal { 78 | require(address(this).balance >= amount, "Address: insufficient balance"); 79 | 80 | // solhint-disable-next-line avoid-call-value 81 | (bool success, ) = recipient.call.value(amount)(""); 82 | require(success, "Address: unable to send value, recipient may have reverted"); 83 | } 84 | } 85 | 86 | library SafeERC20 { 87 | using SafeMath for uint256; 88 | using Address for address; 89 | 90 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 91 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 92 | } 93 | 94 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 95 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 96 | } 97 | 98 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 99 | require((value == 0) || (token.allowance(address(this), spender) == 0), 100 | "SafeERC20: approve from non-zero to non-zero allowance" 101 | ); 102 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 103 | } 104 | function callOptionalReturn(IERC20 token, bytes memory data) private { 105 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 106 | 107 | // solhint-disable-next-line avoid-low-level-calls 108 | (bool success, bytes memory returndata) = address(token).call(data); 109 | require(success, "SafeERC20: low-level call failed"); 110 | 111 | if (returndata.length > 0) { // Return data is optional 112 | // solhint-disable-next-line max-line-length 113 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 114 | } 115 | } 116 | } 117 | 118 | interface Controller { 119 | function vaults(address) external view returns (address); 120 | function rewards() external view returns (address); 121 | } 122 | 123 | /* 124 | 125 | A strategy must implement the following calls; 126 | 127 | - deposit() 128 | - withdraw(address) must exclude any tokens used in the yield - Controller role - withdraw should return to Controller 129 | - withdraw(uint) - Controller | Vault role - withdraw should always return to vault 130 | - withdrawAll() - Controller | Vault role - withdraw should always return to vault 131 | - balanceOf() 132 | 133 | Where possible, strategies must remain as immutable as possible, instead of updating variables, we update the contract by linking it in the controller 134 | 135 | */ 136 | 137 | interface Yam { 138 | function withdraw(uint) external; 139 | function getReward() external; 140 | function stake(uint) external; 141 | function balanceOf(address) external view returns (uint); 142 | function exit() external; 143 | } 144 | 145 | contract Balancer { 146 | function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn) external; 147 | function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut) external; 148 | function swapExactAmountIn( 149 | address tokenIn, 150 | uint tokenAmountIn, 151 | address tokenOut, 152 | uint minAmountOut, 153 | uint maxPrice 154 | ) external returns (uint tokenAmountOut, uint spotPriceAfter); 155 | function swapExactAmountOut( 156 | address tokenIn, 157 | uint maxAmountIn, 158 | address tokenOut, 159 | uint tokenAmountOut, 160 | uint maxPrice 161 | ) external returns (uint tokenAmountIn, uint spotPriceAfter); 162 | function joinswapExternAmountIn(address tokenIn, uint tokenAmountIn, uint minPoolAmountOut) external returns (uint poolAmountOut); 163 | function exitswapPoolAmountIn(address tokenOut, uint poolAmountIn, uint minAmountOut) external returns (uint tokenAmountOut); 164 | } 165 | interface UniswapRouter { 166 | function swapExactTokensForTokens( 167 | uint amountIn, 168 | uint amountOutMin, 169 | address[] calldata path, 170 | address to, 171 | uint deadline 172 | ) external returns (uint[] memory amounts); 173 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 174 | external returns (uint[] memory amounts); 175 | } 176 | 177 | 178 | interface Yvault{ 179 | function make_profit(uint256 amount) external; 180 | } 181 | interface IFreeFromUpTo { 182 | function freeFromUpTo(address from, uint256 value) external returns (uint256 freed); 183 | } 184 | contract StrategyStandardYam { 185 | using SafeERC20 for IERC20; 186 | using Address for address; 187 | using SafeMath for uint256; 188 | 189 | 190 | address constant public yfii = address(0xa1d0E215a23d7030842FC67cE582a6aFa3CCaB83); 191 | address constant public yam = address(0x0e2298E3B3390e3b945a5456fBf59eCc3f55DA16); 192 | address constant public unirouter = address(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); 193 | address constant public weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); 194 | address constant public dai = address(0x6B175474E89094C44Da98b954EedeAC495271d0F); 195 | address constant public balancer = address(0x16cAC1403377978644e78769Daa49d8f6B6CF565); 196 | 197 | IFreeFromUpTo public constant chi = IFreeFromUpTo(0x0000000000004946c0e9F43F4Dee607b0eF1fA1c); 198 | 199 | 200 | 201 | uint constant public fee = 50; 202 | uint constant public max = 10000; 203 | 204 | address public governance; 205 | address public controller; 206 | 207 | address public want; 208 | address public pool ; 209 | 210 | modifier discountCHI { 211 | uint256 gasStart = gasleft(); 212 | _; 213 | uint256 gasSpent = 21000 + gasStart - gasleft() + 16 * msg.data.length; 214 | chi.freeFromUpTo(msg.sender, (gasSpent + 14154) / 41130); 215 | } 216 | 217 | constructor(address _controller,address _want,address _pool) public { 218 | governance = tx.origin; 219 | controller = _controller; 220 | want = _want; 221 | pool = _pool; 222 | } 223 | 224 | 225 | function deposit() external { 226 | IERC20(want).safeApprove(pool, 0); 227 | IERC20(want).safeApprove(pool, IERC20(want).balanceOf(address(this))); 228 | Yam(pool).stake(IERC20(want).balanceOf(address(this))); 229 | } 230 | 231 | // Controller only function for creating additional rewards from dust 232 | function withdraw(IERC20 _asset) external returns (uint balance) { 233 | require(msg.sender == controller, "!controller"); 234 | require(want != address(_asset), "want"); 235 | balance = _asset.balanceOf(address(this)); 236 | _asset.safeTransfer(controller, balance); 237 | } 238 | 239 | // Withdraw partial funds, normally used with a vault withdrawal 240 | function withdraw(uint _amount) external { 241 | require(msg.sender == controller, "!controller"); 242 | uint _balance = IERC20(want).balanceOf(address(this)); 243 | if (_balance < _amount) { 244 | _amount = _withdrawSome(_amount.sub(_balance)); 245 | _amount = _amount.add(_balance); 246 | } 247 | 248 | address _vault = Controller(controller).vaults(address(want)); 249 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 250 | IERC20(want).safeTransfer(_vault, _amount); 251 | } 252 | 253 | // Withdraw all funds, normally used when migrating strategies 254 | function withdrawAll() external returns (uint balance) { 255 | require(msg.sender == controller, "!controller"); 256 | _withdrawAll(); 257 | balance = IERC20(want).balanceOf(address(this)); 258 | 259 | address _vault = Controller(controller).vaults(address(want)); 260 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 261 | IERC20(want).safeTransfer(_vault, balance); 262 | 263 | } 264 | 265 | function _withdrawAll() internal { 266 | Yam(pool).exit(); 267 | harvest(); 268 | } 269 | 270 | function harvest() public discountCHI{ 271 | Yam(pool).getReward(); 272 | address _vault = Controller(controller).vaults(address(want)); 273 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 274 | 275 | // yam->weth->dai 276 | IERC20(yam).approve(unirouter, uint(-1)); 277 | address[] memory path3 = new address[](3); 278 | path3[0] = address(yam); 279 | path3[1] = address(weth); 280 | path3[2] = address(dai); 281 | UniswapRouter(unirouter).swapExactTokensForTokens(IERC20(yam).balanceOf(address(this)), 0, path3, address(this), now.add(1800)); 282 | 283 | // dai ->yfii 284 | IERC20(dai).safeApprove(balancer, 0); 285 | IERC20(dai).safeApprove(balancer, IERC20(dai).balanceOf(address(this))); 286 | Balancer(balancer).swapExactAmountIn(dai, IERC20(dai).balanceOf(address(this)), yfii, 0, uint(-1)); 287 | 288 | // fee 289 | uint b = IERC20(yfii).balanceOf(address(this)); 290 | uint _fee = b.mul(fee).div(max); 291 | IERC20(yfii).safeTransfer(Controller(controller).rewards(), _fee); 292 | 293 | //把yfii 存进去分红. 294 | IERC20(yfii).safeApprove(_vault, 0); 295 | IERC20(yfii).safeApprove(_vault, IERC20(yfii).balanceOf(address(this))); 296 | Yvault(_vault).make_profit(IERC20(yfii).balanceOf(address(this))); 297 | } 298 | 299 | function _withdrawSome(uint256 _amount) internal returns (uint) { 300 | Yam(pool).withdraw(_amount); 301 | return _amount; 302 | } 303 | 304 | function balanceOfWant() public view returns (uint) { 305 | return IERC20(want).balanceOf(address(this)); 306 | } 307 | 308 | function balanceOfYam() public view returns (uint) { 309 | return Yam(pool).balanceOf(address(this)); 310 | } 311 | 312 | function balanceOf() public view returns (uint) { 313 | return balanceOfWant(); 314 | 315 | } 316 | 317 | function setGovernance(address _governance) external { 318 | require(msg.sender == governance, "!governance"); 319 | governance = _governance; 320 | } 321 | 322 | function setController(address _controller) external { 323 | require(msg.sender == governance, "!governance"); 324 | controller = _controller; 325 | } 326 | } -------------------------------------------------------------------------------- /contracts/yamweth/StrategyWETHYam.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2020-07-31 3 | */ 4 | 5 | // SPDX-License-Identifier: MIT 6 | 7 | pragma solidity ^0.5.15; 8 | 9 | interface IERC20 { 10 | function totalSupply() external view returns (uint256); 11 | function balanceOf(address account) external view returns (uint256); 12 | function transfer(address recipient, uint256 amount) external returns (bool); 13 | function allowance(address owner, address spender) external view returns (uint256); 14 | function decimals() external view returns (uint); 15 | function approve(address spender, uint256 amount) external returns (bool); 16 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 17 | event Transfer(address indexed from, address indexed to, uint256 value); 18 | event Approval(address indexed owner, address indexed spender, uint256 value); 19 | } 20 | 21 | library SafeMath { 22 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 23 | uint256 c = a + b; 24 | require(c >= a, "SafeMath: addition overflow"); 25 | 26 | return c; 27 | } 28 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 29 | return sub(a, b, "SafeMath: subtraction overflow"); 30 | } 31 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 32 | require(b <= a, errorMessage); 33 | uint256 c = a - b; 34 | 35 | return c; 36 | } 37 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 38 | if (a == 0) { 39 | return 0; 40 | } 41 | 42 | uint256 c = a * b; 43 | require(c / a == b, "SafeMath: multiplication overflow"); 44 | 45 | return c; 46 | } 47 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 48 | return div(a, b, "SafeMath: division by zero"); 49 | } 50 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 51 | // Solidity only automatically asserts when dividing by 0 52 | require(b > 0, errorMessage); 53 | uint256 c = a / b; 54 | 55 | return c; 56 | } 57 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 58 | return mod(a, b, "SafeMath: modulo by zero"); 59 | } 60 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 61 | require(b != 0, errorMessage); 62 | return a % b; 63 | } 64 | } 65 | 66 | library Address { 67 | function isContract(address account) internal view returns (bool) { 68 | bytes32 codehash; 69 | bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; 70 | // solhint-disable-next-line no-inline-assembly 71 | assembly { codehash := extcodehash(account) } 72 | return (codehash != 0x0 && codehash != accountHash); 73 | } 74 | function toPayable(address account) internal pure returns (address payable) { 75 | return address(uint160(account)); 76 | } 77 | function sendValue(address payable recipient, uint256 amount) internal { 78 | require(address(this).balance >= amount, "Address: insufficient balance"); 79 | 80 | // solhint-disable-next-line avoid-call-value 81 | (bool success, ) = recipient.call.value(amount)(""); 82 | require(success, "Address: unable to send value, recipient may have reverted"); 83 | } 84 | } 85 | 86 | library SafeERC20 { 87 | using SafeMath for uint256; 88 | using Address for address; 89 | 90 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 91 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 92 | } 93 | 94 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 95 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 96 | } 97 | 98 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 99 | require((value == 0) || (token.allowance(address(this), spender) == 0), 100 | "SafeERC20: approve from non-zero to non-zero allowance" 101 | ); 102 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 103 | } 104 | function callOptionalReturn(IERC20 token, bytes memory data) private { 105 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 106 | 107 | // solhint-disable-next-line avoid-low-level-calls 108 | (bool success, bytes memory returndata) = address(token).call(data); 109 | require(success, "SafeERC20: low-level call failed"); 110 | 111 | if (returndata.length > 0) { // Return data is optional 112 | // solhint-disable-next-line max-line-length 113 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 114 | } 115 | } 116 | } 117 | 118 | interface Controller { 119 | function vaults(address) external view returns (address); 120 | function rewards() external view returns (address); 121 | } 122 | 123 | /* 124 | 125 | A strategy must implement the following calls; 126 | 127 | - deposit() 128 | - withdraw(address) must exclude any tokens used in the yield - Controller role - withdraw should return to Controller 129 | - withdraw(uint) - Controller | Vault role - withdraw should always return to vault 130 | - withdrawAll() - Controller | Vault role - withdraw should always return to vault 131 | - balanceOf() 132 | 133 | Where possible, strategies must remain as immutable as possible, instead of updating variables, we update the contract by linking it in the controller 134 | 135 | */ 136 | 137 | interface Yam { 138 | function withdraw(uint) external; 139 | function getReward() external; 140 | function stake(uint) external; 141 | function balanceOf(address) external view returns (uint); 142 | function exit() external; 143 | } 144 | 145 | contract Balancer { 146 | function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn) external; 147 | function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut) external; 148 | function swapExactAmountIn( 149 | address tokenIn, 150 | uint tokenAmountIn, 151 | address tokenOut, 152 | uint minAmountOut, 153 | uint maxPrice 154 | ) external returns (uint tokenAmountOut, uint spotPriceAfter); 155 | function swapExactAmountOut( 156 | address tokenIn, 157 | uint maxAmountIn, 158 | address tokenOut, 159 | uint tokenAmountOut, 160 | uint maxPrice 161 | ) external returns (uint tokenAmountIn, uint spotPriceAfter); 162 | function joinswapExternAmountIn(address tokenIn, uint tokenAmountIn, uint minPoolAmountOut) external returns (uint poolAmountOut); 163 | function exitswapPoolAmountIn(address tokenOut, uint poolAmountIn, uint minAmountOut) external returns (uint tokenAmountOut); 164 | } 165 | interface UniswapRouter { 166 | function swapExactTokensForTokens( 167 | uint amountIn, 168 | uint amountOutMin, 169 | address[] calldata path, 170 | address to, 171 | uint deadline 172 | ) external returns (uint[] memory amounts); 173 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 174 | external returns (uint[] memory amounts); 175 | } 176 | 177 | 178 | interface Yvault{ 179 | function make_profit(uint256 amount) external; 180 | } 181 | interface IFreeFromUpTo { 182 | function freeFromUpTo(address from, uint256 value) external returns (uint256 freed); 183 | } 184 | contract StrategyWETHYam { 185 | using SafeERC20 for IERC20; 186 | using Address for address; 187 | using SafeMath for uint256; 188 | 189 | address constant public want = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); 190 | address constant public pool = address(0x587A07cE5c265A38Dd6d42def1566BA73eeb06F5); 191 | address constant public yfii = address(0xa1d0E215a23d7030842FC67cE582a6aFa3CCaB83); 192 | address constant public yam = address(0x0e2298E3B3390e3b945a5456fBf59eCc3f55DA16); 193 | address constant public unirouter = address(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); 194 | address constant public weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); 195 | address constant public dai = address(0x6B175474E89094C44Da98b954EedeAC495271d0F); 196 | address constant public balancer = address(0x16cAC1403377978644e78769Daa49d8f6B6CF565); 197 | 198 | IFreeFromUpTo public constant chi = IFreeFromUpTo(0x0000000000004946c0e9F43F4Dee607b0eF1fA1c); 199 | 200 | 201 | 202 | uint constant public fee = 50; 203 | uint constant public max = 10000; 204 | 205 | address public governance; 206 | address public controller; 207 | 208 | modifier discountCHI { 209 | uint256 gasStart = gasleft(); 210 | _; 211 | uint256 gasSpent = 21000 + gasStart - gasleft() + 16 * msg.data.length; 212 | chi.freeFromUpTo(msg.sender, (gasSpent + 14154) / 41130); 213 | } 214 | 215 | constructor(address _controller) public { 216 | governance = tx.origin; 217 | controller = _controller; 218 | } 219 | 220 | function deposit() external { 221 | IERC20(want).safeApprove(pool, 0); 222 | IERC20(want).safeApprove(pool, IERC20(want).balanceOf(address(this))); 223 | Yam(pool).stake(IERC20(want).balanceOf(address(this))); 224 | } 225 | 226 | // Controller only function for creating additional rewards from dust 227 | function withdraw(IERC20 _asset) external returns (uint balance) { 228 | require(msg.sender == controller, "!controller"); 229 | require(want != address(_asset), "want"); 230 | balance = _asset.balanceOf(address(this)); 231 | _asset.safeTransfer(controller, balance); 232 | } 233 | 234 | // Withdraw partial funds, normally used with a vault withdrawal 235 | function withdraw(uint _amount) external { 236 | require(msg.sender == controller, "!controller"); 237 | uint _balance = IERC20(want).balanceOf(address(this)); 238 | if (_balance < _amount) { 239 | _amount = _withdrawSome(_amount.sub(_balance)); 240 | _amount = _amount.add(_balance); 241 | } 242 | 243 | address _vault = Controller(controller).vaults(address(want)); 244 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 245 | IERC20(want).safeTransfer(_vault, _amount); 246 | } 247 | 248 | // Withdraw all funds, normally used when migrating strategies 249 | function withdrawAll() external returns (uint balance) { 250 | require(msg.sender == controller, "!controller"); 251 | _withdrawAll(); 252 | balance = IERC20(want).balanceOf(address(this)); 253 | 254 | address _vault = Controller(controller).vaults(address(want)); 255 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 256 | IERC20(want).safeTransfer(_vault, balance); 257 | 258 | } 259 | 260 | function _withdrawAll() internal { 261 | Yam(pool).exit(); 262 | harvest(); 263 | } 264 | 265 | function harvest() public discountCHI{ 266 | Yam(pool).getReward(); 267 | address _vault = Controller(controller).vaults(address(want)); 268 | require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds 269 | 270 | // yam->weth->dai 271 | IERC20(yam).approve(unirouter, uint(-1)); 272 | address[] memory path3 = new address[](3); 273 | path3[0] = address(yam); 274 | path3[1] = address(weth); 275 | path3[2] = address(dai); 276 | UniswapRouter(unirouter).swapExactTokensForTokens(IERC20(yam).balanceOf(address(this)), 0, path3, address(this), now.add(1800)); 277 | 278 | // dai ->yfii 279 | IERC20(dai).safeApprove(balancer, 0); 280 | IERC20(dai).safeApprove(balancer, IERC20(dai).balanceOf(address(this))); 281 | Balancer(balancer).swapExactAmountIn(dai, IERC20(dai).balanceOf(address(this)), yfii, 0, uint(-1)); 282 | 283 | // fee 284 | uint b = IERC20(yfii).balanceOf(address(this)); 285 | uint _fee = b.mul(fee).div(max); 286 | IERC20(yfii).safeTransfer(Controller(controller).rewards(), _fee); 287 | 288 | //把yfii 存进去分红. 289 | IERC20(yfii).safeApprove(_vault, 0); 290 | IERC20(yfii).safeApprove(_vault, IERC20(yfii).balanceOf(address(this))); 291 | Yvault(_vault).make_profit(IERC20(yfii).balanceOf(address(this))); 292 | } 293 | 294 | function _withdrawSome(uint256 _amount) internal returns (uint) { 295 | Yam(pool).withdraw(_amount); 296 | return _amount; 297 | } 298 | 299 | function balanceOfWant() public view returns (uint) { 300 | return IERC20(want).balanceOf(address(this)); 301 | } 302 | 303 | function balanceOfYam() public view returns (uint) { 304 | return Yam(pool).balanceOf(address(this)); 305 | } 306 | 307 | function balanceOf() public view returns (uint) { 308 | return balanceOfWant(); 309 | 310 | } 311 | 312 | function setGovernance(address _governance) external { 313 | require(msg.sender == governance, "!governance"); 314 | governance = _governance; 315 | } 316 | 317 | function setController(address _controller) external { 318 | require(msg.sender == governance, "!governance"); 319 | controller = _controller; 320 | } 321 | } --------------------------------------------------------------------------------