Skip to content

Commit

Permalink
Merge 32b130d into bff8877
Browse files Browse the repository at this point in the history
  • Loading branch information
PierrickGT committed Jul 14, 2021
2 parents bff8877 + 32b130d commit e31d6ae
Show file tree
Hide file tree
Showing 21 changed files with 1,915 additions and 1,355 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
abis
artifacts
cache
deployments/localhost/
node_modules
types
deployments/localhost/

# Solidity Coverage
coverage
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
types
6 changes: 6 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"printWidth": 100,
"singleQuote": true,
"trailingComma": "all",
"tabWidth": 2
}
9 changes: 2 additions & 7 deletions Constant.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
export const ADAI_ADDRESS_KOVAN = '0xdCf0aF9e59C002FA3AA091a46196b37530FD48a8';
export const LENDING_POOL_ADDRESSES_PROVIDER_REGISTRY_ADDRESS_KOVAN =
'0x1E40B561EC587036f9789aF83236f057D1ed2A90';

export const USDC_VAULT_ADDRESS_MAINNET = '0x5f18C75AbDAe578b483E5F43f12a39cF75b973a9';
export const USDC_ADDRESS_MAINNET =
'0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
export const USDC_ADDRESS_MAINNET = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';

export const DAI_VAULT_ADDRESS_MAINNET = '0x19D3364A399d251E894aC732651be8B0E4e85001';
export const DAI_ADDRESS_MAINNET = '0x6B175474E89094C44Da98b954EedeAC495271d0F';
Expand All @@ -14,4 +9,4 @@ export const BINANCE7_ADDRESS = '0xBE0eB53F46cd790Cd13851d5EFf43D12404d33E8';
export const DAI_RICH_ADDRESS = '0xF977814e90dA44bFA03b6295A0616a897441aceC';
export const USDC_RICH_ADDRESS = '0x55FE002aefF02F77364de339a1292923A15844B8';

export const YEARN_GOV_ADDRESS = '0x0';
export const YEARN_GOV_ADDRESS = '0x0';
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@

<br />

# PoolTogether YearnV2 Yield Source 👻

[![Coverage Status](https://coveralls.io/repos/github/jmonteer/pooltogether-yearnv2-yield-source/badge.svg?branch=master)](https://coveralls.io/github/jmonteer/pooltogether-yearnv2-yield-source?branch=master) [![built-with openzeppelin](https://img.shields.io/badge/built%20with-OpenZeppelin-3677FF)](https://docs.openzeppelin.com/) [![Coveralls](https://github.com/jmonteer/pooltogether-yearnv2-yield-source/actions/workflows/main.yml/badge.svg)](https://github.com/jmonteer/pooltogether-yearnv2-yield-source/actions/workflows/main.yml)
# PoolTogether YearnV2 Yield Source

[![Coverage Status](https://coveralls.io/repos/github/pooltogether/pooltogether-yearnv2-yield-source/badge.svg?branch=master)](https://coveralls.io/github/pooltogether/pooltogether-yearnv2-yield-source?branch=master)
[![Coveralls](https://github.com/pooltogether/pooltogether-yearnv2-yield-source/actions/workflows/main.yml/badge.svg)](https://github.com/pooltogether/pooltogether-yearnv2-yield-source/actions/workflows/main.yml)
[![built-with openzeppelin](https://img.shields.io/badge/built%20with-OpenZeppelin-3677FF)](https://docs.openzeppelin.com/)

PoolTogether Yield Source that uses [Yearn](https://yearn.finance/) V2 to generate yield by depositing the deposit token in any Yearn Vault that accepts that token.

Expand Down Expand Up @@ -89,7 +90,7 @@ Start Mainnet fork in a terminal window with the command:
yarn start-fork
```

In another window, start the scripts to deploy and create a YearnV2 Yield Source Prize Pool, deposit USDC into it, send some profit to the Vault, award the prize and withdraw.
In another window, start the scripts to deploy and create a YearnV2 Yield Source Prize Pool, deposit USDC into it, send some profit to the Vault, award the prize and withdraw.

```
yarn deploy-fork && yarn run-fork
Expand Down
4 changes: 2 additions & 2 deletions contracts/external/yearn/IYVaultV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ interface IYVaultV2 is IERC20 {

function withdraw(uint256 maxShares) external returns (uint256);

// function withdraw(uint256 maxShares, address recipient) external returns (uint256);
function withdraw(uint256 maxShares, address recipient) external returns (uint256);

function withdraw(uint256 maxShares, address recipient, uint256 maxLoss) external returns (uint256);

Expand Down Expand Up @@ -118,4 +118,4 @@ interface IYVaultV2 is IERC20 {
* is subject to guardian defined by the Vault.
*/
function guardian() external view returns (address);
}
}
35 changes: 0 additions & 35 deletions contracts/test/YearnV2YieldSourceProxyFactoryHarness.sol

This file was deleted.

134 changes: 95 additions & 39 deletions contracts/yield-source/YearnV2YieldSource.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/SafeERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";


Expand All @@ -18,13 +19,16 @@ import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol
/// @dev are not compatible, as they had dips in shareValue due to a small miscalculation
/// @notice Yield Source Prize Pools subclasses need to implement this interface so that yield can be generated.
contract YearnV2YieldSource is IYieldSource, ERC20Upgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable {
using AddressUpgradeable for address;
using SafeERC20Upgradeable for IERC20Upgradeable;
using SafeMathUpgradeable for uint;

/// @notice Yearn Vault which manages `token` to generate yield
IYVaultV2 public vault;

/// @dev Deposit Token contract address
IERC20Upgradeable internal token;
IERC20Upgradeable internal token;

/// @dev Max % of losses that the Yield Source will accept from the Vault in BPS
uint256 public maxLosses = 0; // 100% would be 10_000

Expand All @@ -33,11 +37,13 @@ contract YearnV2YieldSource is IYieldSource, ERC20Upgradeable, OwnableUpgradeabl
address indexed user,
uint256 amount
);

/// @notice Emitted when the yield source is initialized
event YieldSourceYearnV2Initialized(
event YearnV2YieldSourceInitialized(
IYVaultV2 vault,
IERC20Upgradeable token
uint8 decimals,
string symbol,
string name
);

/// @notice Emitted when the Max Losses accepted when withdrawing from yVault are changed
Expand All @@ -60,44 +66,81 @@ contract YearnV2YieldSource is IYieldSource, ERC20Upgradeable, OwnableUpgradeabl
uint256 amount
);

/// @notice Initializes the yield source with
/// @param _vault YearnV2 Vault in which the Yield Source will deposit `token` to generate Yield
/// @param _token Underlying Token / Deposit Token
/// @notice Mock Initializer to initialize implementations used by minimal proxies.
function freeze() public initializer {
//no-op
}

/// @notice Initializes the yield source with
/// @param _vault Yearn V2 Vault in which the Yield Source will deposit `token` to generate Yield
/// @param _decimals Number of decimals the shares (inherited ERC20) will have. Same as underlying asset to ensure same ExchangeRates.
/// @param _symbol Token symbol for the underlying ERC20 shares (eg: yvysDAI).
/// @param _name Token name for the underlying ERC20 shares (eg: PoolTogether Yearn V2 Vault DAI Yield Source).
function initialize(
IYVaultV2 _vault,
IERC20Upgradeable _token
)
public
uint8 _decimals,
string calldata _symbol,
string calldata _name
)
public
initializer
returns (bool)
{
require(address(vault) == address(0), "YearnV2YieldSource:: already initialized");
require(_vault.token() == address(_token), "YearnV2YieldSource:: incorrect vault");
require(_vault.activation() != uint256(0), "YearnV2YieldSource:: vault not initialized");
require(address(_vault) != address(0), "YearnV2YieldSource/vault-not-zero-address");
require(_vault.activation() != uint256(0), "YearnV2YieldSource/vault-not-initialized");

// NOTE: Vaults from 0.3.2 to 0.3.4 have dips in shareValue
require(!areEqualStrings(_vault.apiVersion(), "0.3.2"), "YearnV2YieldSource:: vault not compatible");
require(!areEqualStrings(_vault.apiVersion(), "0.3.3"), "YearnV2YieldSource:: vault not compatible");
require(!areEqualStrings(_vault.apiVersion(), "0.3.4"), "YearnV2YieldSource:: vault not compatible");
string memory _vaultAPIVersion = _vault.apiVersion();

require(!_areEqualStrings(_vaultAPIVersion, "0.3.2"), "YearnV2YieldSource/vault-not-compatible");
require(!_areEqualStrings(_vaultAPIVersion, "0.3.3"), "YearnV2YieldSource/vault-not-compatible");
require(!_areEqualStrings(_vaultAPIVersion, "0.3.4"), "YearnV2YieldSource/vault-not-compatible");

vault = _vault;
token = _token;
token = IERC20Upgradeable(_vault.token());

__Ownable_init();
__ReentrancyGuard_init();

_token.safeApprove(address(vault), type(uint256).max);
__ERC20_init(_name, _symbol);
require(_decimals > 0, "YearnV2YieldSource/decimals-not-greater-than-zero");
_setupDecimals(_decimals);

emit YieldSourceYearnV2Initialized(
token.safeApprove(address(_vault), type(uint256).max);

emit YearnV2YieldSourceInitialized(
_vault,
_token
_decimals,
_symbol,
_name
);

return true;
}

function setMaxLosses(uint256 _maxLosses) external onlyOwner {
require(_maxLosses <= 10_000, "YearnV2YieldSource:: losses set too high");
/// @notice Approve vault contract to spend max uint256 amount
/// @dev Emergency function to re-approve max amount if approval amount dropped too low
/// @return true if operation is successful
function approveMaxAmount() external onlyOwner returns (bool) {
address _vault = address(vault);
IERC20Upgradeable _token = token;
uint256 allowance = _token.allowance(address(this), _vault);

_token.safeIncreaseAllowance(_vault, type(uint256).max.sub(allowance));
return true;
}

/// @notice Sets the maximum acceptable loss to sustain on withdrawal.
/// @dev This function is only callable by the owner of the yield source.
/// @param _maxLosses Max Losses in double decimal precision.
/// @return True if maxLosses was set successfully.
function setMaxLosses(uint256 _maxLosses) external onlyOwner returns(bool) {
require(_maxLosses <= 10_000, "YearnV2YieldSource/losses-set-too-high");

maxLosses = _maxLosses;

emit MaxLossesChanged(_maxLosses);
return true;
}

/// @notice Returns the ERC20 asset token used for deposits
Expand Down Expand Up @@ -168,9 +211,12 @@ contract YearnV2YieldSource is IYieldSource, ERC20Upgradeable, OwnableUpgradeabl
/// @return The actual amount of shares that were received for the deposited tokens
function _depositInVault() internal returns (uint256) {
IYVaultV2 v = vault; // NOTE: for gas usage
if(token.allowance(address(this), address(v)) < token.balanceOf(address(this))) {
token.safeApprove(address(v), type(uint256).max);
IERC20Upgradeable _token = token;

if (_token.allowance(address(this), address(v)) < _token.balanceOf(address(this))) {
_token.safeApprove(address(v), type(uint256).max);
}

// this will deposit full balance (for cases like not enough room in Vault)
return v.deposit();
}
Expand All @@ -181,17 +227,23 @@ contract YearnV2YieldSource is IYieldSource, ERC20Upgradeable, OwnableUpgradeabl
/// @param amount amount of asset tokens to be redeemed
/// @return Tokens received from the Vault
function _withdrawFromVault(uint amount) internal returns (uint256) {
IERC20Upgradeable _token = token;
IYVaultV2 _vault = vault;
uint256 yShares = _tokenToYShares(amount);
uint256 previousBalance = token.balanceOf(address(this));
uint256 previousBalance = _token.balanceOf(address(this));

// we accept losses to avoid being locked in the Vault (if losses happened for some reason)
if(maxLosses != 0) {
vault.withdraw(yShares, address(this), maxLosses);
uint256 _maxLosses = maxLosses;

if (_maxLosses != 0) {
_vault.withdraw(yShares, address(this), _maxLosses);
} else {
vault.withdraw(yShares);
_vault.withdraw(yShares, address(this));
}
uint256 currentBalance = token.balanceOf(address(this));

return previousBalance.sub(currentBalance);
uint256 currentBalance = _token.balanceOf(address(this));

return currentBalance.sub(previousBalance);
}

/// @notice Returns the amount of shares of yearn's vault that the Yield Source holds
Expand Down Expand Up @@ -222,7 +274,7 @@ contract YearnV2YieldSource is IYieldSource, ERC20Upgradeable, OwnableUpgradeabl
}

/// @notice Support function to retrieve used by Vault
/// @dev used to correctly scale prices
/// @dev used to correctly scale prices
/// @return decimals of vault's shares (and underlying token)
function _vaultDecimals() internal view returns (uint256) {
return vault.decimals();
Expand All @@ -237,7 +289,7 @@ contract YearnV2YieldSource is IYieldSource, ERC20Upgradeable, OwnableUpgradeabl
return tokens.mul(10 ** _vaultDecimals()).div(_pricePerYShare());
}

/// @notice Converter from deposit yShares (yearn vault's shares) to token
/// @notice Converter from deposit yShares (yearn vault's shares) to token
/// @param yShares Vault's shares to be converted
/// @return tokens that will be received if yShares shares are redeemed
function _ySharesToToken(uint256 yShares) internal view returns (uint256) {
Expand All @@ -248,11 +300,13 @@ contract YearnV2YieldSource is IYieldSource, ERC20Upgradeable, OwnableUpgradeabl
/// @param tokens amount of tokens to be converted
/// @return shares number of shares equivalent to the amount of tokens
function _tokenToShares(uint256 tokens) internal view returns (uint256 shares) {
if(totalSupply() == 0) {
uint256 _totalSupply = totalSupply();

if (_totalSupply == 0) {
shares = tokens;
} else {
uint256 _totalTokens = _totalAssetsInToken();
shares = tokens.mul(totalSupply()).div(_totalTokens);
shares = tokens.mul(_totalSupply).div(_totalTokens);
}
}

Expand All @@ -261,19 +315,21 @@ contract YearnV2YieldSource is IYieldSource, ERC20Upgradeable, OwnableUpgradeabl
/// @dev used to calculate how many shares to mint / burn when depositing / withdrawing
/// @return tokens number of tokens equivalent (in value) to the amount of Yield Source shares
function _sharesToToken(uint256 shares) internal view returns (uint256 tokens) {
if(totalSupply() == 0) {
uint256 _totalSupply = totalSupply();

if (_totalSupply == 0) {
tokens = shares;
} else {
uint256 _totalTokens = _totalAssetsInToken();
tokens = shares.mul(_totalTokens).div(totalSupply());
tokens = shares.mul(_totalTokens).div(_totalSupply);
}
}

/// @notice Pure support function to compare strings
/// @param a One string
/// @param b Another string
/// @return Whether or not the strings are the same or not
function areEqualStrings(string memory a, string memory b) internal pure returns (bool) {
function _areEqualStrings(string memory a, string memory b) internal pure returns (bool) {
return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));
}
}
}
34 changes: 0 additions & 34 deletions contracts/yield-source/YearnV2YieldSourceProxyFactory.sol

This file was deleted.

Loading

0 comments on commit e31d6ae

Please sign in to comment.