-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f301947
commit 697e846
Showing
2 changed files
with
134 additions
and
98 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,61 +5,70 @@ pragma solidity ^0.8.0; | |
import {EVCUtil, IEVC} from "ethereum-vault-connector/utils/EVCUtil.sol"; | ||
import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol"; | ||
import {SafeERC20} from "openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; | ||
import {Math} from "openzeppelin-contracts/utils/math/Math.sol"; | ||
import {ESynth} from "./ESynth.sol"; | ||
|
||
/// @title PegStabilityModule | ||
/// @custom:security-contact [email protected] | ||
/// @author Euler Labs (https://www.eulerlabs.com/) | ||
/// @notice The PegStabilityModule is granted minting rights on the ESynth and must allow slippage-free conversion from | ||
/// and to the underlying asset as per configured conversionPrice. On deployment, the fee for swaps to synthetic asset | ||
/// and to the underlying asset as per configured CONVERSION_PRICE. On deployment, the fee for swaps to synthetic asset | ||
/// and to underlying asset are defined. These fees must accrue to the PegStabilityModule contract and can not be | ||
/// withdrawn, serving as a permanent reserve to support the peg. Swapping to the synthetic asset is possible up to the | ||
/// minting cap granted for the PegStabilityModule in the ESynth. Swapping to the underlying asset is possible up to the | ||
/// amount of the underlying asset held by the PegStabilityModule. | ||
contract PegStabilityModule is EVCUtil { | ||
using SafeERC20 for IERC20; | ||
using Math for uint256; | ||
|
||
uint256 public constant BPS_SCALE = 100_00; | ||
uint256 public constant PRICE_SCALE = 1e18; | ||
|
||
ESynth public immutable synth; | ||
IERC20 public immutable underlying; | ||
uint256 public immutable conversionPrice; // 1e18 = 1 SYNTH == 1 UNDERLYING, 0.01e18 = 1 SYNTH == 0.01 UNDERLYING | ||
|
||
uint256 public immutable TO_UNDERLYING_FEE; | ||
uint256 public immutable TO_SYNTH_FEE; | ||
uint256 public immutable CONVERSION_PRICE; | ||
|
||
error E_ZeroAddress(); | ||
error E_FeeExceedsBPS(); | ||
error E_ZeroConversionPrice(); | ||
|
||
/// @param _evc The address of the EVC. | ||
/// @param _synth The address of the synthetic asset. | ||
/// @param _underlying The address of the underlying asset. | ||
/// @param toUnderlyingFeeBPS The fee for swapping to the underlying asset in basis points. eg: 100 = 1% | ||
/// @param toSynthFeeBPS The fee for swapping to the synthetic asset in basis points. eg: 100 = 1% | ||
/// @param _toUnderlyingFeeBPS The fee for swapping to the underlying asset in basis points. eg: 100 = 1% | ||
/// @param _toSynthFeeBPS The fee for swapping to the synthetic asset in basis points. eg: 100 = 1% | ||
/// @param _conversionPrice The conversion price between the synthetic and underlying asset. | ||
/// eg: 1e18 = 1 SYNTH == 1 UNDERLYING, 0.01e18 = 1 SYNTH == 0.01 UNDERLYING | ||
/// @dev _conversionPrice = 10**underlyingDecimals corresponds to 1:1 peg | ||
/// @dev if underlying is 18 decimals, _conversionPrice = 1e18 corresponds to 1:1 peg | ||
/// @dev if underlying is 6 decimals, _conversionPrice = 1e6 corresponds to 1:1 peg | ||
constructor( | ||
address _evc, | ||
address _synth, | ||
address _underlying, | ||
uint256 toUnderlyingFeeBPS, | ||
uint256 toSynthFeeBPS, | ||
uint256 _toUnderlyingFeeBPS, | ||
uint256 _toSynthFeeBPS, | ||
uint256 _conversionPrice | ||
) EVCUtil(_evc) { | ||
if (toUnderlyingFeeBPS >= BPS_SCALE || toSynthFeeBPS >= BPS_SCALE) { | ||
if (_synth == address(0) || _underlying == address(0)) { | ||
revert E_ZeroAddress(); | ||
} | ||
|
||
if (_toUnderlyingFeeBPS >= BPS_SCALE || _toSynthFeeBPS >= BPS_SCALE) { | ||
revert E_FeeExceedsBPS(); | ||
} | ||
|
||
if (_evc == address(0) || _synth == address(0) || _underlying == address(0)) { | ||
revert E_ZeroAddress(); | ||
if (_conversionPrice == 0) { | ||
revert E_ZeroConversionPrice(); | ||
} | ||
|
||
synth = ESynth(_synth); | ||
underlying = IERC20(_underlying); | ||
TO_UNDERLYING_FEE = toUnderlyingFeeBPS; | ||
TO_SYNTH_FEE = toSynthFeeBPS; | ||
conversionPrice = _conversionPrice; | ||
TO_UNDERLYING_FEE = _toUnderlyingFeeBPS; | ||
TO_SYNTH_FEE = _toSynthFeeBPS; | ||
CONVERSION_PRICE = _conversionPrice; | ||
} | ||
|
||
/// @notice Swaps the given amount of synth to underlying given an input amount of synth. | ||
|
@@ -130,27 +139,33 @@ contract PegStabilityModule is EVCUtil { | |
/// @param amountIn The amount of synth to swap. | ||
/// @return The amount of underlying received. | ||
function quoteToUnderlyingGivenIn(uint256 amountIn) public view returns (uint256) { | ||
return amountIn * (BPS_SCALE - TO_UNDERLYING_FEE) * conversionPrice / BPS_SCALE / PRICE_SCALE; | ||
return amountIn.mulDiv( | ||
(BPS_SCALE - TO_UNDERLYING_FEE) * CONVERSION_PRICE, BPS_SCALE * PRICE_SCALE, Math.Rounding.Floor | ||
); | ||
} | ||
|
||
/// @notice Quotes the amount of underlying given an output amount of synth. | ||
/// @param amountOut The amount of underlying to receive. | ||
/// @return The amount of synth swapped. | ||
function quoteToUnderlyingGivenOut(uint256 amountOut) public view returns (uint256) { | ||
return amountOut * BPS_SCALE * PRICE_SCALE / (BPS_SCALE - TO_UNDERLYING_FEE) / conversionPrice; | ||
return amountOut.mulDiv( | ||
(BPS_SCALE + TO_UNDERLYING_FEE) * PRICE_SCALE, BPS_SCALE * CONVERSION_PRICE, Math.Rounding.Ceil | ||
); | ||
} | ||
|
||
/// @notice Quotes the amount of synth given an input amount of underlying. | ||
/// @param amountIn The amount of underlying to swap. | ||
/// @return The amount of synth received. | ||
function quoteToSynthGivenIn(uint256 amountIn) public view returns (uint256) { | ||
return amountIn * (BPS_SCALE - TO_SYNTH_FEE) * PRICE_SCALE / BPS_SCALE / conversionPrice; | ||
return | ||
amountIn.mulDiv((BPS_SCALE - TO_SYNTH_FEE) * PRICE_SCALE, BPS_SCALE * CONVERSION_PRICE, Math.Rounding.Floor); | ||
} | ||
|
||
/// @notice Quotes the amount of synth given an output amount of underlying. | ||
/// @param amountOut The amount of synth to receive. | ||
/// @return The amount of underlying swapped. | ||
function quoteToSynthGivenOut(uint256 amountOut) public view returns (uint256) { | ||
return amountOut * BPS_SCALE * conversionPrice / (BPS_SCALE - TO_SYNTH_FEE) / PRICE_SCALE; | ||
return | ||
amountOut.mulDiv((BPS_SCALE + TO_SYNTH_FEE) * CONVERSION_PRICE, BPS_SCALE * PRICE_SCALE, Math.Rounding.Ceil); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters