Skip to content

Commit

Permalink
added rate and oracle vault
Browse files Browse the repository at this point in the history
  • Loading branch information
RedVeil committed Oct 28, 2024
1 parent b1890a3 commit 743db52
Show file tree
Hide file tree
Showing 12 changed files with 167 additions and 95 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@
[submodule "lib/solidity-bytes-utils"]
path = lib/solidity-bytes-utils
url = https://github.com/GNSPS/solidity-bytes-utils
[submodule "lib/weiroll"]
path = lib/weiroll
url = https://github.com/weiroll/weiroll
3 changes: 2 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ remappings = [
'openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/',
'openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/',
'solmate/=lib/solmate/src/',
'safe-smart-account/=lib/safe-smart-account/',
'safe-smart-account/=lib/safe-smart-account/contracts/',
'weiroll/=lib/weiroll/src/',
'solady/=lib/solady/src/',
'bitlib/=lib/solidity-bytes-utils/contracts/',
'ERC-7540/=lib/ERC-7540-Reference/src/'
Expand Down
1 change: 0 additions & 1 deletion lib/v3-core
Submodule v3-core deleted from 2c51d1
1 change: 0 additions & 1 deletion lib/v3-periphery
Submodule v3-periphery deleted from 80f26c
48 changes: 26 additions & 22 deletions src/peripheral/gnosis/controllerModule/DrawdownModule.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {ControllerModule, ModuleCall} from "src/peripheral/gnosis/controllerModule/MainControllerModule.sol";
import {ControllerModule, ModuleCall, ISafe, Operation} from "src/peripheral/gnosis/controllerModule/MainControllerModule.sol";
import {MultisigVault} from "src/vaults/multisig/phase1/MultisigVault.sol";
import {ERC20} from "solmate/tokens/ERC20.sol";
import {Owned} from "src/utils/Owned.sol";
import {OwnerManager} from "safe-smart-account/base/OwnerManager.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";

contract DrawdownModule is Owned {
using FixedPointMathLib for uint256;

MultisigVault public vault;
ControllerModule public controller;
ModuleCall[] public tokenBalanceCalls;
Expand Down Expand Up @@ -39,7 +43,7 @@ contract DrawdownModule is Owned {
if (abi.decode(data, (uint256)) > 0) revert("Leftover token");
}

address asset = vault.asset();
address asset = address(vault.asset());
uint256 assetBalance = ERC20(asset).balanceOf(controller.gnosisSafe());
uint256 totalAssets = vault.totalAssets();
// TODO add a drawdown parameter
Expand All @@ -66,25 +70,25 @@ contract DrawdownModule is Owned {
ERC20(asset).transfer(address(vault), assetBalance - bounty);

// Put DAO in control of the safe
_takeoverSafe();
_takeoverSafe(newOwners, newThreshold);
}
}

function _takeoverSafe(
address[] memory newOwners,
uint256 newThreshold
address[] memory newOwners_,
uint256 newThreshold_
) internal {
address _gnosisSafe = gnosisSafe;
ISafe safe = ISafe(_gnosisSafe);
address gnosisSafe = controller.gnosisSafe();
ISafe safe = ISafe(gnosisSafe);
address[] memory owners = safe.getOwners();

// remove owners
for (uint256 i = (owners.length - 1); i > 0; --i) {
bool success = safe.execTransactionFromModule({
to: _gnosisSafe,
to: gnosisSafe,
value: 0,
data: abi.encodeCall(
IOwnerManager.removeOwner,
OwnerManager.removeOwner,
(owners[i - 1], owners[i], 1)
),
operation: Operation.Call
Expand All @@ -94,16 +98,16 @@ contract DrawdownModule is Owned {
}
}

for (uint256 i = 0; i < newOwners.length; i++) {
for (uint256 i = 0; i < newOwners_.length; i++) {
bool success;
if (i == 0) {
if (newOwners[i] == owners[i]) continue;
if (newOwners_[i] == owners[i]) continue;
success = safe.execTransactionFromModule({
to: _gnosisSafe,
to: gnosisSafe,
value: 0,
data: abi.encodeCall(
IOwnerManager.swapOwner,
(SENTINEL_OWNERS, owners[i], newOwners[i])
OwnerManager.swapOwner,
(address(0x1), owners[i], newOwners_[i])
),
operation: Operation.Call
});
Expand All @@ -113,11 +117,11 @@ contract DrawdownModule is Owned {
continue;
}
success = safe.execTransactionFromModule({
to: _gnosisSafe,
to: gnosisSafe,
value: 0,
data: abi.encodeCall(
IOwnerManager.addOwnerWithThreshold,
(newOwners[i], 1)
OwnerManager.addOwnerWithThreshold,
(newOwners_[i], 1)
),
operation: Operation.Call
});
Expand All @@ -126,13 +130,13 @@ contract DrawdownModule is Owned {
}
}

if (newThreshold > 1) {
if (newThreshold_ > 1) {
bool success = safe.execTransactionFromModule({
to: _gnosisSafe,
to: gnosisSafe,
value: 0,
data: abi.encodeCall(
IOwnerManager.changeThreshold,
(newThreshold)
OwnerManager.changeThreshold,
(newThreshold_)
),
operation: Operation.Call
});
Expand All @@ -153,7 +157,7 @@ contract DrawdownModule is Owned {
revert("Invalid call operation");

// We want to get the balance of all tokens in the safe that are not the vault asset
if (calls[i].to == vault.asset()) revert("Invalid call");
if (calls[i].to == address(vault.asset())) revert("Invalid call");

delete tokenBalanceCalls;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface IAsyncVault {
function redeemRequests(
address recipient,
address multisig
) external view returns (RedeemRequest);
) external view returns (RedeemRequest memory);
}

contract WithdrawalModule {
Expand Down
2 changes: 1 addition & 1 deletion src/peripheral/gnosis/transactionGuard/LoggerGuard.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {DebugTransactionGuard, Enum} from "safe-smart-account/contracts/examples/guards/DebugTransactionGuard.sol";
import {DebugTransactionGuard, Enum} from "safe-smart-account/examples/guards/DebugTransactionGuard.sol";

contract LoggerGuard is DebugTransactionGuard {
event ModuleTransactionDetails(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.12 <0.9.0;

import {BaseGuard, Guard, Enum} from "safe-smart-account/contracts/base/GuardManager.sol";
import {BaseGuard, Guard, Enum} from "safe-smart-account/base/GuardManager.sol";
import {IModuleGuard} from "safe-smart-account/base/ModuleManager.sol";
import {Owned} from "src/utils/Owned.sol";

contract MainTransactionGuard is BaseGuard, Owned {
Expand Down
6 changes: 3 additions & 3 deletions src/peripheral/gnosis/transactionGuard/ScopeGuard.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.12 <0.9.0;

import {BaseGuard, Guard, Enum} from "safe-smart-account/contracts/base/GuardManager.sol";
import {BaseGuard, Guard, Enum} from "safe-smart-account/base/GuardManager.sol";
import {Owned} from "src/utils/Owned.sol";

contract ScopeGuard is BaseGuard, Owned {
Expand Down Expand Up @@ -181,7 +181,7 @@ contract ScopeGuard is BaseGuard, Owned {
bytes memory data,
Enum.Operation operation,
address
) external view override {
) external view {
_checkTransaction(to, value, data, operation);
}

Expand Down Expand Up @@ -221,5 +221,5 @@ contract ScopeGuard is BaseGuard, Owned {

function checkAfterExecution(bytes32, bool) external view override {}

function checkAfterModuleExecution(bytes32, bool) external view override {}
function checkAfterModuleExecution(bytes32, bool) external view {}
}
95 changes: 31 additions & 64 deletions src/vaults/multisig/phase1/MultisigVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,37 @@ import {BaseControlledAsyncRedeem} from "./BaseControlledAsyncRedeem.sol";
import {BaseERC7540} from "./BaseERC7540.sol";
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {IPriceOracle} from "src/interfaces/IPriceOracle.sol";

contract MultisigVault is BaseControlledAsyncRedeem {
struct InitializeParams {
address asset;
address multisig;
address owner;
Limits limits;
Fees fees;
}

struct Limits {
uint256 depositLimit;
uint256 minAmount;
}

struct Fees {
uint64 performanceFee;
uint64 managementFee;
uint64 withdrawalIncentive;
uint64 feesUpdatedAt;
uint256 highWaterMark;
address feeRecipient;
}

abstract contract MultisigVault is BaseControlledAsyncRedeem {
using FixedPointMathLib for uint256;

address public multisig;

error ZeroAmount();
error Misconfigured();

struct InitializeParams {
address asset;
address multisig;
address owner;
Limits limits;
Fees fees;
}

constructor(
InitializeParams memory params
) BaseERC7540(params.owner, params.asset, "Multisig Vault", "mVault") {
Expand All @@ -39,21 +52,6 @@ contract MultisigVault is BaseControlledAsyncRedeem {
ACCOUNTING LOGIC
//////////////////////////////////////////////////////////////*/

uint256 internal totalAssets_;
uint256 public lastUpdateTime;

/// @return Total amount of underlying `asset` token managed by vault. Delegates to adapter.
function totalAssets() public view override returns (uint256) {
return totalAssets_ + accruedYield();
}

function accruedYield() public view returns (uint256) {
return
(rate * (block.timestamp - lastUpdateTime) * totalAssets_) /
365.25 days /
1e18;
}

// Override to add minAmount check (Which is used in mint and will revert the function)
function previewDeposit(
uint256 assets
Expand All @@ -73,12 +71,14 @@ contract MultisigVault is BaseControlledAsyncRedeem {
return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply);
}

function convertToLowBoundAssets(uint256 shares) public view returns (uint256) {
function convertToLowBoundAssets(
uint256 shares
) public view returns (uint256) {
uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.
uint256 assets = totalAssets().mulDivDown(bounds.lower, 1e18);

return supply == 0 ? shares : shares.mulDivDown(assets, supply);
}
}

/*//////////////////////////////////////////////////////////////
DEPOSIT/WITHDRAWAL LIMIT LOGIC
Expand Down Expand Up @@ -155,7 +155,7 @@ contract MultisigVault is BaseControlledAsyncRedeem {
function fulfillMultipleRedeems(
uint256[] memory shares,
address[] memory controllers
) external override returns (uint256) {
) external returns (uint256) {
if (shares.length != controllers.length) revert Misconfigured();
uint256 withdrawalIncentive = uint256(fees.withdrawalIncentive);

Expand All @@ -177,17 +177,13 @@ contract MultisigVault is BaseControlledAsyncRedeem {
ERC-4626 OVERRIDES
//////////////////////////////////////////////////////////////*/

function beforeWithdraw(uint256 assets, uint256) internal override {
function beforeWithdraw(uint256 assets, uint256) internal virtual override {
_takeFees();

totalAssets_ -= assets;
}

function afterDeposit(uint256 assets, uint256) internal override {
function afterDeposit(uint256 assets, uint256) internal virtual override {
_takeFees();

totalAssets_ += assets;

SafeTransferLib.safeTransfer(asset, multisig, assets);
}

Expand All @@ -201,39 +197,15 @@ contract MultisigVault is BaseControlledAsyncRedeem {
}

Bounds public bounds;
uint256 public rate;

function setRate(uint256 rate_) external onlyOwner {
rate = rate_;
}

function setBounds(Bounds memory bounds_) external onlyOwner {
bounds = bounds_;
}

modifier updateTotalAssets() {
uint256 yieldEarned = accruedYield();

if (yieldEarned > 0) {
totalAssets_ = _totalAssets + yieldEarned;
lastUpdateTime = block.timestamp;
}
_;
}

/*//////////////////////////////////////////////////////////////
FEE LOGIC
//////////////////////////////////////////////////////////////*/

struct Fees {
uint64 performanceFee;
uint64 managementFee;
uint64 withdrawalIncentive;
uint64 feesUpdatedAt;
uint256 highWaterMark;
address feeRecipient;
}

Fees public fees;

event FeesUpdated(Fees prev, Fees next);
Expand Down Expand Up @@ -309,7 +281,7 @@ contract MultisigVault is BaseControlledAsyncRedeem {
if (fees_.feeRecipient == address(0)) revert Misconfigured();

// Dont rely on user input here
fees_.feesUpdatedAt = block.timestamp;
fees_.feesUpdatedAt = uint64(block.timestamp);
fees_.highWaterMark = convertToAssets(1e18);

emit FeesUpdated(fees, fees_);
Expand Down Expand Up @@ -337,11 +309,6 @@ contract MultisigVault is BaseControlledAsyncRedeem {
LIMIT LOGIC
//////////////////////////////////////////////////////////////*/

struct Limits {
uint256 depositLimit;
uint256 minAmount;
}

Limits public limits;

event LimitsUpdated(Limits prev, Limits next);
Expand Down
Loading

0 comments on commit 743db52

Please sign in to comment.