Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Cross-Chain Transactions
Loading...
Loading
Contract Name:
FraxStaker
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 100000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// =========================== Frax Staker ============================
// ====================================================================
import { OwnedUpgradeable } from "../Flox/OwnedUpgradeable.sol";
import { FraxStakerStructs } from "./interfaces/FraxStakerStructs.sol";
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable-5/utils/ReentrancyGuardUpgradeable.sol";
/**
* @title FraxStaker
* @author Frax Finance
* @notice A smart contract that allows users to stake FRAX.
* @dev Delegating one's stake doesn't transfer the balance to the delegatee, so the full deposit can be retrieved by
* the staker.
* @dev This smart contract supports single-hop fractional delegation. This means that a staker can delegate their stake,
* but the delegatee cannot further delegate the accumulated delegations. Fractional delegation means that a
* staker can delegate a part of their stake to multiple delegatees.
* @dev If they want to delegate their stake, they can only do so when they don't have an active stake.
* @dev When the user initiates the withdrawal, their balance should start reporting as 0 (or their delegation shoud be
* revoked). They can only withdraw their FRAX after the cooldown period passes.
* @dev User can't have a stake for themselves as well as a delegated stake at the same time.
* @dev We are able to freeze, unfreeze, slash, and blacklist users. Frozen stakers should have a balance of 0 and
* blacklisted stakers should be ejected and shouldn't be able to stake again.
* @dev May be used for validators in the future.
* @dev Frax Reviewer(s) / Contributor(s)
* Jan Turk: https://github.com/ThunderDeliverer
* Travis Moore: https://github.com/FortisFortuna
* Sam Kazemian: https://github.com/samkazemian
* Dennis Denett: https://github.com/denett
* Carter Carlson: https://github.com/pegahcarter
*/
contract FraxStaker is OwnedUpgradeable, FraxStakerStructs, ReentrancyGuardUpgradeable {
/// @notice Address that is the recipient of slashed stakes.
address public SLASHING_RECIPIENT;
/**
* @notice Used to track the blacklisted stakers.
* @dev staker Address of the staker.
* @dev isBlacklisted True if the address is blacklisted.
*/
mapping(address staker => bool isBlacklisted) public blacklist;
/**
* @notice Used to keep track of the frozen stakers.
* @dev address Address of the staker.
* @dev isFrozen Whether the staker's stake is frozen or not.
*/
mapping(address staker => bool isFrozen) public isFrozenStaker;
/**
* @notice Used to track the Frax contributors.
* @dev contributor Address of the Frax contributor.
* @dev isContributor True if the address is a Frax contributor.
*/
mapping(address contributor => bool isContributor) public isFraxContributor;
/**
* @notice Used to track the Frax sentinels.
* @dev Frax sentinels are addresses that can freeze, unfreeze, slash, and blacklist stakers.
* @dev sentinel Address of the sentinel.
* @dev isSentinel True if the address is a sentinel.
*/
mapping(address sentinel => bool isSentinel) public isFraxSentinel;
/**
* @notice Used to track the stakes of each user.
* @dev staker Address of the staker.
* @dev stake Stake of the user.
*/
mapping(address staker => Stake stake) public stakes;
/// @notice The cooldown required before a staker can withdraw their stake.
uint256 public withdrawalCooldown;
/// @notice Version of this smart contract.
string public version;
/// @notice Variable to track if the contract is paused.
bool public isPaused;
/// @notice Used to make sure the contract is initialized only once.
bool private _initialized;
/// @dev reserve extra storage for future upgrades
uint256[50] private __gap;
/**
* @notice The constructor disables the direct use of the implementation smart contract.
*/
constructor() {
__Owned_init(address(this));
_initialized = true;
}
/**
* @notice Used to initialize the smart contract.
* @dev The initial owner is set as the deployer of the smart contract.
* @dev The initial withdrawal cooldown is set for 90 days.
* @dev The initial slashing recipient update delay is set for 7 days.
* @param _owner Address of the owner of the smart contract
* @param _version Version of this smart contract
*/
function initialize(address _owner, string memory _version) public initializer {
if (_initialized) revert AlreadyInitialized();
_initialized = true;
SLASHING_RECIPIENT = address(0xdead);
version = _version;
withdrawalCooldown = 90 days;
__Owned_init(_owner);
__ReentrancyGuard_init();
}
/**
* @notice Returns the balance of the specified address.
* @dev The balance is zero if the address is blacklisted, frozen, or has initiated a withdrawal.
* @dev This is a sum of the staker's stake and the amount delegated to them, minus the amount they have delegated
* to others.
* @dev Even if the user's balance is negated due to the user having initiated a withdrawal, the user can still
* receive the delegated balance.
* @param account Address to check the balance of
* @return The balance of the specified address
*/
function balanceOf(address account) public view returns (uint256) {
Stake memory stake = stakes[account];
uint256 userBalance;
if (blacklist[account] || isFrozenStaker[account]) {
return 0;
} else if (stake.initiatedWithdrawal) {
userBalance = 0;
} else {
userBalance = stake.amountStaked - stake.amountDelegated;
}
return (userBalance + stake.amountDelegatedToStaker);
}
/**
* @notice Returns the total supply of FRAX staked in the contract.
* @return The total supply of FRAX staked in the contract
*/
function totalSupply() public view returns (uint256) {
return address(this).balance;
}
/**
* @notice Stakes FRAX for the caller.
* @dev Reverts if the contract is paused.
* @dev Reverts if the caller's stake is frozen.
* @dev Reverts if the caller is blacklisted.
* @dev The amount of FRAX to stake is the value sent with the transaction.
* @dev If the caller delegates their stake, this will increase the delegated stake instead of creating a separate
* stake for them.
*/
function stakeFrax() public payable {
_onlyWhenOperational();
_onlyWhenNotFrozen(msg.sender);
_onlyWhenNotBlacklisted(msg.sender);
_stake(msg.value, msg.sender);
Stake memory stake = stakes[msg.sender];
if (stake.delegatee != address(0)) {
_onlyWhenNotFrozen(stake.delegatee);
_onlyWhenNotBlacklisted(stake.delegatee);
_delegate(msg.sender, stake.delegatee, msg.value);
}
}
/**
* @notice Used to donate your FRAX to the recipient's stake.
* @dev Reverts if the contract is paused.
* @dev Reverts if the recipient is frozen or blacklisted.
* @dev Reverts if there is no FRAX sent with the transaction.
* @dev Reverts if the recipient has initiated a withdrawal.
* @dev This can only be executed when the recipient has an active stake. This constraint is to ensure that the
* recipient can delegate their stake if they want to do so and that the ability to delegate is not disabled for
* the user that received the donation.
* @param recipient Address of the recipient to donate the stake to
*/
function donateStake(address recipient) external payable {
_onlyWhenOperational();
_onlyWhenNotFrozen(recipient);
_onlyWhenNotBlacklisted(recipient);
if (msg.value == 0) revert InvalidStakeAmount();
Stake storage recipientStake = stakes[recipient];
if (recipientStake.initiatedWithdrawal) revert WithdrawalInitiated();
if (recipientStake.amountStaked == 0) revert InvalidStakeAmount();
_stake(msg.value, recipient);
if (recipientStake.delegatee != address(0)) {
_onlyWhenNotFrozen(recipientStake.delegatee);
_onlyWhenNotBlacklisted(recipientStake.delegatee);
_delegate(recipient, recipientStake.delegatee, msg.value);
}
emit StakeDonation(msg.sender, recipient, msg.value);
}
/**
* @notice Stakes the caller's FRAX, then delegates to someone else (delegatee). Note they are not adding to the
* delegatee's own position, if any.
* @dev Reverts if the contract is paused.
* @dev Reverts if the staker's stake is frozen.
* @dev Reverts if the delegatee's stake is frozen.
* @dev Reverts if the staker is blacklisted.
* @dev Reverts if the delegatee is blacklisted.
* @dev The amount of FRAX to stake is the value sent with the transaction.
* @dev This overloaded function allows the staker to delegate their stake to another staker.
* @dev If another delegation exists for the staker, this function will revert. They should remove that delegation first
* @param _delegatee Address of the delegatee
*/
function stakeFrax(address _delegatee) external payable {
_onlyWhenOperational();
_onlyWhenNotFrozen(msg.sender);
_onlyWhenNotFrozen(_delegatee);
_onlyWhenNotBlacklisted(msg.sender);
_onlyWhenNotBlacklisted(_delegatee);
// Make sure that the staker doesn't have a non-delegated stake
if (stakes[msg.sender].amountStaked != stakes[msg.sender].amountDelegated) {
revert NonDelegatedStakeAlreadyExists();
}
_stake(msg.value, msg.sender);
_delegate(msg.sender, _delegatee, msg.value);
}
/**
* @notice Initiates the withdrawal of the caller's stake.
* @dev Reverts if the contract is paused.
* @dev Reverts if the caller's stake is frozen.
* @dev Reverts if the caller is blacklisted.
*/
function initiateWithdrawal() external {
_onlyWhenOperational();
_onlyWhenNotFrozen(msg.sender);
_onlyWhenNotBlacklisted(msg.sender);
_revokeDelegation(msg.sender);
_initiateWithdrawal(msg.sender);
}
/**
* @notice Withdraws the staker's stake.
* @dev Reverts if the contract is paused.
* @dev Reverts if the staker's stake is frozen.
* @dev This operation will revoke all delegations of the staker's stake. This is only done in this stepto ensure
* the delegations can't be instantly revoked.
* @dev Blacklisted stakers can withdraw their remaining stake.
*/
function withdrawStake() external nonReentrant {
_onlyWhenOperational();
_onlyWhenNotFrozen(msg.sender);
_withdrawStake(msg.sender);
}
/**
* @notice Allows a Frax contributor to force the withdrawal of staker's stake.
* @dev This can only be called by a Frax contributor and is used to exit stakes that have passed the withdrawal
* cooldown period.
* @dev Reverts if the staker's stake is frozen.
* @dev This revokes the full amount of the delegated stake.
* @param _staker Address of the staker to force withdraw
*/
function forceStakeWithdrawal(address _staker) external nonReentrant {
_onlyFraxContributor();
_onlyWhenNotFrozen(_staker);
_withdrawStake(_staker);
}
/**
* @notice Adds a Frax contributor.
* @dev Can only be called by the owner.
* @param _contributor The address of the Frax contributor to add
*/
function addFraxContributor(address _contributor) external {
_onlyOwner();
if (isFraxContributor[_contributor]) revert AlreadyFraxContributor();
isFraxContributor[_contributor] = true;
emit FraxContributorAdded(_contributor);
}
/**
* @notice Removes a Frax contributor.
* @dev Can only be called by the owner.
* @param _contributor The address of the Frax contributor to remove
*/
function removeFraxContributor(address _contributor) external {
_onlyOwner();
if (!isFraxContributor[_contributor]) revert NotFraxContributor();
isFraxContributor[_contributor] = false;
emit FraxContributorRemoved(_contributor);
}
/**
* @notice Adds a Frax sentinel.
* @dev Can only be called by the owner.
* @param _sentinel The address of the Frax sentinel to add
*/
function addFraxSentinel(address _sentinel) external {
_onlyOwner();
if (isFraxSentinel[_sentinel]) revert AlreadyFraxSentinel();
isFraxSentinel[_sentinel] = true;
emit FraxSentinelAdded(_sentinel);
}
/**
* @notice Removes a Frax sentinel.
* @dev Can only be called by the owner.
* @param _sentinel The address of the Frax sentinel to remove
*/
function removeFraxSentinel(address _sentinel) external {
_onlyOwner();
if (!isFraxSentinel[_sentinel]) revert NotFraxSentinel();
isFraxSentinel[_sentinel] = false;
emit FraxSentinelRemoved(_sentinel);
}
/**
* @notice Updates the withdrawal cooldown duration.
* @dev Can only be called by the owner.
* @param _withdrawalCooldown The new withdrawal cooldown
*/
function updateWithdrawalCooldown(uint256 _withdrawalCooldown) external {
_onlyOwner();
uint256 oldWithdrawalCooldown = withdrawalCooldown;
withdrawalCooldown = _withdrawalCooldown;
emit WithdrawalCooldownUpdated(oldWithdrawalCooldown, withdrawalCooldown);
}
/**
* @notice Stops the operation of the smart contract.
* @dev Can only be called by a Frax contributor.
* @dev Can only be called if the contract is operational.
*/
function stopOperation() external {
_onlyFraxContributor();
if (isPaused) revert ContractPaused();
isPaused = true;
emit OperationPaused(isPaused, block.timestamp);
}
/**
* @notice Enables the operation of the smart contract.
* @dev Can only be called by the owner.
* @dev Can only be called if the contract is paused.
*/
function restartOperation() external {
_onlyOwner();
if (!isPaused) revert ContractOperational();
isPaused = false;
emit OperationPaused(isPaused, block.timestamp);
}
/**
* @notice Updates the slashing recipient address.
* @dev Can only be called by the owner.
* @dev The new slashing recipient cannot be the same as the old one.
* @dev If the same address is passed, the operation will revert. This is to prevent passing a similar spoofed
* address to the function.
* @param _slashingRecipient Address of the new slashing recipient
*/
function updateSlashingRecipient(address _slashingRecipient) external {
_onlyOwner();
address currentSlashingRecipient = SLASHING_RECIPIENT;
if (currentSlashingRecipient == _slashingRecipient) revert AlreadySlashingRecipient();
SLASHING_RECIPIENT = _slashingRecipient;
emit SlashingRecipientUpdated(currentSlashingRecipient, _slashingRecipient);
}
/**
* @notice Slashes the staker's stake by the specified amount.
* @dev Can only be called by the Frax sentinel.
* @dev The user should be able to be slashed even if their stake is frozen.
* @param _staker The address of the slashing recipient
* @param _amount The amount of FRAX to slash
*/
function slashStaker(address _staker, uint256 _amount) external nonReentrant {
_onlyFraxSentinel();
_slash(_staker, _amount);
}
/**
* @notice Freezes the staker's stake.
* @dev Can only be called by the Frax sentinel.
* @dev The freezing operation will be reverted if the contract is paused.
* @param _staker The address of the staker to freeze
*/
function freezeStaker(address _staker) external {
_onlyFraxSentinel();
_freezeStaker(_staker);
}
/**
* @notice Unfreezes the staker's stake.
* @dev Can only be called by the Frax sentinel.
* @dev The unfreezing operation will be reverted if the contract is paused.
* @param _staker The address of the staker to unfreeze
*/
function unfreezeStaker(address _staker) external {
_onlyFraxSentinel();
_unfreezeStaker(_staker);
}
/**
* @notice Blacklists the staker.
* @dev Can only be called by the Frax sentinel.
* @param _staker The address of the staker to blacklist
*/
function blacklistStaker(address _staker) external {
_onlyFraxSentinel();
_blacklistStaker(_staker);
}
/**
* @notice Checks if an address is a Frax contributor.
* @dev Reverts if the caller is not a Frax contributor.
*/
function _onlyFraxContributor() internal view {
if (!isFraxContributor[msg.sender]) revert NotFraxContributor();
}
/**
* @notice Checks if an address is a Frax sentinel.
* @dev Reverts if the caller is not a Frax sentinel.
*/
function _onlyFraxSentinel() internal view {
if (!isFraxSentinel[msg.sender]) revert NotFraxSentinel();
}
/**
* @notice Checks if the contract is operational.
* @dev Reverts if the contract is paused.
*/
function _onlyWhenOperational() internal view {
if (isPaused) revert ContractPaused();
}
/**
* @notice Checks if the staker's stake is frozen.
* @dev Reverts if the staker's stake is frozen.
* @param _staker Address of the staker to check
*/
function _onlyWhenNotFrozen(address _staker) internal view {
if (isFrozenStaker[_staker]) revert FrozenStaker();
}
/**
* @notice Checks if the staker is blacklisted.
* @dev Reverts if the staker is blacklisted.
* @param _staker Address of the staker to check
*/
function _onlyWhenNotBlacklisted(address _staker) internal view {
if (blacklist[_staker]) revert BlacklistedStaker();
}
/**
* @notice Stakes FRAX for the caller.
* @dev Since the amount to stake is the message value, we don't need to validate the user's balance.
* @dev Attempting to stake zero FRAX will result in reverted execution.
* @param _amount Amount of FRAX to stake
* @param _staker Address of the staker
*/
function _stake(uint256 _amount, address _staker) internal {
if (_amount == 0) revert InvalidStakeAmount();
Stake storage stake = stakes[_staker];
if (stake.initiatedWithdrawal) revert WithdrawalInitiated();
uint256 initialStake = stake.amountStaked;
stake.amountStaked += _amount;
emit StakeUpdated(_staker, initialStake, stake.amountStaked);
}
/**
* @notice Initiates the withdrawal of the staker's stake.
* @dev Reverts if the staker has no stake.
* @dev Reverts if the staker has already initiated a withdrawal.
* @param _staker Address of the staker
*/
function _initiateWithdrawal(address _staker) internal {
Stake storage stake = stakes[_staker];
if (stake.amountStaked == 0) revert InvalidStakeAmount();
if (stake.initiatedWithdrawal) revert WithdrawalInitiated();
stake.initiatedWithdrawal = true;
stake.unlockTime = block.timestamp + withdrawalCooldown;
emit StakeWithdrawalInitiated(_staker, stake.amountStaked, stake.unlockTime);
}
/**
* @notice Withdraws the staker's stake.
* @dev Reverts if the staker has not initiated a withdrawal.
* @dev Reverts if the staker's stake is not available to be withdrawn yet.
* @param _staker Address of the staker
*/
function _withdrawStake(address _staker) internal {
Stake storage stake = stakes[_staker];
if (!stake.initiatedWithdrawal) revert WithdrawalNotInitiated();
if (block.timestamp < stake.unlockTime) revert WithdrawalNotAvailable();
uint256 amount = stake.amountStaked;
stake.amountStaked = 0;
stake.initiatedWithdrawal = false;
stake.unlockTime = 0;
(bool success, ) = _staker.call{ value: amount }("");
if (!success) revert TransferFailed();
emit StakeUpdated(_staker, amount, 0);
}
/**
* @notice Delegates a part of the staker's stake to another staker.
* @dev Reverts if the staker wants to delegate more FRAX than available.
* @dev Reverts if the staker has already delegated to amother delegatee.
* @param _staker Address of the staker
* @param _delegatee Address of the delegatee
* @param _amount Amount of FRAX to delegate
*/
function _delegate(address _staker, address _delegatee, uint256 _amount) internal {
if (_staker == _delegatee) revert CannotDelegateToSelf();
if (_delegatee == address(0)) revert InvalidDelegatee();
Stake storage stakerStake = stakes[_staker];
if (_amount > (stakerStake.amountStaked - stakerStake.amountDelegated)) revert InvalidStakeAmount();
if (stakerStake.delegatee != address(0) && stakerStake.delegatee != _delegatee) {
revert AlreadyDelegatedToAnotherDelegatee();
}
stakerStake.amountDelegated += _amount;
stakerStake.delegatee = _delegatee;
stakes[_delegatee].amountDelegatedToStaker += _amount;
emit StakeDelegated(_staker, _delegatee, _amount);
}
/**
* @notice Revokes staker's delegation.
* @dev This revokes the full amount of the delegated stake.
* @param _staker Address of the staker
*/
function _revokeDelegation(address _staker) internal {
Stake storage stake = stakes[_staker];
address delegatee = stake.delegatee;
uint256 amount = stake.amountDelegated;
if (amount > 0) {
stake.amountDelegated = 0;
stakes[delegatee].amountDelegatedToStaker -= amount;
stake.delegatee = address(0);
emit StakeDelegationRevoked(_staker, delegatee, amount);
}
}
/**
* @notice Slashes the staker's stake.
* @dev If the staker's stake is less than the amount to be slashed, the entire stake will be slashed.
* @param _staker Address of the staker to slash
* @param _amount The amount of FRAX to slash
*/
function _slash(address _staker, uint256 _amount) internal {
Stake storage stake = stakes[_staker];
_amount = stake.amountStaked < _amount ? stake.amountStaked : _amount;
stake.amountStaked -= _amount;
if (stake.delegatee != address(0)) {
// Only reduce the amount delegated to the staker if they are not frozen, otherwise the delegated stake is temporarily nullified already
if (!isFrozenStaker[_staker]) {
stakes[stake.delegatee].amountDelegatedToStaker -= _amount;
}
stake.amountDelegated -= _amount;
}
(bool success, ) = SLASHING_RECIPIENT.call{ value: _amount }("");
if (!success) revert TransferFailed();
emit Slashed(_staker, _amount);
}
/**
* @notice Freezes the staker's stake.
* @dev This is reversible and should be used when investigating a staker.
* @dev Reverts if the staker's stake is already frozen.
* @dev If the staker delegated their stake, freezing their stake will temporarily remove the delegated stake.
* @param _staker Address of the staker to freeze
*/
function _freezeStaker(address _staker) internal {
if (isFrozenStaker[_staker]) revert AlreadyFrozenStaker();
isFrozenStaker[_staker] = true;
if (stakes[_staker].delegatee != address(0)) {
stakes[stakes[_staker].delegatee].amountDelegatedToStaker -= stakes[_staker].amountStaked;
}
emit StakerFrozen(_staker, stakes[_staker].amountStaked);
}
/**
* @notice Unfreezes the staker's stake.
* @dev Reverts if the staker's stake is not frozen.
* @param _staker Address of the staker to unfreeze
*/
function _unfreezeStaker(address _staker) internal {
if (!isFrozenStaker[_staker]) revert NotFrozenStaker();
isFrozenStaker[_staker] = false;
if (stakes[_staker].delegatee != address(0)) {
stakes[stakes[_staker].delegatee].amountDelegatedToStaker += stakes[_staker].amountStaked;
}
emit StakerUnfrozen(_staker, stakes[_staker].amountStaked);
}
/**
* @notice Blacklists the staker.
* @dev This is irreversible and should be used when a staker is found to be malicious.
* @dev If the staker should be slashed, slashing should be done before blacklisting.
* @dev This forces the staker to withdraw their stake and prevents them from staking again.
* @dev Reverts if the staker is already blacklisted.
* @param _staker Address of the staker to blacklist
*/
function _blacklistStaker(address _staker) internal {
if (blacklist[_staker]) revert AlreadyBlacklistedStaker();
if (isFrozenStaker[_staker]) {
_unfreezeStaker(_staker);
}
blacklist[_staker] = true;
if (stakes[_staker].amountStaked > 0) {
_initiateWithdrawal(_staker);
}
_revokeDelegation(_staker);
emit StakerBlacklisted(_staker, stakes[_staker].amountStaked);
}
/* ====================== EMERGENCIES AND FALLBACKS ====================== */
/**
* @notice Fallback function to receive FRAX and automatically stake sent funds for the sender.
* @dev This simplifies recovery process of accidentally sent FRAX to the staking smart contract. It allows users to
* retrieve their accidentally sent FRAX by following the withdrawal process.
*/
receive() external payable {
stakeFrax();
}
/**
* @notice Receives FRAX to increase the smart contract balance and does nothing else.
*/
function donate() external payable {
// Just accept FRAX and do nothing
}
/**
* @notice Allows the owner to recover FRAX from the smart contract in case it somehow gets stuck.
* @dev This function can only be called by the owner.
* @dev The specified amount of FRAX will be transferred to the caller's (owner's) address.
* @param _amount The amount of FRAX to recover
*/
function recoverFrax(uint256 _amount) external nonReentrant {
_onlyOwner();
(bool success, ) = address(owner).call{ value: _amount }("");
if (!success) revert TransferFailed();
emit RecoveredFrax(_amount);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ======================= OwnedUpgradeable ===========================
// ====================================================================
/**
* @title OwnedUpgradeable
* @author Frax Finance
* @notice The OwnedUpgradeable contract has an owner address, and provides basic access control.
*/
contract OwnedUpgradeable {
/// Emitted when attempting to initialize an already initialized contract.
error OwnedAlreadyInitialized();
/// Emitted when attempting to accept ownership when the caller is not the nominated owner.
error InvalidOwnershipAcceptance();
/// Emitted when the owner address is set to the zero address.
error OwnerCannotBeZeroAddress();
/// Emitted when the caller is not the owner.
error OnlyOwner();
/// Address of the owner of the smart contract.
address public owner;
/// Address of the nominated owner of the smart contract.
address public nominatedOwner;
/// Used to make sure the contract is initialized only once.
bool private _initialized;
/**
* @notice Used to initialize the smart contract.
* @param _owner The address of the owner
*/
function __Owned_init(address _owner) public {
if (_initialized) revert OwnedAlreadyInitialized();
if (_owner == address(0)) revert OwnerCannotBeZeroAddress();
_initialized = true;
owner = _owner;
emit OwnerChanged(address(0), _owner);
}
/**
* @notice Allows the current owner to nominate a new owner.
* @dev Reverts if the caller is not the current owner.
* @dev Reverts if the nominated owner is the zero address.
* @param _owner The address of the new owner
*/
function nominateNewOwner(address _owner) external {
_onlyOwner();
if (_owner == address(0)) revert OwnerCannotBeZeroAddress();
nominatedOwner = _owner;
emit OwnerNominated(_owner);
}
/**
* @notice Allows the current nominated owner to accept the ownership.
* @dev Reverts if the caller is not the nominated owner.
*/
function acceptOwnership() external {
if (msg.sender != nominatedOwner) revert InvalidOwnershipAcceptance();
address oldOwner = owner;
owner = nominatedOwner;
nominatedOwner = address(0);
emit OwnerChanged(oldOwner, owner);
}
/**
* @notice Restricts access to the function to the owner.
* @dev Reverts if the caller is not the owner.
*/
function _onlyOwner() internal view {
if (msg.sender != owner) revert OnlyOwner();
}
/**
* @notice Emitted when a new owner is nominated.
* @param nominatedOwner The address of the nominated owner
*/
event OwnerNominated(address indexed nominatedOwner);
/**
* @notice Emitted when the ownership is transferred.
* @param previousOwner Address of the previous owner
* @param newOwner Address of the new owner
*/
event OwnerChanged(address indexed previousOwner, address indexed newOwner);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ======================= IFrax Staker Structs =======================
// ====================================================================
import { IFraxStakerErrors } from "./IFraxStakerErrors.sol";
import { IFraxStakerEvents } from "./IFraxStakerEvents.sol";
/**
* @title IFraxStakerStructs
* @author Frax Finance
* @notice A collection of structs used by the FraxStaker system.
*/
contract FraxStakerStructs is IFraxStakerErrors, IFraxStakerEvents {
/**
* @notice A struct used to represent the stake of a user.
* @dev The `unlockTime` is set to 0 if the stake is not slated for withdrawal.
* @param amountStaked The amount of FRAX staked
* @param amountDelegated The amount of FRAX delegated to other stakers
* @param amountDelegatedToStaker The amount of FRAX delegated to this staker
* @param unlockTime The time at which the stake can be withdrawn
* @param delegatee The delegatee address of the staker
* @param initiatedWithdrawal True if the stake withdrawal has been initiated
* @param __gap Reserved 10 storage slots for future upgrades
*/
struct Stake {
uint256 amountStaked;
uint256 amountDelegated;
uint256 amountDelegatedToStaker;
uint256 unlockTime;
address delegatee;
bool initiatedWithdrawal;
uint256[10] __gap; // reserve extra storage for future upgrades
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
$._status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ==================== IFrax Staker Errors ========================
// ====================================================================
/**
* @title IFraxStakerErrors
* @author Frax Finance
* @notice A collection of errors used by the FraxStaker system.
*/
interface IFraxStakerErrors {
/// Emitted when the staker is already blacklisted.
error AlreadyBlacklistedStaker();
/// Emitted when attempting to delegate to someone when you already have an active delegation.
error AlreadyDelegatedToAnotherDelegatee();
/// Emitted when the owner tries to add a Frax contributor that is already a Frax contributor.
error AlreadyFraxContributor();
/// Emitted when the owner tries to add a Frax sentinel that is already a Frax sentinel.
error AlreadyFraxSentinel();
/// Emitted when the staker is aleady frozen.
error AlreadyFrozenStaker();
/// Emitted when the contract is already initialized.
error AlreadyInitialized();
/// Emitted when the supplied address is already the slashing recipient.
error AlreadySlashingRecipient();
/// Emitted when the staker is blacklisted.
error BlacklistedStaker();
/// Emitted when attempting to delegate to self.
error CannotDelegateToSelf();
/// Emitted when the contract is operational and the action that requires it to be paused is attempted.
error ContractOperational();
/// Emitted when the contract is paused and the action that requires it to be operational is attempted.
error ContractPaused();
/// Emitted when the staker is frozen and can't perform any actions.
error FrozenStaker();
/// Emitted when attempting to delegate to an address that is not a valid delegatee.
error InvalidDelegatee();
/// Emitted when attempting to create a stake with a zero amount.
error InvalidStakeAmount();
/// Emitted when the staker tries to delegate their stake when they already have an active non-delegated stake to someone else.
error NonDelegatedStakeAlreadyExists();
/// Emitted when the owner tries to remove a Frax contributor that is not a Frax contributor.
error NotFraxContributor();
/// Emitted when the owner tries to remove a Frax sentinel that is not a Frax sentinel.
error NotFraxSentinel();
/// Emitted when the staker is not frozen.
error NotFrozenStaker();
/// Emitted when the sender is not a flox contributor.
error NotFloxContributor();
/// Emitted when the FRAX transfer fails.
error TransferFailed();
/// Emitted when a user tries to deposit FRAX while they aleady have a stake with initiated withdrawal.
/// They need to either cancel the withdrawal or wait for it to finish.
error WithdrawalInitiated();
/// Emitted when a user tries to withdraw their stake but it is not available to be withdrawn yet.
error WithdrawalNotAvailable();
/// Emitted when a user tries to withdraw their stake but the withdrawal has not been initiated yet.
error WithdrawalNotInitiated();
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/**
* ====================================================================
* | ______ _______ |
* | / _____________ __ __ / ____(_____ ____ _____ ________ |
* | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
* | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
* | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
* | |
* ====================================================================
* ===================== IFraxStakerEvents =========================
* ====================================================================
* Frax Finance: https://github.com/FraxFinance
*/
/**
* @title IFraxStakerEvents
* @author Frax Finance
* @notice A collection of events used by the FraxStaker system.
*/
contract IFraxStakerEvents {
/**
* @notice Emitted when a contributor is added.
* @param contributor The address of the contributor
*/
event FraxContributorAdded(address indexed contributor);
/**
* @notice Emitted when a contributor is removed.
* @param contributor The address of the contributor
*/
event FraxContributorRemoved(address indexed contributor);
/**
* @notice Emitted when a sentinel is added.
* @param sentinel The address of the sentinel
*/
event FraxSentinelAdded(address indexed sentinel);
/**
* @notice Emitted when a sentinel is removed.
* @param sentinel The address of the sentinel
*/
event FraxSentinelRemoved(address indexed sentinel);
/**
* @notice Emitted when a new admin is proposed.
* @param currentAdmin The address of the current admin
* @param proposedFutureAdmin The address of the proposed future admin
*/
event FutureAdminProposed(address indexed currentAdmin, address indexed proposedFutureAdmin);
/**
* @notice Emitted when a new admin is set.
* @param oldAdmin The address of the old admin
* @param newAdmin The address of the new admin
*/
event NewAdmin(address indexed oldAdmin, address indexed newAdmin);
/**
* @notice Emitted when the contract is paused or unpaused.
* @param paused True if the contract is paused, false if it is unpaused
* @param timestamp The timestamp at which the pause or unpause occurred
*/
event OperationPaused(bool paused, uint256 timestamp);
/**
* @notice Emitted when FRAX is recovered from the smart contract.
* @param amount The amount of FRAX recovered
*/
event RecoveredFrax(uint256 amount);
/**
* @notice Emitted when a stake is slashed.
* @param staker The address of the staker
* @param amount The amount of FRAX slashed
*/
event Slashed(address indexed staker, uint256 amount);
/**
* @notice Emitted when the slashing recipient is updated.
* @dev The slashing recipient is the address that receives the slashed FRAX.
* @param oldSlashingRecipient Previous slashing recipient
* @param newSlashingRecipient Updated slashing recipient
*/
event SlashingRecipientUpdated(address indexed oldSlashingRecipient, address indexed newSlashingRecipient);
/**
* @notice Emitted when a stake is delegated.
* @param staker Address of the staker
* @param delegatee Address of the delegatee
* @param amount Amount of FRAX delegated
*/
event StakeDelegated(address indexed staker, address indexed delegatee, uint256 amount);
/**
* @notice Emitted when a stake delegation is revoked.
* @dev The amount of FRAX in the event equals the amount of FRAX delegated to this specific delegatee by this
* staker.
* @param staker Address of the staker
* @param delegatee Address of the delegatee
* @param amount Amount of FRAX delegation revoked
*/
event StakeDelegationRevoked(address indexed staker, address indexed delegatee, uint256 amount);
/**
* @notice Emitted when an address donates FRAX to another staker's stake.
* @param donor Address that donated FRAX to the recipient's stake
* @param recipient Address that received the donated FRAX to their stake
* @param amount Amount of FRAX that was donated
*/
event StakeDonation(address indexed donor, address indexed recipient, uint256 amount);
/**
* @notice Emitted when a staker is blacklisted.
* @param staker The address of the blacklisted staker
* @param amount The amount of FRAX staked
*/
event StakerBlacklisted(address indexed staker, uint256 amount);
/**
* @notice Emitted when a stake is frozen.
* @param staker The address of the staker
* @param amount The amount of FRAX staked
*/
event StakerFrozen(address indexed staker, uint256 amount);
/**
* @notice Emitted when a stake is unfrozen.
* @param staker The address of the staker
* @param amount The amount of FRAX unfrozen
*/
event StakerUnfrozen(address indexed staker, uint256 amount);
/**
* @notice Emitted when a stake is updated.
* @param staker The address of the staker
* @param initialStake The initial amount of FRAX staked
* @param newStake The new amount of FRAX staked
*/
event StakeUpdated(address indexed staker, uint256 initialStake, uint256 newStake);
/**
* @notice Emitted when a stake withdrawal is initiated.
* @param staker The address of the staker
* @param stake The amount of FRAX staked
* @param withdrawalTimestamp The timestamp at which the withdrawal will be available
*/
event StakeWithdrawalInitiated(address indexed staker, uint256 stake, uint256 withdrawalTimestamp);
/**
* @notice Emitted when the withdrawal cooldown period is updated.
* @param oldCooldown Previous withdrawal cooldown period
* @param newCooldown New withdrawal cooldown period
*/
event WithdrawalCooldownUpdated(uint256 oldCooldown, uint256 newCooldown);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}{
"remappings": [
"frax-std/=lib/frax-standard-solidity/src/",
"@fraxtal/=lib/fraxtal/packages/",
"lib/fraxtal/packages/contracts-bedrock:src/=lib/fraxtal/packages/contracts-bedrock/src/",
"lib/fraxtal/packages/contracts-bedrock:test/=lib/fraxtal/packages/contracts-bedrock/test/",
"lib/fraxtal/packages/contracts-bedrock:scripts/=lib/fraxtal/packages/contracts-bedrock/scripts/",
"lib/fraxtal/packages/contracts-bedrock:@cwia/=lib/fraxtal/packages/contracts-bedrock/lib/clones-with-immutable-args/src/",
"lib/fraxtal/packages/contracts-bedrock:@openzeppelin/contracts-upgradeable/=lib/fraxtal/packages/contracts-bedrock/lib/openzeppelin-contracts-upgradeable/contracts/",
"lib/fraxtal/packages/contracts-bedrock:@openzeppelin/contracts/=lib/fraxtal/packages/contracts-bedrock/lib/openzeppelin-contracts/contracts/",
"lib/fraxtal/packages/contracts-bedrock:@rari-capital/solmate/=lib/fraxtal/packages/contracts-bedrock/lib/solmate/",
"lib/fraxtal/packages/contracts-bedrock:@lib-keccak/=lib/fraxtal/packages/contracts-bedrock/lib/lib-keccak/contracts/lib/",
"lib/fraxtal/packages/contracts-bedrock:@solady/=lib/fraxtal/packages/contracts-bedrock/lib/solady/src/",
"lib/fraxtal/packages/contracts-bedrock:solady/=lib/fraxtal/packages/contracts-bedrock/lib/solady/src/",
"lib/fraxtal/packages/contracts-bedrock:@solmate/=lib/fraxtal/packages/contracts-bedrock/lib/solmate/src/",
"lib/fraxtal/packages/contracts-bedrock:solmate/=lib/fraxtal/packages/contracts-bedrock/lib/solmate/src/",
"lib/fraxtal/packages/contracts-bedrock:forge-std/=lib/fraxtal/packages/contracts-bedrock/lib/forge-std/src/",
"lib/fraxtal/packages/contracts-bedrock:ds-test/=lib/fraxtal/packages/contracts-bedrock/lib/forge-std/lib/ds-test/src/",
"lib/fraxtal/packages/contracts-bedrock:safe-contracts/=lib/fraxtal/packages/contracts-bedrock/lib/safe-contracts/contracts/",
"lib/fraxtal/packages/contracts-bedrock:kontrol-cheatcodes/=lib/fraxtal/packages/contracts-bedrock/lib/kontrol-cheatcodes/src/",
"@eth-optimism/=lib/optimism/packages/",
"lib/optimism/packages/contracts-bedrock:src/=lib/optimism/packages/contracts-bedrock/src/",
"lib/optimism/packages/contracts-bedrock:test/=lib/optimism/packages/contracts-bedrock/test/",
"lib/optimism/packages/contracts-bedrock:scripts/=lib/optimism/packages/contracts-bedrock/scripts/",
"lib/optimism/packages/contracts-bedrock:@cwia/=lib/optimism/packages/contracts-bedrock/lib/clones-with-immutable-args/src/",
"lib/optimism/packages/contracts-bedrock:@openzeppelin/contracts-upgradeable/=lib/optimism/packages/contracts-bedrock/lib/openzeppelin-contracts-upgradeable/contracts/",
"lib/optimism/packages/contracts-bedrock:@openzeppelin/contracts/=lib/optimism/packages/contracts-bedrock/lib/openzeppelin-contracts/contracts/",
"lib/optimism/packages/contracts-bedrock:@rari-capital/solmate/=lib/optimism/packages/contracts-bedrock/lib/solmate/",
"lib/optimism/packages/contracts-bedrock:@lib-keccak/=lib/optimism/packages/contracts-bedrock/lib/lib-keccak/contracts/lib/",
"lib/optimism/packages/contracts-bedrock:@solady/=lib/optimism/packages/contracts-bedrock/lib/solady/src/",
"lib/optimism/packages/contracts-bedrock:solady/=lib/optimism/packages/contracts-bedrock/lib/solady/src/",
"lib/optimism/packages/contracts-bedrock:@solmate/=lib/optimism/packages/contracts-bedrock/lib/solmate/src/",
"lib/optimism/packages/contracts-bedrock:solmate/=lib/optimism/packages/contracts-bedrock/lib/solmate/src/",
"lib/optimism/packages/contracts-bedrock:forge-std/=lib/optimism/packages/contracts-bedrock/lib/forge-std/src/",
"lib/optimism/packages/contracts-bedrock:ds-test/=lib/optimism/packages/contracts-bedrock/lib/forge-std/lib/ds-test/src/",
"lib/optimism/packages/contracts-bedrock:safe-contracts/=lib/optimism/packages/contracts-bedrock/lib/safe-contracts/contracts/",
"lib/optimism/packages/contracts-bedrock:kontrol-cheatcodes/=lib/optimism/packages/contracts-bedrock/lib/kontrol-cheatcodes/src/",
"src/=src/",
"@openzeppelin/contracts-upgradeable-5/=node_modules/@openzeppelin/contracts-upgradeable-5/",
"@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
"@openzeppelin-4/=node_modules/@openzeppelin-4/",
"@openzeppelin-5/=node_modules/@openzeppelin-5/",
"@rari-capital/=node_modules/@rari-capital/",
"automate/=lib/fraxtal/packages/contracts-bedrock/lib/automate/contracts/",
"clones-with-immutable-args/=node_modules/clones-with-immutable-args/",
"ds-test/=lib/frax-standard-solidity/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/fraxtal/packages/contracts-bedrock/lib/openzeppelin-contracts-v5/lib/erc4626-tests/",
"forge-std/=lib/frax-standard-solidity/lib/forge-std/src/",
"frax-standard-solidity/=lib/frax-standard-solidity/src/",
"fraxtal/=lib/fraxtal/",
"kontrol-cheatcodes/=lib/fraxtal/packages/contracts-bedrock/lib/kontrol-cheatcodes/src/",
"lib-keccak/=lib/fraxtal/packages/contracts-bedrock/lib/lib-keccak/contracts/",
"openzeppelin-contracts-upgradeable/=lib/fraxtal/packages/contracts-bedrock/lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts-v5/=lib/fraxtal/packages/contracts-bedrock/lib/openzeppelin-contracts-v5/",
"openzeppelin-contracts/=lib/fraxtal/packages/contracts-bedrock/lib/openzeppelin-contracts/",
"optimism/=lib/optimism/",
"prb-test/=lib/fraxtal/packages/contracts-bedrock/lib/automate/lib/prb-test/src/",
"safe-contracts/=lib/fraxtal/packages/contracts-bedrock/lib/safe-contracts/contracts/",
"solady-v0.0.245/=lib/fraxtal/packages/contracts-bedrock/lib/solady-v0.0.245/src/",
"solady/=lib/fraxtal/packages/contracts-bedrock/lib/solady/",
"solidity-bytes-utils/=lib/frax-standard-solidity/lib/solidity-bytes-utils/",
"solmate/=lib/fraxtal/packages/contracts-bedrock/lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 100000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyBlacklistedStaker","type":"error"},{"inputs":[],"name":"AlreadyDelegatedToAnotherDelegatee","type":"error"},{"inputs":[],"name":"AlreadyFraxContributor","type":"error"},{"inputs":[],"name":"AlreadyFraxSentinel","type":"error"},{"inputs":[],"name":"AlreadyFrozenStaker","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AlreadySlashingRecipient","type":"error"},{"inputs":[],"name":"BlacklistedStaker","type":"error"},{"inputs":[],"name":"CannotDelegateToSelf","type":"error"},{"inputs":[],"name":"ContractOperational","type":"error"},{"inputs":[],"name":"ContractPaused","type":"error"},{"inputs":[],"name":"FrozenStaker","type":"error"},{"inputs":[],"name":"InvalidDelegatee","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidOwnershipAcceptance","type":"error"},{"inputs":[],"name":"InvalidStakeAmount","type":"error"},{"inputs":[],"name":"NonDelegatedStakeAlreadyExists","type":"error"},{"inputs":[],"name":"NotFloxContributor","type":"error"},{"inputs":[],"name":"NotFraxContributor","type":"error"},{"inputs":[],"name":"NotFraxSentinel","type":"error"},{"inputs":[],"name":"NotFrozenStaker","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"OnlyOwner","type":"error"},{"inputs":[],"name":"OwnedAlreadyInitialized","type":"error"},{"inputs":[],"name":"OwnerCannotBeZeroAddress","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"WithdrawalInitiated","type":"error"},{"inputs":[],"name":"WithdrawalNotAvailable","type":"error"},{"inputs":[],"name":"WithdrawalNotInitiated","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contributor","type":"address"}],"name":"FraxContributorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contributor","type":"address"}],"name":"FraxContributorRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sentinel","type":"address"}],"name":"FraxSentinelAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sentinel","type":"address"}],"name":"FraxSentinelRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"currentAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"proposedFutureAdmin","type":"address"}],"name":"FutureAdminProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"paused","type":"bool"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"OperationPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nominatedOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RecoveredFrax","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Slashed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldSlashingRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newSlashingRecipient","type":"address"}],"name":"SlashingRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"delegatee","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeDelegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"delegatee","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeDelegationRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"donor","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeDonation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"initialStake","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newStake","type":"uint256"}],"name":"StakeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"stake","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"withdrawalTimestamp","type":"uint256"}],"name":"StakeWithdrawalInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakerBlacklisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakerFrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakerUnfrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCooldown","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCooldown","type":"uint256"}],"name":"WithdrawalCooldownUpdated","type":"event"},{"inputs":[],"name":"SLASHING_RECIPIENT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"__Owned_init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contributor","type":"address"}],"name":"addFraxContributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sentinel","type":"address"}],"name":"addFraxSentinel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"blacklist","outputs":[{"internalType":"bool","name":"isBlacklisted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"blacklistStaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"donate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"donateStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"forceStakeWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"freezeStaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"string","name":"_version","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initiateWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"}],"name":"isFraxContributor","outputs":[{"internalType":"bool","name":"isContributor","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sentinel","type":"address"}],"name":"isFraxSentinel","outputs":[{"internalType":"bool","name":"isSentinel","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"isFrozenStaker","outputs":[{"internalType":"bool","name":"isFrozen","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"recoverFrax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contributor","type":"address"}],"name":"removeFraxContributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sentinel","type":"address"}],"name":"removeFraxSentinel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"restartOperation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"slashStaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeFrax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegatee","type":"address"}],"name":"stakeFrax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"stakes","outputs":[{"internalType":"uint256","name":"amountStaked","type":"uint256"},{"internalType":"uint256","name":"amountDelegated","type":"uint256"},{"internalType":"uint256","name":"amountDelegatedToStaker","type":"uint256"},{"internalType":"uint256","name":"unlockTime","type":"uint256"},{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"bool","name":"initiatedWithdrawal","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stopOperation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"unfreezeStaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_slashingRecipient","type":"address"}],"name":"updateSlashingRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_withdrawalCooldown","type":"uint256"}],"name":"updateWithdrawalCooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalCooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
6080604052348015600e575f80fd5b506016306029565b600a805461ff00191661010017905560d7565b600154600160a01b900460ff1615605357604051633965719d60e21b815260040160405180910390fd5b6001600160a01b038116607957604051630640d5fb60e51b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b1790555f80546001600160a01b0383166001600160a01b0319909116811782556040519091907fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c908290a350565b612f8b806100e45f395ff3fe60806040526004361061025f575f3560e01c80639e1b9aa21161014b578063c76853de116100c6578063d8d9ec001161007c578063ed88c68e11610062578063ed88c68e1461026c578063f399e22e14610747578063f9f92be414610766575f80fd5b8063d8d9ec00146106fa578063e46a61b614610728575f80fd5b8063ce7cd5ad116100ac578063ce7cd5ad146106b2578063d6bd103f146106d1578063d6c89c60146106e5575f80fd5b8063c76853de14610674578063ca2a951214610693575f80fd5b8063b41a52581161011b578063b7a287ac11610101578063b7a287ac1461062d578063b81213851461064c578063bed9d86114610660575f80fd5b8063b41a5258146105fa578063b51d1d4f14610619575f80fd5b80639e1b9aa2146105755780639e48dc2b14610594578063b187bd26146105b3578063b234c544146105cc575f80fd5b806353a47bb7116101db57806386fc754c116101ab5780638da5cb5b116101915780638da5cb5b14610518578063989d1a87146105435780639c1f1f6314610562575f80fd5b806386fc754c146104f157806387c7655c146104f9575f80fd5b806353a47bb71461047157806354fd4d501461049d57806370a08231146104be57806379ba5097146104dd575f80fd5b806316934fc4116102305780631c29b8ba116102165780631c29b8ba146103e25780633b66042f146104015780634f99ef7514610452575f80fd5b806316934fc41461030657806318160ddd146103c6575f80fd5b806283b8d7146102725780630b376695146102855780630fbe82b8146102c85780631627540c146102e7575f80fd5b3661026e5761026c610794565b005b5f80fd5b61026c610280366004612b68565b6108c1565b348015610290575f80fd5b506102b361029f366004612b68565b60046020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156102d3575f80fd5b5061026c6102e2366004612b88565b610ab3565b3480156102f2575f80fd5b5061026c610301366004612b68565b610afa565b348015610311575f80fd5b50610381610320366004612b68565b60076020525f9081526040902080546001820154600283015460038401546004909401549293919290919073ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000900460ff1686565b60408051968752602087019590955293850192909252606084015273ffffffffffffffffffffffffffffffffffffffff166080830152151560a082015260c0016102bf565b3480156103d1575f80fd5b50475b6040519081526020016102bf565b3480156103ed575f80fd5b5061026c6103fc366004612b68565b610bbd565b34801561040c575f80fd5b5060025461042d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102bf565b34801561045d575f80fd5b5061026c61046c366004612b68565b610c90565b34801561047c575f80fd5b5060015461042d9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104a8575f80fd5b506104b1610cdb565b6040516102bf9190612bb0565b3480156104c9575f80fd5b506103d46104d8366004612b68565b610d67565b3480156104e8575f80fd5b5061026c610ece565b61026c610794565b348015610504575f80fd5b5061026c610513366004612c03565b610f9d565b348015610523575f80fd5b505f5461042d9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561054e575f80fd5b5061026c61055d366004612b68565b610fea565b61026c610570366004612b68565b6110c7565b348015610580575f80fd5b5061026c61058f366004612b68565b611154565b34801561059f575f80fd5b5061026c6105ae366004612b68565b6112a5565b3480156105be575f80fd5b50600a546102b39060ff1681565b3480156105d7575f80fd5b506102b36105e6366004612b68565b60066020525f908152604090205460ff1681565b348015610605575f80fd5b5061026c610614366004612b68565b611382565b348015610624575f80fd5b5061026c61145b565b348015610638575f80fd5b5061026c610647366004612c03565b611489565b348015610657575f80fd5b5061026c61158d565b34801561066b575f80fd5b5061026c61163b565b34801561067f575f80fd5b5061026c61068e366004612b68565b611686565b34801561069e575f80fd5b5061026c6106ad366004612b68565b611697565b3480156106bd575f80fd5b5061026c6106cc366004612b68565b611770565b3480156106dc575f80fd5b5061026c611781565b3480156106f0575f80fd5b506103d460085481565b348015610705575f80fd5b506102b3610714366004612b68565b60056020525f908152604090205460ff1681565b348015610733575f80fd5b5061026c610742366004612b68565b611822565b348015610752575f80fd5b5061026c610761366004612c47565b611833565b348015610771575f80fd5b506102b3610780366004612b68565b60036020525f908152604090205460ff1681565b61079c611a68565b6107a533611aa5565b6107ae33611b04565b6107b83433611b63565b335f908152600760209081526040808320815160e0810183528154815260018201549381019390935260028101548383015260038101546060840152600481015473ffffffffffffffffffffffffffffffffffffffff8116608085015274010000000000000000000000000000000000000000900460ff16151560a08401528151610140810192839052909160c0840191906005840190600a9082845b8154815260200190600101908083116108555750505091909252505050608081015190915073ffffffffffffffffffffffffffffffffffffffff16156108be576108a28160800151611aa5565b6108af8160800151611b04565b6108be33826080015134611c8a565b50565b6108c9611a68565b6108d281611aa5565b6108db81611b04565b345f03610914576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600760205260409020600481015474010000000000000000000000000000000000000000900460ff161561098f576040517fd206192300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80545f036109c9576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109d33483611b63565b600481015473ffffffffffffffffffffffffffffffffffffffff1615610a62576004810154610a179073ffffffffffffffffffffffffffffffffffffffff16611aa5565b6004810154610a3b9073ffffffffffffffffffffffffffffffffffffffff16611b04565b6004810154610a6290839073ffffffffffffffffffffffffffffffffffffffff1634611c8a565b60405134815273ffffffffffffffffffffffffffffffffffffffff83169033907f574529f953f301e05f2f1da6e9b7798bf90eef9d89647f049f43c6e8cb842c5c9060200160405180910390a35050565b610abb611f18565b610ac3611f99565b610acd8282611fe1565b610af660017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050565b610b026121da565b73ffffffffffffffffffffffffffffffffffffffff8116610b4f576040517fc81abf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22905f90a250565b610bc56121da565b60025473ffffffffffffffffffffffffffffffffffffffff9081169082168103610c1b576040517fdaf2d6bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84811691821790925560405190918316907fc4e7dd75c3c361103a75b9cc2efbd3c42ff8f20d1e60387292bb3ca1696b49eb905f90a35050565b610c98611f18565b610ca061222a565b610ca981611aa5565b610cb281612272565b6108be60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b60098054610ce890612d48565b80601f0160208091040260200160405190810160405280929190818152602001828054610d1490612d48565b8015610d5f5780601f10610d3657610100808354040283529160200191610d5f565b820191905f5260205f20905b815481529060010190602001808311610d4257829003601f168201915b505050505081565b73ffffffffffffffffffffffffffffffffffffffff8181165f908152600760209081526040808320815160e0810183528154815260018201549381019390935260028101548383015260038101546060840152600481015494851660808401527401000000000000000000000000000000000000000090940460ff16151560a0830152805161014081019182905292938493909160c0840191906005840190600a9082845b815481526020019060010190808311610e0c575050509190925250505073ffffffffffffffffffffffffffffffffffffffff84165f908152600360205260408120549192509060ff1680610e84575073ffffffffffffffffffffffffffffffffffffffff84165f9081526004602052604090205460ff165b15610e9257505f9392505050565b8160a0015115610ea357505f610eb7565b60208201518251610eb49190612dc6565b90505b6040820151610ec69082612ddf565b949350505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610f1f576040517fd74b334e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80546001805473ffffffffffffffffffffffffffffffffffffffff8082167fffffffffffffffffffffffff000000000000000000000000000000000000000080861682178755909216909255604051919092169283917fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9190a350565b610fa56121da565b600880549082905560408051828152602081018490527f339836fabaa5f0eb442f133ec346175cc489ac04dbca653e7dd68dd1c6b56319910160405180910390a15050565b610ff26121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526005602052604090205460ff1615611051576040517f70b9b0d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fe2d01cc637b0a35c9a2dde2789da012cf2b5d14caa779d280c35209b48c31cf29190a250565b6110cf611a68565b6110d833611aa5565b6110e181611aa5565b6110ea33611b04565b6110f381611b04565b335f908152600760205260409020600181015490541461113f576040517fcf78930100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111493433611b63565b6108be338234611c8a565b60015474010000000000000000000000000000000000000000900460ff16156111a9576040517fe595c67400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166111f6576040517fc81abf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790555f805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116811782556040519091907fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c908290a350565b6112ad6121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526006602052604090205460ff161561130c576040517fd4ecc76600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526006602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f018d27189c54515c0464a9160b88974100b4ea338e1e5a16581a580cdd08c76b9190a250565b61138a6121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526005602052604090205460ff166113e8576040517fd56b8a2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f09af5383361cf92f81a21f5147c84aed80ff6d5087bf486623c1d7c43699ab9e9190a250565b611463611a68565b61146c33611aa5565b61147533611b04565b61147e33612441565b61148733612539565b565b611491611f18565b6114996121da565b5f805460405173ffffffffffffffffffffffffffffffffffffffff9091169083908381818185875af1925050503d805f81146114f0576040519150601f19603f3d011682016040523d82523d5f602084013e6114f5565b606091505b5050905080611530576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518281527f104fad8a72e99cad30d4f34b4863020512b61408ab677d7f0c9eae735c31a8679060200160405180910390a1506108be60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b61159561222a565b600a5460ff16156115d2576040517fab35696f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155604080519182524260208301527f5297bdbba6a0f5b1f239889b8bd6040ef096d48d0568711dd5dfa1c31607a8f591015b60405180910390a1565b611643611f18565b61164b611a68565b61165433611aa5565b61165d33612272565b61148760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b61168e611f99565b6108be8161269c565b61169f6121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526006602052604090205460ff166116fd576040517facceb67400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526006602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f8019d8c46c8bc3cf3019ff5b55be5dcdb8aa616d3512ad006c7dee175f090b3c9190a250565b611778611f99565b6108be81612803565b6117896121da565b600a5460ff166117c5576040517f960c07ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055604080515f81524260208201527f5297bdbba6a0f5b1f239889b8bd6040ef096d48d0568711dd5dfa1c31607a8f59101611631565b61182a611f99565b6108be8161295d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f8115801561187d5750825b90505f8267ffffffffffffffff1660011480156118995750303b155b9050811580156118a7575080155b156118de576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001178555831561193f5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b600a54610100900460ff1615611981576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead17905560096119e58782612e3e565b506276a7006008556119f687611154565b6119fe612ac1565b8315611a5f5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b600a5460ff1615611487576040517fab35696f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff16156108be576040517f8456d42b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526003602052604090205460ff16156108be576040517fa1a04a3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815f03611b9c576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600760205260409020600481015474010000000000000000000000000000000000000000900460ff1615611c17576040517fd206192300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805483825f611c268385612ddf565b9091555050815460405173ffffffffffffffffffffffffffffffffffffffff8516917ff3ee618df6e6ff5a26ef25cf1ba9bc24b56492f5ff29acf2815121a2b903138a91611c7c91858252602082015260400190565b60405180910390a250505050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611cef576040517fef99396c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216611d3c576040517fe04bb5d900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83165f90815260076020526040902060018101548154611d719190612dc6565b821115611daa576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600481015473ffffffffffffffffffffffffffffffffffffffff1615801590611df05750600481015473ffffffffffffffffffffffffffffffffffffffff848116911614155b15611e27576040517f4efd913f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81816001015f828254611e3a9190612ddf565b90915550506004810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85169081179091555f9081526007602052604081206002018054849290611ea4908490612ddf565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fd39549de9e66b0b67e3696e4d033b914ea92d1fa64a28ee38da6938575214aaa84604051611f0a91815260200190565b60405180910390a350505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01611f93576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b335f9081526006602052604090205460ff16611487576040517facceb67400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f908152600760205260409020805482116120135781612016565b80545b915081815f015f82825461202a9190612dc6565b9091555050600481015473ffffffffffffffffffffffffffffffffffffffff16156120d55773ffffffffffffffffffffffffffffffffffffffff83165f9081526004602052604090205460ff166120bc57600481015473ffffffffffffffffffffffffffffffffffffffff165f90815260076020526040812060020180548492906120b6908490612dc6565b90915550505b81816001015f8282546120cf9190612dc6565b90915550505b6002546040515f9173ffffffffffffffffffffffffffffffffffffffff169084908381818185875af1925050503d805f811461212c576040519150601f19603f3d011682016040523d82523d5f602084013e612131565b606091505b505090508061216c576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff167f4ed05e9673c26d2ed44f7ef6a7f2942df0ee3b5e1e17db4b99f9dcd261a339cd84604051611c7c91815260200190565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5f5473ffffffffffffffffffffffffffffffffffffffff163314611487576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f9081526005602052604090205460ff16611487576040517fd56b8a2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600760205260409020600481015474010000000000000000000000000000000000000000900460ff166122ec576040517f5bc0da6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806003015442101561232a576040517f442c667900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80545f8083556004830180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690556003830181905560405173ffffffffffffffffffffffffffffffffffffffff85169083908381818185875af1925050503d805f81146123b4576040519150601f19603f3d011682016040523d82523d5f602084013e6123b9565b606091505b50509050806123f4576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518381525f602082015273ffffffffffffffffffffffffffffffffffffffff8616917ff3ee618df6e6ff5a26ef25cf1ba9bc24b56492f5ff29acf2815121a2b903138a9101611c7c565b73ffffffffffffffffffffffffffffffffffffffff8082165f90815260076020526040902060048101546001820154919216908015612533575f6001840181905573ffffffffffffffffffffffffffffffffffffffff8316815260076020526040812060020180548392906124b7908490612dc6565b90915550506004830180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560405181815273ffffffffffffffffffffffffffffffffffffffff83811691908616907f77d8b2d5629f40603353a7f0167e22f1e42d23732efdd24a8ffd477f6812e4b390602001611f0a565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526007602052604081208054909103612598576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600481015474010000000000000000000000000000000000000000900460ff16156125ef576040517fd206192300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004810180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905560085461263d9042612ddf565b60038201819055815460408051918252602082019290925273ffffffffffffffffffffffffffffffffffffffff8416917fedc81e3c02710417110cba808754556207918ce8d29647c4b90fe924e7af3f1a910160405180910390a25050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff166126fa576040517f1dee782100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8082165f90815260046020818152604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556007909152909120015416156127a65773ffffffffffffffffffffffffffffffffffffffff8082165f9081526007602052604080822080546004909101549093168252812060020180549091906127a0908490612ddf565b90915550505b73ffffffffffffffffffffffffffffffffffffffff81165f818152600760209081526040918290205491519182527ff2d07850f24dfd156502c73101307c83043b7ff3aa3191472e9a1e659050491291015b60405180910390a250565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526003602052604090205460ff1615612862576040517f982b22b100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff1615612898576128988161269c565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556007909152902054156128fe576128fe81612539565b61290781612441565b73ffffffffffffffffffffffffffffffffffffffff81165f818152600760209081526040918290205491519182527fba14e0826c92db7828c6814f979548c85017302becc8ea5ca79b6be627d1160a91016127f8565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff16156129bc576040517f29a2d6c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8082165f90815260046020818152604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055600790915290912001541615612a6b5773ffffffffffffffffffffffffffffffffffffffff8082165f908152600760205260408082208054600490910154909316825281206002018054909190612a65908490612dc6565b90915550505b73ffffffffffffffffffffffffffffffffffffffff81165f818152600760209081526040918290205491519182527f98bc7e294f14c351ce5766e9f1c1fd9e692a768b572d75ad0589496247bd8e2e91016127f8565b612ac9612ad1565b611487612b38565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16611487576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121b4612ad1565b803573ffffffffffffffffffffffffffffffffffffffff81168114612b63575f80fd5b919050565b5f60208284031215612b78575f80fd5b612b8182612b40565b9392505050565b5f8060408385031215612b99575f80fd5b612ba283612b40565b946020939093013593505050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f60208284031215612c13575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f8060408385031215612c58575f80fd5b612c6183612b40565b9150602083013567ffffffffffffffff811115612c7c575f80fd5b8301601f81018513612c8c575f80fd5b803567ffffffffffffffff811115612ca657612ca6612c1a565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715612d1257612d12612c1a565b604052818152828201602001871015612d29575f80fd5b816020840160208301375f602083830101528093505050509250929050565b600181811c90821680612d5c57607f821691505b602082108103612d93577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115612dd957612dd9612d99565b92915050565b80820180821115612dd957612dd9612d99565b601f821115612e3957805f5260205f20601f840160051c81016020851015612e175750805b601f840160051c820191505b81811015612e36575f8155600101612e23565b50505b505050565b815167ffffffffffffffff811115612e5857612e58612c1a565b612e6c81612e668454612d48565b84612df2565b6020601f821160018114612ebd575f8315612e875750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455612e36565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b82811015612f0a5787850151825560209485019460019092019101612eea565b5084821015612f4657868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b0190555056fea2646970667358221220c201e946f20e51d43fd96286bb955d49068e981a595f5bc91f595cb739b0d6a264736f6c634300081a0033
Deployed Bytecode
0x60806040526004361061025f575f3560e01c80639e1b9aa21161014b578063c76853de116100c6578063d8d9ec001161007c578063ed88c68e11610062578063ed88c68e1461026c578063f399e22e14610747578063f9f92be414610766575f80fd5b8063d8d9ec00146106fa578063e46a61b614610728575f80fd5b8063ce7cd5ad116100ac578063ce7cd5ad146106b2578063d6bd103f146106d1578063d6c89c60146106e5575f80fd5b8063c76853de14610674578063ca2a951214610693575f80fd5b8063b41a52581161011b578063b7a287ac11610101578063b7a287ac1461062d578063b81213851461064c578063bed9d86114610660575f80fd5b8063b41a5258146105fa578063b51d1d4f14610619575f80fd5b80639e1b9aa2146105755780639e48dc2b14610594578063b187bd26146105b3578063b234c544146105cc575f80fd5b806353a47bb7116101db57806386fc754c116101ab5780638da5cb5b116101915780638da5cb5b14610518578063989d1a87146105435780639c1f1f6314610562575f80fd5b806386fc754c146104f157806387c7655c146104f9575f80fd5b806353a47bb71461047157806354fd4d501461049d57806370a08231146104be57806379ba5097146104dd575f80fd5b806316934fc4116102305780631c29b8ba116102165780631c29b8ba146103e25780633b66042f146104015780634f99ef7514610452575f80fd5b806316934fc41461030657806318160ddd146103c6575f80fd5b806283b8d7146102725780630b376695146102855780630fbe82b8146102c85780631627540c146102e7575f80fd5b3661026e5761026c610794565b005b5f80fd5b61026c610280366004612b68565b6108c1565b348015610290575f80fd5b506102b361029f366004612b68565b60046020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156102d3575f80fd5b5061026c6102e2366004612b88565b610ab3565b3480156102f2575f80fd5b5061026c610301366004612b68565b610afa565b348015610311575f80fd5b50610381610320366004612b68565b60076020525f9081526040902080546001820154600283015460038401546004909401549293919290919073ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000900460ff1686565b60408051968752602087019590955293850192909252606084015273ffffffffffffffffffffffffffffffffffffffff166080830152151560a082015260c0016102bf565b3480156103d1575f80fd5b50475b6040519081526020016102bf565b3480156103ed575f80fd5b5061026c6103fc366004612b68565b610bbd565b34801561040c575f80fd5b5060025461042d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102bf565b34801561045d575f80fd5b5061026c61046c366004612b68565b610c90565b34801561047c575f80fd5b5060015461042d9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104a8575f80fd5b506104b1610cdb565b6040516102bf9190612bb0565b3480156104c9575f80fd5b506103d46104d8366004612b68565b610d67565b3480156104e8575f80fd5b5061026c610ece565b61026c610794565b348015610504575f80fd5b5061026c610513366004612c03565b610f9d565b348015610523575f80fd5b505f5461042d9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561054e575f80fd5b5061026c61055d366004612b68565b610fea565b61026c610570366004612b68565b6110c7565b348015610580575f80fd5b5061026c61058f366004612b68565b611154565b34801561059f575f80fd5b5061026c6105ae366004612b68565b6112a5565b3480156105be575f80fd5b50600a546102b39060ff1681565b3480156105d7575f80fd5b506102b36105e6366004612b68565b60066020525f908152604090205460ff1681565b348015610605575f80fd5b5061026c610614366004612b68565b611382565b348015610624575f80fd5b5061026c61145b565b348015610638575f80fd5b5061026c610647366004612c03565b611489565b348015610657575f80fd5b5061026c61158d565b34801561066b575f80fd5b5061026c61163b565b34801561067f575f80fd5b5061026c61068e366004612b68565b611686565b34801561069e575f80fd5b5061026c6106ad366004612b68565b611697565b3480156106bd575f80fd5b5061026c6106cc366004612b68565b611770565b3480156106dc575f80fd5b5061026c611781565b3480156106f0575f80fd5b506103d460085481565b348015610705575f80fd5b506102b3610714366004612b68565b60056020525f908152604090205460ff1681565b348015610733575f80fd5b5061026c610742366004612b68565b611822565b348015610752575f80fd5b5061026c610761366004612c47565b611833565b348015610771575f80fd5b506102b3610780366004612b68565b60036020525f908152604090205460ff1681565b61079c611a68565b6107a533611aa5565b6107ae33611b04565b6107b83433611b63565b335f908152600760209081526040808320815160e0810183528154815260018201549381019390935260028101548383015260038101546060840152600481015473ffffffffffffffffffffffffffffffffffffffff8116608085015274010000000000000000000000000000000000000000900460ff16151560a08401528151610140810192839052909160c0840191906005840190600a9082845b8154815260200190600101908083116108555750505091909252505050608081015190915073ffffffffffffffffffffffffffffffffffffffff16156108be576108a28160800151611aa5565b6108af8160800151611b04565b6108be33826080015134611c8a565b50565b6108c9611a68565b6108d281611aa5565b6108db81611b04565b345f03610914576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600760205260409020600481015474010000000000000000000000000000000000000000900460ff161561098f576040517fd206192300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80545f036109c9576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109d33483611b63565b600481015473ffffffffffffffffffffffffffffffffffffffff1615610a62576004810154610a179073ffffffffffffffffffffffffffffffffffffffff16611aa5565b6004810154610a3b9073ffffffffffffffffffffffffffffffffffffffff16611b04565b6004810154610a6290839073ffffffffffffffffffffffffffffffffffffffff1634611c8a565b60405134815273ffffffffffffffffffffffffffffffffffffffff83169033907f574529f953f301e05f2f1da6e9b7798bf90eef9d89647f049f43c6e8cb842c5c9060200160405180910390a35050565b610abb611f18565b610ac3611f99565b610acd8282611fe1565b610af660017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050565b610b026121da565b73ffffffffffffffffffffffffffffffffffffffff8116610b4f576040517fc81abf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22905f90a250565b610bc56121da565b60025473ffffffffffffffffffffffffffffffffffffffff9081169082168103610c1b576040517fdaf2d6bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84811691821790925560405190918316907fc4e7dd75c3c361103a75b9cc2efbd3c42ff8f20d1e60387292bb3ca1696b49eb905f90a35050565b610c98611f18565b610ca061222a565b610ca981611aa5565b610cb281612272565b6108be60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b60098054610ce890612d48565b80601f0160208091040260200160405190810160405280929190818152602001828054610d1490612d48565b8015610d5f5780601f10610d3657610100808354040283529160200191610d5f565b820191905f5260205f20905b815481529060010190602001808311610d4257829003601f168201915b505050505081565b73ffffffffffffffffffffffffffffffffffffffff8181165f908152600760209081526040808320815160e0810183528154815260018201549381019390935260028101548383015260038101546060840152600481015494851660808401527401000000000000000000000000000000000000000090940460ff16151560a0830152805161014081019182905292938493909160c0840191906005840190600a9082845b815481526020019060010190808311610e0c575050509190925250505073ffffffffffffffffffffffffffffffffffffffff84165f908152600360205260408120549192509060ff1680610e84575073ffffffffffffffffffffffffffffffffffffffff84165f9081526004602052604090205460ff165b15610e9257505f9392505050565b8160a0015115610ea357505f610eb7565b60208201518251610eb49190612dc6565b90505b6040820151610ec69082612ddf565b949350505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610f1f576040517fd74b334e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80546001805473ffffffffffffffffffffffffffffffffffffffff8082167fffffffffffffffffffffffff000000000000000000000000000000000000000080861682178755909216909255604051919092169283917fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9190a350565b610fa56121da565b600880549082905560408051828152602081018490527f339836fabaa5f0eb442f133ec346175cc489ac04dbca653e7dd68dd1c6b56319910160405180910390a15050565b610ff26121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526005602052604090205460ff1615611051576040517f70b9b0d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fe2d01cc637b0a35c9a2dde2789da012cf2b5d14caa779d280c35209b48c31cf29190a250565b6110cf611a68565b6110d833611aa5565b6110e181611aa5565b6110ea33611b04565b6110f381611b04565b335f908152600760205260409020600181015490541461113f576040517fcf78930100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111493433611b63565b6108be338234611c8a565b60015474010000000000000000000000000000000000000000900460ff16156111a9576040517fe595c67400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166111f6576040517fc81abf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790555f805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116811782556040519091907fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c908290a350565b6112ad6121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526006602052604090205460ff161561130c576040517fd4ecc76600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526006602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f018d27189c54515c0464a9160b88974100b4ea338e1e5a16581a580cdd08c76b9190a250565b61138a6121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526005602052604090205460ff166113e8576040517fd56b8a2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f09af5383361cf92f81a21f5147c84aed80ff6d5087bf486623c1d7c43699ab9e9190a250565b611463611a68565b61146c33611aa5565b61147533611b04565b61147e33612441565b61148733612539565b565b611491611f18565b6114996121da565b5f805460405173ffffffffffffffffffffffffffffffffffffffff9091169083908381818185875af1925050503d805f81146114f0576040519150601f19603f3d011682016040523d82523d5f602084013e6114f5565b606091505b5050905080611530576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518281527f104fad8a72e99cad30d4f34b4863020512b61408ab677d7f0c9eae735c31a8679060200160405180910390a1506108be60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b61159561222a565b600a5460ff16156115d2576040517fab35696f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155604080519182524260208301527f5297bdbba6a0f5b1f239889b8bd6040ef096d48d0568711dd5dfa1c31607a8f591015b60405180910390a1565b611643611f18565b61164b611a68565b61165433611aa5565b61165d33612272565b61148760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b61168e611f99565b6108be8161269c565b61169f6121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526006602052604090205460ff166116fd576040517facceb67400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526006602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f8019d8c46c8bc3cf3019ff5b55be5dcdb8aa616d3512ad006c7dee175f090b3c9190a250565b611778611f99565b6108be81612803565b6117896121da565b600a5460ff166117c5576040517f960c07ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055604080515f81524260208201527f5297bdbba6a0f5b1f239889b8bd6040ef096d48d0568711dd5dfa1c31607a8f59101611631565b61182a611f99565b6108be8161295d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f8115801561187d5750825b90505f8267ffffffffffffffff1660011480156118995750303b155b9050811580156118a7575080155b156118de576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001178555831561193f5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b600a54610100900460ff1615611981576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead17905560096119e58782612e3e565b506276a7006008556119f687611154565b6119fe612ac1565b8315611a5f5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b600a5460ff1615611487576040517fab35696f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff16156108be576040517f8456d42b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526003602052604090205460ff16156108be576040517fa1a04a3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815f03611b9c576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600760205260409020600481015474010000000000000000000000000000000000000000900460ff1615611c17576040517fd206192300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805483825f611c268385612ddf565b9091555050815460405173ffffffffffffffffffffffffffffffffffffffff8516917ff3ee618df6e6ff5a26ef25cf1ba9bc24b56492f5ff29acf2815121a2b903138a91611c7c91858252602082015260400190565b60405180910390a250505050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611cef576040517fef99396c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216611d3c576040517fe04bb5d900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83165f90815260076020526040902060018101548154611d719190612dc6565b821115611daa576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600481015473ffffffffffffffffffffffffffffffffffffffff1615801590611df05750600481015473ffffffffffffffffffffffffffffffffffffffff848116911614155b15611e27576040517f4efd913f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81816001015f828254611e3a9190612ddf565b90915550506004810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85169081179091555f9081526007602052604081206002018054849290611ea4908490612ddf565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fd39549de9e66b0b67e3696e4d033b914ea92d1fa64a28ee38da6938575214aaa84604051611f0a91815260200190565b60405180910390a350505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01611f93576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b335f9081526006602052604090205460ff16611487576040517facceb67400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f908152600760205260409020805482116120135781612016565b80545b915081815f015f82825461202a9190612dc6565b9091555050600481015473ffffffffffffffffffffffffffffffffffffffff16156120d55773ffffffffffffffffffffffffffffffffffffffff83165f9081526004602052604090205460ff166120bc57600481015473ffffffffffffffffffffffffffffffffffffffff165f90815260076020526040812060020180548492906120b6908490612dc6565b90915550505b81816001015f8282546120cf9190612dc6565b90915550505b6002546040515f9173ffffffffffffffffffffffffffffffffffffffff169084908381818185875af1925050503d805f811461212c576040519150601f19603f3d011682016040523d82523d5f602084013e612131565b606091505b505090508061216c576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff167f4ed05e9673c26d2ed44f7ef6a7f2942df0ee3b5e1e17db4b99f9dcd261a339cd84604051611c7c91815260200190565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5f5473ffffffffffffffffffffffffffffffffffffffff163314611487576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f9081526005602052604090205460ff16611487576040517fd56b8a2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600760205260409020600481015474010000000000000000000000000000000000000000900460ff166122ec576040517f5bc0da6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806003015442101561232a576040517f442c667900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80545f8083556004830180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690556003830181905560405173ffffffffffffffffffffffffffffffffffffffff85169083908381818185875af1925050503d805f81146123b4576040519150601f19603f3d011682016040523d82523d5f602084013e6123b9565b606091505b50509050806123f4576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518381525f602082015273ffffffffffffffffffffffffffffffffffffffff8616917ff3ee618df6e6ff5a26ef25cf1ba9bc24b56492f5ff29acf2815121a2b903138a9101611c7c565b73ffffffffffffffffffffffffffffffffffffffff8082165f90815260076020526040902060048101546001820154919216908015612533575f6001840181905573ffffffffffffffffffffffffffffffffffffffff8316815260076020526040812060020180548392906124b7908490612dc6565b90915550506004830180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560405181815273ffffffffffffffffffffffffffffffffffffffff83811691908616907f77d8b2d5629f40603353a7f0167e22f1e42d23732efdd24a8ffd477f6812e4b390602001611f0a565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526007602052604081208054909103612598576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600481015474010000000000000000000000000000000000000000900460ff16156125ef576040517fd206192300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004810180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905560085461263d9042612ddf565b60038201819055815460408051918252602082019290925273ffffffffffffffffffffffffffffffffffffffff8416917fedc81e3c02710417110cba808754556207918ce8d29647c4b90fe924e7af3f1a910160405180910390a25050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff166126fa576040517f1dee782100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8082165f90815260046020818152604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556007909152909120015416156127a65773ffffffffffffffffffffffffffffffffffffffff8082165f9081526007602052604080822080546004909101549093168252812060020180549091906127a0908490612ddf565b90915550505b73ffffffffffffffffffffffffffffffffffffffff81165f818152600760209081526040918290205491519182527ff2d07850f24dfd156502c73101307c83043b7ff3aa3191472e9a1e659050491291015b60405180910390a250565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526003602052604090205460ff1615612862576040517f982b22b100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff1615612898576128988161269c565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556007909152902054156128fe576128fe81612539565b61290781612441565b73ffffffffffffffffffffffffffffffffffffffff81165f818152600760209081526040918290205491519182527fba14e0826c92db7828c6814f979548c85017302becc8ea5ca79b6be627d1160a91016127f8565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff16156129bc576040517f29a2d6c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8082165f90815260046020818152604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055600790915290912001541615612a6b5773ffffffffffffffffffffffffffffffffffffffff8082165f908152600760205260408082208054600490910154909316825281206002018054909190612a65908490612dc6565b90915550505b73ffffffffffffffffffffffffffffffffffffffff81165f818152600760209081526040918290205491519182527f98bc7e294f14c351ce5766e9f1c1fd9e692a768b572d75ad0589496247bd8e2e91016127f8565b612ac9612ad1565b611487612b38565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16611487576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121b4612ad1565b803573ffffffffffffffffffffffffffffffffffffffff81168114612b63575f80fd5b919050565b5f60208284031215612b78575f80fd5b612b8182612b40565b9392505050565b5f8060408385031215612b99575f80fd5b612ba283612b40565b946020939093013593505050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f60208284031215612c13575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f8060408385031215612c58575f80fd5b612c6183612b40565b9150602083013567ffffffffffffffff811115612c7c575f80fd5b8301601f81018513612c8c575f80fd5b803567ffffffffffffffff811115612ca657612ca6612c1a565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715612d1257612d12612c1a565b604052818152828201602001871015612d29575f80fd5b816020840160208301375f602083830101528093505050509250929050565b600181811c90821680612d5c57607f821691505b602082108103612d93577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115612dd957612dd9612d99565b92915050565b80820180821115612dd957612dd9612d99565b601f821115612e3957805f5260205f20601f840160051c81016020851015612e175750805b601f840160051c820191505b81811015612e36575f8155600101612e23565b50505b505050565b815167ffffffffffffffff811115612e5857612e58612c1a565b612e6c81612e668454612d48565b84612df2565b6020601f821160018114612ebd575f8315612e875750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455612e36565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b82811015612f0a5787850151825560209485019460019092019101612eea565b5084821015612f4657868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b0190555056fea2646970667358221220c201e946f20e51d43fd96286bb955d49068e981a595f5bc91f595cb739b0d6a264736f6c634300081a0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in FRAX
0
Token Allocations
FRAX
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| FRAXTAL | 100.00% | $0.988513 | 0.000000002929 | <$0.000001 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.