-
Notifications
You must be signed in to change notification settings - Fork 217
SIP-112: Swap ETH for WETH in contract logic #432
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
eac3fe0
32e9243
4be2d07
845f871
5f15081
7bde250
1071df5
a74da5b
652b0dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,11 +11,11 @@ created: 2021-02-15 | |
|
|
||
| ## Simple Summary | ||
| <!--"If you can't explain it simply, you don't understand it well enough." Simply describe the outcome the proposed changes intends to achieve. This should be non-technical and accessible to a casual community member.--> | ||
| Allow users to wrap ETH and get sETH | ||
| Allow users to wrap ETH or WETH and get sETH | ||
|
|
||
| ## Abstract | ||
| We propose to deploy a new contract that accepts deposits in ETH and in return mints sETH in the user's wallet. After successful ETH deposit, users' ownership over ETH is transferred to Synthetix protocol. Wrappr is a conditionally bidirectional contract, meaning that if it holds ETH in its reserve, it will accept deposits in sETH and releases ETH. | ||
| ETH can be unwrapped at any point by anyone after the corresponding amount of sETH is sent back and effectively burned. | ||
| We propose to deploy a new contract that accepts deposits in ETH or WETH and in return mints sETH in the user's wallet. After successful ETH or WETH deposit, users' ownership is transferred to Synthetix protocol. Wrappr is a conditionally bidirectional contract, meaning that if it holds WETH in its reserve, it will accept deposits in sETH and releases WETH or ETH back to the user. | ||
| WETH or ETH can be withdrawn from the contract at any point by anyone after the corresponding amount of sETH is effectively burned. | ||
|
|
||
| ## Motivation | ||
| <!--This is the problem statement. This is the *why* of the SIP. It should clearly explain *why* the current state of the protocol is inadequate. It is critical that you explain *why* the change is needed, if the SIP proposes changing how something is calculated, you must address *why* the current calculation is innaccurate or wrong. This is not the place to describe how the SIP will address the issue!--> | ||
|
|
@@ -34,9 +34,10 @@ Even with the introduction of Multi-Collateral Loans in SIP-97, problems with th | |
|
|
||
| ### Overview | ||
| <!--This is a high level overview of *how* the SIP will solve the problem. The overview should clearly describe how the new feature will be implemented.--> | ||
| sETH is freshly minted whenever a user deposit ETH into the contract. The user can deposit any amount desired however, this is subject to not exceeding the `maxETH` configurable via SCCP. | ||
| There is no duration, interest rate or collateralization ratio, as any user can at any time buy back the ETH deposited in the contract by burning sETH. | ||
| sETH is freshly minted whenever a user deposits ETH or WETH into the contract. The user can deposit any amount desired however, this is subject to not exceeding the `maxETH` configurable via SCCP. | ||
| There is no duration, interest rate or collateralization ratio, as any user can at any time buy back WETH or ETH available in the contract by burning sETH. | ||
| Minters benefit as minting sETH and burning sETH are subject to a `mintingFeeRate` and `burningFeeRate`, both of which are paid to the fee pool after conversion into `sUSD`. | ||
| The contract supports both ETH and WETH, and automatically handles wrapping/unwrapping ETH for the user. | ||
|
|
||
| ### Rationale | ||
| <!--This is where you explain the reasoning behind how you propose to solve the problem. Why did you propose to implement the change in this way, what were the considerations and trade-offs. The rationale fleshes out what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work. The rationale may also provide evidence of consensus within the community, and should discuss important objections or concerns raised during discussion.--> | ||
|
|
@@ -46,56 +47,104 @@ The main purpose of this proposal rests on the following points: | |
| - The debt pool would be mostly neutral initially as the increase in sETH supply would be offset by the increase in ETH locked in the wappr contract. However, as users swap the freshly minted sETH to other synths, this would lead to a reduction in the sETH skew as ETH locked acts as a counter-weight against the long sETH position, as the total debt calculation would be reduced by the amount of ETH locked in the contract. Hence, the need to incentivize farmers to assume a short sETH positions would be decreased. | ||
| - The minting and burning fees effectively create a new revenue stream for minters who would effectively be getting a cut from the profit generated by actors arbitraging points of inefficiency. | ||
| - The pressure to fix the peg by reducing the collateralization ratio (increasing the solvency risk on minters) is somewhat reduced by having this contract at the spartan's council disposal, as another tool to help steer the peg towards parity (by changing the minting & burning fee as well as the `maxETH` parameter). | ||
| - Supporting WETH makes the contract compatible with L2, specifically the Optimism OVM (OVM doesn’t support native ETH, instead contracts can use a [native WETH deployment](https://community.optimism.io/docs/protocol/evm-comparison.html#native-weth)), as well as reduces interaction complexity for users coming from DeFi, where WETH is the norm. | ||
|
|
||
| ### Technical Specification | ||
| One contract is essentially required to be deployed: | ||
| - `wrappr.sol` which is able to mint `sETH` against ETH deposited and release ETH against `sETH` burned. | ||
|
|
||
| The entry points for users on`wrappr.sol` implements the following interface. | ||
| ### Technical Specification | ||
| #### Contracts | ||
| Two contracts are required to be deployed: | ||
| - `EtherWrapper.sol` which is able to mint `sETH` against WETH deposited and release WETH against `sETH` burned. | ||
| - `NativeEtherWrappr.sol` which is a thin wrapper around `EtherWrapper.sol`, that supports interacting with native ether on L1. | ||
|
|
||
| #### Interfaces | ||
| The entry points for users on `IEtherWrapper.sol` implements the following interface. | ||
| ```sol | ||
| interface IEtherWrapper.sol { | ||
| function mint(uint amount) external; | ||
| function burn(uint amount) external; | ||
| } | ||
| ``` | ||
| interface IWrappr.sol { | ||
| function mint() external payable; | ||
|
|
||
| The `NativeEtherWrapper` has a similar interface. The contract calls into `EtherWrapper` for `mint` and `burn`, converting sent ETH into WETH for the `mint` function, and received `WETH` into `ETH` for the `burn` function. | ||
|
|
||
| ```sol | ||
| interface INativeEtherWrapper { | ||
| function mint() external payable; | ||
| function burn(uint amount) external; | ||
| } | ||
| ``` | ||
| #### L2 Specification | ||
| `NativeEtherWrapper` is not deployed for L2, as using native ETH opcodes (`callvalue`, `balance`) in the OVM will revert. | ||
|
|
||
| #### Key Bounds | ||
|
|
||
| - The upper bound on the amount of *Minting* is determined with a helper function, `capacity`, defined as `maxETH` less `wETH` locked in the contract. In case the user attempts to mint an amount greater than the upper bound, then `capacity` is minted and the residual is returned to the user (please refer to test cases for calculation specs). | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick - can we use consistent naming for wETH or WETH (I prefer the latter).
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. old habits die hard, 😅 all |
||
|
|
||
| - The upper bound on the amount of *Burning* is computed as `wETH` locked in the contract multiplied `(1+burnFeeRate)` (please refer to test cases for calculation specs). | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🙏 thanks for clarifying this one. |
||
|
|
||
| - `mintFeeRate` and `burnFeeRate` are both bounded between 0% and 100%, inclusive. | ||
|
|
||
|
|
||
| ### Test Cases | ||
| - Given that a user has `u` amount of ETH and the contract has `c` amount of ETH in spare capacity | ||
| - Given that a user has `u` amount of ETH and `u` WETH and the contract has `c` amount of ETH in spare capacity | ||
| - Given that `u` is larger than or equal to `c` | ||
| - When the user attempts deposit `u` ETH into the contract | ||
| - When the user attempts to deposit `u` ETH into the contract | ||
| - ✅ Then it succeeds and the following take place: | ||
| - `c` ETH is locked up in the contract | ||
| - `c` ETH is wrapped into WETH and is locked in the contract | ||
| - `c(1-mintFeeRate)` is minted into the user's wallet in sETH | ||
| - `c*mintFeeRate` worth of sETH is sent to the fee pool in the form of sUSD | ||
| - `u - c` worth of ETH is refunded back to the user | ||
| - When the user attempts to deposit `u` WETH into the contract | ||
| - ✅ Then it succeeds and the following take place: | ||
| - `c` WETH is locked up in the contract | ||
| - `c(1-mintFeeRate)` is minted into the user's wallet in sETH | ||
| - `c*mintFeeRate` worth of sETH is sent to the fee pool in the form of sUSD | ||
| - `u - c` worth of WETH is refunded back to the user | ||
| - Given that `u` is strictly lower than `c` | ||
| - When the user attempts deposit `u` ETH into the contract | ||
| - When the user attempts to deposit `u` ETH into the contract | ||
| - ✅ Then it succeeds and the following take place: | ||
| - `u` ETH is wrapped into WETH and is locked in the contract | ||
| - `u(1-mintFeeRate)` is minted into the user's wallet in sETH | ||
| - `u*mintFeeRate` worth of sETH is sent to the fee pool in the form of sUSD | ||
| - When the user attempts to deposit `u` WETH into the contract | ||
| - ✅ Then it succeeds and the following take place: | ||
| - `u` ETH is locked up in the contract | ||
| - `u` WETH is locked up in the contract | ||
| - `u(1-mintFeeRate)` is minted into the user's wallet in sETH | ||
| - `u*mintFeeRate` worth of sETH is sent to the fee pool in the form of sUSD | ||
| - Given that the contract's capacity is zero, as `maxETH` is locked in the contract | ||
| - When the user attempts deposit ETH into the contract | ||
| - When the user attempts deposit ETH or WETH into the contract | ||
| - ❌ Then the transaction reverts due to max capacity being reached | ||
|
|
||
| - Given that a user has `u` amount of sETH and the contract holds `c` amount of ETH | ||
| - Given that a user has `u` amount of sETH and the contract holds `c` amount of WETH | ||
| - Given that `u` is larger than or equal to `c(1+burnFeeRate)` | ||
| - When the user attempts to draw out ETH from the contract by burning `u` sETH | ||
| - When the user attempts to draw out ETH from the contract by burning `u` sETH and flagging withdrawal in ETH | ||
| - ✅ Then it succeeds and the following take place: | ||
| - `c` ETH is sent to the user | ||
| - `c` WETH is unwrapped to ETH and is sent to the user | ||
| - `c` sETH is burned | ||
| - `c * burnFeeRate` worth of sETH is swapped to sUSD and sent to the fee pool | ||
| - `u - c(1+burnFeeRate)` worth of sETH is refunded back to the user | ||
| - When the user attempts to draw out WETH from the contract by burning `u` sETH and flagging withdrawal in WETH | ||
| - ✅ Then it succeeds and the following take place: | ||
| - `c` WETH is sent to the user | ||
| - `c` sETH is burned | ||
| - `c * burnFeeRate` worth of sETH is swapped to sUSD and sent to the fee pool | ||
| - `u - c(1+burnFeeRate)` worth of sETH is refunded back to the user | ||
| - Given that `u` is strictly lower than `c(1+burnFeeRate)` | ||
| - When the user attempts to draw out ETH from the contract by burning `u` sETH | ||
| - When the user attempts to draw out ETH from the contract by burning `u` sETH and flagging withdrawal in ETH | ||
| - ✅ Then it succeeds and the following take place: | ||
| - `u (1-burnFeeRate)` worth of WETH is unwrapped to ETH and is sent to the user | ||
| - `u * burnFeeRate` worth of sETH is swapped to sUSD and sent to the fee pool | ||
| - `u (1 - burnFeeRate)` sETH is burned | ||
| - When the user attempts to draw out WETH from the contract by burning `u` sETH and flagging withdrawal in WETH | ||
| - ✅ Then it succeeds and the following take place: | ||
| - `u (1-burnFeeRate)` worth of ETH is sent to the user | ||
| - `u (1-burnFeeRate)` worth of WETH is sent to the user | ||
| - `u * burnFeeRate` worth of sETH is swapped to sUSD and sent to the fee pool | ||
| - `u (1 - burnFeeRate)` sETH is burned | ||
| - Given that the contract's holds no ETH | ||
| - When the user attempts draw out ETH from the contract by burning sETH | ||
| - ❌ Then the transaction reverts due to the contract being out of ETH | ||
| - Given that the contract's holds no WETH | ||
| - When the user attempts draw out ETH or WETH from the contract | ||
| - ❌ Then the transaction reverts due to the contract being out of WETH | ||
|
|
||
| - Given that a user attemps to mint with `WETH` and `msg.value` is greater than zero then the following takes place: | ||
| - ❌ The transaction reverts due to the user minting with both `WETH` and `ETH` | ||
|
|
||
|
|
||
| ### Configurable Values (Via SCCP) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
capacityis actually max(maxETH - weth, 0) if we're to be precise?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure, updated the full function