Skip to content

Commit

Permalink
Merge pull request #68 from stabilitydao/fixing
Browse files Browse the repository at this point in the history
23.12.1-alpha
  • Loading branch information
DevTeaLeaf authored Dec 2, 2023
2 parents 7f3e2ff + b6f5fa2 commit eee25ce
Show file tree
Hide file tree
Showing 15 changed files with 309 additions and 91 deletions.
35 changes: 35 additions & 0 deletions script/PrepareUpgrade.23.12.1-alpha.Polygon.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {console} from "forge-std/Test.sol";
import "forge-std/Script.sol";
import "../chains/PolygonLib.sol";
import "../src/core/Factory.sol";
import "../src/core/Zap.sol";
import "../src/core/vaults/CVault.sol";
import "../src/core/vaults/RVault.sol";
import "../src/core/vaults/RMVault.sol";

contract PrepareUpgrade1Polygon is Script {
function run() external {
uint deployerPrivateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);
address newImpl;

newImpl = address(new Factory());
console.log("Factory 1.0.1", newImpl);
newImpl = address(new Zap());
console.log("Zap 1.0.1", newImpl);

newImpl = address(new CVault());
console.log("CVault 1.0.1", newImpl);
newImpl = address(new RVault());
console.log("RVault 1.0.1", newImpl);
newImpl = address(new RMVault());
console.log("RMVault 1.0.1", newImpl);

vm.stopBroadcast();
}

