Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip: PCV v3 #855

Closed
wants to merge 3 commits into from
Closed
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
3 changes: 3 additions & 0 deletions contracts/core/TribeRoles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ library TribeRoles {
/// @notice capable of setting properties on Balancer BasePool utility wrapper
bytes32 internal constant BALANCER_MANAGER_ADMIN_ROLE = keccak256("BALANCER_MANAGER_ADMIN_ROLE");

/// @notice capable of managing ENS domains and related metadata
bytes32 internal constant ENS_MANAGER_ROLE = keccak256("ENS_MANAGER_ROLE");

/*///////////////////////////////////////////////////////////////
Minor Roles
//////////////////////////////////////////////////////////////*/
Expand Down
121 changes: 121 additions & 0 deletions contracts/external/ERC4626.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.10;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/// @title ERC4626 interface
/// See: https://eips.ethereum.org/EIPS/eip-4626
abstract contract ERC4626 is ERC20 {
/*////////////////////////////////////////////////////////
Events
////////////////////////////////////////////////////////*/

/// @notice `caller` has exchanged `assets` for `shares`,
/// and transferred those `shares` to `owner`.
event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);

/// @notice `caller` has exchanged `shares`, owned by `owner`, for `assets`,
/// and transferred those `assets` to `owner`.
event Withdraw(
address indexed caller,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);

/*////////////////////////////////////////////////////////
Vault properties
////////////////////////////////////////////////////////*/

/// @notice The address of the underlying ERC20 token used for
/// the Vault for accounting, depositing, and withdrawing.
function asset() public view virtual returns (address asset);

/// @notice Total amount of the underlying asset that
/// is "managed" by Vault.
function totalAssets() public view virtual returns (uint256 totalAssets);

/*////////////////////////////////////////////////////////
Deposit/Withdrawal Logic
////////////////////////////////////////////////////////*/

/// @notice Mints `shares` Vault shares to `receiver` by
/// depositing exactly `assets` of underlying tokens.
function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares);

/// @notice Mints exactly `shares` Vault shares to `receiver`
/// by depositing `assets` of underlying tokens.
function mint(uint256 shares, address receiver) public virtual returns (uint256 assets);

/// @notice Redeems `shares` from `owner` and sends `assets`
/// of underlying tokens to `receiver`.
function withdraw(
uint256 assets,
address receiver,
address owner
) public virtual returns (uint256 shares);

/// @notice Redeems `shares` from `owner` and sends `assets`
/// of underlying tokens to `receiver`.
function redeem(
uint256 shares,
address receiver,
address owner
) public virtual returns (uint256 assets);

/*////////////////////////////////////////////////////////
Vault Accounting Logic
////////////////////////////////////////////////////////*/

/// @notice The amount of shares that the vault would
/// exchange for the amount of assets provided, in an
/// ideal scenario where all the conditions are met.
function convertToShares(uint256 assets) public view virtual returns (uint256 shares);

/// @notice The amount of assets that the vault would
/// exchange for the amount of shares provided, in an
/// ideal scenario where all the conditions are met.
function convertToAssets(uint256 shares) public view virtual returns (uint256 assets);

/// @notice Total number of underlying assets that can
/// be deposited by `owner` into the Vault, where `owner`
/// corresponds to the input parameter `receiver` of a
/// `deposit` call.
function maxDeposit(address owner) public view virtual returns (uint256 maxAssets);

/// @notice Allows an on-chain or off-chain user to simulate
/// the effects of their deposit at the current block, given
/// current on-chain conditions.
function previewDeposit(uint256 assets) public view virtual returns (uint256 shares);

/// @notice Total number of underlying shares that can be minted
/// for `owner`, where `owner` corresponds to the input
/// parameter `receiver` of a `mint` call.
function maxMint(address owner) public view virtual returns (uint256 maxShares);

/// @notice Allows an on-chain or off-chain user to simulate
/// the effects of their mint at the current block, given
/// current on-chain conditions.
function previewMint(uint256 shares) public view virtual returns (uint256 assets);

