Skip to content

Commit

Permalink
forge format
Browse files Browse the repository at this point in the history
  • Loading branch information
ewansheldon committed Oct 2, 2024
1 parent 285e89e commit 23bb66b
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 82 deletions.
22 changes: 13 additions & 9 deletions contracts/PriceCalculator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ contract PriceCalculator is IPriceCalculator, Ownable {
error SequencerDown();
error GracePeriodNotOver();

constructor (bytes32 _native, address _USDCToUSDAddr, address _sequencerUptimeFeed) {
constructor(bytes32 _native, address _USDCToUSDAddr, address _sequencerUptimeFeed) {
NATIVE = _native;
USDCToUSDAddr = _USDCToUSDAddr;
sequencerUptimeFeed = Chainlink.AggregatorV3Interface(_sequencerUptimeFeed);
}

function validateSequencerUp() private view {
(,int256 answer,uint256 startedAt,,) = sequencerUptimeFeed.latestRoundData();
(, int256 answer, uint256 startedAt,,) = sequencerUptimeFeed.latestRoundData();
bool isSequencerUp = answer == 0;
if (!isSequencerUp) {
revert SequencerDown();
Expand All @@ -38,7 +38,11 @@ contract PriceCalculator is IPriceCalculator, Ownable {
}
}

function overscaledCollateral(ITokenManager.Token memory _token, uint256 _tokenValue) private view returns (uint256 _scaledValue) {
function overscaledCollateral(ITokenManager.Token memory _token, uint256 _tokenValue)
private
view
returns (uint256 _scaledValue)
{
uint8 _dec = _token.symbol == NATIVE ? 18 : ERC20(_token.addr).decimals();
return _tokenValue * 10 ** (36 - _dec);
}
Expand All @@ -50,22 +54,22 @@ contract PriceCalculator is IPriceCalculator, Ownable {

function validateData(uint80 _roundId, int256 _answer, uint256 _updatedAt, address _dataFeed) private view {
validateSequencerUp();
if(_roundId == 0) revert InvalidRoundId();
if(_answer == 0) revert InvalidPrice();
if(_updatedAt == 0 || _updatedAt > block.timestamp) revert InvalidUpdate();
if(block.timestamp - _updatedAt > getTimeout(_dataFeed)) revert StalePrice();
if (_roundId == 0) revert InvalidRoundId();
if (_answer == 0) revert InvalidPrice();
if (_updatedAt == 0 || _updatedAt > block.timestamp) revert InvalidUpdate();
if (block.timestamp - _updatedAt > getTimeout(_dataFeed)) revert StalePrice();
}

function tokenToUSD(ITokenManager.Token memory _token, uint256 _tokenValue) external view returns (uint256) {
Chainlink.AggregatorV3Interface tokenUsdClFeed = Chainlink.AggregatorV3Interface(_token.clAddr);
(uint80 _roundId, int256 _tokenUsdPrice, , uint256 _updatedAt, ) = tokenUsdClFeed.latestRoundData();
(uint80 _roundId, int256 _tokenUsdPrice,, uint256 _updatedAt,) = tokenUsdClFeed.latestRoundData();
validateData(_roundId, _tokenUsdPrice, _updatedAt, _token.clAddr);
return overscaledCollateral(_token, _tokenValue) * uint256(_tokenUsdPrice) / 10 ** _token.clDec / 1e18;
}

function USDCToUSD(uint256 _amount, uint8 _dec) external view returns (uint256) {
Chainlink.AggregatorV3Interface _clUSDCToUSD = Chainlink.AggregatorV3Interface(USDCToUSDAddr);
(uint80 _roundId, int256 _USDCToUSDPrice, , uint256 _updatedAt, ) = _clUSDCToUSD.latestRoundData();
(uint80 _roundId, int256 _USDCToUSDPrice,, uint256 _updatedAt,) = _clUSDCToUSD.latestRoundData();
validateData(_roundId, _USDCToUSDPrice, _updatedAt, USDCToUSDAddr);
return _amount * uint256(_USDCToUSDPrice) * 10 ** (18 - _dec) / 10 ** _clUSDCToUSD.decimals();
}
Expand Down
5 changes: 1 addition & 4 deletions contracts/SmartVaultManagerV6.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,7 @@ contract SmartVaultManagerV6 is
address _smartVaultIndex,
address _nftMetadataGenerator,
uint16 _userVaultLimit
)
public
initializer
{
) public initializer {
__ERC721_init("The Standard Smart Vault Manager (USDs)", "TS-VAULTMAN-USDs");
__Ownable_init();
collateralRate = _collateralRate;
Expand Down
82 changes: 56 additions & 26 deletions contracts/SmartVaultV4.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ contract SmartVaultV4 is ISmartVault {
_;
}

modifier remainCollateralised {
modifier remainCollateralised() {
_;
if (undercollateralised()) revert Undercollateralised();
}
Expand Down Expand Up @@ -121,7 +121,7 @@ contract SmartVaultV4 is ISmartVault {
}
}
}

function usdCollateral() private view returns (uint256 _usd) {
ITokenManager tokenManager = ITokenManager(ISmartVaultManagerV3(manager).tokenManager());
ITokenManager.Token[] memory acceptedTokens = tokenManager.getAcceptedTokens();
Expand Down Expand Up @@ -173,12 +173,14 @@ contract SmartVaultV4 is ISmartVault {
liquidated = true;
minted = 0;
// remove all erc20 collateral
ITokenManager.Token[] memory tokens = ITokenManager(ISmartVaultManagerV3(manager).tokenManager()).getAcceptedTokens();
ITokenManager.Token[] memory tokens =
ITokenManager(ISmartVaultManagerV3(manager).tokenManager()).getAcceptedTokens();
for (uint256 i = 0; i < tokens.length; i++) {
if (tokens[i].symbol != NATIVE) {
IERC20 _token = IERC20(tokens[i].addr);
if (_token.balanceOf(address(this)) != 0) {
try _token.transfer(_liquidator, _token.balanceOf(address(this))) {} catch {
try _token.transfer(_liquidator, _token.balanceOf(address(this))) {}
catch {
emit FailedTransfer(address(_token), _token.balanceOf(address(this)));
}
}
Expand All @@ -187,7 +189,9 @@ contract SmartVaultV4 is ISmartVault {
// remove all hypervisor tokens
for (uint256 i = 0; i < hypervisors.length; i++) {
IERC20 _hypervisor = IERC20(hypervisors[i]);
if (_hypervisor.balanceOf(address(this)) != 0) _hypervisor.safeTransfer(_liquidator, _hypervisor.balanceOf(address(this)));
if (_hypervisor.balanceOf(address(this)) != 0) {
_hypervisor.safeTransfer(_liquidator, _hypervisor.balanceOf(address(this)));
}
}
// remove eth
if (address(this).balance != 0) {
Expand Down Expand Up @@ -250,27 +254,35 @@ contract SmartVaultV4 is ISmartVault {
return _token.addr == address(0) ? ISmartVaultManagerV3(manager).weth() : _token.addr;
}

function executeSwapAndFee(ISwapRouter.ExactInputSingleParams memory _params, uint256 _swapFee) private returns (uint256 _amountOut) {
function executeSwapAndFee(ISwapRouter.ExactInputSingleParams memory _params, uint256 _swapFee)
private
returns (uint256 _amountOut)
{
IERC20(_params.tokenIn).safeTransfer(ISmartVaultManagerV3(manager).protocol(), _swapFee);
IERC20(_params.tokenIn).safeApprove(ISmartVaultManagerV3(manager).swapRouter(), _params.amountIn);
_amountOut = ISwapRouter(ISmartVaultManagerV3(manager).swapRouter()).exactInputSingle(_params);
IERC20(_params.tokenIn).safeApprove(ISmartVaultManagerV3(manager).swapRouter(), 0);
}

function swap(bytes32 _inToken, bytes32 _outToken, uint256 _amount, uint256 _minOut, uint24 _fee, uint256 _deadline) external onlyOwner remainCollateralised {
uint256 swapFee = _amount * ISmartVaultManagerV3(manager).swapFeeRate() / ISmartVaultManagerV3(manager).HUNDRED_PC();
function swap(bytes32 _inToken, bytes32 _outToken, uint256 _amount, uint256 _minOut, uint24 _fee, uint256 _deadline)
external
onlyOwner
remainCollateralised
{
uint256 swapFee =
_amount * ISmartVaultManagerV3(manager).swapFeeRate() / ISmartVaultManagerV3(manager).HUNDRED_PC();
address inToken = getTokenisedAddr(_inToken);
if (_inToken == NATIVE) IWETH(ISmartVaultManagerV3(manager).weth()).deposit{ value: _amount }();
if (_inToken == NATIVE) IWETH(ISmartVaultManagerV3(manager).weth()).deposit{value: _amount}();
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: inToken,
tokenOut: getTokenisedAddr(_outToken),
fee: _fee,
recipient: address(this),
deadline: _deadline,
amountIn: _amount - swapFee,
amountOutMinimum: _minOut,
sqrtPriceLimitX96: 0
});
tokenIn: inToken,
tokenOut: getTokenisedAddr(_outToken),
fee: _fee,
recipient: address(this),
deadline: _deadline,
amountIn: _amount - swapFee,
amountOutMinimum: _minOut,
sqrtPriceLimitX96: 0
});
uint256 _amountOut = executeSwapAndFee(params, swapFee);
if (_outToken == NATIVE) {
IWETH(ISmartVaultManagerV3(manager).weth()).withdraw(_amountOut);
Expand All @@ -293,11 +305,21 @@ contract SmartVaultV4 is ISmartVault {
}
}

function significantCollateralDrop(uint256 _preCollateralValue, uint256 _postCollateralValue, uint256 _minCollateralPercentage) private view returns (bool) {
return _postCollateralValue < _minCollateralPercentage * _preCollateralValue / ISmartVaultManagerV3(manager).HUNDRED_PC();
function significantCollateralDrop(
uint256 _preCollateralValue,
uint256 _postCollateralValue,
uint256 _minCollateralPercentage
) private view returns (bool) {
return _postCollateralValue
< _minCollateralPercentage * _preCollateralValue / ISmartVaultManagerV3(manager).HUNDRED_PC();
}

function depositYield(bytes32 _symbol, uint256 _stablePercentage, uint256 _minCollateralPercentage, uint256 _deadline) external onlyOwner withinTimestamp(_deadline) {
function depositYield(
bytes32 _symbol,
uint256 _stablePercentage,
uint256 _minCollateralPercentage,
uint256 _deadline
) external onlyOwner withinTimestamp(_deadline) {
if (_symbol == NATIVE) IWETH(ISmartVaultManagerV3(manager).weth()).deposit{value: address(this).balance}();
address _token = getTokenisedAddr(_symbol);
uint256 _balance = getAssetBalance(_token);
Expand All @@ -309,11 +331,17 @@ contract SmartVaultV4 is ISmartVault {
addUniqueHypervisor(_hypervisor1);
if (_hypervisor2 != address(0)) addUniqueHypervisor(_hypervisor2);
uint256 _postDepositCollateral = usdCollateral();
if (_undercollateralised(_postDepositCollateral) ||
significantCollateralDrop(_preDepositCollateral, _postDepositCollateral, _minCollateralPercentage)) revert Undercollateralised();
if (
_undercollateralised(_postDepositCollateral)
|| significantCollateralDrop(_preDepositCollateral, _postDepositCollateral, _minCollateralPercentage)
) revert Undercollateralised();
}

function withdrawYield(address _hypervisor, bytes32 _symbol, uint256 _minCollateralPercentage, uint256 _deadline) external onlyOwner withinTimestamp(_deadline) {
function withdrawYield(address _hypervisor, bytes32 _symbol, uint256 _minCollateralPercentage, uint256 _deadline)
external
onlyOwner
withinTimestamp(_deadline)
{
address _token = getTokenisedAddr(_symbol);
IERC20(_hypervisor).safeApprove(
ISmartVaultManagerV3(manager).yieldManager(), IERC20(_hypervisor).balanceOf(address(this))
Expand All @@ -325,8 +353,10 @@ contract SmartVaultV4 is ISmartVault {
IWETH(_token).withdraw(getAssetBalance(_token));
}
uint256 _postWithdrawCollateral = usdCollateral();
if (_undercollateralised(_postWithdrawCollateral) ||
significantCollateralDrop(_preWithdrawCollateral, _postWithdrawCollateral, _minCollateralPercentage)) revert Undercollateralised();
if (
_undercollateralised(_postWithdrawCollateral)
|| significantCollateralDrop(_preWithdrawCollateral, _postWithdrawCollateral, _minCollateralPercentage)
) revert Undercollateralised();
}

function yieldAssets() external view returns (YieldPair[] memory _yieldPairs) {
Expand Down
31 changes: 17 additions & 14 deletions contracts/SmartVaultYieldManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,7 @@ contract SmartVaultYieldManager is ISmartVaultYieldManager, Ownable {

function _swapToSingleAsset(address _hypervisor, address _wantedToken, address _swapRouter, uint24 _fee) private {
address _token0 = IHypervisor(_hypervisor).token0();
address _unwantedToken = _token0 == _wantedToken ?
IHypervisor(_hypervisor).token1() :
_token0;
address _unwantedToken = _token0 == _wantedToken ? IHypervisor(_hypervisor).token1() : _token0;
uint256 _balance = _thisBalanceOf(_unwantedToken);
IERC20(_unwantedToken).safeApprove(_swapRouter, _balance);
ISwapRouter(_swapRouter).exactInputSingle(
Expand Down Expand Up @@ -285,18 +283,25 @@ contract SmartVaultYieldManager is ISmartVaultYieldManager, Ownable {
bytes memory _pathFromUSDC = hypervisorData[_token].pathFromUSDC;
uint256 _balance = _thisBalanceOf(USDC);
IERC20(USDC).safeApprove(uniswapRouter, _balance);
ISwapRouter(uniswapRouter).exactInput(ISwapRouter.ExactInputParams({
path: _pathFromUSDC,
recipient: address(this),
deadline: block.timestamp + 60,
amountIn: _balance,
amountOutMinimum: 0
}));
ISwapRouter(uniswapRouter).exactInput(
ISwapRouter.ExactInputParams({
path: _pathFromUSDC,
recipient: address(this),
deadline: block.timestamp + 60,
amountIn: _balance,
amountOutMinimum: 0
})
);
IERC20(USDC).safeApprove(uniswapRouter, 0);
}

function _withdrawUSDsDeposit(address _token) private {
IHypervisor(usdsHypervisor).withdraw(_thisBalanceOf(usdsHypervisor), address(this), address(this), [uint256(0),uint256(0),uint256(0),uint256(0)]);
IHypervisor(usdsHypervisor).withdraw(
_thisBalanceOf(usdsHypervisor),
address(this),
address(this),
[uint256(0), uint256(0), uint256(0), uint256(0)]
);
_swapToSingleAsset(usdsHypervisor, USDC, ramsesRouter, 500);
_sellUSDC(_token);
}
Expand All @@ -312,9 +317,7 @@ contract SmartVaultYieldManager is ISmartVaultYieldManager, Ownable {

function withdraw(address _hypervisor, address _token) external {
IERC20(_hypervisor).safeTransferFrom(msg.sender, address(this), IERC20(_hypervisor).balanceOf(msg.sender));
_hypervisor == usdsHypervisor ?
_withdrawUSDsDeposit(_token) :
_withdrawOtherDeposit(_hypervisor, _token);
_hypervisor == usdsHypervisor ? _withdrawUSDsDeposit(_token) : _withdrawOtherDeposit(_hypervisor, _token);
uint256 _withdrawn = _thisBalanceOf(_token);
uint256 _fee = _withdrawn * feeRate / HUNDRED_PC;
_withdrawn = _withdrawn - _fee;
Expand Down
6 changes: 5 additions & 1 deletion contracts/test_utils/ChainlinkMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ contract ChainlinkMock is AggregatorV3Interface {
startedAt = _startedAt;
}

function latestRoundData() external view returns (uint80 _roundID,int256 _answer,uint256 _startedAt,uint256 _updatedAt,uint80) {
function latestRoundData()
external
view
returns (uint80 _roundID, int256 _answer, uint256 _startedAt, uint256 _updatedAt, uint80)
{
_roundID = roundID;
_answer = price;
_startedAt = startedAt;
Expand Down
4 changes: 1 addition & 3 deletions contracts/test_utils/MockSwapRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ contract MockSwapRouter is ISwapRouter, IPeripheryImmutableState {
}

function receivedSwap() external view returns (MockSwapData memory) {
return MockSwapData(
tokenIn, tokenOut, fee, recipient, deadline, amountIn, amountOutMinimum, sqrtPriceLimitX96
);
return MockSwapData(tokenIn, tokenOut, fee, recipient, deadline, amountIn, amountOutMinimum, sqrtPriceLimitX96);
}

function exactInput(ExactInputParams calldata params) external payable returns (uint256 _amountOut) {
Expand Down
4 changes: 1 addition & 3 deletions test/foundry/SmartVault.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -483,9 +483,7 @@ contract SmartVaultTest is SmartVaultFixture, Test {

uint256 hypervisorBalance = IHypervisor(hypervisor).balanceOf(address(smartVault));
vm.expectRevert(SmartVaultV4.Undercollateralised.selector);
smartVault.removeAsset(
yieldPairs[0].hypervisor, hypervisorBalance, VAULT_OWNER
);
smartVault.removeAsset(yieldPairs[0].hypervisor, hypervisorBalance, VAULT_OWNER);
}

// Helper functions
Expand Down
2 changes: 1 addition & 1 deletion test/foundry/SmartVaultManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ contract SmartVaultManagerTest is SmartVaultManagerFixture, Test {
// Attempt to liquidate without USDs to burn
vm.expectRevert("ERC20: burn amount exceeds balance");
smartVaultManager.liquidateVault(tokenId);

// mint extra because of outstanding fees in vault debt
usds.mint(liquidator, mintValue * 2);

Expand Down
3 changes: 2 additions & 1 deletion test/foundry/fixtures/ForkFixture.sol
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ contract ForkFixture is Test {
function _deployVaultManager() internal {
// deploy SmartVaultManager
smartVaultManager = new SmartVaultManagerV6();
PriceCalculator priceCalculator = new PriceCalculator(NATIVE, CL_USDC_USD_ADDRESS, CL_L2_SEQUENCER_UPTIME_FEED_ADDRESS);
PriceCalculator priceCalculator =
new PriceCalculator(NATIVE, CL_USDC_USD_ADDRESS, CL_L2_SEQUENCER_UPTIME_FEED_ADDRESS);
SmartVaultDeployerV4 smartVaultDeployer = new SmartVaultDeployerV4(NATIVE, address(priceCalculator));
SmartVaultIndex smartVaultIndex = new SmartVaultIndex();
MockNFTMetadataGenerator nftMetadataGenerator = new MockNFTMetadataGenerator();
Expand Down
4 changes: 1 addition & 3 deletions test/foundry/fixtures/SmartVaultFixture.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ contract SmartVaultFixture is SmartVaultYieldManagerFixture {
function _createStandaloneSmartVault(address owner) internal returns (SmartVaultV4 vault) {
// NOTE: Smart vault is deployed bypassing the manager, so we need to grant USDs minter/burner roles

vault = new SmartVaultV4(
NATIVE, address(smartVaultManager), owner, address(usds), address(priceCalculator)
);
vault = new SmartVaultV4(NATIVE, address(smartVaultManager), owner, address(usds), address(priceCalculator));
usds.grantRole(usds.MINTER_ROLE(), address(vault));
usds.grantRole(usds.BURNER_ROLE(), address(vault));
}
Expand Down
Loading

0 comments on commit 23bb66b

Please sign in to comment.