From 5d5cb4b842b5c7f787cf408a20c82d73f3d239cf Mon Sep 17 00:00:00 2001 From: Anton Buenavista Date: Mon, 30 May 2022 19:21:37 +0800 Subject: [PATCH 1/8] Add EIP-5115: Super Composable Yield Token Standard --- EIPS/eip-5115.md | 409 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 409 insertions(+) create mode 100644 EIPS/eip-5115.md diff --git a/EIPS/eip-5115.md b/EIPS/eip-5115.md new file mode 100644 index 00000000000000..83995930c98216 --- /dev/null +++ b/EIPS/eip-5115.md @@ -0,0 +1,409 @@ +--- +EIP: +Title: Super Composable Yield Token Standard +Description: A standard for wrapped yield-generating tokens. +Author: Vu Nguyen (@mrenoon), Long Vuong (@UncleGrandpa925), Anton Buenavista (@ayobuenavista) +Discussions-To: https://ethereum-magicians.org/t/ +Status: Draft +Type: Standards Track +Category: ERC +Created: 2022-05-30 +Requires: 20 +--- + +## Abstract + +This standard allows for the implementation of a standardized API for wrapped yield-generating tokens within smart contracts. This standard is an extension on the ERC-20 token that provides basic functionality for transferring, depositing, withdrawing tokens, and reading balances. + +## Motivation + +Yield generating mechanisms are built in all shapes and sizes, necessitating a manual integration every time a protocol builds on top of another protocol’s yield generating mechanism. + +[ERC-4626](https://eips.ethereum.org/EIPS/eip-4626) tackled a significant part of this fragmentation by standardizing the interfaces for vaults, a major category among various yield-generating mechanisms. + +In this EIP, we’re extending the coverage to include assets beyond ERC4626’s reach, namely: +- Yield-generating assets that have different base tokens used for minting vs accounting for the pool value. + - This category includes AMM liquidity tokens (which are yield generating assets that yield swap fees) since the value of the pool is measured in “liquidity units” (for example, $\sqrt k$ in UniswapV2, as defined in UniswapV2 whitepaper) which can’t be deposited in (as they are not tokens). + - This extends the flexibility in minting the yield-bearing assets. For example, there could be an ETH vault that wants to allow users to deposit cETH directly instead of ETH, for gas efficiency or UX reasons. +- Assets with reward tokens by default (e.g. COMP rewards for supplying in Compound). The reward tokens are expected to be sold to compound into the same asset. + +While ERC-4626 is a well-designed and suitable standard for most vaults, there will inevitably be some yield-generating mechanisms that do not fit into their category (LP tokens for instance). A more flexible standard is required to standardize the interaction with all types of yield generating mechanisms. + +Therefore, we are proposing Super Composable Yield (SCY), a flexible standard for wrapped yield generating tokens that could cover most mechanisms in DeFi. We foresee that: + +- ERC-4626 will still be a popular vault standard, that most vaults should adopt. +- SCY tokens can wrap over most yield generating mechanisms in DeFi, including ERC-4626 vaults for projects built on top of interest-bearing tokens. +- Whoever needs the functionalities of SCY could integrate with the existing SCY tokens or write a new SCY (to wrap over the target interest-bearing token). + + +## Specification + +### Generic Yield Generating Pool + +We will first introduce Generic Yield Generating Pool (GYGP), a model to describe most yield generating mechanisms in DeFi. In every yield generating mechanism, there is a pool of funds, whose value is measured in **assets**. There are a number of users who contribute liquidity to the pool, in exchange for **shares** of the pool, which represents units of ownership of the pool. Over time, the value (measured in **assets**) of the pool grows, such that each **share** is worth more **assets** over time. The pool could earn a number of **reward tokens** over time, which are distributed to the users according to some logic (For example, proportionally the number of **shares**). + +Here are the more concrete definitions of the terms: + +#### Definitions: + +- **asset**: Is a unit to measure the value of the pool. At time *t*, the pool has a total value of *TotalAsset(t)* **assets**. +- **shares**: Is a unit that represents ownership of the pool. At time *t*, there are *TotalShares(t)* **shares** in total. +- **reward tokens**: Over time, the pool earns $n_{rewards}$ types of reward tokens $(n_{rewards} \ge 0)$. At time *t*, $TotalRewards_i(t)$ is the amount of **reward token *i*** that has accumulated for the pool up until time *t*. +- **exchange rate**: At time *t*, the **exchange rate** *ExchangeRate(t)* is simply how many **assets** each **shares** is worth $ExchangeRate(t) = \frac{TotalAsset(t)}{TotalShares(t)}$ +- **users**: At time *t*, each user *u* has $shares_u(t)$ **shares** in the pool, which is worth $asset_u(t) = shares_u(t) \cdot ExchangeRate(t)$ **assets**. Until time *t*, user *u* is entitled to receive a total of $rewards_{u_i}(t)$ **reward token *i***. The sum of all users’ shares, assets and rewards should be the same as the total shares, assets and rewards of the whole pool. + +#### State changes: + +1. A user deposits **assets** into the pool, in exchange for new **shares** that will be created for the user, proportionally to the asset amount being deposited compared to the value of the pool. +2. A user withdraws **assets** from the pool, by burning their **shares**, proportionally to the asset amount being burned compared to the value of the pool +3. The pool earns some **assets**. The **exchange rate** will simply increase due to the additional **assets.** +4. The pool earns some **reward tokens**. The additional reward tokens will be distributed among the users. + +#### Examples of GYGPs in DeFi: + +| Yield generating mechanism | Asset | Shares | Reward tokens | Exchange rate | +| --- | --- | --- | --- | --- | +| Supply USDC in Compound | USDC | cUSDC | COMP | USDC value per cUSDC, increases with USDC supply interests | +| ETH liquid staking in Lido | stETH | wstETH | None | stETH value per wstETH, increases with ETH staking rewards | +| Stake LOOKS in LooksRare | LOOKS | shares (in contract) | WETH | LOOKS value per shares, increases with LOOKS rewards | +| Stake BTRFLY into xBTRFLY | BTRFLY | xBTRFLY | None | BTRFLY value per xBTRFLY, increases due to rebase rewards | +| Provide ETH+USDC liquidity on Sushiswap | ETHUSDC liquidity (a pool of x ETH + y USDC has sqrt(xy) ETHUSDC liquidity) | ETHUSDC Sushiswap LP (SLP) token | None | ETHUSDC liquidity value per ETHUSDC SLP, increases due to swap fees | +| Provide ETH+USDC liquidity on Sushiswap and stake into Onsen | ETHUSDC liquidity (a pool of x ETH + y USDC has sqrt(xy) ETHUSDC liquidity) | ETHUSDC Sushiswap LP (SLP) token | SUSHI | ETHUSDC liquidity value per ETHUSDC SLP, increases due to swap fees | +| Provide USDC+USDT+DAI liquidity in Curve | 3crv pool’s liquidity (amount of D per 3crv token) | 3crv token | CRV | 3crv pool’s liquidity per 3crv token, increases due to swap fees | +| Provide BAL+WETH liquidity in Balancer (80% BAL, 20% WETH) | BALWETH liquidity (a pool of x BAL + y WETH has x^0.8*y^0.2 BALWETH liquidity) | BALWETH Balancer LP token | None | BALWETH liquidity per BALWETH Balancer LP token, increases due to swap fees | + +### Super Composable Yield Token Standard + +#### Overview + +Super Composable Yield is a token standard for all GYGPs. Each Super Composable Yield token represents **shares** in a GYGP and allows for interacting with the GYGP via a standard interface + +All SCY tokens: + +- **MUST** implement **`ERC20`** to represent shares in the underlying GYGP. +- **MUST** implement ERC-20’s optional metadata extensions `name`, `symbol`, and `decimals`, which **SHOULD** reflect the underlying GYGP’s accounting asset’s `name`, `symbol`, and `decimals`. +- **MAY** revert on calls to `transfer` and `transferFrom` if a SCY token is to be non-transferable. +- The ERC-20 operations `balanceOf`, `transfer`, `totalSupply`, etc. **SHOULD** operate on the GYGP “shares”, which represent a claim to ownership on a fraction of the GYGP’s underlying holdings. + +#### Definition of base tokens + +Base tokens are tokens that could be deposited to mint SCY tokens (and hence, to enter the underlying GYGP), or redeemed when burning SCY tokens (and hence, exiting the underlying GYGP). Essentially, base tokens are implicitly converted into units of **assets** when deposited or redeemed, to conform to state change #1 and #2 of the GYGP definition above. + +There could be multiple base tokens in a SCY. This allows for maximum flexibility in how to mint SCY to enter the underlying yield generating pool. For example, both BAL and WETH (and even BALWETH LP token) could be used to mint the SCY token for BALWETH Balancer pool (by providing single-sided liquidity). + +As such, base tokens are not necessarily the same as the asset (which is a key difference between SCY and ERC-4626). + +#### Interface + +```solidity +interface ISuperComposableYield is IERC20Metadata { + enum AssetType { + TOKEN, + LIQUIDITY + } + + event Deposit( + address indexed caller, + address indexed receiver, + address indexed tokenIn, + uint256 amountDeposited, + uint256 amountScyOut + ); + + event Redeem( + address indexed caller, + address indexed receiver, + address indexed tokenOut, + uint256 amountScyToRedeem, + uint256 amountTokenOut + ); + + event ClaimRewards( + address indexed caller, + address indexed user, + address[] rewardTokens, + uint256[] rewardAmounts + ); + + event ExchangeRateUpdated(uint256 oldExchangeRate, uint256 newExchangeRate); + + function deposit( + address receiver, + address tokenIn, + uint256 amountTokenToPull, + uint256 minSharesOut + ) external returns (uint256 amountSharesOut); + + function redeem( + address receiver, + uint256 amountSharesToPull, + address tokenOut, + uint256 minTokenOut + ) external returns (uint256 amountTokenOut); + + function claimRewards(address user) external returns (uint256[] memory rewardAmounts); + + function exchangeRateCurrent() external returns (uint256); + + function exchangeRateStored() external view returns (uint256); + + function getRewardTokens() external view returns (address[] memory); + + function getBaseTokens() external view returns (address[] memory); + + function yieldToken() external view returns (address); + + function isValidBaseToken(address token) external view returns (bool); + + function assetInfo() + external + view + returns ( + AssetType assetType, + address assetAddress, + uint8 assetDecimals + ); +} +``` + +#### Methods + +```solidity +function deposit( + address receiver, + address tokenIn, + uint256 amountTokenToPull, + uint256 minSharesOut +) external returns (uint256 amountSharesOut); +``` + +This method will first pull `amountTokenToPull` of `tokenIn` (a **base token**), and use the floating amount `tokenIn` in the SCY contract to deposit to mint new **shares**. + +The ideal way to deposit is to send `tokenIn` in first, then call the `deposit` function with `amountTokenToPull = 0`. This pattern is similar to UniswapV2 (and UniswapV3) pools, which allow for better composability and gas efficiency by minimizing token transfers. For example, a router contract could swap from some other token to `tokenIn` which is sent directly to the SCY contract before `deposit` is called. + +This function will convert the amount of `tokenIn` into some worth of **assets** and deposit this amount into the SCY contract for the recipient, who will receive `amountSharesOut` of SCY tokens (**shares**). + +- **MUST** emit the `Deposit` event. +- **MUST** support ERC-20’s `approve` / `transferFrom` flow where `tokenIn` are taken from receiver directly (as msg.sender) or if the msg.sender has ERC-20 approved allowance over the base token of the receiver. +- **MUST** revert if $amountSharesOut \lt minSharesOut$ (due to deposit limit being reached, slippage, or the user not approving enough `tokenIn` **to the SCY contract, etc). + +```solidity +function redeem( + address receiver, + uint256 amountSharesToPull, + address tokenOut, + uint256 minTokenOut +) external returns (uint256 amountTokenOut); +``` + +This method will first pull `amountSharesToPull` of SCY tokens, and use the floating amount of SCY tokens in the SCY contract to redeem to `tokenOut` (a **base token**). This pattern is similar to the one in `deposit` + +This function will redeem the exact SCY token (**shares**) from the SCY contract. The **assets** are converted into `tokenOut` of `tokenOut`. + +- **MUST** emit the `Redeem` event. +- **MUST** support ERC-20’s `approve` / `transferFrom` flow where the shares are burned from receiver directly (as msg.sender) or if the msg.sender has ERC-20 approved allowance over the shares of the receiver. +- **MUST** revert if $tokenOut \lt minTokenOut$ (due to redeem limit being reached, slippage, or the user not approving enough `amountSharesToPull` **to the SCY contract, etc). + +```solidity +function claimRewards(address user) external returns (uint256[] memory rewardAmounts); +``` + +This method sends all the available claimable rewards to the user as is, with the amounts in the list being in the same order as `getRewardTokens`. + +- **MUST** emit the `ClaimRewards` event. +- **MAY** return one or multiple rewards to the user. +- **MAY** return zero rewards to the user. + +```solidity +function exchangeRateCurrent() external returns (uint256); +``` + +This method updates and returns the latest **exchange rate**, which is the **exchange rate** from SCY token amount into asset amount, scaled by a fixed scaling factor of 1e18. + +- **MUST** return $ExchangeRate(t_{now})$ such that $ExchangeRate(t_{now}) \times scyBalance / 1e18 = assetBalance$. +- **MUST NOT** include fees that are charged against the underlying yield token in the SCY contract. + +```solidity +function exchangeRateStored() external view returns (uint256); +``` + +This read-only method returns the last saved value of the exchange rate. + +- **MUST** return the value of `exchangeRateCurrent` of a past timestamp where it was last updated in the contract +- **MUST NOT** include fees that are charged against the underlying yield token in the SCY contract. +- **MUST NOT** revert. + +```solidity +function yieldToken() external view returns (address); +``` + +This read-only method returns the underlying yield-generating token (representing a GYGP) that was wrapped into a SCY token. + +- **MUST** return a token address that conforms to the ERC-20 interface, or zero address +- **MUST NOT** revert. +- **MUST** reflect the exact underlying yield-generating token address if the SCY token is a wrapped token. +- **MAY** return 0x or zero address if the SCY token is natively implemented, and not from wrapping. + +```solidity +function getRewardTokens() external view returns (address[] memory); +``` + +This read-only method returns the latest list of all reward tokens. + +- **MUST** return ERC-20 token addresses. +- **MUST NOT** revert. +- **MAY** return an empty list, one, or several token addresses. +- **MAY** return additional reward tokens over time, depending on when `underlyingYieldToken` supports more or less reward tokens. + +```solidity +function getBaseTokens() external view returns (address[] memory); +``` + +This read-only method returns the list of all base tokens that can be used to deposit into the SCY contract. + +- **MUST** return ERC-20 token addresses. +- **MUST** return at least one address. +- **MUST NOT** revert. + +```solidity +function isValidBaseToken(address token) external view returns (bool); +``` + +This read-only method checks whether a token address entered is a base token that can be used to mint SCY. + +- **MUST NOT** revert. + +```solidity +function assetInfo() + external + view + returns ( + AssetType assetType, + address assetAddress, + uint8 assetDecimals + ); +``` + +This read-only function returns useful information about the asset, intended for front-ends or off-chain systems to display balances and information about the asset. + +`decimals` is the decimals to format asset balances. + +Convention for `assetType` and format of the `info` field: 1) If asset is an ERC20 token, `assetType = 0`, `assetAddress` is the address of the token; 2) If asset is liquidity of an AMM (like $\sqrt{k}$ in UniswapV2 forks), `assetType = 1`, `assetAddress` is the address of the LP token. + +* **MUST** reflect the underlying asset’s decimals if at all possible in order to eliminate any possible source of confusion or be deemed malicious. +- **MUST** conform to the conventions for assetType and info. +- **MUST NOT** revert. + +#### Events + +```solidity +event Deposit( + address indexed caller, + address indexed receiver, + address indexed tokenIn, + uint256 amountDeposited, + uint256 amountScyOut +); +``` + +`caller` has converted exact base tokens into SCY (shares) and transferred those SCY to `receiver`. + +- **MUST** be emitted when base tokens are deposited into the SCY contract via `deposit` method. + +```solidity +event Redeem( + address indexed caller, + address indexed receiver, + address indexed tokenOut, + uint256 amountScyToRedeem, + uint256 amountTokenOut +); +``` + +`caller` has converted exact SCY (shares) into base tokens and transferred those base tokens to `receiver`. + +- **MUST** be emitted when base tokens are redeemed from the SCY contract via `redeem` method. + +```solidity +event ClaimRewards( + address indexed caller, + address indexed user, + address[] rewardTokens, + uint256[] rewardAmounts +); +``` + +`caller` has claimed user rewards and transferred them to the user. + +- **MUST** be emitted when rewards are claimed from the SCY contract via `claimRewards` method. + +```solidity +event ExchangeRateUpdated(uint256 oldExchangeRate, uint256 newExchangeRate); +``` + +The `exchangeRateCurrent` is updated to the latest exchange rate. + +- **MUST** be emitted when the exchange rate is updated in the SCY contract via `exchangeRateCurrent` method. + +**"SCY" Word Choice:** + +"SCY" (pronunciation: */sʌɪ/*), an abbreviation of Super Composable Yield, was found to be appropriate to describe a broad universe of composable yield-bearing digital assets. + +## Rationale + +This EIP is designed for flexibility, aiming to accommodate as many yield generating mechanisms as possible. Particularly, this standard aims to be generalized enough that it supports the following uses cases and more: + +- Money market supply positions + - Lending DAI in Compound, getting DAI interests and COMP rewards + - Lending ETH in BenQi, getting ETH interests and QI + AVAX rewards + - Lending USDC in Aave, getting USDC interests and stkAAVE rewards +- AMM liquidity provision + - Provide ETH + USDC to ETHUSDC pool in SushiSwap, getting swap fees in more ETH+USDC + - Provide ETH + USDC to ETHUSDC pool in SushiSwap and stake it in Sushi Onsen, getting swap fees and SUSHI rewards + - Provide USDC+DAI+USDT to 3crv pool and stake it in Convex, getting 3crv swap fees and CRV + CVX rewards +- Vault positions + - Provide ETH into Yearn ERC-4626 vault, where the vault accrues yield from Yearn’s ETH strategy + - Provide DAI into Harvest and staking it, getting DAI interests and FARM rewards +- Liquid staking positions + - Holding stETH (in Lido), getting yields in more stETH +- Liquidity mining programs + - Provide USDC in Stargate, getting STG rewards + - Provide FEI in Tokemak, getting TOKE rewards + - Provide LOOKS in LooksRare, getting LOOKS yield and WETH rewards +- Rebasing tokens + - Stake OHM into sOHM/gOHM, getting OHM rebase yield + - Stake BTRFLY into xBTRFLY, getting BTRFLY rebase yield + +The EIP hopes to minimize, if not possibly eliminate, the use of customized adapters in order to interact with many different forms of yield-generating token mechanisms. + +ERC-20 is enforced because implementation details such as transfer, token approvals, and balance calculation directly carry over to the SCY tokens. This standardization makes the SCY tokens immediately compatible with all ERC-20 use cases. + +## Backwards Compatibility + +This EIP is fully backwards compatible as its implementation extends the functionality of [ERC-20](https://eips.ethereum.org/EIPS/eip-20), however the optional metadata extensions, namely `name`, `decimals`, and `symbol` semantics MUST be implemented for all SCY token implementations. + +## Reference Implementations + +See [PendleAaveV3SCY](https://github.com/pendle-finance/pendle-scy-sample/tree/main/contracts/SuperComposableYield/PendleSCYImpl/AaveV3): an opinionated implementation of the SCY token standard for AaveV3 tokens. + +See [PendleBenQiSCY](https://github.com/pendle-finance/pendle-scy-sample/blob/main/contracts/SuperComposableYield/SCY-implementations/PendleQiTokenSCY.sol): an opinionated implementation of the SCY token standard for BenQi tokens. + +See [PendleBtrflySCY](https://github.com/pendle-finance/pendle-scy-sample/blob/main/contracts/SuperComposableYield/SCY-implementations/PendleBtrflySCY.sol): an opinionated implementation of the SCY token standard for [Redacted Cartel]’s BTRFLY token. + +See [PendleWstETHSCY](https://github.com/pendle-finance/pendle-scy-sample/blob/main/contracts/SuperComposableYield/SCY-implementations/PendleWstEthSCY.sol): an opinionated implementation of the SCY token standard for stETH token. + +See [PendleYearnVaultSCY](https://github.com/pendle-finance/pendle-scy-sample/blob/main/contracts/SuperComposableYield/SCY-implementations/PendleYearnVaultScy.sol): an opinionated implementation of the SCY token standard for Yearn Vault tokens. + +## Security Considerations + +Malicious implementations which conform to the interface can put users at risk. It is recommended that all integrators review the implementation to avoid possible exploits and users losing funds. + +The method `exchangeRateStored` returns an outdated estimated value and does not confer the exact current exchange rate of asset per share. Should accuracy be needed, `exchangeRateCurrent` should be used instead, and in addition, will update `exchangeRateStored`. + +`decimals` in `assetInfo` must strongly reflect the underlying asset’s decimals if at all possible in order to eliminate any possible source of confusion or be deemed malicious. + +`yieldToken` must strongly reflect the address of the underlying wrapped yield-generating token. For a native implementation wherein the SCY token does not wrap a yield-generating token, but natively represents a GYGP share, then the address returned MAY be a zero address. Otherwise, for wrapped tokens, you may introduce confusion on what the SCY token represents, or may be deemed malicious. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). \ No newline at end of file From 95863741e0604552c7c89491db6e2cb80246e5ad Mon Sep 17 00:00:00 2001 From: Anton Buenavista Date: Mon, 30 May 2022 20:37:40 +0800 Subject: [PATCH 2/8] EIP-5115: Updated EIP number and Discusstions-To --- EIPS/eip-5115.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-5115.md b/EIPS/eip-5115.md index 83995930c98216..17cc3859f8129c 100644 --- a/EIPS/eip-5115.md +++ b/EIPS/eip-5115.md @@ -1,9 +1,9 @@ --- -EIP: +EIP: 5115 Title: Super Composable Yield Token Standard Description: A standard for wrapped yield-generating tokens. Author: Vu Nguyen (@mrenoon), Long Vuong (@UncleGrandpa925), Anton Buenavista (@ayobuenavista) -Discussions-To: https://ethereum-magicians.org/t/ +Discussions-To: https://ethereum-magicians.org/t/eip-5115-super-composable-yield-token-standard/9423 Status: Draft Type: Standards Track Category: ERC From 81e8fe6e950b06e0a4e0c7b9efae5ecba7070b2b Mon Sep 17 00:00:00 2001 From: Anton Buenavista Date: Mon, 30 May 2022 20:43:30 +0800 Subject: [PATCH 3/8] EIP-5115: Fix preamble header --- EIPS/eip-5115.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/EIPS/eip-5115.md b/EIPS/eip-5115.md index 17cc3859f8129c..2eb019e06cc423 100644 --- a/EIPS/eip-5115.md +++ b/EIPS/eip-5115.md @@ -1,14 +1,14 @@ --- -EIP: 5115 -Title: Super Composable Yield Token Standard -Description: A standard for wrapped yield-generating tokens. -Author: Vu Nguyen (@mrenoon), Long Vuong (@UncleGrandpa925), Anton Buenavista (@ayobuenavista) +eip: 5115 +title: Super Composable Yield Token Standard +description: A standard for wrapped yield-generating tokens. +author: Vu Nguyen (@mrenoon), Long Vuong (@UncleGrandpa925), Anton Buenavista (@ayobuenavista) Discussions-To: https://ethereum-magicians.org/t/eip-5115-super-composable-yield-token-standard/9423 -Status: Draft -Type: Standards Track -Category: ERC -Created: 2022-05-30 -Requires: 20 +status: Draft +type: Standards Track +category: ERC +created: 2022-05-30 +requires: 20 --- ## Abstract From 6b6800cc1ab1afaa888610c7e03173c8a48b8b30 Mon Sep 17 00:00:00 2001 From: Anton Buenavista Date: Mon, 30 May 2022 21:07:49 +0800 Subject: [PATCH 4/8] EIP-5115: Fixed links to other EIPs --- EIPS/eip-5115.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EIPS/eip-5115.md b/EIPS/eip-5115.md index 2eb019e06cc423..7425fd0bf1a3ad 100644 --- a/EIPS/eip-5115.md +++ b/EIPS/eip-5115.md @@ -3,7 +3,7 @@ eip: 5115 title: Super Composable Yield Token Standard description: A standard for wrapped yield-generating tokens. author: Vu Nguyen (@mrenoon), Long Vuong (@UncleGrandpa925), Anton Buenavista (@ayobuenavista) -Discussions-To: https://ethereum-magicians.org/t/eip-5115-super-composable-yield-token-standard/9423 +discussions-to: https://ethereum-magicians.org/t/eip-5115-super-composable-yield-token-standard/9423 status: Draft type: Standards Track category: ERC @@ -19,7 +19,7 @@ This standard allows for the implementation of a standardized API for wrapped yi Yield generating mechanisms are built in all shapes and sizes, necessitating a manual integration every time a protocol builds on top of another protocol’s yield generating mechanism. -[ERC-4626](https://eips.ethereum.org/EIPS/eip-4626) tackled a significant part of this fragmentation by standardizing the interfaces for vaults, a major category among various yield-generating mechanisms. +[ERC-4626](./eip-4626.md) tackled a significant part of this fragmentation by standardizing the interfaces for vaults, a major category among various yield-generating mechanisms. In this EIP, we’re extending the coverage to include assets beyond ERC4626’s reach, namely: - Yield-generating assets that have different base tokens used for minting vs accounting for the pool value. @@ -380,7 +380,7 @@ ERC-20 is enforced because implementation details such as transfer, token approv ## Backwards Compatibility -This EIP is fully backwards compatible as its implementation extends the functionality of [ERC-20](https://eips.ethereum.org/EIPS/eip-20), however the optional metadata extensions, namely `name`, `decimals`, and `symbol` semantics MUST be implemented for all SCY token implementations. +This EIP is fully backwards compatible as its implementation extends the functionality of [ERC-20](./eip-20.md), however the optional metadata extensions, namely `name`, `decimals`, and `symbol` semantics MUST be implemented for all SCY token implementations. ## Reference Implementations From a4b6dfd48803c829513d8d006cea360e805c3030 Mon Sep 17 00:00:00 2001 From: Anton Buenavista Date: Mon, 30 May 2022 22:27:56 +0800 Subject: [PATCH 5/8] EIP-5115: Remove reference implementation --- EIPS/eip-5115.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/EIPS/eip-5115.md b/EIPS/eip-5115.md index 7425fd0bf1a3ad..a23480d8665ca7 100644 --- a/EIPS/eip-5115.md +++ b/EIPS/eip-5115.md @@ -382,18 +382,6 @@ ERC-20 is enforced because implementation details such as transfer, token approv This EIP is fully backwards compatible as its implementation extends the functionality of [ERC-20](./eip-20.md), however the optional metadata extensions, namely `name`, `decimals`, and `symbol` semantics MUST be implemented for all SCY token implementations. -## Reference Implementations - -See [PendleAaveV3SCY](https://github.com/pendle-finance/pendle-scy-sample/tree/main/contracts/SuperComposableYield/PendleSCYImpl/AaveV3): an opinionated implementation of the SCY token standard for AaveV3 tokens. - -See [PendleBenQiSCY](https://github.com/pendle-finance/pendle-scy-sample/blob/main/contracts/SuperComposableYield/SCY-implementations/PendleQiTokenSCY.sol): an opinionated implementation of the SCY token standard for BenQi tokens. - -See [PendleBtrflySCY](https://github.com/pendle-finance/pendle-scy-sample/blob/main/contracts/SuperComposableYield/SCY-implementations/PendleBtrflySCY.sol): an opinionated implementation of the SCY token standard for [Redacted Cartel]’s BTRFLY token. - -See [PendleWstETHSCY](https://github.com/pendle-finance/pendle-scy-sample/blob/main/contracts/SuperComposableYield/SCY-implementations/PendleWstEthSCY.sol): an opinionated implementation of the SCY token standard for stETH token. - -See [PendleYearnVaultSCY](https://github.com/pendle-finance/pendle-scy-sample/blob/main/contracts/SuperComposableYield/SCY-implementations/PendleYearnVaultScy.sol): an opinionated implementation of the SCY token standard for Yearn Vault tokens. - ## Security Considerations Malicious implementations which conform to the interface can put users at risk. It is recommended that all integrators review the implementation to avoid possible exploits and users losing funds. From 590ca8c04704e569ed7b502a8fa8f3ada701e32a Mon Sep 17 00:00:00 2001 From: Anton Buenavista Date: Mon, 6 Jun 2022 16:06:03 +0800 Subject: [PATCH 6/8] EIP-5115: Update to content based on feedback --- EIPS/eip-5115.md | 106 ++++++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 47 deletions(-) diff --git a/EIPS/eip-5115.md b/EIPS/eip-5115.md index a23480d8665ca7..0c70fc3358268b 100644 --- a/EIPS/eip-5115.md +++ b/EIPS/eip-5115.md @@ -1,7 +1,7 @@ --- eip: 5115 -title: Super Composable Yield Token Standard -description: A standard for wrapped yield-generating tokens. +title: Super Composable Yield Token +description: Interface for wrapped yield-generating tokens. author: Vu Nguyen (@mrenoon), Long Vuong (@UncleGrandpa925), Anton Buenavista (@ayobuenavista) discussions-to: https://ethereum-magicians.org/t/eip-5115-super-composable-yield-token-standard/9423 status: Draft @@ -13,28 +13,52 @@ requires: 20 ## Abstract -This standard allows for the implementation of a standardized API for wrapped yield-generating tokens within smart contracts. This standard is an extension on the ERC-20 token that provides basic functionality for transferring, depositing, withdrawing tokens, and reading balances. +This standard proposes an API for wrapped yield-generating tokens within smart contracts. It is an extension on the [EIP-20](./eip-20.md) token that provides basic functionality for transferring, depositing, withdrawing tokens, as well as reading balances. ## Motivation Yield generating mechanisms are built in all shapes and sizes, necessitating a manual integration every time a protocol builds on top of another protocol’s yield generating mechanism. -[ERC-4626](./eip-4626.md) tackled a significant part of this fragmentation by standardizing the interfaces for vaults, a major category among various yield-generating mechanisms. +[EIP-4626](./eip-4626.md) tackled a significant part of this fragmentation by standardizing the interfaces for vaults, a major category among various yield-generating mechanisms. -In this EIP, we’re extending the coverage to include assets beyond ERC4626’s reach, namely: +In this EIP, we’re extending the coverage to include assets beyond EIP-4626’s reach, namely: - Yield-generating assets that have different base tokens used for minting vs accounting for the pool value. - This category includes AMM liquidity tokens (which are yield generating assets that yield swap fees) since the value of the pool is measured in “liquidity units” (for example, $\sqrt k$ in UniswapV2, as defined in UniswapV2 whitepaper) which can’t be deposited in (as they are not tokens). - This extends the flexibility in minting the yield-bearing assets. For example, there could be an ETH vault that wants to allow users to deposit cETH directly instead of ETH, for gas efficiency or UX reasons. - Assets with reward tokens by default (e.g. COMP rewards for supplying in Compound). The reward tokens are expected to be sold to compound into the same asset. -While ERC-4626 is a well-designed and suitable standard for most vaults, there will inevitably be some yield-generating mechanisms that do not fit into their category (LP tokens for instance). A more flexible standard is required to standardize the interaction with all types of yield generating mechanisms. +While EIP-4626 is a well-designed and suitable standard for most vaults, there will inevitably be some yield-generating mechanisms that do not fit into their category (LP tokens for instance). A more flexible standard is required to standardize the interaction with all types of yield generating mechanisms. Therefore, we are proposing Super Composable Yield (SCY), a flexible standard for wrapped yield generating tokens that could cover most mechanisms in DeFi. We foresee that: -- ERC-4626 will still be a popular vault standard, that most vaults should adopt. -- SCY tokens can wrap over most yield generating mechanisms in DeFi, including ERC-4626 vaults for projects built on top of interest-bearing tokens. +- EIP-4626 will still be a popular vault standard, that most vaults should adopt. +- SCY tokens can wrap over most yield generating mechanisms in DeFi, including EIP-4626 vaults for projects built on top of interest-bearing tokens. - Whoever needs the functionalities of SCY could integrate with the existing SCY tokens or write a new SCY (to wrap over the target interest-bearing token). +This EIP is designed for flexibility, aiming to accommodate as many yield generating mechanisms as possible. Particularly, this standard aims to be generalized enough that it supports the following uses cases and more: + +- Money market supply positions + - Lending DAI in Compound, getting DAI interests and COMP rewards + - Lending ETH in BenQi, getting ETH interests and QI + AVAX rewards + - Lending USDC in Aave, getting USDC interests and stkAAVE rewards +- AMM liquidity provision + - Provide ETH + USDC to ETHUSDC pool in SushiSwap, getting swap fees in more ETH+USDC + - Provide ETH + USDC to ETHUSDC pool in SushiSwap and stake it in Sushi Onsen, getting swap fees and SUSHI rewards + - Provide USDC+DAI+USDT to 3crv pool and stake it in Convex, getting 3crv swap fees and CRV + CVX rewards +- Vault positions + - Provide ETH into Yearn EIP-4626 vault, where the vault accrues yield from Yearn’s ETH strategy + - Provide DAI into Harvest and staking it, getting DAI interests and FARM rewards +- Liquid staking positions + - Holding stETH (in Lido), getting yields in more stETH +- Liquidity mining programs + - Provide USDC in Stargate, getting STG rewards + - Provide FEI in Tokemak, getting TOKE rewards + - Provide LOOKS in LooksRare, getting LOOKS yield and WETH rewards +- Rebasing tokens + - Stake OHM into sOHM/gOHM, getting OHM rebase yield + - Stake BTRFLY into xBTRFLY, getting BTRFLY rebase yield + +The EIP hopes to minimize, if not possibly eliminate, the use of customized adapters in order to interact with many different forms of yield-generating token mechanisms. ## Specification @@ -80,23 +104,24 @@ Super Composable Yield is a token standard for all GYGPs. Each Super Composable All SCY tokens: -- **MUST** implement **`ERC20`** to represent shares in the underlying GYGP. -- **MUST** implement ERC-20’s optional metadata extensions `name`, `symbol`, and `decimals`, which **SHOULD** reflect the underlying GYGP’s accounting asset’s `name`, `symbol`, and `decimals`. +- **MUST** implement **`EIP-20`** to represent shares in the underlying GYGP. +- **MUST** implement EIP-20’s optional metadata extensions `name`, `symbol`, and `decimals`, which **SHOULD** reflect the underlying GYGP’s accounting asset’s `name`, `symbol`, and `decimals`. +- **MAY** implement [EIP-2612](./eip-2612.md) to improve the UX of approving SCY tokens on various integrations. - **MAY** revert on calls to `transfer` and `transferFrom` if a SCY token is to be non-transferable. -- The ERC-20 operations `balanceOf`, `transfer`, `totalSupply`, etc. **SHOULD** operate on the GYGP “shares”, which represent a claim to ownership on a fraction of the GYGP’s underlying holdings. +- The EIP-20 operations `balanceOf`, `transfer`, `totalSupply`, etc. **SHOULD** operate on the GYGP “shares”, which represent a claim to ownership on a fraction of the GYGP’s underlying holdings. #### Definition of base tokens Base tokens are tokens that could be deposited to mint SCY tokens (and hence, to enter the underlying GYGP), or redeemed when burning SCY tokens (and hence, exiting the underlying GYGP). Essentially, base tokens are implicitly converted into units of **assets** when deposited or redeemed, to conform to state change #1 and #2 of the GYGP definition above. -There could be multiple base tokens in a SCY. This allows for maximum flexibility in how to mint SCY to enter the underlying yield generating pool. For example, both BAL and WETH (and even BALWETH LP token) could be used to mint the SCY token for BALWETH Balancer pool (by providing single-sided liquidity). +There could be multiple kinds of base tokens in a SCY. This allows for maximum flexibility in how to mint SCY to enter the underlying yield generating pool. For example, both BAL and WETH (and even BALWETH LP token) could be used to mint the SCY token for BALWETH Balancer pool (by providing single-sided liquidity). -As such, base tokens are not necessarily the same as the asset (which is a key difference between SCY and ERC-4626). +As such, base tokens are not necessarily the same as the asset (which is a key difference between SCY and EIP-4626). #### Interface ```solidity -interface ISuperComposableYield is IERC20Metadata { +interface ISuperComposableYield { enum AssetType { TOKEN, LIQUIDITY @@ -163,6 +188,12 @@ interface ISuperComposableYield is IERC20Metadata { address assetAddress, uint8 assetDecimals ); + + function name() external view returns (string memory); + + function symbol() external view returns (string memory); + + function decimals() external view returns (uint8); } ``` @@ -184,7 +215,7 @@ The ideal way to deposit is to send `tokenIn` in first, then call the `deposit` This function will convert the amount of `tokenIn` into some worth of **assets** and deposit this amount into the SCY contract for the recipient, who will receive `amountSharesOut` of SCY tokens (**shares**). - **MUST** emit the `Deposit` event. -- **MUST** support ERC-20’s `approve` / `transferFrom` flow where `tokenIn` are taken from receiver directly (as msg.sender) or if the msg.sender has ERC-20 approved allowance over the base token of the receiver. +- **MUST** support EIP-20’s `approve` / `transferFrom` flow where `tokenIn` are taken from receiver directly (as msg.sender) or if the msg.sender has EIP-20 approved allowance over the base token of the receiver. - **MUST** revert if $amountSharesOut \lt minSharesOut$ (due to deposit limit being reached, slippage, or the user not approving enough `tokenIn` **to the SCY contract, etc). ```solidity @@ -201,7 +232,7 @@ This method will first pull `amountSharesToPull` of SCY tokens, and use the floa This function will redeem the exact SCY token (**shares**) from the SCY contract. The **assets** are converted into `tokenOut` of `tokenOut`. - **MUST** emit the `Redeem` event. -- **MUST** support ERC-20’s `approve` / `transferFrom` flow where the shares are burned from receiver directly (as msg.sender) or if the msg.sender has ERC-20 approved allowance over the shares of the receiver. +- **MUST** support EIP-20’s `approve` / `transferFrom` flow where the shares are burned from receiver directly (as msg.sender) or if the msg.sender has EIP-20 approved allowance over the shares of the receiver. - **MUST** revert if $tokenOut \lt minTokenOut$ (due to redeem limit being reached, slippage, or the user not approving enough `amountSharesToPull` **to the SCY contract, etc). ```solidity @@ -239,7 +270,7 @@ function yieldToken() external view returns (address); This read-only method returns the underlying yield-generating token (representing a GYGP) that was wrapped into a SCY token. -- **MUST** return a token address that conforms to the ERC-20 interface, or zero address +- **MUST** return a token address that conforms to the EIP-20 interface, or zero address - **MUST NOT** revert. - **MUST** reflect the exact underlying yield-generating token address if the SCY token is a wrapped token. - **MAY** return 0x or zero address if the SCY token is natively implemented, and not from wrapping. @@ -250,7 +281,7 @@ function getRewardTokens() external view returns (address[] memory); This read-only method returns the latest list of all reward tokens. -- **MUST** return ERC-20 token addresses. +- **MUST** return EIP-20 token addresses. - **MUST NOT** revert. - **MAY** return an empty list, one, or several token addresses. - **MAY** return additional reward tokens over time, depending on when `underlyingYieldToken` supports more or less reward tokens. @@ -261,7 +292,7 @@ function getBaseTokens() external view returns (address[] memory); This read-only method returns the list of all base tokens that can be used to deposit into the SCY contract. -- **MUST** return ERC-20 token addresses. +- **MUST** return EIP-20 token addresses. - **MUST** return at least one address. - **MUST NOT** revert. @@ -288,7 +319,7 @@ This read-only function returns useful information about the asset, intended for `decimals` is the decimals to format asset balances. -Convention for `assetType` and format of the `info` field: 1) If asset is an ERC20 token, `assetType = 0`, `assetAddress` is the address of the token; 2) If asset is liquidity of an AMM (like $\sqrt{k}$ in UniswapV2 forks), `assetType = 1`, `assetAddress` is the address of the LP token. +Convention for `assetType` and format of the `info` field: 1) If asset is an EIP-20 token, `assetType = 0`, `assetAddress` is the address of the token; 2) If asset is liquidity of an AMM (like $\sqrt{k}$ in UniswapV2 forks), `assetType = 1`, `assetAddress` is the address of the LP token. * **MUST** reflect the underlying asset’s decimals if at all possible in order to eliminate any possible source of confusion or be deemed malicious. - **MUST** conform to the conventions for assetType and info. @@ -351,42 +382,23 @@ The `exchangeRateCurrent` is updated to the latest exchange rate. ## Rationale -This EIP is designed for flexibility, aiming to accommodate as many yield generating mechanisms as possible. Particularly, this standard aims to be generalized enough that it supports the following uses cases and more: +[EIP-20](./eip-20.md) is enforced because implementation details such as transfer, token approvals, and balance calculation directly carry over to the SCY tokens. This standardization makes the SCY tokens immediately compatible with all EIP-20 use cases. -- Money market supply positions - - Lending DAI in Compound, getting DAI interests and COMP rewards - - Lending ETH in BenQi, getting ETH interests and QI + AVAX rewards - - Lending USDC in Aave, getting USDC interests and stkAAVE rewards -- AMM liquidity provision - - Provide ETH + USDC to ETHUSDC pool in SushiSwap, getting swap fees in more ETH+USDC - - Provide ETH + USDC to ETHUSDC pool in SushiSwap and stake it in Sushi Onsen, getting swap fees and SUSHI rewards - - Provide USDC+DAI+USDT to 3crv pool and stake it in Convex, getting 3crv swap fees and CRV + CVX rewards -- Vault positions - - Provide ETH into Yearn ERC-4626 vault, where the vault accrues yield from Yearn’s ETH strategy - - Provide DAI into Harvest and staking it, getting DAI interests and FARM rewards -- Liquid staking positions - - Holding stETH (in Lido), getting yields in more stETH -- Liquidity mining programs - - Provide USDC in Stargate, getting STG rewards - - Provide FEI in Tokemak, getting TOKE rewards - - Provide LOOKS in LooksRare, getting LOOKS yield and WETH rewards -- Rebasing tokens - - Stake OHM into sOHM/gOHM, getting OHM rebase yield - - Stake BTRFLY into xBTRFLY, getting BTRFLY rebase yield +[EIP-165](./eip-165.md) is not explicitly mentioned to be supported as there are no optional methods in this standard. It is expected for all methods defined in the interface to be implemented. -The EIP hopes to minimize, if not possibly eliminate, the use of customized adapters in order to interact with many different forms of yield-generating token mechanisms. +[EIP-2612](./eip-2612.md) can optionally be implemented in order to improve the UX of approving SCY tokens on various integrations. -ERC-20 is enforced because implementation details such as transfer, token approvals, and balance calculation directly carry over to the SCY tokens. This standardization makes the SCY tokens immediately compatible with all ERC-20 use cases. +The `exchangeRateStored` read-only method serves as a rough estimate of the prevalent exchange rate since the last update. It is included for frontends, wallets, and applications that need an estimate on the exchange rate of SCY tokens into assets, not an exact value possibly including slippage or other fees as this would require them doing a state update and spending gas. For applications that need an exact exchange rate, the `exchangeRateCurrent` mutable function can be used. ## Backwards Compatibility -This EIP is fully backwards compatible as its implementation extends the functionality of [ERC-20](./eip-20.md), however the optional metadata extensions, namely `name`, `decimals`, and `symbol` semantics MUST be implemented for all SCY token implementations. +This EIP is fully backwards compatible as its implementation extends the functionality of [EIP-20](./eip-20.md), however the optional metadata extensions, namely `name`, `decimals`, and `symbol` semantics MUST be implemented for all SCY token implementations. ## Security Considerations -Malicious implementations which conform to the interface can put users at risk. It is recommended that all integrators review the implementation to avoid possible exploits and users losing funds. +Malicious implementations which conform to the interface can put users at risk. It is recommended that all integrators (such as wallets, aggregators, or other smart contract protocols) review the implementation to avoid possible exploits and users losing funds. -The method `exchangeRateStored` returns an outdated estimated value and does not confer the exact current exchange rate of asset per share. Should accuracy be needed, `exchangeRateCurrent` should be used instead, and in addition, will update `exchangeRateStored`. +The method `exchangeRateStored` returns an outdated estimated value and does not confer the exact current exchange rate of asset per share. Should accuracy be needed, `exchangeRateCurrent` should be used instead (which additionally updates `exchangeRateStored`.) `decimals` in `assetInfo` must strongly reflect the underlying asset’s decimals if at all possible in order to eliminate any possible source of confusion or be deemed malicious. @@ -394,4 +406,4 @@ The method `exchangeRateStored` returns an outdated estimated value and does not ## Copyright -Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). \ No newline at end of file +Copyright and related rights waived via [CC0](../LICENSE.md). \ No newline at end of file From 57a1f245bcf50a434ce6668eae02d206e343d315 Mon Sep 17 00:00:00 2001 From: Anton Buenavista Date: Mon, 6 Jun 2022 16:13:43 +0800 Subject: [PATCH 7/8] EIP-5115: Explicitely defined Use Cases subsection under Motivation --- EIPS/eip-5115.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/EIPS/eip-5115.md b/EIPS/eip-5115.md index 0c70fc3358268b..68fc4718945e81 100644 --- a/EIPS/eip-5115.md +++ b/EIPS/eip-5115.md @@ -35,6 +35,8 @@ Therefore, we are proposing Super Composable Yield (SCY), a flexible standard fo - SCY tokens can wrap over most yield generating mechanisms in DeFi, including EIP-4626 vaults for projects built on top of interest-bearing tokens. - Whoever needs the functionalities of SCY could integrate with the existing SCY tokens or write a new SCY (to wrap over the target interest-bearing token). +### Use Cases + This EIP is designed for flexibility, aiming to accommodate as many yield generating mechanisms as possible. Particularly, this standard aims to be generalized enough that it supports the following uses cases and more: - Money market supply positions From 4630163590b10e299fe5cb528abf71c96117ed95 Mon Sep 17 00:00:00 2001 From: Anton Buenavista Date: Mon, 13 Jun 2022 18:17:03 +0800 Subject: [PATCH 8/8] EIP-5115: Small edit to pass spellcheck --- EIPS/eip-5115.md | 1 - 1 file changed, 1 deletion(-) diff --git a/EIPS/eip-5115.md b/EIPS/eip-5115.md index 68fc4718945e81..480b2752b5fd3d 100644 --- a/EIPS/eip-5115.md +++ b/EIPS/eip-5115.md @@ -54,7 +54,6 @@ This EIP is designed for flexibility, aiming to accommodate as many yield genera - Holding stETH (in Lido), getting yields in more stETH - Liquidity mining programs - Provide USDC in Stargate, getting STG rewards - - Provide FEI in Tokemak, getting TOKE rewards - Provide LOOKS in LooksRare, getting LOOKS yield and WETH rewards - Rebasing tokens - Stake OHM into sOHM/gOHM, getting OHM rebase yield