├── Audit ├── Blockchain Consilium │ └── DYPVAULT-AUDIT-REPORT.pdf ├── Certik │ └── CertiK Audit Report for DYP Finance.pdf └── Peckshield │ └── PeckShield-Audit-Report-DYPEarnVault-v1.0.pdf ├── DISCLAIMER.txt ├── README.md ├── LICENSE ├── LICENSE.txt ├── vault.sol └── vault-weth.sol /Audit/Blockchain Consilium/DYPVAULT-AUDIT-REPORT.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dypfinance/dyp-earn-vault/HEAD/Audit/Blockchain Consilium/DYPVAULT-AUDIT-REPORT.pdf -------------------------------------------------------------------------------- /Audit/Certik/CertiK Audit Report for DYP Finance.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dypfinance/dyp-earn-vault/HEAD/Audit/Certik/CertiK Audit Report for DYP Finance.pdf -------------------------------------------------------------------------------- /Audit/Peckshield/PeckShield-Audit-Report-DYPEarnVault-v1.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dypfinance/dyp-earn-vault/HEAD/Audit/Peckshield/PeckShield-Audit-Report-DYPEarnVault-v1.0.pdf -------------------------------------------------------------------------------- /DISCLAIMER.txt: -------------------------------------------------------------------------------- 1 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 4 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 5 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 6 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 7 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 8 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 9 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 10 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DYP Earn Vault 2 | 3 | 1. Support for the following deposit tokens: ETH, WBTC, USDC, USDT, DAI 4 | 5 | 2. https://compound.finance/developers Compound Integration - users deposited funds are forwarded to compound for respective cTokens held by smart contract. 6 | 7 | 3. Users may withdraw their cTokens back to their deposit + interest from compound assuming appropriate liquidity conditions. The setup assumes compound and uniswap has the appropriate amount of liquidity available for the whole setup to work properly. 8 | 9 | 4. 0.3% withdrawal fee in respective token, 25% used to buy back DYP from uniswap and 75% distributed pro-rata among active vault users. 10 | 11 | 5. ETH fee equivalent to 400k gas at current gwei gas price for deposits and withdraw, 25% used to buy back DYP from uniswap and 75% distributed pro-rata among active vault users. 12 | 13 | 6. 5 different lockup durations / pools for each deposit token: 3, 30, 60, 90 and 120 days 14 | 15 | 7. Fixed APY for each pool, in DYP according to uniswap price of DYP from WETH pool. - admin needs to supply the required amount of DYP to the contract, if the contract runs out of DYP, users cannot withdraw their pending DYP rewards. 16 | 17 | 8. Uniswap Integration to periodically auto-buy DYP using above 25% fees and send to burn address. 18 | 19 | 9. Additional Claim button for compound rewards. 20 | 21 | 10. Re-Invest for DYP rewards with constant staking integration. 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, DeFi Yield Protocol 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, BC & Contributors 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /vault.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | 3 | pragma solidity 0.6.11; 4 | 5 | /** 6 | * @dev Wrappers over Solidity's arithmetic operations with added overflow 7 | * checks. 8 | * 9 | * Arithmetic operations in Solidity wrap on overflow. This can easily result 10 | * in bugs, because programmers usually assume that an overflow raises an 11 | * error, which is the standard behavior in high level programming languages. 12 | * `SafeMath` restores this intuition by reverting the transaction when an 13 | * operation overflows. 14 | * 15 | * Using this library instead of the unchecked operations eliminates an entire 16 | * class of bugs, so it's recommended to use it always. 17 | */ 18 | library SafeMath { 19 | /** 20 | * @dev Returns the addition of two unsigned integers, reverting on 21 | * overflow. 22 | * 23 | * Counterpart to Solidity's `+` operator. 24 | * 25 | * Requirements: 26 | * 27 | * - Addition cannot overflow. 28 | */ 29 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 30 | uint256 c = a + b; 31 | require(c >= a, "SafeMath: addition overflow"); 32 | 33 | return c; 34 | } 35 | 36 | /** 37 | * @dev Returns the subtraction of two unsigned integers, reverting on 38 | * overflow (when the result is negative). 39 | * 40 | * Counterpart to Solidity's `-` operator. 41 | * 42 | * Requirements: 43 | * 44 | * - Subtraction cannot overflow. 45 | */ 46 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 47 | return sub(a, b, "SafeMath: subtraction overflow"); 48 | } 49 | 50 | /** 51 | * @dev Returns the subtraction of two unsigned integers, reverting with custom message on 52 | * overflow (when the result is negative). 53 | * 54 | * Counterpart to Solidity's `-` operator. 55 | * 56 | * Requirements: 57 | * 58 | * - Subtraction cannot overflow. 59 | */ 60 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 61 | require(b <= a, errorMessage); 62 | uint256 c = a - b; 63 | 64 | return c; 65 | } 66 | 67 | /** 68 | * @dev Returns the multiplication of two unsigned integers, reverting on 69 | * overflow. 70 | * 71 | * Counterpart to Solidity's `*` operator. 72 | * 73 | * Requirements: 74 | * 75 | * - Multiplication cannot overflow. 76 | */ 77 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 78 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 79 | // benefit is lost if 'b' is also tested. 80 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 81 | if (a == 0) { 82 | return 0; 83 | } 84 | 85 | uint256 c = a * b; 86 | require(c / a == b, "SafeMath: multiplication overflow"); 87 | 88 | return c; 89 | } 90 | 91 | /** 92 | * @dev Returns the integer division of two unsigned integers. Reverts on 93 | * division by zero. The result is rounded towards zero. 94 | * 95 | * Counterpart to Solidity's `/` operator. Note: this function uses a 96 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 97 | * uses an invalid opcode to revert (consuming all remaining gas). 98 | * 99 | * Requirements: 100 | * 101 | * - The divisor cannot be zero. 102 | */ 103 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 104 | return div(a, b, "SafeMath: division by zero"); 105 | } 106 | 107 | /** 108 | * @dev Returns the integer division of two unsigned integers. Reverts with custom message on 109 | * division by zero. The result is rounded towards zero. 110 | * 111 | * Counterpart to Solidity's `/` operator. Note: this function uses a 112 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 113 | * uses an invalid opcode to revert (consuming all remaining gas). 114 | * 115 | * Requirements: 116 | * 117 | * - The divisor cannot be zero. 118 | */ 119 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 120 | require(b > 0, errorMessage); 121 | uint256 c = a / b; 122 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 123 | 124 | return c; 125 | } 126 | 127 | /** 128 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 129 | * Reverts when dividing by zero. 130 | * 131 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 132 | * opcode (which leaves remaining gas untouched) while Solidity uses an 133 | * invalid opcode to revert (consuming all remaining gas). 134 | * 135 | * Requirements: 136 | * 137 | * - The divisor cannot be zero. 138 | */ 139 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 140 | return mod(a, b, "SafeMath: modulo by zero"); 141 | } 142 | 143 | /** 144 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 145 | * Reverts with custom message when dividing by zero. 146 | * 147 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 148 | * opcode (which leaves remaining gas untouched) while Solidity uses an 149 | * invalid opcode to revert (consuming all remaining gas). 150 | * 151 | * Requirements: 152 | * 153 | * - The divisor cannot be zero. 154 | */ 155 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 156 | require(b != 0, errorMessage); 157 | return a % b; 158 | } 159 | } 160 | 161 | /** 162 | * @dev Collection of functions related to the address type 163 | */ 164 | library Address { 165 | /** 166 | * @dev Returns true if `account` is a contract. 167 | * 168 | * [IMPORTANT] 169 | * ==== 170 | * It is unsafe to assume that an address for which this function returns 171 | * false is an externally-owned account (EOA) and not a contract. 172 | * 173 | * Among others, `isContract` will return false for the following 174 | * types of addresses: 175 | * 176 | * - an externally-owned account 177 | * - a contract in construction 178 | * - an address where a contract will be created 179 | * - an address where a contract lived, but was destroyed 180 | * ==== 181 | */ 182 | function isContract(address account) internal view returns (bool) { 183 | // This method relies in extcodesize, which returns 0 for contracts in 184 | // construction, since the code is only stored at the end of the 185 | // constructor execution. 186 | 187 | uint256 size; 188 | // solhint-disable-next-line no-inline-assembly 189 | assembly { size := extcodesize(account) } 190 | return size > 0; 191 | } 192 | 193 | /** 194 | * @dev Replacement for Solidity's `transfer`: sends `amount` wei to 195 | * `recipient`, forwarding all available gas and reverting on errors. 196 | * 197 | * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost 198 | * of certain opcodes, possibly making contracts go over the 2300 gas limit 199 | * imposed by `transfer`, making them unable to receive funds via 200 | * `transfer`. {sendValue} removes this limitation. 201 | * 202 | * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. 203 | * 204 | * IMPORTANT: because control is transferred to `recipient`, care must be 205 | * taken to not create reentrancy vulnerabilities. Consider using 206 | * {ReentrancyGuard} or the 207 | * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. 208 | */ 209 | function sendValue(address payable recipient, uint256 amount) internal { 210 | require(address(this).balance >= amount, "Address: insufficient balance"); 211 | 212 | // solhint-disable-next-line avoid-low-level-calls, avoid-call-value 213 | (bool success, ) = recipient.call{ value: amount }(""); 214 | require(success, "Address: unable to send value, recipient may have reverted"); 215 | } 216 | 217 | /** 218 | * @dev Performs a Solidity function call using a low level `call`. A 219 | * plain`call` is an unsafe replacement for a function call: use this 220 | * function instead. 221 | * 222 | * If `target` reverts with a revert reason, it is bubbled up by this 223 | * function (like regular Solidity function calls). 224 | * 225 | * Returns the raw returned data. To convert to the expected return value, 226 | * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. 227 | * 228 | * Requirements: 229 | * 230 | * - `target` must be a contract. 231 | * - calling `target` with `data` must not revert. 232 | * 233 | * _Available since v3.1._ 234 | */ 235 | function functionCall(address target, bytes memory data) internal returns (bytes memory) { 236 | return functionCall(target, data, "Address: low-level call failed"); 237 | } 238 | 239 | /** 240 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with 241 | * `errorMessage` as a fallback revert reason when `target` reverts. 242 | * 243 | * _Available since v3.1._ 244 | */ 245 | function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { 246 | return _functionCallWithValue(target, data, 0, errorMessage); 247 | } 248 | 249 | /** 250 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 251 | * but also transferring `value` wei to `target`. 252 | * 253 | * Requirements: 254 | * 255 | * - the calling contract must have an ETH balance of at least `value`. 256 | * - the called Solidity function must be `payable`. 257 | * 258 | * _Available since v3.1._ 259 | */ 260 | function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { 261 | return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); 262 | } 263 | 264 | /** 265 | * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but 266 | * with `errorMessage` as a fallback revert reason when `target` reverts. 267 | * 268 | * _Available since v3.1._ 269 | */ 270 | function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { 271 | require(address(this).balance >= value, "Address: insufficient balance for call"); 272 | return _functionCallWithValue(target, data, value, errorMessage); 273 | } 274 | 275 | function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { 276 | require(isContract(target), "Address: call to non-contract"); 277 | 278 | // solhint-disable-next-line avoid-low-level-calls 279 | (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); 280 | if (success) { 281 | return returndata; 282 | } else { 283 | // Look for revert reason and bubble it up if present 284 | if (returndata.length > 0) { 285 | // The easiest way to bubble the revert reason is using memory via assembly 286 | 287 | // solhint-disable-next-line no-inline-assembly 288 | assembly { 289 | let returndata_size := mload(returndata) 290 | revert(add(32, returndata), returndata_size) 291 | } 292 | } else { 293 | revert(errorMessage); 294 | } 295 | } 296 | } 297 | } 298 | 299 | /** 300 | * @dev Library for managing 301 | * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive 302 | * types. 303 | * 304 | * Sets have the following properties: 305 | * 306 | * - Elements are added, removed, and checked for existence in constant time 307 | * (O(1)). 308 | * - Elements are enumerated in O(n). No guarantees are made on the ordering. 309 | * 310 | * ``` 311 | * contract Example { 312 | * // Add the library methods 313 | * using EnumerableSet for EnumerableSet.AddressSet; 314 | * 315 | * // Declare a set state variable 316 | * EnumerableSet.AddressSet private mySet; 317 | * } 318 | * ``` 319 | * 320 | * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256` 321 | * (`UintSet`) are supported. 322 | */ 323 | library EnumerableSet { 324 | // To implement this library for multiple types with as little code 325 | // repetition as possible, we write it in terms of a generic Set type with 326 | // bytes32 values. 327 | // The Set implementation uses private functions, and user-facing 328 | // implementations (such as AddressSet) are just wrappers around the 329 | // underlying Set. 330 | // This means that we can only create new EnumerableSets for types that fit 331 | // in bytes32. 332 | 333 | struct Set { 334 | // Storage of set values 335 | bytes32[] _values; 336 | 337 | // Position of the value in the `values` array, plus 1 because index 0 338 | // means a value is not in the set. 339 | mapping (bytes32 => uint256) _indexes; 340 | } 341 | 342 | /** 343 | * @dev Add a value to a set. O(1). 344 | * 345 | * Returns true if the value was added to the set, that is if it was not 346 | * already present. 347 | */ 348 | function _add(Set storage set, bytes32 value) private returns (bool) { 349 | if (!_contains(set, value)) { 350 | set._values.push(value); 351 | // The value is stored at length-1, but we add 1 to all indexes 352 | // and use 0 as a sentinel value 353 | set._indexes[value] = set._values.length; 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | /** 361 | * @dev Removes a value from a set. O(1). 362 | * 363 | * Returns true if the value was removed from the set, that is if it was 364 | * present. 365 | */ 366 | function _remove(Set storage set, bytes32 value) private returns (bool) { 367 | // We read and store the value's index to prevent multiple reads from the same storage slot 368 | uint256 valueIndex = set._indexes[value]; 369 | 370 | if (valueIndex != 0) { // Equivalent to contains(set, value) 371 | // To delete an element from the _values array in O(1), we swap the element to delete with the last one in 372 | // the array, and then remove the last element (sometimes called as 'swap and pop'). 373 | // This modifies the order of the array, as noted in {at}. 374 | 375 | uint256 toDeleteIndex = valueIndex - 1; 376 | uint256 lastIndex = set._values.length - 1; 377 | 378 | // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs 379 | // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. 380 | 381 | bytes32 lastvalue = set._values[lastIndex]; 382 | 383 | // Move the last value to the index where the value to delete is 384 | set._values[toDeleteIndex] = lastvalue; 385 | // Update the index for the moved value 386 | set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based 387 | 388 | // Delete the slot where the moved value was stored 389 | set._values.pop(); 390 | 391 | // Delete the index for the deleted slot 392 | delete set._indexes[value]; 393 | 394 | return true; 395 | } else { 396 | return false; 397 | } 398 | } 399 | 400 | /** 401 | * @dev Returns true if the value is in the set. O(1). 402 | */ 403 | function _contains(Set storage set, bytes32 value) private view returns (bool) { 404 | return set._indexes[value] != 0; 405 | } 406 | 407 | /** 408 | * @dev Returns the number of values on the set. O(1). 409 | */ 410 | function _length(Set storage set) private view returns (uint256) { 411 | return set._values.length; 412 | } 413 | 414 | /** 415 | * @dev Returns the value stored at position `index` in the set. O(1). 416 | * 417 | * Note that there are no guarantees on the ordering of values inside the 418 | * array, and it may change when more values are added or removed. 419 | * 420 | * Requirements: 421 | * 422 | * - `index` must be strictly less than {length}. 423 | */ 424 | function _at(Set storage set, uint256 index) private view returns (bytes32) { 425 | require(set._values.length > index, "EnumerableSet: index out of bounds"); 426 | return set._values[index]; 427 | } 428 | 429 | // AddressSet 430 | 431 | struct AddressSet { 432 | Set _inner; 433 | } 434 | 435 | /** 436 | * @dev Add a value to a set. O(1). 437 | * 438 | * Returns true if the value was added to the set, that is if it was not 439 | * already present. 440 | */ 441 | function add(AddressSet storage set, address value) internal returns (bool) { 442 | return _add(set._inner, bytes32(uint256(value))); 443 | } 444 | 445 | /** 446 | * @dev Removes a value from a set. O(1). 447 | * 448 | * Returns true if the value was removed from the set, that is if it was 449 | * present. 450 | */ 451 | function remove(AddressSet storage set, address value) internal returns (bool) { 452 | return _remove(set._inner, bytes32(uint256(value))); 453 | } 454 | 455 | /** 456 | * @dev Returns true if the value is in the set. O(1). 457 | */ 458 | function contains(AddressSet storage set, address value) internal view returns (bool) { 459 | return _contains(set._inner, bytes32(uint256(value))); 460 | } 461 | 462 | /** 463 | * @dev Returns the number of values in the set. O(1). 464 | */ 465 | function length(AddressSet storage set) internal view returns (uint256) { 466 | return _length(set._inner); 467 | } 468 | 469 | /** 470 | * @dev Returns the value stored at position `index` in the set. O(1). 471 | * 472 | * Note that there are no guarantees on the ordering of values inside the 473 | * array, and it may change when more values are added or removed. 474 | * 475 | * Requirements: 476 | * 477 | * - `index` must be strictly less than {length}. 478 | */ 479 | function at(AddressSet storage set, uint256 index) internal view returns (address) { 480 | return address(uint256(_at(set._inner, index))); 481 | } 482 | 483 | 484 | // UintSet 485 | 486 | struct UintSet { 487 | Set _inner; 488 | } 489 | 490 | /** 491 | * @dev Add a value to a set. O(1). 492 | * 493 | * Returns true if the value was added to the set, that is if it was not 494 | * already present. 495 | */ 496 | function add(UintSet storage set, uint256 value) internal returns (bool) { 497 | return _add(set._inner, bytes32(value)); 498 | } 499 | 500 | /** 501 | * @dev Removes a value from a set. O(1). 502 | * 503 | * Returns true if the value was removed from the set, that is if it was 504 | * present. 505 | */ 506 | function remove(UintSet storage set, uint256 value) internal returns (bool) { 507 | return _remove(set._inner, bytes32(value)); 508 | } 509 | 510 | /** 511 | * @dev Returns true if the value is in the set. O(1). 512 | */ 513 | function contains(UintSet storage set, uint256 value) internal view returns (bool) { 514 | return _contains(set._inner, bytes32(value)); 515 | } 516 | 517 | /** 518 | * @dev Returns the number of values on the set. O(1). 519 | */ 520 | function length(UintSet storage set) internal view returns (uint256) { 521 | return _length(set._inner); 522 | } 523 | 524 | /** 525 | * @dev Returns the value stored at position `index` in the set. O(1). 526 | * 527 | * Note that there are no guarantees on the ordering of values inside the 528 | * array, and it may change when more values are added or removed. 529 | * 530 | * Requirements: 531 | * 532 | * - `index` must be strictly less than {length}. 533 | */ 534 | function at(UintSet storage set, uint256 index) internal view returns (uint256) { 535 | return uint256(_at(set._inner, index)); 536 | } 537 | } 538 | 539 | /** 540 | * @title SafeERC20 541 | * @dev Wrappers around ERC20 operations that throw on failure (when the token 542 | * contract returns false). Tokens that return no value (and instead revert or 543 | * throw on failure) are also supported, non-reverting calls are assumed to be 544 | * successful. 545 | * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, 546 | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. 547 | */ 548 | library SafeERC20 { 549 | using SafeMath for uint256; 550 | using Address for address; 551 | 552 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 553 | _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 554 | } 555 | 556 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 557 | _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 558 | } 559 | 560 | /** 561 | * @dev Deprecated. This function has issues similar to the ones found in 562 | * {IERC20-approve}, and its usage is discouraged. 563 | * 564 | * Whenever possible, use {safeIncreaseAllowance} and 565 | * {safeDecreaseAllowance} instead. 566 | */ 567 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 568 | // safeApprove should only be called when setting an initial allowance, 569 | // or when resetting it to zero. To increase and decrease it, use 570 | // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' 571 | // solhint-disable-next-line max-line-length 572 | require((value == 0) || (token.allowance(address(this), spender) == 0), 573 | "SafeERC20: approve from non-zero to non-zero allowance" 574 | ); 575 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 576 | } 577 | 578 | function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { 579 | uint256 newAllowance = token.allowance(address(this), spender).add(value); 580 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 581 | } 582 | 583 | function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { 584 | uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); 585 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 586 | } 587 | 588 | /** 589 | * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement 590 | * on the return value: the return value is optional (but if data is returned, it must not be false). 591 | * @param token The token targeted by the call. 592 | * @param data The call data (encoded using abi.encode or one of its variants). 593 | */ 594 | function _callOptionalReturn(IERC20 token, bytes memory data) private { 595 | // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since 596 | // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that 597 | // the target address contains contract code and also asserts for success in the low-level call. 598 | 599 | bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); 600 | if (returndata.length > 0) { // Return data is optional 601 | // solhint-disable-next-line max-line-length 602 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 603 | } 604 | } 605 | } 606 | 607 | /** 608 | * @dev Interface of the ERC20 standard as defined in the EIP. 609 | */ 610 | interface IERC20 { 611 | /** 612 | * @dev Returns the amount of tokens in existence. 613 | */ 614 | function totalSupply() external view returns (uint256); 615 | 616 | /** 617 | * @dev Returns the amount of tokens owned by `account`. 618 | */ 619 | function balanceOf(address account) external view returns (uint256); 620 | 621 | /** 622 | * @dev Moves `amount` tokens from the caller's account to `recipient`. 623 | * 624 | * Returns a boolean value indicating whether the operation succeeded. 625 | * 626 | * Emits a {Transfer} event. 627 | */ 628 | function transfer(address recipient, uint256 amount) external returns (bool); 629 | 630 | /** 631 | * @dev Returns the remaining number of tokens that `spender` will be 632 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 633 | * zero by default. 634 | * 635 | * This value changes when {approve} or {transferFrom} are called. 636 | */ 637 | function allowance(address owner, address spender) external view returns (uint256); 638 | 639 | /** 640 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 641 | * 642 | * Returns a boolean value indicating whether the operation succeeded. 643 | * 644 | * IMPORTANT: Beware that changing an allowance with this method brings the risk 645 | * that someone may use both the old and the new allowance by unfortunate 646 | * transaction ordering. One possible solution to mitigate this race 647 | * condition is to first reduce the spender's allowance to 0 and set the 648 | * desired value afterwards: 649 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 650 | * 651 | * Emits an {Approval} event. 652 | */ 653 | function approve(address spender, uint256 amount) external returns (bool); 654 | 655 | /** 656 | * @dev Moves `amount` tokens from `sender` to `recipient` using the 657 | * allowance mechanism. `amount` is then deducted from the caller's 658 | * allowance. 659 | * 660 | * Returns a boolean value indicating whether the operation succeeded. 661 | * 662 | * Emits a {Transfer} event. 663 | */ 664 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 665 | 666 | /** 667 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 668 | * another (`to`). 669 | * 670 | * Note that `value` may be zero. 671 | */ 672 | event Transfer(address indexed from, address indexed to, uint256 value); 673 | 674 | /** 675 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 676 | * a call to {approve}. `value` is the new allowance. 677 | */ 678 | event Approval(address indexed owner, address indexed spender, uint256 value); 679 | } 680 | 681 | /** 682 | * @dev Contract module that helps prevent reentrant calls to a function. 683 | * 684 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier 685 | * available, which can be applied to functions to make sure there are no nested 686 | * (reentrant) calls to them. 687 | * 688 | * Note that because there is a single `nonReentrant` guard, functions marked as 689 | * `nonReentrant` may not call one another. This can be worked around by making 690 | * those functions `private`, and then adding `external` `nonReentrant` entry 691 | * points to them. 692 | * 693 | * TIP: If you would like to learn more about reentrancy and alternative ways 694 | * to protect against it, check out our blog post 695 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. 696 | */ 697 | contract ReentrancyGuard { 698 | // Booleans are more expensive than uint256 or any type that takes up a full 699 | // word because each write operation emits an extra SLOAD to first read the 700 | // slot's contents, replace the bits taken up by the boolean, and then write 701 | // back. This is the compiler's defense against contract upgrades and 702 | // pointer aliasing, and it cannot be disabled. 703 | 704 | // The values being non-zero value makes deployment a bit more expensive, 705 | // but in exchange the refund on every call to nonReentrant will be lower in 706 | // amount. Since refunds are capped to a percentage of the total 707 | // transaction's gas, it is best to keep them low in cases like this one, to 708 | // increase the likelihood of the full refund coming into effect. 709 | uint256 private constant _NOT_ENTERED = 1; 710 | uint256 private constant _ENTERED = 2; 711 | 712 | uint256 private _status; 713 | 714 | constructor () internal { 715 | _status = _NOT_ENTERED; 716 | } 717 | 718 | /** 719 | * @dev Prevents a contract from calling itself, directly or indirectly. 720 | * Calling a `nonReentrant` function from another `nonReentrant` 721 | * function is not supported. It is possible to prevent this from happening 722 | * by making the `nonReentrant` function external, and make it call a 723 | * `private` function that does the actual work. 724 | */ 725 | modifier nonReentrant() { 726 | // On the first call to nonReentrant, _notEntered will be true 727 | require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); 728 | 729 | // Any calls to nonReentrant after this point will fail 730 | _status = _ENTERED; 731 | 732 | _; 733 | 734 | // By storing the original value once again, a refund is triggered (see 735 | // https://eips.ethereum.org/EIPS/eip-2200) 736 | _status = _NOT_ENTERED; 737 | } 738 | } 739 | 740 | /** 741 | * @dev Contract module which provides a basic access control mechanism, where 742 | * there is an account (an owner) that can be granted exclusive access to 743 | * specific functions. 744 | * 745 | * By default, the owner account will be the one that deploys the contract. This 746 | * can later be changed with {transferOwnership}. 747 | * 748 | * This module is used through inheritance. It will make available the modifier 749 | * `onlyOwner`, which can be applied to your functions to restrict their use to 750 | * the owner. 751 | */ 752 | contract Ownable { 753 | address private _owner; 754 | 755 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 756 | 757 | /** 758 | * @dev Initializes the contract setting the deployer as the initial owner. 759 | */ 760 | constructor () internal { 761 | address msgSender = msg.sender; 762 | _owner = msgSender; 763 | emit OwnershipTransferred(address(0), msgSender); 764 | } 765 | 766 | /** 767 | * @dev Returns the address of the current owner. 768 | */ 769 | function owner() public view returns (address) { 770 | return _owner; 771 | } 772 | 773 | /** 774 | * @dev Throws if called by any account other than the owner. 775 | */ 776 | modifier onlyOwner() { 777 | require(_owner == msg.sender, "Ownable: caller is not the owner"); 778 | _; 779 | } 780 | 781 | /** 782 | * @dev Leaves the contract without owner. It will not be possible to call 783 | * `onlyOwner` functions anymore. Can only be called by the current owner. 784 | * 785 | * NOTE: Renouncing ownership will leave the contract without an owner, 786 | * thereby removing any functionality that is only available to the owner. 787 | */ 788 | function renounceOwnership() public virtual onlyOwner { 789 | emit OwnershipTransferred(_owner, address(0)); 790 | _owner = address(0); 791 | } 792 | 793 | /** 794 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 795 | * Can only be called by the current owner. 796 | */ 797 | function transferOwnership(address newOwner) public virtual onlyOwner { 798 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 799 | emit OwnershipTransferred(_owner, newOwner); 800 | _owner = newOwner; 801 | } 802 | } 803 | 804 | interface CErc20 { 805 | function mint(uint256) external returns (uint256); 806 | 807 | function exchangeRateCurrent() external returns (uint256); 808 | function exchangeRateStored() external view returns (uint256); 809 | 810 | function supplyRatePerBlock() external returns (uint256); 811 | 812 | function redeem(uint) external returns (uint); 813 | 814 | function redeemUnderlying(uint) external returns (uint); 815 | 816 | } 817 | 818 | interface IUniswapV2Router { 819 | function WETH() external pure returns (address); 820 | 821 | function swapExactTokensForTokens( 822 | uint amountIn, 823 | uint amountOutMin, 824 | address[] calldata path, 825 | address to, 826 | uint deadline 827 | ) external returns (uint[] memory amounts); 828 | 829 | function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) 830 | external 831 | payable 832 | returns (uint[] memory amounts); 833 | 834 | function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); 835 | } 836 | 837 | /** 838 | * Accounting: 839 | * - the smart contract maintains a ledger of token balances which changes upon actions affecting 840 | * this smart contract's token balance. 841 | * 842 | * - it allows owner to withdraw any extra amount of any tokens that have not been recorded, 843 | * i.e, - any tokens that are accidentally transferred to this smart contract. 844 | * 845 | * - care must be taken in auditing that `claimExtraTokens` function does not allow withdrawals of 846 | * any tokens in this smart contract in more amounts than necessary. In simple terms, admin can 847 | * only transfer out tokens that are accidentally sent to this smart contract. Nothing more nothing less. 848 | */ 849 | contract Vault is Ownable, ReentrancyGuard { 850 | using SafeMath for uint; 851 | using Address for address; 852 | using EnumerableSet for EnumerableSet.AddressSet; 853 | using SafeERC20 for IERC20; 854 | 855 | //==================== Contract Variables ======================= 856 | // Contract variables must be changed before live deployment 857 | 858 | uint public constant LOCKUP_DURATION = 5 minutes; 859 | uint public constant FEE_PERCENT_X_100 = 30; 860 | uint public constant FEE_PERCENT_TO_BUYBACK_X_100 = 2500; 861 | 862 | uint public constant REWARD_INTERVAL = 365 days; 863 | uint public constant ADMIN_CAN_CLAIM_AFTER = 395 days; 864 | uint public constant REWARD_RETURN_PERCENT_X_100 = 200; 865 | 866 | // ETH fee equivalent predefined gas price 867 | uint public constant MIN_ETH_FEE_IN_WEI = 400000 * 1 * 10**9; 868 | 869 | address public constant TRUSTED_DEPOSIT_TOKEN_ADDRESS = 0x07de306FF27a2B630B1141956844eB1552B956B5; 870 | address public constant TRUSTED_CTOKEN_ADDRESS = 0x3f0A0EA2f86baE6362CF9799B523BA06647Da018; 871 | address public constant TRUSTED_PLATFORM_TOKEN_ADDRESS = 0xd8bB0ff7a267ab387015C18675591912D8035D9E; 872 | 873 | address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD; 874 | 875 | //================= End Contract Variables ====================== 876 | 877 | uint public constant ONE_HUNDRED_X_100 = 10000; 878 | uint public immutable contractStartTime; 879 | 880 | constructor() public { 881 | contractStartTime = block.timestamp; 882 | } 883 | 884 | IUniswapV2Router public constant uniswapRouterV2 = IUniswapV2Router(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); 885 | 886 | modifier noContractsAllowed() { 887 | require(tx.origin == msg.sender, "No Contracts Allowed!"); 888 | _; 889 | } 890 | 891 | // ------------------- event definitions ------------------- 892 | 893 | event Deposit(address indexed account, uint amount); 894 | event Withdraw(address indexed account, uint amount); 895 | 896 | event EtherRewardDisbursed(uint amount); 897 | event TokenRewardDisbursed(uint amount); 898 | 899 | event PlatformTokenRewardClaimed(address indexed account, uint amount); 900 | event CompoundRewardClaimed(address indexed account, uint amount); 901 | event EtherRewardClaimed(address indexed account, uint amount); 902 | event TokenRewardClaimed(address indexed account, uint amount); 903 | 904 | event PlatformTokenAdded(uint amount); 905 | 906 | // ----------------- end event definitions ----------------- 907 | 908 | EnumerableSet.AddressSet private holders; 909 | 910 | // view functon to get number of stakers 911 | function getNumberOfHolders() public view returns (uint) { 912 | return holders.length(); 913 | } 914 | 915 | // token contract address => token balance of this contract 916 | mapping (address => uint) public tokenBalances; 917 | 918 | // user wallet => balance 919 | mapping (address => uint) public cTokenBalance; 920 | mapping (address => uint) public depositTokenBalance; 921 | 922 | mapping (address => uint) public totalTokensDepositedByUser; 923 | mapping (address => uint) public totalTokensWithdrawnByUser; 924 | 925 | mapping (address => uint) public totalEarnedCompoundDivs; 926 | mapping (address => uint) public totalEarnedEthDivs; 927 | mapping (address => uint) public totalEarnedTokenDivs; 928 | mapping (address => uint) public totalEarnedPlatformTokenDivs; 929 | 930 | mapping (address => uint) public depositTime; 931 | mapping (address => uint) public lastClaimedTime; 932 | 933 | uint public totalCTokens; 934 | uint public totalDepositedTokens; 935 | 936 | // ----------------- 937 | 938 | uint public constant POINT_MULTIPLIER = 1e18; 939 | 940 | mapping (address => uint) public lastTokenDivPoints; 941 | mapping (address => uint) public tokenDivsBalance; 942 | uint public totalTokenDivPoints; 943 | 944 | mapping (address => uint) public lastEthDivPoints; 945 | mapping (address => uint) public ethDivsBalance; 946 | uint public totalEthDivPoints; 947 | 948 | mapping (address => uint) public platformTokenDivsBalance; 949 | 950 | uint public totalEthDisbursed; 951 | uint public totalTokensDisbursed; 952 | 953 | 954 | function tokenDivsOwing(address account) public view returns (uint) { 955 | uint newDivPoints = totalTokenDivPoints.sub(lastTokenDivPoints[account]); 956 | return depositTokenBalance[account].mul(newDivPoints).div(POINT_MULTIPLIER); 957 | } 958 | function ethDivsOwing(address account) public view returns (uint) { 959 | uint newDivPoints = totalEthDivPoints.sub(lastEthDivPoints[account]); 960 | return depositTokenBalance[account].mul(newDivPoints).div(POINT_MULTIPLIER); 961 | } 962 | 963 | function distributeEthDivs(uint amount) private { 964 | if (totalDepositedTokens == 0) return; 965 | totalEthDivPoints = totalEthDivPoints.add(amount.mul(POINT_MULTIPLIER).div(totalDepositedTokens)); 966 | totalEthDisbursed = totalEthDisbursed.add(amount); 967 | increaseTokenBalance(address(0), amount); 968 | emit EtherRewardDisbursed(amount); 969 | } 970 | function distributeTokenDivs(uint amount) private { 971 | if (totalDepositedTokens == 0) return; 972 | totalTokenDivPoints = totalTokenDivPoints.add(amount.mul(POINT_MULTIPLIER).div(totalDepositedTokens)); 973 | totalTokensDisbursed = totalTokensDisbursed.add(amount); 974 | increaseTokenBalance(TRUSTED_DEPOSIT_TOKEN_ADDRESS, amount); 975 | emit TokenRewardDisbursed(amount); 976 | } 977 | 978 | 979 | // ----------------- 980 | 981 | // view function to get depositors list 982 | function getDepositorsList(uint startIndex, uint endIndex) 983 | public 984 | view 985 | returns (address[] memory stakers, 986 | uint[] memory stakingTimestamps, 987 | uint[] memory lastClaimedTimeStamps, 988 | uint[] memory stakedTokens) { 989 | require (startIndex < endIndex); 990 | 991 | uint length = endIndex.sub(startIndex); 992 | address[] memory _stakers = new address[](length); 993 | uint[] memory _stakingTimestamps = new uint[](length); 994 | uint[] memory _lastClaimedTimeStamps = new uint[](length); 995 | uint[] memory _stakedTokens = new uint[](length); 996 | 997 | for (uint i = startIndex; i < endIndex; i = i.add(1)) { 998 | address staker = holders.at(i); 999 | uint listIndex = i.sub(startIndex); 1000 | _stakers[listIndex] = staker; 1001 | _stakingTimestamps[listIndex] = depositTime[staker]; 1002 | _lastClaimedTimeStamps[listIndex] = lastClaimedTime[staker]; 1003 | _stakedTokens[listIndex] = depositTokenBalance[staker]; 1004 | } 1005 | 1006 | return (_stakers, _stakingTimestamps, _lastClaimedTimeStamps, _stakedTokens); 1007 | } 1008 | 1009 | function updateAccount(address account) private { 1010 | // update user account here 1011 | uint tokensOwing = tokenDivsOwing(account); 1012 | lastTokenDivPoints[account] = totalTokenDivPoints; 1013 | if (tokensOwing > 0) { 1014 | tokenDivsBalance[account] = tokenDivsBalance[account].add(tokensOwing); 1015 | } 1016 | 1017 | uint weiOwing = ethDivsOwing(account); 1018 | lastEthDivPoints[account] = totalEthDivPoints; 1019 | if (weiOwing > 0) { 1020 | ethDivsBalance[account] = ethDivsBalance[account].add(weiOwing); 1021 | } 1022 | 1023 | uint platformTokensOwing = platformTokenDivsOwing(account); 1024 | if (platformTokensOwing > 0) { 1025 | platformTokenDivsBalance[account] = platformTokenDivsBalance[account].add(platformTokensOwing); 1026 | } 1027 | 1028 | lastClaimedTime[account] = block.timestamp; 1029 | } 1030 | 1031 | function platformTokenDivsOwing(address account) public view returns (uint) { 1032 | if (!holders.contains(account)) return 0; 1033 | if (depositTokenBalance[account] == 0) return 0; 1034 | 1035 | uint timeDiff; 1036 | uint stakingEndTime = contractStartTime.add(REWARD_INTERVAL); 1037 | uint _now = block.timestamp; 1038 | if (_now > stakingEndTime) { 1039 | _now = stakingEndTime; 1040 | } 1041 | 1042 | if (lastClaimedTime[account] >= _now) { 1043 | timeDiff = 0; 1044 | } else { 1045 | timeDiff = _now.sub(lastClaimedTime[account]); 1046 | } 1047 | 1048 | uint pendingDivs = depositTokenBalance[account] 1049 | .mul(REWARD_RETURN_PERCENT_X_100) 1050 | .mul(timeDiff) 1051 | .div(REWARD_INTERVAL) 1052 | .div(ONE_HUNDRED_X_100); 1053 | return pendingDivs; 1054 | } 1055 | 1056 | function getEstimatedCompoundDivsOwing(address account) public view returns (uint) { 1057 | uint convertedBalance = getConvertedBalance(cTokenBalance[account]); 1058 | uint depositedBalance = depositTokenBalance[account]; 1059 | return (convertedBalance > depositedBalance ? convertedBalance.sub(depositedBalance) : 0); 1060 | } 1061 | 1062 | function getConvertedBalance(uint _cTokenBalance) public view returns (uint) { 1063 | uint exchangeRateStored = getExchangeRateStored(); 1064 | uint convertedBalance = _cTokenBalance.mul(exchangeRateStored).div(10**18); 1065 | return convertedBalance; 1066 | } 1067 | 1068 | function _claimEthDivs() private { 1069 | updateAccount(msg.sender); 1070 | uint amount = ethDivsBalance[msg.sender]; 1071 | ethDivsBalance[msg.sender] = 0; 1072 | if (amount == 0) return; 1073 | decreaseTokenBalance(address(0), amount); 1074 | msg.sender.transfer(amount); 1075 | totalEarnedEthDivs[msg.sender] = totalEarnedEthDivs[msg.sender].add(amount); 1076 | 1077 | emit EtherRewardClaimed(msg.sender, amount); 1078 | } 1079 | function _claimTokenDivs() private { 1080 | updateAccount(msg.sender); 1081 | uint amount = tokenDivsBalance[msg.sender]; 1082 | tokenDivsBalance[msg.sender] = 0; 1083 | if (amount == 0) return; 1084 | decreaseTokenBalance(TRUSTED_DEPOSIT_TOKEN_ADDRESS, amount); 1085 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeTransfer(msg.sender, amount); 1086 | totalEarnedTokenDivs[msg.sender] = totalEarnedTokenDivs[msg.sender].add(amount); 1087 | 1088 | emit TokenRewardClaimed(msg.sender, amount); 1089 | } 1090 | function _claimCompoundDivs() private { 1091 | updateAccount(msg.sender); 1092 | uint exchangeRateCurrent = getExchangeRateCurrent(); 1093 | 1094 | uint convertedBalance = cTokenBalance[msg.sender].mul(exchangeRateCurrent).div(10**18); 1095 | uint depositedBalance = depositTokenBalance[msg.sender]; 1096 | 1097 | uint amount = convertedBalance > depositedBalance ? convertedBalance.sub(depositedBalance) : 0; 1098 | 1099 | if (amount == 0) return; 1100 | 1101 | uint oldCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1102 | uint oldDepositTokenBalance = IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).balanceOf(address(this)); 1103 | require(CErc20(TRUSTED_CTOKEN_ADDRESS).redeemUnderlying(amount) == 0, "redeemUnderlying failed!"); 1104 | uint newCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1105 | uint newDepositTokenBalance = IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).balanceOf(address(this)); 1106 | 1107 | uint depositTokenReceived = newDepositTokenBalance.sub(oldDepositTokenBalance); 1108 | uint cTokenRedeemed = oldCTokenBalance.sub(newCTokenBalance); 1109 | 1110 | require(cTokenRedeemed <= cTokenBalance[msg.sender], "redeem exceeds balance!"); 1111 | cTokenBalance[msg.sender] = cTokenBalance[msg.sender].sub(cTokenRedeemed); 1112 | totalCTokens = totalCTokens.sub(cTokenRedeemed); 1113 | decreaseTokenBalance(TRUSTED_CTOKEN_ADDRESS, cTokenRedeemed); 1114 | 1115 | totalTokensWithdrawnByUser[msg.sender] = totalTokensWithdrawnByUser[msg.sender].add(depositTokenReceived); 1116 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeTransfer(msg.sender, depositTokenReceived); 1117 | 1118 | totalEarnedCompoundDivs[msg.sender] = totalEarnedCompoundDivs[msg.sender].add(depositTokenReceived); 1119 | 1120 | emit CompoundRewardClaimed(msg.sender, depositTokenReceived); 1121 | } 1122 | function _claimPlatformTokenDivs(uint _amountOutMin_platformTokens) private { 1123 | updateAccount(msg.sender); 1124 | uint amount = platformTokenDivsBalance[msg.sender]; 1125 | 1126 | if (amount == 0) return; 1127 | 1128 | address[] memory path = new address[](3); 1129 | path[0] = TRUSTED_DEPOSIT_TOKEN_ADDRESS; 1130 | path[1] = uniswapRouterV2.WETH(); 1131 | path[2] = TRUSTED_PLATFORM_TOKEN_ADDRESS; 1132 | 1133 | uint estimatedAmountOut = uniswapRouterV2.getAmountsOut(amount, path)[2]; 1134 | require(estimatedAmountOut >= _amountOutMin_platformTokens, "_claimPlatformTokenDivs: slippage error!"); 1135 | 1136 | if (IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).balanceOf(address(this)) < estimatedAmountOut) { 1137 | return; 1138 | } 1139 | 1140 | platformTokenDivsBalance[msg.sender] = 0; 1141 | 1142 | 1143 | decreaseTokenBalance(TRUSTED_PLATFORM_TOKEN_ADDRESS, estimatedAmountOut); 1144 | IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).safeTransfer(msg.sender, estimatedAmountOut); 1145 | totalEarnedPlatformTokenDivs[msg.sender] = totalEarnedPlatformTokenDivs[msg.sender].add(estimatedAmountOut); 1146 | 1147 | emit PlatformTokenRewardClaimed(msg.sender, estimatedAmountOut); 1148 | } 1149 | 1150 | function claimEthDivs() external noContractsAllowed nonReentrant { 1151 | _claimEthDivs(); 1152 | } 1153 | function claimTokenDivs() external noContractsAllowed nonReentrant { 1154 | _claimTokenDivs(); 1155 | } 1156 | function claimCompoundDivs() external noContractsAllowed nonReentrant { 1157 | _claimCompoundDivs(); 1158 | } 1159 | function claimPlatformTokenDivs(uint _amountOutMin_platformTokens) external noContractsAllowed nonReentrant { 1160 | _claimPlatformTokenDivs(_amountOutMin_platformTokens); 1161 | } 1162 | 1163 | function claim(uint _amountOutMin_platformTokens) external noContractsAllowed nonReentrant { 1164 | _claimEthDivs(); 1165 | _claimTokenDivs(); 1166 | _claimCompoundDivs(); 1167 | _claimPlatformTokenDivs(_amountOutMin_platformTokens); 1168 | } 1169 | 1170 | function getExchangeRateCurrent() public returns (uint) { 1171 | uint exchangeRateCurrent = CErc20(TRUSTED_CTOKEN_ADDRESS).exchangeRateCurrent(); 1172 | return exchangeRateCurrent; 1173 | } 1174 | 1175 | function getExchangeRateStored() public view returns (uint) { 1176 | uint exchangeRateStored = CErc20(TRUSTED_CTOKEN_ADDRESS).exchangeRateStored(); 1177 | return exchangeRateStored; 1178 | } 1179 | 1180 | function deposit(uint amount, uint _amountOutMin_ethFeeBuyBack, uint deadline) external noContractsAllowed nonReentrant payable { 1181 | require(amount > 0, "invalid amount!"); 1182 | 1183 | updateAccount(msg.sender); 1184 | 1185 | // increment token balance! 1186 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeTransferFrom(msg.sender, address(this), amount); 1187 | 1188 | 1189 | totalTokensDepositedByUser[msg.sender] = totalTokensDepositedByUser[msg.sender].add(amount); 1190 | 1191 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeApprove(TRUSTED_CTOKEN_ADDRESS, 0); 1192 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeApprove(TRUSTED_CTOKEN_ADDRESS, amount); 1193 | 1194 | uint oldCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1195 | require(CErc20(TRUSTED_CTOKEN_ADDRESS).mint(amount) == 0, "mint failed!"); 1196 | uint newCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1197 | uint cTokenReceived = newCTokenBalance.sub(oldCTokenBalance); 1198 | 1199 | cTokenBalance[msg.sender] = cTokenBalance[msg.sender].add(cTokenReceived); 1200 | totalCTokens = totalCTokens.add(cTokenReceived); 1201 | increaseTokenBalance(TRUSTED_CTOKEN_ADDRESS, cTokenReceived); 1202 | 1203 | depositTokenBalance[msg.sender] = depositTokenBalance[msg.sender].add(amount); 1204 | totalDepositedTokens = totalDepositedTokens.add(amount); 1205 | 1206 | handleEthFee(msg.value, _amountOutMin_ethFeeBuyBack, deadline); 1207 | 1208 | holders.add(msg.sender); 1209 | depositTime[msg.sender] = block.timestamp; 1210 | 1211 | emit Deposit(msg.sender, amount); 1212 | } 1213 | function withdraw(uint amount, uint _amountOutMin_ethFeeBuyBack, uint _amountOutMin_tokenFeeBuyBack, uint deadline) external noContractsAllowed nonReentrant payable { 1214 | require(amount > 0, "invalid amount!"); 1215 | require(amount <= depositTokenBalance[msg.sender], "Cannot withdraw more than deposited!"); 1216 | require(block.timestamp.sub(depositTime[msg.sender]) > LOCKUP_DURATION, "You recently deposited, please wait before withdrawing."); 1217 | 1218 | updateAccount(msg.sender); 1219 | 1220 | depositTokenBalance[msg.sender] = depositTokenBalance[msg.sender].sub(amount); 1221 | totalDepositedTokens = totalDepositedTokens.sub(amount); 1222 | 1223 | uint oldCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1224 | uint oldDepositTokenBalance = IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).balanceOf(address(this)); 1225 | require(CErc20(TRUSTED_CTOKEN_ADDRESS).redeemUnderlying(amount) == 0, "redeemUnderlying failed!"); 1226 | uint newCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1227 | uint newDepositTokenBalance = IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).balanceOf(address(this)); 1228 | 1229 | uint depositTokenReceived = newDepositTokenBalance.sub(oldDepositTokenBalance); 1230 | uint cTokenRedeemed = oldCTokenBalance.sub(newCTokenBalance); 1231 | 1232 | require(cTokenRedeemed <= cTokenBalance[msg.sender], "redeem exceeds balance!"); 1233 | cTokenBalance[msg.sender] = cTokenBalance[msg.sender].sub(cTokenRedeemed); 1234 | totalCTokens = totalCTokens.sub(cTokenRedeemed); 1235 | decreaseTokenBalance(TRUSTED_CTOKEN_ADDRESS, cTokenRedeemed); 1236 | 1237 | totalTokensWithdrawnByUser[msg.sender] = totalTokensWithdrawnByUser[msg.sender].add(depositTokenReceived); 1238 | 1239 | uint feeAmount = depositTokenReceived.mul(FEE_PERCENT_X_100).div(ONE_HUNDRED_X_100); 1240 | uint depositTokenReceivedAfterFee = depositTokenReceived.sub(feeAmount); 1241 | 1242 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeTransfer(msg.sender, depositTokenReceivedAfterFee); 1243 | 1244 | handleFee(feeAmount, _amountOutMin_tokenFeeBuyBack, deadline); 1245 | handleEthFee(msg.value, _amountOutMin_ethFeeBuyBack, deadline); 1246 | 1247 | if (depositTokenBalance[msg.sender] == 0) { 1248 | holders.remove(msg.sender); 1249 | } 1250 | 1251 | emit Withdraw(msg.sender, depositTokenReceived); 1252 | } 1253 | 1254 | // emergency withdraw without interacting with uniswap 1255 | function emergencyWithdraw(uint amount) external noContractsAllowed nonReentrant payable { 1256 | require(amount > 0, "invalid amount!"); 1257 | require(amount <= depositTokenBalance[msg.sender], "Cannot withdraw more than deposited!"); 1258 | require(block.timestamp.sub(depositTime[msg.sender]) > LOCKUP_DURATION, "You recently deposited, please wait before withdrawing."); 1259 | 1260 | updateAccount(msg.sender); 1261 | 1262 | depositTokenBalance[msg.sender] = depositTokenBalance[msg.sender].sub(amount); 1263 | totalDepositedTokens = totalDepositedTokens.sub(amount); 1264 | 1265 | uint oldCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1266 | uint oldDepositTokenBalance = IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).balanceOf(address(this)); 1267 | require(CErc20(TRUSTED_CTOKEN_ADDRESS).redeemUnderlying(amount) == 0, "redeemUnderlying failed!"); 1268 | uint newCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1269 | uint newDepositTokenBalance = IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).balanceOf(address(this)); 1270 | 1271 | uint depositTokenReceived = newDepositTokenBalance.sub(oldDepositTokenBalance); 1272 | uint cTokenRedeemed = oldCTokenBalance.sub(newCTokenBalance); 1273 | 1274 | require(cTokenRedeemed <= cTokenBalance[msg.sender], "redeem exceeds balance!"); 1275 | cTokenBalance[msg.sender] = cTokenBalance[msg.sender].sub(cTokenRedeemed); 1276 | totalCTokens = totalCTokens.sub(cTokenRedeemed); 1277 | decreaseTokenBalance(TRUSTED_CTOKEN_ADDRESS, cTokenRedeemed); 1278 | 1279 | totalTokensWithdrawnByUser[msg.sender] = totalTokensWithdrawnByUser[msg.sender].add(depositTokenReceived); 1280 | 1281 | uint feeAmount = depositTokenReceived.mul(FEE_PERCENT_X_100).div(ONE_HUNDRED_X_100); 1282 | uint depositTokenReceivedAfterFee = depositTokenReceived.sub(feeAmount); 1283 | 1284 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeTransfer(msg.sender, depositTokenReceivedAfterFee); 1285 | 1286 | // no uniswap interaction 1287 | // handleFee(feeAmount, _amountOutMin_tokenFeeBuyBack, deadline); 1288 | // handleEthFee(msg.value, _amountOutMin_ethFeeBuyBack, deadline); 1289 | 1290 | if (depositTokenBalance[msg.sender] == 0) { 1291 | holders.remove(msg.sender); 1292 | } 1293 | 1294 | emit Withdraw(msg.sender, depositTokenReceived); 1295 | } 1296 | 1297 | function handleFee(uint feeAmount, uint _amountOutMin_tokenFeeBuyBack, uint deadline) private { 1298 | uint buyBackFeeAmount = feeAmount.mul(FEE_PERCENT_TO_BUYBACK_X_100).div(ONE_HUNDRED_X_100); 1299 | uint remainingFeeAmount = feeAmount.sub(buyBackFeeAmount); 1300 | 1301 | // handle distribution 1302 | distributeTokenDivs(remainingFeeAmount); 1303 | 1304 | 1305 | // handle buyback 1306 | // --- swap token to platform token here! ---- 1307 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeApprove(address(uniswapRouterV2), 0); 1308 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeApprove(address(uniswapRouterV2), buyBackFeeAmount); 1309 | 1310 | uint oldPlatformTokenBalance = IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).balanceOf(address(this)); 1311 | address[] memory path = new address[](3); 1312 | path[0] = TRUSTED_DEPOSIT_TOKEN_ADDRESS; 1313 | path[1] = uniswapRouterV2.WETH(); 1314 | path[2] = TRUSTED_PLATFORM_TOKEN_ADDRESS; 1315 | 1316 | uniswapRouterV2.swapExactTokensForTokens(buyBackFeeAmount, _amountOutMin_tokenFeeBuyBack, path, address(this), deadline); 1317 | uint newPlatformTokenBalance = IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).balanceOf(address(this)); 1318 | uint platformTokensReceived = newPlatformTokenBalance.sub(oldPlatformTokenBalance); 1319 | IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).safeTransfer(BURN_ADDRESS, platformTokensReceived); 1320 | // ---- end swap token to plaform tokens ----- 1321 | } 1322 | 1323 | function handleEthFee(uint feeAmount, uint _amountOutMin_ethFeeBuyBack, uint deadline) private { 1324 | require(feeAmount >= MIN_ETH_FEE_IN_WEI, "Insufficient ETH Fee!"); 1325 | uint buyBackFeeAmount = feeAmount.mul(FEE_PERCENT_TO_BUYBACK_X_100).div(ONE_HUNDRED_X_100); 1326 | uint remainingFeeAmount = feeAmount.sub(buyBackFeeAmount); 1327 | 1328 | // handle distribution 1329 | distributeEthDivs(remainingFeeAmount); 1330 | 1331 | 1332 | // handle buyback 1333 | 1334 | // --- swap eth to platform token here! ---- 1335 | uint oldPlatformTokenBalance = IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).balanceOf(address(this)); 1336 | address[] memory path = new address[](2); 1337 | path[0] = uniswapRouterV2.WETH(); 1338 | path[1] = TRUSTED_PLATFORM_TOKEN_ADDRESS; 1339 | 1340 | uniswapRouterV2.swapExactETHForTokens{value: buyBackFeeAmount}(_amountOutMin_ethFeeBuyBack, path, address(this), deadline); 1341 | uint newPlatformTokenBalance = IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).balanceOf(address(this)); 1342 | uint platformTokensReceived = newPlatformTokenBalance.sub(oldPlatformTokenBalance); 1343 | IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).safeTransfer(BURN_ADDRESS, platformTokensReceived); 1344 | // ---- end swap eth to plaform tokens ----- 1345 | } 1346 | 1347 | receive () external payable { 1348 | // receive eth do nothing 1349 | } 1350 | 1351 | function increaseTokenBalance(address token, uint amount) private { 1352 | tokenBalances[token] = tokenBalances[token].add(amount); 1353 | } 1354 | function decreaseTokenBalance(address token, uint amount) private { 1355 | tokenBalances[token] = tokenBalances[token].sub(amount); 1356 | } 1357 | 1358 | function addPlatformTokenBalance(uint amount) external nonReentrant onlyOwner { 1359 | increaseTokenBalance(TRUSTED_PLATFORM_TOKEN_ADDRESS, amount); 1360 | IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).safeTransferFrom(msg.sender, address(this), amount); 1361 | 1362 | emit PlatformTokenAdded(amount); 1363 | } 1364 | 1365 | function claimExtraTokens(address token) external nonReentrant onlyOwner { 1366 | if (token == address(0)) { 1367 | uint ethDiff = address(this).balance.sub(tokenBalances[token]); 1368 | msg.sender.transfer(ethDiff); 1369 | return; 1370 | } 1371 | uint diff = IERC20(token).balanceOf(address(this)).sub(tokenBalances[token]); 1372 | IERC20(token).safeTransfer(msg.sender, diff); 1373 | } 1374 | 1375 | function claimAnyToken(address token, uint amount) external onlyOwner { 1376 | require(now > contractStartTime.add(ADMIN_CAN_CLAIM_AFTER), "Contract not expired yet!"); 1377 | if (token == address(0)) { 1378 | msg.sender.transfer(amount); 1379 | return; 1380 | } 1381 | IERC20(token).safeTransfer(msg.sender, amount); 1382 | } 1383 | } 1384 | -------------------------------------------------------------------------------- /vault-weth.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | 3 | pragma solidity 0.6.11; 4 | 5 | /** 6 | * @dev Wrappers over Solidity's arithmetic operations with added overflow 7 | * checks. 8 | * 9 | * Arithmetic operations in Solidity wrap on overflow. This can easily result 10 | * in bugs, because programmers usually assume that an overflow raises an 11 | * error, which is the standard behavior in high level programming languages. 12 | * `SafeMath` restores this intuition by reverting the transaction when an 13 | * operation overflows. 14 | * 15 | * Using this library instead of the unchecked operations eliminates an entire 16 | * class of bugs, so it's recommended to use it always. 17 | */ 18 | library SafeMath { 19 | /** 20 | * @dev Returns the addition of two unsigned integers, reverting on 21 | * overflow. 22 | * 23 | * Counterpart to Solidity's `+` operator. 24 | * 25 | * Requirements: 26 | * 27 | * - Addition cannot overflow. 28 | */ 29 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 30 | uint256 c = a + b; 31 | require(c >= a, "SafeMath: addition overflow"); 32 | 33 | return c; 34 | } 35 | 36 | /** 37 | * @dev Returns the subtraction of two unsigned integers, reverting on 38 | * overflow (when the result is negative). 39 | * 40 | * Counterpart to Solidity's `-` operator. 41 | * 42 | * Requirements: 43 | * 44 | * - Subtraction cannot overflow. 45 | */ 46 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 47 | return sub(a, b, "SafeMath: subtraction overflow"); 48 | } 49 | 50 | /** 51 | * @dev Returns the subtraction of two unsigned integers, reverting with custom message on 52 | * overflow (when the result is negative). 53 | * 54 | * Counterpart to Solidity's `-` operator. 55 | * 56 | * Requirements: 57 | * 58 | * - Subtraction cannot overflow. 59 | */ 60 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 61 | require(b <= a, errorMessage); 62 | uint256 c = a - b; 63 | 64 | return c; 65 | } 66 | 67 | /** 68 | * @dev Returns the multiplication of two unsigned integers, reverting on 69 | * overflow. 70 | * 71 | * Counterpart to Solidity's `*` operator. 72 | * 73 | * Requirements: 74 | * 75 | * - Multiplication cannot overflow. 76 | */ 77 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 78 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 79 | // benefit is lost if 'b' is also tested. 80 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 81 | if (a == 0) { 82 | return 0; 83 | } 84 | 85 | uint256 c = a * b; 86 | require(c / a == b, "SafeMath: multiplication overflow"); 87 | 88 | return c; 89 | } 90 | 91 | /** 92 | * @dev Returns the integer division of two unsigned integers. Reverts on 93 | * division by zero. The result is rounded towards zero. 94 | * 95 | * Counterpart to Solidity's `/` operator. Note: this function uses a 96 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 97 | * uses an invalid opcode to revert (consuming all remaining gas). 98 | * 99 | * Requirements: 100 | * 101 | * - The divisor cannot be zero. 102 | */ 103 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 104 | return div(a, b, "SafeMath: division by zero"); 105 | } 106 | 107 | /** 108 | * @dev Returns the integer division of two unsigned integers. Reverts with custom message on 109 | * division by zero. The result is rounded towards zero. 110 | * 111 | * Counterpart to Solidity's `/` operator. Note: this function uses a 112 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 113 | * uses an invalid opcode to revert (consuming all remaining gas). 114 | * 115 | * Requirements: 116 | * 117 | * - The divisor cannot be zero. 118 | */ 119 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 120 | require(b > 0, errorMessage); 121 | uint256 c = a / b; 122 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 123 | 124 | return c; 125 | } 126 | 127 | /** 128 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 129 | * Reverts when dividing by zero. 130 | * 131 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 132 | * opcode (which leaves remaining gas untouched) while Solidity uses an 133 | * invalid opcode to revert (consuming all remaining gas). 134 | * 135 | * Requirements: 136 | * 137 | * - The divisor cannot be zero. 138 | */ 139 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 140 | return mod(a, b, "SafeMath: modulo by zero"); 141 | } 142 | 143 | /** 144 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 145 | * Reverts with custom message when dividing by zero. 146 | * 147 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 148 | * opcode (which leaves remaining gas untouched) while Solidity uses an 149 | * invalid opcode to revert (consuming all remaining gas). 150 | * 151 | * Requirements: 152 | * 153 | * - The divisor cannot be zero. 154 | */ 155 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 156 | require(b != 0, errorMessage); 157 | return a % b; 158 | } 159 | } 160 | 161 | /** 162 | * @dev Collection of functions related to the address type 163 | */ 164 | library Address { 165 | /** 166 | * @dev Returns true if `account` is a contract. 167 | * 168 | * [IMPORTANT] 169 | * ==== 170 | * It is unsafe to assume that an address for which this function returns 171 | * false is an externally-owned account (EOA) and not a contract. 172 | * 173 | * Among others, `isContract` will return false for the following 174 | * types of addresses: 175 | * 176 | * - an externally-owned account 177 | * - a contract in construction 178 | * - an address where a contract will be created 179 | * - an address where a contract lived, but was destroyed 180 | * ==== 181 | */ 182 | function isContract(address account) internal view returns (bool) { 183 | // This method relies in extcodesize, which returns 0 for contracts in 184 | // construction, since the code is only stored at the end of the 185 | // constructor execution. 186 | 187 | uint256 size; 188 | // solhint-disable-next-line no-inline-assembly 189 | assembly { size := extcodesize(account) } 190 | return size > 0; 191 | } 192 | 193 | /** 194 | * @dev Replacement for Solidity's `transfer`: sends `amount` wei to 195 | * `recipient`, forwarding all available gas and reverting on errors. 196 | * 197 | * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost 198 | * of certain opcodes, possibly making contracts go over the 2300 gas limit 199 | * imposed by `transfer`, making them unable to receive funds via 200 | * `transfer`. {sendValue} removes this limitation. 201 | * 202 | * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. 203 | * 204 | * IMPORTANT: because control is transferred to `recipient`, care must be 205 | * taken to not create reentrancy vulnerabilities. Consider using 206 | * {ReentrancyGuard} or the 207 | * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. 208 | */ 209 | function sendValue(address payable recipient, uint256 amount) internal { 210 | require(address(this).balance >= amount, "Address: insufficient balance"); 211 | 212 | // solhint-disable-next-line avoid-low-level-calls, avoid-call-value 213 | (bool success, ) = recipient.call{ value: amount }(""); 214 | require(success, "Address: unable to send value, recipient may have reverted"); 215 | } 216 | 217 | /** 218 | * @dev Performs a Solidity function call using a low level `call`. A 219 | * plain`call` is an unsafe replacement for a function call: use this 220 | * function instead. 221 | * 222 | * If `target` reverts with a revert reason, it is bubbled up by this 223 | * function (like regular Solidity function calls). 224 | * 225 | * Returns the raw returned data. To convert to the expected return value, 226 | * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. 227 | * 228 | * Requirements: 229 | * 230 | * - `target` must be a contract. 231 | * - calling `target` with `data` must not revert. 232 | * 233 | * _Available since v3.1._ 234 | */ 235 | function functionCall(address target, bytes memory data) internal returns (bytes memory) { 236 | return functionCall(target, data, "Address: low-level call failed"); 237 | } 238 | 239 | /** 240 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with 241 | * `errorMessage` as a fallback revert reason when `target` reverts. 242 | * 243 | * _Available since v3.1._ 244 | */ 245 | function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { 246 | return _functionCallWithValue(target, data, 0, errorMessage); 247 | } 248 | 249 | /** 250 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 251 | * but also transferring `value` wei to `target`. 252 | * 253 | * Requirements: 254 | * 255 | * - the calling contract must have an ETH balance of at least `value`. 256 | * - the called Solidity function must be `payable`. 257 | * 258 | * _Available since v3.1._ 259 | */ 260 | function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { 261 | return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); 262 | } 263 | 264 | /** 265 | * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but 266 | * with `errorMessage` as a fallback revert reason when `target` reverts. 267 | * 268 | * _Available since v3.1._ 269 | */ 270 | function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { 271 | require(address(this).balance >= value, "Address: insufficient balance for call"); 272 | return _functionCallWithValue(target, data, value, errorMessage); 273 | } 274 | 275 | function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { 276 | require(isContract(target), "Address: call to non-contract"); 277 | 278 | // solhint-disable-next-line avoid-low-level-calls 279 | (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); 280 | if (success) { 281 | return returndata; 282 | } else { 283 | // Look for revert reason and bubble it up if present 284 | if (returndata.length > 0) { 285 | // The easiest way to bubble the revert reason is using memory via assembly 286 | 287 | // solhint-disable-next-line no-inline-assembly 288 | assembly { 289 | let returndata_size := mload(returndata) 290 | revert(add(32, returndata), returndata_size) 291 | } 292 | } else { 293 | revert(errorMessage); 294 | } 295 | } 296 | } 297 | } 298 | 299 | /** 300 | * @dev Library for managing 301 | * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive 302 | * types. 303 | * 304 | * Sets have the following properties: 305 | * 306 | * - Elements are added, removed, and checked for existence in constant time 307 | * (O(1)). 308 | * - Elements are enumerated in O(n). No guarantees are made on the ordering. 309 | * 310 | * ``` 311 | * contract Example { 312 | * // Add the library methods 313 | * using EnumerableSet for EnumerableSet.AddressSet; 314 | * 315 | * // Declare a set state variable 316 | * EnumerableSet.AddressSet private mySet; 317 | * } 318 | * ``` 319 | * 320 | * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256` 321 | * (`UintSet`) are supported. 322 | */ 323 | library EnumerableSet { 324 | // To implement this library for multiple types with as little code 325 | // repetition as possible, we write it in terms of a generic Set type with 326 | // bytes32 values. 327 | // The Set implementation uses private functions, and user-facing 328 | // implementations (such as AddressSet) are just wrappers around the 329 | // underlying Set. 330 | // This means that we can only create new EnumerableSets for types that fit 331 | // in bytes32. 332 | 333 | struct Set { 334 | // Storage of set values 335 | bytes32[] _values; 336 | 337 | // Position of the value in the `values` array, plus 1 because index 0 338 | // means a value is not in the set. 339 | mapping (bytes32 => uint256) _indexes; 340 | } 341 | 342 | /** 343 | * @dev Add a value to a set. O(1). 344 | * 345 | * Returns true if the value was added to the set, that is if it was not 346 | * already present. 347 | */ 348 | function _add(Set storage set, bytes32 value) private returns (bool) { 349 | if (!_contains(set, value)) { 350 | set._values.push(value); 351 | // The value is stored at length-1, but we add 1 to all indexes 352 | // and use 0 as a sentinel value 353 | set._indexes[value] = set._values.length; 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | /** 361 | * @dev Removes a value from a set. O(1). 362 | * 363 | * Returns true if the value was removed from the set, that is if it was 364 | * present. 365 | */ 366 | function _remove(Set storage set, bytes32 value) private returns (bool) { 367 | // We read and store the value's index to prevent multiple reads from the same storage slot 368 | uint256 valueIndex = set._indexes[value]; 369 | 370 | if (valueIndex != 0) { // Equivalent to contains(set, value) 371 | // To delete an element from the _values array in O(1), we swap the element to delete with the last one in 372 | // the array, and then remove the last element (sometimes called as 'swap and pop'). 373 | // This modifies the order of the array, as noted in {at}. 374 | 375 | uint256 toDeleteIndex = valueIndex - 1; 376 | uint256 lastIndex = set._values.length - 1; 377 | 378 | // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs 379 | // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. 380 | 381 | bytes32 lastvalue = set._values[lastIndex]; 382 | 383 | // Move the last value to the index where the value to delete is 384 | set._values[toDeleteIndex] = lastvalue; 385 | // Update the index for the moved value 386 | set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based 387 | 388 | // Delete the slot where the moved value was stored 389 | set._values.pop(); 390 | 391 | // Delete the index for the deleted slot 392 | delete set._indexes[value]; 393 | 394 | return true; 395 | } else { 396 | return false; 397 | } 398 | } 399 | 400 | /** 401 | * @dev Returns true if the value is in the set. O(1). 402 | */ 403 | function _contains(Set storage set, bytes32 value) private view returns (bool) { 404 | return set._indexes[value] != 0; 405 | } 406 | 407 | /** 408 | * @dev Returns the number of values on the set. O(1). 409 | */ 410 | function _length(Set storage set) private view returns (uint256) { 411 | return set._values.length; 412 | } 413 | 414 | /** 415 | * @dev Returns the value stored at position `index` in the set. O(1). 416 | * 417 | * Note that there are no guarantees on the ordering of values inside the 418 | * array, and it may change when more values are added or removed. 419 | * 420 | * Requirements: 421 | * 422 | * - `index` must be strictly less than {length}. 423 | */ 424 | function _at(Set storage set, uint256 index) private view returns (bytes32) { 425 | require(set._values.length > index, "EnumerableSet: index out of bounds"); 426 | return set._values[index]; 427 | } 428 | 429 | // AddressSet 430 | 431 | struct AddressSet { 432 | Set _inner; 433 | } 434 | 435 | /** 436 | * @dev Add a value to a set. O(1). 437 | * 438 | * Returns true if the value was added to the set, that is if it was not 439 | * already present. 440 | */ 441 | function add(AddressSet storage set, address value) internal returns (bool) { 442 | return _add(set._inner, bytes32(uint256(value))); 443 | } 444 | 445 | /** 446 | * @dev Removes a value from a set. O(1). 447 | * 448 | * Returns true if the value was removed from the set, that is if it was 449 | * present. 450 | */ 451 | function remove(AddressSet storage set, address value) internal returns (bool) { 452 | return _remove(set._inner, bytes32(uint256(value))); 453 | } 454 | 455 | /** 456 | * @dev Returns true if the value is in the set. O(1). 457 | */ 458 | function contains(AddressSet storage set, address value) internal view returns (bool) { 459 | return _contains(set._inner, bytes32(uint256(value))); 460 | } 461 | 462 | /** 463 | * @dev Returns the number of values in the set. O(1). 464 | */ 465 | function length(AddressSet storage set) internal view returns (uint256) { 466 | return _length(set._inner); 467 | } 468 | 469 | /** 470 | * @dev Returns the value stored at position `index` in the set. O(1). 471 | * 472 | * Note that there are no guarantees on the ordering of values inside the 473 | * array, and it may change when more values are added or removed. 474 | * 475 | * Requirements: 476 | * 477 | * - `index` must be strictly less than {length}. 478 | */ 479 | function at(AddressSet storage set, uint256 index) internal view returns (address) { 480 | return address(uint256(_at(set._inner, index))); 481 | } 482 | 483 | 484 | // UintSet 485 | 486 | struct UintSet { 487 | Set _inner; 488 | } 489 | 490 | /** 491 | * @dev Add a value to a set. O(1). 492 | * 493 | * Returns true if the value was added to the set, that is if it was not 494 | * already present. 495 | */ 496 | function add(UintSet storage set, uint256 value) internal returns (bool) { 497 | return _add(set._inner, bytes32(value)); 498 | } 499 | 500 | /** 501 | * @dev Removes a value from a set. O(1). 502 | * 503 | * Returns true if the value was removed from the set, that is if it was 504 | * present. 505 | */ 506 | function remove(UintSet storage set, uint256 value) internal returns (bool) { 507 | return _remove(set._inner, bytes32(value)); 508 | } 509 | 510 | /** 511 | * @dev Returns true if the value is in the set. O(1). 512 | */ 513 | function contains(UintSet storage set, uint256 value) internal view returns (bool) { 514 | return _contains(set._inner, bytes32(value)); 515 | } 516 | 517 | /** 518 | * @dev Returns the number of values on the set. O(1). 519 | */ 520 | function length(UintSet storage set) internal view returns (uint256) { 521 | return _length(set._inner); 522 | } 523 | 524 | /** 525 | * @dev Returns the value stored at position `index` in the set. O(1). 526 | * 527 | * Note that there are no guarantees on the ordering of values inside the 528 | * array, and it may change when more values are added or removed. 529 | * 530 | * Requirements: 531 | * 532 | * - `index` must be strictly less than {length}. 533 | */ 534 | function at(UintSet storage set, uint256 index) internal view returns (uint256) { 535 | return uint256(_at(set._inner, index)); 536 | } 537 | } 538 | 539 | /** 540 | * @title SafeERC20 541 | * @dev Wrappers around ERC20 operations that throw on failure (when the token 542 | * contract returns false). Tokens that return no value (and instead revert or 543 | * throw on failure) are also supported, non-reverting calls are assumed to be 544 | * successful. 545 | * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, 546 | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. 547 | */ 548 | library SafeERC20 { 549 | using SafeMath for uint256; 550 | using Address for address; 551 | 552 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 553 | _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 554 | } 555 | 556 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 557 | _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 558 | } 559 | 560 | /** 561 | * @dev Deprecated. This function has issues similar to the ones found in 562 | * {IERC20-approve}, and its usage is discouraged. 563 | * 564 | * Whenever possible, use {safeIncreaseAllowance} and 565 | * {safeDecreaseAllowance} instead. 566 | */ 567 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 568 | // safeApprove should only be called when setting an initial allowance, 569 | // or when resetting it to zero. To increase and decrease it, use 570 | // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' 571 | // solhint-disable-next-line max-line-length 572 | require((value == 0) || (token.allowance(address(this), spender) == 0), 573 | "SafeERC20: approve from non-zero to non-zero allowance" 574 | ); 575 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 576 | } 577 | 578 | function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { 579 | uint256 newAllowance = token.allowance(address(this), spender).add(value); 580 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 581 | } 582 | 583 | function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { 584 | uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); 585 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 586 | } 587 | 588 | /** 589 | * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement 590 | * on the return value: the return value is optional (but if data is returned, it must not be false). 591 | * @param token The token targeted by the call. 592 | * @param data The call data (encoded using abi.encode or one of its variants). 593 | */ 594 | function _callOptionalReturn(IERC20 token, bytes memory data) private { 595 | // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since 596 | // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that 597 | // the target address contains contract code and also asserts for success in the low-level call. 598 | 599 | bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); 600 | if (returndata.length > 0) { // Return data is optional 601 | // solhint-disable-next-line max-line-length 602 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 603 | } 604 | } 605 | } 606 | 607 | /** 608 | * @dev Interface of the ERC20 standard as defined in the EIP. 609 | */ 610 | interface IERC20 { 611 | /** 612 | * @dev Returns the amount of tokens in existence. 613 | */ 614 | function totalSupply() external view returns (uint256); 615 | 616 | /** 617 | * @dev Returns the amount of tokens owned by `account`. 618 | */ 619 | function balanceOf(address account) external view returns (uint256); 620 | 621 | /** 622 | * @dev Moves `amount` tokens from the caller's account to `recipient`. 623 | * 624 | * Returns a boolean value indicating whether the operation succeeded. 625 | * 626 | * Emits a {Transfer} event. 627 | */ 628 | function transfer(address recipient, uint256 amount) external returns (bool); 629 | 630 | /** 631 | * @dev Returns the remaining number of tokens that `spender` will be 632 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 633 | * zero by default. 634 | * 635 | * This value changes when {approve} or {transferFrom} are called. 636 | */ 637 | function allowance(address owner, address spender) external view returns (uint256); 638 | 639 | /** 640 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 641 | * 642 | * Returns a boolean value indicating whether the operation succeeded. 643 | * 644 | * IMPORTANT: Beware that changing an allowance with this method brings the risk 645 | * that someone may use both the old and the new allowance by unfortunate 646 | * transaction ordering. One possible solution to mitigate this race 647 | * condition is to first reduce the spender's allowance to 0 and set the 648 | * desired value afterwards: 649 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 650 | * 651 | * Emits an {Approval} event. 652 | */ 653 | function approve(address spender, uint256 amount) external returns (bool); 654 | 655 | /** 656 | * @dev Moves `amount` tokens from `sender` to `recipient` using the 657 | * allowance mechanism. `amount` is then deducted from the caller's 658 | * allowance. 659 | * 660 | * Returns a boolean value indicating whether the operation succeeded. 661 | * 662 | * Emits a {Transfer} event. 663 | */ 664 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 665 | 666 | /** 667 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 668 | * another (`to`). 669 | * 670 | * Note that `value` may be zero. 671 | */ 672 | event Transfer(address indexed from, address indexed to, uint256 value); 673 | 674 | /** 675 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 676 | * a call to {approve}. `value` is the new allowance. 677 | */ 678 | event Approval(address indexed owner, address indexed spender, uint256 value); 679 | } 680 | 681 | /** 682 | * @dev Contract module that helps prevent reentrant calls to a function. 683 | * 684 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier 685 | * available, which can be applied to functions to make sure there are no nested 686 | * (reentrant) calls to them. 687 | * 688 | * Note that because there is a single `nonReentrant` guard, functions marked as 689 | * `nonReentrant` may not call one another. This can be worked around by making 690 | * those functions `private`, and then adding `external` `nonReentrant` entry 691 | * points to them. 692 | * 693 | * TIP: If you would like to learn more about reentrancy and alternative ways 694 | * to protect against it, check out our blog post 695 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. 696 | */ 697 | contract ReentrancyGuard { 698 | // Booleans are more expensive than uint256 or any type that takes up a full 699 | // word because each write operation emits an extra SLOAD to first read the 700 | // slot's contents, replace the bits taken up by the boolean, and then write 701 | // back. This is the compiler's defense against contract upgrades and 702 | // pointer aliasing, and it cannot be disabled. 703 | 704 | // The values being non-zero value makes deployment a bit more expensive, 705 | // but in exchange the refund on every call to nonReentrant will be lower in 706 | // amount. Since refunds are capped to a percentage of the total 707 | // transaction's gas, it is best to keep them low in cases like this one, to 708 | // increase the likelihood of the full refund coming into effect. 709 | uint256 private constant _NOT_ENTERED = 1; 710 | uint256 private constant _ENTERED = 2; 711 | 712 | uint256 private _status; 713 | 714 | constructor () internal { 715 | _status = _NOT_ENTERED; 716 | } 717 | 718 | /** 719 | * @dev Prevents a contract from calling itself, directly or indirectly. 720 | * Calling a `nonReentrant` function from another `nonReentrant` 721 | * function is not supported. It is possible to prevent this from happening 722 | * by making the `nonReentrant` function external, and make it call a 723 | * `private` function that does the actual work. 724 | */ 725 | modifier nonReentrant() { 726 | // On the first call to nonReentrant, _notEntered will be true 727 | require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); 728 | 729 | // Any calls to nonReentrant after this point will fail 730 | _status = _ENTERED; 731 | 732 | _; 733 | 734 | // By storing the original value once again, a refund is triggered (see 735 | // https://eips.ethereum.org/EIPS/eip-2200) 736 | _status = _NOT_ENTERED; 737 | } 738 | } 739 | 740 | /** 741 | * @dev Contract module which provides a basic access control mechanism, where 742 | * there is an account (an owner) that can be granted exclusive access to 743 | * specific functions. 744 | * 745 | * By default, the owner account will be the one that deploys the contract. This 746 | * can later be changed with {transferOwnership}. 747 | * 748 | * This module is used through inheritance. It will make available the modifier 749 | * `onlyOwner`, which can be applied to your functions to restrict their use to 750 | * the owner. 751 | */ 752 | contract Ownable { 753 | address private _owner; 754 | 755 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 756 | 757 | /** 758 | * @dev Initializes the contract setting the deployer as the initial owner. 759 | */ 760 | constructor () internal { 761 | address msgSender = msg.sender; 762 | _owner = msgSender; 763 | emit OwnershipTransferred(address(0), msgSender); 764 | } 765 | 766 | /** 767 | * @dev Returns the address of the current owner. 768 | */ 769 | function owner() public view returns (address) { 770 | return _owner; 771 | } 772 | 773 | /** 774 | * @dev Throws if called by any account other than the owner. 775 | */ 776 | modifier onlyOwner() { 777 | require(_owner == msg.sender, "Ownable: caller is not the owner"); 778 | _; 779 | } 780 | 781 | /** 782 | * @dev Leaves the contract without owner. It will not be possible to call 783 | * `onlyOwner` functions anymore. Can only be called by the current owner. 784 | * 785 | * NOTE: Renouncing ownership will leave the contract without an owner, 786 | * thereby removing any functionality that is only available to the owner. 787 | */ 788 | function renounceOwnership() public virtual onlyOwner { 789 | emit OwnershipTransferred(_owner, address(0)); 790 | _owner = address(0); 791 | } 792 | 793 | /** 794 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 795 | * Can only be called by the current owner. 796 | */ 797 | function transferOwnership(address newOwner) public virtual onlyOwner { 798 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 799 | emit OwnershipTransferred(_owner, newOwner); 800 | _owner = newOwner; 801 | } 802 | } 803 | 804 | interface CEther { 805 | function mint() external payable; 806 | 807 | function exchangeRateCurrent() external returns (uint256); 808 | function exchangeRateStored() external view returns (uint256); 809 | 810 | function supplyRatePerBlock() external returns (uint256); 811 | 812 | function redeem(uint) external returns (uint); 813 | 814 | function redeemUnderlying(uint) external returns (uint); 815 | 816 | } 817 | 818 | interface IUniswapV2Router { 819 | function WETH() external pure returns (address); 820 | 821 | function swapExactTokensForTokens( 822 | uint amountIn, 823 | uint amountOutMin, 824 | address[] calldata path, 825 | address to, 826 | uint deadline 827 | ) external returns (uint[] memory amounts); 828 | 829 | function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) 830 | external 831 | payable 832 | returns (uint[] memory amounts); 833 | 834 | function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); 835 | } 836 | 837 | interface IWETH { 838 | function deposit() external payable; 839 | function transfer(address to, uint value) external returns (bool); 840 | function withdraw(uint) external; 841 | } 842 | 843 | /** 844 | * Accounting: 845 | * - the smart contract maintains a ledger of token balances which changes upon actions affecting 846 | * this smart contract's token balance. 847 | * 848 | * - it allows owner to withdraw any extra amount of any tokens that have not been recorded, 849 | * i.e, - any tokens that are accidentally transferred to this smart contract. 850 | * 851 | * - care must be taken in auditing that `claimExtraTokens` function does not allow withdrawals of 852 | * any tokens in this smart contract in more amounts than necessary. In simple terms, admin can 853 | * only transfer out tokens that are accidentally sent to this smart contract. Nothing more nothing less. 854 | */ 855 | contract VaultWETH is Ownable, ReentrancyGuard { 856 | using SafeMath for uint; 857 | using Address for address; 858 | using EnumerableSet for EnumerableSet.AddressSet; 859 | using SafeERC20 for IERC20; 860 | 861 | //==================== Contract Variables ======================= 862 | // Contract variables must be changed before live deployment 863 | 864 | uint public constant LOCKUP_DURATION = 5 minutes; 865 | uint public constant FEE_PERCENT_X_100 = 30; 866 | uint public constant FEE_PERCENT_TO_BUYBACK_X_100 = 2500; 867 | 868 | uint public constant REWARD_INTERVAL = 365 days; 869 | uint public constant ADMIN_CAN_CLAIM_AFTER = 395 days; 870 | uint public constant REWARD_RETURN_PERCENT_X_100 = 200; 871 | 872 | // ETH fee equivalent predefined gas price 873 | uint public constant MIN_ETH_FEE_IN_WEI = 400000 * 1 * 10**9; 874 | 875 | address public constant TRUSTED_CTOKEN_ADDRESS = 0x41B5844f4680a8C38fBb695b7F9CFd1F64474a72; 876 | address public constant TRUSTED_PLATFORM_TOKEN_ADDRESS = 0xd8bB0ff7a267ab387015C18675591912D8035D9E; 877 | 878 | address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD; 879 | 880 | //================= End Contract Variables ====================== 881 | 882 | IUniswapV2Router public constant uniswapRouterV2 = IUniswapV2Router(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); 883 | 884 | uint public constant ONE_HUNDRED_X_100 = 10000; 885 | uint public immutable contractStartTime; 886 | 887 | address public immutable TRUSTED_DEPOSIT_TOKEN_ADDRESS; 888 | 889 | constructor() public { 890 | contractStartTime = block.timestamp; 891 | TRUSTED_DEPOSIT_TOKEN_ADDRESS = uniswapRouterV2.WETH(); 892 | } 893 | 894 | modifier noContractsAllowed() { 895 | require(tx.origin == msg.sender, "No Contracts Allowed!"); 896 | _; 897 | } 898 | 899 | // ------------------- event definitions ------------------- 900 | 901 | event Deposit(address indexed account, uint amount); 902 | event Withdraw(address indexed account, uint amount); 903 | 904 | event EtherRewardDisbursed(uint amount); 905 | event TokenRewardDisbursed(uint amount); 906 | 907 | event PlatformTokenRewardClaimed(address indexed account, uint amount); 908 | event CompoundRewardClaimed(address indexed account, uint amount); 909 | event EtherRewardClaimed(address indexed account, uint amount); 910 | event TokenRewardClaimed(address indexed account, uint amount); 911 | 912 | event PlatformTokenAdded(uint amount); 913 | 914 | // ----------------- end event definitions ----------------- 915 | 916 | EnumerableSet.AddressSet private holders; 917 | 918 | // view functon to get number of stakers 919 | function getNumberOfHolders() public view returns (uint) { 920 | return holders.length(); 921 | } 922 | 923 | // token contract address => token balance of this contract 924 | mapping (address => uint) public tokenBalances; 925 | 926 | // user wallet => balance 927 | mapping (address => uint) public cTokenBalance; 928 | mapping (address => uint) public depositTokenBalance; 929 | 930 | mapping (address => uint) public totalTokensDepositedByUser; 931 | mapping (address => uint) public totalTokensWithdrawnByUser; 932 | 933 | mapping (address => uint) public totalEarnedCompoundDivs; 934 | mapping (address => uint) public totalEarnedEthDivs; 935 | mapping (address => uint) public totalEarnedTokenDivs; 936 | mapping (address => uint) public totalEarnedPlatformTokenDivs; 937 | 938 | mapping (address => uint) public depositTime; 939 | mapping (address => uint) public lastClaimedTime; 940 | 941 | uint public totalCTokens; 942 | uint public totalDepositedTokens; 943 | 944 | // ----------------- 945 | 946 | uint public constant POINT_MULTIPLIER = 1e18; 947 | 948 | mapping (address => uint) public lastTokenDivPoints; 949 | mapping (address => uint) public tokenDivsBalance; 950 | uint public totalTokenDivPoints; 951 | 952 | mapping (address => uint) public lastEthDivPoints; 953 | mapping (address => uint) public ethDivsBalance; 954 | uint public totalEthDivPoints; 955 | 956 | mapping (address => uint) public platformTokenDivsBalance; 957 | 958 | uint public totalEthDisbursed; 959 | uint public totalTokensDisbursed; 960 | 961 | 962 | function tokenDivsOwing(address account) public view returns (uint) { 963 | uint newDivPoints = totalTokenDivPoints.sub(lastTokenDivPoints[account]); 964 | return depositTokenBalance[account].mul(newDivPoints).div(POINT_MULTIPLIER); 965 | } 966 | function ethDivsOwing(address account) public view returns (uint) { 967 | uint newDivPoints = totalEthDivPoints.sub(lastEthDivPoints[account]); 968 | return depositTokenBalance[account].mul(newDivPoints).div(POINT_MULTIPLIER); 969 | } 970 | 971 | function distributeEthDivs(uint amount) private { 972 | if (totalDepositedTokens == 0) return; 973 | totalEthDivPoints = totalEthDivPoints.add(amount.mul(POINT_MULTIPLIER).div(totalDepositedTokens)); 974 | totalEthDisbursed = totalEthDisbursed.add(amount); 975 | increaseTokenBalance(address(0), amount); 976 | emit EtherRewardDisbursed(amount); 977 | } 978 | function distributeTokenDivs(uint amount) private { 979 | if (totalDepositedTokens == 0) return; 980 | totalTokenDivPoints = totalTokenDivPoints.add(amount.mul(POINT_MULTIPLIER).div(totalDepositedTokens)); 981 | totalTokensDisbursed = totalTokensDisbursed.add(amount); 982 | increaseTokenBalance(TRUSTED_DEPOSIT_TOKEN_ADDRESS, amount); 983 | emit TokenRewardDisbursed(amount); 984 | } 985 | 986 | 987 | // ----------------- 988 | 989 | // view function to get depositors list 990 | function getDepositorsList(uint startIndex, uint endIndex) 991 | public 992 | view 993 | returns (address[] memory stakers, 994 | uint[] memory stakingTimestamps, 995 | uint[] memory lastClaimedTimeStamps, 996 | uint[] memory stakedTokens) { 997 | require (startIndex < endIndex); 998 | 999 | uint length = endIndex.sub(startIndex); 1000 | address[] memory _stakers = new address[](length); 1001 | uint[] memory _stakingTimestamps = new uint[](length); 1002 | uint[] memory _lastClaimedTimeStamps = new uint[](length); 1003 | uint[] memory _stakedTokens = new uint[](length); 1004 | 1005 | for (uint i = startIndex; i < endIndex; i = i.add(1)) { 1006 | address staker = holders.at(i); 1007 | uint listIndex = i.sub(startIndex); 1008 | _stakers[listIndex] = staker; 1009 | _stakingTimestamps[listIndex] = depositTime[staker]; 1010 | _lastClaimedTimeStamps[listIndex] = lastClaimedTime[staker]; 1011 | _stakedTokens[listIndex] = depositTokenBalance[staker]; 1012 | } 1013 | 1014 | return (_stakers, _stakingTimestamps, _lastClaimedTimeStamps, _stakedTokens); 1015 | } 1016 | 1017 | function updateAccount(address account) private { 1018 | // update user account here 1019 | uint tokensOwing = tokenDivsOwing(account); 1020 | lastTokenDivPoints[account] = totalTokenDivPoints; 1021 | if (tokensOwing > 0) { 1022 | tokenDivsBalance[account] = tokenDivsBalance[account].add(tokensOwing); 1023 | } 1024 | 1025 | uint weiOwing = ethDivsOwing(account); 1026 | lastEthDivPoints[account] = totalEthDivPoints; 1027 | if (weiOwing > 0) { 1028 | ethDivsBalance[account] = ethDivsBalance[account].add(weiOwing); 1029 | } 1030 | 1031 | uint platformTokensOwing = platformTokenDivsOwing(account); 1032 | if (platformTokensOwing > 0) { 1033 | platformTokenDivsBalance[account] = platformTokenDivsBalance[account].add(platformTokensOwing); 1034 | } 1035 | 1036 | lastClaimedTime[account] = block.timestamp; 1037 | } 1038 | 1039 | function platformTokenDivsOwing(address account) public view returns (uint) { 1040 | if (!holders.contains(account)) return 0; 1041 | if (depositTokenBalance[account] == 0) return 0; 1042 | 1043 | uint timeDiff; 1044 | uint stakingEndTime = contractStartTime.add(REWARD_INTERVAL); 1045 | uint _now = block.timestamp; 1046 | if (_now > stakingEndTime) { 1047 | _now = stakingEndTime; 1048 | } 1049 | 1050 | if (lastClaimedTime[account] >= _now) { 1051 | timeDiff = 0; 1052 | } else { 1053 | timeDiff = _now.sub(lastClaimedTime[account]); 1054 | } 1055 | 1056 | uint pendingDivs = depositTokenBalance[account] 1057 | .mul(REWARD_RETURN_PERCENT_X_100) 1058 | .mul(timeDiff) 1059 | .div(REWARD_INTERVAL) 1060 | .div(ONE_HUNDRED_X_100); 1061 | return pendingDivs; 1062 | } 1063 | 1064 | function getEstimatedCompoundDivsOwing(address account) public view returns (uint) { 1065 | uint convertedBalance = getConvertedBalance(cTokenBalance[account]); 1066 | uint depositedBalance = depositTokenBalance[account]; 1067 | return (convertedBalance > depositedBalance ? convertedBalance.sub(depositedBalance) : 0); 1068 | } 1069 | 1070 | function getConvertedBalance(uint _cTokenBalance) public view returns (uint) { 1071 | uint exchangeRateStored = getExchangeRateStored(); 1072 | uint convertedBalance = _cTokenBalance.mul(exchangeRateStored).div(10**18); 1073 | return convertedBalance; 1074 | } 1075 | 1076 | function _claimEthDivs() private { 1077 | updateAccount(msg.sender); 1078 | uint amount = ethDivsBalance[msg.sender]; 1079 | ethDivsBalance[msg.sender] = 0; 1080 | if (amount == 0) return; 1081 | decreaseTokenBalance(address(0), amount); 1082 | msg.sender.transfer(amount); 1083 | totalEarnedEthDivs[msg.sender] = totalEarnedEthDivs[msg.sender].add(amount); 1084 | 1085 | emit EtherRewardClaimed(msg.sender, amount); 1086 | } 1087 | function _claimTokenDivs() private { 1088 | updateAccount(msg.sender); 1089 | uint amount = tokenDivsBalance[msg.sender]; 1090 | tokenDivsBalance[msg.sender] = 0; 1091 | if (amount == 0) return; 1092 | decreaseTokenBalance(TRUSTED_DEPOSIT_TOKEN_ADDRESS, amount); 1093 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeTransfer(msg.sender, amount); 1094 | totalEarnedTokenDivs[msg.sender] = totalEarnedTokenDivs[msg.sender].add(amount); 1095 | 1096 | emit TokenRewardClaimed(msg.sender, amount); 1097 | } 1098 | function _claimCompoundDivs() private { 1099 | updateAccount(msg.sender); 1100 | uint exchangeRateCurrent = getExchangeRateCurrent(); 1101 | 1102 | uint convertedBalance = cTokenBalance[msg.sender].mul(exchangeRateCurrent).div(10**18); 1103 | uint depositedBalance = depositTokenBalance[msg.sender]; 1104 | 1105 | uint amount = convertedBalance > depositedBalance ? convertedBalance.sub(depositedBalance) : 0; 1106 | 1107 | if (amount == 0) return; 1108 | 1109 | uint oldCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1110 | uint oldEtherBalance = address(this).balance; 1111 | require(CEther(TRUSTED_CTOKEN_ADDRESS).redeemUnderlying(amount) == 0, "redeemUnderlying failed!"); 1112 | uint newCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1113 | uint newEtherBalance = address(this).balance; 1114 | 1115 | uint depositTokenReceived = newEtherBalance.sub(oldEtherBalance); 1116 | uint cTokenRedeemed = oldCTokenBalance.sub(newCTokenBalance); 1117 | 1118 | IWETH(TRUSTED_DEPOSIT_TOKEN_ADDRESS).deposit{value: depositTokenReceived}(); 1119 | 1120 | require(cTokenRedeemed <= cTokenBalance[msg.sender], "redeem exceeds balance!"); 1121 | cTokenBalance[msg.sender] = cTokenBalance[msg.sender].sub(cTokenRedeemed); 1122 | totalCTokens = totalCTokens.sub(cTokenRedeemed); 1123 | decreaseTokenBalance(TRUSTED_CTOKEN_ADDRESS, cTokenRedeemed); 1124 | 1125 | totalTokensWithdrawnByUser[msg.sender] = totalTokensWithdrawnByUser[msg.sender].add(depositTokenReceived); 1126 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeTransfer(msg.sender, depositTokenReceived); 1127 | 1128 | totalEarnedCompoundDivs[msg.sender] = totalEarnedCompoundDivs[msg.sender].add(depositTokenReceived); 1129 | 1130 | emit CompoundRewardClaimed(msg.sender, depositTokenReceived); 1131 | } 1132 | function _claimPlatformTokenDivs(uint _amountOutMin_platformTokens) private { 1133 | updateAccount(msg.sender); 1134 | uint amount = platformTokenDivsBalance[msg.sender]; 1135 | 1136 | if (amount == 0) return; 1137 | 1138 | address[] memory path = new address[](2); 1139 | path[0] = TRUSTED_DEPOSIT_TOKEN_ADDRESS; 1140 | path[1] = TRUSTED_PLATFORM_TOKEN_ADDRESS; 1141 | 1142 | uint estimatedAmountOut = uniswapRouterV2.getAmountsOut(amount, path)[1]; 1143 | require(estimatedAmountOut >= _amountOutMin_platformTokens, "_claimPlatformTokenDivs: slippage error!"); 1144 | 1145 | if (IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).balanceOf(address(this)) < estimatedAmountOut) { 1146 | return; 1147 | } 1148 | 1149 | platformTokenDivsBalance[msg.sender] = 0; 1150 | 1151 | 1152 | decreaseTokenBalance(TRUSTED_PLATFORM_TOKEN_ADDRESS, estimatedAmountOut); 1153 | IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).safeTransfer(msg.sender, estimatedAmountOut); 1154 | totalEarnedPlatformTokenDivs[msg.sender] = totalEarnedPlatformTokenDivs[msg.sender].add(estimatedAmountOut); 1155 | 1156 | emit PlatformTokenRewardClaimed(msg.sender, estimatedAmountOut); 1157 | } 1158 | 1159 | function claimEthDivs() external noContractsAllowed nonReentrant { 1160 | _claimEthDivs(); 1161 | } 1162 | function claimTokenDivs() external noContractsAllowed nonReentrant { 1163 | _claimTokenDivs(); 1164 | } 1165 | function claimCompoundDivs() external noContractsAllowed nonReentrant { 1166 | _claimCompoundDivs(); 1167 | } 1168 | function claimPlatformTokenDivs(uint _amountOutMin_platformTokens) external noContractsAllowed nonReentrant { 1169 | _claimPlatformTokenDivs(_amountOutMin_platformTokens); 1170 | } 1171 | 1172 | function claim(uint _amountOutMin_platformTokens) external noContractsAllowed nonReentrant { 1173 | _claimEthDivs(); 1174 | _claimTokenDivs(); 1175 | _claimCompoundDivs(); 1176 | _claimPlatformTokenDivs(_amountOutMin_platformTokens); 1177 | } 1178 | 1179 | function getExchangeRateCurrent() public returns (uint) { 1180 | uint exchangeRateCurrent = CEther(TRUSTED_CTOKEN_ADDRESS).exchangeRateCurrent(); 1181 | return exchangeRateCurrent; 1182 | } 1183 | 1184 | function getExchangeRateStored() public view returns (uint) { 1185 | uint exchangeRateStored = CEther(TRUSTED_CTOKEN_ADDRESS).exchangeRateStored(); 1186 | return exchangeRateStored; 1187 | } 1188 | 1189 | function deposit(uint amount, uint _amountOutMin_ethFeeBuyBack, uint deadline) external noContractsAllowed nonReentrant payable { 1190 | require(amount > 0, "invalid amount!"); 1191 | 1192 | updateAccount(msg.sender); 1193 | 1194 | // increment token balance! 1195 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeTransferFrom(msg.sender, address(this), amount); 1196 | 1197 | 1198 | totalTokensDepositedByUser[msg.sender] = totalTokensDepositedByUser[msg.sender].add(amount); 1199 | 1200 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeApprove(TRUSTED_CTOKEN_ADDRESS, 0); 1201 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeApprove(TRUSTED_CTOKEN_ADDRESS, amount); 1202 | 1203 | uint oldCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1204 | 1205 | IWETH(TRUSTED_DEPOSIT_TOKEN_ADDRESS).withdraw(amount); 1206 | CEther(TRUSTED_CTOKEN_ADDRESS).mint{value: amount}(); 1207 | 1208 | uint newCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1209 | uint cTokenReceived = newCTokenBalance.sub(oldCTokenBalance); 1210 | 1211 | cTokenBalance[msg.sender] = cTokenBalance[msg.sender].add(cTokenReceived); 1212 | totalCTokens = totalCTokens.add(cTokenReceived); 1213 | increaseTokenBalance(TRUSTED_CTOKEN_ADDRESS, cTokenReceived); 1214 | 1215 | depositTokenBalance[msg.sender] = depositTokenBalance[msg.sender].add(amount); 1216 | totalDepositedTokens = totalDepositedTokens.add(amount); 1217 | 1218 | handleEthFee(msg.value, _amountOutMin_ethFeeBuyBack, deadline); 1219 | 1220 | holders.add(msg.sender); 1221 | depositTime[msg.sender] = block.timestamp; 1222 | 1223 | emit Deposit(msg.sender, amount); 1224 | } 1225 | function withdraw(uint amount, uint _amountOutMin_ethFeeBuyBack, uint _amountOutMin_tokenFeeBuyBack, uint deadline) external noContractsAllowed nonReentrant payable { 1226 | require(amount > 0, "invalid amount!"); 1227 | require(amount <= depositTokenBalance[msg.sender], "Cannot withdraw more than deposited!"); 1228 | require(block.timestamp.sub(depositTime[msg.sender]) > LOCKUP_DURATION, "You recently deposited, please wait before withdrawing."); 1229 | 1230 | updateAccount(msg.sender); 1231 | 1232 | depositTokenBalance[msg.sender] = depositTokenBalance[msg.sender].sub(amount); 1233 | totalDepositedTokens = totalDepositedTokens.sub(amount); 1234 | 1235 | uint oldCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1236 | uint oldEtherBalance = address(this).balance; 1237 | require(CEther(TRUSTED_CTOKEN_ADDRESS).redeemUnderlying(amount) == 0, "redeemUnderlying failed!"); 1238 | uint newCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1239 | uint newEtherBalance = address(this).balance; 1240 | 1241 | uint depositTokenReceived = newEtherBalance.sub(oldEtherBalance); 1242 | uint cTokenRedeemed = oldCTokenBalance.sub(newCTokenBalance); 1243 | 1244 | IWETH(TRUSTED_DEPOSIT_TOKEN_ADDRESS).deposit{value: depositTokenReceived}(); 1245 | 1246 | require(cTokenRedeemed <= cTokenBalance[msg.sender], "redeem exceeds balance!"); 1247 | cTokenBalance[msg.sender] = cTokenBalance[msg.sender].sub(cTokenRedeemed); 1248 | totalCTokens = totalCTokens.sub(cTokenRedeemed); 1249 | decreaseTokenBalance(TRUSTED_CTOKEN_ADDRESS, cTokenRedeemed); 1250 | 1251 | totalTokensWithdrawnByUser[msg.sender] = totalTokensWithdrawnByUser[msg.sender].add(depositTokenReceived); 1252 | 1253 | uint feeAmount = depositTokenReceived.mul(FEE_PERCENT_X_100).div(ONE_HUNDRED_X_100); 1254 | uint depositTokenReceivedAfterFee = depositTokenReceived.sub(feeAmount); 1255 | 1256 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeTransfer(msg.sender, depositTokenReceivedAfterFee); 1257 | 1258 | handleFee(feeAmount, _amountOutMin_tokenFeeBuyBack, deadline); 1259 | handleEthFee(msg.value, _amountOutMin_ethFeeBuyBack, deadline); 1260 | 1261 | if (depositTokenBalance[msg.sender] == 0) { 1262 | holders.remove(msg.sender); 1263 | } 1264 | 1265 | emit Withdraw(msg.sender, depositTokenReceived); 1266 | } 1267 | 1268 | // emergency withdraw without interacting with uniswap 1269 | function emergencyWithdraw(uint amount) external noContractsAllowed nonReentrant payable { 1270 | require(amount > 0, "invalid amount!"); 1271 | require(amount <= depositTokenBalance[msg.sender], "Cannot withdraw more than deposited!"); 1272 | require(block.timestamp.sub(depositTime[msg.sender]) > LOCKUP_DURATION, "You recently deposited, please wait before withdrawing."); 1273 | 1274 | updateAccount(msg.sender); 1275 | 1276 | depositTokenBalance[msg.sender] = depositTokenBalance[msg.sender].sub(amount); 1277 | totalDepositedTokens = totalDepositedTokens.sub(amount); 1278 | 1279 | uint oldCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1280 | uint oldEtherBalance = address(this).balance; 1281 | require(CEther(TRUSTED_CTOKEN_ADDRESS).redeemUnderlying(amount) == 0, "redeemUnderlying failed!"); 1282 | uint newCTokenBalance = IERC20(TRUSTED_CTOKEN_ADDRESS).balanceOf(address(this)); 1283 | uint newEtherBalance = address(this).balance; 1284 | 1285 | uint depositTokenReceived = newEtherBalance.sub(oldEtherBalance); 1286 | uint cTokenRedeemed = oldCTokenBalance.sub(newCTokenBalance); 1287 | 1288 | IWETH(TRUSTED_DEPOSIT_TOKEN_ADDRESS).deposit{value: depositTokenReceived}(); 1289 | 1290 | require(cTokenRedeemed <= cTokenBalance[msg.sender], "redeem exceeds balance!"); 1291 | cTokenBalance[msg.sender] = cTokenBalance[msg.sender].sub(cTokenRedeemed); 1292 | totalCTokens = totalCTokens.sub(cTokenRedeemed); 1293 | decreaseTokenBalance(TRUSTED_CTOKEN_ADDRESS, cTokenRedeemed); 1294 | 1295 | totalTokensWithdrawnByUser[msg.sender] = totalTokensWithdrawnByUser[msg.sender].add(depositTokenReceived); 1296 | 1297 | uint feeAmount = depositTokenReceived.mul(FEE_PERCENT_X_100).div(ONE_HUNDRED_X_100); 1298 | uint depositTokenReceivedAfterFee = depositTokenReceived.sub(feeAmount); 1299 | 1300 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeTransfer(msg.sender, depositTokenReceivedAfterFee); 1301 | 1302 | // no uniswap interaction 1303 | // handleFee(feeAmount, _amountOutMin_tokenFeeBuyBack, deadline); 1304 | // handleEthFee(msg.value, _amountOutMin_ethFeeBuyBack, deadline); 1305 | 1306 | if (depositTokenBalance[msg.sender] == 0) { 1307 | holders.remove(msg.sender); 1308 | } 1309 | 1310 | emit Withdraw(msg.sender, depositTokenReceived); 1311 | } 1312 | 1313 | function handleFee(uint feeAmount, uint _amountOutMin_tokenFeeBuyBack, uint deadline) private { 1314 | uint buyBackFeeAmount = feeAmount.mul(FEE_PERCENT_TO_BUYBACK_X_100).div(ONE_HUNDRED_X_100); 1315 | uint remainingFeeAmount = feeAmount.sub(buyBackFeeAmount); 1316 | 1317 | // handle distribution 1318 | distributeTokenDivs(remainingFeeAmount); 1319 | 1320 | 1321 | // handle buyback 1322 | // --- swap token to platform token here! ---- 1323 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeApprove(address(uniswapRouterV2), 0); 1324 | IERC20(TRUSTED_DEPOSIT_TOKEN_ADDRESS).safeApprove(address(uniswapRouterV2), buyBackFeeAmount); 1325 | 1326 | uint oldPlatformTokenBalance = IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).balanceOf(address(this)); 1327 | address[] memory path = new address[](2); 1328 | path[0] = TRUSTED_DEPOSIT_TOKEN_ADDRESS; 1329 | path[1] = TRUSTED_PLATFORM_TOKEN_ADDRESS; 1330 | 1331 | uniswapRouterV2.swapExactTokensForTokens(buyBackFeeAmount, _amountOutMin_tokenFeeBuyBack, path, address(this), deadline); 1332 | uint newPlatformTokenBalance = IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).balanceOf(address(this)); 1333 | uint platformTokensReceived = newPlatformTokenBalance.sub(oldPlatformTokenBalance); 1334 | IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).safeTransfer(BURN_ADDRESS, platformTokensReceived); 1335 | // ---- end swap token to plaform tokens ----- 1336 | } 1337 | 1338 | function handleEthFee(uint feeAmount, uint _amountOutMin_ethFeeBuyBack, uint deadline) private { 1339 | require(feeAmount >= MIN_ETH_FEE_IN_WEI, "Insufficient ETH Fee!"); 1340 | uint buyBackFeeAmount = feeAmount.mul(FEE_PERCENT_TO_BUYBACK_X_100).div(ONE_HUNDRED_X_100); 1341 | uint remainingFeeAmount = feeAmount.sub(buyBackFeeAmount); 1342 | 1343 | // handle distribution 1344 | distributeEthDivs(remainingFeeAmount); 1345 | 1346 | 1347 | // handle buyback 1348 | 1349 | // --- swap eth to platform token here! ---- 1350 | uint oldPlatformTokenBalance = IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).balanceOf(address(this)); 1351 | address[] memory path = new address[](2); 1352 | path[0] = uniswapRouterV2.WETH(); 1353 | path[1] = TRUSTED_PLATFORM_TOKEN_ADDRESS; 1354 | 1355 | uniswapRouterV2.swapExactETHForTokens{value: buyBackFeeAmount}(_amountOutMin_ethFeeBuyBack, path, address(this), deadline); 1356 | uint newPlatformTokenBalance = IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).balanceOf(address(this)); 1357 | uint platformTokensReceived = newPlatformTokenBalance.sub(oldPlatformTokenBalance); 1358 | IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).safeTransfer(BURN_ADDRESS, platformTokensReceived); 1359 | // ---- end swap eth to plaform tokens ----- 1360 | } 1361 | 1362 | receive () external payable { 1363 | // receive eth do nothing 1364 | } 1365 | 1366 | function increaseTokenBalance(address token, uint amount) private { 1367 | tokenBalances[token] = tokenBalances[token].add(amount); 1368 | } 1369 | function decreaseTokenBalance(address token, uint amount) private { 1370 | tokenBalances[token] = tokenBalances[token].sub(amount); 1371 | } 1372 | 1373 | function addPlatformTokenBalance(uint amount) external nonReentrant onlyOwner { 1374 | increaseTokenBalance(TRUSTED_PLATFORM_TOKEN_ADDRESS, amount); 1375 | IERC20(TRUSTED_PLATFORM_TOKEN_ADDRESS).safeTransferFrom(msg.sender, address(this), amount); 1376 | 1377 | emit PlatformTokenAdded(amount); 1378 | } 1379 | 1380 | function claimExtraTokens(address token) external nonReentrant onlyOwner { 1381 | if (token == address(0)) { 1382 | uint ethDiff = address(this).balance.sub(tokenBalances[token]); 1383 | msg.sender.transfer(ethDiff); 1384 | return; 1385 | } 1386 | uint diff = IERC20(token).balanceOf(address(this)).sub(tokenBalances[token]); 1387 | IERC20(token).safeTransfer(msg.sender, diff); 1388 | } 1389 | 1390 | function claimAnyToken(address token, uint amount) external onlyOwner { 1391 | require(now > contractStartTime.add(ADMIN_CAN_CLAIM_AFTER), "Contract not expired yet!"); 1392 | if (token == address(0)) { 1393 | msg.sender.transfer(amount); 1394 | return; 1395 | } 1396 | IERC20(token).safeTransfer(msg.sender, amount); 1397 | } 1398 | } 1399 | --------------------------------------------------------------------------------