Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
Latest 25 from a total of 3,296 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Redeem | 21113664 | 16 hrs ago | IN | 0 ETH | 0.00036991 | ||||
Redeem | 21112251 | 21 hrs ago | IN | 0 ETH | 0.00039826 | ||||
Redeem | 21111686 | 23 hrs ago | IN | 0 ETH | 0.00040893 | ||||
Deposit | 21111477 | 23 hrs ago | IN | 0 ETH | 0.0004074 | ||||
Deposit | 21111310 | 24 hrs ago | IN | 0 ETH | 0.00031382 | ||||
Approve | 21110278 | 27 hrs ago | IN | 0 ETH | 0.00019906 | ||||
Approve | 21108641 | 33 hrs ago | IN | 0 ETH | 0.00011814 | ||||
Approve | 21108640 | 33 hrs ago | IN | 0 ETH | 0.00012557 | ||||
Approve | 21103819 | 2 days ago | IN | 0 ETH | 0.00015983 | ||||
Deposit | 21100000 | 2 days ago | IN | 0 ETH | 0.00041367 | ||||
Redeem | 21097442 | 2 days ago | IN | 0 ETH | 0.00035253 | ||||
Redeem | 21096266 | 3 days ago | IN | 0 ETH | 0.00039141 | ||||
Redeem | 21096112 | 3 days ago | IN | 0 ETH | 0.00047556 | ||||
Approve | 21094344 | 3 days ago | IN | 0 ETH | 0.00051286 | ||||
Redeem | 21093458 | 3 days ago | IN | 0 ETH | 0.00196894 | ||||
Approve | 21085788 | 4 days ago | IN | 0 ETH | 0.00045831 | ||||
Approve | 21084950 | 4 days ago | IN | 0 ETH | 0.00033281 | ||||
Redeem | 21083615 | 4 days ago | IN | 0 ETH | 0.0007312 | ||||
Deposit | 21081061 | 5 days ago | IN | 0 ETH | 0.00097017 | ||||
Approve | 21080755 | 5 days ago | IN | 0 ETH | 0.0005061 | ||||
Deposit | 21080730 | 5 days ago | IN | 0 ETH | 0.00120297 | ||||
Deposit | 21074337 | 6 days ago | IN | 0 ETH | 0.00080271 | ||||
Approve | 21073570 | 6 days ago | IN | 0 ETH | 0.00070746 | ||||
Approve | 21071124 | 6 days ago | IN | 0 ETH | 0.00035003 | ||||
Redeem | 21068752 | 6 days ago | IN | 0 ETH | 0.00084588 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
18378085 | 383 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
StakedFrax
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 99999999 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.21; // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ============================ StakedFrax ============================ // ==================================================================== // Frax Finance: https://github.com/FraxFinance import { Timelock2Step } from "frax-std/access-control/v2/Timelock2Step.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { SafeCastLib } from "solmate/utils/SafeCastLib.sol"; import { LinearRewardsErc4626, ERC20 } from "./LinearRewardsErc4626.sol"; /// @title Staked Frax /// @notice A ERC4626 Vault implementation with linear rewards, rewards can be capped contract StakedFrax is LinearRewardsErc4626, Timelock2Step { using SafeCastLib for *; /// @notice The maximum amount of rewards that can be distributed per second per 1e18 asset uint256 public maxDistributionPerSecondPerAsset; /// @param _underlying The erc20 asset deposited /// @param _name The name of the vault /// @param _symbol The symbol of the vault /// @param _rewardsCycleLength The length of the rewards cycle in seconds /// @param _maxDistributionPerSecondPerAsset The maximum amount of rewards that can be distributed per second per 1e18 asset /// @param _timelockAddress The address of the timelock/owner contract constructor( IERC20 _underlying, string memory _name, string memory _symbol, uint32 _rewardsCycleLength, uint256 _maxDistributionPerSecondPerAsset, address _timelockAddress ) LinearRewardsErc4626(ERC20(address(_underlying)), _name, _symbol, _rewardsCycleLength) Timelock2Step(_timelockAddress) { maxDistributionPerSecondPerAsset = _maxDistributionPerSecondPerAsset; } /// @notice The ```SetMaxDistributionPerSecondPerAsset``` event is emitted when the maxDistributionPerSecondPerAsset is set /// @param oldMax The old maxDistributionPerSecondPerAsset value /// @param newMax The new maxDistributionPerSecondPerAsset value event SetMaxDistributionPerSecondPerAsset(uint256 oldMax, uint256 newMax); /// @notice The ```setMaxDistributionPerSecondPerAsset``` function sets the maxDistributionPerSecondPerAsset /// @dev This function can only be called by the timelock, caps the value to type(uint64).max /// @param _maxDistributionPerSecondPerAsset The maximum amount of rewards that can be distributed per second per 1e18 asset function setMaxDistributionPerSecondPerAsset(uint256 _maxDistributionPerSecondPerAsset) external { _requireSenderIsTimelock(); syncRewardsAndDistribution(); // NOTE: prevents bricking the contract via overflow if (_maxDistributionPerSecondPerAsset > type(uint64).max) { _maxDistributionPerSecondPerAsset = type(uint64).max; } emit SetMaxDistributionPerSecondPerAsset({ oldMax: maxDistributionPerSecondPerAsset, newMax: _maxDistributionPerSecondPerAsset }); maxDistributionPerSecondPerAsset = _maxDistributionPerSecondPerAsset; } /// @notice The ```calculateRewardsToDistribute``` function calculates the amount of rewards to distribute based on the rewards cycle data and the time passed /// @param _rewardsCycleData The rewards cycle data /// @param _deltaTime The time passed since the last rewards distribution /// @return _rewardToDistribute The amount of rewards to distribute function calculateRewardsToDistribute( RewardsCycleData memory _rewardsCycleData, uint256 _deltaTime ) public view override returns (uint256 _rewardToDistribute) { _rewardToDistribute = super.calculateRewardsToDistribute({ _rewardsCycleData: _rewardsCycleData, _deltaTime: _deltaTime }); // Cap rewards uint256 _maxDistribution = (maxDistributionPerSecondPerAsset * _deltaTime * storedTotalAssets) / PRECISION; if (_rewardToDistribute > _maxDistribution) { _rewardToDistribute = _maxDistribution; } } }
// SPDX-License-Identifier: ISC pragma solidity >=0.8.0; // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ========================== Timelock2Step =========================== // ==================================================================== // Frax Finance: https://github.com/FraxFinance // Primary Author // Drake Evans: https://github.com/DrakeEvans // Reviewers // Dennis: https://github.com/denett // ==================================================================== /// @title Timelock2Step /// @author Drake Evans (Frax Finance) https://github.com/drakeevans /// @dev Inspired by OpenZeppelin's Ownable2Step contract /// @notice An abstract contract which contains 2-step transfer and renounce logic for a timelock address abstract contract Timelock2Step { /// @notice The pending timelock address address public pendingTimelockAddress; /// @notice The current timelock address address public timelockAddress; constructor(address _timelockAddress) { timelockAddress = _timelockAddress; } // ============================================================================================ // Functions: External Functions // ============================================================================================ /// @notice The ```transferTimelock``` function initiates the timelock transfer /// @dev Must be called by the current timelock /// @param _newTimelock The address of the nominated (pending) timelock function transferTimelock(address _newTimelock) external virtual { _requireSenderIsTimelock(); _transferTimelock(_newTimelock); } /// @notice The ```acceptTransferTimelock``` function completes the timelock transfer /// @dev Must be called by the pending timelock function acceptTransferTimelock() external virtual { _requireSenderIsPendingTimelock(); _acceptTransferTimelock(); } /// @notice The ```renounceTimelock``` function renounces the timelock after setting pending timelock to current timelock /// @dev Pending timelock must be set to current timelock before renouncing, creating a 2-step renounce process function renounceTimelock() external virtual { _requireSenderIsTimelock(); _requireSenderIsPendingTimelock(); _transferTimelock(address(0)); _setTimelock(address(0)); } // ============================================================================================ // Functions: Internal Actions // ============================================================================================ /// @notice The ```_transferTimelock``` function initiates the timelock transfer /// @dev This function is to be implemented by a public function /// @param _newTimelock The address of the nominated (pending) timelock function _transferTimelock(address _newTimelock) internal { pendingTimelockAddress = _newTimelock; emit TimelockTransferStarted(timelockAddress, _newTimelock); } /// @notice The ```_acceptTransferTimelock``` function completes the timelock transfer /// @dev This function is to be implemented by a public function function _acceptTransferTimelock() internal { pendingTimelockAddress = address(0); _setTimelock(msg.sender); } /// @notice The ```_setTimelock``` function sets the timelock address /// @dev This function is to be implemented by a public function /// @param _newTimelock The address of the new timelock function _setTimelock(address _newTimelock) internal { emit TimelockTransferred(timelockAddress, _newTimelock); timelockAddress = _newTimelock; } // ============================================================================================ // Functions: Internal Checks // ============================================================================================ /// @notice The ```_isTimelock``` function checks if _address is current timelock address /// @param _address The address to check against the timelock /// @return Whether or not msg.sender is current timelock address function _isTimelock(address _address) internal view returns (bool) { return _address == timelockAddress; } /// @notice The ```_requireIsTimelock``` function reverts if _address is not current timelock address /// @param _address The address to check against the timelock function _requireIsTimelock(address _address) internal view { if (!_isTimelock(_address)) revert AddressIsNotTimelock(timelockAddress, _address); } /// @notice The ```_requireSenderIsTimelock``` function reverts if msg.sender is not current timelock address /// @dev This function is to be implemented by a public function function _requireSenderIsTimelock() internal view { _requireIsTimelock(msg.sender); } /// @notice The ```_isPendingTimelock``` function checks if the _address is pending timelock address /// @dev This function is to be implemented by a public function /// @param _address The address to check against the pending timelock /// @return Whether or not _address is pending timelock address function _isPendingTimelock(address _address) internal view returns (bool) { return _address == pendingTimelockAddress; } /// @notice The ```_requireIsPendingTimelock``` function reverts if the _address is not pending timelock address /// @dev This function is to be implemented by a public function /// @param _address The address to check against the pending timelock function _requireIsPendingTimelock(address _address) internal view { if (!_isPendingTimelock(_address)) revert AddressIsNotPendingTimelock(pendingTimelockAddress, _address); } /// @notice The ```_requirePendingTimelock``` function reverts if msg.sender is not pending timelock address /// @dev This function is to be implemented by a public function function _requireSenderIsPendingTimelock() internal view { _requireIsPendingTimelock(msg.sender); } // ============================================================================================ // Functions: Events // ============================================================================================ /// @notice The ```TimelockTransferStarted``` event is emitted when the timelock transfer is initiated /// @param previousTimelock The address of the previous timelock /// @param newTimelock The address of the new timelock event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock); /// @notice The ```TimelockTransferred``` event is emitted when the timelock transfer is completed /// @param previousTimelock The address of the previous timelock /// @param newTimelock The address of the new timelock event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock); // ============================================================================================ // Functions: Errors // ============================================================================================ /// @notice Emitted when timelock is transferred error AddressIsNotTimelock(address timelockAddress, address actualAddress); /// @notice Emitted when pending timelock is transferred error AddressIsNotPendingTimelock(address pendingTimelockAddress, address actualAddress); }
// 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: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Safe unsigned integer casting library that reverts on overflow. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeCastLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol) library SafeCastLib { function safeCastTo248(uint256 x) internal pure returns (uint248 y) { require(x < 1 << 248); y = uint248(x); } function safeCastTo240(uint256 x) internal pure returns (uint240 y) { require(x < 1 << 240); y = uint240(x); } function safeCastTo232(uint256 x) internal pure returns (uint232 y) { require(x < 1 << 232); y = uint232(x); } function safeCastTo224(uint256 x) internal pure returns (uint224 y) { require(x < 1 << 224); y = uint224(x); } function safeCastTo216(uint256 x) internal pure returns (uint216 y) { require(x < 1 << 216); y = uint216(x); } function safeCastTo208(uint256 x) internal pure returns (uint208 y) { require(x < 1 << 208); y = uint208(x); } function safeCastTo200(uint256 x) internal pure returns (uint200 y) { require(x < 1 << 200); y = uint200(x); } function safeCastTo192(uint256 x) internal pure returns (uint192 y) { require(x < 1 << 192); y = uint192(x); } function safeCastTo184(uint256 x) internal pure returns (uint184 y) { require(x < 1 << 184); y = uint184(x); } function safeCastTo176(uint256 x) internal pure returns (uint176 y) { require(x < 1 << 176); y = uint176(x); } function safeCastTo168(uint256 x) internal pure returns (uint168 y) { require(x < 1 << 168); y = uint168(x); } function safeCastTo160(uint256 x) internal pure returns (uint160 y) { require(x < 1 << 160); y = uint160(x); } function safeCastTo152(uint256 x) internal pure returns (uint152 y) { require(x < 1 << 152); y = uint152(x); } function safeCastTo144(uint256 x) internal pure returns (uint144 y) { require(x < 1 << 144); y = uint144(x); } function safeCastTo136(uint256 x) internal pure returns (uint136 y) { require(x < 1 << 136); y = uint136(x); } function safeCastTo128(uint256 x) internal pure returns (uint128 y) { require(x < 1 << 128); y = uint128(x); } function safeCastTo120(uint256 x) internal pure returns (uint120 y) { require(x < 1 << 120); y = uint120(x); } function safeCastTo112(uint256 x) internal pure returns (uint112 y) { require(x < 1 << 112); y = uint112(x); } function safeCastTo104(uint256 x) internal pure returns (uint104 y) { require(x < 1 << 104); y = uint104(x); } function safeCastTo96(uint256 x) internal pure returns (uint96 y) { require(x < 1 << 96); y = uint96(x); } function safeCastTo88(uint256 x) internal pure returns (uint88 y) { require(x < 1 << 88); y = uint88(x); } function safeCastTo80(uint256 x) internal pure returns (uint80 y) { require(x < 1 << 80); y = uint80(x); } function safeCastTo72(uint256 x) internal pure returns (uint72 y) { require(x < 1 << 72); y = uint72(x); } function safeCastTo64(uint256 x) internal pure returns (uint64 y) { require(x < 1 << 64); y = uint64(x); } function safeCastTo56(uint256 x) internal pure returns (uint56 y) { require(x < 1 << 56); y = uint56(x); } function safeCastTo48(uint256 x) internal pure returns (uint48 y) { require(x < 1 << 48); y = uint48(x); } function safeCastTo40(uint256 x) internal pure returns (uint40 y) { require(x < 1 << 40); y = uint40(x); } function safeCastTo32(uint256 x) internal pure returns (uint32 y) { require(x < 1 << 32); y = uint32(x); } function safeCastTo24(uint256 x) internal pure returns (uint24 y) { require(x < 1 << 24); y = uint24(x); } function safeCastTo16(uint256 x) internal pure returns (uint16 y) { require(x < 1 << 16); y = uint16(x); } function safeCastTo8(uint256 x) internal pure returns (uint8 y) { require(x < 1 << 8); y = uint8(x); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.21; // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ======================== LinearRewardsErc4626 ====================== // ==================================================================== // Frax Finance: https://github.com/FraxFinance import { ERC20, ERC4626 } from "solmate/mixins/ERC4626.sol"; import { SafeCastLib } from "solmate/utils/SafeCastLib.sol"; /// @title LinearRewardsErc4626 /// @notice An ERC4626 Vault implementation with linear rewards abstract contract LinearRewardsErc4626 is ERC4626 { using SafeCastLib for *; /// @notice The precision of all integer calculations uint256 public constant PRECISION = 1e18; /// @notice The rewards cycle length in seconds uint256 public immutable REWARDS_CYCLE_LENGTH; /// @notice Information about the current rewards cycle struct RewardsCycleData { uint40 cycleEnd; // Timestamp of the end of the current rewards cycle uint40 lastSync; // Timestamp of the last time the rewards cycle was synced uint216 rewardCycleAmount; // Amount of rewards to be distributed in the current cycle } /// @notice The rewards cycle data, stored in a single word to save gas RewardsCycleData public rewardsCycleData; /// @notice The timestamp of the last time rewards were distributed uint256 public lastRewardsDistribution; /// @notice The total amount of assets that have been distributed and deposited uint256 public storedTotalAssets; /// @notice The precision of the underlying asset uint256 public immutable UNDERLYING_PRECISION; /// @param _underlying The erc20 asset deposited /// @param _name The name of the vault /// @param _symbol The symbol of the vault /// @param _rewardsCycleLength The length of the rewards cycle in seconds constructor( ERC20 _underlying, string memory _name, string memory _symbol, uint256 _rewardsCycleLength ) ERC4626(_underlying, _name, _symbol) { REWARDS_CYCLE_LENGTH = _rewardsCycleLength; UNDERLYING_PRECISION = 10 ** _underlying.decimals(); // initialize rewardsCycleEnd value // NOTE: normally distribution of rewards should be done prior to _syncRewards but in this case we know there are no users or rewards yet. _syncRewards(); // initialize lastRewardsDistribution value _distributeRewards(); } function pricePerShare() external view returns (uint256 _pricePerShare) { _pricePerShare = convertToAssets(UNDERLYING_PRECISION); } /// @notice The ```calculateRewardsToDistribute``` function calculates the amount of rewards to distribute based on the rewards cycle data and the time elapsed /// @param _rewardsCycleData The rewards cycle data /// @param _deltaTime The time elapsed since the last rewards distribution /// @return _rewardToDistribute The amount of rewards to distribute function calculateRewardsToDistribute( RewardsCycleData memory _rewardsCycleData, uint256 _deltaTime ) public view virtual returns (uint256 _rewardToDistribute) { _rewardToDistribute = (_rewardsCycleData.rewardCycleAmount * _deltaTime) / (_rewardsCycleData.cycleEnd - _rewardsCycleData.lastSync); } /// @notice The ```previewDistributeRewards``` function is used to preview the rewards distributed at the top of the block /// @return _rewardToDistribute The amount of underlying to distribute function previewDistributeRewards() public view virtual returns (uint256 _rewardToDistribute) { // Cache state for gas savings RewardsCycleData memory _rewardsCycleData = rewardsCycleData; uint256 _lastRewardsDistribution = lastRewardsDistribution; uint40 _timestamp = block.timestamp.safeCastTo40(); // Calculate the delta time, but only include up to the cycle end in case we are passed it uint256 _deltaTime = _timestamp > _rewardsCycleData.cycleEnd ? _rewardsCycleData.cycleEnd - _lastRewardsDistribution : _timestamp - _lastRewardsDistribution; // Calculate the rewards to distribute _rewardToDistribute = calculateRewardsToDistribute({ _rewardsCycleData: _rewardsCycleData, _deltaTime: _deltaTime }); } /// @notice The ```distributeRewards``` function distributes the rewards once per block /// @return _rewardToDistribute The amount of underlying to distribute function _distributeRewards() internal virtual returns (uint256 _rewardToDistribute) { _rewardToDistribute = previewDistributeRewards(); // Only write to state/emit if we actually distribute rewards if (_rewardToDistribute != 0) { storedTotalAssets += _rewardToDistribute; emit DistributeRewards({ rewardsToDistribute: _rewardToDistribute }); } lastRewardsDistribution = block.timestamp; } /// @notice The ```previewSyncRewards``` function returns the updated rewards cycle data without updating the state /// @return _newRewardsCycleData The updated rewards cycle data function previewSyncRewards() public view virtual returns (RewardsCycleData memory _newRewardsCycleData) { RewardsCycleData memory _rewardsCycleData = rewardsCycleData; uint256 _timestamp = block.timestamp; // Only sync if the previous cycle has ended if (_timestamp <= _rewardsCycleData.cycleEnd) return _rewardsCycleData; // Calculate rewards for next cycle uint256 _newRewards = asset.balanceOf(address(this)) - storedTotalAssets; // Calculate the next cycle end, this keeps cycles at the same time regardless of when sync is called uint40 _cycleEnd = (((_timestamp + REWARDS_CYCLE_LENGTH) / REWARDS_CYCLE_LENGTH) * REWARDS_CYCLE_LENGTH) .safeCastTo40(); // This block prevents big jumps in rewards rate in case the sync happens near the end of the cycle if (_cycleEnd - _timestamp < REWARDS_CYCLE_LENGTH / 40) { _cycleEnd += REWARDS_CYCLE_LENGTH.safeCastTo40(); } // Write return values _rewardsCycleData.rewardCycleAmount = _newRewards.safeCastTo216(); _rewardsCycleData.lastSync = _timestamp.safeCastTo40(); _rewardsCycleData.cycleEnd = _cycleEnd; return _rewardsCycleData; } /// @notice The ```_syncRewards``` function is used to update the rewards cycle data function _syncRewards() internal virtual { RewardsCycleData memory _rewardsCycleData = previewSyncRewards(); if ( block .timestamp // If true, then preview shows a rewards should be processed .safeCastTo40() == _rewardsCycleData.lastSync && // Ensures that we don't write to state twice in the same block rewardsCycleData.lastSync != _rewardsCycleData.lastSync ) { rewardsCycleData = _rewardsCycleData; emit SyncRewards({ cycleEnd: _rewardsCycleData.cycleEnd, lastSync: _rewardsCycleData.lastSync, rewardCycleAmount: _rewardsCycleData.rewardCycleAmount }); } } /// @notice The ```syncRewardsAndDistribution``` function is used to update the rewards cycle data and distribute rewards /// @dev rewards must be distributed before the cycle is synced function syncRewardsAndDistribution() public virtual { _distributeRewards(); _syncRewards(); } /// @notice The ```totalAssets``` function returns the total assets available in the vault /// @dev This function simulates the rewards that will be distributed at the top of the block /// @return _totalAssets The total assets available in the vault function totalAssets() public view virtual override returns (uint256 _totalAssets) { uint256 _rewardToDistribute = previewDistributeRewards(); _totalAssets = storedTotalAssets + _rewardToDistribute; } function afterDeposit(uint256 amount, uint256 shares) internal virtual override { storedTotalAssets += amount; } /// @notice The ```deposit``` function allows a user to mint shares by depositing underlying /// @param _assets The amount of underlying to deposit /// @param _receiver The address to send the shares to /// @return _shares The amount of shares minted function deposit(uint256 _assets, address _receiver) public override returns (uint256 _shares) { syncRewardsAndDistribution(); _shares = super.deposit({ assets: _assets, receiver: _receiver }); } /// @notice The ```mint``` function allows a user to mint a given number of shares /// @param _shares The amount of shares to mint /// @param _receiver The address to send the shares to /// @return _assets The amount of underlying deposited function mint(uint256 _shares, address _receiver) public override returns (uint256 _assets) { syncRewardsAndDistribution(); _assets = super.mint({ shares: _shares, receiver: _receiver }); } function beforeWithdraw(uint256 amount, uint256 shares) internal virtual override { storedTotalAssets -= amount; } /// @notice The ```withdraw``` function allows a user to withdraw a given amount of underlying /// @param _assets The amount of underlying to withdraw /// @param _receiver The address to send the underlying to /// @param _owner The address of the owner of the shares /// @return _shares The amount of shares burned function withdraw(uint256 _assets, address _receiver, address _owner) public override returns (uint256 _shares) { syncRewardsAndDistribution(); _shares = super.withdraw({ assets: _assets, receiver: _receiver, owner: _owner }); } /// @notice The ```redeem``` function allows a user to redeem their shares for underlying /// @param _shares The amount of shares to redeem /// @param _receiver The address to send the underlying to /// @param _owner The address of the owner of the shares /// @return _assets The amount of underlying redeemed function redeem(uint256 _shares, address _receiver, address _owner) public override returns (uint256 _assets) { syncRewardsAndDistribution(); _assets = super.redeem({ shares: _shares, receiver: _receiver, owner: _owner }); } /// @notice The ```depositWithSignature``` function allows a user to use signed approvals to deposit /// @param _assets The amount of underlying to deposit /// @param _receiver The address to send the shares to /// @param _deadline The deadline for the signature /// @param _approveMax Whether or not to approve the maximum amount /// @param _v The v value of the signature /// @param _r The r value of the signature /// @param _s The s value of the signature /// @return _shares The amount of shares minted function depositWithSignature( uint256 _assets, address _receiver, uint256 _deadline, bool _approveMax, uint8 _v, bytes32 _r, bytes32 _s ) external returns (uint256 _shares) { uint256 _amount = _approveMax ? type(uint256).max : _assets; asset.permit({ owner: msg.sender, spender: address(this), value: _amount, deadline: _deadline, v: _v, r: _r, s: _s }); _shares = (deposit({ _assets: _assets, _receiver: _receiver })); } //============================================================================== // Events //============================================================================== /// @notice The ```SyncRewards``` event is emitted when the rewards cycle is synced /// @param cycleEnd The timestamp of the end of the current rewards cycle /// @param lastSync The timestamp of the last time the rewards cycle was synced /// @param rewardCycleAmount The amount of rewards to be distributed in the current cycle event SyncRewards(uint40 cycleEnd, uint40 lastSync, uint216 rewardCycleAmount); /// @notice The ```DistributeRewards``` event is emitted when rewards are distributed to storedTotalAssets /// @param rewardsToDistribute The amount of rewards that were distributed event DistributeRewards(uint256 rewardsToDistribute); }
// 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 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 v4.4.1 (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; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; import {FixedPointMathLib} from "../utils/FixedPointMathLib.sol"; /// @notice Minimal ERC4626 tokenized Vault implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/mixins/ERC4626.sol) abstract contract ERC4626 is ERC20 { using SafeTransferLib for ERC20; using FixedPointMathLib for uint256; /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /*////////////////////////////////////////////////////////////// IMMUTABLES //////////////////////////////////////////////////////////////*/ ERC20 public immutable asset; constructor( ERC20 _asset, string memory _name, string memory _symbol ) ERC20(_name, _symbol, _asset.decimals()) { asset = _asset; } /*////////////////////////////////////////////////////////////// DEPOSIT/WITHDRAWAL LOGIC //////////////////////////////////////////////////////////////*/ function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) { // Check for rounding error since we round down in previewDeposit. require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES"); // Need to transfer before minting or ERC777s could reenter. asset.safeTransferFrom(msg.sender, address(this), assets); _mint(receiver, shares); emit Deposit(msg.sender, receiver, assets, shares); afterDeposit(assets, shares); } function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) { assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up. // Need to transfer before minting or ERC777s could reenter. asset.safeTransferFrom(msg.sender, address(this), assets); _mint(receiver, shares); emit Deposit(msg.sender, receiver, assets, shares); afterDeposit(assets, shares); } function withdraw( uint256 assets, address receiver, address owner ) public virtual returns (uint256 shares) { shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up. if (msg.sender != owner) { uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares; } beforeWithdraw(assets, shares); _burn(owner, shares); emit Withdraw(msg.sender, receiver, owner, assets, shares); asset.safeTransfer(receiver, assets); } function redeem( uint256 shares, address receiver, address owner ) public virtual returns (uint256 assets) { if (msg.sender != owner) { uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares; } // Check for rounding error since we round down in previewRedeem. require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS"); beforeWithdraw(assets, shares); _burn(owner, shares); emit Withdraw(msg.sender, receiver, owner, assets, shares); asset.safeTransfer(receiver, assets); } /*////////////////////////////////////////////////////////////// ACCOUNTING LOGIC //////////////////////////////////////////////////////////////*/ function totalAssets() public view virtual returns (uint256); function convertToShares(uint256 assets) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets()); } function convertToAssets(uint256 shares) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply); } function previewDeposit(uint256 assets) public view virtual returns (uint256) { return convertToShares(assets); } function previewMint(uint256 shares) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply); } function previewWithdraw(uint256 assets) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets()); } function previewRedeem(uint256 shares) public view virtual returns (uint256) { return convertToAssets(shares); } /*////////////////////////////////////////////////////////////// DEPOSIT/WITHDRAWAL LIMIT LOGIC //////////////////////////////////////////////////////////////*/ function maxDeposit(address) public view virtual returns (uint256) { return type(uint256).max; } function maxMint(address) public view virtual returns (uint256) { return type(uint256).max; } function maxWithdraw(address owner) public view virtual returns (uint256) { return convertToAssets(balanceOf[owner]); } function maxRedeem(address owner) public view virtual returns (uint256) { return balanceOf[owner]; } /*////////////////////////////////////////////////////////////// INTERNAL HOOKS LOGIC //////////////////////////////////////////////////////////////*/ function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {} function afterDeposit(uint256 assets, uint256 shares) internal virtual {} }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; /// @solidity memory-safe-assembly assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument. mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant MAX_UINT256 = 2**256 - 1; uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // Divide x * y by the denominator. z := div(mul(x, y), denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // If x * y modulo the denominator is strictly greater than 0, // 1 is added to round up the division of x * y by the denominator. z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let y := x // We start y at x, which will help us make our initial estimate. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // We check y >= 2^(k + 8) but shift right by k bits // each branch to ensure that if x >= 256, then y >= 256. if iszero(lt(y, 0x10000000000000000000000000000000000)) { y := shr(128, y) z := shl(64, z) } if iszero(lt(y, 0x1000000000000000000)) { y := shr(64, y) z := shl(32, z) } if iszero(lt(y, 0x10000000000)) { y := shr(32, y) z := shl(16, z) } if iszero(lt(y, 0x1000000)) { y := shr(16, y) z := shl(8, z) } // Goal was to get z*z*y within a small factor of x. More iterations could // get y in a tighter range. Currently, we will have y in [256, 256*2^16). // We ensured y >= 256 so that the relative difference between y and y+1 is small. // That's not possible if x < 256 but we can just verify those cases exhaustively. // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. // There is no overflow risk here since y < 2^136 after the first branch above. z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If x+1 is a perfect square, the Babylonian method cycles between // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Mod x by y. Note this will return // 0 instead of reverting if y is zero. z := mod(x, y) } } function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Divide x by y. Note this will return // 0 instead of reverting if y is zero. r := div(x, y) } } function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Add 1 to x * y if x % y > 0. Note this will // return 0 instead of reverting if y is zero. z := add(gt(mod(x, y), 0), div(x, y)) } } }
{ "remappings": [ "frax-std/=lib/frax-standard-solidity/src/", "ds-test/=lib/frax-standard-solidity/lib/forge-std/lib/ds-test/src/", "solmate/=lib/solmate/src/", "@openzeppelin/=node_modules/@openzeppelin/", "forge-std/=lib/frax-standard-solidity/lib/forge-std/src/", "frax-standard-solidity/=lib/frax-standard-solidity/src/", "solidity-bytes-utils/=lib/frax-standard-solidity/lib/solidity-bytes-utils/" ], "optimizer": { "enabled": true, "runs": 99999999 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": false }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IERC20","name":"_underlying","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint32","name":"_rewardsCycleLength","type":"uint32"},{"internalType":"uint256","name":"_maxDistributionPerSecondPerAsset","type":"uint256"},{"internalType":"address","name":"_timelockAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"pendingTimelockAddress","type":"address"},{"internalType":"address","name":"actualAddress","type":"address"}],"name":"AddressIsNotPendingTimelock","type":"error"},{"inputs":[{"internalType":"address","name":"timelockAddress","type":"address"},{"internalType":"address","name":"actualAddress","type":"address"}],"name":"AddressIsNotTimelock","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rewardsToDistribute","type":"uint256"}],"name":"DistributeRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMax","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMax","type":"uint256"}],"name":"SetMaxDistributionPerSecondPerAsset","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint40","name":"cycleEnd","type":"uint40"},{"indexed":false,"internalType":"uint40","name":"lastSync","type":"uint40"},{"indexed":false,"internalType":"uint216","name":"rewardCycleAmount","type":"uint216"}],"name":"SyncRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTimelock","type":"address"},{"indexed":true,"internalType":"address","name":"newTimelock","type":"address"}],"name":"TimelockTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTimelock","type":"address"},{"indexed":true,"internalType":"address","name":"newTimelock","type":"address"}],"name":"TimelockTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARDS_CYCLE_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNDERLYING_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptTransferTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint40","name":"cycleEnd","type":"uint40"},{"internalType":"uint40","name":"lastSync","type":"uint40"},{"internalType":"uint216","name":"rewardCycleAmount","type":"uint216"}],"internalType":"struct LinearRewardsErc4626.RewardsCycleData","name":"_rewardsCycleData","type":"tuple"},{"internalType":"uint256","name":"_deltaTime","type":"uint256"}],"name":"calculateRewardsToDistribute","outputs":[{"internalType":"uint256","name":"_rewardToDistribute","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bool","name":"_approveMax","type":"bool"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"depositWithSignature","outputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastRewardsDistribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxDistributionPerSecondPerAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"_assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingTimelockAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"previewDistributeRewards","outputs":[{"internalType":"uint256","name":"_rewardToDistribute","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"previewSyncRewards","outputs":[{"components":[{"internalType":"uint40","name":"cycleEnd","type":"uint40"},{"internalType":"uint40","name":"lastSync","type":"uint40"},{"internalType":"uint216","name":"rewardCycleAmount","type":"uint216"}],"internalType":"struct LinearRewardsErc4626.RewardsCycleData","name":"_newRewardsCycleData","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pricePerShare","outputs":[{"internalType":"uint256","name":"_pricePerShare","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"_assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardsCycleData","outputs":[{"internalType":"uint40","name":"cycleEnd","type":"uint40"},{"internalType":"uint40","name":"lastSync","type":"uint40"},{"internalType":"uint216","name":"rewardCycleAmount","type":"uint216"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxDistributionPerSecondPerAsset","type":"uint256"}],"name":"setMaxDistributionPerSecondPerAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"storedTotalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"syncRewardsAndDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"timelockAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"_totalAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newTimelock","type":"address"}],"name":"transferTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
61014080604052346200083c576200355b80380380916200002182856200085d565b833981019060c0818303126200083c578051906001600160a01b0380831683036200083c5760208201516001600160401b0381116200083c57846200006891840162000881565b604083015190946001600160401b0382116200083c576200008b91840162000881565b9260608301519463ffffffff86168096036200083c5760a060808501519401519483861686036200083c5760405163313ce56760e01b8152916020836004818789165afa9283156200059e5760009362000804575b508051906001600160401b038211620005aa5781906200010260005462000912565b601f8111620007a1575b50602090601f8311600114620007255760009262000719575b50508160011b916000199060031b1c1916176000555b8051906001600160401b038211620005aa5781906200015c60015462000912565b601f8111620006b5575b50602090601f83116001146200063b576000926200062f575b50508160011b916000199060031b1c1916176001555b6080524660a05260405160009081549181620001b18462000912565b918282526020820194600181169081600014620006115750600114620005c0575b620001e0925003826200085d565b519020906040519160208301907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f825260408401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608401524660808401523060a084015260a0835260c083019183831060018060401b03841117620005aa57600483868193602095836040528851902060c05281811660e0526101009b8c5263313ce56760e01b8352165afa9081156200059e5760ff9260009262000562575b50501692604d84116200054c5761012093600a0a8452620002c3620009f5565b620002ce42620009a7565b60208201519164ffffffffff9283928382169384911614806200053a575b620004b3575b505050620002ff6200095d565b6008546200030d42620009a7565b825190841691908416821115620004a1576200032e91508383511662000999565b915b60408201516000906200034e9085906001600160d81b0316620009e1565b9282602081835116920151169003908282116200048d575091620003799162000383931690620009c0565b91600c54620009e1565b670de0b6b3a76400006200039b6009548093620009e1565b0480831162000484575b508162000442575b5050426008551660018060a01b0319600b541617600b55600c556040519061298c928362000b8f8439608051836116a4015260a05183611ea2015260c05183611ec9015260e051838181610871015281816109fa01528181610de701528181610fc80152818161152d0152818161227401526125bd0152518281816111f901526122b3015251818181610be40152610c3f0152f35b81620004727fb9d196a585c1a894f648393ec7d52cc59ff6d94191579d073ba32b0a74d7f7a6936020936200094f565b600955604051908152a13880620003ad565b915038620003a5565b634e487b7160e01b81526011600452602490fd5b620004ac9162000999565b9162000330565b7fc32a546ed958490e37f30335e501e0a39438cb650a4851bfd4b775490af29dad9282856060945116928369ffffffffff00000000006006549260281b169160018060501b0319161717600655604060018060d81b0391015116908164ffffffffff60d81b600754161760075560405192835260208301526040820152a1388080620002f2565b50828460065460281c161415620002ec565b634e487b7160e01b600052601160045260246000fd5b6200058d925060c0906020903d60201162000595575b6200058482856200085d565b010190620008f7565b3880620002a3565b3d915062000578565b6040513d6000823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b50600080805290916000805160206200351b8339815191525b818310620005f4575050906020620001e092820101620001d2565b6020919350806001915483858801015201910190918392620005d9565b60ff1916865250620001e092151560051b82016020019050620001d2565b0151905038806200017f565b600160009081526000805160206200353b8339815191529350601f198516905b8181106200069c575090846001959493921062000682575b505050811b0160015562000195565b015160001960f88460031b161c1916905538808062000673565b929360206001819287860151815501950193016200065b565b60016000529091506000805160206200353b833981519152601f840160051c810191602085106200070e575b90601f859493920160051c01905b818110620006fe575062000166565b60008155849350600101620006ef565b9091508190620006e1565b01519050388062000125565b600080805293506000805160206200351b83398151915291905b601f198416851062000785576001945083601f198116106200076b575b505050811b016000556200013b565b015160001960f88460031b161c191690553880806200075c565b818101518355602094850194600190930192909101906200073f565b600080529091506000805160206200351b833981519152601f840160051c81019160208510620007f9575b90601f859493920160051c01905b818110620007e957506200010c565b60008155849350600101620007da565b9091508190620007cc565b6200082c91935060203d60201162000834575b6200082381836200085d565b810190620008f7565b9138620000e0565b503d62000817565b600080fd5b606081019081106001600160401b03821117620005aa57604052565b601f909101601f19168101906001600160401b03821190821017620005aa57604052565b919080601f840112156200083c5782516001600160401b038111620005aa5760209060405192620008bc83601f19601f85011601856200085d565b8184528282870101116200083c5760005b818110620008e357508260009394955001015290565b8581018301518482018401528201620008cd565b908160209103126200083c575160ff811681036200083c5790565b90600182811c9216801562000944575b60208310146200092e57565b634e487b7160e01b600052602260045260246000fd5b91607f169162000922565b919082018092116200054c57565b604051906200096c8262000841565b60065464ffffffffff808216845260289190911c1660208301526007546001600160d81b03166040830152565b919082039182116200054c57565b650100000000008110156200083c5764ffffffffff1690565b8115620009cb570490565b634e487b7160e01b600052601260045260246000fd5b818102929181159184041417156200054c57565b60405162000a038162000841565b6000908181528160406020928284820152015262000a206200095d565b9164ffffffffff918284511642111562000b885760e0516040516370a0823160e01b8152306004820152908290829060249082906001600160a01b03165afa801562000b7d57839062000b43575b62000a7e91506009549062000999565b6101009262000ab362000aad62000aa462000a9b8751426200094f565b875190620009c0565b865190620009e1565b620009a7565b93858086169162000ac5428462000999565b905190602882041162000b0c575b505050600160d81b82101562000b0957506001600160d81b031660408501528262000afe42620009a7565b169084015216815290565b80fd5b62000b1b9192939650620009a7565b160184811162000b2f579238858162000ad3565b634e487b7160e01b84526011600452602484fd5b508181813d831162000b75575b62000b5c81836200085d565b8101031262000b715762000a7e905162000a6e565b8280fd5b503d62000b50565b6040513d85823e3d90fd5b5050509056fe6040608081526004908136101561001557600080fd5b600091823560e01c91826301e1d11414611a4c57826306fdde031461198657826307a2d13a146112f0578263090f3f5014611933578263095ea7b3146118985782630a28a4771461185b57826318160ddd1461181e57826323b872dd146117055782632af98d6d146116c8578263313ce5671461166c578263358245fc146116315782633644e515146115f6578263374010a41461155157826338d52e0f146114e2578263402d267d14610787578263450140951461143457826348f76e0f146113805782634bc66f321461132d5782634cdad506146112f05782634f8b4ae71461121c57826356caf605146111c35782635ebae5661461114957826361c1c5e91461110c5782636e553f65146110c757826370a082311461039057826375e077c314610f395782637ecebe0014610ed75782638f765d5914610e5b57826394bf804d14610d7957826395d89b4114610c6357826399530b0614610c07578263a80e754714610bae578263a9059cbb14610b01578263aaf5eb6814610ac0578263b3d7f6b914610a83578263b460af9414610963578263ba087652146107c9578263bd6f36031461078c578263c63d75b614610787578263c6e6f592146102d4578263ce96cb7714610724578263d505accf14610430578263d71356e6146103f6578263d905777e14610390578263dd62ed3e14610318578263ef8b30f7146102d457505063f6ccaad41461022957600080fd5b346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761025f611d66565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600a5416600a55600b54903373ffffffffffffffffffffffffffffffffffffffff83167f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68580a3163317600b5580f35b80fd5b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611dd8565b9051908152f35b91503461038c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c576020928291610355611bd7565b61035d611bff565b9173ffffffffffffffffffffffffffffffffffffffff8092168452865283832091168252845220549051908152f35b8280fd5b8390346103f25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2578060209273ffffffffffffffffffffffffffffffffffffffff6103e2611bd7565b1681526003845220549051908152f35b5080fd5b83346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761042d6123fc565b80f35b8390346103f25760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257610469611bd7565b90610472611bff565b9160443560643592610482611c84565b924285106106c757610492611e9d565b9573ffffffffffffffffffffffffffffffffffffffff8092169586895260209560058752848a209889549960018b01905585519285898501957f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c987528b89870152169a8b606086015288608086015260a085015260c084015260c0835260e0830167ffffffffffffffff948482108683111761069a57818852845190206101008501927f19010000000000000000000000000000000000000000000000000000000000008452610102860152610122850152604281526101608401948186109086111761066e57848752519020835260ff1661018082015260a4356101a082015260c4356101c0909101528780528490889060809060015afa1561066457865116968715158061065b575b156106005786977f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259596975283528087208688528352818188205551908152a380f35b8360649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152fd5b508488146105bd565b81513d88823e3d90fd5b60248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5060248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b60648860208451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152fd5b8390346103f25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576103118160209373ffffffffffffffffffffffffffffffffffffffff610779611bd7565b168152600385522054611dfd565b611c22565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906008549051908152f35b9083346102d1576107d936611c94565b6107e5939291936123fc565b73ffffffffffffffffffffffffffffffffffffffff90818116938433036108f8575b5061081183611dfd565b95861561089b57509282602097959261083d88956108959761083588600954611e61565b6009556127d7565b865191858352898301528316907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db873392a47f000000000000000000000000000000000000000000000000000000000000000061283e565b51908152f35b60649060208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600b60248201527f5a45524f5f4153534554530000000000000000000000000000000000000000006044820152fd5b848152866020528781203382526020528780822054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361093e575b505050610807565b61094791611e61565b9186815288602052818120338252602052205587878185610936565b8390346103f25761089560209361097936611c94565b959091926109856123fc565b6109c561099185611e3f565b809873ffffffffffffffffffffffffffffffffffffffff938985831696873303610a1e575b50505061083587600954611e61565b85519084825287898301528316907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db873392a47f000000000000000000000000000000000000000000000000000000000000000061283e565b878152828e528181203382528e5281812054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610a60575b50506109b6565b610a6991611e61565b928882528e528181203382528e5220558b89818085610a59565b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611e1e565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25760209051670de0b6b3a76400008152f35b8390346103f257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602091610b3c611bd7565b8273ffffffffffffffffffffffffffffffffffffffff6024359233855260038752828520610b6b858254611e61565b90551692838152600386522081815401905582519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef843392a35160018152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906103117f0000000000000000000000000000000000000000000000000000000000000000611dfd565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25780519082600190815491610ca683611a92565b918286526020938281169081600014610d395750600114610ce1575b610cdd8686610cd3828b0383611b30565b5191829182611b71565b0390f35b9295508083527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b828410610d265750505082610cdd94610cd3928201019486610cc2565b8054868501880152928601928101610d09565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001687860152505050151560051b8301019250610cd382610cdd86610cc2565b91503461038c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c57602092503590610db7611bff565b91610dc06123fc565b73ffffffffffffffffffffffffffffffffffffffff610dde82611e1e565b93610e0b8530337f0000000000000000000000000000000000000000000000000000000000000000612707565b610e1583826126a1565b8351928584528684015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7833392a3610e5282600954612199565b60095551908152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257606090610e966121f2565b907affffffffffffffffffffffffffffffffffffffffffffffffffffff8180519364ffffffffff808251168652602082015116602086015201511690820152f35b8390346103f25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2578060209273ffffffffffffffffffffffffffffffffffffffff610f29611bd7565b1681526005845220549051908152f35b83346102d15760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1578235610f73611bff565b916064359081151582036102d157610f89611c84565b91156110c1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b1561038c579060e48884809460ff8b5198899687957fd505accf00000000000000000000000000000000000000000000000000000000875233908701523060248701526044860152604435606486015216608484015260a43560a484015260c43560c48401525af180156110b55761106a575b6020856103118686612598565b67ffffffffffffffff821161108957508352602093506103118561105d565b806041877f4e487b71000000000000000000000000000000000000000000000000000000006024945252fd5b508451903d90823e3d90fd5b82610fb1565b83346102d157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15750610311602092611105611bff565b9035612598565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906009549051908152f35b83346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15750600654600754915164ffffffffff808316825260289290921c90911660208201527affffffffffffffffffffffffffffffffffffffffffffffffffffff9091166040820152606090f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b83346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d157611253611cf4565b61125b611d66565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600a5416600a55600b548273ffffffffffffffffffffffffffffffffffffffff821681817f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8280a37f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68280a316600b5580f35b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611dfd565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25760209073ffffffffffffffffffffffffffffffffffffffff600b54169051908152f35b91503461038c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c5735906113bb611cf4565b6113c36123fc565b67ffffffffffffffff80831161140c575b507f05d530f0fd6974b7d995fd3b71870f5301bb9fe086180bdd0bd36526728f5c6b90600c548151908152836020820152a1600c5580f35b91507f05d530f0fd6974b7d995fd3b71870f5301bb9fe086180bdd0bd36526728f5c6b6113d4565b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761146c611bd7565b611474611cf4565b73ffffffffffffffffffffffffffffffffffffffff80911690817fffffffffffffffffffffffff0000000000000000000000000000000000000000600a541617600a55600b54167f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8380a380f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b83346102d1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601608081126103f2576060136102d15781519261159584611ae5565b3564ffffffffff90818116810361038c57845260243590811681036103f2576020840152604435907affffffffffffffffffffffffffffffffffffffffffffffffffffff821682036102d15750826103119183602095015260643590612905565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090610311611e9d565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090610311612137565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020905160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090600c549051908152f35b83346102d15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761173d611bd7565b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef611766611bff565b946044358573ffffffffffffffffffffffffffffffffffffffff80951694858752602098848a958652838920338a52865283892054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036117fb575b505050868852600385528288206117dc858254611e61565b9055169586815260038452208181540190558551908152a35160018152f35b61180491611e61565b90888a528652838920338a528652838920558a80856117c4565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906002549051908152f35b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611e3f565b91503461038c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c576020926118d3611bd7565b9183602435928392338252875273ffffffffffffffffffffffffffffffffffffffff8282209516948582528752205582519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925843392a35160018152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25760209073ffffffffffffffffffffffffffffffffffffffff600a54169051908152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2578051908280546119c581611a92565b908185526020926001918281169081600014610d3957506001146119f457610cdd8686610cd3828b0383611b30565b8080949750527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b828410611a395750505082610cdd94610cd3928201019486610cc2565b8054868501880152928601928101611a1c565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090610311611a8a612137565b600954612199565b90600182811c92168015611adb575b6020831014611aac57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611aa1565b6060810190811067ffffffffffffffff821117611b0157604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611b0157604052565b60208082528251818301819052939260005b858110611bc3575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201611b83565b6004359073ffffffffffffffffffffffffffffffffffffffff82168203611bfa57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff82168203611bfa57565b34611bfa5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112611bfa57611c59611bd7565b5060206040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8152f35b6084359060ff82168203611bfa57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6060910112611bfa576004359073ffffffffffffffffffffffffffffffffffffffff906024358281168103611bfa57916044359081168103611bfa5790565b73ffffffffffffffffffffffffffffffffffffffff600b5416803303611d175750565b6040517f443dc2b400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b73ffffffffffffffffffffffffffffffffffffffff600a5416803303611d895750565b6040517fbe5a953700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b60025480611de4575090565b90611dfa91611df4611a8a612137565b9161207a565b90565b60025480611e09575090565b611dfa91611e18611a8a612137565b9061207a565b60025480611e2a575090565b611dfa91611e39611a8a612137565b906120ae565b60025480611e4b575090565b90611dfa91611e5b611a8a612137565b916120ae565b91908203918211611e6e57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000467f000000000000000000000000000000000000000000000000000000000000000003611eeb57507f000000000000000000000000000000000000000000000000000000000000000090565b60405181548291611efb82611a92565b808252816020948582019460019087828216918260001461203e575050600114611fe5575b50611f2d92500382611b30565b51902091604051918201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f845260408301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a083015260a0825260c082019082821067ffffffffffffffff831117611fb8575060405251902090565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526041600452fd5b87805286915087907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b858310612026575050611f2d935082010138611f20565b8054838801850152869450889390920191810161200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168852611f2d95151560051b8501019250389150611f209050565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215611bfa57020490565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215611bfa570290808204910615150190565b604051906120f782611ae5565b8160065464ffffffffff90818116835260281c16602082015260407affffffffffffffffffffffffffffffffffffffffffffffffffffff60075416910152565b611dfa6121426120ea565b60085461214e42612181565b825164ffffffffff92918316908316811115612177575061217191835116611e61565b90612905565b6121719250611e61565b65010000000000811015611bfa5764ffffffffff1690565b91908201809211611e6e57565b81156121b0570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b81810292918115918404141715611e6e57565b6040516121fe81611ae5565b600090818152816040602092828482015201526122196120ea565b9164ffffffffff91828451164211156123f6576040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152818160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa80156123eb5783906123bc575b6122b1915060095490611e61565b7f0000000000000000000000000000000000000000000000000000000000000000926122f76122f2856122ed816122e88142612199565b6121a6565b6121df565b612181565b9385808616916123074284611e61565b6028820411612370575b5050507b010000000000000000000000000000000000000000000000000000008210156102d157507affffffffffffffffffffffffffffffffffffffffffffffffffffff1660408501528261236542612181565b169084015216815290565b61237d9192939650612181565b160184811161238f5792388581612311565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b508181813d83116123e4575b6123d28183611b30565b8101031261038c576122b190516122a3565b503d6123c8565b6040513d85823e3d90fd5b50505090565b612404612137565b80612558575b50426008556124176121f2565b61242042612181565b602082015164ffffffffff808216928116831480612547575b612444575b50505050565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff60408561253b937fc32a546ed958490e37f30335e501e0a39438cb650a4851bfd4b775490af29dad97511694857fffffffffffffffffffffffffffffffffffffffffffff0000000000000000000069ffffffffff00000000006006549360281b1692161717600655015116807fffffffffff0000000000000000000000000000000000000000000000000000006007541617600755604051938493849193927affffffffffffffffffffffffffffffffffffffffffffffffffffff90604092606085019664ffffffffff809216865216602085015216910152565b0390a13880808061243e565b50828160065460281c161415612439565b6020816125887fb9d196a585c1a894f648393ec7d52cc59ff6d94191579d073ba32b0a74d7f7a693600954612199565b600955604051908152a13861240a565b906125a16123fc565b6125aa82611dd8565b9182156126435761263d916125e18230337f0000000000000000000000000000000000000000000000000000000000000000612707565b6125eb84826126a1565b73ffffffffffffffffffffffffffffffffffffffff6040519183835285602084015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d760403392a3600954612199565b60095590565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f5348415245530000000000000000000000000000000000000000006044820152fd5b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602073ffffffffffffffffffffffffffffffffffffffff6000936126e886600254612199565b60025516938484526003825260408420818154019055604051908152a3565b9160008093602095606494604051947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216600487015216602485015260448401525af13d15601f3d116001600051141617161561277957565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602073ffffffffffffffffffffffffffffffffffffffff6000941692838552600382526040852061282b828254611e61565b90558060025403600255604051908152a3565b6000918260449260209573ffffffffffffffffffffffffffffffffffffffff604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af13d15601f3d11600160005114161716156128a757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b919091612933837affffffffffffffffffffffffffffffffffffffffffffffffffffff6040840151166121df565b64ffffffffff918260208183511692015116900391808311611e6e5761296b61297d9261297492670de0b6b3a76400009516906121a6565b94600c546121df565b600954906121df565b048083116129885750565b915056290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6000000000000000000000000853d955acef822db058eb8505911ed77f175b99e00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000000000000b4241eae000000000000000000000000831822660572bd54ebaa065c2acef662a6277d40000000000000000000000000000000000000000000000000000000000000000b5374616b6564204652415800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057346524158000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6040608081526004908136101561001557600080fd5b600091823560e01c91826301e1d11414611a4c57826306fdde031461198657826307a2d13a146112f0578263090f3f5014611933578263095ea7b3146118985782630a28a4771461185b57826318160ddd1461181e57826323b872dd146117055782632af98d6d146116c8578263313ce5671461166c578263358245fc146116315782633644e515146115f6578263374010a41461155157826338d52e0f146114e2578263402d267d14610787578263450140951461143457826348f76e0f146113805782634bc66f321461132d5782634cdad506146112f05782634f8b4ae71461121c57826356caf605146111c35782635ebae5661461114957826361c1c5e91461110c5782636e553f65146110c757826370a082311461039057826375e077c314610f395782637ecebe0014610ed75782638f765d5914610e5b57826394bf804d14610d7957826395d89b4114610c6357826399530b0614610c07578263a80e754714610bae578263a9059cbb14610b01578263aaf5eb6814610ac0578263b3d7f6b914610a83578263b460af9414610963578263ba087652146107c9578263bd6f36031461078c578263c63d75b614610787578263c6e6f592146102d4578263ce96cb7714610724578263d505accf14610430578263d71356e6146103f6578263d905777e14610390578263dd62ed3e14610318578263ef8b30f7146102d457505063f6ccaad41461022957600080fd5b346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761025f611d66565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600a5416600a55600b54903373ffffffffffffffffffffffffffffffffffffffff83167f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68580a3163317600b5580f35b80fd5b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611dd8565b9051908152f35b91503461038c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c576020928291610355611bd7565b61035d611bff565b9173ffffffffffffffffffffffffffffffffffffffff8092168452865283832091168252845220549051908152f35b8280fd5b8390346103f25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2578060209273ffffffffffffffffffffffffffffffffffffffff6103e2611bd7565b1681526003845220549051908152f35b5080fd5b83346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761042d6123fc565b80f35b8390346103f25760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257610469611bd7565b90610472611bff565b9160443560643592610482611c84565b924285106106c757610492611e9d565b9573ffffffffffffffffffffffffffffffffffffffff8092169586895260209560058752848a209889549960018b01905585519285898501957f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c987528b89870152169a8b606086015288608086015260a085015260c084015260c0835260e0830167ffffffffffffffff948482108683111761069a57818852845190206101008501927f19010000000000000000000000000000000000000000000000000000000000008452610102860152610122850152604281526101608401948186109086111761066e57848752519020835260ff1661018082015260a4356101a082015260c4356101c0909101528780528490889060809060015afa1561066457865116968715158061065b575b156106005786977f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259596975283528087208688528352818188205551908152a380f35b8360649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152fd5b508488146105bd565b81513d88823e3d90fd5b60248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5060248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b60648860208451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152fd5b8390346103f25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576103118160209373ffffffffffffffffffffffffffffffffffffffff610779611bd7565b168152600385522054611dfd565b611c22565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906008549051908152f35b9083346102d1576107d936611c94565b6107e5939291936123fc565b73ffffffffffffffffffffffffffffffffffffffff90818116938433036108f8575b5061081183611dfd565b95861561089b57509282602097959261083d88956108959761083588600954611e61565b6009556127d7565b865191858352898301528316907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db873392a47f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e61283e565b51908152f35b60649060208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600b60248201527f5a45524f5f4153534554530000000000000000000000000000000000000000006044820152fd5b848152866020528781203382526020528780822054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361093e575b505050610807565b61094791611e61565b9186815288602052818120338252602052205587878185610936565b8390346103f25761089560209361097936611c94565b959091926109856123fc565b6109c561099185611e3f565b809873ffffffffffffffffffffffffffffffffffffffff938985831696873303610a1e575b50505061083587600954611e61565b85519084825287898301528316907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db873392a47f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e61283e565b878152828e528181203382528e5281812054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610a60575b50506109b6565b610a6991611e61565b928882528e528181203382528e5220558b89818085610a59565b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611e1e565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25760209051670de0b6b3a76400008152f35b8390346103f257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602091610b3c611bd7565b8273ffffffffffffffffffffffffffffffffffffffff6024359233855260038752828520610b6b858254611e61565b90551692838152600386522081815401905582519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef843392a35160018152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090517f0000000000000000000000000000000000000000000000000de0b6b3a76400008152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906103117f0000000000000000000000000000000000000000000000000de0b6b3a7640000611dfd565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25780519082600190815491610ca683611a92565b918286526020938281169081600014610d395750600114610ce1575b610cdd8686610cd3828b0383611b30565b5191829182611b71565b0390f35b9295508083527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b828410610d265750505082610cdd94610cd3928201019486610cc2565b8054868501880152928601928101610d09565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001687860152505050151560051b8301019250610cd382610cdd86610cc2565b91503461038c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c57602092503590610db7611bff565b91610dc06123fc565b73ffffffffffffffffffffffffffffffffffffffff610dde82611e1e565b93610e0b8530337f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e612707565b610e1583826126a1565b8351928584528684015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7833392a3610e5282600954612199565b60095551908152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257606090610e966121f2565b907affffffffffffffffffffffffffffffffffffffffffffffffffffff8180519364ffffffffff808251168652602082015116602086015201511690820152f35b8390346103f25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2578060209273ffffffffffffffffffffffffffffffffffffffff610f29611bd7565b1681526005845220549051908152f35b83346102d15760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1578235610f73611bff565b916064359081151582036102d157610f89611c84565b91156110c1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e16803b1561038c579060e48884809460ff8b5198899687957fd505accf00000000000000000000000000000000000000000000000000000000875233908701523060248701526044860152604435606486015216608484015260a43560a484015260c43560c48401525af180156110b55761106a575b6020856103118686612598565b67ffffffffffffffff821161108957508352602093506103118561105d565b806041877f4e487b71000000000000000000000000000000000000000000000000000000006024945252fd5b508451903d90823e3d90fd5b82610fb1565b83346102d157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15750610311602092611105611bff565b9035612598565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906009549051908152f35b83346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15750600654600754915164ffffffffff808316825260289290921c90911660208201527affffffffffffffffffffffffffffffffffffffffffffffffffffff9091166040820152606090f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090517f0000000000000000000000000000000000000000000000000000000000093a808152f35b83346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d157611253611cf4565b61125b611d66565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600a5416600a55600b548273ffffffffffffffffffffffffffffffffffffffff821681817f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8280a37f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68280a316600b5580f35b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611dfd565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25760209073ffffffffffffffffffffffffffffffffffffffff600b54169051908152f35b91503461038c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c5735906113bb611cf4565b6113c36123fc565b67ffffffffffffffff80831161140c575b507f05d530f0fd6974b7d995fd3b71870f5301bb9fe086180bdd0bd36526728f5c6b90600c548151908152836020820152a1600c5580f35b91507f05d530f0fd6974b7d995fd3b71870f5301bb9fe086180bdd0bd36526728f5c6b6113d4565b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761146c611bd7565b611474611cf4565b73ffffffffffffffffffffffffffffffffffffffff80911690817fffffffffffffffffffffffff0000000000000000000000000000000000000000600a541617600a55600b54167f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8380a380f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e168152f35b83346102d1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601608081126103f2576060136102d15781519261159584611ae5565b3564ffffffffff90818116810361038c57845260243590811681036103f2576020840152604435907affffffffffffffffffffffffffffffffffffffffffffffffffffff821682036102d15750826103119183602095015260643590612905565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090610311611e9d565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090610311612137565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020905160ff7f0000000000000000000000000000000000000000000000000000000000000012168152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090600c549051908152f35b83346102d15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761173d611bd7565b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef611766611bff565b946044358573ffffffffffffffffffffffffffffffffffffffff80951694858752602098848a958652838920338a52865283892054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036117fb575b505050868852600385528288206117dc858254611e61565b9055169586815260038452208181540190558551908152a35160018152f35b61180491611e61565b90888a528652838920338a528652838920558a80856117c4565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906002549051908152f35b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611e3f565b91503461038c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c576020926118d3611bd7565b9183602435928392338252875273ffffffffffffffffffffffffffffffffffffffff8282209516948582528752205582519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925843392a35160018152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25760209073ffffffffffffffffffffffffffffffffffffffff600a54169051908152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2578051908280546119c581611a92565b908185526020926001918281169081600014610d3957506001146119f457610cdd8686610cd3828b0383611b30565b8080949750527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b828410611a395750505082610cdd94610cd3928201019486610cc2565b8054868501880152928601928101611a1c565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090610311611a8a612137565b600954612199565b90600182811c92168015611adb575b6020831014611aac57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611aa1565b6060810190811067ffffffffffffffff821117611b0157604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611b0157604052565b60208082528251818301819052939260005b858110611bc3575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201611b83565b6004359073ffffffffffffffffffffffffffffffffffffffff82168203611bfa57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff82168203611bfa57565b34611bfa5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112611bfa57611c59611bd7565b5060206040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8152f35b6084359060ff82168203611bfa57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6060910112611bfa576004359073ffffffffffffffffffffffffffffffffffffffff906024358281168103611bfa57916044359081168103611bfa5790565b73ffffffffffffffffffffffffffffffffffffffff600b5416803303611d175750565b6040517f443dc2b400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b73ffffffffffffffffffffffffffffffffffffffff600a5416803303611d895750565b6040517fbe5a953700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b60025480611de4575090565b90611dfa91611df4611a8a612137565b9161207a565b90565b60025480611e09575090565b611dfa91611e18611a8a612137565b9061207a565b60025480611e2a575090565b611dfa91611e39611a8a612137565b906120ae565b60025480611e4b575090565b90611dfa91611e5b611a8a612137565b916120ae565b91908203918211611e6e57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000467f000000000000000000000000000000000000000000000000000000000000000103611eeb57507f9215534876c4f9b64ee9cbc7b70915f8def0270d6a0aacd514b3ccd16f7e1fe490565b60405181548291611efb82611a92565b808252816020948582019460019087828216918260001461203e575050600114611fe5575b50611f2d92500382611b30565b51902091604051918201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f845260408301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a083015260a0825260c082019082821067ffffffffffffffff831117611fb8575060405251902090565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526041600452fd5b87805286915087907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b858310612026575050611f2d935082010138611f20565b8054838801850152869450889390920191810161200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168852611f2d95151560051b8501019250389150611f209050565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215611bfa57020490565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215611bfa570290808204910615150190565b604051906120f782611ae5565b8160065464ffffffffff90818116835260281c16602082015260407affffffffffffffffffffffffffffffffffffffffffffffffffffff60075416910152565b611dfa6121426120ea565b60085461214e42612181565b825164ffffffffff92918316908316811115612177575061217191835116611e61565b90612905565b6121719250611e61565b65010000000000811015611bfa5764ffffffffff1690565b91908201809211611e6e57565b81156121b0570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b81810292918115918404141715611e6e57565b6040516121fe81611ae5565b600090818152816040602092828482015201526122196120ea565b9164ffffffffff91828451164211156123f6576040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152818160248173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e165afa80156123eb5783906123bc575b6122b1915060095490611e61565b7f0000000000000000000000000000000000000000000000000000000000093a80926122f76122f2856122ed816122e88142612199565b6121a6565b6121df565b612181565b9385808616916123074284611e61565b6028820411612370575b5050507b010000000000000000000000000000000000000000000000000000008210156102d157507affffffffffffffffffffffffffffffffffffffffffffffffffffff1660408501528261236542612181565b169084015216815290565b61237d9192939650612181565b160184811161238f5792388581612311565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b508181813d83116123e4575b6123d28183611b30565b8101031261038c576122b190516122a3565b503d6123c8565b6040513d85823e3d90fd5b50505090565b612404612137565b80612558575b50426008556124176121f2565b61242042612181565b602082015164ffffffffff808216928116831480612547575b612444575b50505050565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff60408561253b937fc32a546ed958490e37f30335e501e0a39438cb650a4851bfd4b775490af29dad97511694857fffffffffffffffffffffffffffffffffffffffffffff0000000000000000000069ffffffffff00000000006006549360281b1692161717600655015116807fffffffffff0000000000000000000000000000000000000000000000000000006007541617600755604051938493849193927affffffffffffffffffffffffffffffffffffffffffffffffffffff90604092606085019664ffffffffff809216865216602085015216910152565b0390a13880808061243e565b50828160065460281c161415612439565b6020816125887fb9d196a585c1a894f648393ec7d52cc59ff6d94191579d073ba32b0a74d7f7a693600954612199565b600955604051908152a13861240a565b906125a16123fc565b6125aa82611dd8565b9182156126435761263d916125e18230337f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e612707565b6125eb84826126a1565b73ffffffffffffffffffffffffffffffffffffffff6040519183835285602084015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d760403392a3600954612199565b60095590565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f5348415245530000000000000000000000000000000000000000006044820152fd5b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602073ffffffffffffffffffffffffffffffffffffffff6000936126e886600254612199565b60025516938484526003825260408420818154019055604051908152a3565b9160008093602095606494604051947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216600487015216602485015260448401525af13d15601f3d116001600051141617161561277957565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602073ffffffffffffffffffffffffffffffffffffffff6000941692838552600382526040852061282b828254611e61565b90558060025403600255604051908152a3565b6000918260449260209573ffffffffffffffffffffffffffffffffffffffff604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af13d15601f3d11600160005114161716156128a757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b919091612933837affffffffffffffffffffffffffffffffffffffffffffffffffffff6040840151166121df565b64ffffffffff918260208183511692015116900391808311611e6e5761296b61297d9261297492670de0b6b3a76400009516906121a6565b94600c546121df565b600954906121df565b048083116129885750565b915056
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000853d955acef822db058eb8505911ed77f175b99e00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000000000000b4241eae000000000000000000000000831822660572bd54ebaa065c2acef662a6277d40000000000000000000000000000000000000000000000000000000000000000b5374616b6564204652415800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057346524158000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _underlying (address): 0x853d955aCEf822Db058eb8505911ED77F175b99e
Arg [1] : _name (string): Staked FRAX
Arg [2] : _symbol (string): sFRAX
Arg [3] : _rewardsCycleLength (uint32): 604800
Arg [4] : _maxDistributionPerSecondPerAsset (uint256): 3022266030
Arg [5] : _timelockAddress (address): 0x831822660572bd54ebaa065C2acef662a6277D40
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 000000000000000000000000853d955acef822db058eb8505911ed77f175b99e
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [3] : 0000000000000000000000000000000000000000000000000000000000093a80
Arg [4] : 00000000000000000000000000000000000000000000000000000000b4241eae
Arg [5] : 000000000000000000000000831822660572bd54ebaa065c2acef662a6277d40
Arg [6] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [7] : 5374616b65642046524158000000000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [9] : 7346524158000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
OVERVIEW
Staked FRAX (sFRAX) is an ERC4626 staking vault that distributes part of the Frax Protocol yield weekly to stakers denominated in FRAX stablecoins.Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $0.994642 | 53,645,776.8644 | $53,358,342.79 |
Loading...
Loading
[ Download: CSV Export ]
[ 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.