Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 632 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Redeem | 19431774 | 247 days ago | IN | 0 ETH | 0.00435418 | ||||
Sync Rewards And... | 19366366 | 256 days ago | IN | 0 ETH | 0.00432696 | ||||
Sync Rewards And... | 19179750 | 282 days ago | IN | 0 ETH | 0.00222005 | ||||
Redeem | 19153881 | 286 days ago | IN | 0 ETH | 0.00121424 | ||||
Sync Rewards And... | 19150113 | 286 days ago | IN | 0 ETH | 0.00064556 | ||||
Sync Rewards And... | 19080605 | 296 days ago | IN | 0 ETH | 0.00049129 | ||||
Sync Rewards And... | 19034438 | 302 days ago | IN | 0 ETH | 0.00161751 | ||||
Sync Rewards And... | 18980577 | 310 days ago | IN | 0 ETH | 0.00160593 | ||||
Sync Rewards And... | 18930640 | 317 days ago | IN | 0 ETH | 0.0011075 | ||||
Redeem | 18915788 | 319 days ago | IN | 0 ETH | 0.00093657 | ||||
Sync Rewards And... | 18880502 | 324 days ago | IN | 0 ETH | 0.00124424 | ||||
Redeem | 18844898 | 329 days ago | IN | 0 ETH | 0.00148639 | ||||
Sync Rewards And... | 18830585 | 331 days ago | IN | 0 ETH | 0.00270157 | ||||
Sync Rewards And... | 18781122 | 338 days ago | IN | 0 ETH | 0.00220068 | ||||
Sync Rewards And... | 18736410 | 344 days ago | IN | 0 ETH | 0.00311803 | ||||
Sync Rewards And... | 18683511 | 352 days ago | IN | 0 ETH | 0.00147275 | ||||
Redeem | 18651352 | 356 days ago | IN | 0 ETH | 0.00242816 | ||||
Redeem | 18649730 | 356 days ago | IN | 0 ETH | 0.00247095 | ||||
Redeem | 18648239 | 357 days ago | IN | 0 ETH | 0.00156096 | ||||
Approve | 18633641 | 359 days ago | IN | 0 ETH | 0.00061526 | ||||
Sync Rewards And... | 18630718 | 359 days ago | IN | 0 ETH | 0.00168226 | ||||
Sync Rewards And... | 18580737 | 366 days ago | IN | 0 ETH | 0.00195959 | ||||
Redeem | 18576536 | 367 days ago | IN | 0 ETH | 0.00203289 | ||||
Redeem | 18571530 | 367 days ago | IN | 0 ETH | 0.00444493 | ||||
Redeem | 18558899 | 369 days ago | IN | 0 ETH | 0.00209433 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
18273219 | 409 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
StakedFrax
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.19; // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ============================ 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.19; // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ======================== 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 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; /// @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; // 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(); } /// @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() public virtual returns (uint256 _rewardToDistribute) { _rewardToDistribute = previewDistributeRewards(); // Only write to state if we need to update if (_rewardToDistribute != 0) { storedTotalAssets += _rewardToDistribute; } lastRewardsDistribution = block.timestamp; emit DistributeRewards({ rewardsToDistribute: _rewardToDistribute }); } /// @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 / 20) { _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) { distributeRewards(); _syncRewards(); _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) { distributeRewards(); _syncRewards(); _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) { distributeRewards(); _syncRewards(); _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) { distributeRewards(); _syncRewards(); _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": 1000000 }, "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":"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":"distributeRewards","outputs":[{"internalType":"uint256","name":"_rewardToDistribute","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":[{"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
6101206040818152346200072f57620033bd803803809162000022828662000750565b843982019160c0818403126200072f5780516001600160a01b0390818116908190036200072f576020838101519091906001600160401b03908181116200072f57876200007191870162000774565b9686860151908282116200072f576200008c91870162000774565b60608601519763ffffffff89168099036200072f5760a060808801519701519586168096036200072f57875163313ce56760e01b81528581600481885afa9081156200072457600091620006df575b50908051848111620004cf5780620000f5600054620007eb565b92601f938481116200068b575b508890848311600114620006205760009262000614575b50508160011b916000199060031b1c1916176000555b825190848211620004cf5781906001946200014b8654620007eb565b828111620005bc575b5088918311600114620005545760009262000548575b5050600019600383901b1c191690831b1782555b6080524660a0528651600091818354936200019985620007eb565b928383528883019589828216918260001462000528575050600114620004e5575b50620001c99250038262000750565b51902090865190848201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452888301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a083015260a0825260c082019082821090821117620004cf57875251902060c05260e0526101009485526200025d620008e4565b620002684262000896565b828201519164ffffffffff928392838216938491161480620004bd575b6200043a575b505050620002986200084c565b600854620002a64262000896565b8251908416919084168211156200042857620002c791508383511662000888565b915b81870151600090620002e69085906001600160d81b0316620008d0565b92828681835116920151169003908282116200041457507fb9d196a585c1a894f648393ec7d52cc59ff6d94191579d073ba32b0a74d7f7a69493926200033d9262000333921690620008af565b91600c54620008d0565b670de0b6b3a7640000620003556009548093620008d0565b048083116200040b575b508180620003f5575b5050426008558551908152a1600b80546001600160a01b031916919091179055600c5551612942918262000a7b833960805182611651015260a05182611e4f015260c05182611e76015260e05182818161087801528181610a0a01528181610d5001528181610f31015281816114da01528181612274015261257301525181818161119d01526122b30152f35b620004009162000828565b600955388162000368565b9150386200035f565b634e487b7160e01b81526011600452602490fd5b620004339162000888565b91620002c9565b7fc32a546ed958490e37f30335e501e0a39438cb650a4851bfd4b775490af29dad9282856060945116928369ffffffffff00000000006006549260281b169160018060501b03191617176006558960018060d81b0391015116908164ffffffffff60d81b600754161760075589519283528683015288820152a13880806200028b565b50828460065460281c16141562000285565b634e487b7160e01b600052604160045260246000fd5b8891506000805281600020906000915b8583106200050f575050620001c9935082010138620001ba565b80548388018501528694508a93909201918101620004f5565b60ff19168852620001c995151560051b8501019250389150620001ba9050565b0151905038806200016a565b90859350601f1983169184600052896000209260005b8b828210620005a557505084116200058b575b505050811b0182556200017e565b015160001960f88460031b161c191690553880806200057d565b83850151865589979095019493840193016200056a565b9091925085600052886000208380860160051c8201928b87106200060a575b91869589929594930160051c01915b828110620005fa57505062000154565b60008155869550889101620005ea565b92508192620005db565b01519050388062000119565b60008080528a81209350601f198516905b8b828210620006745750509084600195949392106200065a575b505050811b016000556200012f565b015160001960f88460031b161c191690553880806200064b565b600185968293968601518155019501930162000631565b90915060008052886000208480850160051c8201928b8610620006d5575b9085949392910160051c01905b818110620006c5575062000102565b60008155849350600101620006b6565b92508192620006a9565b8681813d83116200071c575b620006f7818362000750565b810103126200071857519060ff8216820362000715575038620000db565b80fd5b5080fd5b503d620006eb565b89513d6000823e3d90fd5b600080fd5b606081019081106001600160401b03821117620004cf57604052565b601f909101601f19168101906001600160401b03821190821017620004cf57604052565b919080601f840112156200072f578251906001600160401b038211620004cf5760405191602091620007b0601f8301601f191684018562000750565b8184528282870101116200072f5760005b818110620007d757508260009394955001015290565b8581018301518482018401528201620007c1565b90600182811c921680156200081d575b60208310146200080757565b634e487b7160e01b600052602260045260246000fd5b91607f1691620007fb565b919082018092116200083657565b634e487b7160e01b600052601160045260246000fd5b604051906200085b8262000734565b60065464ffffffffff808216845260289190911c1660208301526007546001600160d81b03166040830152565b919082039182116200083657565b650100000000008110156200072f5764ffffffffff1690565b8115620008ba570490565b634e487b7160e01b600052601260045260246000fd5b818102929181159184041417156200083657565b604051620008f28162000734565b600090818152816040602092828482015201526200090f6200084c565b9164ffffffffff918284511642111562000a745760e0516040516370a0823160e01b8152306004820152908290829060249082906001600160a01b03165afa801562000a6957839062000a2f575b6200096d91506009549062000888565b61010092620009a26200099c620009936200098a87514262000828565b875190620008af565b865190620008d0565b62000896565b938580861691620009b4428462000888565b9051906014820411620009f8575b505050600160d81b8210156200071557506001600160d81b0316604085015282620009ed4262000896565b169084015216815290565b62000a07919293965062000896565b160184811162000a1b5792388581620009c2565b634e487b7160e01b84526011600452602484fd5b508181813d831162000a61575b62000a48818362000750565b8101031262000a5d576200096d90516200095d565b8280fd5b503d62000a3c565b6040513d85823e3d90fd5b5050509056fe6040608081526004908136101561001557600080fd5b600091823560e01c91826301e1d114146119f957826306fdde031461193357826307a2d13a14611294578263090f3f50146118e0578263095ea7b3146118455782630a28a4771461180857826318160ddd146117cb57826323b872dd146116b25782632af98d6d14611675578263313ce56714611619578263358245fc146115de5782633644e515146115a3578263374010a4146114fe57826338d52e0f1461148f578263402d267d1461078557826345014095146113e157826348f76e0f146113245782634bc66f32146112d15782634cdad506146112945782634f8b4ae7146111c057826356caf605146111675782635ebae566146110ed57826361c1c5e9146110b05782636e553f651461106b5782636f4a2cd01461103057826370a082311461038557826375e077c314610ea25782637ecebe0014610e405782638f765d5914610dc457826394bf804d14610cd957826395d89b4114610bbe578263a9059cbb14610b11578263aaf5eb6814610ad0578263b3d7f6b914610a93578263b460af941461096a578263ba087652146107c7578263bd6f36031461078a578263c63d75b614610785578263c6e6f592146102c9578263ce96cb7714610722578263d505accf1461042e578263d71356e6146103eb578263d905777e14610385578263dd62ed3e1461030d578263ef8b30f7146102c957505063f6ccaad41461021e57600080fd5b346102c657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657610254611d13565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600a5416600a55600b54903373ffffffffffffffffffffffffffffffffffffffff83167f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68580a3163317600b5580f35b80fd5b83346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6575061030660209235611d85565b9051908152f35b91503461038157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038157602092829161034a611b84565b610352611bac565b9173ffffffffffffffffffffffffffffffffffffffff8092168452865283832091168252845220549051908152f35b8280fd5b8390346103e75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7578060209273ffffffffffffffffffffffffffffffffffffffff6103d7611b84565b1681526003845220549051908152f35b5080fd5b83346102c657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657610422612153565b5061042b6123fc565b80f35b8390346103e75760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757610467611b84565b90610470611bac565b9160443560643592610480611c31565b924285106106c557610490611e4a565b9573ffffffffffffffffffffffffffffffffffffffff8092169586895260209560058752848a209889549960018b01905585519285898501957f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c987528b89870152169a8b606086015288608086015260a085015260c084015260c0835260e0830167ffffffffffffffff948482108683111761069857818852845190206101008501927f19010000000000000000000000000000000000000000000000000000000000008452610102860152610122850152604281526101608401948186109086111761066c57848752519020835260ff1661018082015260a4356101a082015260c4356101c0909101528780528490889060809060015afa15610662578651169687151580610659575b156105fe5786977f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259596975283528087208688528352818188205551908152a380f35b8360649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152fd5b508488146105bb565b81513d88823e3d90fd5b60248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5060248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b60648860208451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152fd5b8390346103e75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576103068160209373ffffffffffffffffffffffffffffffffffffffff610777611b84565b168152600385522054611daa565b611bcf565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576020906008549051908152f35b9083346102c6576107d736611c41565b6107e393929193612153565b506107ec6123fc565b73ffffffffffffffffffffffffffffffffffffffff90818116938433036108ff575b5061081883611daa565b9586156108a2575092826020979592610844889561089c9761083c88600954611e0e565b60095561278d565b865191858352898301528316907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db873392a47f00000000000000000000000000000000000000000000000000000000000000006127f4565b51908152f35b60649060208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600b60248201527f5a45524f5f4153534554530000000000000000000000000000000000000000006044820152fd5b848152866020528781203382526020528780822054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610945575b50505061080e565b61094e91611e0e565b918681528860205281812033825260205220558787818561093d565b8390346103e75761089c60209361098036611c41565b9590919261098c612153565b506109956123fc565b6109d56109a185611dec565b809873ffffffffffffffffffffffffffffffffffffffff938985831696873303610a2e575b50505061083c87600954611e0e565b85519084825287898301528316907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db873392a47f00000000000000000000000000000000000000000000000000000000000000006127f4565b878152828e528181203382528e5281812054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610a70575b50506109c6565b610a7991611e0e565b928882528e528181203382528e5220558b89818085610a69565b83346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6575061030660209235611dcb565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e75760209051670de0b6b3a76400008152f35b8390346103e757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757602091610b4c611b84565b8273ffffffffffffffffffffffffffffffffffffffff6024359233855260038752828520610b7b858254611e0e565b90551692838152600386522081815401905582519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef843392a35160018152f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757805190826001805491610c0083611a3f565b80865292828116908115610c935750600114610c37575b505050610c2982610c33940383611add565b5191829182611b1e565b0390f35b94508085527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b828610610c7b57505050610c29826020610c339582010194610c17565b80546020878701810191909152909501948101610c5e565b610c33975086935060209250610c299491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b82010194610c17565b91503461038157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038157602092503590610d17611bac565b91610d20612153565b50610d296123fc565b73ffffffffffffffffffffffffffffffffffffffff610d4782611dcb565b93610d748530337f00000000000000000000000000000000000000000000000000000000000000006126bd565b610d7e8382612657565b8351928584528684015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7833392a3610dbb82600954612146565b60095551908152f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757606090610dff6121f2565b907affffffffffffffffffffffffffffffffffffffffffffffffffffff8180519364ffffffffff808251168652602082015116602086015201511690820152f35b8390346103e75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7578060209273ffffffffffffffffffffffffffffffffffffffff610e92611b84565b1681526005845220549051908152f35b83346102c65760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6578235610edc611bac565b916064359081151582036102c657610ef2611c31565b911561102a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b15610381579060e48884809460ff8b5198899687957fd505accf00000000000000000000000000000000000000000000000000000000875233908701523060248701526044860152604435606486015216608484015260a43560a484015260c43560c48401525af1801561101e57610fd3575b6020856103068686612545565b67ffffffffffffffff8211610ff2575083526020935061030685610fc6565b806041877f4e487b71000000000000000000000000000000000000000000000000000000006024945252fd5b508451903d90823e3d90fd5b82610f1a565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757602090610306612153565b83346102c657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657506103066020926110a9611bac565b9035612545565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576020906009549051908152f35b83346102c657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65750600654600754915164ffffffffff808316825260289290921c90911660208201527affffffffffffffffffffffffffffffffffffffffffffffffffffff9091166040820152606090f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b83346102c657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576111f7611ca1565b6111ff611d13565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600a5416600a55600b548273ffffffffffffffffffffffffffffffffffffffff821681817f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8280a37f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68280a316600b5580f35b83346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6575061030660209235611daa565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e75760209073ffffffffffffffffffffffffffffffffffffffff600b54169051908152f35b9150346103815760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038157359061135f611ca1565b611367612153565b506113706123fc565b67ffffffffffffffff8083116113b9575b507f05d530f0fd6974b7d995fd3b71870f5301bb9fe086180bdd0bd36526728f5c6b90600c548151908152836020820152a1600c5580f35b91507f05d530f0fd6974b7d995fd3b71870f5301bb9fe086180bdd0bd36526728f5c6b611381565b83346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657611419611b84565b611421611ca1565b73ffffffffffffffffffffffffffffffffffffffff80911690817fffffffffffffffffffffffff0000000000000000000000000000000000000000600a541617600a55600b54167f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8380a380f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b83346102c6577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601608081126103e7576060136102c65781519261154284611a92565b3564ffffffffff90818116810361038157845260243590811681036103e7576020840152604435907affffffffffffffffffffffffffffffffffffffffffffffffffffff821682036102c657508261030691836020950152606435906128bb565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757602090610306611e4a565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576020906103066120e4565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576020905160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757602090600c549051908152f35b83346102c65760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576116ea611b84565b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef611713611bac565b946044358573ffffffffffffffffffffffffffffffffffffffff80951694858752602098848a958652838920338a52865283892054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036117a8575b50505086885260038552828820611789858254611e0e565b9055169586815260038452208181540190558551908152a35160018152f35b6117b191611e0e565b90888a528652838920338a528652838920558a8085611771565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576020906002549051908152f35b83346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6575061030660209235611dec565b91503461038157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038157602092611880611b84565b9183602435928392338252875273ffffffffffffffffffffffffffffffffffffffff8282209516948582528752205582519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925843392a35160018152f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e75760209073ffffffffffffffffffffffffffffffffffffffff600a54169051908152f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e75780519082805461197281611a3f565b80855291600191808316908115610c93575060011461199d57505050610c2982610c33940383611add565b80809650527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8286106119e157505050610c29826020610c339582010194610c17565b805460208787018101919091529095019481016119c4565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757602090610306611a376120e4565b600954612146565b90600182811c92168015611a88575b6020831014611a5957565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611a4e565b6060810190811067ffffffffffffffff821117611aae57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611aae57604052565b60208082528251818301819052939260005b858110611b70575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201611b30565b6004359073ffffffffffffffffffffffffffffffffffffffff82168203611ba757565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff82168203611ba757565b34611ba75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112611ba757611c06611b84565b5060206040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8152f35b6084359060ff82168203611ba757565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6060910112611ba7576004359073ffffffffffffffffffffffffffffffffffffffff906024358281168103611ba757916044359081168103611ba75790565b73ffffffffffffffffffffffffffffffffffffffff600b5416803303611cc45750565b6040517f443dc2b400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b73ffffffffffffffffffffffffffffffffffffffff600a5416803303611d365750565b6040517fbe5a953700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b60025480611d91575090565b90611da791611da1611a376120e4565b91612027565b90565b60025480611db6575090565b611da791611dc5611a376120e4565b90612027565b60025480611dd7575090565b611da791611de6611a376120e4565b9061205b565b60025480611df8575090565b90611da791611e08611a376120e4565b9161205b565b91908203918211611e1b57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000467f000000000000000000000000000000000000000000000000000000000000000003611e9857507f000000000000000000000000000000000000000000000000000000000000000090565b60405181548291611ea882611a3f565b8082528160209485820194600190878282169182600014611feb575050600114611f92575b50611eda92500382611add565b51902091604051918201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f845260408301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a083015260a0825260c082019082821067ffffffffffffffff831117611f65575060405251902090565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526041600452fd5b87805286915087907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b858310611fd3575050611eda935082010138611ecd565b80548388018501528694508893909201918101611fbc565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168852611eda95151560051b8501019250389150611ecd9050565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215611ba757020490565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215611ba7570290808204910615150190565b604051906120a482611a92565b8160065464ffffffffff90818116835260281c16602082015260407affffffffffffffffffffffffffffffffffffffffffffffffffffff60075416910152565b611da76120ef612097565b6008546120fb4261212e565b825164ffffffffff92918316908316811115612124575061211e91835116611e0e565b906128bb565b61211e9250611e0e565b65010000000000811015611ba75764ffffffffff1690565b91908201809211611e1b57565b61215b6120e4565b9081612192575b426008557fb9d196a585c1a894f648393ec7d52cc59ff6d94191579d073ba32b0a74d7f7a66020604051848152a1565b61219e82600954612146565b600955612162565b81156121b0570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b81810292918115918404141715611e1b57565b6040516121fe81611a92565b60009081815281604060209282848201520152612219612097565b9164ffffffffff91828451164211156123f6576040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152818160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa80156123eb5783906123bc575b6122b1915060095490611e0e565b7f0000000000000000000000000000000000000000000000000000000000000000926122f76122f2856122ed816122e88142612146565b6121a6565b6121df565b61212e565b9385808616916123074284611e0e565b6014820411612370575b5050507b010000000000000000000000000000000000000000000000000000008210156102c657507affffffffffffffffffffffffffffffffffffffffffffffffffffff166040850152826123654261212e565b169084015216815290565b61237d919293965061212e565b160184811161238f5792388581612311565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b508181813d83116123e4575b6123d28183611add565b81010312610381576122b190516122a3565b503d6123c8565b6040513d85823e3d90fd5b50505090565b6124046121f2565b61240d4261212e565b602082015164ffffffffff808216928116831480612534575b612431575b50505050565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff604085612528937fc32a546ed958490e37f30335e501e0a39438cb650a4851bfd4b775490af29dad97511694857fffffffffffffffffffffffffffffffffffffffffffff0000000000000000000069ffffffffff00000000006006549360281b1692161717600655015116807fffffffffff0000000000000000000000000000000000000000000000000000006007541617600755604051938493849193927affffffffffffffffffffffffffffffffffffffffffffffffffffff90604092606085019664ffffffffff809216865216602085015216910152565b0390a13880808061242b565b50828160065460281c161415612426565b9061254e612153565b506125576123fc565b61256082611d85565b9182156125f9576125f3916125978230337f00000000000000000000000000000000000000000000000000000000000000006126bd565b6125a18482612657565b73ffffffffffffffffffffffffffffffffffffffff6040519183835285602084015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d760403392a3600954612146565b60095590565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f5348415245530000000000000000000000000000000000000000006044820152fd5b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602073ffffffffffffffffffffffffffffffffffffffff60009361269e86600254612146565b60025516938484526003825260408420818154019055604051908152a3565b9160008093602095606494604051947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216600487015216602485015260448401525af13d15601f3d116001600051141617161561272f57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602073ffffffffffffffffffffffffffffffffffffffff600094169283855260038252604085206127e1828254611e0e565b90558060025403600255604051908152a3565b6000918260449260209573ffffffffffffffffffffffffffffffffffffffff604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af13d15601f3d116001600051141617161561285d57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b9190916128e9837affffffffffffffffffffffffffffffffffffffffffffffffffffff6040840151166121df565b64ffffffffff918260208183511692015116900391808311611e1b576129216129339261292a92670de0b6b3a76400009516906121a6565b94600c546121df565b600954906121df565b0480831161293e5750565b915056000000000000000000000000853d955acef822db058eb8505911ed77f175b99e00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000000000000b4241eae000000000000000000000000831822660572bd54ebaa065c2acef662a6277d40000000000000000000000000000000000000000000000000000000000000000b5374616b6564204672617800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057346524158000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6040608081526004908136101561001557600080fd5b600091823560e01c91826301e1d114146119f957826306fdde031461193357826307a2d13a14611294578263090f3f50146118e0578263095ea7b3146118455782630a28a4771461180857826318160ddd146117cb57826323b872dd146116b25782632af98d6d14611675578263313ce56714611619578263358245fc146115de5782633644e515146115a3578263374010a4146114fe57826338d52e0f1461148f578263402d267d1461078557826345014095146113e157826348f76e0f146113245782634bc66f32146112d15782634cdad506146112945782634f8b4ae7146111c057826356caf605146111675782635ebae566146110ed57826361c1c5e9146110b05782636e553f651461106b5782636f4a2cd01461103057826370a082311461038557826375e077c314610ea25782637ecebe0014610e405782638f765d5914610dc457826394bf804d14610cd957826395d89b4114610bbe578263a9059cbb14610b11578263aaf5eb6814610ad0578263b3d7f6b914610a93578263b460af941461096a578263ba087652146107c7578263bd6f36031461078a578263c63d75b614610785578263c6e6f592146102c9578263ce96cb7714610722578263d505accf1461042e578263d71356e6146103eb578263d905777e14610385578263dd62ed3e1461030d578263ef8b30f7146102c957505063f6ccaad41461021e57600080fd5b346102c657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657610254611d13565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600a5416600a55600b54903373ffffffffffffffffffffffffffffffffffffffff83167f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68580a3163317600b5580f35b80fd5b83346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6575061030660209235611d85565b9051908152f35b91503461038157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038157602092829161034a611b84565b610352611bac565b9173ffffffffffffffffffffffffffffffffffffffff8092168452865283832091168252845220549051908152f35b8280fd5b8390346103e75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7578060209273ffffffffffffffffffffffffffffffffffffffff6103d7611b84565b1681526003845220549051908152f35b5080fd5b83346102c657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657610422612153565b5061042b6123fc565b80f35b8390346103e75760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757610467611b84565b90610470611bac565b9160443560643592610480611c31565b924285106106c557610490611e4a565b9573ffffffffffffffffffffffffffffffffffffffff8092169586895260209560058752848a209889549960018b01905585519285898501957f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c987528b89870152169a8b606086015288608086015260a085015260c084015260c0835260e0830167ffffffffffffffff948482108683111761069857818852845190206101008501927f19010000000000000000000000000000000000000000000000000000000000008452610102860152610122850152604281526101608401948186109086111761066c57848752519020835260ff1661018082015260a4356101a082015260c4356101c0909101528780528490889060809060015afa15610662578651169687151580610659575b156105fe5786977f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259596975283528087208688528352818188205551908152a380f35b8360649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152fd5b508488146105bb565b81513d88823e3d90fd5b60248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5060248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b60648860208451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152fd5b8390346103e75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576103068160209373ffffffffffffffffffffffffffffffffffffffff610777611b84565b168152600385522054611daa565b611bcf565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576020906008549051908152f35b9083346102c6576107d736611c41565b6107e393929193612153565b506107ec6123fc565b73ffffffffffffffffffffffffffffffffffffffff90818116938433036108ff575b5061081883611daa565b9586156108a2575092826020979592610844889561089c9761083c88600954611e0e565b60095561278d565b865191858352898301528316907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db873392a47f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e6127f4565b51908152f35b60649060208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600b60248201527f5a45524f5f4153534554530000000000000000000000000000000000000000006044820152fd5b848152866020528781203382526020528780822054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610945575b50505061080e565b61094e91611e0e565b918681528860205281812033825260205220558787818561093d565b8390346103e75761089c60209361098036611c41565b9590919261098c612153565b506109956123fc565b6109d56109a185611dec565b809873ffffffffffffffffffffffffffffffffffffffff938985831696873303610a2e575b50505061083c87600954611e0e565b85519084825287898301528316907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db873392a47f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e6127f4565b878152828e528181203382528e5281812054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610a70575b50506109c6565b610a7991611e0e565b928882528e528181203382528e5220558b89818085610a69565b83346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6575061030660209235611dcb565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e75760209051670de0b6b3a76400008152f35b8390346103e757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757602091610b4c611b84565b8273ffffffffffffffffffffffffffffffffffffffff6024359233855260038752828520610b7b858254611e0e565b90551692838152600386522081815401905582519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef843392a35160018152f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757805190826001805491610c0083611a3f565b80865292828116908115610c935750600114610c37575b505050610c2982610c33940383611add565b5191829182611b1e565b0390f35b94508085527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b828610610c7b57505050610c29826020610c339582010194610c17565b80546020878701810191909152909501948101610c5e565b610c33975086935060209250610c299491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b82010194610c17565b91503461038157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038157602092503590610d17611bac565b91610d20612153565b50610d296123fc565b73ffffffffffffffffffffffffffffffffffffffff610d4782611dcb565b93610d748530337f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e6126bd565b610d7e8382612657565b8351928584528684015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7833392a3610dbb82600954612146565b60095551908152f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757606090610dff6121f2565b907affffffffffffffffffffffffffffffffffffffffffffffffffffff8180519364ffffffffff808251168652602082015116602086015201511690820152f35b8390346103e75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7578060209273ffffffffffffffffffffffffffffffffffffffff610e92611b84565b1681526005845220549051908152f35b83346102c65760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6578235610edc611bac565b916064359081151582036102c657610ef2611c31565b911561102a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e16803b15610381579060e48884809460ff8b5198899687957fd505accf00000000000000000000000000000000000000000000000000000000875233908701523060248701526044860152604435606486015216608484015260a43560a484015260c43560c48401525af1801561101e57610fd3575b6020856103068686612545565b67ffffffffffffffff8211610ff2575083526020935061030685610fc6565b806041877f4e487b71000000000000000000000000000000000000000000000000000000006024945252fd5b508451903d90823e3d90fd5b82610f1a565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757602090610306612153565b83346102c657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657506103066020926110a9611bac565b9035612545565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576020906009549051908152f35b83346102c657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65750600654600754915164ffffffffff808316825260289290921c90911660208201527affffffffffffffffffffffffffffffffffffffffffffffffffffff9091166040820152606090f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757602090517f0000000000000000000000000000000000000000000000000000000000093a808152f35b83346102c657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576111f7611ca1565b6111ff611d13565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600a5416600a55600b548273ffffffffffffffffffffffffffffffffffffffff821681817f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8280a37f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68280a316600b5580f35b83346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6575061030660209235611daa565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e75760209073ffffffffffffffffffffffffffffffffffffffff600b54169051908152f35b9150346103815760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038157359061135f611ca1565b611367612153565b506113706123fc565b67ffffffffffffffff8083116113b9575b507f05d530f0fd6974b7d995fd3b71870f5301bb9fe086180bdd0bd36526728f5c6b90600c548151908152836020820152a1600c5580f35b91507f05d530f0fd6974b7d995fd3b71870f5301bb9fe086180bdd0bd36526728f5c6b611381565b83346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657611419611b84565b611421611ca1565b73ffffffffffffffffffffffffffffffffffffffff80911690817fffffffffffffffffffffffff0000000000000000000000000000000000000000600a541617600a55600b54167f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8380a380f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e168152f35b83346102c6577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601608081126103e7576060136102c65781519261154284611a92565b3564ffffffffff90818116810361038157845260243590811681036103e7576020840152604435907affffffffffffffffffffffffffffffffffffffffffffffffffffff821682036102c657508261030691836020950152606435906128bb565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757602090610306611e4a565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576020906103066120e4565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576020905160ff7f0000000000000000000000000000000000000000000000000000000000000012168152f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757602090600c549051908152f35b83346102c65760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576116ea611b84565b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef611713611bac565b946044358573ffffffffffffffffffffffffffffffffffffffff80951694858752602098848a958652838920338a52865283892054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036117a8575b50505086885260038552828820611789858254611e0e565b9055169586815260038452208181540190558551908152a35160018152f35b6117b191611e0e565b90888a528652838920338a528652838920558a8085611771565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e7576020906002549051908152f35b83346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6575061030660209235611dec565b91503461038157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038157602092611880611b84565b9183602435928392338252875273ffffffffffffffffffffffffffffffffffffffff8282209516948582528752205582519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925843392a35160018152f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e75760209073ffffffffffffffffffffffffffffffffffffffff600a54169051908152f35b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e75780519082805461197281611a3f565b80855291600191808316908115610c93575060011461199d57505050610c2982610c33940383611add565b80809650527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8286106119e157505050610c29826020610c339582010194610c17565b805460208787018101919091529095019481016119c4565b8390346103e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e757602090610306611a376120e4565b600954612146565b90600182811c92168015611a88575b6020831014611a5957565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611a4e565b6060810190811067ffffffffffffffff821117611aae57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611aae57604052565b60208082528251818301819052939260005b858110611b70575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201611b30565b6004359073ffffffffffffffffffffffffffffffffffffffff82168203611ba757565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff82168203611ba757565b34611ba75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112611ba757611c06611b84565b5060206040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8152f35b6084359060ff82168203611ba757565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6060910112611ba7576004359073ffffffffffffffffffffffffffffffffffffffff906024358281168103611ba757916044359081168103611ba75790565b73ffffffffffffffffffffffffffffffffffffffff600b5416803303611cc45750565b6040517f443dc2b400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b73ffffffffffffffffffffffffffffffffffffffff600a5416803303611d365750565b6040517fbe5a953700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b60025480611d91575090565b90611da791611da1611a376120e4565b91612027565b90565b60025480611db6575090565b611da791611dc5611a376120e4565b90612027565b60025480611dd7575090565b611da791611de6611a376120e4565b9061205b565b60025480611df8575090565b90611da791611e08611a376120e4565b9161205b565b91908203918211611e1b57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000467f000000000000000000000000000000000000000000000000000000000000000103611e9857507f8985ed3e454034d145e3bab613cff20d69afee6ef4c4dda8301dcc4f65e7f38890565b60405181548291611ea882611a3f565b8082528160209485820194600190878282169182600014611feb575050600114611f92575b50611eda92500382611add565b51902091604051918201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f845260408301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a083015260a0825260c082019082821067ffffffffffffffff831117611f65575060405251902090565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526041600452fd5b87805286915087907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b858310611fd3575050611eda935082010138611ecd565b80548388018501528694508893909201918101611fbc565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168852611eda95151560051b8501019250389150611ecd9050565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215611ba757020490565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215611ba7570290808204910615150190565b604051906120a482611a92565b8160065464ffffffffff90818116835260281c16602082015260407affffffffffffffffffffffffffffffffffffffffffffffffffffff60075416910152565b611da76120ef612097565b6008546120fb4261212e565b825164ffffffffff92918316908316811115612124575061211e91835116611e0e565b906128bb565b61211e9250611e0e565b65010000000000811015611ba75764ffffffffff1690565b91908201809211611e1b57565b61215b6120e4565b9081612192575b426008557fb9d196a585c1a894f648393ec7d52cc59ff6d94191579d073ba32b0a74d7f7a66020604051848152a1565b61219e82600954612146565b600955612162565b81156121b0570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b81810292918115918404141715611e1b57565b6040516121fe81611a92565b60009081815281604060209282848201520152612219612097565b9164ffffffffff91828451164211156123f6576040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152818160248173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e165afa80156123eb5783906123bc575b6122b1915060095490611e0e565b7f0000000000000000000000000000000000000000000000000000000000093a80926122f76122f2856122ed816122e88142612146565b6121a6565b6121df565b61212e565b9385808616916123074284611e0e565b6014820411612370575b5050507b010000000000000000000000000000000000000000000000000000008210156102c657507affffffffffffffffffffffffffffffffffffffffffffffffffffff166040850152826123654261212e565b169084015216815290565b61237d919293965061212e565b160184811161238f5792388581612311565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b508181813d83116123e4575b6123d28183611add565b81010312610381576122b190516122a3565b503d6123c8565b6040513d85823e3d90fd5b50505090565b6124046121f2565b61240d4261212e565b602082015164ffffffffff808216928116831480612534575b612431575b50505050565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff604085612528937fc32a546ed958490e37f30335e501e0a39438cb650a4851bfd4b775490af29dad97511694857fffffffffffffffffffffffffffffffffffffffffffff0000000000000000000069ffffffffff00000000006006549360281b1692161717600655015116807fffffffffff0000000000000000000000000000000000000000000000000000006007541617600755604051938493849193927affffffffffffffffffffffffffffffffffffffffffffffffffffff90604092606085019664ffffffffff809216865216602085015216910152565b0390a13880808061242b565b50828160065460281c161415612426565b9061254e612153565b506125576123fc565b61256082611d85565b9182156125f9576125f3916125978230337f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e6126bd565b6125a18482612657565b73ffffffffffffffffffffffffffffffffffffffff6040519183835285602084015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d760403392a3600954612146565b60095590565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f5348415245530000000000000000000000000000000000000000006044820152fd5b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602073ffffffffffffffffffffffffffffffffffffffff60009361269e86600254612146565b60025516938484526003825260408420818154019055604051908152a3565b9160008093602095606494604051947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216600487015216602485015260448401525af13d15601f3d116001600051141617161561272f57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602073ffffffffffffffffffffffffffffffffffffffff600094169283855260038252604085206127e1828254611e0e565b90558060025403600255604051908152a3565b6000918260449260209573ffffffffffffffffffffffffffffffffffffffff604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af13d15601f3d116001600051141617161561285d57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b9190916128e9837affffffffffffffffffffffffffffffffffffffffffffffffffffff6040840151166121df565b64ffffffffff918260208183511692015116900391808311611e1b576129216129339261292a92670de0b6b3a76400009516906121a6565b94600c546121df565b600954906121df565b0480831161293e5750565b915056
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000853d955acef822db058eb8505911ed77f175b99e00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000000000000b4241eae000000000000000000000000831822660572bd54ebaa065c2acef662a6277d40000000000000000000000000000000000000000000000000000000000000000b5374616b6564204672617800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057346524158000000000000000000000000000000000000000000000000000000
-----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] : 5374616b65642046726178000000000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [9] : 7346524158000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $0.995645 | 45,914.3538 | $45,714.4 |
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.