Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions contracts/contracts/interfaces/IVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ interface IVault {
event RebasePaused();
event RebaseUnpaused();
event VaultBufferUpdated(uint256 _vaultBuffer);
event RedeemFeeUpdated(uint256 _redeemFeeBps);
event AllocateThresholdUpdated(uint256 _threshold);
event RebaseThresholdUpdated(uint256 _threshold);
event StrategistUpdated(address _address);
Expand Down Expand Up @@ -53,10 +52,6 @@ interface IVault {
function ADMIN_IMPLEMENTATION() external view returns (address);

// VaultAdmin.sol
function setRedeemFeeBps(uint256 _redeemFeeBps) external;

function redeemFeeBps() external view returns (uint256);

function setVaultBuffer(uint256 _vaultBuffer) external;

function vaultBuffer() external view returns (uint256);
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/mocks/MockNonRebasing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ contract MockNonRebasing {
}

function redeemOusd(address _vaultContract, uint256 _amount) public {
IVault(_vaultContract).redeem(_amount, 0);
IVault(_vaultContract).requestWithdrawal(_amount);
}

function approveFor(
Expand Down
32 changes: 3 additions & 29 deletions contracts/contracts/vault/OETHBaseVaultCore.sol
Original file line number Diff line number Diff line change
@@ -1,38 +1,12 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import { StableMath } from "../utils/StableMath.sol";
import { OETHVaultCore } from "./OETHVaultCore.sol";

import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IStrategy } from "../interfaces/IStrategy.sol";
import { VaultCore } from "./VaultCore.sol";

/**
* @title OETH Base VaultCore Contract
* @author Origin Protocol Inc
*/
contract OETHBaseVaultCore is OETHVaultCore {
using SafeERC20 for IERC20;
using StableMath for uint256;

constructor(address _weth) OETHVaultCore(_weth) {}

// @inheritdoc OETHVaultCore
function _redeem(uint256 _amount, uint256 _minimumUnitAmount)
internal
virtual
override
{
// Only Strategist or Governor can redeem using the Vault for now.
// We don't have the onlyGovernorOrStrategist modifier on VaultCore.
// Since we won't be using that modifier anywhere in the VaultCore as well,
// the check has been added inline instead of moving it to VaultStorage.
require(
msg.sender == strategistAddr || isGovernor(),
"Caller is not the Strategist or Governor"
);

super._redeem(_amount, _minimumUnitAmount);
}
contract OETHBaseVaultCore is VaultCore {
constructor(address _weth) VaultCore(_weth) {}
}
26 changes: 4 additions & 22 deletions contracts/contracts/vault/OETHPlumeVaultCore.sol
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import { OETHVaultCore } from "./OETHVaultCore.sol";
import { VaultCore } from "./VaultCore.sol";

/**
* @title OETH Plume VaultCore Contract
* @author Origin Protocol Inc
*/
contract OETHPlumeVaultCore is OETHVaultCore {
constructor(address _weth) OETHVaultCore(_weth) {}
contract OETHPlumeVaultCore is VaultCore {
constructor(address _weth) VaultCore(_weth) {}

// @inheritdoc OETHVaultCore
// @inheritdoc VaultCore
function _mint(
address,
uint256 _amount,
Expand All @@ -26,22 +26,4 @@ contract OETHPlumeVaultCore is OETHVaultCore {

super._mint(_amount);
}

// @inheritdoc OETHVaultCore
function _redeem(uint256 _amount, uint256 _minimumUnitAmount)
internal
virtual
override
{
// Only Strategist or Governor can redeem using the Vault for now.
// We don't have the onlyGovernorOrStrategist modifier on VaultCore.
// Since we won't be using that modifier anywhere in the VaultCore as well,
// the check has been added inline instead of moving it to VaultStorage.
require(
msg.sender == strategistAddr || isGovernor(),
"Caller is not the Strategist or Governor"
);

super._redeem(_amount, _minimumUnitAmount);
}
}
6 changes: 0 additions & 6 deletions contracts/contracts/vault/OETHVaultCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,5 @@ import { VaultCore } from "./VaultCore.sol";
* @author Origin Protocol Inc
*/
contract OETHVaultCore is VaultCore {
// slither-disable-next-line constable-states
uint256 private _deprecated_wethAssetIndex;

// For future use (because OETHBaseVaultCore inherits from this)
uint256[50] private __gap;

constructor(address _weth) VaultCore(_weth) {}
}
14 changes: 3 additions & 11 deletions contracts/contracts/vault/OSonicVaultCore.sol
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import { OETHVaultCore } from "./OETHVaultCore.sol";
import { VaultCore } from "./VaultCore.sol";

/**
* @title Origin Sonic VaultCore contract on Sonic
* @author Origin Protocol Inc
*/
contract OSonicVaultCore is OETHVaultCore {
contract OSonicVaultCore is VaultCore {
/// @param _wS Sonic's Wrapped S token
constructor(address _wS) OETHVaultCore(_wS) {}

/**
* @notice Instant redeem is not supported on Sonic.
* Use the asynchronous `requestWithdrawal` a `claimWithdrawal` instead.
*/
function _redeem(uint256, uint256) internal override {
revert("unsupported function");
}
constructor(address _wS) VaultCore(_wS) {}
}
21 changes: 0 additions & 21 deletions contracts/contracts/vault/OUSDVaultCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,5 @@ import { VaultCore } from "./VaultCore.sol";
* @author Origin Protocol Inc
*/
contract OUSDVaultCore is VaultCore {
// For future use (because OETHBaseVaultCore inherits from this)
uint256[50] private __gap;

constructor(address _usdc) VaultCore(_usdc) {}

// @inheritdoc VaultCore
function _redeem(uint256 _amount, uint256 _minimumUnitAmount)
internal
virtual
override
{
// Only Strategist or Governor can redeem using the Vault for now.
// We don't have the onlyGovernorOrStrategist modifier on VaultCore.
// Since we won't be using that modifier anywhere in the VaultCore as well,
// the check has been added inline instead of moving it to VaultStorage.
require(
msg.sender == strategistAddr || isGovernor(),
"Caller is not the Strategist or Governor"
);

super._redeem(_amount, _minimumUnitAmount);
}
}
11 changes: 0 additions & 11 deletions contracts/contracts/vault/VaultAdmin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,6 @@ abstract contract VaultAdmin is VaultStorage {
/***************************************
Configuration
****************************************/

/**
* @notice Set a fee in basis points to be charged for a redeem.
* @param _redeemFeeBps Basis point fee to be charged
*/
function setRedeemFeeBps(uint256 _redeemFeeBps) external onlyGovernor {
require(_redeemFeeBps <= 1000, "Redeem fee should not be over 10%");
redeemFeeBps = _redeemFeeBps;
emit RedeemFeeUpdated(_redeemFeeBps);
}

/**
* @notice Set a buffer of asset to keep in the Vault to handle most
* redemptions without needing to spend gas unwinding asset from a Strategy.
Expand Down
156 changes: 30 additions & 126 deletions contracts/contracts/vault/VaultCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ import "./VaultInitializer.sol";
abstract contract VaultCore is VaultInitializer {
using SafeERC20 for IERC20;
using StableMath for uint256;
/// @dev max signed int
uint256 internal constant MAX_INT = uint256(type(int256).max);

/**
* @dev Verifies that the rebasing is not paused.
Expand All @@ -43,7 +41,7 @@ abstract contract VaultCore is VaultInitializer {
constructor(address _asset) VaultInitializer(_asset) {}

////////////////////////////////////////////////////
/// MINT / REDEEM / BURN ///
/// MINT / BURN ///
////////////////////////////////////////////////////
/**
* @notice Deposit a supported asset and mint OTokens.
Expand Down Expand Up @@ -134,85 +132,6 @@ abstract contract VaultCore is VaultInitializer {
oUSD.mint(msg.sender, _amount);
}

/**
* @notice Withdraw a supported asset and burn OTokens.
* @param _amount Amount of OTokens to burn
* @param _minimumUnitAmount Minimum stablecoin units to receive in return
*/
function redeem(uint256 _amount, uint256 _minimumUnitAmount)
external
whenNotCapitalPaused
nonReentrant
{
_redeem(_amount, _minimumUnitAmount);
}

/**
* @notice Withdraw a supported asset and burn OTokens.
* @param _amount Amount of OTokens to burn
* @param _minimumUnitAmount Minimum stablecoin units to receive in return
*/
function _redeem(uint256 _amount, uint256 _minimumUnitAmount)
internal
virtual
{
emit Redeem(msg.sender, _amount);

if (_amount == 0) return;

// Amount excluding fees
// No fee for the strategist or the governor, makes it easier to do operations
uint256 amountMinusFee = (msg.sender == strategistAddr || isGovernor())
? _amount.scaleBy(assetDecimals, 18)
: _calculateRedeemOutput(_amount);

require(
amountMinusFee >= _minimumUnitAmount,
"Redeem amount lower than minimum"
);

// Is there enough asset in the Vault available after accounting for the withdrawal queue
require(_assetAvailable() >= amountMinusFee, "Liquidity error");

// Transfer asset minus the fee to the redeemer
IERC20(asset).safeTransfer(msg.sender, amountMinusFee);

// Burn OToken from user (including fees)
oUSD.burn(msg.sender, _amount);

// Prevent insolvency
_postRedeem(_amount);
}

function _postRedeem(uint256 _amount) internal {
// Until we can prove that we won't affect the prices of our asset
// by withdrawing them, this should be here.
// It's possible that a strategy was off on its asset total, perhaps
// a reward token sold for more or for less than anticipated.
uint256 totalUnits = 0;
if (_amount >= rebaseThreshold && !rebasePaused) {
totalUnits = _rebase();
} else {
totalUnits = _totalValue();
}

// Check that the OTokens are backed by enough asset
if (maxSupplyDiff > 0) {
// If there are more outstanding withdrawal requests than asset in the vault and strategies
// then the available asset will be negative and totalUnits will be rounded up to zero.
// As we don't know the exact shortfall amount, we will reject all redeem and withdrawals
require(totalUnits > 0, "Too many outstanding requests");

// Allow a max difference of maxSupplyDiff% between
// asset value and OUSD total supply
uint256 diff = oUSD.totalSupply().divPrecisely(totalUnits);
require(
(diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,
"Backing supply liquidity error"
);
}
}

/**
* @notice Burn OTokens for an allowed Strategy
* @param _amount Amount of OToken to burn
Expand Down Expand Up @@ -425,6 +344,35 @@ abstract contract VaultCore is VaultInitializer {
return request.amount;
}

function _postRedeem(uint256 _amount) internal {
// Until we can prove that we won't affect the prices of our asset
// by withdrawing them, this should be here.
// It's possible that a strategy was off on its asset total, perhaps
// a reward token sold for more or for less than anticipated.
uint256 totalUnits = 0;
if (_amount >= rebaseThreshold && !rebasePaused) {
totalUnits = _rebase();
} else {
totalUnits = _totalValue();
}

// Check that the OTokens are backed by enough asset
if (maxSupplyDiff > 0) {
// If there are more outstanding withdrawal requests than asset in the vault and strategies
// then the available asset will be negative and totalUnits will be rounded up to zero.
// As we don't know the exact shortfall amount, we will reject all redeem and withdrawals
require(totalUnits > 0, "Too many outstanding requests");

// Allow a max difference of maxSupplyDiff% between
// asset value and OUSD total supply
uint256 diff = oUSD.totalSupply().divPrecisely(totalUnits);
require(
(diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,
"Backing supply liquidity error"
);
}
}

/**
* @notice Allocate unallocated funds on Vault to strategies.
*/
Expand Down Expand Up @@ -675,50 +623,6 @@ abstract contract VaultCore is VaultInitializer {
return balance + queue.claimed - queue.queued;
}

/**
* @notice Deprecated. Use calculateRedeemOutput instead.
*/
function calculateRedeemOutputs(uint256 _amount)
external
view
returns (uint256[] memory outputs)
{
outputs = new uint256[](1);
outputs[0] = _calculateRedeemOutput(_amount);
}

/**
* @notice Calculate the amount of asset received on redeeming OToken.
* @param _amount Amount of OToken to redeem
* @return Amount of asset received
*/
function calculateRedeemOutput(uint256 _amount)
external
view
returns (uint256)
{
return _calculateRedeemOutput(_amount);
}

/**
* @dev Calculate the amount of asset received on redeeming OToken.
* @param _amount Amount of OToken to redeem
* @return Amount of asset received
*/
function _calculateRedeemOutput(uint256 _amount)
internal
view
virtual
returns (uint256)
{
// Calculate redeem fee
if (redeemFeeBps > 0) {
uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4);
_amount = _amount - redeemFee;
}
return _amount.scaleBy(assetDecimals, 18);
}

/**
* @notice Adds WETH to the withdrawal queue if there is a funding shortfall.
* @dev is called from the Native Staking strategy when validator withdrawals are processed.
Expand Down
2 changes: 0 additions & 2 deletions contracts/contracts/vault/VaultInitializer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ abstract contract VaultInitializer is VaultStorage {
rebasePaused = false;
capitalPaused = true;

// Initial redeem fee of 0 basis points
redeemFeeBps = 0;
// Initial Vault buffer of 0%
vaultBuffer = 0;
// Initial allocate threshold of 25,000 OUSD
Expand Down
Loading
Loading