Skip to content

Commit

Permalink
Euler-Lender-with-staking (#53)
Browse files Browse the repository at this point in the history
* first draft genericEulerStaker

* compiler issue

* reorganized the test files

* old tests passing

* temp copy paste test file foundry

* forge install: forge-std

* first try exact rounding

* brute force on rounding

* tests done except check on rewards received

* change 1inch endpoint to v5

* first comments @sogipec

* removed wrong comments

* test rewards

* changing the generic euler function (#54)

* fixed all imports

* import in the CI the endpoint foundry

* commented test using 1inch payloads --> update in the contracts to 1inchV5

* setting variables as storage and not hardcoded

* comments @sogipec

* small fixes tests

Co-authored-by: Pablo Veyrat <[email protected]>
  • Loading branch information
GuillaumeNervoXS and sogipec authored Jan 9, 2023
1 parent 873b5e7 commit a339610
Show file tree
Hide file tree
Showing 52 changed files with 1,237 additions and 238 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ jobs:
- name: Run Foundry tests
run: yarn foundry:test
env:
ETH_NODE_URI_ETH_FOUNDRY: ${{secrets.ETH_NODE_URI_ETH_FOUNDRY}}
ETH_NODE_URI_MAINNET: ${{ secrets.ETH_NODE_URI_MAINNET }}
ETH_NODE_URI_POLYGON: ${{ secrets.ETH_NODE_URI_POLYGON }}
ETH_NODE_URI_GOERLI: ${{ secrets.ETH_NODE_URI_GOERLI }}
Expand Down
110 changes: 110 additions & 0 deletions contracts/external/FullMath.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.4.0;

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
/// @dev This contract was forked from Uniswap V3's contract `FullMath.sol` available here
/// https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/libraries/FullMath.sol
abstract contract FullMath {
/// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
function _mulDiv(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
// 512-bit multiply [prod1 prod0] = a * b
// Compute the product mod 2**256 and mod 2**256 - 1
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2**256 + prod0
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(a, b, not(0))
prod0 := mul(a, b)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}

// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
require(denominator > 0);
assembly {
result := div(prod0, denominator)
}
return result;
}

// Make sure the result is less than 2**256.
// Also prevents denominator == 0
require(denominator > prod1);

///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////

// Make division exact by subtracting the remainder from [prod1 prod0]
// Compute remainder using mulmod
uint256 remainder;
assembly {
remainder := mulmod(a, b, denominator)
}
// Subtract 256 bit number from 512 bit number
assembly {
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}

// Factor powers of two out of denominator
// Compute largest power of two divisor of denominator.
// Always >= 1.
uint256 twos = denominator & (~denominator + 1);
// Divide denominator by power of two
assembly {
denominator := div(denominator, twos)
}

// Divide [prod1 prod0] by the factors of two
assembly {
prod0 := div(prod0, twos)
}
// Shift in bits from prod1 into prod0. For this we need
// to flip `twos` such that it is 2**256 / twos.
// If twos is zero, then it becomes one
assembly {
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;

// Invert denominator mod 2**256
// Now that denominator is an odd number, it has an inverse
// modulo 2**256 such that denominator * inv = 1 mod 2**256.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, denominator * inv = 1 mod 2**4
uint256 inv = (3 * denominator) ^ 2;
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv *= 2 - denominator * inv; // inverse mod 2**8
inv *= 2 - denominator * inv; // inverse mod 2**16
inv *= 2 - denominator * inv; // inverse mod 2**32
inv *= 2 - denominator * inv; // inverse mod 2**64
inv *= 2 - denominator * inv; // inverse mod 2**128
inv *= 2 - denominator * inv; // inverse mod 2**256

// Because the division is now exact we can divide by multiplying
// with the modular inverse of denominator. This will give us the
// correct result modulo 2**256. Since the precoditions guarantee
// that the outcome is less than 2**256, this is the final result.
// We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inv;
return result;
}
}
81 changes: 81 additions & 0 deletions contracts/external/ProxyAdmin.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.17;

import "./TransparentUpgradeableProxy.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

/**
* @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
* explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
* This contract was fully forked from OpenZeppelin `ProxyAdmin`
*/
contract ProxyAdmin is Ownable {
/**
* @dev Returns the current implementation of `proxy`.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
// We need to manually run the static call since the getter cannot be flagged as view
// bytes4(keccak256("implementation()")) == 0x5c60da1b
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
require(success);
return abi.decode(returndata, (address));
}

/**
* @dev Returns the current admin of `proxy`.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
// We need to manually run the static call since the getter cannot be flagged as view
// bytes4(keccak256("admin()")) == 0xf851a440
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
require(success);
return abi.decode(returndata, (address));
}

/**
* @dev Changes the admin of `proxy` to `newAdmin`.
*
* Requirements:
*
* - This contract must be the current admin of `proxy`.
*/
function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
proxy.changeAdmin(newAdmin);
}

/**
* @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
proxy.upgradeTo(implementation);
}

/**
* @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
* {TransparentUpgradeableProxy-upgradeToAndCall}.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function upgradeAndCall(
TransparentUpgradeableProxy proxy,
address implementation,
bytes memory data
) public payable virtual onlyOwner {
proxy.upgradeToAndCall{ value: msg.value }(implementation, data);
}
}
10 changes: 10 additions & 0 deletions contracts/interfaces/external/euler/IEuler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,16 @@ interface IEulerEToken is IEulerConstants {
/// @param subAccountId 0 for primary, 1-255 for a sub-account
/// @param amount In underlying units (use max uint256 for full pool balance)
function withdraw(uint256 subAccountId, uint256 amount) external;

/// @notice Convert an eToken balance to an underlying amount, taking into account current exchange rate
/// @param balance eToken balance, in internal book-keeping units (18 decimals)
/// @return Amount in underlying units, (same decimals as underlying token)
function convertBalanceToUnderlying(uint256 balance) external view returns (uint256);

/// @notice Convert an underlying amount to an eToken balance, taking into account current exchange rate
/// @param underlyingAmount Amount in underlying units (same decimals as underlying token)
/// @return eToken balance, in internal book-keeping units (18 decimals)
function convertUnderlyingToBalance(uint256 underlyingAmount) external view returns (uint256);
}

interface IEulerDToken is IEulerConstants {
Expand Down
43 changes: 43 additions & 0 deletions contracts/interfaces/external/euler/IEulerStakingRewards.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.0;

// Original contract can be found under the following link:
// https://github.com/Synthetixio/synthetix/blob/master/contracts/interfaces/IStakingRewards.sol
interface IEulerStakingRewards {
// Views

function balanceOf(address account) external view returns (uint256);

function earned(address account) external view returns (uint256);

function getRewardForDuration() external view returns (uint256);

function lastTimeRewardApplicable() external view returns (uint256);

function rewardPerToken() external view returns (uint256);

function rewardRate() external view returns (uint256);

function totalSupply() external view returns (uint256);

function periodFinish() external view returns (uint256);

// Mutative

function exit() external;

function exit(uint256 subAccountId) external;

function getReward() external;

function stake(uint256 amount) external;

function stake(uint256 subAccountId, uint256 amount) external;

function withdraw(uint256 amount) external;

function withdraw(uint256 subAccountId, uint256 amount) external;

function notifyRewardAmount(uint256 reward) external;
}
23 changes: 23 additions & 0 deletions contracts/interfaces/external/uniswap/IUniswapV3Pool.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.5.0;

/// @title Pool state that is not stored
/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the
/// blockchain. The functions here may have variable gas costs.
interface IUniswapV3Pool {
/// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp
/// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing
/// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,
/// you must call it with secondsAgos = [3600, 0].
/// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in
/// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.
/// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned
/// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp
/// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block
/// timestamp
function observe(uint32[] calldata secondsAgos)
external
view
returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ contract AaveFlashloanStrategy is BaseStrategyUpgradeable, IERC3156FlashBorrower

/// @notice Router used for swaps
// solhint-disable-next-line
address private constant _oneInch = 0x1111111254fb6c44bAC0beD2854e76F90643097d;
address private constant _oneInch = 0x1111111254EEB25477B68fb85Ed929f73A960582;
/// @notice Chainlink oracle used to fetch data
// solhint-disable-next-line
AggregatorV3Interface private constant _chainlinkOracle =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ abstract contract GenericLenderBaseUpgradeable is IGenericLender, AccessControlA
// ======================= References to contracts =============================

// solhint-disable-next-line
address internal constant oneInch = 0x1111111254fb6c44bAC0beD2854e76F90643097d;
address internal constant oneInch = 0x1111111254EEB25477B68fb85Ed929f73A960582;

// ========================= References and Parameters =========================

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

pragma solidity ^0.8.17;

import "../../../interfaces/external/frax/IFraxUnifiedFarmTemplate.sol";
import "../../../interfaces/external/convex/frax/IBoosterFrax.sol";
import "../../../interfaces/external/convex/frax/IPoolRegistryFrax.sol";
import "../../../interfaces/external/convex/frax/IFeeRegistryFrax.sol";
import "../../../interfaces/external/convex/frax/IStakingProxyERC20.sol";
import "../../../../interfaces/external/frax/IFraxUnifiedFarmTemplate.sol";
import "../../../../interfaces/external/convex/frax/IBoosterFrax.sol";
import "../../../../interfaces/external/convex/frax/IPoolRegistryFrax.sol";
import "../../../../interfaces/external/convex/frax/IFeeRegistryFrax.sol";
import "../../../../interfaces/external/convex/frax/IStakingProxyERC20.sol";

import "./GenericAaveUpgradeable.sol";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pragma solidity ^0.8.17;

import "../../../interfaces/external/frax/IFraxUnifiedFarmTemplate.sol";
import "../../../../interfaces/external/frax/IFraxUnifiedFarmTemplate.sol";
import "./GenericAaveUpgradeable.sol";

/// @title GenericAaveFraxStaker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ pragma solidity ^0.8.17;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

import { DataTypes, IStakedAave, IReserveInterestRateStrategy } from "../../../interfaces/external/aave/IAave.sol";
import { IProtocolDataProvider } from "../../../interfaces/external/aave/IProtocolDataProvider.sol";
import { ILendingPool } from "../../../interfaces/external/aave/ILendingPool.sol";
import { IAaveIncentivesController } from "../../../interfaces/external/aave/IAaveIncentivesController.sol";
import { IAToken, IVariableDebtToken } from "../../../interfaces/external/aave/IAaveToken.sol";
import "./GenericLenderBaseUpgradeable.sol";
import { DataTypes, IStakedAave, IReserveInterestRateStrategy } from "../../../../interfaces/external/aave/IAave.sol";
import { IProtocolDataProvider } from "../../../../interfaces/external/aave/IProtocolDataProvider.sol";
import { ILendingPool } from "../../../../interfaces/external/aave/ILendingPool.sol";
import { IAaveIncentivesController } from "../../../../interfaces/external/aave/IAaveIncentivesController.sol";
import { IAToken, IVariableDebtToken } from "../../../../interfaces/external/aave/IAaveToken.sol";
import "./../GenericLenderBaseUpgradeable.sol";

/// @title GenericAave
/// @author Forked from https://github.com/Grandthrax/yearnV2-generic-lender-strat/blob/master/contracts/GenericLender/GenericAave.sol
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ pragma solidity ^0.8.17;

import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

import "../../../interfaces/external/compound/CErc20I.sol";
import "../../../interfaces/external/compound/IComptroller.sol";
import "../../../interfaces/external/compound/InterestRateModel.sol";
import "../../../../interfaces/external/compound/CErc20I.sol";
import "../../../../interfaces/external/compound/IComptroller.sol";
import "../../../../interfaces/external/compound/InterestRateModel.sol";

import "./GenericLenderBaseUpgradeable.sol";
import "./../GenericLenderBaseUpgradeable.sol";

/// @title GenericCompoundV3
/// @author Forked from here: https://github.com/Grandthrax/yearnV2-generic-lender-strat/blob/master/contracts/GenericLender/GenericCompound.sol
Expand Down
Loading

0 comments on commit a339610

Please sign in to comment.