Overview
BERA Balance
BERA Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 2,390 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Zap Into Sty BGT... | 4088141 | 6 mins ago | IN | 0 BERA | 0 | ||||
Deposit | 4087926 | 13 mins ago | IN | 0 BERA | 0 | ||||
Zap Into Sty BGT... | 4087668 | 21 mins ago | IN | 0 BERA | 0.00020069 | ||||
Zap Into Sty BGT... | 4087653 | 22 mins ago | IN | 0 BERA | 0 | ||||
Deposit | 4087556 | 25 mins ago | IN | 0 BERA | 0.00021033 | ||||
Zap Into Sty BGT... | 4087552 | 25 mins ago | IN | 0 BERA | 0.00020754 | ||||
Deposit | 4087266 | 34 mins ago | IN | 0 BERA | 0.00001581 | ||||
Zap Into Sty BGT... | 4087163 | 38 mins ago | IN | 0 BERA | 0 | ||||
Deposit | 4087025 | 42 mins ago | IN | 0 BERA | 0.00026068 | ||||
Deposit | 4086937 | 45 mins ago | IN | 0 BERA | 0.00020917 | ||||
Zap Into Sty BGT... | 4086671 | 54 mins ago | IN | 0 BERA | 0 | ||||
Zap Into Sty BGT... | 4086180 | 1 hr ago | IN | 0 BERA | 0 | ||||
Deposit | 4085860 | 1 hr ago | IN | 0 BERA | 0.00020916 | ||||
Deposit | 4085823 | 1 hr ago | IN | 0 BERA | 0.00020694 | ||||
Zap Into Sty BGT... | 4085690 | 1 hr ago | IN | 0 BERA | 0 | ||||
Zap Into Sty BGT... | 4085489 | 1 hr ago | IN | 0 BERA | 0.00020754 | ||||
Zap Into Sty BGT... | 4085316 | 1 hr ago | IN | 0 BERA | 0.00009196 | ||||
Zap Into Sty BGT... | 4085200 | 1 hr ago | IN | 0 BERA | 0 | ||||
Zap Into Sty BGT... | 4084711 | 1 hr ago | IN | 0 BERA | 0 | ||||
Deposit | 4084688 | 1 hr ago | IN | 0 BERA | 0.00020693 | ||||
Zap Into Sty BGT... | 4084255 | 2 hrs ago | IN | 0 BERA | 0.00007463 | ||||
Zap Into Sty BGT... | 4084224 | 2 hrs ago | IN | 0 BERA | 0.00016427 | ||||
Zap Into Sty BGT... | 4084221 | 2 hrs ago | IN | 0 BERA | 0 | ||||
Zap Into Sty BGT... | 4084071 | 2 hrs ago | IN | 0 BERA | 0.0000761 | ||||
Zap Into Sty BGT... | 4083919 | 2 hrs ago | IN | 0 BERA | 0.00006226 |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
BearnTips
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 1 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Authorized} from "@bearn/governance/contracts/bases/Authorized.sol"; import {BearnVault} from "src/BearnVault.sol"; import {IBearnVault} from "src/interfaces/IBearnVault.sol"; import {IStakedBearnBGT} from "src/interfaces/IStakedBearnBGT.sol"; import {IStakedBearnBGTCompounder} from "src/interfaces/IStakedBearnBGTCompounder.sol"; /// @title BearnTips /// @author bearn.sucks /// @notice Help us afford a UI dev contract BearnTips is Authorized { using SafeERC20 for IERC20; event Tipped(address indexed tipper, address indexed token, uint256 amount); address immutable yBGT; address immutable styBGT; address immutable styBGTCompounder; address public treasury; constructor( address _authorizer, address _styBGTCompounder ) Authorized(_authorizer) { treasury = msg.sender; styBGTCompounder = _styBGTCompounder; styBGT = IStakedBearnBGTCompounder(_styBGTCompounder).styBGT(); yBGT = IStakedBearnBGT(styBGT).yBGT(); } function setTreasury( address newTreasury ) external isAuthorized(MANAGER_ROLE) { treasury = newTreasury; } function deposit( address bearnVault, address staking, uint256 amount, uint256 tips ) external { IERC20(staking).safeTransferFrom(msg.sender, address(this), amount); IERC20(staking).forceApprove(bearnVault, amount); // force approve is the new safeApprove in OZ uint256 output = IBearnVault(bearnVault).deposit(amount, address(this)); if (tips > 0) { uint256 tipAmount = (output * (tips)) / (tips + 100); output -= tipAmount; IBearnVault(bearnVault).transfer(treasury, tipAmount); emit Tipped(msg.sender, staking, tipAmount); } IBearnVault(bearnVault).transfer(msg.sender, output); } function zapIntoStyBGTCompounder( uint256 amount ) external returns (uint256) { IERC20(yBGT).safeTransferFrom(msg.sender, address(this), amount); IERC20(yBGT).forceApprove(styBGT, amount); // force approve is the new safeApprove in OZ uint256 styBGTAmount = IBearnVault(styBGT).deposit( amount, address(this) ); IERC20(styBGT).forceApprove(styBGTCompounder, styBGTAmount); // force approve is the new safeApprove in OZ uint256 output = IBearnVault(styBGTCompounder).deposit( styBGTAmount, address(msg.sender) ); return output; } function zapOutFromStyBGTCompounder( uint256 amount ) external returns (uint256) { uint256 styBGTAmount = IBearnVault(styBGTCompounder).redeem( amount, // shares address(this), // receiver msg.sender // owner ); uint256 output = IBearnVault(styBGT).redeem( styBGTAmount, // shares address(msg.sender), // receiver address(this) // owner ); return output; } function rescue( address token, uint256 amount ) external isAuthorized(MANAGER_ROLE) { IERC20(token).safeTransfer(treasury, amount); } }
// 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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC1363} from "../../../interfaces/IERC1363.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC-20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { /** * @dev An operation with an ERC-20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. * * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being * set here. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { safeTransfer(token, to, value); } else if (!token.transferAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferFromAndCallRelaxed( IERC1363 token, address from, address to, uint256 value, bytes memory data ) internal { if (to.code.length == 0) { safeTransferFrom(token, from, to, value); } else if (!token.transferFromAndCall(from, to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}. * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall} * once without retrying, and relies on the returned value to be true. * * Reverts if the returned value is other than `true`. */ function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { forceApprove(token, to, value); } else if (!token.approveAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements. */ function _callOptionalReturn(IERC20 token, bytes memory data) private { uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) // bubble errors if iszero(success) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } returnSize := returndatasize() returnValue := mload(0) } if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { bool success; uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) returnSize := returndatasize() returnValue := mload(0) } return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; import {IBearnAuthorizer} from "../interfaces/IBearnAuthorizer.sol"; contract Authorized { modifier isAuthorized(bytes32 _role) { _isAuthorized(_role, msg.sender); _; } modifier hasRole(bytes32 _role) { _hasRole(_role, msg.sender); _; } function _isAuthorized( bytes32 _role, address _sender ) internal view virtual { require( IBearnAuthorizer(AUTHORIZER).isAuthorized(_role, _sender), "!authorized" ); } function _hasRole(bytes32 _role, address _sender) internal view virtual { require( IBearnAuthorizer(AUTHORIZER).hasRole(_role, _sender), "!authorized" ); } address public immutable AUTHORIZER; bytes32 internal constant MANAGER_ROLE = keccak256("MANAGER_ROLE"); bytes32 internal constant GOVERNANCE_ROLE = keccak256("GOVERNANCE_ROLE"); constructor(address _authorizer) { AUTHORIZER = _authorizer; } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {TokenizedStaker} from "@yearn/tokenized-strategy-periphery/Bases/Staker/TokenizedStaker.sol"; import {IBearnVaultFactory} from "src/interfaces/IBearnVaultFactory.sol"; import {IBeraVault} from "src/interfaces/IBeraVault.sol"; import {IBearnBGT} from "src/interfaces/IBearnBGT.sol"; abstract contract BearnVault is TokenizedStaker { using SafeERC20 for IERC20; IBearnVaultFactory public immutable bearnVaultFactory; IBeraVault public immutable beraVault; IBearnBGT public immutable yBGT; string public symbol; constructor( string memory _name, string memory _symbol, address _asset, address _beraVault, address _yBGT ) TokenizedStaker(_asset, _name) { symbol = _symbol; bearnVaultFactory = IBearnVaultFactory(msg.sender); beraVault = IBeraVault(_beraVault); yBGT = IBearnBGT(_yBGT); // set up approvals IERC20(_asset).forceApprove(address(beraVault), type(uint256).max); // force approve is the new safeApprove in OZ // call setOperator so the BGT can be claimed to Bearn Voter IBeraVault(_beraVault).setOperator(_yBGT); //Overrideable initialization since this part will be different for yBGT and Compounding Vaults _initialize(); } function stakingAsset() external view returns (address) { return address(asset); } /// @notice Overrideable initialization since this part will be different for yBGT and Compounding Vaults function _initialize() internal virtual {} function _deployFunds(uint256 amount) internal override { beraVault.stake(amount); } function _freeFunds(uint256 amount) internal override { beraVault.withdraw(amount); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; import {ITokenizedStaker} from "@yearn/tokenized-strategy-periphery/Bases/Staker/ITokenizedStaker.sol"; interface IBearnVault is ITokenizedStaker { function bearnVaultFactory() external view returns (address); function beraVault() external view returns (address); function yBGT() external view returns (address); function stakingAsset() external view returns (address); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; import {ITokenizedStaker} from "@yearn/tokenized-strategy-periphery/Bases/Staker/ITokenizedStaker.sol"; interface IStakedBearnBGT is ITokenizedStaker { function yBGT() external view returns (address); function honey() external view returns (address); function bearnVaultManager() external view returns (address); function lastClaimedBlock() external view returns (uint256); function auction() external view returns (address); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; import {ITokenizedStaker} from "@yearn/tokenized-strategy-periphery/Bases/Staker/ITokenizedStaker.sol"; interface IStakedBearnBGTCompounder is ITokenizedStaker { function styBGT() external view returns (address); function honey() external view returns (address); function bearnVaultManager() external view returns (address); function auction() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC165} from "./IERC165.sol"; /** * @title IERC1363 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. * * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction. */ interface IERC1363 is IERC20, IERC165 { /* * Note: the ERC-165 identifier for this interface is 0xb0202a11. * 0xb0202a11 === * bytes4(keccak256('transferAndCall(address,uint256)')) ^ * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^ * bytes4(keccak256('approveAndCall(address,uint256)')) ^ * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) */ /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @param data Additional data with no specified format, sent in call to `spender`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; import {IAccessControlEnumerable} from "@openzeppelin-bearn-governance/contracts/access/extensions/IAccessControlEnumerable.sol"; interface IBearnAuthorizer is IAccessControlEnumerable { function MANAGER_ROLE() external view returns (bytes32); function GOVERNANCE_ROLE() external view returns (bytes32); function isAuthorized( bytes32 _role, address _account ) external view returns (bool); function name() external view returns (string memory); function version() external view returns (string memory); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.18; import {BaseHooks, ERC20} from "../Hooks/BaseHooks.sol"; import {SafeERC20} from "@openzeppelin-yearn/contracts/token/ERC20/utils/SafeERC20.sol"; import {ReentrancyGuard} from "@openzeppelin-yearn/contracts/security/ReentrancyGuard.sol"; import {IVaultFactory} from "@yearn-vaults/interfaces/IVaultFactory.sol"; abstract contract TokenizedStaker is BaseHooks, ReentrancyGuard { using SafeERC20 for ERC20; struct Reward { /// @notice The only address able to top up rewards for a token (aka notifyRewardAmount()). address rewardsDistributor; /// @notice The duration of our rewards distribution for staking, default is 7 days. uint96 rewardsDuration; /// @notice The end (timestamp) of our current or most recent reward period. uint96 periodFinish; /** * @notice The last time rewards were updated, triggered by updateReward() or notifyRewardAmount(). * @dev Will be the timestamp of the update or the end of the period, whichever is earlier. */ uint96 lastUpdateTime; /// @notice The distribution rate of reward token per second. uint128 rewardRate; /** * @notice The most recent stored amount for rewardPerToken(). * @dev Updated every time anyone calls the updateReward() modifier. */ uint128 rewardPerTokenStored; /** * @notice The last time a notifyRewardAmount was called. * @dev Used for lastRewardRate, a rewardRate equivalent for instant reward releases. */ uint96 lastNotifyTime; /// @notice The last rewardRate before a notifyRewardAmount was called uint128 lastRewardRate; } /* ========== EVENTS ========== */ event RewardAdded(address indexed rewardToken, uint256 reward); event RewardPaid( address indexed user, address indexed rewardToken, uint256 reward ); event RewardsDurationUpdated( address indexed rewardToken, uint256 newDuration ); event NotifiedWithZeroSupply(address indexed rewardToken, uint256 reward); event Recovered(address token, uint256 amount); /* ========== MODIFIERS ========== */ modifier updateReward(address _account) { _updateReward(_account); _; } function _updateReward(address _account) internal virtual { for (uint256 i; i < rewardTokens.length; ++i) { address rewardToken = rewardTokens[i]; rewardData[rewardToken].rewardPerTokenStored = uint128( rewardPerToken(rewardToken) ); rewardData[rewardToken].lastUpdateTime = uint96( lastTimeRewardApplicable(rewardToken) ); if (_account != address(0)) { rewards[_account][rewardToken] = earned(_account, rewardToken); userRewardPerTokenPaid[_account][rewardToken] = rewardData[ rewardToken ].rewardPerTokenStored; } } } /// @notice Array containing the addresses of all of our reward tokens. address[] public rewardTokens; /// @notice The address of our reward token => reward info. mapping(address => Reward) public rewardData; /** * @notice Mapping for staker address => address that can claim+receive tokens for them. * @dev This mapping can only be updated by management. */ mapping(address => address) public claimForRecipient; /** * @notice The amount of rewards allocated to a user per whole token staked. * @dev Note that this is not the same as amount of rewards claimed. Mapping order is user -> reward token -> amount */ mapping(address => mapping(address => uint256)) public userRewardPerTokenPaid; /** * @notice The amount of unclaimed rewards an account is owed. * @dev Mapping order is user -> reward token -> amount */ mapping(address => mapping(address => uint256)) public rewards; uint256 internal constant PRECISION = 1e18; constructor(address _asset, string memory _name) BaseHooks(_asset, _name) {} function _preDepositHook( uint256 /* assets */, uint256 /* shares */, address receiver ) internal virtual override { _updateReward(receiver); } function _preWithdrawHook( uint256 /* assets */, uint256 /* shares */, address /* receiver */, address owner, uint256 /* maxLoss */ ) internal virtual override { _updateReward(owner); } function _preTransferHook( address from, address to, uint256 /* amount */ ) internal virtual override { _updateReward(from); _updateReward(to); } // Need to update fee recipients before reporting to ensure accurate accounting // since fees are issued as shares to the recipients outside normal functionality. function _preReportHook() internal virtual override { _updateReward(TokenizedStrategy.performanceFeeRecipient()); (uint16 feeBps, address protocolFeeRecipient) = IVaultFactory( TokenizedStrategy.FACTORY() ).protocol_fee_config(); if (feeBps > 0) { _updateReward(protocolFeeRecipient); } } /// @notice Either the current timestamp or end of the most recent period. function lastTimeRewardApplicable( address _rewardToken ) public view virtual returns (uint256) { return block.timestamp < rewardData[_rewardToken].periodFinish ? block.timestamp : rewardData[_rewardToken].periodFinish; } /// @notice Reward paid out per whole token. function rewardPerToken( address _rewardToken ) public view virtual returns (uint256) { // store in memory to save gas Reward memory _rewardData = rewardData[_rewardToken]; uint256 totalSupply = _totalSupply(); if (totalSupply == 0 || _rewardData.rewardsDuration == 1) { return _rewardData.rewardPerTokenStored; } return _rewardData.rewardPerTokenStored + (((lastTimeRewardApplicable(_rewardToken) - _rewardData.lastUpdateTime) * _rewardData.rewardRate * PRECISION) / totalSupply); } /// @notice Amount of reward token pending claim by an account. function earned( address _account, address _rewardToken ) public view virtual returns (uint256) { return (TokenizedStrategy.balanceOf(_account) * (rewardPerToken(_rewardToken) - userRewardPerTokenPaid[_account][_rewardToken])) / PRECISION + rewards[_account][_rewardToken]; } /** * @notice Amount of reward token(s) pending claim by an account. * @dev Checks for all rewardTokens. * @param _account Account to check earned balance for. * @return pending Amount of reward token(s) pending claim. */ function earnedMulti( address _account ) public view virtual returns (uint256[] memory pending) { address[] memory _rewardTokens = rewardTokens; uint256 length = _rewardTokens.length; pending = new uint256[](length); for (uint256 i; i < length; ++i) { pending[i] = earned(_account, _rewardTokens[i]); } } /// @notice Reward tokens emitted over the entire rewardsDuration. function getRewardForDuration( address _rewardToken ) external view virtual returns (uint256) { // note that if rewards are instant released, this will always return zero return rewardData[_rewardToken].rewardRate * rewardData[_rewardToken].rewardsDuration; } /// @notice Correct Total supply for the locked shares from profits function _totalSupply() internal view virtual returns (uint256) { return TokenizedStrategy.totalSupply() - TokenizedStrategy.balanceOf(address(this)); } /** * @notice Notify staking contract that it has more reward to account for. * @dev May only be called by rewards distribution role or management. Set up token first via addReward(). * @param _rewardToken Address of the rewards token. * @param _rewardAmount Amount of reward tokens to add. */ function notifyRewardAmount( address _rewardToken, uint256 _rewardAmount ) external virtual { require( rewardData[_rewardToken].rewardsDistributor == msg.sender || msg.sender == TokenizedStrategy.management(), "!authorized" ); // handle the transfer of reward tokens via `transferFrom` to reduce the number // of transactions required and ensure correctness of the reward amount ERC20(_rewardToken).safeTransferFrom( msg.sender, address(this), _rewardAmount ); _notifyRewardAmount(_rewardToken, _rewardAmount); } function _notifyRewardAmount( address _rewardToken, uint256 _rewardAmount ) internal virtual updateReward(address(0)) { Reward memory _rewardData = rewardData[_rewardToken]; require(_rewardAmount > 0 && _rewardAmount < 1e30, "bad reward value"); // If total supply is 0, send tokens to management instead of reverting. // Prevent footguns if _notifyRewardInstant() is part of predeposit hooks. uint256 totalSupply = _totalSupply(); if (totalSupply == 0) { address management = TokenizedStrategy.management(); ERC20(_rewardToken).safeTransfer(management, _rewardAmount); emit NotifiedWithZeroSupply(_rewardToken, _rewardAmount); return; } // this is the only part of the struct that will be the same for instant or normal _rewardData.lastUpdateTime = uint96(block.timestamp); /// @dev A rewardsDuration of 1 dictates instant release of rewards if (_rewardData.rewardsDuration == 1) { // Update lastNotifyTime and lastRewardRate if needed (would revert if in the same block otherwise) if (uint96(block.timestamp) != _rewardData.lastNotifyTime) { _rewardData.lastRewardRate = uint128( _rewardAmount / (block.timestamp - _rewardData.lastNotifyTime) ); _rewardData.lastNotifyTime = uint96(block.timestamp); } // Update rewardRate, lastUpdateTime, periodFinish _rewardData.rewardRate = 0; _rewardData.periodFinish = uint96(block.timestamp); // Instantly release rewards by modifying rewardPerTokenStored _rewardData.rewardPerTokenStored = uint128( _rewardData.rewardPerTokenStored + (_rewardAmount * PRECISION) / totalSupply ); } else { // store current rewardRate _rewardData.lastRewardRate = _rewardData.rewardRate; _rewardData.lastNotifyTime = uint96(block.timestamp); // update our rewardData with our new rewardRate if (block.timestamp >= _rewardData.periodFinish) { _rewardData.rewardRate = uint128( _rewardAmount / _rewardData.rewardsDuration ); } else { _rewardData.rewardRate = uint128( (_rewardAmount + (_rewardData.periodFinish - block.timestamp) * _rewardData.rewardRate) / _rewardData.rewardsDuration ); } // update time-based struct fields _rewardData.periodFinish = uint96( block.timestamp + _rewardData.rewardsDuration ); } // make sure we have enough reward token for our new rewardRate require( _rewardData.rewardRate <= (ERC20(_rewardToken).balanceOf(address(this)) / _rewardData.rewardsDuration), "Not enough balance" ); // write to storage rewardData[_rewardToken] = _rewardData; emit RewardAdded(_rewardToken, _rewardAmount); } /** * @notice Claim any (and all) earned reward tokens. * @dev Can claim rewards even if no tokens still staked. */ function getReward() external virtual nonReentrant updateReward(msg.sender) { _getRewardFor(msg.sender, msg.sender); } /** * @notice Claim any (and all) earned reward tokens for another user. * @dev Mapping must be manually updated via management. Must be called by recipient. * @param _staker Address of the user to claim rewards for. */ function getRewardFor( address _staker ) external virtual nonReentrant updateReward(_staker) { require(claimForRecipient[_staker] == msg.sender, "!recipient"); _getRewardFor(_staker, msg.sender); } // internal function to get rewards. function _getRewardFor( address _staker, address _recipient ) internal virtual { for (uint256 i; i < rewardTokens.length; ++i) { address _rewardToken = rewardTokens[i]; uint256 reward = rewards[_staker][_rewardToken]; if (reward > 0) { rewards[_staker][_rewardToken] = 0; ERC20(_rewardToken).safeTransfer(_recipient, reward); emit RewardPaid(_staker, _rewardToken, reward); } } } /** * @notice Claim any one earned reward token. * @dev Can claim rewards even if no tokens still staked. * @param _rewardToken Address of the rewards token to claim. */ function getOneReward( address _rewardToken ) external virtual nonReentrant updateReward(msg.sender) { uint256 reward = rewards[msg.sender][_rewardToken]; if (reward > 0) { rewards[msg.sender][_rewardToken] = 0; ERC20(_rewardToken).safeTransfer(msg.sender, reward); emit RewardPaid(msg.sender, _rewardToken, reward); } } /// @notice Unstake all of the sender's tokens and claim any outstanding rewards. function exit() external virtual { redeem( TokenizedStrategy.balanceOf(msg.sender), msg.sender, msg.sender, 10_000 ); _getRewardFor(msg.sender, msg.sender); } /** * @notice Add a new reward token to the staking contract. * @dev May only be called by management, and can't be set to zero address. Add reward tokens sparingly, as each new * one will increase gas costs. This must be set before notifyRewardAmount can be used. A rewardsDuration of 1 * dictates instant release of rewards. * @param _rewardToken Address of the rewards token. * @param _rewardsDistributor Address of the rewards distributor. * @param _rewardsDuration The duration of our rewards distribution for staking in seconds. Set to 1 for instant * rewards distribution. */ function addReward( address _rewardToken, address _rewardsDistributor, uint256 _rewardsDuration ) external virtual onlyManagement { _addReward(_rewardToken, _rewardsDistributor, _rewardsDuration); } /// @dev Internal function to add a new reward token to the staking contract. function _addReward( address _rewardToken, address _rewardsDistributor, uint256 _rewardsDuration ) internal virtual { require( _rewardToken != address(0) && _rewardsDistributor != address(0), "No zero address" ); require(_rewardsDuration > 0, "Must be >0"); require( rewardData[_rewardToken].rewardsDuration == 0, "Reward already added" ); rewardTokens.push(_rewardToken); rewardData[_rewardToken].rewardsDistributor = _rewardsDistributor; rewardData[_rewardToken].rewardsDuration = uint96(_rewardsDuration); } /** * @notice Set the duration of our rewards period. * @dev May only be called by management, and must be done after most recent period ends. * @param _rewardToken Address of the rewards token. * @param _rewardsDuration New length of period in seconds. Set to 1 for instant rewards release. */ function setRewardsDuration( address _rewardToken, uint256 _rewardsDuration ) external virtual onlyManagement { _setRewardsDuration(_rewardToken, _rewardsDuration); } function _setRewardsDuration( address _rewardToken, uint256 _rewardsDuration ) internal virtual { _updateReward(address(0)); // Previous rewards period must be complete before changing the duration for the new period require( block.timestamp > rewardData[_rewardToken].periodFinish, "!period" ); require(_rewardsDuration > 0, "Must be >0"); rewardData[_rewardToken].rewardsDuration = uint96(_rewardsDuration); emit RewardsDurationUpdated(_rewardToken, _rewardsDuration); } /** * @notice Setup a staker-recipient pair. * @dev May only be called by management. Useful for contracts that can't handle extra reward tokens to direct * rewards elsewhere. * @param _staker Address that holds the vault tokens. * @param _recipient Address to claim and receive extra rewards on behalf of _staker. */ function setClaimFor( address _staker, address _recipient ) external virtual onlyManagement { _setClaimFor(_staker, _recipient); } /** * @notice Give another address permission to claim (and receive!) your rewards. * @dev Useful if we want to add in complex logic following rewards claim such as staking. * @param _recipient Address to claim and receive extra rewards on behalf of msg.sender. */ function setClaimForSelf(address _recipient) external virtual { _setClaimFor(msg.sender, _recipient); } function _setClaimFor( address _staker, address _recipient ) internal virtual { require(_staker != address(0), "No zero address"); claimForRecipient[_staker] = _recipient; } /** * @notice Sweep out tokens accidentally sent here. * @dev May only be called by management. If a pool has multiple tokens to sweep out, call this once for each. * @param _tokenAddress Address of token to sweep. * @param _tokenAmount Amount of tokens to sweep. */ function recoverERC20( address _tokenAddress, uint256 _tokenAmount ) external virtual onlyManagement { require(_tokenAddress != address(asset), "!asset"); // can only recover reward tokens 90 days after last reward token ends bool isRewardToken; address[] memory _rewardTokens = rewardTokens; uint256 maxPeriodFinish; for (uint256 i; i < _rewardTokens.length; ++i) { uint256 rewardPeriodFinish = rewardData[_rewardTokens[i]] .periodFinish; if (rewardPeriodFinish > maxPeriodFinish) { maxPeriodFinish = rewardPeriodFinish; } if (_rewardTokens[i] == _tokenAddress) { isRewardToken = true; } } if (isRewardToken) { require( block.timestamp > maxPeriodFinish + 90 days, "wait >90 days" ); // if we do this, automatically sweep all reward token _tokenAmount = ERC20(_tokenAddress).balanceOf(address(this)); } ERC20(_tokenAddress).safeTransfer( TokenizedStrategy.management(), _tokenAmount ); emit Recovered(_tokenAddress, _tokenAmount); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; interface IBearnVaultFactory { /* ========== ERRORS ========== */ error NotInitialized(); error NoBeraVault(); error AlreadyExists(); /* ========== EVENTS ========== */ event NewVaultManager(address newVaultManager); event NewAuctionFactory(address newAuctionFactory); event NewVaults( address indexed stakingToken, address compoundingVault, address yBGTVault ); function beraVaultFactory() external view returns (address); function keeper() external view returns (address); function yBGT() external view returns (address); function bearnVaultManager() external view returns (address); function bearnAuctionFactory() external view returns (address); function stakingToCompoundingVaults( address stakingToken ) external view returns (address); function stakingToBGTEarnerVaults( address stakingToken ) external view returns (address); function isBearnVault(address bearnVault) external view returns (bool); function getAllCompoundingVaultsLength() external view returns (uint256); function getCompoundingVault(uint256 index) external view returns (address); function getAllCompoundingVaults() external view returns (address[] memory); function getAllBgtEarnerVaultsLength() external view returns (uint256); function getBgtEarnerVault(uint256 index) external view returns (address); function getAllBgtEarnerVaults() external view returns (address[] memory); function setVaultManager(address _newBearnVaultManager) external; function setAuctionFactory(address _newAuctionFactory) external; function createVaults( address stakingToken ) external returns (address compoundingVault, address yBGTVault); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; import {IRewardVault} from "@berachain/contracts/pol/interfaces/IRewardVault.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IBeraVault is IRewardVault { /// @notice ERC20 token which users stake to earn rewards. function stakeToken() external view returns (address); /// @notice ERC20 token in which rewards are denominated and distributed. function rewardToken() external view returns (address); /// @notice The reward rate for the current reward period scaled by PRECISION. function rewardRate() external view returns (uint256); /// @notice The amount of undistributed rewards scaled by PRECISION. function undistributedRewards() external view returns (uint256); /// @notice The last updated reward per token scaled by PRECISION. function rewardPerTokenStored() external view returns (uint256); /// @notice The total supply of the staked tokens. function totalSupply() external view returns (uint256); /// @notice The end of the current reward period, where we need to start a new one. function periodFinish() external view returns (uint256); /// @notice The time over which the rewards will be distributed. Current default is 7 days. function rewardsDuration() external view returns (uint256); /// @notice The last time the rewards were updated. function lastUpdateTime() external view returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; interface IBearnBGT is IERC20, IERC20Permit { error NoBeraVault(); error NoBGT(); event NewFeeModule(address newFeeModule); event NewTreasury(address newFeeRecipient); function MANAGER_ROLE() external view returns (bytes32); function beraVaultFactory() external view returns (address); function bearnVoter() external view returns (address); function feeModule() external view returns (address); function treasury() external view returns (address); function wrap(address stakingToken) external returns (uint256 amount); function redeem(uint256 amount) external returns (uint256 outputAmount); function previewWrap( address to, uint256 inputAmount ) external view returns (uint256 outputAmount); function previewRedeem( address to, uint256 amount ) external view returns (uint256 outputAmount); function maxRedeem() external view returns (uint256 maxAmount); function setFeeModule(address newFeeModule) external; function setFeeRecipient(address newFeeRecipient) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.18; import {IStrategy} from "@tokenized-strategy/interfaces/IStrategy.sol"; interface ITokenizedStaker is IStrategy { struct Reward { /// @notice The only address able to top up rewards for a token (aka notifyRewardAmount()). address rewardsDistributor; /// @notice The duration of our rewards distribution for staking, default is 7 days. uint96 rewardsDuration; /// @notice The end (timestamp) of our current or most recent reward period. uint96 periodFinish; /** * @notice The last time r ewards were updated, triggered by updateReward() or notifyRewardAmount(). * @dev Will be the timestamp of the update or the end of the period, whichever is earlier. */ uint96 lastUpdateTime; /// @notice The distribution rate of reward token per second. uint128 rewardRate; /** * @notice The most recent stored amount for rewardPerToken(). * @dev Updated every time anyone calls the updateReward() modifier. */ uint128 rewardPerTokenStored; /** * @notice The last time a notifyRewardAmount was called. * @dev Used for lastRewardRate, a rewardRate equivalent for instant reward releases. */ uint96 lastNotifyTime; /// @notice The last rewardRate before a notifyRewardAmount was called uint128 lastRewardRate; } /* ========== EVENTS ========== */ event RewardAdded(address indexed rewardToken, uint256 reward); event RewardPaid( address indexed user, address indexed rewardToken, uint256 reward ); event RewardsDurationUpdated( address indexed rewardToken, uint256 newDuration ); event NotifiedWithZeroSupply(address indexed rewardToken, uint256 reward); event Recovered(address token, uint256 amount); /* ========== STATE VARIABLES ========== */ function rewardTokens(uint256 index) external view returns (address); function rewardToken(address) external view returns (address); function periodFinish(address) external view returns (uint256); function rewardRate(address) external view returns (uint256); function rewardsDuration(address) external view returns (uint256); function lastUpdateTime(address) external view returns (uint256); function rewardPerTokenStored(address) external view returns (uint256); function userRewardPerTokenPaid( address _account, address _rewardToken ) external view returns (uint256); function rewards( address _account, address _rewardToken ) external view returns (uint256); function claimForRecipient(address) external view returns (address); /* ========== FUNCTIONS ========== */ function lastTimeRewardApplicable( address _rewardToken ) external view returns (uint256); function rewardPerToken( address _rewardToken ) external view returns (uint256); function earned( address _account, address _rewardToken ) external view returns (uint256); function earnedMulti( address _account ) external view returns (uint256[] memory); function getRewardForDuration( address _rewardToken ) external view returns (uint256); function notifyRewardAmount( address _rewardToken, uint256 _rewardAmount ) external; function getReward() external; function exit() external; function setRewardsDuration( address _rewardToken, uint256 _rewardsDuration ) external; function setClaimFor(address _staker, address _recipient) external; function setClaimForSelf(address _recipient) external; function rewardData( address rewardToken ) external view returns (Reward memory); function addReward( address _rewardToken, address _rewardsDistributor, uint256 _rewardsDuration ) external; function getOneReward(address _rewardToken) external; function recoverERC20(address _tokenAddress, uint256 _tokenAmount) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (access/extensions/IAccessControlEnumerable.sol) pragma solidity ^0.8.20; import {IAccessControl} from "../IAccessControl.sol"; /** * @dev External interface of AccessControlEnumerable declared to support ERC-165 detection. */ interface IAccessControlEnumerable is IAccessControl { /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) external view returns (address); /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) external view returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; import {Hooks} from "./Hooks.sol"; import {BaseHealthCheck, ERC20} from "../HealthCheck/BaseHealthCheck.sol"; /** * @title Base Hooks * @author Yearn.finance * @notice This contract can be inherited by any Yearn * strategy wishing to implement pre or post deposit, withdraw * or transfer hooks in their strategy. */ abstract contract BaseHooks is BaseHealthCheck, Hooks { constructor( address _asset, string memory _name ) BaseHealthCheck(_asset, _name) {} // Deposit function deposit( uint256 assets, address receiver ) external virtual returns (uint256 shares) { _preDepositHook(assets, shares, receiver); shares = abi.decode( _delegateCall( abi.encodeCall(TokenizedStrategy.deposit, (assets, receiver)) ), (uint256) ); _postDepositHook(assets, shares, receiver); } // Mint function mint( uint256 shares, address receiver ) external virtual returns (uint256 assets) { _preDepositHook(assets, shares, receiver); assets = abi.decode( _delegateCall( abi.encodeCall(TokenizedStrategy.mint, (shares, receiver)) ), (uint256) ); _postDepositHook(assets, shares, receiver); } // Withdraw function withdraw( uint256 assets, address receiver, address owner ) external virtual returns (uint256 shares) { return withdraw(assets, receiver, owner, 0); } function withdraw( uint256 assets, address receiver, address owner, uint256 maxLoss ) public virtual returns (uint256 shares) { _preWithdrawHook(assets, shares, receiver, owner, maxLoss); shares = abi.decode( _delegateCall( // Have to use encodeWithSignature due to overloading parameters. abi.encodeWithSignature( "withdraw(uint256,address,address,uint256)", assets, receiver, owner, maxLoss ) ), (uint256) ); _postWithdrawHook(assets, shares, receiver, owner, maxLoss); } // Redeem function redeem( uint256 shares, address receiver, address owner ) external virtual returns (uint256) { // We default to not limiting a potential loss. return redeem(shares, receiver, owner, MAX_BPS); } function redeem( uint256 shares, address receiver, address owner, uint256 maxLoss ) public returns (uint256 assets) { _preWithdrawHook(assets, shares, receiver, owner, maxLoss); assets = abi.decode( _delegateCall( // Have to use encodeWithSignature due to overloading parameters. abi.encodeWithSignature( "redeem(uint256,address,address,uint256)", shares, receiver, owner, maxLoss ) ), (uint256) ); _postWithdrawHook(assets, shares, receiver, owner, maxLoss); } // Transfer function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool success) { _preTransferHook(from, to, amount); success = abi.decode( _delegateCall( abi.encodeCall( TokenizedStrategy.transferFrom, (from, to, amount) ) ), (bool) ); _postTransferHook(from, to, amount, success); } // Transfer from function transfer( address to, uint256 amount ) external virtual returns (bool success) { _preTransferHook(msg.sender, to, amount); success = abi.decode( _delegateCall( abi.encodeCall(TokenizedStrategy.transfer, (to, amount)) ), (bool) ); _postTransferHook(msg.sender, to, amount, success); } function report() external virtual returns (uint256 profit, uint256 loss) { _preReportHook(); (profit, loss) = abi.decode( _delegateCall(abi.encodeCall(TokenizedStrategy.report, ())), (uint256, uint256) ); _postReportHook(profit, loss); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.18; import {ERC20} from "@openzeppelin-yearn/contracts/token/ERC20/ERC20.sol"; interface IVaultFactory { event NewVault(address indexed vaultAddress, address indexed asset); event UpdateProtocolFeeBps( uint16 oldProtocolFeeBps, uint16 newProtocolFeeBps ); event UpdateProtocolFeeRecipient( address oldProtocolFeeRecipient, address newProtocolFeeRecipient ); event UpdateCustomProtocolFee(address vault, uint16 newCustomProtocolFee); event RemovedCustomProtocolFee(address vault); event FactoryShutdown(); event UpdatePendingGovernance(address newPendingGovernance); event GovernanceTransferred( address previousGovernance, address newGovernance ); function shutdown() external view returns (bool); function governance() external view returns (address); function pendingGovernance() external view returns (address); function name() external view returns (string memory); function use_custom_protocol_fee(address) external view returns (bool); function deploy_new_vault( address asset, string memory name, string memory symbol, address role_manager, uint256 profit_max_unlock_time ) external returns (address); function vault_original() external view returns (address); function apiVersion() external view returns (string memory); function protocol_fee_config() external view returns (uint16 fee_bps, address fee_recipient); function protocol_fee_config( address vault ) external view returns (uint16 fee_bps, address fee_recipient); function set_protocol_fee_bps(uint16 new_protocol_fee_bps) external; function set_protocol_fee_recipient( address new_protocol_fee_recipient ) external; function set_custom_protocol_fee_bps( address vault, uint16 new_custom_protocol_fee ) external; function remove_custom_protocol_fee(address vault) external; function shutdown_factory() external; function transferGovernance(address new_governance) external; function acceptGovernance() external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.28; import { IPOLErrors } from "./IPOLErrors.sol"; import { IStakingRewards } from "../../base/IStakingRewards.sol"; interface IRewardVault is IPOLErrors, IStakingRewards { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Emitted when a delegate has staked on behalf of an account. /// @param account The account whose delegate has staked. /// @param delegate The delegate that has staked. /// @param amount The amount of staked tokens. event DelegateStaked(address indexed account, address indexed delegate, uint256 amount); /// @notice Emitted when a delegate has withdrawn on behalf of an account. /// @param account The account whose delegate has withdrawn. /// @param delegate The delegate that has withdrawn. /// @param amount The amount of withdrawn tokens. event DelegateWithdrawn(address indexed account, address indexed delegate, uint256 amount); /// @notice Emitted when a token has been recovered. /// @param token The token that has been recovered. /// @param amount The amount of token recovered. event Recovered(address token, uint256 amount); /// @notice Emitted when the msg.sender has set an operator to handle its rewards. /// @param account The account that has set the operator. /// @param operator The operator that has been set. event OperatorSet(address account, address operator); /// @notice Emitted when the distributor is set. /// @param distributor The address of the distributor. event DistributorSet(address indexed distributor); /// @notice Emitted when the manager of an incentive token is changed. /// @param token The address of the incentive token. /// @param newManager The new manager of the incentive token. /// @param oldManager The old manager of the incentive token. event IncentiveManagerChanged(address indexed token, address newManager, address oldManager); /// @notice Emitted when an incentive token is whitelisted. /// @param token The address of the token that has been whitelisted. /// @param minIncentiveRate The minimum amount of the token to incentivize per BGT emission. /// @param manager The address of the manager that can addIncentive for this incentive token. event IncentiveTokenWhitelisted(address indexed token, uint256 minIncentiveRate, address manager); /// @notice Emitted when an incentive token is removed. /// @param token The address of the token that has been removed. event IncentiveTokenRemoved(address indexed token); /// @notice Emitted when maxIncentiveTokensCount is updated. /// @param maxIncentiveTokensCount The max count of incentive tokens. event MaxIncentiveTokensCountUpdated(uint8 maxIncentiveTokensCount); /// @notice Emitted when incentives are processed for the operator of a validator. event IncentivesProcessed(bytes indexed pubkey, address indexed token, uint256 bgtEmitted, uint256 amount); /// @notice Emitted when incentives fail to be processed for the operator of a validator. event IncentivesProcessFailed(bytes indexed pubkey, address indexed token, uint256 bgtEmitted, uint256 amount); /// @notice Emitted when incentives are added to the vault. /// @param token The incentive token. /// @param sender The address that added the incentive. /// @param amount The amount of the incentive. /// @param incentiveRate The amount of the token to incentivize per BGT emission. event IncentiveAdded(address indexed token, address sender, uint256 amount, uint256 incentiveRate); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GETTERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Get the address that is allowed to distribute rewards. /// @return The address that is allowed to distribute rewards. function distributor() external view returns (address); /// @notice Get the operator for an account. /// @param account The account to get the operator for. /// @return The operator for the account. function operator(address account) external view returns (address); /// @notice Get the count of active incentive tokens. /// @return The count of active incentive tokens. function getWhitelistedTokensCount() external view returns (uint256); /// @notice Get the list of whitelisted tokens. /// @return The list of whitelisted tokens. function getWhitelistedTokens() external view returns (address[] memory); /// @notice Get the total amount staked by delegates. /// @return The total amount staked by delegates. function getTotalDelegateStaked(address account) external view returns (uint256); /// @notice Get the amount staked by a delegate on behalf of an account. /// @return The amount staked by a delegate. function getDelegateStake(address account, address delegate) external view returns (uint256); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ADMIN */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @notice Initialize the vault, this is only callable once and by the factory since its the deployer. * @param _berachef The address of the berachef. * @param _bgt The address of the BGT token. * @param _distributor The address of the distributor. * @param _stakingToken The address of the staking token. */ function initialize(address _berachef, address _bgt, address _distributor, address _stakingToken) external; /// @notice Allows the factory owner to set the contract that is allowed to distribute rewards. /// @param _rewardDistribution The address that is allowed to distribute rewards. function setDistributor(address _rewardDistribution) external; /// @notice Allows the distributor to notify the reward amount. /// @param pubkey The pubkey of the validator. /// @param reward The amount of reward to notify. function notifyRewardAmount(bytes calldata pubkey, uint256 reward) external; /// @notice Allows the factory owner to recover any ERC20 token from the vault. /// @param tokenAddress The address of the token to recover. /// @param tokenAmount The amount of token to recover. function recoverERC20(address tokenAddress, uint256 tokenAmount) external; /// @notice Allows the factory owner to update the duration of the rewards. /// @param _rewardsDuration The new duration of the rewards. function setRewardsDuration(uint256 _rewardsDuration) external; /// @notice Allows the factory owner to whitelist a token to incentivize with. /// @param token The address of the token to whitelist. /// @param minIncentiveRate The minimum amount of the token to incentivize per BGT emission. /// @param manager The address of the manager that can addIncentive for this token. function whitelistIncentiveToken(address token, uint256 minIncentiveRate, address manager) external; /// @notice Allows the factory vault manager to remove a whitelisted incentive token. /// @param token The address of the token to remove. function removeIncentiveToken(address token) external; /// @notice Allows the factory owner to update the maxIncentiveTokensCount. /// @param _maxIncentiveTokensCount The new maxIncentiveTokens count. function setMaxIncentiveTokensCount(uint8 _maxIncentiveTokensCount) external; /// @notice Allows the factory vault pauser to pause the vault. function pause() external; /// @notice Allows the factory vault manager to unpause the vault. function unpause() external; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MUTATIVE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Exit the vault with the staked tokens and claim the reward. /// @dev Only the account holder can call this function, not the operator. /// @dev Clears out the user self-staked balance and rewards. /// @param recipient The address to send the 'BGT' reward to. function exit(address recipient) external; /// @notice Claim the reward. /// @dev The operator only handles BGT, not STAKING_TOKEN. /// @dev Callable by the operator or the account holder. /// @param account The account to get the reward for. /// @param recipient The address to send the reward to. /// @return The amount of the reward claimed. function getReward(address account, address recipient) external returns (uint256); /// @notice Stake tokens in the vault. /// @param amount The amount of tokens to stake. function stake(uint256 amount) external; /// @notice Stake tokens on behalf of another account. /// @param account The account to stake for. /// @param amount The amount of tokens to stake. function delegateStake(address account, uint256 amount) external; /// @notice Withdraw the staked tokens from the vault. /// @param amount The amount of tokens to withdraw. function withdraw(uint256 amount) external; /// @notice Withdraw tokens staked on behalf of another account by the delegate (msg.sender). /// @param account The account to withdraw for. /// @param amount The amount of tokens to withdraw. function delegateWithdraw(address account, uint256 amount) external; /// @notice Allows msg.sender to set another address to claim and manage their rewards. /// @param _operator The address that will be allowed to claim and manage rewards. function setOperator(address _operator) external; /// @notice Update the manager of an incentive token. /// @dev Permissioned function, only allow factory owner to update the manager. /// @param token The address of the incentive token. /// @param newManager The new manager of the incentive token. function updateIncentiveManager(address token, address newManager) external; /// @notice Add an incentive token to the vault. /// @notice The incentive token's transfer should not exceed a gas usage of 500k units. /// In case the transfer exceeds 500k gas units, your incentive will fail to be transferred to the validator and /// its delegates. /// @param token The address of the token to add as an incentive. /// @param amount The amount of the token to add as an incentive. /// @param incentiveRate The amount of the token to incentivize per BGT emission. /// @dev Permissioned function, only callable by incentive token manager. function addIncentive(address token, uint256 amount, uint256 incentiveRate) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612]. * * Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; import {ITokenizedStrategy} from "./ITokenizedStrategy.sol"; import {IBaseStrategy} from "./IBaseStrategy.sol"; interface IStrategy is IBaseStrategy, ITokenizedStrategy {}
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC-165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role). * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; contract DepositHooks { function _preDepositHook( uint256 assets, uint256 shares, address receiver ) internal virtual {} function _postDepositHook( uint256 assets, uint256 shares, address receiver ) internal virtual {} } contract WithdrawHooks { function _preWithdrawHook( uint256 assets, uint256 shares, address receiver, address owner, uint256 maxLoss ) internal virtual {} function _postWithdrawHook( uint256 assets, uint256 shares, address receiver, address owner, uint256 maxLoss ) internal virtual {} } contract TransferHooks { function _preTransferHook( address from, address to, uint256 amount ) internal virtual {} function _postTransferHook( address from, address to, uint256 amount, bool success ) internal virtual {} } contract ReportHooks { function _preReportHook() internal virtual {} function _postReportHook(uint256 profit, uint256 loss) internal virtual {} } contract Hooks is DepositHooks, WithdrawHooks, TransferHooks, ReportHooks {}
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; import {BaseStrategy, ERC20} from "@tokenized-strategy/BaseStrategy.sol"; /** * @title Base Health Check * @author Yearn.finance * @notice This contract can be inherited by any Yearn * V3 strategy wishing to implement a health check during * the `report` function in order to prevent any unexpected * behavior from being permanently recorded as well as the * `checkHealth` modifier. * * A strategist simply needs to inherit this contract. Set * the limit ratios to the desired amounts and then * override `_harvestAndReport()` just as they otherwise * would. If the profit or loss that would be recorded is * outside the acceptable bounds the tx will revert. * * The healthcheck does not prevent a strategy from reporting * losses, but rather can make sure manual intervention is * needed before reporting an unexpected loss or profit. */ abstract contract BaseHealthCheck is BaseStrategy { // Can be used to determine if a healthcheck should be called. // Defaults to true; bool public doHealthCheck = true; uint256 internal constant MAX_BPS = 10_000; // Default profit limit to 100%. uint16 private _profitLimitRatio = uint16(MAX_BPS); // Defaults loss limit to 0. uint16 private _lossLimitRatio; constructor( address _asset, string memory _name ) BaseStrategy(_asset, _name) {} /** * @notice Returns the current profit limit ratio. * @dev Use a getter function to keep the variable private. * @return . The current profit limit ratio. */ function profitLimitRatio() public view returns (uint256) { return _profitLimitRatio; } /** * @notice Returns the current loss limit ratio. * @dev Use a getter function to keep the variable private. * @return . The current loss limit ratio. */ function lossLimitRatio() public view returns (uint256) { return _lossLimitRatio; } /** * @notice Set the `profitLimitRatio`. * @dev Denominated in basis points. I.E. 1_000 == 10%. * @param _newProfitLimitRatio The mew profit limit ratio. */ function setProfitLimitRatio( uint256 _newProfitLimitRatio ) external onlyManagement { _setProfitLimitRatio(_newProfitLimitRatio); } /** * @dev Internally set the profit limit ratio. Denominated * in basis points. I.E. 1_000 == 10%. * @param _newProfitLimitRatio The mew profit limit ratio. */ function _setProfitLimitRatio(uint256 _newProfitLimitRatio) internal { require(_newProfitLimitRatio > 0, "!zero profit"); require(_newProfitLimitRatio <= type(uint16).max, "!too high"); _profitLimitRatio = uint16(_newProfitLimitRatio); } /** * @notice Set the `lossLimitRatio`. * @dev Denominated in basis points. I.E. 1_000 == 10%. * @param _newLossLimitRatio The new loss limit ratio. */ function setLossLimitRatio( uint256 _newLossLimitRatio ) external onlyManagement { _setLossLimitRatio(_newLossLimitRatio); } /** * @dev Internally set the loss limit ratio. Denominated * in basis points. I.E. 1_000 == 10%. * @param _newLossLimitRatio The new loss limit ratio. */ function _setLossLimitRatio(uint256 _newLossLimitRatio) internal { require(_newLossLimitRatio < MAX_BPS, "!loss limit"); _lossLimitRatio = uint16(_newLossLimitRatio); } /** * @notice Turns the healthcheck on and off. * @dev If turned off the next report will auto turn it back on. * @param _doHealthCheck Bool if healthCheck should be done. */ function setDoHealthCheck(bool _doHealthCheck) public onlyManagement { doHealthCheck = _doHealthCheck; } /** * @notice OVerrides the default {harvestAndReport} to include a healthcheck. * @return _totalAssets New totalAssets post report. */ function harvestAndReport() external override onlySelf returns (uint256 _totalAssets) { // Let the strategy report. _totalAssets = _harvestAndReport(); // Run the healthcheck on the amount returned. _executeHealthCheck(_totalAssets); } /** * @dev To be called during a report to make sure the profit * or loss being recorded is within the acceptable bound. * * @param _newTotalAssets The amount that will be reported. */ function _executeHealthCheck(uint256 _newTotalAssets) internal virtual { if (!doHealthCheck) { doHealthCheck = true; return; } // Get the current total assets from the implementation. uint256 currentTotalAssets = TokenizedStrategy.totalAssets(); if (_newTotalAssets > currentTotalAssets) { require( ((_newTotalAssets - currentTotalAssets) <= (currentTotalAssets * uint256(_profitLimitRatio)) / MAX_BPS), "healthCheck" ); } else if (currentTotalAssets > _newTotalAssets) { require( (currentTotalAssets - _newTotalAssets <= ((currentTotalAssets * uint256(_lossLimitRatio)) / MAX_BPS)), "healthCheck" ); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ 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 amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` 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 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.28; import { IStakingRewardsErrors } from "../../base/IStakingRewardsErrors.sol"; /// @notice Interface of POL errors interface IPOLErrors is IStakingRewardsErrors { // Signature: 0xf2d81d95 error NotApprovedSender(); // Signature: 0x1db3b859 error NotDelegate(); // Signature: 0x53f0a596 error NotBGT(); // Signature: 0x1b0eb4ec error NotBlockRewardController(); // Signature: 0x385296d5 error NotDistributor(); // Signature: 0x73fcd3fe error NotFeeCollector(); // Signature: 0x36407850 error NotWhitelistedVault(); // Signature:0x7c214f04 error NotOperator(); // Signature: 0xad3a8b9e error NotEnoughBalance(); // Signature: 0xadd377f6 error InvalidActivateBoostDelay(); // Signature: 0x2f14f4f9 error InvalidDropBoostDelay(); // Signature: 0x14969061 error NotEnoughBoostedBalance(); // Signature: 0xe8966d7a error NotEnoughTime(); // Signature: 0xec2caa0d error InvalidStartBlock(); // Signature: 0x3be31f8c error RewardAllocationAlreadyQueued(); // Signature: 0x13134d24 error InvalidRewardAllocationWeights(); // Signature: 0xf6fae721 error TooManyWeights(); // Signature: 0x3e38573f error InvalidateDefaultRewardAllocation(); // Signature: 0xd92e233d error ZeroAddress(); // Signature: 0x462a2bb2 error RewardAllocationBlockDelayTooLarge(); // Signature: 0x08519afa error NotFactoryVault(); // Signature: 0x978dc040 error ZeroPercentageWeight(); /* BLOCK REWARD CONTROLLLER */ // Signature: 0x2e2dab43 error InvalidBaseRate(); // Signature: 0x22be2284 error InvalidRewardRate(); // Signature: 0x15482337 error InvalidMinBoostedRewardRate(); // Signature: 0xb7b2319a error InvalidBoostMultiplier(); // Signature: 0x347f95b2 error InvalidRewardConvexity(); /* STAKING */ // Signature: 0x09ee12d5 error NotAContract(); // Signature: 0xe4ea100b error CannotRecoverRewardToken(); // Signature: 0x1b813803 error CannotRecoverStakingToken(); // Signature: 0x2899103f error CannotRecoverIncentiveToken(); // Signature: 0x38432c89 error IncentiveRateTooHigh(); // Signature: 0x5ee4de0e error NotIncentiveManager(); // Signature: 0xf84835a0 error TokenNotWhitelisted(); // Signature: 0x8d1473a6 error InsufficientDelegateStake(); // Signature: 0x08e88f46 error InsufficientSelfStake(); // Signature: 0xfbf97e07 error TokenAlreadyWhitelistedOrLimitReached(); // Signature: 0xad57d95d error AmountLessThanMinIncentiveRate(); // Signature: 0xfbf1123c error InvalidMaxIncentiveTokensCount(); // Signature: 0x546c7600 error PayoutAmountIsZero(); // Signature: 0x89c622a2 error DonateAmountLessThanPayoutAmount(); // Signature: 0xa4cc22ed error MaxNumWeightsPerRewardAllocationIsZero(); // Signature: 0x0b5c3aff error MinIncentiveRateIsZero(); // Signature: 0x8e7572da error InvariantCheckFailed(); /* BEACON ROOTS */ // Signature: 0x1390f2a1 error IndexOutOfRange(); // Signature: 0x09bde339 error InvalidProof(); // Signature: 0x0a431b2a error TimestampAlreadyProcessed(); /* BEACON DEPOSIT */ /// @dev Error thrown when the deposit amount is too small, to prevent dust deposits. // Signature: 0x0e1eddda error InsufficientDeposit(); /// @dev Error thrown when the deposit amount is not a multiple of Gwei. // Signature: 0x40567b38 error DepositNotMultipleOfGwei(); /// @dev Error thrown when the deposit amount is too high, since it is a uint64. // Signature: 0x2aa66734 error DepositValueTooHigh(); /// @dev Error thrown when the public key length is not 48 bytes. // Signature: 0x9f106472 error InvalidPubKeyLength(); /// @dev Error thrown when the withdrawal credentials length is not 32 bytes. // Signature: 0xb39bca16 error InvalidCredentialsLength(); /// @dev Error thrown when the signature length is not 96 bytes. // Signature: 0x4be6321b error InvalidSignatureLength(); /// @dev Error thrown when the input operator is zero address on the first deposit. // Signature: 0x51969a7a error ZeroOperatorOnFirstDeposit(); /// @dev Error thrown when the operator is already set and caller passed non-zero operator. // Signature: 0xc4142b41 error OperatorAlreadySet(); /// @dev Error thrown when the caller is not the current operator. // Signature: 0x819a0d0b error NotNewOperator(); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.28; import { IStakingRewardsErrors } from "./IStakingRewardsErrors.sol"; /// @notice Interface of staking rewards interface IStakingRewards is IStakingRewardsErrors { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Emitted when a reward has been added to the vault. /// @param reward The amount of reward added, scaled by PRECISION. event RewardAdded(uint256 reward); /// @notice Emitted when the staking balance of an account has increased. /// @param account The account that has staked. /// @param amount The amount of staked tokens. event Staked(address indexed account, uint256 amount); /// @notice Emitted when the staking balance of an account has decreased. /// @param account The account that has withdrawn. /// @param amount The amount of withdrawn tokens. event Withdrawn(address indexed account, uint256 amount); /// @notice Emitted when a reward has been claimed. /// @param account The account whose reward has been claimed. /// @param to The address that the reward was sent to. (user or operator). /// @param reward The amount of reward claimed. event RewardPaid(address indexed account, address to, uint256 reward); /// @notice Emitted when the reward duration has been updated. /// @param newDuration The new duration of the reward. event RewardsDurationUpdated(uint256 newDuration); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GETTERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Get the balance of the staked tokens for an account. /// @param account The account to get the balance for. /// @return The balance of the staked tokens. function balanceOf(address account) external view returns (uint256); /// @notice Get the reward balance for a specific account. /// @param account The account to retrieve the reward balance for. /// @return The current reward balance of the specified account. function rewards(address account) external view returns (uint256); /// @notice Get the user reward per token paid. /// @param account The account to retrieve the reward for. /// @return The current reward balance of the specified account. function userRewardPerTokenPaid(address account) external view returns (uint256); /// @notice Retrieves the amount of reward earned by a specific account. /// @param account The account to calculate the reward for. /// @return The amount of reward earned by the account. function earned(address account) external view returns (uint256); /// @notice Retrieves the total reward vested over the specified duration. /// @return The total reward vested over the duration. function getRewardForDuration() external view returns (uint256); /// @notice Returns the timestamp of the last reward distribution. This is either the current timestamp (if rewards /// are still being actively distributed) or the timestamp when the reward duration ended (if all rewards have /// already been distributed). /// @return The timestamp of the last reward distribution. function lastTimeRewardApplicable() external view returns (uint256); /// @notice Retrieves the current value of the global reward per token accumulator. This value is the sum of the /// last checkpoint value and the accumulated value since the last checkpoint. It should increase monotonically /// over time as more rewards are distributed. /// @return The current value of the global reward per token accumulator scaled by 1e18. function rewardPerToken() external view returns (uint256); /// @notice Get the total supply of the staked tokens in the vault. /// @return The total supply of the staked tokens in the vault. function totalSupply() external view returns (uint256); /// @notice Get the end of the current reward period. /// @return The end of the current reward period. function periodFinish() external view returns (uint256); /// @notice Get the reward rate for the current reward period. /// @return The reward rate. function rewardRate() external view returns (uint256); /// @notice Get the time over which the rewards will be distributed. /// @return The duration of the rewards cycle. function rewardsDuration() external view returns (uint256); /// @notice Get the last time the rewards were updated. /// @return The last time the rewards were updated. function lastUpdateTime() external view returns (uint256); /// @notice Get the amount of undistributed rewards. /// @return The amount of undistributed rewards. function undistributedRewards() external view returns (uint256); /// @notice Get the last updated reward per token scaled. /// @return The last updated reward per token. function rewardPerTokenStored() external view returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; import {ERC20} from "@openzeppelin-yearn/contracts/token/ERC20/ERC20.sol"; import {IERC4626} from "@openzeppelin-yearn/contracts/interfaces/IERC4626.sol"; import {IERC20Permit} from "@openzeppelin-yearn/contracts/token/ERC20/extensions/IERC20Permit.sol"; // Interface that implements the 4626 standard and the implementation functions interface ITokenizedStrategy is IERC4626, IERC20Permit { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event StrategyShutdown(); event NewTokenizedStrategy( address indexed strategy, address indexed asset, string apiVersion ); event Reported( uint256 profit, uint256 loss, uint256 protocolFees, uint256 performanceFees ); event UpdatePerformanceFeeRecipient( address indexed newPerformanceFeeRecipient ); event UpdateKeeper(address indexed newKeeper); event UpdatePerformanceFee(uint16 newPerformanceFee); event UpdateManagement(address indexed newManagement); event UpdateEmergencyAdmin(address indexed newEmergencyAdmin); event UpdateProfitMaxUnlockTime(uint256 newProfitMaxUnlockTime); event UpdatePendingManagement(address indexed newPendingManagement); /*////////////////////////////////////////////////////////////// INITIALIZATION //////////////////////////////////////////////////////////////*/ function initialize( address _asset, string memory _name, address _management, address _performanceFeeRecipient, address _keeper ) external; /*////////////////////////////////////////////////////////////// NON-STANDARD 4626 OPTIONS //////////////////////////////////////////////////////////////*/ function withdraw( uint256 assets, address receiver, address owner, uint256 maxLoss ) external returns (uint256); function redeem( uint256 shares, address receiver, address owner, uint256 maxLoss ) external returns (uint256); function maxWithdraw( address owner, uint256 /*maxLoss*/ ) external view returns (uint256); function maxRedeem( address owner, uint256 /*maxLoss*/ ) external view returns (uint256); /*////////////////////////////////////////////////////////////// MODIFIER HELPERS //////////////////////////////////////////////////////////////*/ function requireManagement(address _sender) external view; function requireKeeperOrManagement(address _sender) external view; function requireEmergencyAuthorized(address _sender) external view; /*////////////////////////////////////////////////////////////// KEEPERS FUNCTIONS //////////////////////////////////////////////////////////////*/ function tend() external; function report() external returns (uint256 _profit, uint256 _loss); /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ function MAX_FEE() external view returns (uint16); function FACTORY() external view returns (address); /*////////////////////////////////////////////////////////////// GETTERS //////////////////////////////////////////////////////////////*/ function apiVersion() external view returns (string memory); function pricePerShare() external view returns (uint256); function management() external view returns (address); function pendingManagement() external view returns (address); function keeper() external view returns (address); function emergencyAdmin() external view returns (address); function performanceFee() external view returns (uint16); function performanceFeeRecipient() external view returns (address); function fullProfitUnlockDate() external view returns (uint256); function profitUnlockingRate() external view returns (uint256); function profitMaxUnlockTime() external view returns (uint256); function lastReport() external view returns (uint256); function isShutdown() external view returns (bool); function unlockedShares() external view returns (uint256); /*////////////////////////////////////////////////////////////// SETTERS //////////////////////////////////////////////////////////////*/ function setPendingManagement(address) external; function acceptManagement() external; function setKeeper(address _keeper) external; function setEmergencyAdmin(address _emergencyAdmin) external; function setPerformanceFee(uint16 _performanceFee) external; function setPerformanceFeeRecipient( address _performanceFeeRecipient ) external; function setProfitMaxUnlockTime(uint256 _profitMaxUnlockTime) external; function setName(string calldata _newName) external; function shutdownStrategy() external; function emergencyWithdraw(uint256 _amount) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; interface IBaseStrategy { function tokenizedStrategyAddress() external view returns (address); /*////////////////////////////////////////////////////////////// IMMUTABLE FUNCTIONS //////////////////////////////////////////////////////////////*/ function availableDepositLimit( address _owner ) external view returns (uint256); function availableWithdrawLimit( address _owner ) external view returns (uint256); function deployFunds(uint256 _assets) external; function freeFunds(uint256 _amount) external; function harvestAndReport() external returns (uint256); function tendThis(uint256 _totalIdle) external; function shutdownWithdraw(uint256 _amount) external; function tendTrigger() external view returns (bool, bytes memory); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; import {ERC20} from "@openzeppelin-yearn/contracts/token/ERC20/ERC20.sol"; // TokenizedStrategy interface used for internal view delegateCalls. import {ITokenizedStrategy} from "./interfaces/ITokenizedStrategy.sol"; /** * @title YearnV3 Base Strategy * @author yearn.finance * @notice * BaseStrategy implements all of the required functionality to * seamlessly integrate with the `TokenizedStrategy` implementation contract * allowing anyone to easily build a fully permissionless ERC-4626 compliant * Vault by inheriting this contract and overriding three simple functions. * It utilizes an immutable proxy pattern that allows the BaseStrategy * to remain simple and small. All standard logic is held within the * `TokenizedStrategy` and is reused over any n strategies all using the * `fallback` function to delegatecall the implementation so that strategists * can only be concerned with writing their strategy specific code. * * This contract should be inherited and the three main abstract methods * `_deployFunds`, `_freeFunds` and `_harvestAndReport` implemented to adapt * the Strategy to the particular needs it has to generate yield. There are * other optional methods that can be implemented to further customize * the strategy if desired. * * All default storage for the strategy is controlled and updated by the * `TokenizedStrategy`. The implementation holds a storage struct that * contains all needed global variables in a manual storage slot. This * means strategists can feel free to implement their own custom storage * variables as they need with no concern of collisions. All global variables * can be viewed within the Strategy by a simple call using the * `TokenizedStrategy` variable. IE: TokenizedStrategy.globalVariable();. */ abstract contract BaseStrategy { /*////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////*/ /** * @dev Used on TokenizedStrategy callback functions to make sure it is post * a delegateCall from this address to the TokenizedStrategy. */ modifier onlySelf() { _onlySelf(); _; } /** * @dev Use to assure that the call is coming from the strategies management. */ modifier onlyManagement() { TokenizedStrategy.requireManagement(msg.sender); _; } /** * @dev Use to assure that the call is coming from either the strategies * management or the keeper. */ modifier onlyKeepers() { TokenizedStrategy.requireKeeperOrManagement(msg.sender); _; } /** * @dev Use to assure that the call is coming from either the strategies * management or the emergency admin. */ modifier onlyEmergencyAuthorized() { TokenizedStrategy.requireEmergencyAuthorized(msg.sender); _; } /** * @dev Require that the msg.sender is this address. */ function _onlySelf() internal view { require(msg.sender == address(this), "!self"); } /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ /** * @dev This is the address of the TokenizedStrategy implementation * contract that will be used by all strategies to handle the * accounting, logic, storage etc. * * Any external calls to the that don't hit one of the functions * defined in this base or the strategy will end up being forwarded * through the fallback function, which will delegateCall this address. * * This address should be the same for every strategy, never be adjusted * and always be checked before any integration with the Strategy. */ address public constant tokenizedStrategyAddress = 0xD377919FA87120584B21279a491F82D5265A139c; /*////////////////////////////////////////////////////////////// IMMUTABLES //////////////////////////////////////////////////////////////*/ /** * @dev Underlying asset the Strategy is earning yield on. * Stored here for cheap retrievals within the strategy. */ ERC20 internal immutable asset; /** * @dev This variable is set to address(this) during initialization of each strategy. * * This can be used to retrieve storage data within the strategy * contract as if it were a linked library. * * i.e. uint256 totalAssets = TokenizedStrategy.totalAssets() * * Using address(this) will mean any calls using this variable will lead * to a call to itself. Which will hit the fallback function and * delegateCall that to the actual TokenizedStrategy. */ ITokenizedStrategy internal immutable TokenizedStrategy; /** * @notice Used to initialize the strategy on deployment. * * This will set the `TokenizedStrategy` variable for easy * internal view calls to the implementation. As well as * initializing the default storage variables based on the * parameters and using the deployer for the permissioned roles. * * @param _asset Address of the underlying asset. * @param _name Name the strategy will use. */ constructor(address _asset, string memory _name) { asset = ERC20(_asset); // Set instance of the implementation for internal use. TokenizedStrategy = ITokenizedStrategy(address(this)); // Initialize the strategy's storage variables. _delegateCall( abi.encodeCall( ITokenizedStrategy.initialize, (_asset, _name, msg.sender, msg.sender, msg.sender) ) ); // Store the tokenizedStrategyAddress at the standard implementation // address storage slot so etherscan picks up the interface. This gets // stored on initialization and never updated. assembly { sstore( // keccak256('eip1967.proxy.implementation' - 1) 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc, tokenizedStrategyAddress ) } } /*////////////////////////////////////////////////////////////// NEEDED TO BE OVERRIDDEN BY STRATEGIST //////////////////////////////////////////////////////////////*/ /** * @dev Can deploy up to '_amount' of 'asset' in the yield source. * * This function is called at the end of a {deposit} or {mint} * call. Meaning that unless a whitelist is implemented it will * be entirely permissionless and thus can be sandwiched or otherwise * manipulated. * * @param _amount The amount of 'asset' that the strategy can attempt * to deposit in the yield source. */ function _deployFunds(uint256 _amount) internal virtual; /** * @dev Should attempt to free the '_amount' of 'asset'. * * NOTE: The amount of 'asset' that is already loose has already * been accounted for. * * This function is called during {withdraw} and {redeem} calls. * Meaning that unless a whitelist is implemented it will be * entirely permissionless and thus can be sandwiched or otherwise * manipulated. * * Should not rely on asset.balanceOf(address(this)) calls other than * for diff accounting purposes. * * Any difference between `_amount` and what is actually freed will be * counted as a loss and passed on to the withdrawer. This means * care should be taken in times of illiquidity. It may be better to revert * if withdraws are simply illiquid so not to realize incorrect losses. * * @param _amount, The amount of 'asset' to be freed. */ function _freeFunds(uint256 _amount) internal virtual; /** * @dev Internal function to harvest all rewards, redeploy any idle * funds and return an accurate accounting of all funds currently * held by the Strategy. * * This should do any needed harvesting, rewards selling, accrual, * redepositing etc. to get the most accurate view of current assets. * * NOTE: All applicable assets including loose assets should be * accounted for in this function. * * Care should be taken when relying on oracles or swap values rather * than actual amounts as all Strategy profit/loss accounting will * be done based on this returned value. * * This can still be called post a shutdown, a strategist can check * `TokenizedStrategy.isShutdown()` to decide if funds should be * redeployed or simply realize any profits/losses. * * @return _totalAssets A trusted and accurate account for the total * amount of 'asset' the strategy currently holds including idle funds. */ function _harvestAndReport() internal virtual returns (uint256 _totalAssets); /*////////////////////////////////////////////////////////////// OPTIONAL TO OVERRIDE BY STRATEGIST //////////////////////////////////////////////////////////////*/ /** * @dev Optional function for strategist to override that can * be called in between reports. * * If '_tend' is used tendTrigger() will also need to be overridden. * * This call can only be called by a permissioned role so may be * through protected relays. * * This can be used to harvest and compound rewards, deposit idle funds, * perform needed position maintenance or anything else that doesn't need * a full report for. * * EX: A strategy that can not deposit funds without getting * sandwiched can use the tend when a certain threshold * of idle to totalAssets has been reached. * * This will have no effect on PPS of the strategy till report() is called. * * @param _totalIdle The current amount of idle funds that are available to deploy. */ function _tend(uint256 _totalIdle) internal virtual {} /** * @dev Optional trigger to override if tend() will be used by the strategy. * This must be implemented if the strategy hopes to invoke _tend(). * * @return . Should return true if tend() should be called by keeper or false if not. */ function _tendTrigger() internal view virtual returns (bool) { return false; } /** * @notice Returns if tend() should be called by a keeper. * * @return . Should return true if tend() should be called by keeper or false if not. * @return . Calldata for the tend call. */ function tendTrigger() external view virtual returns (bool, bytes memory) { return ( // Return the status of the tend trigger. _tendTrigger(), // And the needed calldata either way. abi.encodeWithSelector(ITokenizedStrategy.tend.selector) ); } /** * @notice Gets the max amount of `asset` that an address can deposit. * @dev Defaults to an unlimited amount for any address. But can * be overridden by strategists. * * This function will be called before any deposit or mints to enforce * any limits desired by the strategist. This can be used for either a * traditional deposit limit or for implementing a whitelist etc. * * EX: * if(isAllowed[_owner]) return super.availableDepositLimit(_owner); * * This does not need to take into account any conversion rates * from shares to assets. But should know that any non max uint256 * amounts may be converted to shares. So it is recommended to keep * custom amounts low enough as not to cause overflow when multiplied * by `totalSupply`. * * @param . The address that is depositing into the strategy. * @return . The available amount the `_owner` can deposit in terms of `asset` */ function availableDepositLimit( address /*_owner*/ ) public view virtual returns (uint256) { return type(uint256).max; } /** * @notice Gets the max amount of `asset` that can be withdrawn. * @dev Defaults to an unlimited amount for any address. But can * be overridden by strategists. * * This function will be called before any withdraw or redeem to enforce * any limits desired by the strategist. This can be used for illiquid * or sandwichable strategies. It should never be lower than `totalIdle`. * * EX: * return TokenIzedStrategy.totalIdle(); * * This does not need to take into account the `_owner`'s share balance * or conversion rates from shares to assets. * * @param . The address that is withdrawing from the strategy. * @return . The available amount that can be withdrawn in terms of `asset` */ function availableWithdrawLimit( address /*_owner*/ ) public view virtual returns (uint256) { return type(uint256).max; } /** * @dev Optional function for a strategist to override that will * allow management to manually withdraw deployed funds from the * yield source if a strategy is shutdown. * * This should attempt to free `_amount`, noting that `_amount` may * be more than is currently deployed. * * NOTE: This will not realize any profits or losses. A separate * {report} will be needed in order to record any profit/loss. If * a report may need to be called after a shutdown it is important * to check if the strategy is shutdown during {_harvestAndReport} * so that it does not simply re-deploy all funds that had been freed. * * EX: * if(freeAsset > 0 && !TokenizedStrategy.isShutdown()) { * depositFunds... * } * * @param _amount The amount of asset to attempt to free. */ function _emergencyWithdraw(uint256 _amount) internal virtual {} /*////////////////////////////////////////////////////////////// TokenizedStrategy HOOKS //////////////////////////////////////////////////////////////*/ /** * @notice Can deploy up to '_amount' of 'asset' in yield source. * @dev Callback for the TokenizedStrategy to call during a {deposit} * or {mint} to tell the strategy it can deploy funds. * * Since this can only be called after a {deposit} or {mint} * delegateCall to the TokenizedStrategy msg.sender == address(this). * * Unless a whitelist is implemented this will be entirely permissionless * and thus can be sandwiched or otherwise manipulated. * * @param _amount The amount of 'asset' that the strategy can * attempt to deposit in the yield source. */ function deployFunds(uint256 _amount) external virtual onlySelf { _deployFunds(_amount); } /** * @notice Should attempt to free the '_amount' of 'asset'. * @dev Callback for the TokenizedStrategy to call during a withdraw * or redeem to free the needed funds to service the withdraw. * * This can only be called after a 'withdraw' or 'redeem' delegateCall * to the TokenizedStrategy so msg.sender == address(this). * * @param _amount The amount of 'asset' that the strategy should attempt to free up. */ function freeFunds(uint256 _amount) external virtual onlySelf { _freeFunds(_amount); } /** * @notice Returns the accurate amount of all funds currently * held by the Strategy. * @dev Callback for the TokenizedStrategy to call during a report to * get an accurate accounting of assets the strategy controls. * * This can only be called after a report() delegateCall to the * TokenizedStrategy so msg.sender == address(this). * * @return . A trusted and accurate account for the total amount * of 'asset' the strategy currently holds including idle funds. */ function harvestAndReport() external virtual onlySelf returns (uint256) { return _harvestAndReport(); } /** * @notice Will call the internal '_tend' when a keeper tends the strategy. * @dev Callback for the TokenizedStrategy to initiate a _tend call in the strategy. * * This can only be called after a tend() delegateCall to the TokenizedStrategy * so msg.sender == address(this). * * We name the function `tendThis` so that `tend` calls are forwarded to * the TokenizedStrategy. * @param _totalIdle The amount of current idle funds that can be * deployed during the tend */ function tendThis(uint256 _totalIdle) external virtual onlySelf { _tend(_totalIdle); } /** * @notice Will call the internal '_emergencyWithdraw' function. * @dev Callback for the TokenizedStrategy during an emergency withdraw. * * This can only be called after a emergencyWithdraw() delegateCall to * the TokenizedStrategy so msg.sender == address(this). * * We name the function `shutdownWithdraw` so that `emergencyWithdraw` * calls are forwarded to the TokenizedStrategy. * * @param _amount The amount of asset to attempt to free. */ function shutdownWithdraw(uint256 _amount) external virtual onlySelf { _emergencyWithdraw(_amount); } /** * @dev Function used to delegate call the TokenizedStrategy with * certain `_calldata` and return any return values. * * This is used to setup the initial storage of the strategy, and * can be used by strategist to forward any other call to the * TokenizedStrategy implementation. * * @param _calldata The abi encoded calldata to use in delegatecall. * @return . The return value if the call was successful in bytes. */ function _delegateCall( bytes memory _calldata ) internal returns (bytes memory) { // Delegate call the tokenized strategy with provided calldata. (bool success, bytes memory result) = tokenizedStrategyAddress .delegatecall(_calldata); // If the call reverted. Return the error. if (!success) { assembly { let ptr := mload(0x40) let size := returndatasize() returndatacopy(ptr, 0, size) revert(ptr, size) } } // Return the result. return result; } /** * @dev Execute a function on the TokenizedStrategy and return any value. * * This fallback function will be executed when any of the standard functions * defined in the TokenizedStrategy are called since they wont be defined in * this contract. * * It will delegatecall the TokenizedStrategy implementation with the exact * calldata and return any relevant values. * */ fallback() external { // load our target address address _tokenizedStrategyAddress = tokenizedStrategyAddress; // Execute external function using delegatecall and return any value. assembly { // Copy function selector and any arguments. calldatacopy(0, 0, calldatasize()) // Execute function delegatecall. let result := delegatecall( gas(), _tokenizedStrategyAddress, 0, calldatasize(), 0, 0 ) // Get any return value returndatacopy(0, 0, returndatasize()) // Return any return value or error back to the caller switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ 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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; /** * @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; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.28; /// @notice Interface of staking rewards errors interface IStakingRewardsErrors { // Signature: 0xf4ba521f error InsolventReward(); // Signature: 0xf1bc94d2 error InsufficientStake(); // Signature: 0x49835af0 error RewardCycleNotEnded(); // Signature: 0x5ce91fd0 error StakeAmountIsZero(); // Signature: 0xe5cfe957 error TotalSupplyOverflow(); // Signature: 0xa393d14b error WithdrawAmountIsZero(); // Signature: 0x359f174d error RewardsDurationIsZero(); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol"; import "../token/ERC20/extensions/IERC20Metadata.sol"; /** * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. * * _Available since v4.7._ */ 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); }
{ "remappings": [ "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin-bera/contracts/=lib/berachain-contracts/node_modules/@openzeppelin/contracts/", "@openzeppelin-bera/contracts-upgradeable/=lib/berachain-contracts/node_modules/@openzeppelin/contracts-upgradeable/", "@openzeppelin-yearn/contracts/=lib/yearn-tokenized-strategy-periphery/lib/openzeppelin-contracts/contracts/", "@openzeppelin-bearn-governance/contracts/=lib/bearn-governance/lib/openzeppelin-contracts/contracts/", "forge-std/=lib/forge-std/src/", "@yearn/tokenized-strategy-periphery/=lib/yearn-tokenized-strategy-periphery/src/", "@yearn/tokenized-strategy/=lib/yearn-tokenized-strategy-periphery/lib/tokenized-strategy/src/", "@tokenized-strategy-periphery/=lib/yearn-tokenized-strategy-periphery/src/", "@berachain/contracts/=lib/berachain-contracts/src/", "@berachain/test/=lib/berachain-contracts/test/", "solady/=lib/berachain-contracts/lib/solady/", "@bearn/governance/contracts/=lib/bearn-governance/src/", "@mock/=lib/berachain-contracts/test/mock/", "@openzeppelin-gov-ext/=lib/berachain-contracts/node_modules/@openzeppelin/contracts-upgradeable/governance/extensions/", "@openzeppelin-gov/=lib/berachain-contracts/node_modules/@openzeppelin/contracts-upgradeable/governance/", "@prb/=lib/berachain-contracts/node_modules/@prb/math/src/", "@pythnetwork/=lib/berachain-contracts/node_modules/", "@tokenized-strategy/=lib/yearn-tokenized-strategy-periphery/lib/tokenized-strategy/src/", "@yearn-vaults/=lib/yearn-tokenized-strategy-periphery/lib/yearn-vaults-v3/contracts/", "bearn-governance/=lib/bearn-governance/", "berachain-contracts/=lib/berachain-contracts/", "ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin-foundry-upgrades/=lib/berachain-contracts/lib/openzeppelin-foundry-upgrades/src/", "solidity-stringutils/=lib/berachain-contracts/lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/", "tokenized-strategy-periphery/=lib/bearn-governance/lib/tokenized-strategy-periphery/", "tokenized-strategy/=lib/yearn-tokenized-strategy-periphery/lib/tokenized-strategy/", "transient-goodies/=lib/berachain-contracts/lib/transient-goodies/src/", "yearn-tokenized-strategy-periphery/=lib/yearn-tokenized-strategy-periphery/", "yearn-vaults-v3/=lib/yearn-tokenized-strategy-periphery/lib/yearn-vaults-v3/" ], "optimizer": { "enabled": true, "runs": 1 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": false, "libraries": { "src/libraries/BearnBGTEarnerVaultDeployer.sol": { "BearnBGTEarnerVaultDeployer": "0x0218BaD428a684f9dc70A16975375326161448AB" }, "src/libraries/BearnCompoundingVaultDeployer.sol": { "BearnCompoundingVaultDeployer": "0x82F3CC84D719AF95eF41ce8ce562D23E3AA50112" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_authorizer","type":"address"},{"internalType":"address","name":"_styBGTCompounder","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tipper","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Tipped","type":"event"},{"inputs":[],"name":"AUTHORIZER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"bearnVault","type":"address"},{"internalType":"address","name":"staking","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"tips","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTreasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"zapIntoStyBGTCompounder","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"zapOutFromStyBGTCompounder","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
610100604052348015610010575f5ffd5b50604051610d3a380380610d3a83398101604081905261002f9161014c565b6001600160a01b038083166080525f80546001600160a01b03191633179055811660e081905260408051630d87f78160e21b8152905163361fde04916004808201926020929091908290030181865afa15801561008e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100b2919061017d565b6001600160a01b031660c0819052604080516348e7cde960e01b815290516348e7cde9916004808201926020929091908290030181865afa1580156100f9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061011d919061017d565b6001600160a01b031660a0525061019d9050565b80516001600160a01b0381168114610147575f5ffd5b919050565b5f5f6040838503121561015d575f5ffd5b61016683610131565b915061017460208401610131565b90509250929050565b5f6020828403121561018d575f5ffd5b61019682610131565b9392505050565b60805160a05160c05160e051610b396102015f395f818161012d015281816105d1015261060f01525f81816101c0015281816104eb0152818161052901526105af01525f818161049401526104c901525f818161010701526107940152610b395ff3fe608060405234801561000f575f5ffd5b506004361061006b575f3560e01c80631844fdfa1461006f57806320e8c5651461009557806361d027b3146100aa5780637a4e4ecf146100c95780638533128a146100dc578063f0f44260146100ef578063fe70235814610102575b5f5ffd5b61008261007d366004610921565b610129565b6040519081526020015b60405180910390f35b6100a86100a3366004610953565b610256565b005b5f546100bc906001600160a01b031681565b60405161008c9190610992565b6100a86100d73660046109a6565b610450565b6100826100ea366004610921565b610486565b6100a86100fd3660046109ce565b610646565b6100bc7f000000000000000000000000000000000000000000000000000000000000000081565b5f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ba0876528430336040518463ffffffff1660e01b815260040161017b939291906109ee565b6020604051808303815f875af1158015610197573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101bb9190610a0d565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ba0876528333306040518463ffffffff1660e01b815260040161020e939291906109ee565b6020604051808303815f875af115801561022a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061024e9190610a0d565b949350505050565b61026b6001600160a01b038416333085610680565b61027f6001600160a01b03841685846106ed565b604051636e553f6560e01b81525f906001600160a01b03861690636e553f65906102af9086903090600401610a24565b6020604051808303815f875af11580156102cb573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102ef9190610a0d565b905081156103da575f610303836064610a4f565b61030d8484610a62565b6103179190610a79565b90506103238183610a98565b5f5460405163a9059cbb60e01b81529193506001600160a01b038089169263a9059cbb926103579216908590600401610aab565b6020604051808303815f875af1158015610373573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103979190610ac4565b506040518181526001600160a01b0386169033907f91d9aec1bf873fb589194ec67c304522c89e9e1de41ed647cf135fb41226befc9060200160405180910390a3505b60405163a9059cbb60e01b81526001600160a01b0386169063a9059cbb906104089033908590600401610aab565b6020604051808303815f875af1158015610424573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104489190610ac4565b505050505050565b5f516020610ae45f395f51905f52610468813361077d565b5f54610481906001600160a01b0385811691168461084d565b505050565b5f6104bc6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333085610680565b6105106001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000846106ed565b604051636e553f6560e01b81525f906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636e553f65906105609086903090600401610a24565b6020604051808303815f875af115801561057c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105a09190610a0d565b90506105f66001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000836106ed565b604051636e553f6560e01b81525f906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636e553f659061020e9085903390600401610a24565b5f516020610ae45f395f51905f5261065e813361077d565b505f80546001600160a01b0319166001600160a01b0392909216919091179055565b6040516001600160a01b0384811660248301528381166044830152606482018390526106e79186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050610873565b50505050565b5f836001600160a01b031663095ea7b38484604051602401610710929190610aab565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050905061074984826108d6565b6106e75761077384856001600160a01b031663095ea7b3865f6040516024016106b5929190610aab565b6106e78482610873565b60405163956db46560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063956db465906107cb9085908590600401610a24565b602060405180830381865afa1580156107e6573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061080a9190610ac4565b6108495760405162461bcd60e51b815260206004820152600b60248201526a08585d5d1a1bdc9a5e995960aa1b60448201526064015b60405180910390fd5b5050565b61048183846001600160a01b031663a9059cbb85856040516024016106b5929190610aab565b5f5f60205f8451602086015f885af180610892576040513d5f823e3d81fd5b50505f513d915081156108a95780600114156108b6565b6001600160a01b0384163b155b156106e75783604051635274afe760e01b81526004016108409190610992565b5f5f5f5f60205f8651602088015f8a5af192503d91505f519050828015610915575081156109075780600114610915565b5f866001600160a01b03163b115b93505050505b92915050565b5f60208284031215610931575f5ffd5b5035919050565b80356001600160a01b038116811461094e575f5ffd5b919050565b5f5f5f5f60808587031215610966575f5ffd5b61096f85610938565b935061097d60208601610938565b93969395505050506040820135916060013590565b6001600160a01b0391909116815260200190565b5f5f604083850312156109b7575f5ffd5b6109c083610938565b946020939093013593505050565b5f602082840312156109de575f5ffd5b6109e782610938565b9392505050565b9283526001600160a01b03918216602084015216604082015260600190565b5f60208284031215610a1d575f5ffd5b5051919050565b9182526001600160a01b0316602082015260400190565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561091b5761091b610a3b565b808202811582820484141761091b5761091b610a3b565b5f82610a9357634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111561091b5761091b610a3b565b6001600160a01b03929092168252602082015260400190565b5f60208284031215610ad4575f5ffd5b815180151581146109e7575f5ffdfe241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b08a26469706673582212201c15303f77021b506ee1c58a3e7fbdbbde65b1879a86904ae1037d925645712c64736f6c634300081c0033000000000000000000000000261cf8ccbf5023ae7d5219a136c31e8a86220fd30000000000000000000000006fd7f15a0d7babe0a1a752564a591e1cb6117f80
Deployed Bytecode
0x608060405234801561000f575f5ffd5b506004361061006b575f3560e01c80631844fdfa1461006f57806320e8c5651461009557806361d027b3146100aa5780637a4e4ecf146100c95780638533128a146100dc578063f0f44260146100ef578063fe70235814610102575b5f5ffd5b61008261007d366004610921565b610129565b6040519081526020015b60405180910390f35b6100a86100a3366004610953565b610256565b005b5f546100bc906001600160a01b031681565b60405161008c9190610992565b6100a86100d73660046109a6565b610450565b6100826100ea366004610921565b610486565b6100a86100fd3660046109ce565b610646565b6100bc7f000000000000000000000000261cf8ccbf5023ae7d5219a136c31e8a86220fd381565b5f5f7f0000000000000000000000006fd7f15a0d7babe0a1a752564a591e1cb6117f806001600160a01b031663ba0876528430336040518463ffffffff1660e01b815260040161017b939291906109ee565b6020604051808303815f875af1158015610197573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101bb9190610a0d565b90505f7f0000000000000000000000006f8ceaf347da79287e49a5c9f0a03b20bdfcb7d36001600160a01b031663ba0876528333306040518463ffffffff1660e01b815260040161020e939291906109ee565b6020604051808303815f875af115801561022a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061024e9190610a0d565b949350505050565b61026b6001600160a01b038416333085610680565b61027f6001600160a01b03841685846106ed565b604051636e553f6560e01b81525f906001600160a01b03861690636e553f65906102af9086903090600401610a24565b6020604051808303815f875af11580156102cb573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102ef9190610a0d565b905081156103da575f610303836064610a4f565b61030d8484610a62565b6103179190610a79565b90506103238183610a98565b5f5460405163a9059cbb60e01b81529193506001600160a01b038089169263a9059cbb926103579216908590600401610aab565b6020604051808303815f875af1158015610373573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103979190610ac4565b506040518181526001600160a01b0386169033907f91d9aec1bf873fb589194ec67c304522c89e9e1de41ed647cf135fb41226befc9060200160405180910390a3505b60405163a9059cbb60e01b81526001600160a01b0386169063a9059cbb906104089033908590600401610aab565b6020604051808303815f875af1158015610424573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104489190610ac4565b505050505050565b5f516020610ae45f395f51905f52610468813361077d565b5f54610481906001600160a01b0385811691168461084d565b505050565b5f6104bc6001600160a01b037f0000000000000000000000007e768f47dfdd5dae874aac233f1bc5817137e45316333085610680565b6105106001600160a01b037f0000000000000000000000007e768f47dfdd5dae874aac233f1bc5817137e453167f0000000000000000000000006f8ceaf347da79287e49a5c9f0a03b20bdfcb7d3846106ed565b604051636e553f6560e01b81525f906001600160a01b037f0000000000000000000000006f8ceaf347da79287e49a5c9f0a03b20bdfcb7d31690636e553f65906105609086903090600401610a24565b6020604051808303815f875af115801561057c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105a09190610a0d565b90506105f66001600160a01b037f0000000000000000000000006f8ceaf347da79287e49a5c9f0a03b20bdfcb7d3167f0000000000000000000000006fd7f15a0d7babe0a1a752564a591e1cb6117f80836106ed565b604051636e553f6560e01b81525f906001600160a01b037f0000000000000000000000006fd7f15a0d7babe0a1a752564a591e1cb6117f801690636e553f659061020e9085903390600401610a24565b5f516020610ae45f395f51905f5261065e813361077d565b505f80546001600160a01b0319166001600160a01b0392909216919091179055565b6040516001600160a01b0384811660248301528381166044830152606482018390526106e79186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050610873565b50505050565b5f836001600160a01b031663095ea7b38484604051602401610710929190610aab565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050905061074984826108d6565b6106e75761077384856001600160a01b031663095ea7b3865f6040516024016106b5929190610aab565b6106e78482610873565b60405163956db46560e01b81526001600160a01b037f000000000000000000000000261cf8ccbf5023ae7d5219a136c31e8a86220fd3169063956db465906107cb9085908590600401610a24565b602060405180830381865afa1580156107e6573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061080a9190610ac4565b6108495760405162461bcd60e51b815260206004820152600b60248201526a08585d5d1a1bdc9a5e995960aa1b60448201526064015b60405180910390fd5b5050565b61048183846001600160a01b031663a9059cbb85856040516024016106b5929190610aab565b5f5f60205f8451602086015f885af180610892576040513d5f823e3d81fd5b50505f513d915081156108a95780600114156108b6565b6001600160a01b0384163b155b156106e75783604051635274afe760e01b81526004016108409190610992565b5f5f5f5f60205f8651602088015f8a5af192503d91505f519050828015610915575081156109075780600114610915565b5f866001600160a01b03163b115b93505050505b92915050565b5f60208284031215610931575f5ffd5b5035919050565b80356001600160a01b038116811461094e575f5ffd5b919050565b5f5f5f5f60808587031215610966575f5ffd5b61096f85610938565b935061097d60208601610938565b93969395505050506040820135916060013590565b6001600160a01b0391909116815260200190565b5f5f604083850312156109b7575f5ffd5b6109c083610938565b946020939093013593505050565b5f602082840312156109de575f5ffd5b6109e782610938565b9392505050565b9283526001600160a01b03918216602084015216604082015260600190565b5f60208284031215610a1d575f5ffd5b5051919050565b9182526001600160a01b0316602082015260400190565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561091b5761091b610a3b565b808202811582820484141761091b5761091b610a3b565b5f82610a9357634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111561091b5761091b610a3b565b6001600160a01b03929092168252602082015260400190565b5f60208284031215610ad4575f5ffd5b815180151581146109e7575f5ffdfe241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b08a26469706673582212201c15303f77021b506ee1c58a3e7fbdbbde65b1879a86904ae1037d925645712c64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000261cf8ccbf5023ae7d5219a136c31e8a86220fd30000000000000000000000006fd7f15a0d7babe0a1a752564a591e1cb6117f80
-----Decoded View---------------
Arg [0] : _authorizer (address): 0x261cF8ccBf5023aE7D5219A136c31e8a86220FD3
Arg [1] : _styBGTCompounder (address): 0x6Fd7f15a0d7babe0A1a752564a591e1Cb6117F80
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000261cf8ccbf5023ae7d5219a136c31e8a86220fd3
Arg [1] : 0000000000000000000000006fd7f15a0d7babe0a1a752564a591e1cb6117f80
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.