/// @notice Total number of underlying assets that can be
/// withdrawn from the Vault by `owner`, where `owner`
/// corresponds to the input parameter of a `withdraw` call.
function maxWithdraw(address owner) public view virtual returns (uint256 maxAssets);

/// @notice Allows an on-chain or off-chain user to simulate
/// the effects of their withdrawal at the current block,
/// given current on-chain conditions.
function previewWithdraw(uint256 assets) public view virtual returns (uint256 shares);

/// @notice Total number of underlying shares that can be
/// redeemed from the Vault by `owner`, where `owner` corresponds
/// to the input parameter of a `redeem` call.
function maxRedeem(address owner) public view virtual returns (uint256 maxShares);

/// @notice Allows an on-chain or off-chain user to simulate
/// the effects of their redeemption at the current block,
/// given current on-chain conditions.
function previewRedeem(uint256 shares) public view virtual returns (uint256 assets);
}
64 changes: 64 additions & 0 deletions contracts/external/solmate/Auth.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
abstract contract Auth {
event OwnerUpdated(address indexed user, address indexed newOwner);

event AuthorityUpdated(address indexed user, Authority indexed newAuthority);

address public owner;

Authority public authority;

constructor(address _owner, Authority _authority) {
owner = _owner;
authority = _authority;

emit OwnerUpdated(msg.sender, _owner);
emit AuthorityUpdated(msg.sender, _authority);
}

modifier requiresAuth() virtual {
require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED");

_;
}

function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas.

// Checking if the caller is the owner only after calling the authority saves gas in most cases, but be
// aware that this makes protected functions uncallable even to the owner if the authority is out of order.
return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner;
}

function setAuthority(Authority newAuthority) public virtual {
// We check if the caller is the owner first because we want to ensure they can
// always swap out the authority even if it's reverting or using up a lot of gas.
require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig));

authority = newAuthority;

emit AuthorityUpdated(msg.sender, newAuthority);
}

function setOwner(address newOwner) public virtual requiresAuth {
owner = newOwner;

emit OwnerUpdated(msg.sender, newOwner);
}
}

/// @notice A generic interface for a contract which provides authorization data to an Auth instance.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
interface Authority {
function canCall(
address user,
address target,
bytes4 functionSig
) external view returns (bool);
}
53 changes: 53 additions & 0 deletions contracts/pcv/v3/PCVStrategy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.10;

import "../../external/ERC4626.sol";
import "../../utils/ENSNamed.sol";
import "../../core/TribeRoles.sol";

/// @title Interface representing a PCV strategy
/// @author eswak
abstract contract PCVStrategy is ERC4626, ENSNamed {
ICore private constant CORE = ICore(0x8d5ED43dCa8C2F7dFB20CF7b53CC7E593635d7b9);

function setName(string calldata newName) public override {
require(CORE.hasRole(TribeRoles.ENS_MANAGER_ROLE, msg.sender), "UNAUTHORIZED");
_setName(newName);
}

// ---------- Read Methods ---------------

/// @notice list of assets handled by this strategy
/// asset() must be a assets()[0]
function assets() public view virtual returns (address[] memory tokens) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

separate 4626 strategies & multi assets strategies

tokens = new address[](1);
tokens[0] = asset();
}

function balances(address owner) external view virtual returns (int256[] memory amounts) {
amounts = new int256[](1);
amounts[0] = int256(previewRedeem(balanceOf(owner)));
}

// ------ State-changing Methods ---------

function claimRewards() external virtual {}

/// @notice convert an amount of assets
/// All numbers must be in the order returned by assets().
function convertAssets(int256[] memory amountsIn, int256[] memory minAmountsOut)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spin out converters

external
virtual
returns (int256[] memory amountsOut)
{
require(false, "NOT_IMPLEMENTED");
}

function withdrawERC20(address token) external virtual {
// everyone can transfer random airdropped tokens to the tribe dao
IERC20(token).safeTransfer(
address(0xd51dbA7a94e1adEa403553A8235C302cEbF41a3c),
IERC20(token).balanceOf(address(this))
);
}
}
Loading