function testDeployPolygon() external {}
}
8 changes: 7 additions & 1 deletion src/core/Factory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ contract Factory is Controllable, ReentrancyGuardUpgradeable, IFactory {
//region ----- Constants -----

/// @inheritdoc IControllable
string public constant VERSION = "1.0.0";
string public constant VERSION = "1.0.1";

uint internal constant _WEEK = 60 * 60 * 24 * 7;

Expand Down Expand Up @@ -104,6 +104,9 @@ contract Factory is Controllable, ReentrancyGuardUpgradeable, IFactory {
bytes32 typeHash = keccak256(abi.encodePacked(type_));
$.vaultConfig[typeHash] = vaultConfig_;
bool newVaultType = $.vaultTypeHashes.add(typeHash);
if (!newVaultType) {
_requireGovernanceOrMultisig();
}
emit VaultConfigChanged(
type_, vaultConfig_.implementation, vaultConfig_.deployAllowed, vaultConfig_.upgradeAllowed, newVaultType
);
Expand All @@ -126,6 +129,9 @@ contract Factory is Controllable, ReentrancyGuardUpgradeable, IFactory {
}
$.strategyLogicConfig[strategyIdHash] = config;
bool newStrategy = $.strategyLogicIdHashes.add(strategyIdHash);
if (!newStrategy) {
_requireGovernanceOrMultisig();
}
emit StrategyLogicConfigChanged(
config.id, config.implementation, config.deployAllowed, config.upgradeAllowed, newStrategy
);
Expand Down
34 changes: 18 additions & 16 deletions src/core/Zap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ contract Zap is Controllable, ReentrancyGuardUpgradeable, IZap {
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/// @inheritdoc IControllable
string public constant VERSION = "1.0.0";
string public constant VERSION = "1.0.1";

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INITIALIZATION */
Expand Down Expand Up @@ -74,11 +74,14 @@ contract Zap is Controllable, ReentrancyGuardUpgradeable, IZap {
uint[] memory depositAmounts = new uint[](len);
//nosemgrep
for (uint i; i < len; ++i) {
if (tokenIn != assets[i]) {
//slither-disable-next-line low-level-calls
(bool success, bytes memory result) = agg.call(swapData[i]);
//nosemgrep
require(success, string(result));
if (tokenIn == assets[i]) {
continue;
}

//slither-disable-next-line low-level-calls
(bool success, bytes memory result) = agg.call(swapData[i]);
if (!success) {
revert AggSwapFailed(string(result));
}
}
//nosemgrep
Expand Down Expand Up @@ -106,20 +109,24 @@ contract Zap is Controllable, ReentrancyGuardUpgradeable, IZap {
revert NotAllowedDexAggregator(agg);
}

IERC20(vault).safeTransferFrom(msg.sender, address(this), sharesToBurn);

address strategy = address(IVault(vault).strategy());
address[] memory assets = IStrategy(strategy).assets();
uint[] memory amountsOut = IVault(vault).withdrawAssets(assets, sharesToBurn, minAssetAmountsOut);
uint[] memory amountsOut =
IVault(vault).withdrawAssets(assets, sharesToBurn, minAssetAmountsOut, address(this), msg.sender);

uint len = swapData.length;
for (uint i; i < len; ++i) {
if (tokenOut == assets[i]) {
continue;
}

_approveIfNeeds(assets[i], amountsOut[i], agg);
// slither-disable-next-line calls-loop
// slither-disable-next-line low-level-calls
(bool success, bytes memory result) = agg.call(swapData[i]);
//nosemgrep
require(success, string(result));
if (!success) {
revert AggSwapFailed(string(result));
}
}

_sendAllRemaining(tokenOut, assets, IStrategy(strategy).underlying());
Expand All @@ -135,14 +142,10 @@ contract Zap is Controllable, ReentrancyGuardUpgradeable, IZap {
address tokenIn,
uint amountIn
) external view returns (address[] memory tokensOut, uint[] memory swapAmounts) {
// todo check vault

address strategy = address(IVault(vault).strategy());
tokensOut = IStrategy(strategy).assets();
uint len = tokensOut.length;

swapAmounts = new uint[](len);

uint[] memory proportions = IStrategy(strategy).getAssetsProportions();
uint amountInUsed = 0;
//nosemgrep
Expand All @@ -151,7 +154,6 @@ contract Zap is Controllable, ReentrancyGuardUpgradeable, IZap {
amountInUsed += amountIn * proportions[i] / 1e18;
continue;
}

if (i < len - 1) {
swapAmounts[i] = amountIn * proportions[i] / 1e18;
amountInUsed += swapAmounts[i];
Expand Down
148 changes: 87 additions & 61 deletions src/core/base/VaultBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ abstract contract VaultBase is Controllable, ERC20Upgradeable, ReentrancyGuardUp
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/// @dev Version of VaultBase implementation
string public constant VERSION_VAULT_BASE = "1.0.0";
string public constant VERSION_VAULT_BASE = "1.0.1";

/// @dev Delay between deposits/transfers and withdrawals
uint internal constant _WITHDRAW_REQUEST_BLOCKS = 5;
Expand Down Expand Up @@ -200,61 +200,18 @@ abstract contract VaultBase is Controllable, ERC20Upgradeable, ReentrancyGuardUp
uint amountShares,
uint[] memory minAssetAmountsOut
) external virtual nonReentrant returns (uint[] memory) {
if (amountShares == 0) {
revert IControllable.IncorrectZeroArgument();
}
if (amountShares > balanceOf(msg.sender)) {
revert NotEnoughBalanceToPay();
}
if (assets_.length != minAssetAmountsOut.length) {
revert IControllable.IncorrectArrayLength();
}

VaultBaseStorage storage $ = _getVaultBaseStorage();
_beforeWithdraw($);

IStrategy _strategy = $.strategy;
uint localTotalSupply = totalSupply();
uint totalValue = _strategy.total();

uint[] memory amountsOut;
address underlying = _strategy.underlying();
//nosemgrep
bool isUnderlyingWithdrawal = assets_.length == 1 && underlying != address(0) && underlying == assets_[0];

// fuse is not triggered
if (totalValue > 0) {
uint value = amountShares * totalValue / localTotalSupply;
if (isUnderlyingWithdrawal) {
amountsOut = new uint[](1);
amountsOut[0] = value;
$.strategy.withdrawUnderlying(amountsOut[0], msg.sender);
} else {
amountsOut = $.strategy.withdrawAssets(assets_, value, msg.sender);
}
} else {
if (isUnderlyingWithdrawal) {
amountsOut = new uint[](1);
amountsOut[0] = amountShares * IERC20(underlying).balanceOf(address(_strategy)) / localTotalSupply;
$.strategy.withdrawUnderlying(amountsOut[0], msg.sender);
} else {
amountsOut = $.strategy.transferAssets(amountShares, localTotalSupply, msg.sender);
}
}

uint len = amountsOut.length;
//nosemgrep
for (uint i; i < len; ++i) {
if (amountsOut[i] < minAssetAmountsOut[i]) {
revert ExceedSlippageExactAsset(assets_[i], amountsOut[i], minAssetAmountsOut[i]);
}
}

_burn(msg.sender, amountShares);

emit WithdrawAssets(msg.sender, assets_, amountShares, amountsOut);
return _withdrawAssets(assets_, amountShares, minAssetAmountsOut, msg.sender, msg.sender);
}

return amountsOut;
/// @inheritdoc IVault
function withdrawAssets(
address[] memory assets_,
uint amountShares,
uint[] memory minAssetAmountsOut,
address receiver,
address owner
) external virtual nonReentrant returns (uint[] memory) {
return _withdrawAssets(assets_, amountShares, minAssetAmountsOut, receiver, owner);
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
Expand Down Expand Up @@ -465,19 +422,88 @@ abstract contract VaultBase is Controllable, ERC20Upgradeable, ReentrancyGuardUp
}
}

function _beforeWithdraw(VaultBaseStorage storage $) internal {
if ($.withdrawRequests[msg.sender] + _WITHDRAW_REQUEST_BLOCKS >= block.number) {
function _withdrawAssets(
address[] memory assets_,
uint amountShares,
uint[] memory minAssetAmountsOut,
address receiver,
address owner
) internal virtual returns (uint[] memory) {
if (msg.sender != owner) {
_spendAllowance(owner, msg.sender, amountShares);
}

if (amountShares == 0) {
revert IControllable.IncorrectZeroArgument();
}
if (amountShares > balanceOf(owner)) {
revert NotEnoughBalanceToPay();
}
if (assets_.length != minAssetAmountsOut.length) {
revert IControllable.IncorrectArrayLength();
}

VaultBaseStorage storage $ = _getVaultBaseStorage();
_beforeWithdraw($, owner);

IStrategy _strategy = $.strategy;
uint localTotalSupply = totalSupply();
uint totalValue = _strategy.total();

uint[] memory amountsOut;

{
address underlying = _strategy.underlying();
//nosemgrep
bool isUnderlyingWithdrawal = assets_.length == 1 && underlying != address(0) && underlying == assets_[0];

// fuse is not triggered
if (totalValue > 0) {
uint value = amountShares * totalValue / localTotalSupply;
if (isUnderlyingWithdrawal) {
amountsOut = new uint[](1);
amountsOut[0] = value;
$.strategy.withdrawUnderlying(amountsOut[0], receiver);
} else {
amountsOut = $.strategy.withdrawAssets(assets_, value, receiver);
}
} else {
if (isUnderlyingWithdrawal) {
amountsOut = new uint[](1);
amountsOut[0] = amountShares * IERC20(underlying).balanceOf(address(_strategy)) / localTotalSupply;
$.strategy.withdrawUnderlying(amountsOut[0], receiver);
} else {
amountsOut = $.strategy.transferAssets(amountShares, localTotalSupply, receiver);
}
}

uint len = amountsOut.length;
//nosemgrep
for (uint i; i < len; ++i) {
if (amountsOut[i] < minAssetAmountsOut[i]) {
revert ExceedSlippageExactAsset(assets_[i], amountsOut[i], minAssetAmountsOut[i]);
}
}
}

_burn(owner, amountShares);

emit WithdrawAssets(msg.sender, owner, assets_, amountShares, amountsOut);

return amountsOut;
}

function _beforeWithdraw(VaultBaseStorage storage $, address owner) internal {
if ($.withdrawRequests[owner] + _WITHDRAW_REQUEST_BLOCKS >= block.number) {
revert WaitAFewBlocks();
}
$.withdrawRequests[msg.sender] = block.number;
$.withdrawRequests[owner] = block.number;
}

function _update(address from, address to, uint value) internal virtual override {
super._update(from, to, value);
VaultBaseStorage storage $ = _getVaultBaseStorage();
$.withdrawRequests[from] = block.number;
if (to != IPlatform(platform()).zap()) {
$.withdrawRequests[to] = block.number;
}
$.withdrawRequests[to] = block.number;
}
}
2 changes: 1 addition & 1 deletion src/core/vaults/CVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ contract CVault is VaultBase {
//region ----- Constants -----

/// @dev Version of CVault implementation
string public constant VERSION = "1.0.0";
string public constant VERSION = "1.0.1";

uint internal constant _UNIQUE_INIT_ADDRESSES = 1;

Expand Down
2 changes: 1 addition & 1 deletion src/core/vaults/RMVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ contract RMVault is RVaultBase, IManagedVault {
//region ----- Constants -----

/// @dev Version of RMVault implementation
string public constant VERSION = "1.0.0";
string public constant VERSION = "1.0.1";

uint internal constant _UNIQUE_INIT_ADDRESSES = 1;

Expand Down
2 changes: 1 addition & 1 deletion src/core/vaults/RVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ contract RVault is RVaultBase {
//region ----- Constants -----

/// @dev Version of RVault implementation
string public constant VERSION = "1.0.0";
string public constant VERSION = "1.0.1";

uint public constant BB_TOKEN_DURATION = 86400 * 7;

Expand Down
2 changes: 2 additions & 0 deletions src/interfaces/IFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,12 @@ interface IFactory {
function updateFarm(uint id, Farm memory farm_) external;

/// @notice Initial addition or change of vault type settings.
/// Operator can add new vault type. Governance or multisig can change existing vault type config.
/// @param vaultConfig_ Vault type settings
function setVaultConfig(VaultConfig memory vaultConfig_) external;

/// @notice Initial addition or change of strategy logic settings.
/// Operator can add new strategy logic. Governance or multisig can change existing logic config.
/// @param config Strategy logic settings
/// @param developer Strategy developer is receiver of minted StrategyLogic NFT on initial addition
function setStrategyLogicConfig(StrategyLogicConfig memory config, address developer) external;
Expand Down
19 changes: 18 additions & 1 deletion src/interfaces/IVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ interface IVault is IERC165 {
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

event DepositAssets(address indexed account, address[] assets, uint[] amounts, uint mintAmount);
event WithdrawAssets(address indexed account, address[] assets, uint sharesAmount, uint[] amountsOut);
event WithdrawAssets(
address indexed sender, address indexed owner, address[] assets, uint sharesAmount, uint[] amountsOut
);
event HardWorkGas(uint gasUsed, uint gasCost, bool compensated);
event DoHardWorkOnDepositChanged(bool oldValue, bool newValue);
event MaxSupply(uint maxShares);
Expand Down Expand Up @@ -181,6 +183,21 @@ interface IVault is IERC165 {
uint[] memory minAssetAmountsOut
) external returns (uint[] memory);

/// @dev Burning shares of vault and obtaining strategy assets.
/// @param assets_ Assets suitable for the strategy. Can be strategy assets, underlying asset or specific set of assets depending on strategy logic.
/// @param amountShares Shares amount for burning
/// @param minAssetAmountsOut Slippage tolerance. Minimal amounts of strategy assets that user must receive.
/// @param receiver Receiver of assets
/// @param owner Owner of vault shares
/// @return Amount of assets for withdraw. It's related to assets_ one-by-one.
function withdrawAssets(
address[] memory assets_,
uint amountShares,
uint[] memory minAssetAmountsOut,
address receiver,
address owner
) external returns (uint[] memory);

/// @dev Setting of vault capacity
/// @param maxShares If totalSupply() exceeds this value, deposits will not be possible
function setMaxSupply(uint maxShares) external;
Expand Down
Loading

0 comments on commit eee25ce

Please sign in to comment.