Skip to content

Commit

Permalink
other mitigation changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Picodes committed Jul 14, 2023
1 parent f8d0bf7 commit 66bba3f
Show file tree
Hide file tree
Showing 14 changed files with 158 additions and 105 deletions.
6 changes: 5 additions & 1 deletion contracts/savings/Savings.sol
Expand Up @@ -224,7 +224,11 @@ contract Savings is BaseSavings {
}

/// @notice Updates the inflation rate for depositing `asset` in this contract
function setRate(uint208 newRate) external onlyGovernor {
/// @dev Guardian can reduce the rate but not increase it
function setRate(uint208 newRate) external {
if (newRate < rate) {
if (!accessControlManager.isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian();
} else if (!accessControlManager.isGovernor(msg.sender)) revert NotGovernor();
_accrue();
rate = newRate;
emit RateUpdated(newRate);
Expand Down
4 changes: 3 additions & 1 deletion contracts/savings/SavingsVest.sol
Expand Up @@ -36,7 +36,7 @@ contract SavingsVest is BaseSavings {
uint64 public protocolSafetyFee;

/// @notice The period in seconds over which locked profit is unlocked
/// @dev Cannot be 0 as it opens the system to sandwich attacks
/// @dev A vesting period of 0 opens the system to sandwich attacks
uint32 public vestingPeriod;

/// @notice Minimum time between two calls to the `accrue` function
Expand All @@ -52,6 +52,7 @@ contract SavingsVest is BaseSavings {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/

event FiledUint64(uint64 param, bytes32 what);
event SurplusManagerUpdated(address indexed _surplusManager);

/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INITIALIZATION
Expand Down Expand Up @@ -199,6 +200,7 @@ contract SavingsVest is BaseSavings {
/// @notice Sets the `surplusManager` address which handles protocol fees
function setSurplusManager(address _surplusManager) external onlyGuardian {
surplusManager = _surplusManager;
emit SurplusManagerUpdated(_surplusManager);
}

/// @notice Changes the contract parameters
Expand Down
2 changes: 1 addition & 1 deletion contracts/transmuter/DiamondProxy.sol
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: CC0-1.0
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

Expand Down
19 changes: 10 additions & 9 deletions contracts/transmuter/Storage.sol
Expand Up @@ -42,22 +42,19 @@ enum QuoteType {
enum OracleReadType {
CHAINLINK_FEEDS,
EXTERNAL,
NO_ORACLE
}

enum OracleQuoteType {
UNIT,
TARGET
}

enum OracleTargetType {
NO_ORACLE,
STABLE,
WSTETH,
CBETH,
RETH,
SFRXETH
}

enum OracleQuoteType {
UNIT,
TARGET
}

enum WhitelistType {
BACKED
}
Expand Down Expand Up @@ -94,6 +91,10 @@ struct DiamondStorage {
IAccessControlManager accessControlManager; // Contract handling access control
}

struct ImplementationStorage {
address implementation; // Dummy implementation address for Etherscan usability
}

struct ManagerStorage {
IERC20[] subCollaterals; // Subtokens handled by the manager or strategies
bytes config; // Additional configuration data
Expand Down
11 changes: 8 additions & 3 deletions contracts/transmuter/facets/Getters.sol
Expand Up @@ -125,7 +125,11 @@ contract Getters is IGetters {
/// @inheritdoc IGetters
function getOracle(
address collateral
) external view returns (OracleReadType readType, OracleTargetType targetType, bytes memory data) {
)
external
view
returns (OracleReadType oracleType, OracleReadType targetType, bytes memory oracleData, bytes memory targetData)
{
return LibOracle.getOracle(collateral);
}

Expand Down Expand Up @@ -156,11 +160,12 @@ contract Getters is IGetters {

/// @inheritdoc IGetters
function isWhitelistedForType(WhitelistType whitelistType, address sender) external view returns (bool) {
return LibWhitelist.isWhitelistedForType(whitelistType, sender);
return s.transmuterStorage().isWhitelistedForType[whitelistType][sender] > 0;
}

/// @inheritdoc IGetters
function isWhitelistedForCollateral(address collateral, address sender) external view returns (bool) {
/// @dev This function is non view as it may consult external non view functions from whitelist providers
function isWhitelistedForCollateral(address collateral, address sender) external returns (bool) {
Collateral storage collatInfo = s.transmuterStorage().collaterals[collateral];
return (collatInfo.onlyWhitelisted == 0 || LibWhitelist.checkWhitelist(collatInfo.whitelistData, sender));
}
Expand Down
1 change: 1 addition & 0 deletions contracts/transmuter/facets/SettersGovernor.sol
Expand Up @@ -68,6 +68,7 @@ contract SettersGovernor is AccessControlModifiers, ISettersGovernor {
}

/// @inheritdoc ISettersGovernor
/// @dev Collateral assets with a fee on transfer are not supported by the system
function addCollateral(address collateral) external onlyGovernor {
LibSetters.addCollateral(collateral);
}
Expand Down
36 changes: 18 additions & 18 deletions contracts/transmuter/facets/Swapper.sol
Expand Up @@ -2,9 +2,9 @@

pragma solidity ^0.8.19;

import { Address } from "oz/utils/Address.sol";
import { IERC20 } from "oz/token/ERC20/IERC20.sol";
import { SafeERC20 } from "oz/token/ERC20/utils/SafeERC20.sol";
import { Address } from "oz/utils/Address.sol";
import { Math } from "oz/utils/math/Math.sol";
import { SafeCast } from "oz/utils/math/SafeCast.sol";

Expand All @@ -13,12 +13,12 @@ import { ISwapper } from "interfaces/ISwapper.sol";
import { IPermit2, PermitTransferFrom } from "interfaces/external/permit2/IPermit2.sol";
import { SignatureTransferDetails, TokenPermissions } from "interfaces/external/permit2/IPermit2.sol";

import { AccessControlModifiers } from "./AccessControlModifiers.sol";
import { LibHelpers } from "../libraries/LibHelpers.sol";
import { LibManager } from "../libraries/LibManager.sol";
import { LibOracle } from "../libraries/LibOracle.sol";
import { LibStorage as s } from "../libraries/LibStorage.sol";
import { LibWhitelist } from "../libraries/LibWhitelist.sol";
import { AccessControlModifiers } from "./AccessControlModifiers.sol";

import "../../utils/Constants.sol";
import "../../utils/Errors.sol";
Expand Down Expand Up @@ -155,7 +155,7 @@ contract Swapper is ISwapper, AccessControlModifiers {
if (mint) return _quoteMintExactInput(collatInfo, amountIn);
else {
amountOut = _quoteBurnExactInput(tokenOut, collatInfo, amountIn);
_checkAmounts(collatInfo, amountOut);
_checkAmounts(tokenOut, collatInfo, amountOut);
}
}

Expand All @@ -164,7 +164,7 @@ contract Swapper is ISwapper, AccessControlModifiers {
(bool mint, Collateral storage collatInfo) = _getMintBurn(tokenIn, tokenOut, 0);
if (mint) return _quoteMintExactOutput(collatInfo, amountOut);
else {
_checkAmounts(collatInfo, amountOut);
_checkAmounts(tokenOut, collatInfo, amountOut);
return _quoteBurnExactOutput(tokenOut, collatInfo, amountOut);
}
}
Expand All @@ -190,8 +190,8 @@ contract Swapper is ISwapper, AccessControlModifiers {
uint128 changeAmount = (amountOut.mulDiv(BASE_27, ts.normalizer, Math.Rounding.Up)).toUint128();
// The amount of stablecoins issued from a collateral are not stored as absolute variables, but
// as variables normalized by a `normalizer`
collatInfo.normalizedStables += uint216(changeAmount);
ts.normalizedStables += changeAmount;
collatInfo.normalizedStables = collatInfo.normalizedStables + uint216(changeAmount);
ts.normalizedStables = ts.normalizedStables + changeAmount;
if (permitData.length > 0) {
PERMIT_2.functionCall(permitData);
} else if (collatInfo.isManaged > 0)
Expand All @@ -211,8 +211,8 @@ contract Swapper is ISwapper, AccessControlModifiers {
uint128 changeAmount = ((amountIn * BASE_27) / ts.normalizer).toUint128();
// This will underflow when the system is trying to burn more stablecoins than what has been issued
// from this collateral
collatInfo.normalizedStables -= uint216(changeAmount);
ts.normalizedStables -= changeAmount;
collatInfo.normalizedStables = collatInfo.normalizedStables - uint216(changeAmount);
ts.normalizedStables = ts.normalizedStables - changeAmount;
IAgToken(tokenIn).burnSelf(amountIn, msg.sender);
if (collatInfo.isManaged > 0)
LibManager.release(tokenOut, to, amountOut, collatInfo.managerData.config);
Expand Down Expand Up @@ -388,7 +388,7 @@ contract Swapper is ISwapper, AccessControlModifiers {
// In the mint case:
// `m_t = (-1-g(0)+sqrt[(1+g(0))**2+2M(f_{i+1}-g(0))/b_{i+1})]/((f_{i+1}-g(0))/b_{i+1})`
// And so: g(0)+(f_{i+1}-f_i)/(b_{i+1}-b_i)m_t/2
// = (g(0)-1+sqrt[(1+g(0))**2+2M(f_{i+1}-g(0))/b_{i+1})])
// = (g(0)-1+sqrt[(1+g(0))**2+2M(f_{i+1}-g(0))/b_{i+1})]) / 2
midFee = int64(
(int256(
Math.sqrt((uint256(int256(BASE_9) + currentFees)) ** 2 + ac4, Math.Rounding.Up)
Expand All @@ -400,7 +400,7 @@ contract Swapper is ISwapper, AccessControlModifiers {
// In the burn case:
// `m_t = (1-g(0)+sqrt[(1-g(0))**2-2M(f_{i+1}-g(0))/b_{i+1})]/((f_{i+1}-g(0))/b_{i+1})`
// And so: g(0)+(f_{i+1}-f_i)/(b_{i+1}-b_i)m_t/2
// = (g(0)+1-sqrt[(1-g(0))**2-2M(f_{i+1}-g(0))/b_{i+1})])
// = (g(0)+1-sqrt[(1-g(0))**2-2M(f_{i+1}-g(0))/b_{i+1})]) / 2

uint256 baseMinusCurrentSquared = (uint256(int256(BASE_9) - currentFees)) ** 2;
// Mathematically, this condition is always verified, but rounding errors may make this
Expand Down Expand Up @@ -444,12 +444,12 @@ contract Swapper is ISwapper, AccessControlModifiers {
_computeFee(quoteType, amountStable, v.isMint ? collatInfo.yFeeMint[n - 1] : collatInfo.yFeeBurn[n - 1]);
}

/// @notice Checks whether a managed collateral asset still has enough collateral available to process
/// a transfer
function _checkAmounts(Collateral storage collatInfo, uint256 amountOut) internal view {
// Checking if enough is available for collateral assets that involve manager addresses
if (collatInfo.isManaged > 0 && LibManager.maxAvailable(collatInfo.managerData.config) < amountOut)
revert InvalidSwap();
/// @notice Checks whether there is still enough of the collateral to process the transfer
function _checkAmounts(address collateral, Collateral storage collatInfo, uint256 amountOut) internal view {
if (
(collatInfo.isManaged > 0 && LibManager.maxAvailable(collatInfo.managerData.config) < amountOut) ||
(collatInfo.isManaged == 0 && IERC20(collateral).balanceOf(address(this)) < amountOut)
) revert InvalidSwap();
}

/// @notice Checks whether a swap from `tokenIn` to `tokenOut` is a mint or a burn, whether the
Expand Down Expand Up @@ -490,7 +490,7 @@ contract Swapper is ISwapper, AccessControlModifiers {
/// @notice Builds a permit2 `permitTransferFrom` payload for a `tokenIn` transfer
/// @dev The transfer should be from `msg.sender` to this contract or a manager
function _buildPermitTransferPayload(
uint256 amount,
uint256 amountIn,
uint256 approvedAmount,
address tokenIn,
uint256 deadline,
Expand All @@ -508,7 +508,7 @@ contract Swapper is ISwapper, AccessControlModifiers {
nonce: details.nonce,
deadline: deadline
}),
SignatureTransferDetails({ to: details.to, requestedAmount: amount }),
SignatureTransferDetails({ to: details.to, requestedAmount: amountIn }),
msg.sender,
details.signature
);
Expand Down
12 changes: 8 additions & 4 deletions contracts/transmuter/libraries/LibDiamond.sol
Expand Up @@ -31,7 +31,8 @@ library LibDiamond {

/// @notice Internal function version of `diamondCut`
function diamondCut(FacetCut[] memory _diamondCut, address _init, bytes memory _calldata) internal {
for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
uint256 diamondCutLength = _diamondCut.length;
for (uint256 facetIndex; facetIndex < diamondCutLength; facetIndex++) {
bytes4[] memory functionSelectors = _diamondCut[facetIndex].functionSelectors;
address facetAddress = _diamondCut[facetIndex].facetAddress;

Expand Down Expand Up @@ -85,7 +86,8 @@ library LibDiamond {
DiamondStorage storage ds = s.diamondStorage();
uint16 selectorCount = uint16(ds.selectors.length);
_enforceHasContractCode(_facetAddress);
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
uint256 functionSelectorsLength = _functionSelectors.length;
for (uint256 selectorIndex; selectorIndex < functionSelectorsLength; selectorIndex++) {
bytes4 selector = _functionSelectors[selectorIndex];
address oldFacetAddress = ds.selectorInfo[selector].facetAddress;
if (oldFacetAddress != address(0)) {
Expand All @@ -105,7 +107,8 @@ library LibDiamond {
revert CannotReplaceFunctionsFromFacetWithZeroAddress(_functionSelectors);
}
_enforceHasContractCode(_facetAddress);
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
uint256 functionSelectorsLength = _functionSelectors.length;
for (uint256 selectorIndex; selectorIndex < functionSelectorsLength; selectorIndex++) {
bytes4 selector = _functionSelectors[selectorIndex];
address oldFacetAddress = ds.selectorInfo[selector].facetAddress;
// Can't replace immutable functions -- functions defined directly in the diamond in this case
Expand All @@ -131,7 +134,8 @@ library LibDiamond {
if (_facetAddress != address(0)) {
revert RemoveFacetAddressMustBeZeroAddress(_facetAddress);
}
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
uint256 functionSelectorsLength = _functionSelectors.length;
for (uint256 selectorIndex; selectorIndex < functionSelectorsLength; selectorIndex++) {
bytes4 selector = _functionSelectors[selectorIndex];
FacetInfo memory oldFacetAddressAndSelectorPosition = ds.selectorInfo[selector];
if (oldFacetAddressAndSelectorPosition.facetAddress == address(0)) {
Expand Down
2 changes: 1 addition & 1 deletion contracts/transmuter/libraries/LibHelpers.sol
Expand Up @@ -20,7 +20,7 @@ library LibHelpers {
/// or -1 in the other case
function checkList(address token, address[] memory tokens) internal pure returns (int256) {
uint256 tokensLength = tokens.length;
for (uint256 i = 0; i < tokensLength; ++i) {
for (uint256 i; i < tokensLength; ++i) {
if (token == tokens[i]) return int256(i);
}
return -1;
Expand Down

0 comments on commit 66bba3f

Please sign in to comment.