Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 14745640 | 809 days ago | IN | 0 ETH | 0.3431332 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
TenderToken
Compiler Version
v0.8.4+commit.c7e474f2
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-FileCopyrightText: 2021 Tenderize <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "../libs/MathUtils.sol"; import "../tenderizer/ITotalStakedReader.sol"; import "./ITenderToken.sol"; // solhint-disable-next-line max-line-length import { ERC20Upgradeable, ERC20PermitUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol"; /** * @title Interest-bearing ERC20-like token for Tenderize protocol. * @author Tenderize <[email protected]> * @dev TenderToken balances are dynamic and are calculated based on the accounts' shares * and the total amount of Tokens controlled by the protocol. Account shares aren't * normalized, so the contract also stores the sum of all shares to calculate * each account's token balance which equals to: * * shares[account] * _getTotalPooledTokens() / _getTotalShares() */ contract TenderToken is OwnableUpgradeable, ERC20PermitUpgradeable, ITenderToken { uint8 internal constant DECIMALS = 18; /** * @dev Total amount of outstanding shares */ uint256 private totalShares; /** * @dev Nominal amount of shares held by each account */ mapping(address => uint256) private shares; /** * @dev Allowances nominated in tokens, not token shares. */ mapping(address => mapping(address => uint256)) private allowances; /** * @dev Tenderizer address, to read total staked tokens */ ITotalStakedReader public totalStakedReader; /// @inheritdoc ITenderToken function initialize( string memory _name, string memory _symbol, ITotalStakedReader _totalStakedReader ) external override initializer returns (bool) { __Context_init_unchained(); __Ownable_init_unchained(); __ERC20_init_unchained(string(abi.encodePacked("tender ", _name)), string(abi.encodePacked("t", _symbol))); __EIP712_init_unchained(string(abi.encodePacked("tender ", _name)), "1"); __ERC20Permit_init_unchained(string(abi.encodePacked("tender ", _name))); totalStakedReader = _totalStakedReader; return true; } /// @inheritdoc ITenderToken function decimals() public pure override(ITenderToken, ERC20Upgradeable) returns (uint8) { return DECIMALS; } /// @inheritdoc ITenderToken function totalSupply() public view override(ITenderToken, ERC20Upgradeable) returns (uint256) { return _getTotalPooledTokens(); } /// @inheritdoc ITenderToken function getTotalPooledTokens() external view override returns (uint256) { return _getTotalPooledTokens(); } /// @inheritdoc ITenderToken function getTotalShares() external view override returns (uint256) { return _getTotalShares(); } /// @inheritdoc ITenderToken function balanceOf(address _account) public view override(ITenderToken, ERC20Upgradeable) returns (uint256) { return _sharesToTokens(_sharesOf(_account)); } /// @inheritdoc ITenderToken function sharesOf(address _account) external view override returns (uint256) { return _sharesOf(_account); } /// @inheritdoc ITenderToken function allowance(address _owner, address _spender) public view override(ITenderToken, ERC20Upgradeable) returns (uint256) { return allowances[_owner][_spender]; } /// @inheritdoc ITenderToken function tokensToShares(uint256 _tokens) external view override returns (uint256) { return _tokensToShares(_tokens); } /// @inheritdoc ITenderToken function sharesToTokens(uint256 _shares) external view override returns (uint256) { return _sharesToTokens(_shares); } /// @inheritdoc ITenderToken function transfer(address _recipient, uint256 _amount) public override(ITenderToken, ERC20Upgradeable) returns (bool) { _transfer(msg.sender, _recipient, _amount); return true; } /// @inheritdoc ITenderToken function approve(address _spender, uint256 _amount) public override(ITenderToken, ERC20Upgradeable) returns (bool) { _approve(msg.sender, _spender, _amount); return true; } /// @inheritdoc ITenderToken function transferFrom( address _sender, address _recipient, uint256 _amount ) public override(ITenderToken, ERC20Upgradeable) returns (bool) { uint256 currentAllowance = allowances[_sender][msg.sender]; require(currentAllowance >= _amount, "TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE"); _transfer(_sender, _recipient, _amount); _approve(_sender, msg.sender, currentAllowance - _amount); return true; } /// @inheritdoc ITenderToken function increaseAllowance(address _spender, uint256 _addedValue) public override(ITenderToken, ERC20Upgradeable) returns (bool) { _approve(msg.sender, _spender, allowances[msg.sender][_spender] + _addedValue); return true; } /// @inheritdoc ITenderToken function decreaseAllowance(address _spender, uint256 _subtractedValue) public override(ITenderToken, ERC20Upgradeable) returns (bool) { uint256 currentAllowance = allowances[msg.sender][_spender]; require(currentAllowance >= _subtractedValue, "DECREASED_ALLOWANCE_BELOW_ZERO"); _approve(msg.sender, _spender, currentAllowance - _subtractedValue); return true; } /// @inheritdoc ITenderToken function mint(address _recipient, uint256 _amount) external override onlyOwner returns (bool) { _mintShares(_recipient, _tokensToShares(_amount)); return true; } /// @inheritdoc ITenderToken function burn(address _account, uint256 _amount) external override onlyOwner returns (bool) { uint256 _sharesToburn = _tokensToShares(_amount); _burnShares(_account, _sharesToburn); return true; } /// @inheritdoc ITenderToken function setTotalStakedReader(ITotalStakedReader _totalStakedReader) external override onlyOwner { require(address(_totalStakedReader) != address(0)); totalStakedReader = _totalStakedReader; } // INTERNAL FUNCTIONS /** * @return the total amount (in 10e18) of Tokens controlled by the protocol. * @dev This is used for calculating tokens from shares and vice versa. * @dev This function is required to be implemented in a derived contract. */ function _getTotalPooledTokens() internal view returns (uint256) { return totalStakedReader.totalStakedTokens(); } /** * @dev Moves `_amount` tokens from `_sender` to `_recipient`. * @dev Emits a `Transfer` event. */ function _transfer( address _sender, address _recipient, uint256 _amount ) internal override { uint256 _sharesToTransfer = _tokensToShares(_amount); _transferShares(_sender, _recipient, _sharesToTransfer); emit Transfer(_sender, _recipient, _amount); } /** * @dev Sets `_amount` as the allowance of `_spender` over the `_owner` s tokens. * @dev Emits an `Approval` event. */ function _approve( address _owner, address _spender, uint256 _amount ) internal override { require(_owner != address(0), "APPROVE_FROM_ZERO_ADDRESS"); require(_spender != address(0), "APPROVE_TO_ZERO_ADDRESS"); allowances[_owner][_spender] = _amount; emit Approval(_owner, _spender, _amount); } /** * @dev the total amount of shares in existence. */ function _getTotalShares() internal view returns (uint256) { return totalShares; } /** * @dev the amount of shares owned by `_account`. */ function _sharesOf(address _account) internal view returns (uint256) { return shares[_account]; } /** * @dev Moves `_shares` shares from `_sender` to `_recipient`. * @dev Requirements: * - `_sender` cannot be the zero address. * - `_recipient` cannot be the zero address. * - `_sender` must hold at least `_shares` shares. */ function _transferShares( address _sender, address _recipient, uint256 _shares ) internal { require(_sender != address(0), "TRANSFER_FROM_THE_ZERO_ADDRESS"); require(_recipient != address(0), "TRANSFER_TO_THE_ZERO_ADDRESS"); uint256 currentSenderShares = shares[_sender]; require(_shares <= currentSenderShares, "TRANSFER_AMOUNT_EXCEEDS_BALANCE"); shares[_sender] = currentSenderShares - _shares; shares[_recipient] += _shares; } /** * @dev Creates `_shares` shares and assigns them to `_recipient`, increasing the total amount of shares. * @dev This doesn't increase the token total supply. * @dev Requirements: * - `_recipient` cannot be the zero address. */ function _mintShares(address _recipient, uint256 _shares) internal { require(_recipient != address(0), "MINT_TO_THE_ZERO_ADDRESS"); shares[_recipient] += _shares; // Notice: we're not emitting a Transfer event from the zero address here since shares mint // works by taking the amount of tokens corresponding to the minted shares from all other // token holders, proportionally to their share. The total supply of the token doesn't change // as the result. This is equivalent to performing a send from each other token holder's // address to `address`, but we cannot reflect this as it would require sending an unbounded // number of events. totalShares += _shares; } /** * @dev Destroys `_shares` shares from `_account`'s holdings, decreasing the total amount of shares. * @dev This doesn't decrease the token total supply. * @dev Requirements: * - `_account` cannot be the zero address. * - `_account` must hold at least `_shares` shares. */ function _burnShares(address _account, uint256 _shares) internal returns (uint256 newTotalShares) { require(_account != address(0), "BURN_FROM_THE_ZERO_ADDRESS"); uint256 accountShares = shares[_account]; require(_shares <= accountShares, "BURN_AMOUNT_EXCEEDS_BALANCE"); newTotalShares = totalShares - _shares; shares[_account] = accountShares - _shares; // Notice: we're not emitting a Transfer event to the zero address here since shares burn // works by redistributing the amount of tokens corresponding to the burned shares between // all other token holders. The total supply of the token doesn't change as the result. // This is equivalent to performing a send from `address` to each other token holder address, // but we cannot reflect this as it would require sending an unbounded number of events. totalShares = newTotalShares; } function _tokensToShares(uint256 _tokens) internal view returns (uint256) { uint256 _totalPooledTokens = _getTotalPooledTokens(); uint256 _totalShares = _getTotalShares(); if (_totalShares == 0) { return _tokens; } else if (_totalPooledTokens == 0) { return 0; } else { return MathUtils.percOf(_tokens, _totalShares, _totalPooledTokens); } } function _sharesToTokens(uint256 _shares) internal view returns (uint256) { uint256 _totalShares = _getTotalShares(); if (_totalShares == 0) { return 0; } else { return MathUtils.percOf(_shares, _getTotalPooledTokens(), _totalShares); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal initializer { __Context_init_unchained(); __Ownable_init_unchained(); } function __Ownable_init_unchained() internal initializer { _setOwner(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _setOwner(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _setOwner(newOwner); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } uint256[49] private __gap; }
// SPDX-FileCopyrightText: 2021 Tenderize <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.4; library MathUtils { // Divisor used for representing percentages uint256 public constant PERC_DIVISOR = 10**21; /** * @dev Returns whether an amount is a valid percentage out of PERC_DIVISOR * @param _amount Amount that is supposed to be a percentage */ function validPerc(uint256 _amount) internal pure returns (bool) { return _amount <= PERC_DIVISOR; } /** * @dev Compute percentage of a value with the percentage represented by a fraction * @param _amount Amount to take the percentage of * @param _fracNum Numerator of fraction representing the percentage * @param _fracDenom Denominator of fraction representing the percentage */ function percOf( uint256 _amount, uint256 _fracNum, uint256 _fracDenom ) internal pure returns (uint256) { return (_amount * percPoints(_fracNum, _fracDenom)) / PERC_DIVISOR; } /** * @dev Compute percentage of a value with the percentage represented by a fraction over PERC_DIVISOR * @param _amount Amount to take the percentage of * @param _fracNum Numerator of fraction representing the percentage with PERC_DIVISOR as the denominator */ function percOf(uint256 _amount, uint256 _fracNum) internal pure returns (uint256) { return (_amount * _fracNum) / PERC_DIVISOR; } /** * @dev Compute percentage representation of a fraction * @param _fracNum Numerator of fraction represeting the percentage * @param _fracDenom Denominator of fraction represeting the percentage */ function percPoints(uint256 _fracNum, uint256 _fracDenom) internal pure returns (uint256) { return (_fracNum * PERC_DIVISOR) / _fracDenom; } /** * @notice Compares a and b and returns true if the difference between a and b * is less than 1 or equal to each other. * @param a uint256 to compare with * @param b uint256 to compare with * @return True if the difference between a and b is less than 1 or equal, * otherwise return false */ function within1(uint256 a, uint256 b) internal pure returns (bool) { return (difference(a, b) <= 1); } /** * @notice Calculates absolute difference between a and b * @param a uint256 to compare with * @param b uint256 to compare with * @return Difference between a and b */ function difference(uint256 a, uint256 b) internal pure returns (uint256) { if (a > b) { return a - b; } return b - a; } }
// SPDX-FileCopyrightText: 2021 Tenderize <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.4; interface ITotalStakedReader { /** * @notice Total Staked Tokens returns the total amount of underlying tokens staked by this Tenderizer. * @return _totalStakedTokens total amount staked by this Tenderizer */ function totalStakedTokens() external view returns (uint256 _totalStakedTokens); }
// SPDX-FileCopyrightText: 2021 Tenderize <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "../tenderizer/ITotalStakedReader.sol"; /** * @title Interest-bearing ERC20-like token for Tenderize protocol. * @author Tenderize <[email protected]> * @dev TenderToken balances are dynamic and are calculated based on the accounts' shares * and the total amount of Tokens controlled by the protocol. Account shares aren't * normalized, so the contract also stores the sum of all shares to calculate * each account's token balance which equals to: * * shares[account] * _getTotalPooledTokens() / _getTotalShares() */ interface ITenderToken { /** * @notice Initilize the TenderToken Contract * @param _name name of the token (steak) * @param _symbol symbol of the token (steak) * @param _stakedReader contract address implementing the ITotalStakedReader interface * @return a boolean value indicating whether the init succeeded. */ function initialize( string memory _name, string memory _symbol, ITotalStakedReader _stakedReader ) external returns (bool); /** * @notice The number of decimals the TenderToken uses. * @return decimals the number of decimals for getting user representation of a token amount. */ function decimals() external pure returns (uint8); /** * @notice The total supply of tender tokens in existence. * @dev Always equals to `_getTotalPooledTokens()` since token amount * is pegged to the total amount of Tokens controlled by the protocol. * @return totalSupply total supply */ function totalSupply() external view returns (uint256); /** * @notice Total amount of underlying tokens controlled by the Tenderizer. * @dev The sum of all Tokens balances in the protocol, equals to the total supply of TenderToken. * @return totalPooledTokens total amount of pooled tokens */ function getTotalPooledTokens() external view returns (uint256); /** * @notice The total amount of shares in existence. * @dev The sum of all accounts' shares can be an arbitrary number, therefore * it is necessary to store it in order to calculate each account's relative share. * @return totalShares total amount of shares */ function getTotalShares() external view returns (uint256); /** * @notice the amount of tokens owned by the `_account`. * @dev Balances are dynamic and equal the `_account`'s share in the amount of the total Tokens controlled by the protocol. See `sharesOf`. * @param _account address of the account to check the balance for * @return balance token balance of `_account` */ function balanceOf(address _account) external view returns (uint256); /** * @notice The amount of shares owned by an account * @param _account address of the account * @return shares the amount of shares owned by `_account`. */ function sharesOf(address _account) external view returns (uint256); /** * @notice The remaining number of tokens that `_spender` is allowed to spend * behalf of `_owner` through `transferFrom`. This is zero by default. * @dev This value changes when `approve` or `transferFrom` is called. * @param _owner address that approved the allowance * @param _spender address that is allowed to spend the allowance * @return allowance amount '_spender' is allowed to spend from '_owner' */ function allowance(address _owner, address _spender) external view returns (uint256); /** * @notice The amount of shares that corresponds to `_tokens` protocol-controlled Tokens. * @param _tokens amount of tokens to calculate shares for * @return shares nominal amount of shares the tokens represent */ function tokensToShares(uint256 _tokens) external view returns (uint256); /** * @notice The amount of tokens that corresponds to `_shares` token shares. * @param _shares the amount of shares to calculate the amount of tokens for * @return tokens the amount of tokens represented by the shares */ function sharesToTokens(uint256 _shares) external view returns (uint256); /** * @notice Transfers `_amount` tokens from the caller's account to the `_recipient` account. * @param _recipient address of the recipient * @param _amount amount of tokens to transfer * @return success a boolean value indicating whether the operation succeeded. * @dev Emits a `Transfer` event. * @dev Requirements: * - `_recipient` cannot be the zero address. * - the caller must have a balance of at least `_amount`. * @dev The `_amount` argument is the amount of tokens, not shares. */ function transfer(address _recipient, uint256 _amount) external returns (bool); /** * @notice Sets `_amount` as the allowance of `_spender` over the caller's tokens. * @param _spender address of the spender allowed to approve tokens from caller * @param _amount amount of tokens to allow '_spender' to spend * @return success a boolean value indicating whether the operation succeeded. * @dev Emits an `Approval` event. * @dev Requirements: * - `_spender` cannot be the zero address. * @dev The `_amount` argument is the amount of tokens, not shares. */ function approve(address _spender, uint256 _amount) external returns (bool); /** * @notice Transfers `_amount` tokens from `_sender` to `_recipient` using the * allowance mechanism. `_amount` is then deducted from the caller's allowance. * @param _sender address of the account to transfer tokens from * @param _recipient address of the recipient * @return success a boolean value indicating whether the operation succeeded. * @dev Emits a `Transfer` event. * @dev Emits an `Approval` event indicating the updated allowance. * @dev Requirements: * - `_sender` and `_recipient` cannot be the zero addresses. * - `_sender` must have a balance of at least `_amount`. * - the caller must have allowance for `_sender`'s tokens of at least `_amount`. * @dev The `_amount` argument is the amount of tokens, not shares. */ function transferFrom( address _sender, address _recipient, uint256 _amount ) external returns (bool); /** * @notice Atomically increases the allowance granted to `_spender` by the caller by `_addedValue`. * @param _spender address of the spender allowed to approve tokens from caller * @param _addedValue amount to add to allowance * @return success a boolean value indicating whether the operation succeeded. * @dev This is an alternative to `approve` that can be used as a mitigation for problems described in: * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L42 * @dev Emits an `Approval` event indicating the updated allowance. * @dev Requirements: * - `_spender` cannot be the the zero address. */ function increaseAllowance(address _spender, uint256 _addedValue) external returns (bool); /** * @notice Atomically decreases the allowance granted to `_spender` by the caller by `_subtractedValue`. * @param _spender address of the spender allowed to approve tokens from caller * @param _subtractedValue amount to subtract from current allowance * @return success a boolean value indicating whether the operation succeeded. * @dev This is an alternative to `approve` that can be used as a mitigation for problems described in: * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L42 * @dev Emits an `Approval` event indicating the updated allowance. * @dev Requirements: * - `_spender` cannot be the zero address. * - `_spender` must have allowance for the caller of at least `_subtractedValue`. */ function decreaseAllowance(address _spender, uint256 _subtractedValue) external returns (bool); /** * @notice Mints '_amount' of tokens for '_recipient' * @param _recipient address to mint tokens for * @param _amount amount to mint * @return success a boolean value indicating whether the operation succeeded. * @dev Only callable by contract owner * @dev Calculates the amount of shares to create based on the specified '_amount' * and creates new shares rather than minting actual tokens * @dev '_recipient' should also deposit into Tenderizer * atomically to prevent diluation of existing particpants */ function mint(address _recipient, uint256 _amount) external returns (bool); /** * @notice Burns '_amount' of tokens from '_recipient' * @param _account address to burn the tokens from * @param _amount amount to burn * @return success a boolean value indicating whether the operation succeeded. * @dev Only callable by contract owner * @dev Calculates the amount of shares to destroy based on the specified '_amount' * and destroy shares rather than burning tokens * @dev '_recipient' should also withdraw from Tenderizer atomically */ function burn(address _account, uint256 _amount) external returns (bool); /** * @notice sets a TotalStakedReader to read the total staked tokens from * @param _stakedReader contract address implementing the ITotalStakedReader interface * @dev Only callable by contract owner. * @dev Used to determine TenderToken total supply. */ function setTotalStakedReader(ITotalStakedReader _stakedReader) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./draft-IERC20PermitUpgradeable.sol"; import "../ERC20Upgradeable.sol"; import "../../../utils/cryptography/draft-EIP712Upgradeable.sol"; import "../../../utils/cryptography/ECDSAUpgradeable.sol"; import "../../../utils/CountersUpgradeable.sol"; import "../../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * _Available since v3.4._ */ abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IERC20PermitUpgradeable, EIP712Upgradeable { using CountersUpgradeable for CountersUpgradeable.Counter; mapping(address => CountersUpgradeable.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private _PERMIT_TYPEHASH; /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC20 token name. */ function __ERC20Permit_init(string memory name) internal initializer { __Context_init_unchained(); __EIP712_init_unchained(name, "1"); __ERC20Permit_init_unchained(name); } function __ERC20Permit_init_unchained(string memory name) internal initializer { _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");} /** * @dev See {IERC20Permit-permit}. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSAUpgradeable.recover(hash, v, r, s); require(signer == owner, "ERC20Permit: invalid signature"); _approve(owner, spender, value); } /** * @dev See {IERC20Permit-nonces}. */ function nonces(address owner) public view virtual override returns (uint256) { return _nonces[owner].current(); } /** * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } /** * @dev "Consume a nonce": return the current value and increment. * * _Available since v4.1._ */ function _useNonce(address owner) internal virtual returns (uint256 current) { CountersUpgradeable.Counter storage nonce = _nonces[owner]; current = nonce.current(); nonce.increment(); } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } uint256[50] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "./extensions/IERC20MetadataUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal initializer { __Context_init_unchained(); __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal initializer { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][_msgSender()]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); unchecked { _approve(sender, _msgSender(), currentAllowance - amount); } return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { uint256 currentAllowance = _allowances[_msgSender()][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(_msgSender(), spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `sender` to `recipient`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); uint256 senderBalance = _balances[sender]; require(senderBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[sender] = senderBalance - amount; } _balances[recipient] += amount; emit Transfer(sender, recipient, amount); _afterTokenTransfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; } _totalSupply -= amount; emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} uint256[45] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./ECDSAUpgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * _Available since v3.4._ */ abstract contract EIP712Upgradeable is Initializable { /* solhint-disable var-name-mixedcase */ bytes32 private _HASHED_NAME; bytes32 private _HASHED_VERSION; bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /* solhint-enable var-name-mixedcase */ /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ function __EIP712_init(string memory name, string memory version) internal initializer { __EIP712_init_unchained(name, version); } function __EIP712_init_unchained(string memory name, string memory version) internal initializer { bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedVersion = keccak256(bytes(version)); _HASHED_NAME = hashedName; _HASHED_VERSION = hashedVersion; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { return _buildDomainSeparator(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash()); } function _buildDomainSeparator( bytes32 typeHash, bytes32 nameHash, bytes32 versionHash ) private view returns (bytes32) { return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev The hash of the name parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712NameHash() internal virtual view returns (bytes32) { return _HASHED_NAME; } /** * @dev The hash of the version parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712VersionHash() internal virtual view returns (bytes32) { return _HASHED_VERSION; } uint256[50] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSAUpgradeable { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } else if (error == RecoverError.InvalidSignatureV) { revert("ECDSA: invalid signature 'v' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { // Check the signature length // - case 65: r,s,v signature (standard) // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else if (signature.length == 64) { bytes32 r; bytes32 vs; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) vs := mload(add(signature, 0x40)) } return tryRecover(hash, r, vs); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s; uint8 v; assembly { s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) v := add(shr(255, vs), 27) } return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } if (v != 27 && v != 28) { return (address(0), RecoverError.InvalidSignatureV); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library CountersUpgradeable { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
{ "optimizer": { "enabled": false, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getTotalPooledTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"contract ITotalStakedReader","name":"_totalStakedReader","type":"address"}],"name":"initialize","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ITotalStakedReader","name":"_totalStakedReader","type":"address"}],"name":"setTotalStakedReader","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"sharesToTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokens","type":"uint256"}],"name":"tokensToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStakedReader","outputs":[{"internalType":"contract ITotalStakedReader","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50613b4b806100206000396000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c8063715018a6116100f9578063a9059cbb11610097578063dd62ed3e11610071578063dd62ed3e1461050e578063f2fde38b1461053e578063f3044ac71461055a578063f5eb42dc1461058a576101a9565b8063a9059cbb146104a4578063d5002f2e146104d4578063d505accf146104f2576101a9565b80638da5cb5b116100d35780638da5cb5b1461040857806395d89b41146104265780639dc29fac14610444578063a457c2d714610474576101a9565b8063715018a6146103b05780637ecebe00146103ba5780638d7a7164146103ea576101a9565b806323b872dd116101665780633644e515116101405780633644e51514610302578063395093511461032057806340c10f191461035057806370a0823114610380576101a9565b806323b872dd1461028457806327def4fd146102b4578063313ce567146102e4576101a9565b80630216b5ec146101ae57806306fdde03146101cc578063077f224a146101ea578063095ea7b31461021a57806310eae6b51461024a57806318160ddd14610266575b600080fd5b6101b66105ba565b6040516101c39190612fe8565b60405180910390f35b6101d46105e1565b6040516101e19190613003565b60405180910390f35b61020460048036038101906101ff9190612975565b610673565b6040516102119190612eb9565b60405180910390f35b610234600480360381019061022f9190612910565b610876565b6040516102419190612eb9565b60405180910390f35b610264600480360381019061025f919061294c565b61088d565b005b61026e610988565b60405161027b9190613285565b60405180910390f35b61029e60048036038101906102999190612823565b610997565b6040516102ab9190612eb9565b60405180910390f35b6102ce60048036038101906102c991906129f4565b610a8a565b6040516102db9190613285565b60405180910390f35b6102ec610a9c565b6040516102f991906132a0565b60405180910390f35b61030a610aa5565b6040516103179190612ed4565b60405180910390f35b61033a60048036038101906103359190612910565b610ab4565b6040516103479190612eb9565b60405180910390f35b61036a60048036038101906103659190612910565b610b53565b6040516103779190612eb9565b60405180910390f35b61039a600480360381019061039591906127be565b610bed565b6040516103a79190613285565b60405180910390f35b6103b8610c07565b005b6103d460048036038101906103cf91906127be565b610c8f565b6040516103e19190613285565b60405180910390f35b6103f2610cdf565b6040516103ff9190613285565b60405180910390f35b610410610cee565b60405161041d9190612e9e565b60405180910390f35b61042e610d18565b60405161043b9190613003565b60405180910390f35b61045e60048036038101906104599190612910565b610daa565b60405161046b9190612eb9565b60405180910390f35b61048e60048036038101906104899190612910565b610e4b565b60405161049b9190612eb9565b60405180910390f35b6104be60048036038101906104b99190612910565b610f32565b6040516104cb9190612eb9565b60405180910390f35b6104dc610f49565b6040516104e99190613285565b60405180910390f35b61050c60048036038101906105079190612872565b610f58565b005b610528600480360381019061052391906127e7565b61107c565b6040516105359190613285565b60405180910390f35b610558600480360381019061055391906127be565b611104565b005b610574600480360381019061056f91906129f4565b6111fc565b6040516105819190613285565b60405180910390f35b6105a4600480360381019061059f91906127be565b61120e565b6040516105b19190613285565b60405180910390f35b61010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6060606880546105f090613524565b80601f016020809104026020016040519081016040528092919081815260200182805461061c90613524565b80156106695780601f1061063e57610100808354040283529160200191610669565b820191906000526020600020905b81548152906001019060200180831161064c57829003601f168201915b5050505050905090565b60008060019054906101000a900460ff168061069a575060008054906101000a900460ff16155b6106d9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106d090613165565b60405180910390fd5b60008060019054906101000a900460ff161590508015610729576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b610731611220565b6107396112f9565b6107818560405160200161074d9190612e5a565b6040516020818303038152906040528560405160200161076d9190612e7c565b6040516020818303038152906040526113e2565b6107df856040516020016107959190612e5a565b6040516020818303038152906040526040518060400160405280600181526020017f31000000000000000000000000000000000000000000000000000000000000008152506114eb565b610807856040516020016107f39190612e5a565b6040516020818303038152906040526115ee565b8261010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060019150801561086e5760008060016101000a81548160ff0219169083151502179055505b509392505050565b60006108833384846116ef565b6001905092915050565b6108956118bb565b73ffffffffffffffffffffffffffffffffffffffff166108b3610cee565b73ffffffffffffffffffffffffffffffffffffffff1614610909576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161090090613205565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561094357600080fd5b8061010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006109926118c3565b905090565b60008061010060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082811015610a5d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5490613045565b60405180910390fd5b610a6885858561196b565b610a7e85338584610a799190613419565b6116ef565b60019150509392505050565b6000610a95826119ee565b9050919050565b60006012905090565b6000610aaf611a29565b905090565b6000610b4933848461010060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610b449190613338565b6116ef565b6001905092915050565b6000610b5d6118bb565b73ffffffffffffffffffffffffffffffffffffffff16610b7b610cee565b73ffffffffffffffffffffffffffffffffffffffff1614610bd1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bc890613205565b60405180910390fd5b610be383610bde84611a69565b611abe565b6001905092915050565b6000610c00610bfb83611ba1565b6119ee565b9050919050565b610c0f6118bb565b73ffffffffffffffffffffffffffffffffffffffff16610c2d610cee565b73ffffffffffffffffffffffffffffffffffffffff1614610c83576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c7a90613205565b60405180910390fd5b610c8d6000611bea565b565b6000610cd860cb60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020611cb0565b9050919050565b6000610ce96118c3565b905090565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606060698054610d2790613524565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5390613524565b8015610da05780601f10610d7557610100808354040283529160200191610da0565b820191906000526020600020905b815481529060010190602001808311610d8357829003601f168201915b5050505050905090565b6000610db46118bb565b73ffffffffffffffffffffffffffffffffffffffff16610dd2610cee565b73ffffffffffffffffffffffffffffffffffffffff1614610e28576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e1f90613205565b60405180910390fd5b6000610e3383611a69565b9050610e3f8482611cbe565b50600191505092915050565b60008061010060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082811015610f11576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f0890613145565b60405180910390fd5b610f2733858584610f229190613419565b6116ef565b600191505092915050565b6000610f3f33848461196b565b6001905092915050565b6000610f53611e23565b905090565b83421115610f9b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f9290613105565b60405180910390fd5b600060cc54888888610fac8c611e2d565b89604051602001610fc296959493929190612eef565b6040516020818303038152906040528051906020012090506000610fe582611e8b565b90506000610ff582878787611ea5565b90508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611065576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161105c906131e5565b60405180910390fd5b6110708a8a8a6116ef565b50505050505050505050565b600061010060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b61110c6118bb565b73ffffffffffffffffffffffffffffffffffffffff1661112a610cee565b73ffffffffffffffffffffffffffffffffffffffff1614611180576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161117790613205565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156111f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111e7906130c5565b60405180910390fd5b6111f981611bea565b50565b600061120782611a69565b9050919050565b600061121982611ba1565b9050919050565b600060019054906101000a900460ff1680611246575060008054906101000a900460ff16155b611285576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161127c90613165565b60405180910390fd5b60008060019054906101000a900460ff1615905080156112d5576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b80156112f65760008060016101000a81548160ff0219169083151502179055505b50565b600060019054906101000a900460ff168061131f575060008054906101000a900460ff16155b61135e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161135590613165565b60405180910390fd5b60008060019054906101000a900460ff1615905080156113ae576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b6113be6113b96118bb565b611bea565b80156113df5760008060016101000a81548160ff0219169083151502179055505b50565b600060019054906101000a900460ff1680611408575060008054906101000a900460ff16155b611447576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161143e90613165565b60405180910390fd5b60008060019054906101000a900460ff161590508015611497576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b82606890805190602001906114ad929190612635565b5081606990805190602001906114c4929190612635565b5080156114e65760008060016101000a81548160ff0219169083151502179055505b505050565b600060019054906101000a900460ff1680611511575060008054906101000a900460ff16155b611550576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161154790613165565b60405180910390fd5b60008060019054906101000a900460ff1615905080156115a0576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b6000838051906020012090506000838051906020012090508160978190555080609881905550505080156115e95760008060016101000a81548160ff0219169083151502179055505b505050565b600060019054906101000a900460ff1680611614575060008054906101000a900460ff16155b611653576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161164a90613165565b60405180910390fd5b60008060019054906101000a900460ff1615905080156116a3576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c960cc8190555080156116eb5760008060016101000a81548160ff0219169083151502179055505b5050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561175f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161175690613245565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156117cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117c6906130e5565b60405180910390fd5b8061010060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516118ae9190613285565b60405180910390a3505050565b600033905090565b600061010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633ae732596040518163ffffffff1660e01b815260040160206040518083038186803b15801561192e57600080fd5b505afa158015611942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119669190612a1d565b905090565b600061197682611a69565b9050611983848483611ed0565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516119e09190613285565b60405180910390a350505050565b6000806119f9611e23565b90506000811415611a0e576000915050611a24565b611a2083611a1a6118c3565b836120e2565b9150505b919050565b6000611a647f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611a57612116565b611a5f612120565b61212a565b905090565b600080611a746118c3565b90506000611a80611e23565b90506000811415611a95578392505050611ab9565b6000821415611aa957600092505050611ab9565b611ab48482846120e2565b925050505b919050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611b2e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b2590613265565b60405180910390fd5b8060ff60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611b7d9190613338565b925050819055508060fe6000828254611b969190613338565b925050819055505050565b600060ff60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081603360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600081600001549050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611d2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d26906130a5565b60405180910390fd5b600060ff60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905080831115611db6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dad906131c5565b60405180910390fd5b8260fe54611dc49190613419565b91508281611dd29190613419565b60ff60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508160fe819055505092915050565b600060fe54905090565b60008060cb60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050611e7a81611cb0565b9150611e8581612164565b50919050565b6000611e9e611e98611a29565b8361217a565b9050919050565b6000806000611eb6878787876121ad565b91509150611ec3816122ba565b8192505050949350505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611f40576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f3790613085565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611fb0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fa7906131a5565b60405180910390fd5b600060ff60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905080821115612037576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161202e90613225565b60405180910390fd5b81816120439190613419565b60ff60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508160ff60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546120d59190613338565b9250508190555050505050565b6000683635c9adc5dea000006120f8848461260b565b8561210391906133bf565b61210d919061338e565b90509392505050565b6000609754905090565b6000609854905090565b60008383834630604051602001612145959493929190612f50565b6040516020818303038152906040528051906020012090509392505050565b6001816000016000828254019250508190555050565b6000828260405160200161218f929190612e23565b60405160208183030381529060405280519060200120905092915050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08360001c11156121e85760006003915091506122b1565b601b8560ff16141580156122005750601c8560ff1614155b156122125760006004915091506122b1565b6000600187878787604051600081526020016040526040516122379493929190612fa3565b6020604051602081039080840390855afa158015612259573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156122a8576000600192509250506122b1565b80600092509250505b94509492505050565b600060048111156122f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b81600481111561232d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b141561233857612608565b60016004811115612372577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8160048111156123ab577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14156123ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123e390613025565b60405180910390fd5b60026004811115612426577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b81600481111561245f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14156124a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161249790613065565b60405180910390fd5b600360048111156124da577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b816004811115612513577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415612554576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161254b90613125565b60405180910390fd5b60048081111561258d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8160048111156125c6577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415612607576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125fe90613185565b60405180910390fd5b5b50565b600081683635c9adc5dea000008461262391906133bf565b61262d919061338e565b905092915050565b82805461264190613524565b90600052602060002090601f01602090048101928261266357600085556126aa565b82601f1061267c57805160ff19168380011785556126aa565b828001600101855582156126aa579182015b828111156126a957825182559160200191906001019061268e565b5b5090506126b791906126bb565b5090565b5b808211156126d45760008160009055506001016126bc565b5090565b60006126eb6126e6846132e0565b6132bb565b90508281526020810184848401111561270357600080fd5b61270e8482856134e2565b509392505050565b60008135905061272581613aa2565b92915050565b60008135905061273a81613ab9565b92915050565b60008135905061274f81613ad0565b92915050565b600082601f83011261276657600080fd5b81356127768482602086016126d8565b91505092915050565b60008135905061278e81613ae7565b92915050565b6000815190506127a381613ae7565b92915050565b6000813590506127b881613afe565b92915050565b6000602082840312156127d057600080fd5b60006127de84828501612716565b91505092915050565b600080604083850312156127fa57600080fd5b600061280885828601612716565b925050602061281985828601612716565b9150509250929050565b60008060006060848603121561283857600080fd5b600061284686828701612716565b935050602061285786828701612716565b92505060406128688682870161277f565b9150509250925092565b600080600080600080600060e0888a03121561288d57600080fd5b600061289b8a828b01612716565b97505060206128ac8a828b01612716565b96505060406128bd8a828b0161277f565b95505060606128ce8a828b0161277f565b94505060806128df8a828b016127a9565b93505060a06128f08a828b0161272b565b92505060c06129018a828b0161272b565b91505092959891949750929550565b6000806040838503121561292357600080fd5b600061293185828601612716565b92505060206129428582860161277f565b9150509250929050565b60006020828403121561295e57600080fd5b600061296c84828501612740565b91505092915050565b60008060006060848603121561298a57600080fd5b600084013567ffffffffffffffff8111156129a457600080fd5b6129b086828701612755565b935050602084013567ffffffffffffffff8111156129cd57600080fd5b6129d986828701612755565b92505060406129ea86828701612740565b9150509250925092565b600060208284031215612a0657600080fd5b6000612a148482850161277f565b91505092915050565b600060208284031215612a2f57600080fd5b6000612a3d84828501612794565b91505092915050565b612a4f8161344d565b82525050565b612a5e8161345f565b82525050565b612a6d8161346b565b82525050565b612a84612a7f8261346b565b613587565b82525050565b612a93816134be565b82525050565b6000612aa482613311565b612aae818561331c565b9350612abe8185602086016134f1565b612ac78161364d565b840191505092915050565b6000612add82613311565b612ae7818561332d565b9350612af78185602086016134f1565b80840191505092915050565b6000612b1060188361331c565b9150612b1b8261365e565b602082019050919050565b6000612b3360218361331c565b9150612b3e82613687565b604082019050919050565b6000612b56601f8361331c565b9150612b61826136d6565b602082019050919050565b6000612b79601e8361331c565b9150612b84826136ff565b602082019050919050565b6000612b9c601a8361331c565b9150612ba782613728565b602082019050919050565b6000612bbf60268361331c565b9150612bca82613751565b604082019050919050565b6000612be260178361331c565b9150612bed826137a0565b602082019050919050565b6000612c0560028361332d565b9150612c10826137c9565b600282019050919050565b6000612c28601d8361331c565b9150612c33826137f2565b602082019050919050565b6000612c4b60228361331c565b9150612c568261381b565b604082019050919050565b6000612c6e601e8361331c565b9150612c798261386a565b602082019050919050565b6000612c9160078361332d565b9150612c9c82613893565b600782019050919050565b6000612cb4602e8361331c565b9150612cbf826138bc565b604082019050919050565b6000612cd760228361331c565b9150612ce28261390b565b604082019050919050565b6000612cfa601c8361331c565b9150612d058261395a565b602082019050919050565b6000612d1d601b8361331c565b9150612d2882613983565b602082019050919050565b6000612d40601e8361331c565b9150612d4b826139ac565b602082019050919050565b6000612d6360208361331c565b9150612d6e826139d5565b602082019050919050565b6000612d86601f8361331c565b9150612d91826139fe565b602082019050919050565b6000612da960018361332d565b9150612db482613a27565b600182019050919050565b6000612dcc60198361331c565b9150612dd782613a50565b602082019050919050565b6000612def60188361331c565b9150612dfa82613a79565b602082019050919050565b612e0e816134a7565b82525050565b612e1d816134b1565b82525050565b6000612e2e82612bf8565b9150612e3a8285612a73565b602082019150612e4a8284612a73565b6020820191508190509392505050565b6000612e6582612c84565b9150612e718284612ad2565b915081905092915050565b6000612e8782612d9c565b9150612e938284612ad2565b915081905092915050565b6000602082019050612eb36000830184612a46565b92915050565b6000602082019050612ece6000830184612a55565b92915050565b6000602082019050612ee96000830184612a64565b92915050565b600060c082019050612f046000830189612a64565b612f116020830188612a46565b612f1e6040830187612a46565b612f2b6060830186612e05565b612f386080830185612e05565b612f4560a0830184612e05565b979650505050505050565b600060a082019050612f656000830188612a64565b612f726020830187612a64565b612f7f6040830186612a64565b612f8c6060830185612e05565b612f996080830184612a46565b9695505050505050565b6000608082019050612fb86000830187612a64565b612fc56020830186612e14565b612fd26040830185612a64565b612fdf6060830184612a64565b95945050505050565b6000602082019050612ffd6000830184612a8a565b92915050565b6000602082019050818103600083015261301d8184612a99565b905092915050565b6000602082019050818103600083015261303e81612b03565b9050919050565b6000602082019050818103600083015261305e81612b26565b9050919050565b6000602082019050818103600083015261307e81612b49565b9050919050565b6000602082019050818103600083015261309e81612b6c565b9050919050565b600060208201905081810360008301526130be81612b8f565b9050919050565b600060208201905081810360008301526130de81612bb2565b9050919050565b600060208201905081810360008301526130fe81612bd5565b9050919050565b6000602082019050818103600083015261311e81612c1b565b9050919050565b6000602082019050818103600083015261313e81612c3e565b9050919050565b6000602082019050818103600083015261315e81612c61565b9050919050565b6000602082019050818103600083015261317e81612ca7565b9050919050565b6000602082019050818103600083015261319e81612cca565b9050919050565b600060208201905081810360008301526131be81612ced565b9050919050565b600060208201905081810360008301526131de81612d10565b9050919050565b600060208201905081810360008301526131fe81612d33565b9050919050565b6000602082019050818103600083015261321e81612d56565b9050919050565b6000602082019050818103600083015261323e81612d79565b9050919050565b6000602082019050818103600083015261325e81612dbf565b9050919050565b6000602082019050818103600083015261327e81612de2565b9050919050565b600060208201905061329a6000830184612e05565b92915050565b60006020820190506132b56000830184612e14565b92915050565b60006132c56132d6565b90506132d18282613556565b919050565b6000604051905090565b600067ffffffffffffffff8211156132fb576132fa61361e565b5b6133048261364d565b9050602081019050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b6000613343826134a7565b915061334e836134a7565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561338357613382613591565b5b828201905092915050565b6000613399826134a7565b91506133a4836134a7565b9250826133b4576133b36135c0565b5b828204905092915050565b60006133ca826134a7565b91506133d5836134a7565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561340e5761340d613591565b5b828202905092915050565b6000613424826134a7565b915061342f836134a7565b92508282101561344257613441613591565b5b828203905092915050565b600061345882613487565b9050919050565b60008115159050919050565b6000819050919050565b60006134808261344d565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60006134c9826134d0565b9050919050565b60006134db82613487565b9050919050565b82818337600083830152505050565b60005b8381101561350f5780820151818401526020810190506134f4565b8381111561351e576000848401525b50505050565b6000600282049050600182168061353c57607f821691505b602082108114156135505761354f6135ef565b5b50919050565b61355f8261364d565b810181811067ffffffffffffffff8211171561357e5761357d61361e565b5b80604052505050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b7f45434453413a20696e76616c6964207369676e61747572650000000000000000600082015250565b7f5452414e534645525f414d4f554e545f455843454544535f414c4c4f57414e4360008201527f4500000000000000000000000000000000000000000000000000000000000000602082015250565b7f45434453413a20696e76616c6964207369676e6174757265206c656e67746800600082015250565b7f5452414e534645525f46524f4d5f5448455f5a45524f5f414444524553530000600082015250565b7f4255524e5f46524f4d5f5448455f5a45524f5f41444452455353000000000000600082015250565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b7f415050524f56455f544f5f5a45524f5f41444452455353000000000000000000600082015250565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b7f45524332305065726d69743a206578706972656420646561646c696e65000000600082015250565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b7f4445435245415345445f414c4c4f57414e43455f42454c4f575f5a45524f0000600082015250565b7f74656e6465722000000000000000000000000000000000000000000000000000600082015250565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b7f45434453413a20696e76616c6964207369676e6174757265202776272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b7f5452414e534645525f544f5f5448455f5a45524f5f4144445245535300000000600082015250565b7f4255524e5f414d4f554e545f455843454544535f42414c414e43450000000000600082015250565b7f45524332305065726d69743a20696e76616c6964207369676e61747572650000600082015250565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b7f5452414e534645525f414d4f554e545f455843454544535f42414c414e434500600082015250565b7f7400000000000000000000000000000000000000000000000000000000000000600082015250565b7f415050524f56455f46524f4d5f5a45524f5f4144445245535300000000000000600082015250565b7f4d494e545f544f5f5448455f5a45524f5f414444524553530000000000000000600082015250565b613aab8161344d565b8114613ab657600080fd5b50565b613ac28161346b565b8114613acd57600080fd5b50565b613ad981613475565b8114613ae457600080fd5b50565b613af0816134a7565b8114613afb57600080fd5b50565b613b07816134b1565b8114613b1257600080fd5b5056fea26469706673582212208ddc692d830446bc45ea3672b6cc369fa704f8ffad723c656f87d6d80358d94664736f6c63430008040033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101a95760003560e01c8063715018a6116100f9578063a9059cbb11610097578063dd62ed3e11610071578063dd62ed3e1461050e578063f2fde38b1461053e578063f3044ac71461055a578063f5eb42dc1461058a576101a9565b8063a9059cbb146104a4578063d5002f2e146104d4578063d505accf146104f2576101a9565b80638da5cb5b116100d35780638da5cb5b1461040857806395d89b41146104265780639dc29fac14610444578063a457c2d714610474576101a9565b8063715018a6146103b05780637ecebe00146103ba5780638d7a7164146103ea576101a9565b806323b872dd116101665780633644e515116101405780633644e51514610302578063395093511461032057806340c10f191461035057806370a0823114610380576101a9565b806323b872dd1461028457806327def4fd146102b4578063313ce567146102e4576101a9565b80630216b5ec146101ae57806306fdde03146101cc578063077f224a146101ea578063095ea7b31461021a57806310eae6b51461024a57806318160ddd14610266575b600080fd5b6101b66105ba565b6040516101c39190612fe8565b60405180910390f35b6101d46105e1565b6040516101e19190613003565b60405180910390f35b61020460048036038101906101ff9190612975565b610673565b6040516102119190612eb9565b60405180910390f35b610234600480360381019061022f9190612910565b610876565b6040516102419190612eb9565b60405180910390f35b610264600480360381019061025f919061294c565b61088d565b005b61026e610988565b60405161027b9190613285565b60405180910390f35b61029e60048036038101906102999190612823565b610997565b6040516102ab9190612eb9565b60405180910390f35b6102ce60048036038101906102c991906129f4565b610a8a565b6040516102db9190613285565b60405180910390f35b6102ec610a9c565b6040516102f991906132a0565b60405180910390f35b61030a610aa5565b6040516103179190612ed4565b60405180910390f35b61033a60048036038101906103359190612910565b610ab4565b6040516103479190612eb9565b60405180910390f35b61036a60048036038101906103659190612910565b610b53565b6040516103779190612eb9565b60405180910390f35b61039a600480360381019061039591906127be565b610bed565b6040516103a79190613285565b60405180910390f35b6103b8610c07565b005b6103d460048036038101906103cf91906127be565b610c8f565b6040516103e19190613285565b60405180910390f35b6103f2610cdf565b6040516103ff9190613285565b60405180910390f35b610410610cee565b60405161041d9190612e9e565b60405180910390f35b61042e610d18565b60405161043b9190613003565b60405180910390f35b61045e60048036038101906104599190612910565b610daa565b60405161046b9190612eb9565b60405180910390f35b61048e60048036038101906104899190612910565b610e4b565b60405161049b9190612eb9565b60405180910390f35b6104be60048036038101906104b99190612910565b610f32565b6040516104cb9190612eb9565b60405180910390f35b6104dc610f49565b6040516104e99190613285565b60405180910390f35b61050c60048036038101906105079190612872565b610f58565b005b610528600480360381019061052391906127e7565b61107c565b6040516105359190613285565b60405180910390f35b610558600480360381019061055391906127be565b611104565b005b610574600480360381019061056f91906129f4565b6111fc565b6040516105819190613285565b60405180910390f35b6105a4600480360381019061059f91906127be565b61120e565b6040516105b19190613285565b60405180910390f35b61010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6060606880546105f090613524565b80601f016020809104026020016040519081016040528092919081815260200182805461061c90613524565b80156106695780601f1061063e57610100808354040283529160200191610669565b820191906000526020600020905b81548152906001019060200180831161064c57829003601f168201915b5050505050905090565b60008060019054906101000a900460ff168061069a575060008054906101000a900460ff16155b6106d9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106d090613165565b60405180910390fd5b60008060019054906101000a900460ff161590508015610729576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b610731611220565b6107396112f9565b6107818560405160200161074d9190612e5a565b6040516020818303038152906040528560405160200161076d9190612e7c565b6040516020818303038152906040526113e2565b6107df856040516020016107959190612e5a565b6040516020818303038152906040526040518060400160405280600181526020017f31000000000000000000000000000000000000000000000000000000000000008152506114eb565b610807856040516020016107f39190612e5a565b6040516020818303038152906040526115ee565b8261010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060019150801561086e5760008060016101000a81548160ff0219169083151502179055505b509392505050565b60006108833384846116ef565b6001905092915050565b6108956118bb565b73ffffffffffffffffffffffffffffffffffffffff166108b3610cee565b73ffffffffffffffffffffffffffffffffffffffff1614610909576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161090090613205565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561094357600080fd5b8061010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006109926118c3565b905090565b60008061010060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082811015610a5d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5490613045565b60405180910390fd5b610a6885858561196b565b610a7e85338584610a799190613419565b6116ef565b60019150509392505050565b6000610a95826119ee565b9050919050565b60006012905090565b6000610aaf611a29565b905090565b6000610b4933848461010060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610b449190613338565b6116ef565b6001905092915050565b6000610b5d6118bb565b73ffffffffffffffffffffffffffffffffffffffff16610b7b610cee565b73ffffffffffffffffffffffffffffffffffffffff1614610bd1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bc890613205565b60405180910390fd5b610be383610bde84611a69565b611abe565b6001905092915050565b6000610c00610bfb83611ba1565b6119ee565b9050919050565b610c0f6118bb565b73ffffffffffffffffffffffffffffffffffffffff16610c2d610cee565b73ffffffffffffffffffffffffffffffffffffffff1614610c83576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c7a90613205565b60405180910390fd5b610c8d6000611bea565b565b6000610cd860cb60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020611cb0565b9050919050565b6000610ce96118c3565b905090565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606060698054610d2790613524565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5390613524565b8015610da05780601f10610d7557610100808354040283529160200191610da0565b820191906000526020600020905b815481529060010190602001808311610d8357829003601f168201915b5050505050905090565b6000610db46118bb565b73ffffffffffffffffffffffffffffffffffffffff16610dd2610cee565b73ffffffffffffffffffffffffffffffffffffffff1614610e28576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e1f90613205565b60405180910390fd5b6000610e3383611a69565b9050610e3f8482611cbe565b50600191505092915050565b60008061010060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082811015610f11576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f0890613145565b60405180910390fd5b610f2733858584610f229190613419565b6116ef565b600191505092915050565b6000610f3f33848461196b565b6001905092915050565b6000610f53611e23565b905090565b83421115610f9b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f9290613105565b60405180910390fd5b600060cc54888888610fac8c611e2d565b89604051602001610fc296959493929190612eef565b6040516020818303038152906040528051906020012090506000610fe582611e8b565b90506000610ff582878787611ea5565b90508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611065576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161105c906131e5565b60405180910390fd5b6110708a8a8a6116ef565b50505050505050505050565b600061010060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b61110c6118bb565b73ffffffffffffffffffffffffffffffffffffffff1661112a610cee565b73ffffffffffffffffffffffffffffffffffffffff1614611180576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161117790613205565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156111f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111e7906130c5565b60405180910390fd5b6111f981611bea565b50565b600061120782611a69565b9050919050565b600061121982611ba1565b9050919050565b600060019054906101000a900460ff1680611246575060008054906101000a900460ff16155b611285576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161127c90613165565b60405180910390fd5b60008060019054906101000a900460ff1615905080156112d5576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b80156112f65760008060016101000a81548160ff0219169083151502179055505b50565b600060019054906101000a900460ff168061131f575060008054906101000a900460ff16155b61135e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161135590613165565b60405180910390fd5b60008060019054906101000a900460ff1615905080156113ae576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b6113be6113b96118bb565b611bea565b80156113df5760008060016101000a81548160ff0219169083151502179055505b50565b600060019054906101000a900460ff1680611408575060008054906101000a900460ff16155b611447576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161143e90613165565b60405180910390fd5b60008060019054906101000a900460ff161590508015611497576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b82606890805190602001906114ad929190612635565b5081606990805190602001906114c4929190612635565b5080156114e65760008060016101000a81548160ff0219169083151502179055505b505050565b600060019054906101000a900460ff1680611511575060008054906101000a900460ff16155b611550576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161154790613165565b60405180910390fd5b60008060019054906101000a900460ff1615905080156115a0576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b6000838051906020012090506000838051906020012090508160978190555080609881905550505080156115e95760008060016101000a81548160ff0219169083151502179055505b505050565b600060019054906101000a900460ff1680611614575060008054906101000a900460ff16155b611653576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161164a90613165565b60405180910390fd5b60008060019054906101000a900460ff1615905080156116a3576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c960cc8190555080156116eb5760008060016101000a81548160ff0219169083151502179055505b5050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561175f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161175690613245565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156117cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117c6906130e5565b60405180910390fd5b8061010060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516118ae9190613285565b60405180910390a3505050565b600033905090565b600061010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633ae732596040518163ffffffff1660e01b815260040160206040518083038186803b15801561192e57600080fd5b505afa158015611942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119669190612a1d565b905090565b600061197682611a69565b9050611983848483611ed0565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516119e09190613285565b60405180910390a350505050565b6000806119f9611e23565b90506000811415611a0e576000915050611a24565b611a2083611a1a6118c3565b836120e2565b9150505b919050565b6000611a647f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611a57612116565b611a5f612120565b61212a565b905090565b600080611a746118c3565b90506000611a80611e23565b90506000811415611a95578392505050611ab9565b6000821415611aa957600092505050611ab9565b611ab48482846120e2565b925050505b919050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611b2e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b2590613265565b60405180910390fd5b8060ff60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611b7d9190613338565b925050819055508060fe6000828254611b969190613338565b925050819055505050565b600060ff60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081603360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600081600001549050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611d2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d26906130a5565b60405180910390fd5b600060ff60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905080831115611db6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dad906131c5565b60405180910390fd5b8260fe54611dc49190613419565b91508281611dd29190613419565b60ff60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508160fe819055505092915050565b600060fe54905090565b60008060cb60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050611e7a81611cb0565b9150611e8581612164565b50919050565b6000611e9e611e98611a29565b8361217a565b9050919050565b6000806000611eb6878787876121ad565b91509150611ec3816122ba565b8192505050949350505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611f40576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f3790613085565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611fb0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fa7906131a5565b60405180910390fd5b600060ff60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905080821115612037576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161202e90613225565b60405180910390fd5b81816120439190613419565b60ff60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508160ff60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546120d59190613338565b9250508190555050505050565b6000683635c9adc5dea000006120f8848461260b565b8561210391906133bf565b61210d919061338e565b90509392505050565b6000609754905090565b6000609854905090565b60008383834630604051602001612145959493929190612f50565b6040516020818303038152906040528051906020012090509392505050565b6001816000016000828254019250508190555050565b6000828260405160200161218f929190612e23565b60405160208183030381529060405280519060200120905092915050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08360001c11156121e85760006003915091506122b1565b601b8560ff16141580156122005750601c8560ff1614155b156122125760006004915091506122b1565b6000600187878787604051600081526020016040526040516122379493929190612fa3565b6020604051602081039080840390855afa158015612259573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156122a8576000600192509250506122b1565b80600092509250505b94509492505050565b600060048111156122f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b81600481111561232d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b141561233857612608565b60016004811115612372577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8160048111156123ab577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14156123ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123e390613025565b60405180910390fd5b60026004811115612426577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b81600481111561245f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14156124a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161249790613065565b60405180910390fd5b600360048111156124da577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b816004811115612513577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415612554576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161254b90613125565b60405180910390fd5b60048081111561258d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8160048111156125c6577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415612607576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125fe90613185565b60405180910390fd5b5b50565b600081683635c9adc5dea000008461262391906133bf565b61262d919061338e565b905092915050565b82805461264190613524565b90600052602060002090601f01602090048101928261266357600085556126aa565b82601f1061267c57805160ff19168380011785556126aa565b828001600101855582156126aa579182015b828111156126a957825182559160200191906001019061268e565b5b5090506126b791906126bb565b5090565b5b808211156126d45760008160009055506001016126bc565b5090565b60006126eb6126e6846132e0565b6132bb565b90508281526020810184848401111561270357600080fd5b61270e8482856134e2565b509392505050565b60008135905061272581613aa2565b92915050565b60008135905061273a81613ab9565b92915050565b60008135905061274f81613ad0565b92915050565b600082601f83011261276657600080fd5b81356127768482602086016126d8565b91505092915050565b60008135905061278e81613ae7565b92915050565b6000815190506127a381613ae7565b92915050565b6000813590506127b881613afe565b92915050565b6000602082840312156127d057600080fd5b60006127de84828501612716565b91505092915050565b600080604083850312156127fa57600080fd5b600061280885828601612716565b925050602061281985828601612716565b9150509250929050565b60008060006060848603121561283857600080fd5b600061284686828701612716565b935050602061285786828701612716565b92505060406128688682870161277f565b9150509250925092565b600080600080600080600060e0888a03121561288d57600080fd5b600061289b8a828b01612716565b97505060206128ac8a828b01612716565b96505060406128bd8a828b0161277f565b95505060606128ce8a828b0161277f565b94505060806128df8a828b016127a9565b93505060a06128f08a828b0161272b565b92505060c06129018a828b0161272b565b91505092959891949750929550565b6000806040838503121561292357600080fd5b600061293185828601612716565b92505060206129428582860161277f565b9150509250929050565b60006020828403121561295e57600080fd5b600061296c84828501612740565b91505092915050565b60008060006060848603121561298a57600080fd5b600084013567ffffffffffffffff8111156129a457600080fd5b6129b086828701612755565b935050602084013567ffffffffffffffff8111156129cd57600080fd5b6129d986828701612755565b92505060406129ea86828701612740565b9150509250925092565b600060208284031215612a0657600080fd5b6000612a148482850161277f565b91505092915050565b600060208284031215612a2f57600080fd5b6000612a3d84828501612794565b91505092915050565b612a4f8161344d565b82525050565b612a5e8161345f565b82525050565b612a6d8161346b565b82525050565b612a84612a7f8261346b565b613587565b82525050565b612a93816134be565b82525050565b6000612aa482613311565b612aae818561331c565b9350612abe8185602086016134f1565b612ac78161364d565b840191505092915050565b6000612add82613311565b612ae7818561332d565b9350612af78185602086016134f1565b80840191505092915050565b6000612b1060188361331c565b9150612b1b8261365e565b602082019050919050565b6000612b3360218361331c565b9150612b3e82613687565b604082019050919050565b6000612b56601f8361331c565b9150612b61826136d6565b602082019050919050565b6000612b79601e8361331c565b9150612b84826136ff565b602082019050919050565b6000612b9c601a8361331c565b9150612ba782613728565b602082019050919050565b6000612bbf60268361331c565b9150612bca82613751565b604082019050919050565b6000612be260178361331c565b9150612bed826137a0565b602082019050919050565b6000612c0560028361332d565b9150612c10826137c9565b600282019050919050565b6000612c28601d8361331c565b9150612c33826137f2565b602082019050919050565b6000612c4b60228361331c565b9150612c568261381b565b604082019050919050565b6000612c6e601e8361331c565b9150612c798261386a565b602082019050919050565b6000612c9160078361332d565b9150612c9c82613893565b600782019050919050565b6000612cb4602e8361331c565b9150612cbf826138bc565b604082019050919050565b6000612cd760228361331c565b9150612ce28261390b565b604082019050919050565b6000612cfa601c8361331c565b9150612d058261395a565b602082019050919050565b6000612d1d601b8361331c565b9150612d2882613983565b602082019050919050565b6000612d40601e8361331c565b9150612d4b826139ac565b602082019050919050565b6000612d6360208361331c565b9150612d6e826139d5565b602082019050919050565b6000612d86601f8361331c565b9150612d91826139fe565b602082019050919050565b6000612da960018361332d565b9150612db482613a27565b600182019050919050565b6000612dcc60198361331c565b9150612dd782613a50565b602082019050919050565b6000612def60188361331c565b9150612dfa82613a79565b602082019050919050565b612e0e816134a7565b82525050565b612e1d816134b1565b82525050565b6000612e2e82612bf8565b9150612e3a8285612a73565b602082019150612e4a8284612a73565b6020820191508190509392505050565b6000612e6582612c84565b9150612e718284612ad2565b915081905092915050565b6000612e8782612d9c565b9150612e938284612ad2565b915081905092915050565b6000602082019050612eb36000830184612a46565b92915050565b6000602082019050612ece6000830184612a55565b92915050565b6000602082019050612ee96000830184612a64565b92915050565b600060c082019050612f046000830189612a64565b612f116020830188612a46565b612f1e6040830187612a46565b612f2b6060830186612e05565b612f386080830185612e05565b612f4560a0830184612e05565b979650505050505050565b600060a082019050612f656000830188612a64565b612f726020830187612a64565b612f7f6040830186612a64565b612f8c6060830185612e05565b612f996080830184612a46565b9695505050505050565b6000608082019050612fb86000830187612a64565b612fc56020830186612e14565b612fd26040830185612a64565b612fdf6060830184612a64565b95945050505050565b6000602082019050612ffd6000830184612a8a565b92915050565b6000602082019050818103600083015261301d8184612a99565b905092915050565b6000602082019050818103600083015261303e81612b03565b9050919050565b6000602082019050818103600083015261305e81612b26565b9050919050565b6000602082019050818103600083015261307e81612b49565b9050919050565b6000602082019050818103600083015261309e81612b6c565b9050919050565b600060208201905081810360008301526130be81612b8f565b9050919050565b600060208201905081810360008301526130de81612bb2565b9050919050565b600060208201905081810360008301526130fe81612bd5565b9050919050565b6000602082019050818103600083015261311e81612c1b565b9050919050565b6000602082019050818103600083015261313e81612c3e565b9050919050565b6000602082019050818103600083015261315e81612c61565b9050919050565b6000602082019050818103600083015261317e81612ca7565b9050919050565b6000602082019050818103600083015261319e81612cca565b9050919050565b600060208201905081810360008301526131be81612ced565b9050919050565b600060208201905081810360008301526131de81612d10565b9050919050565b600060208201905081810360008301526131fe81612d33565b9050919050565b6000602082019050818103600083015261321e81612d56565b9050919050565b6000602082019050818103600083015261323e81612d79565b9050919050565b6000602082019050818103600083015261325e81612dbf565b9050919050565b6000602082019050818103600083015261327e81612de2565b9050919050565b600060208201905061329a6000830184612e05565b92915050565b60006020820190506132b56000830184612e14565b92915050565b60006132c56132d6565b90506132d18282613556565b919050565b6000604051905090565b600067ffffffffffffffff8211156132fb576132fa61361e565b5b6133048261364d565b9050602081019050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b6000613343826134a7565b915061334e836134a7565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561338357613382613591565b5b828201905092915050565b6000613399826134a7565b91506133a4836134a7565b9250826133b4576133b36135c0565b5b828204905092915050565b60006133ca826134a7565b91506133d5836134a7565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561340e5761340d613591565b5b828202905092915050565b6000613424826134a7565b915061342f836134a7565b92508282101561344257613441613591565b5b828203905092915050565b600061345882613487565b9050919050565b60008115159050919050565b6000819050919050565b60006134808261344d565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60006134c9826134d0565b9050919050565b60006134db82613487565b9050919050565b82818337600083830152505050565b60005b8381101561350f5780820151818401526020810190506134f4565b8381111561351e576000848401525b50505050565b6000600282049050600182168061353c57607f821691505b602082108114156135505761354f6135ef565b5b50919050565b61355f8261364d565b810181811067ffffffffffffffff8211171561357e5761357d61361e565b5b80604052505050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b7f45434453413a20696e76616c6964207369676e61747572650000000000000000600082015250565b7f5452414e534645525f414d4f554e545f455843454544535f414c4c4f57414e4360008201527f4500000000000000000000000000000000000000000000000000000000000000602082015250565b7f45434453413a20696e76616c6964207369676e6174757265206c656e67746800600082015250565b7f5452414e534645525f46524f4d5f5448455f5a45524f5f414444524553530000600082015250565b7f4255524e5f46524f4d5f5448455f5a45524f5f41444452455353000000000000600082015250565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b7f415050524f56455f544f5f5a45524f5f41444452455353000000000000000000600082015250565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b7f45524332305065726d69743a206578706972656420646561646c696e65000000600082015250565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b7f4445435245415345445f414c4c4f57414e43455f42454c4f575f5a45524f0000600082015250565b7f74656e6465722000000000000000000000000000000000000000000000000000600082015250565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b7f45434453413a20696e76616c6964207369676e6174757265202776272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b7f5452414e534645525f544f5f5448455f5a45524f5f4144445245535300000000600082015250565b7f4255524e5f414d4f554e545f455843454544535f42414c414e43450000000000600082015250565b7f45524332305065726d69743a20696e76616c6964207369676e61747572650000600082015250565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b7f5452414e534645525f414d4f554e545f455843454544535f42414c414e434500600082015250565b7f7400000000000000000000000000000000000000000000000000000000000000600082015250565b7f415050524f56455f46524f4d5f5a45524f5f4144445245535300000000000000600082015250565b7f4d494e545f544f5f5448455f5a45524f5f414444524553530000000000000000600082015250565b613aab8161344d565b8114613ab657600080fd5b50565b613ac28161346b565b8114613acd57600080fd5b50565b613ad981613475565b8114613ae457600080fd5b50565b613af0816134a7565b8114613afb57600080fd5b50565b613b07816134b1565b8114613b1257600080fd5b5056fea26469706673582212208ddc692d830446bc45ea3672b6cc369fa704f8ffad723c656f87d6d80358d94664736f6c63430008040033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.