| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| 0x67999bf63c33800f0d49b03da306a4210fd9889fbb34bc4b260af4134b7cc84f | Claim Rewards | (pending) | 7 days ago | IN | 0 ETH | (Pending) | |||
| Claim Rewards | 24209812 | 25 mins ago | IN | 0 ETH | 0.00000306 | ||||
| Claim Rewards | 24209774 | 33 mins ago | IN | 0 ETH | 0.0000025 | ||||
| Claim Rewards | 24209741 | 39 mins ago | IN | 0 ETH | 0.00000292 | ||||
| Claim Rewards | 24209730 | 42 mins ago | IN | 0 ETH | 0.00015328 | ||||
| Claim Rewards | 24209488 | 1 hr ago | IN | 0 ETH | 0.00000281 | ||||
| Claim Rewards | 24209423 | 1 hr ago | IN | 0 ETH | 0.00000242 | ||||
| Claim Rewards | 24209361 | 1 hr ago | IN | 0 ETH | 0.00000328 | ||||
| Claim Rewards | 24209349 | 1 hr ago | IN | 0 ETH | 0.0000024 | ||||
| Claim Rewards | 24209341 | 2 hrs ago | IN | 0 ETH | 0.00000248 | ||||
| Claim Rewards | 24209190 | 2 hrs ago | IN | 0 ETH | 0.00000244 | ||||
| Claim Rewards | 24209176 | 2 hrs ago | IN | 0 ETH | 0.00003989 | ||||
| Claim Rewards | 24208981 | 3 hrs ago | IN | 0 ETH | 0.00000241 | ||||
| Claim Rewards | 24208819 | 3 hrs ago | IN | 0 ETH | 0.00004013 | ||||
| Claim Rewards | 24208750 | 3 hrs ago | IN | 0 ETH | 0.00000242 | ||||
| Claim Rewards | 24208694 | 4 hrs ago | IN | 0 ETH | 0.0000023 | ||||
| Claim Rewards | 24208602 | 4 hrs ago | IN | 0 ETH | 0.00000618 | ||||
| Claim Rewards | 24208501 | 4 hrs ago | IN | 0 ETH | 0.00000235 | ||||
| Claim Rewards | 24208475 | 4 hrs ago | IN | 0 ETH | 0.00000213 | ||||
| Claim Rewards | 24208366 | 5 hrs ago | IN | 0 ETH | 0.00000371 | ||||
| Claim Rewards | 24208359 | 5 hrs ago | IN | 0 ETH | 0.00000268 | ||||
| Claim Rewards | 24207931 | 6 hrs ago | IN | 0 ETH | 0.00000252 | ||||
| Claim Rewards | 24207915 | 6 hrs ago | IN | 0 ETH | 0.00015293 | ||||
| Claim Rewards | 24207838 | 7 hrs ago | IN | 0 ETH | 0.00000229 | ||||
| Claim Rewards | 24207597 | 7 hrs ago | IN | 0 ETH | 0.00000246 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
PermanentNFTStaking
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
No with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
import "../lib/contracts/contracts/base/Staking721Base.sol";
/**
* @title PermanentNFTStaking
* @dev NFT staking contract where NFTs are permanently locked after staking.
* Users cannot withdraw their NFTs once staked, but the owner can perform emergency withdrawals.
*/
contract PermanentNFTStaking is Staking721Base {
/// @dev Maximum NFTs that can be withdrawn in a single emergency batch
uint256 public constant MAX_EMERGENCY_WITHDRAW_BATCH = 300;
constructor(
address _defaultAdmin,
uint256 _timeUnit,
uint256 _rewardsPerUnitTime,
address _stakingToken,
address _rewardToken,
address _nativeTokenWrapper
) Staking721Base(
_defaultAdmin,
_timeUnit,
_rewardsPerUnitTime,
_stakingToken,
_rewardToken,
_nativeTokenWrapper
) {}
/**
* @dev Instead of overriding withdraw, we intercept the call in Staking721Base._withdraw
*/
function _withdraw(uint256[] calldata) internal pure override {
revert("NFTs are permanently staked");
}
/**
* @dev Emergency withdraw function that can only be called by the owner
* @param _tokenIds Array of token IDs to withdraw
* @param _recipient Address to send the NFTs to
*/
function emergencyWithdraw(uint256[] calldata _tokenIds, address _recipient) external nonReentrant {
require(msg.sender == owner(), "Only owner can emergency withdraw");
require(_recipient != address(0), "Cannot withdraw to zero address");
require(_tokenIds.length <= MAX_EMERGENCY_WITHDRAW_BATCH, "Batch too large");
address _stakingToken = stakingToken;
for (uint256 i = 0; i < _tokenIds.length; i++) {
// Check if the token is actually staked in this contract
require(stakerAddress[_tokenIds[i]] != address(0), "Token not staked");
// Clear staking data
address staker = stakerAddress[_tokenIds[i]];
stakerAddress[_tokenIds[i]] = address(0);
// Update staker data
if (stakers[staker].amountStaked > 0) {
_updateUnclaimedRewardsForStaker(staker);
stakers[staker].amountStaked -= 1;
// Remove staker from array if no tokens left
if (stakers[staker].amountStaked == 0) {
for (uint256 j = 0; j < stakersArray.length; j++) {
if (stakersArray[j] == staker) {
stakersArray[j] = stakersArray[stakersArray.length - 1];
stakersArray.pop();
break;
}
}
}
}
// Transfer NFT to recipient
IERC721(_stakingToken).safeTransferFrom(address(this), _recipient, _tokenIds[i]);
}
emit EmergencyWithdraw(msg.sender, _recipient, _tokenIds);
}
/**
* @dev Event emitted when owner performs emergency withdrawal
*/
event EmergencyWithdraw(address indexed owner, address indexed recipient, uint256[] tokenIds);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../extension/ContractMetadata.sol";
import "../extension/Multicall.sol";
import "../extension/Ownable.sol";
import "../extension/Staking721.sol";
import "../eip/ERC165.sol";
import "../eip/interface/IERC20.sol";
import "../eip/interface/IERC721Receiver.sol";
import { CurrencyTransferLib } from "../lib/CurrencyTransferLib.sol";
/**
*
* EXTENSION: Staking721
*
* The `Staking721Base` smart contract implements NFT staking mechanism.
* Allows users to stake their ERC-721 NFTs and earn rewards in form of ERC-20 tokens.
*
* Following features and implementation setup must be noted:
*
* - ERC-721 NFTs from only one NFT collection can be staked.
*
* - Contract admin can choose to give out rewards by either transferring or minting the rewardToken,
* which is an ERC20 token. See {_mintRewards}.
*
* - To implement custom logic for staking, reward calculation, etc. corresponding functions can be
* overridden from the extension `Staking721`.
*
* - Ownership of the contract, with the ability to restrict certain functions to
* only be called by the contract's owner.
*
* - Multicall capability to perform multiple actions atomically.
*
*/
/// note: This contract is provided as a base contract.
// This is to support a variety of use-cases that can be build on top of this base.
//
// Additional functionality such as deposit functions, reward-minting, etc.
// must be implemented by the deployer of this contract, as needed for their use-case.
contract Staking721Base is ContractMetadata, Multicall, Ownable, Staking721, ERC165, IERC721Receiver {
/// @dev ERC20 Reward Token address. See {_mintRewards} below.
address public immutable rewardToken;
/// @dev The address of the native token wrapper contract.
address public immutable nativeTokenWrapper;
/// @dev Total amount of reward tokens in the contract.
uint256 private rewardTokenBalance;
constructor(
address _defaultAdmin,
uint256 _timeUnit,
uint256 _rewardsPerUnitTime,
address _stakingToken,
address _rewardToken,
address _nativeTokenWrapper
) Staking721(_stakingToken) {
_setupOwner(_defaultAdmin);
_setStakingCondition(_timeUnit, _rewardsPerUnitTime);
rewardToken = _rewardToken;
nativeTokenWrapper = _nativeTokenWrapper;
}
/// @dev Lets the contract receive ether to unwrap native tokens.
receive() external payable virtual {
require(msg.sender == nativeTokenWrapper, "caller not native token wrapper.");
}
/// @dev Admin deposits reward tokens.
function depositRewardTokens(uint256 _amount) external payable virtual nonReentrant {
_depositRewardTokens(_amount); // override this for custom logic.
}
/// @dev Admin can withdraw excess reward tokens.
function withdrawRewardTokens(uint256 _amount) external virtual nonReentrant {
_withdrawRewardTokens(_amount); // override this for custom logic.
}
/// @notice View total rewards available in the staking contract.
function getRewardTokenBalance() external view virtual override returns (uint256) {
return rewardTokenBalance;
}
/*///////////////////////////////////////////////////////////////
ERC 165 / 721 logic
//////////////////////////////////////////////////////////////*/
function onERC721Received(
address,
address,
uint256,
bytes calldata
) external view virtual override returns (bytes4) {
require(isStaking == 2, "Direct transfer");
return this.onERC721Received.selector;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC721Receiver).interfaceId || super.supportsInterface(interfaceId);
}
/*//////////////////////////////////////////////////////////////
Minting logic
//////////////////////////////////////////////////////////////*/
/**
* @dev Mint ERC20 rewards to the staker. Override for custom logic.
*
* @param _staker Address for which to calculated rewards.
* @param _rewards Amount of tokens to be given out as reward.
*
*/
function _mintRewards(address _staker, uint256 _rewards) internal virtual override {
require(_rewards <= rewardTokenBalance, "Not enough reward tokens");
rewardTokenBalance -= _rewards;
CurrencyTransferLib.transferCurrencyWithWrapper(
rewardToken,
address(this),
_staker,
_rewards,
nativeTokenWrapper
);
}
/*//////////////////////////////////////////////////////////////
Other Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Admin deposits reward tokens -- override for custom logic.
function _depositRewardTokens(uint256 _amount) internal virtual {
require(msg.sender == owner(), "Not authorized");
address _rewardToken = rewardToken == CurrencyTransferLib.NATIVE_TOKEN ? nativeTokenWrapper : rewardToken;
uint256 balanceBefore = IERC20(_rewardToken).balanceOf(address(this));
CurrencyTransferLib.transferCurrencyWithWrapper(
rewardToken,
msg.sender,
address(this),
_amount,
nativeTokenWrapper
);
uint256 actualAmount = IERC20(_rewardToken).balanceOf(address(this)) - balanceBefore;
rewardTokenBalance += actualAmount;
}
/// @dev Admin can withdraw excess reward tokens -- override for custom logic.
function _withdrawRewardTokens(uint256 _amount) internal virtual {
require(msg.sender == owner(), "Not authorized");
// to prevent locking of direct-transferred tokens
rewardTokenBalance = _amount > rewardTokenBalance ? 0 : rewardTokenBalance - _amount;
CurrencyTransferLib.transferCurrencyWithWrapper(
rewardToken,
address(this),
msg.sender,
_amount,
nativeTokenWrapper
);
}
/// @dev Returns whether staking restrictions can be set in given execution context.
function _canSetStakeConditions() internal view virtual override returns (bool) {
return msg.sender == owner();
}
/// @dev Returns whether contract metadata can be set in the given execution context.
function _canSetContractURI() internal view virtual override returns (bool) {
return msg.sender == owner();
}
/// @dev Returns whether owner can be set in the given execution context.
function _canSetOwner() internal view virtual override returns (bool) {
return msg.sender == owner();
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "./interface/IContractMetadata.sol";
/**
* @title Contract Metadata
* @notice Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
* for you contract.
* Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
*/
abstract contract ContractMetadata is IContractMetadata {
/// @dev The sender is not authorized to perform the action
error ContractMetadataUnauthorized();
/// @notice Returns the contract metadata URI.
string public override contractURI;
/**
* @notice Lets a contract admin set the URI for contract-level metadata.
* @dev Caller should be authorized to setup contractURI, e.g. contract admin.
* See {_canSetContractURI}.
* Emits {ContractURIUpdated Event}.
*
* @param _uri keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
*/
function setContractURI(string memory _uri) external override {
if (!_canSetContractURI()) {
revert ContractMetadataUnauthorized();
}
_setupContractURI(_uri);
}
/// @dev Lets a contract admin set the URI for contract-level metadata.
function _setupContractURI(string memory _uri) internal {
string memory prevURI = contractURI;
contractURI = _uri;
emit ContractURIUpdated(prevURI, _uri);
}
/// @dev Returns whether contract metadata can be set in the given execution context.
function _canSetContractURI() internal view virtual returns (bool);
}// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../lib/Address.sol";
import "./interface/IMulticall.sol";
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* _Available since v4.1._
*/
contract Multicall is IMulticall {
/**
* @notice Receives and executes a batch of function calls on this contract.
* @dev Receives and executes a batch of function calls on this contract.
*
* @param data The bytes data that makes up the batch of function calls to execute.
* @return results The bytes data that makes up the result of the batch of function calls executed.
*/
function multicall(bytes[] calldata data) external returns (bytes[] memory results) {
results = new bytes[](data.length);
address sender = _msgSender();
bool isForwarder = msg.sender != sender;
for (uint256 i = 0; i < data.length; i++) {
if (isForwarder) {
results[i] = Address.functionDelegateCall(address(this), abi.encodePacked(data[i], sender));
} else {
results[i] = Address.functionDelegateCall(address(this), data[i]);
}
}
return results;
}
/// @notice Returns the sender in the given execution context.
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "./interface/IOwnable.sol";
/**
* @title Ownable
* @notice Thirdweb's `Ownable` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* who the 'owner' of the inheriting smart contract is, and lets the inheriting contract perform conditional logic that uses
* information about who the contract's owner is.
*/
abstract contract Ownable is IOwnable {
/// @dev The sender is not authorized to perform the action
error OwnableUnauthorized();
/// @dev Owner of the contract (purpose: OpenSea compatibility)
address private _owner;
/// @dev Reverts if caller is not the owner.
modifier onlyOwner() {
if (msg.sender != _owner) {
revert OwnableUnauthorized();
}
_;
}
/**
* @notice Returns the owner of the contract.
*/
function owner() public view override returns (address) {
return _owner;
}
/**
* @notice Lets an authorized wallet set a new owner for the contract.
* @param _newOwner The address to set as the new owner of the contract.
*/
function setOwner(address _newOwner) external override {
if (!_canSetOwner()) {
revert OwnableUnauthorized();
}
_setupOwner(_newOwner);
}
/// @dev Lets a contract admin set a new owner for the contract. The new owner must be a contract admin.
function _setupOwner(address _newOwner) internal {
address _prevOwner = _owner;
_owner = _newOwner;
emit OwnerUpdated(_prevOwner, _newOwner);
}
/// @dev Returns whether owner can be set in the given execution context.
function _canSetOwner() internal view virtual returns (bool);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
/// @author thirdweb
import "../external-deps/openzeppelin/security/ReentrancyGuard.sol";
import "../external-deps/openzeppelin/utils/math/SafeMath.sol";
import "../eip/interface/IERC721.sol";
import "./interface/IStaking721.sol";
abstract contract Staking721 is ReentrancyGuard, IStaking721 {
/*///////////////////////////////////////////////////////////////
State variables / Mappings
//////////////////////////////////////////////////////////////*/
///@dev Address of ERC721 NFT contract -- staked tokens belong to this contract.
address public immutable stakingToken;
/// @dev Flag to check direct transfers of staking tokens.
uint8 internal isStaking = 1;
///@dev Next staking condition Id. Tracks number of conditon updates so far.
uint64 private nextConditionId;
///@dev List of token-ids ever staked.
uint256[] public indexedTokens;
/// @dev List of accounts that have staked their NFTs.
address[] public stakersArray;
///@dev Mapping from token-id to whether it is indexed or not.
mapping(uint256 => bool) public isIndexed;
///@dev Mapping from staker address to Staker struct. See {struct IStaking721.Staker}.
mapping(address => Staker) public stakers;
/// @dev Mapping from staked token-id to staker address.
mapping(uint256 => address) public stakerAddress;
///@dev Mapping from condition Id to staking condition. See {struct IStaking721.StakingCondition}
mapping(uint256 => StakingCondition) private stakingConditions;
constructor(address _stakingToken) ReentrancyGuard() {
require(address(_stakingToken) != address(0), "collection address 0");
stakingToken = _stakingToken;
}
/*///////////////////////////////////////////////////////////////
External/Public Functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Stake ERC721 Tokens.
*
* @dev See {_stake}. Override that to implement custom logic.
*
* @param _tokenIds List of tokens to stake.
*/
function stake(uint256[] calldata _tokenIds) external nonReentrant {
_stake(_tokenIds);
}
/**
* @notice Withdraw staked tokens.
*
* @dev See {_withdraw}. Override that to implement custom logic.
*
* @param _tokenIds List of tokens to withdraw.
*/
function withdraw(uint256[] calldata _tokenIds) external nonReentrant {
_withdraw(_tokenIds);
}
/**
* @notice Claim accumulated rewards.
*
* @dev See {_claimRewards}. Override that to implement custom logic.
* See {_calculateRewards} for reward-calculation logic.
*/
function claimRewards() external nonReentrant {
_claimRewards();
}
/**
* @notice Set time unit. Set as a number of seconds.
* Could be specified as -- x * 1 hours, x * 1 days, etc.
*
* @dev Only admin/authorized-account can call it.
*
*
* @param _timeUnit New time unit.
*/
function setTimeUnit(uint256 _timeUnit) external virtual {
if (!_canSetStakeConditions()) {
revert("Not authorized");
}
StakingCondition memory condition = stakingConditions[nextConditionId - 1];
require(_timeUnit != condition.timeUnit, "Time-unit unchanged.");
_setStakingCondition(_timeUnit, condition.rewardsPerUnitTime);
emit UpdatedTimeUnit(condition.timeUnit, _timeUnit);
}
/**
* @notice Set rewards per unit of time.
* Interpreted as x rewards per second/per day/etc based on time-unit.
*
* @dev Only admin/authorized-account can call it.
*
*
* @param _rewardsPerUnitTime New rewards per unit time.
*/
function setRewardsPerUnitTime(uint256 _rewardsPerUnitTime) external virtual {
if (!_canSetStakeConditions()) {
revert("Not authorized");
}
StakingCondition memory condition = stakingConditions[nextConditionId - 1];
require(_rewardsPerUnitTime != condition.rewardsPerUnitTime, "Reward unchanged.");
_setStakingCondition(condition.timeUnit, _rewardsPerUnitTime);
emit UpdatedRewardsPerUnitTime(condition.rewardsPerUnitTime, _rewardsPerUnitTime);
}
/**
* @notice View amount staked and total rewards for a user.
*
* @param _staker Address for which to calculated rewards.
* @return _tokensStaked List of token-ids staked by staker.
* @return _rewards Available reward amount.
*/
function getStakeInfo(
address _staker
) external view virtual returns (uint256[] memory _tokensStaked, uint256 _rewards) {
uint256[] memory _indexedTokens = indexedTokens;
bool[] memory _isStakerToken = new bool[](_indexedTokens.length);
uint256 indexedTokenCount = _indexedTokens.length;
uint256 stakerTokenCount = 0;
for (uint256 i = 0; i < indexedTokenCount; i++) {
_isStakerToken[i] = stakerAddress[_indexedTokens[i]] == _staker;
if (_isStakerToken[i]) stakerTokenCount += 1;
}
_tokensStaked = new uint256[](stakerTokenCount);
uint256 count = 0;
for (uint256 i = 0; i < indexedTokenCount; i++) {
if (_isStakerToken[i]) {
_tokensStaked[count] = _indexedTokens[i];
count += 1;
}
}
_rewards = _availableRewards(_staker);
}
function getTimeUnit() public view returns (uint256 _timeUnit) {
_timeUnit = stakingConditions[nextConditionId - 1].timeUnit;
}
function getRewardsPerUnitTime() public view returns (uint256 _rewardsPerUnitTime) {
_rewardsPerUnitTime = stakingConditions[nextConditionId - 1].rewardsPerUnitTime;
}
/*///////////////////////////////////////////////////////////////
Internal Functions
//////////////////////////////////////////////////////////////*/
/// @dev Staking logic. Override to add custom logic.
function _stake(uint256[] calldata _tokenIds) internal virtual {
uint64 len = uint64(_tokenIds.length);
require(len != 0, "Staking 0 tokens");
address _stakingToken = stakingToken;
if (stakers[_stakeMsgSender()].amountStaked > 0) {
_updateUnclaimedRewardsForStaker(_stakeMsgSender());
} else {
stakersArray.push(_stakeMsgSender());
stakers[_stakeMsgSender()].timeOfLastUpdate = uint128(block.timestamp);
stakers[_stakeMsgSender()].conditionIdOflastUpdate = nextConditionId - 1;
}
for (uint256 i = 0; i < len; ++i) {
isStaking = 2;
IERC721(_stakingToken).safeTransferFrom(_stakeMsgSender(), address(this), _tokenIds[i]);
isStaking = 1;
stakerAddress[_tokenIds[i]] = _stakeMsgSender();
if (!isIndexed[_tokenIds[i]]) {
isIndexed[_tokenIds[i]] = true;
indexedTokens.push(_tokenIds[i]);
}
}
stakers[_stakeMsgSender()].amountStaked += len;
emit TokensStaked(_stakeMsgSender(), _tokenIds);
}
/// @dev Withdraw logic. Override to add custom logic.
function _withdraw(uint256[] calldata _tokenIds) internal virtual {
uint256 _amountStaked = stakers[_stakeMsgSender()].amountStaked;
uint64 len = uint64(_tokenIds.length);
require(len != 0, "Withdrawing 0 tokens");
require(_amountStaked >= len, "Withdrawing more than staked");
address _stakingToken = stakingToken;
_updateUnclaimedRewardsForStaker(_stakeMsgSender());
if (_amountStaked == len) {
address[] memory _stakersArray = stakersArray;
for (uint256 i = 0; i < _stakersArray.length; ++i) {
if (_stakersArray[i] == _stakeMsgSender()) {
stakersArray[i] = _stakersArray[_stakersArray.length - 1];
stakersArray.pop();
break;
}
}
}
stakers[_stakeMsgSender()].amountStaked -= len;
for (uint256 i = 0; i < len; ++i) {
require(stakerAddress[_tokenIds[i]] == _stakeMsgSender(), "Not staker");
stakerAddress[_tokenIds[i]] = address(0);
IERC721(_stakingToken).safeTransferFrom(address(this), _stakeMsgSender(), _tokenIds[i]);
}
emit TokensWithdrawn(_stakeMsgSender(), _tokenIds);
}
/// @dev Logic for claiming rewards. Override to add custom logic.
function _claimRewards() internal virtual {
uint256 rewards = stakers[_stakeMsgSender()].unclaimedRewards + _calculateRewards(_stakeMsgSender());
require(rewards != 0, "No rewards");
stakers[_stakeMsgSender()].timeOfLastUpdate = uint128(block.timestamp);
stakers[_stakeMsgSender()].unclaimedRewards = 0;
stakers[_stakeMsgSender()].conditionIdOflastUpdate = nextConditionId - 1;
_mintRewards(_stakeMsgSender(), rewards);
emit RewardsClaimed(_stakeMsgSender(), rewards);
}
/// @dev View available rewards for a user.
function _availableRewards(address _user) internal view virtual returns (uint256 _rewards) {
if (stakers[_user].amountStaked == 0) {
_rewards = stakers[_user].unclaimedRewards;
} else {
_rewards = stakers[_user].unclaimedRewards + _calculateRewards(_user);
}
}
/// @dev Update unclaimed rewards for a users. Called for every state change for a user.
function _updateUnclaimedRewardsForStaker(address _staker) internal virtual {
uint256 rewards = _calculateRewards(_staker);
stakers[_staker].unclaimedRewards += rewards;
stakers[_staker].timeOfLastUpdate = uint128(block.timestamp);
stakers[_staker].conditionIdOflastUpdate = nextConditionId - 1;
}
/// @dev Set staking conditions.
function _setStakingCondition(uint256 _timeUnit, uint256 _rewardsPerUnitTime) internal virtual {
require(_timeUnit != 0, "time-unit can't be 0");
uint256 conditionId = nextConditionId;
nextConditionId += 1;
stakingConditions[conditionId] = StakingCondition({
timeUnit: _timeUnit,
rewardsPerUnitTime: _rewardsPerUnitTime,
startTimestamp: block.timestamp,
endTimestamp: 0
});
if (conditionId > 0) {
stakingConditions[conditionId - 1].endTimestamp = block.timestamp;
}
}
/// @dev Calculate rewards for a staker.
function _calculateRewards(address _staker) internal view virtual returns (uint256 _rewards) {
Staker memory staker = stakers[_staker];
uint256 _stakerConditionId = staker.conditionIdOflastUpdate;
uint256 _nextConditionId = nextConditionId;
for (uint256 i = _stakerConditionId; i < _nextConditionId; i += 1) {
StakingCondition memory condition = stakingConditions[i];
uint256 startTime = i != _stakerConditionId ? condition.startTimestamp : staker.timeOfLastUpdate;
uint256 endTime = condition.endTimestamp != 0 ? condition.endTimestamp : block.timestamp;
(bool noOverflowProduct, uint256 rewardsProduct) = SafeMath.tryMul(
(endTime - startTime) * staker.amountStaked,
condition.rewardsPerUnitTime
);
(bool noOverflowSum, uint256 rewardsSum) = SafeMath.tryAdd(_rewards, rewardsProduct / condition.timeUnit);
_rewards = noOverflowProduct && noOverflowSum ? rewardsSum : _rewards;
}
}
/*////////////////////////////////////////////////////////////////////
Optional hooks that can be implemented in the derived contract
///////////////////////////////////////////////////////////////////*/
/// @dev Exposes the ability to override the msg sender -- support ERC2771.
function _stakeMsgSender() internal virtual returns (address) {
return msg.sender;
}
/*///////////////////////////////////////////////////////////////
Virtual functions to be implemented in derived contract
//////////////////////////////////////////////////////////////*/
/**
* @notice View total rewards available in the staking contract.
*
*/
function getRewardTokenBalance() external view virtual returns (uint256 _rewardsAvailableInContract);
/**
* @dev Mint/Transfer ERC20 rewards to the staker. Must override.
*
* @param _staker Address for which to calculated rewards.
* @param _rewards Amount of tokens to be given out as reward.
*
* For example, override as below to mint ERC20 rewards:
*
* ```
* function _mintRewards(address _staker, uint256 _rewards) internal override {
*
* TokenERC20(rewardTokenAddress).mintTo(_staker, _rewards);
*
* }
* ```
*/
function _mintRewards(address _staker, uint256 _rewards) internal virtual;
/**
* @dev Returns whether staking restrictions can be set in given execution context.
* Must override.
*
*
* For example, override as below to restrict access to admin:
*
* ```
* function _canSetStakeConditions() internal override {
*
* return msg.sender == adminAddress;
*
* }
* ```
*/
function _canSetStakeConditions() internal view virtual returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./interface/IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address who) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
// Helper interfaces
import { IWETH } from "../infra/interface/IWETH.sol";
import { SafeERC20, IERC20 } from "../external-deps/openzeppelin/token/ERC20/utils/SafeERC20.sol";
library CurrencyTransferLib {
using SafeERC20 for IERC20;
error CurrencyTransferLibMismatchedValue(uint256 expected, uint256 actual);
error CurrencyTransferLibFailedNativeTransfer(address recipient, uint256 value);
/// @dev The address interpreted as native token of the chain.
address public constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev Transfers a given amount of currency.
function transferCurrency(address _currency, address _from, address _to, uint256 _amount) internal {
if (_amount == 0) {
return;
}
if (_currency == NATIVE_TOKEN) {
safeTransferNativeToken(_to, _amount);
} else {
safeTransferERC20(_currency, _from, _to, _amount);
}
}
/// @dev Transfers a given amount of currency. (With native token wrapping)
function transferCurrencyWithWrapper(
address _currency,
address _from,
address _to,
uint256 _amount,
address _nativeTokenWrapper
) internal {
if (_amount == 0) {
return;
}
if (_currency == NATIVE_TOKEN) {
if (_from == address(this)) {
// withdraw from weth then transfer withdrawn native token to recipient
IWETH(_nativeTokenWrapper).withdraw(_amount);
safeTransferNativeTokenWithWrapper(_to, _amount, _nativeTokenWrapper);
} else if (_to == address(this)) {
// store native currency in weth
if (_amount != msg.value) {
revert CurrencyTransferLibMismatchedValue(msg.value, _amount);
}
IWETH(_nativeTokenWrapper).deposit{ value: _amount }();
} else {
safeTransferNativeTokenWithWrapper(_to, _amount, _nativeTokenWrapper);
}
} else {
safeTransferERC20(_currency, _from, _to, _amount);
}
}
/// @dev Transfer `amount` of ERC20 token from `from` to `to`.
function safeTransferERC20(address _currency, address _from, address _to, uint256 _amount) internal {
if (_from == _to) {
return;
}
if (_from == address(this)) {
IERC20(_currency).safeTransfer(_to, _amount);
} else {
IERC20(_currency).safeTransferFrom(_from, _to, _amount);
}
}
/// @dev Transfers `amount` of native token to `to`.
function safeTransferNativeToken(address to, uint256 value) internal {
// solhint-disable avoid-low-level-calls
// slither-disable-next-line low-level-calls
(bool success, ) = to.call{ value: value }("");
if (!success) {
revert CurrencyTransferLibFailedNativeTransfer(to, value);
}
}
/// @dev Transfers `amount` of native token to `to`. (With native token wrapping)
function safeTransferNativeTokenWithWrapper(address to, uint256 value, address _nativeTokenWrapper) internal {
// solhint-disable avoid-low-level-calls
// slither-disable-next-line low-level-calls
(bool success, ) = to.call{ value: value }("");
if (!success) {
IWETH(_nativeTokenWrapper).deposit{ value: value }();
IERC20(_nativeTokenWrapper).safeTransfer(to, value);
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
* for you contract.
*
* Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
*/
interface IContractMetadata {
/// @dev Returns the metadata URI of the contract.
function contractURI() external view returns (string memory);
/**
* @dev Sets contract URI for the storefront-level metadata of the contract.
* Only module admin can call this function.
*/
function setContractURI(string calldata _uri) external;
/// @dev Emitted when the contract URI is updated.
event ContractURIUpdated(string prevURI, string newURI);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.1;
/// @author thirdweb, OpenZeppelin Contracts (v4.9.0)
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* _Available since v4.1._
*/
interface IMulticall {
/**
* @dev Receives and executes a batch of function calls on this contract.
*/
function multicall(bytes[] calldata data) external returns (bytes[] memory results);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* Thirdweb's `Ownable` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* who the 'owner' of the inheriting smart contract is, and lets the inheriting contract perform conditional logic that uses
* information about who the contract's owner is.
*/
interface IOwnable {
/// @dev Returns the owner of the contract.
function owner() external view returns (address);
/// @dev Lets a module admin set a new owner for the contract. The new owner must be a module admin.
function setOwner(address _newOwner) external;
/// @dev Emitted when a new Owner is set.
event OwnerUpdated(address indexed prevOwner, address indexed newOwner);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address);
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
/// @author thirdweb
interface IStaking721 {
/// @dev Emitted when a set of token-ids are staked.
event TokensStaked(address indexed staker, uint256[] indexed tokenIds);
/// @dev Emitted when a set of staked token-ids are withdrawn.
event TokensWithdrawn(address indexed staker, uint256[] indexed tokenIds);
/// @dev Emitted when a staker claims staking rewards.
event RewardsClaimed(address indexed staker, uint256 rewardAmount);
/// @dev Emitted when contract admin updates timeUnit.
event UpdatedTimeUnit(uint256 oldTimeUnit, uint256 newTimeUnit);
/// @dev Emitted when contract admin updates rewardsPerUnitTime.
event UpdatedRewardsPerUnitTime(uint256 oldRewardsPerUnitTime, uint256 newRewardsPerUnitTime);
/**
* @notice Staker Info.
*
* @param amountStaked Total number of tokens staked by the staker.
*
* @param timeOfLastUpdate Last reward-update timestamp.
*
* @param unclaimedRewards Rewards accumulated but not claimed by user yet.
*
* @param conditionIdOflastUpdate Condition-Id when rewards were last updated for user.
*/
struct Staker {
uint64 amountStaked;
uint64 conditionIdOflastUpdate;
uint128 timeOfLastUpdate;
uint256 unclaimedRewards;
}
/**
* @notice Staking Condition.
*
* @param timeUnit Unit of time specified in number of seconds. Can be set as 1 seconds, 1 days, 1 hours, etc.
*
* @param rewardsPerUnitTime Rewards accumulated per unit of time.
*
* @param startTimestamp Condition start timestamp.
*
* @param endTimestamp Condition end timestamp.
*/
struct StakingCondition {
uint256 timeUnit;
uint256 rewardsPerUnitTime;
uint256 startTimestamp;
uint256 endTimestamp;
}
/**
* @notice Stake ERC721 Tokens.
*
* @param tokenIds List of tokens to stake.
*/
function stake(uint256[] calldata tokenIds) external;
/**
* @notice Withdraw staked tokens.
*
* @param tokenIds List of tokens to withdraw.
*/
function withdraw(uint256[] calldata tokenIds) external;
/**
* @notice Claim accumulated rewards.
*/
function claimRewards() external;
/**
* @notice View amount staked and total rewards for a user.
*
* @param staker Address for which to calculated rewards.
*/
function getStakeInfo(address staker) external view returns (uint256[] memory _tokensStaked, uint256 _rewards);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* [EIP](https://eips.ethereum.org/EIPS/eip-165).
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
interface IWETH {
function deposit() external payable;
function withdraw(uint256 amount) external;
function transfer(address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../../../../../eip/interface/IERC20.sol";
import { Address } from "../../../../../lib/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}{
"remappings": [
"@chainlink/=lib/contracts/lib/chainlink/",
"@ds-test/=lib/contracts/lib/ds-test/src/",
"@openzeppelin/contracts-upgradeable/=lib/contracts/lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/contracts/lib/openzeppelin-contracts/contracts/",
"@rari-capital/solmate/=lib/contracts/lib/seaport/lib/solmate/",
"@seaport/=lib/contracts/lib/seaport/contracts/",
"@solady/=lib/contracts/lib/solady/",
"@std/=lib/contracts/lib/forge-std/src/",
"@thirdweb-dev/dynamic-contracts/=lib/contracts/lib/dynamic-contracts/",
"ERC721A-Upgradeable/=lib/contracts/lib/ERC721A-Upgradeable/contracts/",
"ERC721A/=lib/contracts/lib/ERC721A/contracts/",
"chainlink/=lib/contracts/lib/chainlink/contracts/",
"contracts/=lib/contracts/contracts/",
"ds-test/=lib/contracts/lib/ds-test/src/",
"dynamic-contracts/=lib/contracts/lib/dynamic-contracts/src/",
"erc4626-tests/=lib/contracts/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"erc721a-upgradeable/=lib/contracts/lib/ERC721A-Upgradeable/",
"erc721a/=lib/contracts/lib/ERC721A/",
"forge-std/=lib/contracts/lib/forge-std/src/",
"lib/sstore2/=lib/contracts/lib/dynamic-contracts/lib/sstore2/",
"murky/=lib/contracts/lib/murky/src/",
"openzeppelin-contracts-upgradeable/=lib/contracts/lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/contracts/lib/openzeppelin-contracts/",
"openzeppelin/=lib/contracts/lib/openzeppelin-contracts-upgradeable/contracts/",
"seaport-core/=lib/contracts/lib/seaport-core/src/",
"seaport-sol/=lib/contracts/lib/seaport-sol/src/",
"seaport-types/=lib/contracts/lib/seaport-types/src/",
"seaport/=lib/contracts/lib/seaport/",
"solady/=lib/contracts/lib/solady/src/",
"solarray/=lib/contracts/lib/seaport/lib/solarray/src/",
"solmate/=lib/contracts/lib/seaport/lib/solmate/src/",
"sstore2/=lib/contracts/lib/dynamic-contracts/lib/sstore2/contracts/"
],
"optimizer": {
"enabled": false,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_defaultAdmin","type":"address"},{"internalType":"uint256","name":"_timeUnit","type":"uint256"},{"internalType":"uint256","name":"_rewardsPerUnitTime","type":"uint256"},{"internalType":"address","name":"_stakingToken","type":"address"},{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"address","name":"_nativeTokenWrapper","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ContractMetadataUnauthorized","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"CurrencyTransferLibMismatchedValue","type":"error"},{"inputs":[],"name":"OwnableUnauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"prevURI","type":"string"},{"indexed":false,"internalType":"string","name":"newURI","type":"string"}],"name":"ContractURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"prevOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewardAmount","type":"uint256"}],"name":"RewardsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"TokensStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"TokensWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRewardsPerUnitTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRewardsPerUnitTime","type":"uint256"}],"name":"UpdatedRewardsPerUnitTime","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldTimeUnit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTimeUnit","type":"uint256"}],"name":"UpdatedTimeUnit","type":"event"},{"inputs":[],"name":"MAX_EMERGENCY_WITHDRAW_BATCH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositRewardTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRewardTokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardsPerUnitTime","outputs":[{"internalType":"uint256","name":"_rewardsPerUnitTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"getStakeInfo","outputs":[{"internalType":"uint256[]","name":"_tokensStaked","type":"uint256[]"},{"internalType":"uint256","name":"_rewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTimeUnit","outputs":[{"internalType":"uint256","name":"_timeUnit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"indexedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isIndexed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nativeTokenWrapper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_uri","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardsPerUnitTime","type":"uint256"}],"name":"setRewardsPerUnitTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timeUnit","type":"uint256"}],"name":"setTimeUnit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakers","outputs":[{"internalType":"uint64","name":"amountStaked","type":"uint64"},{"internalType":"uint64","name":"conditionIdOflastUpdate","type":"uint64"},{"internalType":"uint128","name":"timeOfLastUpdate","type":"uint128"},{"internalType":"uint256","name":"unclaimedRewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakersArray","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawRewardTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60e0604052600160035f6101000a81548160ff021916908360ff16021790555034801561002a575f5ffd5b506040516159a43803806159a4833981810160405281019061004c919061042a565b8585858585858260016002819055505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036100c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100c09061050d565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250505061010d8661019660201b60201c565b61011d858561025960201b60201c565b8173ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff1681525050505050505050505050505050610641565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7660405160405180910390a35050565b5f820361029b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161029290610575565b60405180910390fd5b5f600360019054906101000a900467ffffffffffffffff1667ffffffffffffffff1690506001600360018282829054906101000a900467ffffffffffffffff166102e591906105d3565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060405180608001604052808481526020018381526020014281526020015f81525060095f8381526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301559050505f811115610394574260095f60018461037f919061060e565b81526020019081526020015f20600301819055505b505050565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6103c68261039d565b9050919050565b6103d6816103bc565b81146103e0575f5ffd5b50565b5f815190506103f1816103cd565b92915050565b5f819050919050565b610409816103f7565b8114610413575f5ffd5b50565b5f8151905061042481610400565b92915050565b5f5f5f5f5f5f60c0878903121561044457610443610399565b5b5f61045189828a016103e3565b965050602061046289828a01610416565b955050604061047389828a01610416565b945050606061048489828a016103e3565b935050608061049589828a016103e3565b92505060a06104a689828a016103e3565b9150509295509295509295565b5f82825260208201905092915050565b7f636f6c6c656374696f6e206164647265737320300000000000000000000000005f82015250565b5f6104f76014836104b3565b9150610502826104c3565b602082019050919050565b5f6020820190508181035f830152610524816104eb565b9050919050565b7f74696d652d756e69742063616e277420626520300000000000000000000000005f82015250565b5f61055f6014836104b3565b915061056a8261052b565b602082019050919050565b5f6020820190508181035f83015261058c81610553565b9050919050565b5f67ffffffffffffffff82169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6105dd82610593565b91506105e883610593565b9250828201905067ffffffffffffffff811115610608576106076105a6565b5b92915050565b5f610618826103f7565b9150610623836103f7565b925082820390508181111561063b5761063a6105a6565b5b92915050565b60805160a05160c0516152e56106bf5f395f81816101c101528181611b0d01528181612329015281816123ef01528181612d4b015261325901525f8181611ae9015281816122c701528181612303015281816123cb01528181612d27015261323501525f8181610e41015281816113be0152611c0b01526152e55ff3fe6080604052600436106101ba575f3560e01c80639168ae72116100eb578063c345315311610089578063e8a3d48511610063578063e8a3d485146106a5578063f7c618c1146106cf578063f9ea29cb146106f9578063fd48ba17146107235761024f565b8063c345315314610616578063cb43b2dd14610653578063d68124c71461067b5761024f565b806394067045116100c5578063940670451461053a578063961004d314610576578063983d95ce146105b2578063ac9650d8146105da5761024f565b80639168ae72146104a9578063938e3d7b146104e857806393ce5343146105105761024f565b806323ef2580116101585780636360106f116101325780636360106f146104055780636c60d9e71461042d57806372f702f3146104555780638da5cb5b1461047f5761024f565b806323ef25801461038b578063372500ab146103b35780635357e916146103c95761024f565b80630fbf0a93116101945780630fbf0a93146102e357806313af40351461030b578063150b7a021461033357806316c621e01461036f5761024f565b806301ffc9a714610253578063080cd2791461028f5780630e8b229b146102b95761024f565b3661024f577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461024d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161024490613938565b60405180910390fd5b005b5f5ffd5b34801561025e575f5ffd5b50610279600480360381019061027491906139bc565b61075f565b6040516102869190613a01565b60405180910390f35b34801561029a575f5ffd5b506102a36107d8565b6040516102b09190613a32565b60405180910390f35b3480156102c4575f5ffd5b506102cd6107de565b6040516102da9190613a32565b60405180910390f35b3480156102ee575f5ffd5b5061030960048036038101906103049190613aac565b610825565b005b348015610316575f5ffd5b50610331600480360381019061032c9190613b51565b610886565b005b34801561033e575f5ffd5b5061035960048036038101906103549190613bfb565b6108d0565b6040516103669190613c8e565b60405180910390f35b61038960048036038101906103849190613ca7565b610938565b005b348015610396575f5ffd5b506103b160048036038101906103ac9190613ca7565b610997565b005b3480156103be575f5ffd5b506103c7610ae4565b005b3480156103d4575f5ffd5b506103ef60048036038101906103ea9190613ca7565b610b41565b6040516103fc9190613ce1565b60405180910390f35b348015610410575f5ffd5b5061042b60048036038101906104269190613ca7565b610b7c565b005b348015610438575f5ffd5b50610453600480360381019061044e9190613cfa565b610cc8565b005b348015610460575f5ffd5b506104696113bc565b6040516104769190613ce1565b60405180910390f35b34801561048a575f5ffd5b506104936113e0565b6040516104a09190613ce1565b60405180910390f35b3480156104b4575f5ffd5b506104cf60048036038101906104ca9190613b51565b611408565b6040516104df9493929190613da3565b60405180910390f35b3480156104f3575f5ffd5b5061050e60048036038101906105099190613f1e565b611475565b005b34801561051b575f5ffd5b506105246114bf565b6040516105319190613a32565b60405180910390f35b348015610545575f5ffd5b50610560600480360381019061055b9190613ca7565b6114c8565b60405161056d9190613ce1565b60405180910390f35b348015610581575f5ffd5b5061059c60048036038101906105979190613ca7565b6114f8565b6040516105a99190613a32565b60405180910390f35b3480156105bd575f5ffd5b506105d860048036038101906105d39190613aac565b611518565b005b3480156105e5575f5ffd5b5061060060048036038101906105fb9190613fba565b611579565b60405161060d9190614120565b60405180910390f35b348015610621575f5ffd5b5061063c60048036038101906106379190613b51565b61173a565b60405161064a9291906141f7565b60405180910390f35b34801561065e575f5ffd5b5061067960048036038101906106749190613ca7565b6119b7565b005b348015610686575f5ffd5b5061068f611a16565b60405161069c9190613a32565b60405180910390f35b3480156106b0575f5ffd5b506106b9611a5c565b6040516106c69190614267565b60405180910390f35b3480156106da575f5ffd5b506106e3611ae7565b6040516106f09190613ce1565b60405180910390f35b348015610704575f5ffd5b5061070d611b0b565b60405161071a9190613ce1565b60405180910390f35b34801561072e575f5ffd5b5061074960048036038101906107449190613ca7565b611b2f565b6040516107569190613a01565b60405180910390f35b5f7f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806107d157506107d082611b4c565b5b9050919050565b61012c81565b5f60095f6001600360019054906101000a900467ffffffffffffffff1661080591906142b4565b67ffffffffffffffff1681526020019081526020015f2060010154905090565b6002805403610869576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161086090614339565b60405180910390fd5b6002808190555061087a8282611bb5565b60016002819055505050565b61088e612125565b6108c4576040517f2d99739600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108cd81612161565b50565b5f600260035f9054906101000a900460ff1660ff1614610925576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091c906143a1565b60405180910390fd5b63150b7a0260e01b905095945050505050565b600280540361097c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097390614339565b60405180910390fd5b6002808190555061098c81612224565b600160028190555050565b61099f6124b7565b6109de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109d590614409565b60405180910390fd5b5f60095f6001600360019054906101000a900467ffffffffffffffff16610a0591906142b4565b67ffffffffffffffff1681526020019081526020015f206040518060800160405290815f82015481526020016001820154815260200160028201548152602001600382015481525050905080602001518203610a96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a8d90614471565b60405180910390fd5b610aa3815f0151836124f3565b7f243c4656edc72b2c7ec8575d464d955b2f42c1b205960c6c2fb7eecda5419cf6816020015183604051610ad892919061448f565b60405180910390a15050565b6002805403610b28576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1f90614339565b60405180910390fd5b60028081905550610b37612633565b6001600281905550565b60058181548110610b50575f80fd5b905f5260205f20015f915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610b846124b7565b610bc3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bba90614409565b60405180910390fd5b5f60095f6001600360019054906101000a900467ffffffffffffffff16610bea91906142b4565b67ffffffffffffffff1681526020019081526020015f206040518060800160405290815f820154815260200160018201548152602001600282015481526020016003820154815250509050805f01518203610c7a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c7190614500565b60405180910390fd5b610c888282602001516124f3565b7fd968de290ed68f978b9e4816f7d4be9ef46189fe8eeb3eeb86199e7229cf2de0815f015183604051610cbc92919061448f565b60405180910390a15050565b6002805403610d0c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0390614339565b60405180910390fd5b60028081905550610d1b6113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610d88576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7f9061458e565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610df6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ded906145f6565b60405180910390fd5b61012c838390501115610e3e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e359061465e565b60405180910390fd5b5f7f000000000000000000000000000000000000000000000000000000000000000090505f5f90505b84849050811015611346575f73ffffffffffffffffffffffffffffffffffffffff1660085f878785818110610e9f57610e9e61467c565b5b9050602002013581526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1603610f29576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f20906146f3565b60405180910390fd5b5f60085f878785818110610f4057610f3f61467c565b5b9050602002013581526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f60085f888886818110610f8d57610f8c61467c565b5b9050602002013581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1611156112b55761104b8161289b565b600160075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f8282829054906101000a900467ffffffffffffffff166110ad91906142b4565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff16036112b4575f5f90505b6005805490508110156112b2578173ffffffffffffffffffffffffffffffffffffffff16600582815481106111735761117261467c565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16036112a557600560016005805490506111ca9190614711565b815481106111db576111da61467c565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600582815481106112175761121661467c565b5b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600580548061126e5761126d614744565b5b600190038181905f5260205f20015f6101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905590556112b2565b808060010191505061113b565b505b5b8273ffffffffffffffffffffffffffffffffffffffff166342842e0e30868989878181106112e6576112e561467c565b5b905060200201356040518463ffffffff1660e01b815260040161130b93929190614771565b5f604051808303815f87803b158015611322575f5ffd5b505af1158015611334573d5f5f3e3d5ffd5b50505050508080600101915050610e67565b508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f49e7e98dba11447f42e55b1d3976705fad5dfb9df072d68da019756796baf3ef86866040516113a692919061480e565b60405180910390a3506001600281905550505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6007602052805f5260405f205f91509050805f015f9054906101000a900467ffffffffffffffff1690805f0160089054906101000a900467ffffffffffffffff1690805f0160109054906101000a90046fffffffffffffffffffffffffffffffff16908060010154905084565b61147d6129ff565b6114b3576040517f9f7f092500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114bc81612a3b565b50565b5f600a54905090565b6008602052805f5260405f205f915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60048181548110611507575f80fd5b905f5260205f20015f915090505481565b600280540361155c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161155390614339565b60405180910390fd5b6002808190555061156d8282612b12565b60016002819055505050565b60608282905067ffffffffffffffff81111561159857611597613dfa565b5b6040519080825280602002602001820160405280156115cb57816020015b60608152602001906001900390816115b65790505b5090505f6115d7612b4d565b90505f8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141590505f5f90505b8585905081101561173157811561169557611672308787848181106116395761163861467c565b5b905060200281019061164b919061483c565b8660405160200161165e93929190614911565b604051602081830303815290604052612b54565b8482815181106116855761168461467c565b5b6020026020010181905250611724565b611705308787848181106116ac576116ab61467c565b5b90506020028101906116be919061483c565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612b54565b8482815181106117185761171761467c565b5b60200260200101819052505b8080600101915050611611565b50505092915050565b60605f5f600480548060200260200160405190810160405280929190818152602001828054801561178857602002820191905f5260205f20905b815481526020019060010190808311611774575b505050505090505f815167ffffffffffffffff8111156117ab576117aa613dfa565b5b6040519080825280602002602001820160405280156117d95781602001602082028036833780820191505090505b5090505f825190505f5f90505f5f90505b828110156118cd578773ffffffffffffffffffffffffffffffffffffffff1660085f87848151811061181f5761181e61467c565b5b602002602001015181526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161484828151811061187e5761187d61467c565b5b6020026020010190151590811515815250508381815181106118a3576118a261467c565b5b6020026020010151156118c0576001826118bd919061493a565b91505b80806001019150506117ea565b508067ffffffffffffffff8111156118e8576118e7613dfa565b5b6040519080825280602002602001820160405280156119165781602001602082028036833780820191505090505b5095505f5f90505f5f90505b838110156119a15784818151811061193d5761193c61467c565b5b6020026020010151156119945785818151811061195d5761195c61467c565b5b60200260200101518883815181106119785761197761467c565b5b602002602001018181525050600182611991919061493a565b91505b8080600101915050611922565b506119ab88612b81565b95505050505050915091565b60028054036119fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119f290614339565b60405180910390fd5b60028081905550611a0b81612c89565b600160028190555050565b5f60095f6001600360019054906101000a900467ffffffffffffffff16611a3d91906142b4565b67ffffffffffffffff1681526020019081526020015f205f0154905090565b5f8054611a689061499a565b80601f0160208091040260200160405190810160405280929190818152602001828054611a949061499a565b8015611adf5780601f10611ab657610100808354040283529160200191611adf565b820191905f5260205f20905b815481529060010190602001808311611ac257829003601f168201915b505050505081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6006602052805f5260405f205f915054906101000a900460ff1681565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f8282905090505f8167ffffffffffffffff1603611c08576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bff90614a14565b60405180910390fd5b5f7f000000000000000000000000000000000000000000000000000000000000000090505f60075f611c38612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff161115611cac57611ca7611ca2612d72565b61289b565b611e20565b6005611cb6612d72565b908060018154018082558091505060019003905f5260205f20015f9091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055504260075f611d1f612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506001600360019054906101000a900467ffffffffffffffff16611db391906142b4565b60075f611dbe612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b5f5f90505b8267ffffffffffffffff1681101561202e57600260035f6101000a81548160ff021916908360ff1602179055508173ffffffffffffffffffffffffffffffffffffffff166342842e0e611e76612d72565b30888886818110611e8a57611e8961467c565b5b905060200201356040518463ffffffff1660e01b8152600401611eaf93929190614771565b5f604051808303815f87803b158015611ec6575f5ffd5b505af1158015611ed8573d5f5f3e3d5ffd5b50505050600160035f6101000a81548160ff021916908360ff160217905550611eff612d72565b60085f878785818110611f1557611f1461467c565b5b9050602002013581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060065f868684818110611f7c57611f7b61467c565b5b9050602002013581526020019081526020015f205f9054906101000a900460ff1661202357600160065f878785818110611fb957611fb861467c565b5b9050602002013581526020019081526020015f205f6101000a81548160ff0219169083151502179055506004858583818110611ff857611ff761467c565b5b90506020020135908060018154018082558091505060019003905f5260205f20015f90919091909150555b806001019050611e25565b508160075f61203b612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f8282829054906101000a900467ffffffffffffffff166120979190614a32565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555083836040516120cd929190614ad2565b60405180910390206120dd612d72565b73ffffffffffffffffffffffffffffffffffffffff167f540cd34f06460fd67aeca9d19e0a56cd3a7c1cde8dc2263f265b68b2ef3495d260405160405180910390a350505050565b5f61212e6113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7660405160405180910390a35050565b61222c6113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161229090614409565b60405180910390fd5b5f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1614612327577f0000000000000000000000000000000000000000000000000000000000000000612349565b7f00000000000000000000000000000000000000000000000000000000000000005b90505f8173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016123859190613ce1565b602060405180830381865afa1580156123a0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123c49190614afe565b90506124137f00000000000000000000000000000000000000000000000000000000000000003330867f0000000000000000000000000000000000000000000000000000000000000000612d79565b5f818373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161244e9190613ce1565b602060405180830381865afa158015612469573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061248d9190614afe565b6124979190614711565b905080600a5f8282546124aa919061493a565b9250508190555050505050565b5f6124c06113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b5f8203612535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161252c90614b73565b60405180910390fd5b5f600360019054906101000a900467ffffffffffffffff1667ffffffffffffffff1690506001600360018282829054906101000a900467ffffffffffffffff1661257f9190614a32565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060405180608001604052808481526020018381526020014281526020015f81525060095f8381526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301559050505f81111561262e574260095f6001846126199190614711565b81526020019081526020015f20600301819055505b505050565b5f61264461263f612d72565b612f73565b60075f61264f612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2060010154612696919061493a565b90505f81036126da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126d190614bdb565b60405180910390fd5b4260075f6126e6612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055505f60075f612763612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20600101819055506001600360019054906101000a900467ffffffffffffffff166127c691906142b4565b60075f6127d1612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555061284361283d612d72565b826131d3565b61284b612d72565b73ffffffffffffffffffffffffffffffffffffffff167ffc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe826040516128909190613a32565b60405180910390a250565b5f6128a582612f73565b90508060075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206001015f8282546128f6919061493a565b925050819055504260075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506001600360019054906101000a900467ffffffffffffffff1661299691906142b4565b60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505050565b5f612a086113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b5f5f8054612a489061499a565b80601f0160208091040260200160405190810160405280929190818152602001828054612a749061499a565b8015612abf5780601f10612a9657610100808354040283529160200191612abf565b820191905f5260205f20905b815481529060010190602001808311612aa257829003601f168201915b50505050509050815f9081612ad49190614d99565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a168183604051612b06929190614e68565b60405180910390a15050565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b4490614ee7565b60405180910390fd5b5f33905090565b6060612b79838360405180606001604052806027815260200161528960279139613281565b905092915050565b5f5f60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1603612c2d5760075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20600101549050612c84565b612c3682612f73565b60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2060010154612c81919061493a565b90505b919050565b612c916113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612cfe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cf590614409565b60405180910390fd5b600a548111612d1a5780600a54612d159190614711565b612d1c565b5f5b600a81905550612d6f7f00000000000000000000000000000000000000000000000000000000000000003033847f0000000000000000000000000000000000000000000000000000000000000000612d79565b50565b5f33905090565b5f820315612f6c5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612f5e573073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612e71578073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b8152600401612e349190613a32565b5f604051808303815f87803b158015612e4b575f5ffd5b505af1158015612e5d573d5f5f3e3d5ffd5b50505050612e6c838383613303565b612f59565b3073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612f4c57348214612eea5734826040517f03e085f9000000000000000000000000000000000000000000000000000000008152600401612ee192919061448f565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836040518263ffffffff1660e01b81526004015f604051808303818588803b158015612f30575f5ffd5b505af1158015612f42573d5f5f3e3d5ffd5b5050505050612f58565b612f57838383613303565b5b5b612f6b565b612f6a858585856133ff565b5b5b5050505050565b5f5f60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060800160405290815f82015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020015f820160089054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020015f820160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16815260200160018201548152505090505f816020015167ffffffffffffffff1690505f600360019054906101000a900467ffffffffffffffff1667ffffffffffffffff1690505f8290505b818110156131ca575f60095f8381526020019081526020015f206040518060800160405290815f8201548152602001600182015481526020016002820154815260200160038201548152505090505f8483036131205785604001516fffffffffffffffffffffffffffffffff16613126565b81604001515b90505f5f83606001510361313a5742613140565b82606001515b90505f5f613175895f015167ffffffffffffffff1685856131619190614711565b61316b9190614f05565b86602001516134cb565b915091505f5f6131938c885f01518561318e9190614f73565b613519565b915091508380156131a15750815b6131ab578b6131ad565b805b9b50505050505050506001816131c3919061493a565b90506130ae565b50505050919050565b600a54811115613218576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161320f90614fed565b60405180910390fd5b80600a5f8282546132299190614711565b9250508190555061327d7f00000000000000000000000000000000000000000000000000000000000000003084847f0000000000000000000000000000000000000000000000000000000000000000612d79565b5050565b60605f5f8573ffffffffffffffffffffffffffffffffffffffff16856040516132aa919061503b565b5f60405180830381855af49150503d805f81146132e2576040519150601f19603f3d011682016040523d82523d5f602084013e6132e7565b606091505b50915091506132f886838387613545565b925050509392505050565b5f8373ffffffffffffffffffffffffffffffffffffffff168360405161332890615074565b5f6040518083038185875af1925050503d805f8114613362576040519150601f19603f3d011682016040523d82523d5f602084013e613367565b606091505b50509050806133f9578173ffffffffffffffffffffffffffffffffffffffff1663d0e30db0846040518263ffffffff1660e01b81526004015f604051808303818588803b1580156133b6575f5ffd5b505af11580156133c8573d5f5f3e3d5ffd5b50505050506133f884848473ffffffffffffffffffffffffffffffffffffffff166135b99092919063ffffffff16565b5b50505050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603156134c5573073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036134965761349182828673ffffffffffffffffffffffffffffffffffffffff166135b99092919063ffffffff16565b6134c4565b6134c38383838773ffffffffffffffffffffffffffffffffffffffff1661363f909392919063ffffffff16565b5b5b50505050565b5f5f5f84036134e05760015f91509150613512565b5f8385029050838582816134f7576134f6614f46565b5b0414613509575f5f9250925050613512565b60018192509250505b9250929050565b5f5f5f838501905084811015613535575f5f925092505061353e565b60018192509250505b9250929050565b606083156135a6575f83510361359e5761355e856136c8565b61359d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613594906150d2565b60405180910390fd5b5b8290506135b1565b6135b083836136ea565b5b949350505050565b61363a8363a9059cbb60e01b84846040516024016135d89291906150f0565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613739565b505050565b6136c2846323b872dd60e01b85858560405160240161366093929190614771565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613739565b50505050565b5f5f8273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5f825111156136fc5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137309190614267565b60405180910390fd5b5f61379a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166137fe9092919063ffffffff16565b90505f815111156137f957808060200190518101906137b99190615141565b6137f8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137ef906151dc565b60405180910390fd5b5b505050565b606061380c84845f85613815565b90509392505050565b60608247101561385a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016138519061526a565b60405180910390fd5b5f5f8673ffffffffffffffffffffffffffffffffffffffff168587604051613882919061503b565b5f6040518083038185875af1925050503d805f81146138bc576040519150601f19603f3d011682016040523d82523d5f602084013e6138c1565b606091505b50915091506138d287838387613545565b92505050949350505050565b5f82825260208201905092915050565b7f63616c6c6572206e6f74206e617469766520746f6b656e20777261707065722e5f82015250565b5f6139226020836138de565b915061392d826138ee565b602082019050919050565b5f6020820190508181035f83015261394f81613916565b9050919050565b5f604051905090565b5f5ffd5b5f5ffd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61399b81613967565b81146139a5575f5ffd5b50565b5f813590506139b681613992565b92915050565b5f602082840312156139d1576139d061395f565b5b5f6139de848285016139a8565b91505092915050565b5f8115159050919050565b6139fb816139e7565b82525050565b5f602082019050613a145f8301846139f2565b92915050565b5f819050919050565b613a2c81613a1a565b82525050565b5f602082019050613a455f830184613a23565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112613a6c57613a6b613a4b565b5b8235905067ffffffffffffffff811115613a8957613a88613a4f565b5b602083019150836020820283011115613aa557613aa4613a53565b5b9250929050565b5f5f60208385031215613ac257613ac161395f565b5b5f83013567ffffffffffffffff811115613adf57613ade613963565b5b613aeb85828601613a57565b92509250509250929050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f613b2082613af7565b9050919050565b613b3081613b16565b8114613b3a575f5ffd5b50565b5f81359050613b4b81613b27565b92915050565b5f60208284031215613b6657613b6561395f565b5b5f613b7384828501613b3d565b91505092915050565b613b8581613a1a565b8114613b8f575f5ffd5b50565b5f81359050613ba081613b7c565b92915050565b5f5f83601f840112613bbb57613bba613a4b565b5b8235905067ffffffffffffffff811115613bd857613bd7613a4f565b5b602083019150836001820283011115613bf457613bf3613a53565b5b9250929050565b5f5f5f5f5f60808688031215613c1457613c1361395f565b5b5f613c2188828901613b3d565b9550506020613c3288828901613b3d565b9450506040613c4388828901613b92565b935050606086013567ffffffffffffffff811115613c6457613c63613963565b5b613c7088828901613ba6565b92509250509295509295909350565b613c8881613967565b82525050565b5f602082019050613ca15f830184613c7f565b92915050565b5f60208284031215613cbc57613cbb61395f565b5b5f613cc984828501613b92565b91505092915050565b613cdb81613b16565b82525050565b5f602082019050613cf45f830184613cd2565b92915050565b5f5f5f60408486031215613d1157613d1061395f565b5b5f84013567ffffffffffffffff811115613d2e57613d2d613963565b5b613d3a86828701613a57565b93509350506020613d4d86828701613b3d565b9150509250925092565b5f67ffffffffffffffff82169050919050565b613d7381613d57565b82525050565b5f6fffffffffffffffffffffffffffffffff82169050919050565b613d9d81613d79565b82525050565b5f608082019050613db65f830187613d6a565b613dc36020830186613d6a565b613dd06040830185613d94565b613ddd6060830184613a23565b95945050505050565b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b613e3082613dea565b810181811067ffffffffffffffff82111715613e4f57613e4e613dfa565b5b80604052505050565b5f613e61613956565b9050613e6d8282613e27565b919050565b5f67ffffffffffffffff821115613e8c57613e8b613dfa565b5b613e9582613dea565b9050602081019050919050565b828183375f83830152505050565b5f613ec2613ebd84613e72565b613e58565b905082815260208101848484011115613ede57613edd613de6565b5b613ee9848285613ea2565b509392505050565b5f82601f830112613f0557613f04613a4b565b5b8135613f15848260208601613eb0565b91505092915050565b5f60208284031215613f3357613f3261395f565b5b5f82013567ffffffffffffffff811115613f5057613f4f613963565b5b613f5c84828501613ef1565b91505092915050565b5f5f83601f840112613f7a57613f79613a4b565b5b8235905067ffffffffffffffff811115613f9757613f96613a4f565b5b602083019150836020820283011115613fb357613fb2613a53565b5b9250929050565b5f5f60208385031215613fd057613fcf61395f565b5b5f83013567ffffffffffffffff811115613fed57613fec613963565b5b613ff985828601613f65565b92509250509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f6140608261402e565b61406a8185614038565b935061407a818560208601614048565b61408381613dea565b840191505092915050565b5f6140998383614056565b905092915050565b5f602082019050919050565b5f6140b782614005565b6140c1818561400f565b9350836020820285016140d38561401f565b805f5b8581101561410e57848403895281516140ef858261408e565b94506140fa836140a1565b925060208a019950506001810190506140d6565b50829750879550505050505092915050565b5f6020820190508181035f83015261413881846140ad565b905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61417281613a1a565b82525050565b5f6141838383614169565b60208301905092915050565b5f602082019050919050565b5f6141a582614140565b6141af818561414a565b93506141ba8361415a565b805f5b838110156141ea5781516141d18882614178565b97506141dc8361418f565b9250506001810190506141bd565b5085935050505092915050565b5f6040820190508181035f83015261420f818561419b565b905061421e6020830184613a23565b9392505050565b5f81519050919050565b5f61423982614225565b61424381856138de565b9350614253818560208601614048565b61425c81613dea565b840191505092915050565b5f6020820190508181035f83015261427f818461422f565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6142be82613d57565b91506142c983613d57565b9250828203905067ffffffffffffffff8111156142e9576142e8614287565b5b92915050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c005f82015250565b5f614323601f836138de565b915061432e826142ef565b602082019050919050565b5f6020820190508181035f83015261435081614317565b9050919050565b7f446972656374207472616e7366657200000000000000000000000000000000005f82015250565b5f61438b600f836138de565b915061439682614357565b602082019050919050565b5f6020820190508181035f8301526143b88161437f565b9050919050565b7f4e6f7420617574686f72697a65640000000000000000000000000000000000005f82015250565b5f6143f3600e836138de565b91506143fe826143bf565b602082019050919050565b5f6020820190508181035f830152614420816143e7565b9050919050565b7f52657761726420756e6368616e6765642e0000000000000000000000000000005f82015250565b5f61445b6011836138de565b915061446682614427565b602082019050919050565b5f6020820190508181035f8301526144888161444f565b9050919050565b5f6040820190506144a25f830185613a23565b6144af6020830184613a23565b9392505050565b7f54696d652d756e697420756e6368616e6765642e0000000000000000000000005f82015250565b5f6144ea6014836138de565b91506144f5826144b6565b602082019050919050565b5f6020820190508181035f830152614517816144de565b9050919050565b7f4f6e6c79206f776e65722063616e20656d657267656e637920776974686472615f8201527f7700000000000000000000000000000000000000000000000000000000000000602082015250565b5f6145786021836138de565b91506145838261451e565b604082019050919050565b5f6020820190508181035f8301526145a58161456c565b9050919050565b7f43616e6e6f7420776974686472617720746f207a65726f2061646472657373005f82015250565b5f6145e0601f836138de565b91506145eb826145ac565b602082019050919050565b5f6020820190508181035f83015261460d816145d4565b9050919050565b7f426174636820746f6f206c6172676500000000000000000000000000000000005f82015250565b5f614648600f836138de565b915061465382614614565b602082019050919050565b5f6020820190508181035f8301526146758161463c565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f546f6b656e206e6f74207374616b6564000000000000000000000000000000005f82015250565b5f6146dd6010836138de565b91506146e8826146a9565b602082019050919050565b5f6020820190508181035f83015261470a816146d1565b9050919050565b5f61471b82613a1a565b915061472683613a1a565b925082820390508181111561473e5761473d614287565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f6060820190506147845f830186613cd2565b6147916020830185613cd2565b61479e6040830184613a23565b949350505050565b5f5ffd5b82818337505050565b5f6147be838561414a565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156147f1576147f06147a6565b5b6020830292506148028385846147aa565b82840190509392505050565b5f6020820190508181035f8301526148278184866147b3565b90509392505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f8335600160200384360303811261485857614857614830565b5b80840192508235915067ffffffffffffffff82111561487a57614879614834565b5b60208301925060018202360383131561489657614895614838565b5b509250929050565b5f81905092915050565b5f6148b3838561489e565b93506148c0838584613ea2565b82840190509392505050565b5f8160601b9050919050565b5f6148e2826148cc565b9050919050565b5f6148f3826148d8565b9050919050565b61490b61490682613b16565b6148e9565b82525050565b5f61491d8285876148a8565b915061492982846148fa565b601482019150819050949350505050565b5f61494482613a1a565b915061494f83613a1a565b925082820190508082111561496757614966614287565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806149b157607f821691505b6020821081036149c4576149c361496d565b5b50919050565b7f5374616b696e67203020746f6b656e73000000000000000000000000000000005f82015250565b5f6149fe6010836138de565b9150614a09826149ca565b602082019050919050565b5f6020820190508181035f830152614a2b816149f2565b9050919050565b5f614a3c82613d57565b9150614a4783613d57565b9250828201905067ffffffffffffffff811115614a6757614a66614287565b5b92915050565b5f81905092915050565b5f614a828385614a6d565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614ab557614ab46147a6565b5b602083029250614ac68385846147aa565b82840190509392505050565b5f614ade828486614a77565b91508190509392505050565b5f81519050614af881613b7c565b92915050565b5f60208284031215614b1357614b1261395f565b5b5f614b2084828501614aea565b91505092915050565b7f74696d652d756e69742063616e277420626520300000000000000000000000005f82015250565b5f614b5d6014836138de565b9150614b6882614b29565b602082019050919050565b5f6020820190508181035f830152614b8a81614b51565b9050919050565b7f4e6f2072657761726473000000000000000000000000000000000000000000005f82015250565b5f614bc5600a836138de565b9150614bd082614b91565b602082019050919050565b5f6020820190508181035f830152614bf281614bb9565b9050919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302614c557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614c1a565b614c5f8683614c1a565b95508019841693508086168417925050509392505050565b5f819050919050565b5f614c9a614c95614c9084613a1a565b614c77565b613a1a565b9050919050565b5f819050919050565b614cb383614c80565b614cc7614cbf82614ca1565b848454614c26565b825550505050565b5f5f905090565b614cde614ccf565b614ce9818484614caa565b505050565b5b81811015614d0c57614d015f82614cd6565b600181019050614cef565b5050565b601f821115614d5157614d2281614bf9565b614d2b84614c0b565b81016020851015614d3a578190505b614d4e614d4685614c0b565b830182614cee565b50505b505050565b5f82821c905092915050565b5f614d715f1984600802614d56565b1980831691505092915050565b5f614d898383614d62565b9150826002028217905092915050565b614da282614225565b67ffffffffffffffff811115614dbb57614dba613dfa565b5b614dc5825461499a565b614dd0828285614d10565b5f60209050601f831160018114614e01575f8415614def578287015190505b614df98582614d7e565b865550614e60565b601f198416614e0f86614bf9565b5f5b82811015614e3657848901518255600182019150602085019450602081019050614e11565b86831015614e535784890151614e4f601f891682614d62565b8355505b6001600288020188555050505b505050505050565b5f6040820190508181035f830152614e80818561422f565b90508181036020830152614e94818461422f565b90509392505050565b7f4e46547320617265207065726d616e656e746c79207374616b656400000000005f82015250565b5f614ed1601b836138de565b9150614edc82614e9d565b602082019050919050565b5f6020820190508181035f830152614efe81614ec5565b9050919050565b5f614f0f82613a1a565b9150614f1a83613a1a565b9250828202614f2881613a1a565b91508282048414831517614f3f57614f3e614287565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f614f7d82613a1a565b9150614f8883613a1a565b925082614f9857614f97614f46565b5b828204905092915050565b7f4e6f7420656e6f7567682072657761726420746f6b656e7300000000000000005f82015250565b5f614fd76018836138de565b9150614fe282614fa3565b602082019050919050565b5f6020820190508181035f83015261500481614fcb565b9050919050565b5f6150158261402e565b61501f818561489e565b935061502f818560208601614048565b80840191505092915050565b5f615046828461500b565b915081905092915050565b50565b5f61505f5f8361489e565b915061506a82615051565b5f82019050919050565b5f61507e82615054565b9150819050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000005f82015250565b5f6150bc601d836138de565b91506150c782615088565b602082019050919050565b5f6020820190508181035f8301526150e9816150b0565b9050919050565b5f6040820190506151035f830185613cd2565b6151106020830184613a23565b9392505050565b615120816139e7565b811461512a575f5ffd5b50565b5f8151905061513b81615117565b92915050565b5f602082840312156151565761515561395f565b5b5f6151638482850161512d565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e5f8201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b5f6151c6602a836138de565b91506151d18261516c565b604082019050919050565b5f6020820190508181035f8301526151f3816151ba565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f5f8201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b5f6152546026836138de565b915061525f826151fa565b604082019050919050565b5f6020820190508181035f83015261528181615248565b905091905056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212208d303b28d426b05eacbd0c12f762c5c0eb7ec880d79828074be3f892bfefaeb664736f6c634300081c0033000000000000000000000000fac9746e0b49d2d3982b43e754f0fe64b9883d270000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000aa87bee5380000000000000000000000000003a40312a1c376aecf855ef784371d1fb1aa2d25d000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Deployed Bytecode
0x6080604052600436106101ba575f3560e01c80639168ae72116100eb578063c345315311610089578063e8a3d48511610063578063e8a3d485146106a5578063f7c618c1146106cf578063f9ea29cb146106f9578063fd48ba17146107235761024f565b8063c345315314610616578063cb43b2dd14610653578063d68124c71461067b5761024f565b806394067045116100c5578063940670451461053a578063961004d314610576578063983d95ce146105b2578063ac9650d8146105da5761024f565b80639168ae72146104a9578063938e3d7b146104e857806393ce5343146105105761024f565b806323ef2580116101585780636360106f116101325780636360106f146104055780636c60d9e71461042d57806372f702f3146104555780638da5cb5b1461047f5761024f565b806323ef25801461038b578063372500ab146103b35780635357e916146103c95761024f565b80630fbf0a93116101945780630fbf0a93146102e357806313af40351461030b578063150b7a021461033357806316c621e01461036f5761024f565b806301ffc9a714610253578063080cd2791461028f5780630e8b229b146102b95761024f565b3661024f577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461024d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161024490613938565b60405180910390fd5b005b5f5ffd5b34801561025e575f5ffd5b50610279600480360381019061027491906139bc565b61075f565b6040516102869190613a01565b60405180910390f35b34801561029a575f5ffd5b506102a36107d8565b6040516102b09190613a32565b60405180910390f35b3480156102c4575f5ffd5b506102cd6107de565b6040516102da9190613a32565b60405180910390f35b3480156102ee575f5ffd5b5061030960048036038101906103049190613aac565b610825565b005b348015610316575f5ffd5b50610331600480360381019061032c9190613b51565b610886565b005b34801561033e575f5ffd5b5061035960048036038101906103549190613bfb565b6108d0565b6040516103669190613c8e565b60405180910390f35b61038960048036038101906103849190613ca7565b610938565b005b348015610396575f5ffd5b506103b160048036038101906103ac9190613ca7565b610997565b005b3480156103be575f5ffd5b506103c7610ae4565b005b3480156103d4575f5ffd5b506103ef60048036038101906103ea9190613ca7565b610b41565b6040516103fc9190613ce1565b60405180910390f35b348015610410575f5ffd5b5061042b60048036038101906104269190613ca7565b610b7c565b005b348015610438575f5ffd5b50610453600480360381019061044e9190613cfa565b610cc8565b005b348015610460575f5ffd5b506104696113bc565b6040516104769190613ce1565b60405180910390f35b34801561048a575f5ffd5b506104936113e0565b6040516104a09190613ce1565b60405180910390f35b3480156104b4575f5ffd5b506104cf60048036038101906104ca9190613b51565b611408565b6040516104df9493929190613da3565b60405180910390f35b3480156104f3575f5ffd5b5061050e60048036038101906105099190613f1e565b611475565b005b34801561051b575f5ffd5b506105246114bf565b6040516105319190613a32565b60405180910390f35b348015610545575f5ffd5b50610560600480360381019061055b9190613ca7565b6114c8565b60405161056d9190613ce1565b60405180910390f35b348015610581575f5ffd5b5061059c60048036038101906105979190613ca7565b6114f8565b6040516105a99190613a32565b60405180910390f35b3480156105bd575f5ffd5b506105d860048036038101906105d39190613aac565b611518565b005b3480156105e5575f5ffd5b5061060060048036038101906105fb9190613fba565b611579565b60405161060d9190614120565b60405180910390f35b348015610621575f5ffd5b5061063c60048036038101906106379190613b51565b61173a565b60405161064a9291906141f7565b60405180910390f35b34801561065e575f5ffd5b5061067960048036038101906106749190613ca7565b6119b7565b005b348015610686575f5ffd5b5061068f611a16565b60405161069c9190613a32565b60405180910390f35b3480156106b0575f5ffd5b506106b9611a5c565b6040516106c69190614267565b60405180910390f35b3480156106da575f5ffd5b506106e3611ae7565b6040516106f09190613ce1565b60405180910390f35b348015610704575f5ffd5b5061070d611b0b565b60405161071a9190613ce1565b60405180910390f35b34801561072e575f5ffd5b5061074960048036038101906107449190613ca7565b611b2f565b6040516107569190613a01565b60405180910390f35b5f7f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806107d157506107d082611b4c565b5b9050919050565b61012c81565b5f60095f6001600360019054906101000a900467ffffffffffffffff1661080591906142b4565b67ffffffffffffffff1681526020019081526020015f2060010154905090565b6002805403610869576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161086090614339565b60405180910390fd5b6002808190555061087a8282611bb5565b60016002819055505050565b61088e612125565b6108c4576040517f2d99739600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108cd81612161565b50565b5f600260035f9054906101000a900460ff1660ff1614610925576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091c906143a1565b60405180910390fd5b63150b7a0260e01b905095945050505050565b600280540361097c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097390614339565b60405180910390fd5b6002808190555061098c81612224565b600160028190555050565b61099f6124b7565b6109de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109d590614409565b60405180910390fd5b5f60095f6001600360019054906101000a900467ffffffffffffffff16610a0591906142b4565b67ffffffffffffffff1681526020019081526020015f206040518060800160405290815f82015481526020016001820154815260200160028201548152602001600382015481525050905080602001518203610a96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a8d90614471565b60405180910390fd5b610aa3815f0151836124f3565b7f243c4656edc72b2c7ec8575d464d955b2f42c1b205960c6c2fb7eecda5419cf6816020015183604051610ad892919061448f565b60405180910390a15050565b6002805403610b28576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1f90614339565b60405180910390fd5b60028081905550610b37612633565b6001600281905550565b60058181548110610b50575f80fd5b905f5260205f20015f915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610b846124b7565b610bc3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bba90614409565b60405180910390fd5b5f60095f6001600360019054906101000a900467ffffffffffffffff16610bea91906142b4565b67ffffffffffffffff1681526020019081526020015f206040518060800160405290815f820154815260200160018201548152602001600282015481526020016003820154815250509050805f01518203610c7a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c7190614500565b60405180910390fd5b610c888282602001516124f3565b7fd968de290ed68f978b9e4816f7d4be9ef46189fe8eeb3eeb86199e7229cf2de0815f015183604051610cbc92919061448f565b60405180910390a15050565b6002805403610d0c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0390614339565b60405180910390fd5b60028081905550610d1b6113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610d88576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7f9061458e565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610df6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ded906145f6565b60405180910390fd5b61012c838390501115610e3e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e359061465e565b60405180910390fd5b5f7f0000000000000000000000003a40312a1c376aecf855ef784371d1fb1aa2d25d90505f5f90505b84849050811015611346575f73ffffffffffffffffffffffffffffffffffffffff1660085f878785818110610e9f57610e9e61467c565b5b9050602002013581526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1603610f29576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f20906146f3565b60405180910390fd5b5f60085f878785818110610f4057610f3f61467c565b5b9050602002013581526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f60085f888886818110610f8d57610f8c61467c565b5b9050602002013581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1611156112b55761104b8161289b565b600160075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f8282829054906101000a900467ffffffffffffffff166110ad91906142b4565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff16036112b4575f5f90505b6005805490508110156112b2578173ffffffffffffffffffffffffffffffffffffffff16600582815481106111735761117261467c565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16036112a557600560016005805490506111ca9190614711565b815481106111db576111da61467c565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600582815481106112175761121661467c565b5b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600580548061126e5761126d614744565b5b600190038181905f5260205f20015f6101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905590556112b2565b808060010191505061113b565b505b5b8273ffffffffffffffffffffffffffffffffffffffff166342842e0e30868989878181106112e6576112e561467c565b5b905060200201356040518463ffffffff1660e01b815260040161130b93929190614771565b5f604051808303815f87803b158015611322575f5ffd5b505af1158015611334573d5f5f3e3d5ffd5b50505050508080600101915050610e67565b508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f49e7e98dba11447f42e55b1d3976705fad5dfb9df072d68da019756796baf3ef86866040516113a692919061480e565b60405180910390a3506001600281905550505050565b7f0000000000000000000000003a40312a1c376aecf855ef784371d1fb1aa2d25d81565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6007602052805f5260405f205f91509050805f015f9054906101000a900467ffffffffffffffff1690805f0160089054906101000a900467ffffffffffffffff1690805f0160109054906101000a90046fffffffffffffffffffffffffffffffff16908060010154905084565b61147d6129ff565b6114b3576040517f9f7f092500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114bc81612a3b565b50565b5f600a54905090565b6008602052805f5260405f205f915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60048181548110611507575f80fd5b905f5260205f20015f915090505481565b600280540361155c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161155390614339565b60405180910390fd5b6002808190555061156d8282612b12565b60016002819055505050565b60608282905067ffffffffffffffff81111561159857611597613dfa565b5b6040519080825280602002602001820160405280156115cb57816020015b60608152602001906001900390816115b65790505b5090505f6115d7612b4d565b90505f8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141590505f5f90505b8585905081101561173157811561169557611672308787848181106116395761163861467c565b5b905060200281019061164b919061483c565b8660405160200161165e93929190614911565b604051602081830303815290604052612b54565b8482815181106116855761168461467c565b5b6020026020010181905250611724565b611705308787848181106116ac576116ab61467c565b5b90506020028101906116be919061483c565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612b54565b8482815181106117185761171761467c565b5b60200260200101819052505b8080600101915050611611565b50505092915050565b60605f5f600480548060200260200160405190810160405280929190818152602001828054801561178857602002820191905f5260205f20905b815481526020019060010190808311611774575b505050505090505f815167ffffffffffffffff8111156117ab576117aa613dfa565b5b6040519080825280602002602001820160405280156117d95781602001602082028036833780820191505090505b5090505f825190505f5f90505f5f90505b828110156118cd578773ffffffffffffffffffffffffffffffffffffffff1660085f87848151811061181f5761181e61467c565b5b602002602001015181526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161484828151811061187e5761187d61467c565b5b6020026020010190151590811515815250508381815181106118a3576118a261467c565b5b6020026020010151156118c0576001826118bd919061493a565b91505b80806001019150506117ea565b508067ffffffffffffffff8111156118e8576118e7613dfa565b5b6040519080825280602002602001820160405280156119165781602001602082028036833780820191505090505b5095505f5f90505f5f90505b838110156119a15784818151811061193d5761193c61467c565b5b6020026020010151156119945785818151811061195d5761195c61467c565b5b60200260200101518883815181106119785761197761467c565b5b602002602001018181525050600182611991919061493a565b91505b8080600101915050611922565b506119ab88612b81565b95505050505050915091565b60028054036119fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119f290614339565b60405180910390fd5b60028081905550611a0b81612c89565b600160028190555050565b5f60095f6001600360019054906101000a900467ffffffffffffffff16611a3d91906142b4565b67ffffffffffffffff1681526020019081526020015f205f0154905090565b5f8054611a689061499a565b80601f0160208091040260200160405190810160405280929190818152602001828054611a949061499a565b8015611adf5780601f10611ab657610100808354040283529160200191611adf565b820191905f5260205f20905b815481529060010190602001808311611ac257829003601f168201915b505050505081565b7f000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f81565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6006602052805f5260405f205f915054906101000a900460ff1681565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f8282905090505f8167ffffffffffffffff1603611c08576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bff90614a14565b60405180910390fd5b5f7f0000000000000000000000003a40312a1c376aecf855ef784371d1fb1aa2d25d90505f60075f611c38612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff161115611cac57611ca7611ca2612d72565b61289b565b611e20565b6005611cb6612d72565b908060018154018082558091505060019003905f5260205f20015f9091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055504260075f611d1f612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506001600360019054906101000a900467ffffffffffffffff16611db391906142b4565b60075f611dbe612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b5f5f90505b8267ffffffffffffffff1681101561202e57600260035f6101000a81548160ff021916908360ff1602179055508173ffffffffffffffffffffffffffffffffffffffff166342842e0e611e76612d72565b30888886818110611e8a57611e8961467c565b5b905060200201356040518463ffffffff1660e01b8152600401611eaf93929190614771565b5f604051808303815f87803b158015611ec6575f5ffd5b505af1158015611ed8573d5f5f3e3d5ffd5b50505050600160035f6101000a81548160ff021916908360ff160217905550611eff612d72565b60085f878785818110611f1557611f1461467c565b5b9050602002013581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060065f868684818110611f7c57611f7b61467c565b5b9050602002013581526020019081526020015f205f9054906101000a900460ff1661202357600160065f878785818110611fb957611fb861467c565b5b9050602002013581526020019081526020015f205f6101000a81548160ff0219169083151502179055506004858583818110611ff857611ff761467c565b5b90506020020135908060018154018082558091505060019003905f5260205f20015f90919091909150555b806001019050611e25565b508160075f61203b612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f8282829054906101000a900467ffffffffffffffff166120979190614a32565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555083836040516120cd929190614ad2565b60405180910390206120dd612d72565b73ffffffffffffffffffffffffffffffffffffffff167f540cd34f06460fd67aeca9d19e0a56cd3a7c1cde8dc2263f265b68b2ef3495d260405160405180910390a350505050565b5f61212e6113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7660405160405180910390a35050565b61222c6113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161229090614409565b60405180910390fd5b5f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f73ffffffffffffffffffffffffffffffffffffffff1614612327577f000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f612349565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b90505f8173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016123859190613ce1565b602060405180830381865afa1580156123a0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123c49190614afe565b90506124137f000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f3330867f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2612d79565b5f818373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161244e9190613ce1565b602060405180830381865afa158015612469573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061248d9190614afe565b6124979190614711565b905080600a5f8282546124aa919061493a565b9250508190555050505050565b5f6124c06113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b5f8203612535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161252c90614b73565b60405180910390fd5b5f600360019054906101000a900467ffffffffffffffff1667ffffffffffffffff1690506001600360018282829054906101000a900467ffffffffffffffff1661257f9190614a32565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060405180608001604052808481526020018381526020014281526020015f81525060095f8381526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301559050505f81111561262e574260095f6001846126199190614711565b81526020019081526020015f20600301819055505b505050565b5f61264461263f612d72565b612f73565b60075f61264f612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2060010154612696919061493a565b90505f81036126da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126d190614bdb565b60405180910390fd5b4260075f6126e6612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055505f60075f612763612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20600101819055506001600360019054906101000a900467ffffffffffffffff166127c691906142b4565b60075f6127d1612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555061284361283d612d72565b826131d3565b61284b612d72565b73ffffffffffffffffffffffffffffffffffffffff167ffc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe826040516128909190613a32565b60405180910390a250565b5f6128a582612f73565b90508060075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206001015f8282546128f6919061493a565b925050819055504260075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506001600360019054906101000a900467ffffffffffffffff1661299691906142b4565b60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505050565b5f612a086113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b5f5f8054612a489061499a565b80601f0160208091040260200160405190810160405280929190818152602001828054612a749061499a565b8015612abf5780601f10612a9657610100808354040283529160200191612abf565b820191905f5260205f20905b815481529060010190602001808311612aa257829003601f168201915b50505050509050815f9081612ad49190614d99565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a168183604051612b06929190614e68565b60405180910390a15050565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b4490614ee7565b60405180910390fd5b5f33905090565b6060612b79838360405180606001604052806027815260200161528960279139613281565b905092915050565b5f5f60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1603612c2d5760075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20600101549050612c84565b612c3682612f73565b60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2060010154612c81919061493a565b90505b919050565b612c916113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612cfe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cf590614409565b60405180910390fd5b600a548111612d1a5780600a54612d159190614711565b612d1c565b5f5b600a81905550612d6f7f000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f3033847f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2612d79565b50565b5f33905090565b5f820315612f6c5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612f5e573073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612e71578073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b8152600401612e349190613a32565b5f604051808303815f87803b158015612e4b575f5ffd5b505af1158015612e5d573d5f5f3e3d5ffd5b50505050612e6c838383613303565b612f59565b3073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612f4c57348214612eea5734826040517f03e085f9000000000000000000000000000000000000000000000000000000008152600401612ee192919061448f565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836040518263ffffffff1660e01b81526004015f604051808303818588803b158015612f30575f5ffd5b505af1158015612f42573d5f5f3e3d5ffd5b5050505050612f58565b612f57838383613303565b5b5b612f6b565b612f6a858585856133ff565b5b5b5050505050565b5f5f60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060800160405290815f82015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020015f820160089054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020015f820160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16815260200160018201548152505090505f816020015167ffffffffffffffff1690505f600360019054906101000a900467ffffffffffffffff1667ffffffffffffffff1690505f8290505b818110156131ca575f60095f8381526020019081526020015f206040518060800160405290815f8201548152602001600182015481526020016002820154815260200160038201548152505090505f8483036131205785604001516fffffffffffffffffffffffffffffffff16613126565b81604001515b90505f5f83606001510361313a5742613140565b82606001515b90505f5f613175895f015167ffffffffffffffff1685856131619190614711565b61316b9190614f05565b86602001516134cb565b915091505f5f6131938c885f01518561318e9190614f73565b613519565b915091508380156131a15750815b6131ab578b6131ad565b805b9b50505050505050506001816131c3919061493a565b90506130ae565b50505050919050565b600a54811115613218576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161320f90614fed565b60405180910390fd5b80600a5f8282546132299190614711565b9250508190555061327d7f000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f3084847f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2612d79565b5050565b60605f5f8573ffffffffffffffffffffffffffffffffffffffff16856040516132aa919061503b565b5f60405180830381855af49150503d805f81146132e2576040519150601f19603f3d011682016040523d82523d5f602084013e6132e7565b606091505b50915091506132f886838387613545565b925050509392505050565b5f8373ffffffffffffffffffffffffffffffffffffffff168360405161332890615074565b5f6040518083038185875af1925050503d805f8114613362576040519150601f19603f3d011682016040523d82523d5f602084013e613367565b606091505b50509050806133f9578173ffffffffffffffffffffffffffffffffffffffff1663d0e30db0846040518263ffffffff1660e01b81526004015f604051808303818588803b1580156133b6575f5ffd5b505af11580156133c8573d5f5f3e3d5ffd5b50505050506133f884848473ffffffffffffffffffffffffffffffffffffffff166135b99092919063ffffffff16565b5b50505050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603156134c5573073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036134965761349182828673ffffffffffffffffffffffffffffffffffffffff166135b99092919063ffffffff16565b6134c4565b6134c38383838773ffffffffffffffffffffffffffffffffffffffff1661363f909392919063ffffffff16565b5b5b50505050565b5f5f5f84036134e05760015f91509150613512565b5f8385029050838582816134f7576134f6614f46565b5b0414613509575f5f9250925050613512565b60018192509250505b9250929050565b5f5f5f838501905084811015613535575f5f925092505061353e565b60018192509250505b9250929050565b606083156135a6575f83510361359e5761355e856136c8565b61359d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613594906150d2565b60405180910390fd5b5b8290506135b1565b6135b083836136ea565b5b949350505050565b61363a8363a9059cbb60e01b84846040516024016135d89291906150f0565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613739565b505050565b6136c2846323b872dd60e01b85858560405160240161366093929190614771565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613739565b50505050565b5f5f8273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5f825111156136fc5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137309190614267565b60405180910390fd5b5f61379a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166137fe9092919063ffffffff16565b90505f815111156137f957808060200190518101906137b99190615141565b6137f8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137ef906151dc565b60405180910390fd5b5b505050565b606061380c84845f85613815565b90509392505050565b60608247101561385a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016138519061526a565b60405180910390fd5b5f5f8673ffffffffffffffffffffffffffffffffffffffff168587604051613882919061503b565b5f6040518083038185875af1925050503d805f81146138bc576040519150601f19603f3d011682016040523d82523d5f602084013e6138c1565b606091505b50915091506138d287838387613545565b92505050949350505050565b5f82825260208201905092915050565b7f63616c6c6572206e6f74206e617469766520746f6b656e20777261707065722e5f82015250565b5f6139226020836138de565b915061392d826138ee565b602082019050919050565b5f6020820190508181035f83015261394f81613916565b9050919050565b5f604051905090565b5f5ffd5b5f5ffd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61399b81613967565b81146139a5575f5ffd5b50565b5f813590506139b681613992565b92915050565b5f602082840312156139d1576139d061395f565b5b5f6139de848285016139a8565b91505092915050565b5f8115159050919050565b6139fb816139e7565b82525050565b5f602082019050613a145f8301846139f2565b92915050565b5f819050919050565b613a2c81613a1a565b82525050565b5f602082019050613a455f830184613a23565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112613a6c57613a6b613a4b565b5b8235905067ffffffffffffffff811115613a8957613a88613a4f565b5b602083019150836020820283011115613aa557613aa4613a53565b5b9250929050565b5f5f60208385031215613ac257613ac161395f565b5b5f83013567ffffffffffffffff811115613adf57613ade613963565b5b613aeb85828601613a57565b92509250509250929050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f613b2082613af7565b9050919050565b613b3081613b16565b8114613b3a575f5ffd5b50565b5f81359050613b4b81613b27565b92915050565b5f60208284031215613b6657613b6561395f565b5b5f613b7384828501613b3d565b91505092915050565b613b8581613a1a565b8114613b8f575f5ffd5b50565b5f81359050613ba081613b7c565b92915050565b5f5f83601f840112613bbb57613bba613a4b565b5b8235905067ffffffffffffffff811115613bd857613bd7613a4f565b5b602083019150836001820283011115613bf457613bf3613a53565b5b9250929050565b5f5f5f5f5f60808688031215613c1457613c1361395f565b5b5f613c2188828901613b3d565b9550506020613c3288828901613b3d565b9450506040613c4388828901613b92565b935050606086013567ffffffffffffffff811115613c6457613c63613963565b5b613c7088828901613ba6565b92509250509295509295909350565b613c8881613967565b82525050565b5f602082019050613ca15f830184613c7f565b92915050565b5f60208284031215613cbc57613cbb61395f565b5b5f613cc984828501613b92565b91505092915050565b613cdb81613b16565b82525050565b5f602082019050613cf45f830184613cd2565b92915050565b5f5f5f60408486031215613d1157613d1061395f565b5b5f84013567ffffffffffffffff811115613d2e57613d2d613963565b5b613d3a86828701613a57565b93509350506020613d4d86828701613b3d565b9150509250925092565b5f67ffffffffffffffff82169050919050565b613d7381613d57565b82525050565b5f6fffffffffffffffffffffffffffffffff82169050919050565b613d9d81613d79565b82525050565b5f608082019050613db65f830187613d6a565b613dc36020830186613d6a565b613dd06040830185613d94565b613ddd6060830184613a23565b95945050505050565b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b613e3082613dea565b810181811067ffffffffffffffff82111715613e4f57613e4e613dfa565b5b80604052505050565b5f613e61613956565b9050613e6d8282613e27565b919050565b5f67ffffffffffffffff821115613e8c57613e8b613dfa565b5b613e9582613dea565b9050602081019050919050565b828183375f83830152505050565b5f613ec2613ebd84613e72565b613e58565b905082815260208101848484011115613ede57613edd613de6565b5b613ee9848285613ea2565b509392505050565b5f82601f830112613f0557613f04613a4b565b5b8135613f15848260208601613eb0565b91505092915050565b5f60208284031215613f3357613f3261395f565b5b5f82013567ffffffffffffffff811115613f5057613f4f613963565b5b613f5c84828501613ef1565b91505092915050565b5f5f83601f840112613f7a57613f79613a4b565b5b8235905067ffffffffffffffff811115613f9757613f96613a4f565b5b602083019150836020820283011115613fb357613fb2613a53565b5b9250929050565b5f5f60208385031215613fd057613fcf61395f565b5b5f83013567ffffffffffffffff811115613fed57613fec613963565b5b613ff985828601613f65565b92509250509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f6140608261402e565b61406a8185614038565b935061407a818560208601614048565b61408381613dea565b840191505092915050565b5f6140998383614056565b905092915050565b5f602082019050919050565b5f6140b782614005565b6140c1818561400f565b9350836020820285016140d38561401f565b805f5b8581101561410e57848403895281516140ef858261408e565b94506140fa836140a1565b925060208a019950506001810190506140d6565b50829750879550505050505092915050565b5f6020820190508181035f83015261413881846140ad565b905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61417281613a1a565b82525050565b5f6141838383614169565b60208301905092915050565b5f602082019050919050565b5f6141a582614140565b6141af818561414a565b93506141ba8361415a565b805f5b838110156141ea5781516141d18882614178565b97506141dc8361418f565b9250506001810190506141bd565b5085935050505092915050565b5f6040820190508181035f83015261420f818561419b565b905061421e6020830184613a23565b9392505050565b5f81519050919050565b5f61423982614225565b61424381856138de565b9350614253818560208601614048565b61425c81613dea565b840191505092915050565b5f6020820190508181035f83015261427f818461422f565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6142be82613d57565b91506142c983613d57565b9250828203905067ffffffffffffffff8111156142e9576142e8614287565b5b92915050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c005f82015250565b5f614323601f836138de565b915061432e826142ef565b602082019050919050565b5f6020820190508181035f83015261435081614317565b9050919050565b7f446972656374207472616e7366657200000000000000000000000000000000005f82015250565b5f61438b600f836138de565b915061439682614357565b602082019050919050565b5f6020820190508181035f8301526143b88161437f565b9050919050565b7f4e6f7420617574686f72697a65640000000000000000000000000000000000005f82015250565b5f6143f3600e836138de565b91506143fe826143bf565b602082019050919050565b5f6020820190508181035f830152614420816143e7565b9050919050565b7f52657761726420756e6368616e6765642e0000000000000000000000000000005f82015250565b5f61445b6011836138de565b915061446682614427565b602082019050919050565b5f6020820190508181035f8301526144888161444f565b9050919050565b5f6040820190506144a25f830185613a23565b6144af6020830184613a23565b9392505050565b7f54696d652d756e697420756e6368616e6765642e0000000000000000000000005f82015250565b5f6144ea6014836138de565b91506144f5826144b6565b602082019050919050565b5f6020820190508181035f830152614517816144de565b9050919050565b7f4f6e6c79206f776e65722063616e20656d657267656e637920776974686472615f8201527f7700000000000000000000000000000000000000000000000000000000000000602082015250565b5f6145786021836138de565b91506145838261451e565b604082019050919050565b5f6020820190508181035f8301526145a58161456c565b9050919050565b7f43616e6e6f7420776974686472617720746f207a65726f2061646472657373005f82015250565b5f6145e0601f836138de565b91506145eb826145ac565b602082019050919050565b5f6020820190508181035f83015261460d816145d4565b9050919050565b7f426174636820746f6f206c6172676500000000000000000000000000000000005f82015250565b5f614648600f836138de565b915061465382614614565b602082019050919050565b5f6020820190508181035f8301526146758161463c565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f546f6b656e206e6f74207374616b6564000000000000000000000000000000005f82015250565b5f6146dd6010836138de565b91506146e8826146a9565b602082019050919050565b5f6020820190508181035f83015261470a816146d1565b9050919050565b5f61471b82613a1a565b915061472683613a1a565b925082820390508181111561473e5761473d614287565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f6060820190506147845f830186613cd2565b6147916020830185613cd2565b61479e6040830184613a23565b949350505050565b5f5ffd5b82818337505050565b5f6147be838561414a565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156147f1576147f06147a6565b5b6020830292506148028385846147aa565b82840190509392505050565b5f6020820190508181035f8301526148278184866147b3565b90509392505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f8335600160200384360303811261485857614857614830565b5b80840192508235915067ffffffffffffffff82111561487a57614879614834565b5b60208301925060018202360383131561489657614895614838565b5b509250929050565b5f81905092915050565b5f6148b3838561489e565b93506148c0838584613ea2565b82840190509392505050565b5f8160601b9050919050565b5f6148e2826148cc565b9050919050565b5f6148f3826148d8565b9050919050565b61490b61490682613b16565b6148e9565b82525050565b5f61491d8285876148a8565b915061492982846148fa565b601482019150819050949350505050565b5f61494482613a1a565b915061494f83613a1a565b925082820190508082111561496757614966614287565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806149b157607f821691505b6020821081036149c4576149c361496d565b5b50919050565b7f5374616b696e67203020746f6b656e73000000000000000000000000000000005f82015250565b5f6149fe6010836138de565b9150614a09826149ca565b602082019050919050565b5f6020820190508181035f830152614a2b816149f2565b9050919050565b5f614a3c82613d57565b9150614a4783613d57565b9250828201905067ffffffffffffffff811115614a6757614a66614287565b5b92915050565b5f81905092915050565b5f614a828385614a6d565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614ab557614ab46147a6565b5b602083029250614ac68385846147aa565b82840190509392505050565b5f614ade828486614a77565b91508190509392505050565b5f81519050614af881613b7c565b92915050565b5f60208284031215614b1357614b1261395f565b5b5f614b2084828501614aea565b91505092915050565b7f74696d652d756e69742063616e277420626520300000000000000000000000005f82015250565b5f614b5d6014836138de565b9150614b6882614b29565b602082019050919050565b5f6020820190508181035f830152614b8a81614b51565b9050919050565b7f4e6f2072657761726473000000000000000000000000000000000000000000005f82015250565b5f614bc5600a836138de565b9150614bd082614b91565b602082019050919050565b5f6020820190508181035f830152614bf281614bb9565b9050919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302614c557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614c1a565b614c5f8683614c1a565b95508019841693508086168417925050509392505050565b5f819050919050565b5f614c9a614c95614c9084613a1a565b614c77565b613a1a565b9050919050565b5f819050919050565b614cb383614c80565b614cc7614cbf82614ca1565b848454614c26565b825550505050565b5f5f905090565b614cde614ccf565b614ce9818484614caa565b505050565b5b81811015614d0c57614d015f82614cd6565b600181019050614cef565b5050565b601f821115614d5157614d2281614bf9565b614d2b84614c0b565b81016020851015614d3a578190505b614d4e614d4685614c0b565b830182614cee565b50505b505050565b5f82821c905092915050565b5f614d715f1984600802614d56565b1980831691505092915050565b5f614d898383614d62565b9150826002028217905092915050565b614da282614225565b67ffffffffffffffff811115614dbb57614dba613dfa565b5b614dc5825461499a565b614dd0828285614d10565b5f60209050601f831160018114614e01575f8415614def578287015190505b614df98582614d7e565b865550614e60565b601f198416614e0f86614bf9565b5f5b82811015614e3657848901518255600182019150602085019450602081019050614e11565b86831015614e535784890151614e4f601f891682614d62565b8355505b6001600288020188555050505b505050505050565b5f6040820190508181035f830152614e80818561422f565b90508181036020830152614e94818461422f565b90509392505050565b7f4e46547320617265207065726d616e656e746c79207374616b656400000000005f82015250565b5f614ed1601b836138de565b9150614edc82614e9d565b602082019050919050565b5f6020820190508181035f830152614efe81614ec5565b9050919050565b5f614f0f82613a1a565b9150614f1a83613a1a565b9250828202614f2881613a1a565b91508282048414831517614f3f57614f3e614287565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f614f7d82613a1a565b9150614f8883613a1a565b925082614f9857614f97614f46565b5b828204905092915050565b7f4e6f7420656e6f7567682072657761726420746f6b656e7300000000000000005f82015250565b5f614fd76018836138de565b9150614fe282614fa3565b602082019050919050565b5f6020820190508181035f83015261500481614fcb565b9050919050565b5f6150158261402e565b61501f818561489e565b935061502f818560208601614048565b80840191505092915050565b5f615046828461500b565b915081905092915050565b50565b5f61505f5f8361489e565b915061506a82615051565b5f82019050919050565b5f61507e82615054565b9150819050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000005f82015250565b5f6150bc601d836138de565b91506150c782615088565b602082019050919050565b5f6020820190508181035f8301526150e9816150b0565b9050919050565b5f6040820190506151035f830185613cd2565b6151106020830184613a23565b9392505050565b615120816139e7565b811461512a575f5ffd5b50565b5f8151905061513b81615117565b92915050565b5f602082840312156151565761515561395f565b5b5f6151638482850161512d565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e5f8201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b5f6151c6602a836138de565b91506151d18261516c565b604082019050919050565b5f6020820190508181035f8301526151f3816151ba565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f5f8201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b5f6152546026836138de565b915061525f826151fa565b604082019050919050565b5f6020820190508181035f83015261528181615248565b905091905056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212208d303b28d426b05eacbd0c12f762c5c0eb7ec880d79828074be3f892bfefaeb664736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000fac9746e0b49d2d3982b43e754f0fe64b9883d270000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000aa87bee5380000000000000000000000000003a40312a1c376aecf855ef784371d1fb1aa2d25d000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
-----Decoded View---------------
Arg [0] : _defaultAdmin (address): 0xfAc9746E0b49d2D3982B43E754F0fE64b9883d27
Arg [1] : _timeUnit (uint256): 1
Arg [2] : _rewardsPerUnitTime (uint256): 3000000000000000
Arg [3] : _stakingToken (address): 0x3A40312A1C376aEcF855eF784371d1fb1AA2d25D
Arg [4] : _rewardToken (address): 0xa0C69824C820F36CA32666462405eA85F414409f
Arg [5] : _nativeTokenWrapper (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000fac9746e0b49d2d3982b43e754f0fe64b9883d27
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [2] : 000000000000000000000000000000000000000000000000000aa87bee538000
Arg [3] : 0000000000000000000000003a40312a1c376aecf855ef784371d1fb1aa2d25d
Arg [4] : 000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f
Arg [5] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Loading...
Loading
Loading...
Loading
OVERVIEW
Locking NFTs to earn points on Cashmere campaigns.Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.