Address Contract Verified
Address
0x2d8BcE1FaE00a959354aCD9eBf9174337A64d4fb
Balance
0 ETH
Nonce
1
Code Size
5914 bytes
Creator
0xeB13955d...A064 at tx 0x7d862211...9f84ab
Indexed Transactions
0 (1 on-chain, 0.9% indexed)
Contract Bytecode
5914 bytes
0x608060405234801561000f575f5ffd5b506004361061023f575f3560e01c80638604dee611610135578063d5db72eb116100b4578063ef64d76311610079578063ef64d76314610706578063f1710d081461073b578063f2fde38b1461074e578063f46c6c6714610761578063f815c03d14610774575f5ffd5b8063d5db72eb14610682578063d5fe1d13146106ad578063e30c3978146106c0578063e397cb9e146106d1578063e64624fa146106f3575f5ffd5b8063b3890209116100fa578063b3890209146105df578063bac1e94b14610614578063c1bf1dcf14610627578063cce2f3fb1461063a578063cd3985921461064d575f5ffd5b80638604dee6146105685780638da5cb5b1461057b5780639c4667a21461058b578063a1292903146105b9578063b23a56f0146105cc575f5ffd5b80634cf64f33116101c15780637664a7e8116101865780637664a7e81461048f578063791d5d311461052757806379ba50971461053a5780637b730d16146105425780637c663ae214610555575f5ffd5b80634cf64f33146103e8578063622e152d146104235780636720a12014610436578063715018a614610465578063760ad7bb1461046d575f5ffd5b80630c642df1116102075780630c642df11461034557806322f1cf691461035a57806323404e6c1461038c5780633aa83ec71461039f5780634bc5d735146103b2575f5ffd5b80630595a6541461024357806305de62c01461029557806305f533cf146102b857806309b65e66146102ed57806309f142721461030f575b5f5ffd5b610278610251366004611521565b6001600160e01b0319165f908152600560205260409020600201546001600160a01b031690565b6040516001600160a01b0390911681526020015b60405180910390f35b6102a86102a3366004611557565b61079f565b604051901515815260200161028c565b6102786102c6366004611521565b6001600160e01b0319165f908152600560205260409020600101546001600160a01b031690565b6102a86102fb366004611521565b60086020525f908152604090205460ff1681565b61027861031d366004611521565b6001600160e01b0319165f90815260056020819052604090912001546001600160a01b031690565b610358610353366004611597565b6107fa565b005b610278610368366004611521565b6001600160e01b0319165f908152600560205260409020546001600160a01b031690565b61035861039a3660046115c8565b6108b4565b6103586103ad366004611521565b61096c565b6102a86103c03660046115e2565b6001600160a01b03165f9081526002602081905260409091200154600160c01b900460ff1690565b6102a86103f63660046115c8565b6001600160a01b039182165f90815260066020908152604080832093909416825291909152205460ff1690565b6103586104313660046115e2565b6109c0565b6102786104443660046115e2565b6001600160a01b039081165f90815260026020819052604090912001541690565b610358610ab6565b6102a861047b3660046115e2565b60046020525f908152604090205460ff1681565b6104e461049d3660046115e2565b600260208190525f91825260409091208054600182015491909201546001600160a01b039283169291821691811690600160a01b810460e01b90600160c01b900460ff1685565b604080516001600160a01b039687168152948616602086015292909416918301919091526001600160e01b0319166060820152901515608082015260a00161028c565b610358610535366004611597565b610ac9565b610358610b44565b610358610550366004611597565b610b8d565b6103586105633660046115fb565b610c0c565b610358610576366004611597565b610d70565b5f546001600160a01b0316610278565b6102786105993660046115e2565b6001600160a01b039081165f908152600260205260409020600101541690565b6103586105c73660046115c8565b610df0565b6103586105da366004611597565b610eac565b6102786105ed366004611521565b6001600160e01b0319165f908152600560205260409020600601546001600160a01b031690565b610358610622366004611521565b610f2f565b61035861063536600461166b565b610f80565b6103586106483660046115e2565b61100e565b61027861065b366004611521565b6001600160e01b0319165f908152600560205260409020600401546001600160a01b031690565b6102a86106903660046115e2565b6001600160a01b03165f9081526003602052604090205460ff1690565b6103586106bb366004611597565b611135565b6001546001600160a01b0316610278565b6102a86106df3660046115e2565b60036020525f908152604090205460ff1681565b610358610701366004611693565b6111fa565b610278610714366004611521565b6001600160e01b0319165f908152600560205260409020600301546001600160a01b031690565b61035861074936600461166b565b6112ff565b61035861075c3660046115e2565b611385565b61035861076f366004611597565b6113f5565b6102786107823660046115e2565b6001600160a01b039081165f908152600260205260409020541690565b6001600160a01b038084165f90815260076020908152604080832093861683529281528282206001600160e01b03198516835290529081205460ff16806107f257505f546001600160a01b038481169116145b949350505050565b610802611476565b6001600160a01b0381166108295760405163d92e233d60e01b815260040160405180910390fd5b6001600160e01b031982165f908152600560205260409081902060060180546001600160a01b0319166001600160a01b038416908117909155905166466163746f727960c81b81526007015b604051908190038120906001600160e01b03198516907f23a80e454b9e756d9b2ebb718293c09fe024b7adf6ea29070e27dd44dded2464905f90a45050565b335f9081526003602052604090205460ff16806108da57505f546001600160a01b031633145b6108f757604051632fed761f60e01b815260040160405180910390fd5b6001600160a01b038083165f9081526006602090815260408083209385168352929052205460ff1661093c57604051635b7d61af60e01b815260040160405180910390fd5b6001600160a01b039182165f9081526006602090815260408083209390941682529190915220805460ff19169055565b610974611476565b6001600160e01b031981165f81815260086020526040808220805460ff19166001179055517fa5ced19b26a7fec9bfb9e35d68605a1241d62b1ab9a3b862f36a219891fdf5159190a250565b6109c8611476565b6001600160a01b0381165f9081526002602081905260409091200154600160c01b900460ff16610a0b57604051633728287760e11b815260040160405180910390fd5b6001600160a01b038082165f908152600260208190526040808320918201805460ff60c01b19169055905481516395a4cdcb60e01b815291519316926395a4cdcb9260048084019391929182900301818387803b158015610a6a575f5ffd5b505af1158015610a7c573d5f5f3e3d5ffd5b50506040516001600160a01b03841692507fc8e74fb3d97c0a82e22800e7bf8248c005c7aed9376e0893f8a2506ce1992c8991505f90a250565b610abe611476565b610ac75f6114a2565b565b610ad1611476565b6001600160a01b038116610af85760405163d92e233d60e01b815260040160405180910390fd5b6001600160e01b031982165f908152600560205260409081902080546001600160a01b0319166001600160a01b0384169081179091559051652637b1b5b2b960d11b8152600601610875565b60015433906001600160a01b03168114610b815760405163118cdaa760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b610b8a816114a2565b50565b610b95611476565b6001600160a01b038116610bbc5760405163d92e233d60e01b815260040160405180910390fd5b6001600160e01b031982165f908152600560205260409081902060010180546001600160a01b0319166001600160a01b0384169081179091559051664761746577617960c81b8152600701610875565b335f9081526003602052604090205460ff1680610c3257505f546001600160a01b031633145b610c4f57604051632fed761f60e01b815260040160405180910390fd5b6001600160a01b03851615801590610c6f57506001600160a01b03841615155b8015610c8357506001600160a01b03831615155b8015610c9757506001600160a01b03821615155b610cb45760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038581165f8181526002602081815260409283902080548a87166001600160a01b0319918216811783556001830180548c8a1690841681179091559483018054988b1660e08b901c600160a01b029093166001600160c01b031990991698909817821790975584519081526001600160e01b031988169281019290925294919391927f01faf72cecd22e6d7b9a5d03dfdd583ecc5fd698872639d99a9731c240dbbcdd910160405180910390a4505050505050565b610d78611476565b6001600160a01b038116610d9f5760405163d92e233d60e01b815260040160405180910390fd5b6001600160e01b031982165f908152600560205260409081902060020180546001600160a01b0319166001600160a01b038416908117909155905167537472617465677960c01b8152600801610875565b335f9081526003602052604090205460ff1680610e1657505f546001600160a01b031633145b610e3357604051632fed761f60e01b815260040160405180910390fd5b6001600160a01b038083165f9081526006602090815260408083209385168352929052205460ff1615610e7957604051635b7d61af60e01b815260040160405180910390fd5b6001600160a01b039182165f9081526006602090815260408083209390941682529190915220805460ff19166001179055565b610eb4611476565b6001600160a01b038116610edb5760405163d92e233d60e01b815260040160405180910390fd5b6001600160e01b031982165f908152600560208190526040918290200180546001600160a01b0319166001600160a01b03841690811790915590516a2332b2a932b1b2b4bb32b960a91b8152600b01610875565b610f37611476565b6001600160e01b031981165f81815260086020526040808220805460ff19169055517fb95723779c5dae72a25db18011ec3a516b76f381329525a24e1b97605fb5fe989190a250565b610f88611476565b6001600160a01b038216610faf5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0382165f81815260036020908152604091829020805460ff191685151590811790915591519182527fd6a2ab6b0dbd98e539210db72e366dd068032c1abcfce8b8588bcee82052ded591015b60405180910390a25050565b611016611476565b6001600160a01b0381165f90815260026020819052604090912090810154600160c01b900460ff161561105c57604051631950f80960e21b815260040160405180910390fd5b6001600160a01b038281165f8181526002602081815260408084208301805460ff60c01b1916600160c01b179055868301546001600160e01b0319600160a01b90910460e01b1684526005909152918290200154905163cce2f3fb60e01b815260048101929092529091169063cce2f3fb906024015f604051808303815f87803b1580156110e8575f5ffd5b505af11580156110fa573d5f5f3e3d5ffd5b50506040516001600160a01b03851692507f5303f5e3277cb33a424732af8355550ed3446778c3b06e5cb9b79474773c95f091505f90a25050565b61113d611476565b6001600160a01b0381166111645760405163d92e233d60e01b815260040160405180910390fd5b6001600160e01b031982165f908152600560205260409020600401546001600160a01b0316156111a7576040516314a2174b60e11b815260040160405180910390fd5b6001600160e01b031982165f908152600560205260409081902060040180546001600160a01b0319166001600160a01b0384169081179091559051691058d8dbdd5b9d185b9d60b21b8152600a01610875565b335f9081526004602052604090205460ff168061122057505f546001600160a01b031633145b61123d576040516376df46cd60e11b815260040160405180910390fd5b6001600160a01b0384161580159061125d57506001600160a01b03831615155b61127a5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038481165f8181526007602090815260408083209488168084529482528083206001600160e01b0319881680855290835292819020805460ff19168715159081179091559051908152919392917f9d950e4919d7c91068179be3cd6a99029ee6fdfcf4fb488053aa79841b517e03910160405180910390a450505050565b611307611476565b6001600160a01b03821661132e5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0382165f81815260046020908152604091829020805460ff191685151590811790915591519182527f023ef6e50bf1aa5e0ac13acee4206b46ded01551f0247af798912f40d14baa799101611002565b61138d611476565b600180546001600160a01b0383166001600160a01b031990911681179091556113bd5f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6113fd611476565b6001600160a01b0381166114245760405163d92e233d60e01b815260040160405180910390fd5b6001600160e01b031982165f908152600560205260409081902060030180546001600160a01b0319166001600160a01b03841690811790915590516820b63637b1b0ba37b960b91b8152600901610875565b5f546001600160a01b03163314610ac75760405163118cdaa760e01b8152336004820152602401610b78565b600180546001600160a01b0319169055610b8a815f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80356001600160e01b03198116811461151c575f5ffd5b919050565b5f60208284031215611531575f5ffd5b61153a82611505565b9392505050565b80356001600160a01b038116811461151c575f5ffd5b5f5f5f60608486031215611569575f5ffd5b61157284611541565b925061158060208501611541565b915061158e60408501611505565b90509250925092565b5f5f604083850312156115a8575f5ffd5b6115b183611505565b91506115bf60208401611541565b90509250929050565b5f5f604083850312156115d9575f5ffd5b6115b183611541565b5f602082840312156115f2575f5ffd5b61153a82611541565b5f5f5f5f5f60a0868803121561160f575f5ffd5b61161886611541565b945061162660208701611541565b935061163460408701611541565b925061164260608701611541565b915061165060808701611505565b90509295509295909350565b8035801515811461151c575f5ffd5b5f5f6040838503121561167c575f5ffd5b61168583611541565b91506115bf6020840161165c565b5f5f5f5f608085870312156116a6575f5ffd5b6116af85611541565b93506116bd60208601611541565b92506116cb60408601611505565b91506116d96060860161165c565b90509295919450925056fea2646970667358221220043b1ee79e8f9be505cbab8a7b3dbcae4b92e202018e59b4a94efd18f5d43ac564736f6c634300081c0033
Verified Source Code Full Match
Compiler: v0.8.28+commit.7893614a
EVM: cancun
Optimization: Yes (200 runs)
ProtocolController.sol 491 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {IStrategy} from "src/interfaces/IStrategy.sol";
import {IRewardVault} from "src/interfaces/IRewardVault.sol";
import {IProtocolController} from "src/interfaces/IProtocolController.sol";
/// @title ProtocolController.
/// @author Stake DAO
/// @custom:github @stake-dao
/// @custom:contact [email protected]
/// @notice ProtocolController is the central registry that facilitate the management of protocols integrations.
/// It allows the registration of vaults, management of protocol components (strategy, allocator, accountant, etc.),
/// and provides a permission system for granular access control.
/// It also supports pausing deposits for specific protocols while allowing withdrawals, and shutdown mechanisms per vault or at the protocol level.
contract ProtocolController is IProtocolController, Ownable2Step {
/// @notice Stores the core components for each protocol integration.
/// @dev Each protocol (Curve, Balancer, etc.) has its own set of components.
struct ProtocolComponents {
address locker;
address gateway;
address strategy;
address allocator;
address accountant;
address feeReceiver;
address factory;
}
/// @notice Links a gauge to its associated vault and protocol.
/// @dev A gauge is the external yield source (e.g., Curve gauge) that the vault interacts with.
struct Gauge {
address vault;
address asset;
address rewardReceiver;
bytes4 protocolId;
bool isShutdown;
}
//////////////////////////////////////////////////////
// --- STATE VARIABLES
//////////////////////////////////////////////////////
/// @notice Maps each gauge address to its configuration.
mapping(address => Gauge) public gauge;
/// @notice Authorized addresses that can register new vaults, such as factory contracts.
mapping(address => bool) public registrar;
/// @notice Addresses authorized to manage granular function-level permissions.
mapping(address => bool) public permissionSetters;
/// @notice Core components for each protocol, indexed by protocol ID.
/// @dev Protocol ID is typically keccak256("PROTOCOL_NAME") truncated to bytes4.
mapping(bytes4 => ProtocolComponents) internal _protocolComponents;
/// @notice Whitelisted allocation targets for each gauge.
/// @dev Strategies can only allocate funds to these pre-approved destinations (e.g., locker, sidecars).
mapping(address => mapping(address => bool)) internal _isValidAllocationTargets;
/// @notice Granular permission system: contract -> caller -> function -> allowed.
/// @dev Enables fine-grained access control for specific function calls. Main usecase is to allow router contracts
/// to deposit on behalf or claim on behalf of accounts.
mapping(address => mapping(address => mapping(bytes4 => bool))) internal _permissions;
/// @notice Per-protocol deposit pause state.
/// @dev When true for a protocol, deposits are paused but withdrawals remain functional.
mapping(bytes4 => bool) public isPaused;
//////////////////////////////////////////////////////
// --- ERRORS & EVENTS
//////////////////////////////////////////////////////
/// @notice Event emitted when a protocol component is set.
/// @param protocolId The protocol identifier.
/// @param componentId The component identifier ("Strategy", "Allocator", "Accountant", "FeeReceiver", "Locker", "Gateway", "Factory").
/// @param component The component address.
event ProtocolComponentSet(bytes4 indexed protocolId, string indexed componentId, address indexed component);
/// @notice Event emitted when a vault is registered.
/// @param gauge The gauge address.
/// @param vault The vault address.
/// @param asset The asset address.
/// @param rewardReceiver The reward receiver address.
/// @param protocolId The protocol identifier.
event VaultRegistered(
address indexed gauge, address indexed vault, address indexed asset, address rewardReceiver, bytes4 protocolId
);
/// @notice Event emitted when a gauge is shutdown.
/// @param gauge The gauge address that is being shutdown.
event GaugeShutdown(address indexed gauge);
/// @notice Event emitted when a gauge is unshut down.
/// @param gauge The gauge address that is being unshut down.
event GaugeUnshutdown(address indexed gauge);
/// @notice Event emitted when a protocol is shutdown.
/// @param protocolId The protocol identifier of the protocol integration that is being shutdown.
event ProtocolShutdown(bytes4 indexed protocolId);
/// @notice Event emitted when a permission is set.
/// @param target The contract address where the permission is valid.
/// @param caller The caller address that is allowed to call the function.
/// @param selector The function selector that is being allowed or disallowed.
/// @param allowed Whether the caller is allowed to call the function on the contract.
event PermissionSet(address indexed target, address indexed caller, bytes4 indexed selector, bool allowed);
/// @notice Event emitted when a registrar is added or removed to the list of authorized registrars.
/// @param registrar The registrar address that is being set or unset.
/// @param allowed Whether the registrar is allowed to manage vault registrations and rewards tokens.
event RegistrarPermissionSet(address indexed registrar, bool allowed);
/// @notice Event emitted when a permission setter is set.
/// @param setter The permission setter address that is being set or unset and have rights to set permissions.
/// @param allowed Whether the permission setter is allowed to set permissions.
event PermissionSetterSet(address indexed setter, bool allowed);
/// @notice Event emitted when deposits are paused for a protocol.
/// @param protocolId The protocol identifier of the protocol integration that is being paused.
event Paused(bytes4 indexed protocolId);
/// @notice Event emitted when deposits are unpaused for a protocol.
/// @param protocolId The protocol identifier of the protocol integration that is being unpaused.
event Unpaused(bytes4 indexed protocolId);
/// @notice Thrown when a non-strategy calls a strategy-only function.
error OnlyStrategy();
/// @notice Thrown when a non-registrar calls a registrar-only function.
error OnlyRegistrar();
/// @notice Thrown when a zero address is used.
error ZeroAddress();
/// @notice Thrown when an accountant is already set.
error AccountantAlreadySet();
/// @notice Thrown when an unauthorized address tries to set permissions.
error NotPermissionSetter();
/// @notice Thrown when trying to unshutdown a gauge that is not shutdown.
error GaugeNotShutdown();
/// @notice Thrown when trying to shutdown a gauge that is already shutdown.
error GaugeAlreadyShutdown();
/// @notice Thrown when trying to set an allocation target that is already whitelisted.
error InvalidAllocationTarget();
//////////////////////////////////////////////////////
// --- MODIFIERS
//////////////////////////////////////////////////////
/// @notice Ensures only authorized registrars or owner can register vaults.
modifier onlyRegistrar() {
require(registrar[msg.sender] || msg.sender == owner(), OnlyRegistrar());
_;
}
/// @notice Ensures only authorized permission setters can modify permissions.
modifier onlyPermissionSetter() {
require(permissionSetters[msg.sender] || msg.sender == owner(), NotPermissionSetter());
_;
}
constructor(address owner) Ownable(owner) {}
//////////////////////////////////////////////////////
// --- PERMISSION MANAGEMENT
//////////////////////////////////////////////////////
/// @notice Sets or revokes registrar permission for an address.
/// @param registrar_ The registrar address.
/// @param allowed Whether the registrar is allowed to register vaults.
/// @custom:reverts Throws an error if the registrar address is zero.
function setRegistrar(address registrar_, bool allowed) external onlyOwner {
require(registrar_ != address(0), ZeroAddress());
registrar[registrar_] = allowed;
emit RegistrarPermissionSet(registrar_, allowed);
}
/// @notice Sets or revokes permission setter status for an address.
/// @param setter The permission setter address.
/// @param allowed Whether the address is allowed to set permissions.
/// @custom:reverts Throws an error if the setter address is zero.
function setPermissionSetter(address setter, bool allowed) external onlyOwner {
require(setter != address(0), ZeroAddress());
permissionSetters[setter] = allowed;
emit PermissionSetterSet(setter, allowed);
}
/// @notice Sets a permission for a contract, caller, and function selector.
/// @param target The contract address where the permission is valid.
/// @param caller The caller address that is allowed to call the function.
/// @param selector The function selector that is being allowed or disallowed.
/// @param allowed Whether the caller is allowed to call the function.
/// @custom:reverts Throws an error if the target or caller address is zero, or if the caller is not a permission setter.
function setPermission(address target, address caller, bytes4 selector, bool allowed)
external
onlyPermissionSetter
{
require(target != address(0) && caller != address(0), ZeroAddress());
_permissions[target][caller][selector] = allowed;
emit PermissionSet(target, caller, selector, allowed);
}
//////////////////////////////////////////////////////
// --- PROTOCOL COMPONENTS MANAGEMENT
//////////////////////////////////////////////////////
/// @notice Sets a protocol strategy.
/// @param protocolId The protocol identifier.
/// @param strategy The strategy address.
/// @custom:reverts Throws an error if the _strategy address is zero.
function setStrategy(bytes4 protocolId, address strategy) external onlyOwner {
require(strategy != address(0), ZeroAddress());
_protocolComponents[protocolId].strategy = strategy;
emit ProtocolComponentSet(protocolId, "Strategy", strategy);
}
/// @notice Sets a protocol allocator.
/// @param protocolId The protocol identifier.
/// @param allocator The allocator address.
/// @custom:reverts Throws an error if the allocator address is zero.
function setAllocator(bytes4 protocolId, address allocator) external onlyOwner {
require(allocator != address(0), ZeroAddress());
_protocolComponents[protocolId].allocator = allocator;
emit ProtocolComponentSet(protocolId, "Allocator", allocator);
}
/// @notice Sets a protocol accountant.
/// @dev Accountant is immutable once set to prevent reward accounting disruption.
/// @param protocolId The protocol identifier.
/// @param accountant The accountant address.
/// @custom:reverts Throws an error if the accountant address is zero or if it was previously set.
function setAccountant(bytes4 protocolId, address accountant) external onlyOwner {
require(accountant != address(0), ZeroAddress());
require(_protocolComponents[protocolId].accountant == address(0), AccountantAlreadySet());
_protocolComponents[protocolId].accountant = accountant;
emit ProtocolComponentSet(protocolId, "Accountant", accountant);
}
/// @notice Sets a protocol fee receiver.
/// @param protocolId The protocol identifier.
/// @param feeReceiver The fee receiver address.
/// @custom:reverts Throws an error if the feeReceiver address is zero.
function setFeeReceiver(bytes4 protocolId, address feeReceiver) external onlyOwner {
require(feeReceiver != address(0), ZeroAddress());
_protocolComponents[protocolId].feeReceiver = feeReceiver;
emit ProtocolComponentSet(protocolId, "FeeReceiver", feeReceiver);
}
/// @notice Sets a protocol factory.
/// @param protocolId The protocol identifier.
/// @param factory The factory address.
/// @custom:reverts Throws an error if the factory address is zero.
function setFactory(bytes4 protocolId, address factory) external onlyOwner {
require(factory != address(0), ZeroAddress());
_protocolComponents[protocolId].factory = factory;
emit ProtocolComponentSet(protocolId, "Factory", factory);
}
/// @notice Sets a protocol locker.
/// @param protocolId The protocol identifier.
/// @param locker The locker address.
/// @custom:reverts Throws an error if the locker address is zero.
function setLocker(bytes4 protocolId, address locker) external onlyOwner {
require(locker != address(0), ZeroAddress());
_protocolComponents[protocolId].locker = locker;
emit ProtocolComponentSet(protocolId, "Locker", locker);
}
/// @notice Sets a protocol gateway
/// @param protocolId The protocol identifier
/// @param gateway The gateway address
/// @custom:reverts Throws an error if the gateway address is zero.
function setGateway(bytes4 protocolId, address gateway) external onlyOwner {
require(gateway != address(0), ZeroAddress());
_protocolComponents[protocolId].gateway = gateway;
emit ProtocolComponentSet(protocolId, "Gateway", gateway);
}
//////////////////////////////////////////////////////
// --- VAULT REGISTRATION & SHUTDOWN
//////////////////////////////////////////////////////
/// @notice Registers a vault for a gauge.
/// @dev Creates the association between an external gauge and our vault system.
/// @param gauge_ The gauge address (external protocol's staking contract).
/// @param vault The vault address (our ERC4626 vault).
/// @param asset The asset address (Token that users deposit).
/// @param rewardReceiver The reward receiver address (receives extra rewards from gauge).
/// @param protocolId The protocol identifier for the gauge.
/// @custom:reverts Throws an error if any of the addresses are zero.
function registerVault(address gauge_, address vault, address asset, address rewardReceiver, bytes4 protocolId)
external
onlyRegistrar
{
require(
gauge_ != address(0) && vault != address(0) && asset != address(0) && rewardReceiver != address(0),
ZeroAddress()
);
Gauge storage g = gauge[gauge_];
g.vault = vault;
g.asset = asset;
g.protocolId = protocolId;
g.rewardReceiver = rewardReceiver;
emit VaultRegistered(gauge_, vault, asset, rewardReceiver, protocolId);
}
/// @notice Whitelists an allocation target for a gauge.
/// @dev Strategies can only send funds to whitelisted targets for security.
/// @param gauge The gauge address.
/// @param target The target address (e.g., locker or sidecar contract).
/// @custom:reverts InvalidAllocationTarget if target is already whitelisted.
function setValidAllocationTarget(address gauge, address target) external onlyRegistrar {
require(!_isValidAllocationTargets[gauge][target], InvalidAllocationTarget());
_isValidAllocationTargets[gauge][target] = true;
}
/// @notice Removes an allocation target from the whitelist.
/// @dev Used when a target is no longer needed or trusted.
/// @param gauge The gauge address.
/// @param target The target address to remove.
/// @custom:reverts InvalidAllocationTarget if target is not currently whitelisted.
function removeValidAllocationTarget(address gauge, address target) external onlyRegistrar {
require(_isValidAllocationTargets[gauge][target], InvalidAllocationTarget());
_isValidAllocationTargets[gauge][target] = false;
}
/// @notice Emergency shutdown for a specific gauge.
/// @dev Prevents new deposits while allowing withdrawals for user fund recovery.
/// @param gauge_ The gauge address to shut down.
/// @custom:reverts GaugeAlreadyShutdown if gauge was previously shutdown.
function shutdown(address gauge_) external onlyOwner {
Gauge storage g = gauge[gauge_];
require(!g.isShutdown, GaugeAlreadyShutdown());
gauge[gauge_].isShutdown = true;
// Shutdown the gauge and withdraw all funds.
IStrategy(_protocolComponents[g.protocolId].strategy).shutdown(gauge_);
emit GaugeShutdown(gauge_);
}
/// @notice Unshuts down a gauge.
/// @dev Allows a previously shutdown gauge to resume operations.
/// @param gauge_ The gauge address to unshut down.
/// @custom:reverts GaugeNotShutdown if gauge was not previously shutdown.
function unshutdown(address gauge_) external onlyOwner {
require(gauge[gauge_].isShutdown, GaugeNotShutdown());
// Mark the gauge as not shutdown.
gauge[gauge_].isShutdown = false;
// Resume the vault operations.
IRewardVault(gauge[gauge_].vault).resumeVault();
emit GaugeUnshutdown(gauge_);
}
/// @notice Pauses deposits for a specific protocol.
/// @dev Withdrawals remain functional during pause.
/// @param protocolId The protocol identifier to pause.
function pause(bytes4 protocolId) external onlyOwner {
isPaused[protocolId] = true;
emit Paused(protocolId);
}
/// @notice Unpauses deposits for a specific protocol.
/// @param protocolId The protocol identifier to unpause.
function unpause(bytes4 protocolId) external onlyOwner {
isPaused[protocolId] = false;
emit Unpaused(protocolId);
}
//////////////////////////////////////////////////////
// --- VIEW FUNCTIONS
//////////////////////////////////////////////////////
/// @notice Returns the strategy address for a protocol.
/// @param protocolId The protocol identifier.
/// @return _ The strategy address.
function strategy(bytes4 protocolId) external view returns (address) {
return _protocolComponents[protocolId].strategy;
}
/// @notice Returns the allocator address for a protocol.
/// @param protocolId The protocol identifier.
/// @return _ The allocator address.
function allocator(bytes4 protocolId) external view returns (address) {
return _protocolComponents[protocolId].allocator;
}
/// @notice Returns the accountant address for a protocol.
/// @param protocolId The protocol identifier.
/// @return _ The accountant address.
function accountant(bytes4 protocolId) external view returns (address) {
return _protocolComponents[protocolId].accountant;
}
/// @notice Returns the fee receiver address for a protocol.
/// @param protocolId The protocol identifier.
/// @return _ The fee receiver address.
function feeReceiver(bytes4 protocolId) external view returns (address) {
return _protocolComponents[protocolId].feeReceiver;
}
/// @notice Returns the factory address for a protocol.
/// @param protocolId The protocol identifier.
/// @return _ The factory address.
function factory(bytes4 protocolId) external view returns (address) {
return _protocolComponents[protocolId].factory;
}
/// @notice Returns the locker for a given protocol.
/// @param protocolId The protocol identifier.
/// @return _ The locker address.
function locker(bytes4 protocolId) external view returns (address) {
return _protocolComponents[protocolId].locker;
}
/// @notice Returns the gateway for a given protocol.
/// @param protocolId The protocol identifier.
/// @return _ The locker address.
function gateway(bytes4 protocolId) external view returns (address) {
return _protocolComponents[protocolId].gateway;
}
/// @notice Checks if an address is an authorized registrar.
/// @param registrar_ The address to check.
/// @return _ Whether the address is an authorized registrar.
function isRegistrar(address registrar_) external view returns (bool) {
return registrar[registrar_];
}
/// @notice Returns the vault address for a gauge.
/// @param gauge_ The gauge address.
/// @return _ The vault address.
function vault(address gauge_) external view returns (address) {
return gauge[gauge_].vault;
}
/// @notice Returns the reward receiver address for a gauge.
/// @param gauge_ The gauge address.
/// @return _ The reward receiver address.
function rewardReceiver(address gauge_) external view returns (address) {
return gauge[gauge_].rewardReceiver;
}
/// @notice Returns the asset address for a gauge.
/// @param gauge_ The gauge address.
/// @return _ The asset address.
function asset(address gauge_) external view returns (address) {
return gauge[gauge_].asset;
}
/// @notice Checks if a caller is allowed to call a function on a contract.
/// @param target The contract address.
/// @param caller The caller address.
/// @param selector The function selector.
/// @return _ Whether the caller is allowed.
function allowed(address target, address caller, bytes4 selector) external view returns (bool) {
return _permissions[target][caller][selector] || caller == owner();
}
/// @notice Checks if a gauge is shutdown.
/// @dev Returns true if either the gauge itself or its protocol is shutdown.
/// @param gauge_ The gauge address.
/// @return _ Whether the gauge is shutdown.
function isShutdown(address gauge_) external view returns (bool) {
return gauge[gauge_].isShutdown;
}
/// @notice Checks if a target is a valid allocation target for a gauge
/// @param gauge The gauge address
/// @param target The target address
/// @return _ Whether the target is a valid allocation target
function isValidAllocationTarget(address gauge, address target) external view returns (bool) {
return _isValidAllocationTargets[gauge][target];
}
}
Ownable2Step.sol 67 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
import {Ownable} from "./Ownable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* This extension of the {Ownable} contract includes a two-step mechanism to transfer
* ownership, where the new owner must call {acceptOwnership} in order to replace the
* old one. This can help prevent common mistakes, such as transfers of ownership to
* incorrect accounts, or to contracts that are unable to interact with the
* permission system.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*
* Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}
IStrategy.sol 31 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import "src/interfaces/IAllocator.sol";
interface IStrategy {
/// @notice The policy for harvesting rewards.
enum HarvestPolicy {
CHECKPOINT,
HARVEST
}
struct PendingRewards {
uint128 feeSubjectAmount;
uint128 totalAmount;
}
function deposit(IAllocator.Allocation calldata allocation, HarvestPolicy policy)
external
returns (PendingRewards memory pendingRewards);
function withdraw(IAllocator.Allocation calldata allocation, HarvestPolicy policy, address receiver)
external
returns (PendingRewards memory pendingRewards);
function balanceOf(address gauge) external view returns (uint256 balance);
function harvest(address gauge, bytes calldata extraData) external returns (PendingRewards memory pendingRewards);
function flush() external;
function shutdown(address gauge) external;
}
IRewardVault.sol 59 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {IAccountant} from "src/interfaces/IAccountant.sol";
/// @title IRewardVault
/// @notice Interface for the RewardVault contract
interface IRewardVault is IERC4626 {
function addRewardToken(address rewardsToken, address distributor) external;
function depositRewards(address _rewardsToken, uint128 _amount) external;
function deposit(uint256 assets, address receiver, address referrer) external returns (uint256 shares);
function deposit(address account, address receiver, uint256 assets, address referrer)
external
returns (uint256 shares);
function claim(address[] calldata tokens, address receiver) external returns (uint256[] memory amounts);
function claim(address account, address[] calldata tokens, address receiver)
external
returns (uint256[] memory amounts);
function getRewardsDistributor(address token) external view returns (address);
function getLastUpdateTime(address token) external view returns (uint32);
function getPeriodFinish(address token) external view returns (uint32);
function getRewardRate(address token) external view returns (uint128);
function getRewardPerTokenStored(address token) external view returns (uint128);
function getRewardPerTokenPaid(address token, address account) external view returns (uint128);
function getClaimable(address token, address account) external view returns (uint128);
function getRewardTokens() external view returns (address[] memory);
function lastTimeRewardApplicable(address token) external view returns (uint256);
function rewardPerToken(address token) external view returns (uint128);
function earned(address account, address token) external view returns (uint128);
function isRewardToken(address rewardToken) external view returns (bool);
function resumeVault() external;
function gauge() external view returns (address);
function ACCOUNTANT() external view returns (IAccountant);
function checkpoint(address account) external;
function PROTOCOL_ID() external view returns (bytes4);
}
IProtocolController.sol 33 lines
/// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
interface IProtocolController {
function vault(address) external view returns (address);
function asset(address) external view returns (address);
function rewardReceiver(address) external view returns (address);
function allowed(address, address, bytes4 selector) external view returns (bool);
function permissionSetters(address) external view returns (bool);
function isRegistrar(address) external view returns (bool);
function strategy(bytes4 protocolId) external view returns (address);
function allocator(bytes4 protocolId) external view returns (address);
function accountant(bytes4 protocolId) external view returns (address);
function feeReceiver(bytes4 protocolId) external view returns (address);
function factory(bytes4 protocolId) external view returns (address);
function isPaused(bytes4) external view returns (bool);
function isShutdown(address) external view returns (bool);
function registerVault(address _gauge, address _vault, address _asset, address _rewardReceiver, bytes4 _protocolId)
external;
function setValidAllocationTarget(address _gauge, address _target) external;
function removeValidAllocationTarget(address _gauge, address _target) external;
function isValidAllocationTarget(address _gauge, address _target) external view returns (bool);
function shutdown(address _gauge) external;
function setPermissionSetter(address _setter, bool _allowed) external;
function setPermission(address _contract, address _caller, bytes4 _selector, bool _allowed) external;
}
Ownable.sol 100 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
IAllocator.sol 26 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
interface IAllocator {
struct Allocation {
address asset;
address gauge;
address[] targets;
uint256[] amounts;
}
function getDepositAllocation(address asset, address gauge, uint256 amount)
external
view
returns (Allocation memory);
function getWithdrawalAllocation(address asset, address gauge, uint256 amount)
external
view
returns (Allocation memory);
function getRebalancedAllocation(address asset, address gauge, uint256 amount)
external
view
returns (Allocation memory);
function getAllocationTargets(address gauge) external view returns (address[] memory);
}
IERC4626.sol 230 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC-4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns 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.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns 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.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}
IAccountant.sol 43 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import {IStrategy} from "src/interfaces/IStrategy.sol";
interface IAccountant {
function checkpoint(
address gauge,
address from,
address to,
uint128 amount,
IStrategy.PendingRewards calldata pendingRewards,
IStrategy.HarvestPolicy policy
) external;
function checkpoint(
address gauge,
address from,
address to,
uint128 amount,
IStrategy.PendingRewards calldata pendingRewards,
IStrategy.HarvestPolicy policy,
address referrer
) external;
function totalSupply(address asset) external view returns (uint128);
function balanceOf(address asset, address account) external view returns (uint128);
function claim(address[] calldata _gauges, bytes[] calldata harvestData) external;
function claim(address[] calldata _gauges, bytes[] calldata harvestData, address receiver) external;
function claim(address[] calldata _gauges, address account, bytes[] calldata harvestData, address receiver)
external;
function claimProtocolFees() external;
function harvest(address[] calldata _gauges, bytes[] calldata _harvestData, address _receiver) external;
function REWARD_TOKEN() external view returns (address);
function getPendingRewards(address vault) external view returns (uint128);
function getPendingRewards(address vault, address account) external view returns (uint256);
function SCALING_FACTOR() external view returns (uint128);
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
IERC20Metadata.sol 26 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
Read Contract
accountant 0xcd398592 → address
allocator 0xef64d763 → address
allowed 0x05de62c0 → bool
asset 0x9c4667a2 → address
factory 0xb3890209 → address
feeReceiver 0x09f14272 → address
gateway 0x05f533cf → address
gauge 0x7664a7e8 → address, address, address, bytes4, bool
isPaused 0x09b65e66 → bool
isRegistrar 0xd5db72eb → bool
isShutdown 0x4bc5d735 → bool
isValidAllocationTarget 0x4cf64f33 → bool
locker 0x22f1cf69 → address
owner 0x8da5cb5b → address
pendingOwner 0xe30c3978 → address
permissionSetters 0x760ad7bb → bool
registrar 0xe397cb9e → bool
rewardReceiver 0x6720a120 → address
strategy 0x0595a654 → address
vault 0xf815c03d → address
Write Contract 20 functions
These functions modify contract state and require a wallet transaction to execute.
acceptOwnership 0x79ba5097
No parameters
pause 0x3aa83ec7
bytes4 protocolId
registerVault 0x7c663ae2
address gauge_
address vault
address asset
address rewardReceiver
bytes4 protocolId
removeValidAllocationTarget 0x23404e6c
address gauge
address target
renounceOwnership 0x715018a6
No parameters
setAccountant 0xd5fe1d13
bytes4 protocolId
address accountant
setAllocator 0xf46c6c67
bytes4 protocolId
address allocator
setFactory 0x0c642df1
bytes4 protocolId
address factory
setFeeReceiver 0xb23a56f0
bytes4 protocolId
address feeReceiver
setGateway 0x7b730d16
bytes4 protocolId
address gateway
setLocker 0x791d5d31
bytes4 protocolId
address locker
setPermission 0xe64624fa
address target
address caller
bytes4 selector
bool allowed
setPermissionSetter 0xf1710d08
address setter
bool allowed
setRegistrar 0xc1bf1dcf
address registrar_
bool allowed
setStrategy 0x8604dee6
bytes4 protocolId
address strategy
setValidAllocationTarget 0xa1292903
address gauge
address target
shutdown 0xcce2f3fb
address gauge_
transferOwnership 0xf2fde38b
address newOwner
unpause 0xbac1e94b
bytes4 protocolId
unshutdown 0x622e152d
address gauge_
Recent Transactions
This address has 1 on-chain transactions, but only 0.9% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →