Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- Coins
- Optimization enabled
- true
- Compiler version
- v0.8.20+commit.a1b79de6
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2024-11-01T02:54:40.889947Z
Contract source code
// File: contracts/common/commonPulseWars.sol
pragma solidity 0.8.20;
/**
* @title NFTType
* @dev Enum representing different types of NFT categories
*/
enum NFTType {
PULSICANS,
MAXIS,
NATIVES,
FRENEMIES_VCs,
FOUNDERS_OF_THE_FUTURE,
POWER_ITEMS,
CITIZENS
}
/**
* @title NFTInfo
* @dev Struct to represent NFT information
*/
struct NFTInfo {
NFTType nftType;
address minter;
}
/**
* @title CitizenInfo
* @dev Struct to represent Citizen NFT information
*/
struct CitizenInfo {
address nftAddress;
uint256 nftID;
}
/**
* @title Badge
* @dev struct to represent badge information
*/
struct Badge {
string name;
uint maxClaimable;
uint totalClaimed;
}
enum TradeCoinType {
PULSECHAIN_COINS,
NON_PULSECHAIN_COINS,
BOTH
}
struct CoinInfo {
string symbol;
uint256 decimals;
uint256 priceInDai;
uint256 priceInDaiAtStart;
TradeCoinType coinType;
}
// File: contracts/interface/ICoins.sol
pragma solidity 0.8.20;
interface ICoins {
// Event emitted when a new coin is added
event CoinAdded(uint256 indexed id, string symbol, uint256 decimals, uint256 priceInDai, TradeCoinType tradeCoinType);
event CoinPriceUpdated(uint256 indexed tokenId, uint256 newPrice);
event DefaultSelectionRangeUpdated(uint256 total, uint256 pwCoins, uint256 npwCoins, uint256 defaultRandomNumber);
function addCoin(TradeCoinType _tradeCoinType,string calldata symbol, uint256 _decimals, uint256 _priceInDai) external returns (uint256);
//Get initial coin list
function getInitialCoinList(TradeCoinType _tradeCoinType, uint256 _rn) external view returns (uint[4] memory);
//default coin list
function getDefaultCoinList(TradeCoinType _tradeCoinType, uint _nftID) external view returns (uint[4] memory);
// Function to get information about a coin
function getCoin(uint256 id) external view returns (CoinInfo memory);
// Function to get all coin addresses
function getAllCoins(uint256 start, uint count) external view returns (CoinInfo[] memory);
// Function to get the total number of coins
function getTotalCoins() external view returns (uint256);
//swaps
/**
* @notice Calculate the amount of DAI tokens that can be obtained for a given amount of input tokens
* @param tokenId The ID of the input token
* @param tokenAmount The amount of the input token
* @return The amount of DAI tokens that can be obtained
*/
function getDaiOutputForToken(uint256 tokenId, uint256 tokenAmount) external view returns (uint256);
/**
* @notice Calculate the amount of input tokens required to obtain a specific amount of DAI tokens
* @param tokenId The ID of the input token
* @param daiAmount The desired amount of DAI tokens
* @return The amount of input tokens required
*/
function getTokenAmountForDaiOutput(uint256 tokenId, uint256 daiAmount) external view returns (uint256);
/**
* @notice Calculate the amount of output tokens that can be obtained for a given amount of DAI tokens
* @param tokenId The ID of the output token
* @param daiAmount The amount of DAI tokens to be exchanged
* @return The amount of output tokens that can be obtained
*/
function getTokenOutputForDai(uint256 tokenId, uint256 daiAmount) external view returns (uint256);
/**
* @notice Calculate the amount of output tokens that can be obtained for a given amount of DAI tokens based on the price at the begining price of token
* @param tokenId The ID of the output token
* @param daiAmount The amount of DAI tokens to be exchanged
* @return The amount of output tokens that can be obtained
*/
function getTokenOutputForDaiAtStart(uint256 tokenId, uint256 daiAmount) external view returns (uint256);
/**
* @notice Calculate the amount of DAI tokens required to obtain a specific amount of output tokens
* @param tokenId The ID of the output token
* @param tokenAmount The desired amount of output tokens
* @return The amount of DAI tokens required
*/
function getDaiAmountForTokenOutput(uint256 tokenId, uint256 tokenAmount) external view returns (uint256);
}
// File: @openzeppelin/contracts@4.9.0/utils/Context.sol
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
// File: @openzeppelin/contracts@4.9.0/access/Ownable.sol
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
/**
* @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 Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(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");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// File: @openzeppelin/contracts@4.9.0/access/Ownable2Step.sol
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module which provides 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} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
}
// File: contracts/utils/Authorizable.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
contract Authorizable is Ownable2Step {
mapping(address => bool) private authorized;
modifier onlyAuthorized() {
require(authorized[msg.sender] || owner() == msg.sender, "Not authorized");
_;
}
function isAuthorised(address _authAdd) public view returns(bool _isAuth){
_isAuth = (authorized[_authAdd] || owner() == _authAdd) ;
}
function addAuthorized(address _toAdd) onlyOwner public {
require(_toAdd != address(0));
authorized[_toAdd] = true;
}
function removeAuthorized(address _toRemove) onlyOwner public {
require(_toRemove != msg.sender);
authorized[_toRemove] = false;
}
}
// File: contracts/libraries/CoinUtils.sol
pragma solidity 0.8.20;
/// @title CoinUtils Library
/// @dev Provides utility functions for handling and selecting coins randomly.
library CoinUtils {
/// @notice Randomly selects 4 unique coins from a given category of coins.
/// @param _rn The random seed number to generate random indices.
/// @param categoryLength The number of coins available in the category.
/// @param coinCategory An array containing the coin IDs of the category.
/// @return An array containing the 4 randomly selected coin IDs.
/// @dev The function requires that the category length is at least 4.
function randomSelectionfromList(
uint _rn,
uint categoryLength,
uint[] memory coinCategory
) internal pure returns (uint[4] memory) {
require(categoryLength >= 4, "Not enough coins in the category");
uint[4] memory selectedCoins;
uint256 randBase = _rn;
for (uint256 i = 0; i < 4; i++) {
uint256 randomIndex = uint256(keccak256(abi.encodePacked(randBase, i))) % categoryLength;
selectedCoins[i] = coinCategory[randomIndex];
// Swap this element with the last unchosen element
coinCategory[randomIndex] = coinCategory[categoryLength - 1];
categoryLength--;
randBase += selectedCoins[i]; // Shuffle the randomness base
}
return selectedCoins;
}
/// @notice Randomly selects 4 unique coin IDs from a range of available coins.
/// @param _rn The random seed number to generate random indices.
/// @param len The total number of available coin IDs to select from.
/// @return An array containing the 4 randomly selected coin IDs.
/// @dev The function requires that the total number of available coins (`len`) is at least 4.
function getRandomSelectionFromAll(uint _rn, uint len) internal pure returns (uint[4] memory) {
uint[4] memory selectedCoins;
require(len >= 4, "Not enough coins available");
uint256 coinCount = 0;
uint256 randBase = _rn;
while (coinCount < 4) {
uint256 randomId = (uint256(keccak256(abi.encodePacked(randBase))) % len) + 1;
bool alreadySelected = false;
for (uint256 i = 0; i < coinCount; i++) {
if (selectedCoins[i] == randomId) {
alreadySelected = true;
break;
}
}
if (alreadySelected) {
randBase++;
continue;
}
selectedCoins[coinCount] = randomId;
coinCount++;
randBase++;
}
return selectedCoins;
}
}
// File: contracts/core/Coins.sol
pragma solidity 0.8.20;
/// @title Coins Contract
/// @dev Manages the in-game coins, their prices, and provides utilities for coin selection.
contract Coins is ICoins, Authorizable {
// ---- Structs -----
/// @dev Struct to define the range for default coin selection.
/// @param total The total number of coins to consider for default selection.
/// @param pwCoins The number of PulseChain coins to select for default selection.
/// @param npwCoins The number of Non-PulseChain coins to select for default selection.
struct DefaultSelectionRange {
uint total;
uint pwCoins;
uint npwCoins;
}
// ---- Variables ----
/// @dev Total number of coins added to the contract.
uint256 private totalCoins;
/// @dev Mapping of coin ID to CoinInfo struct.
mapping(uint256 => CoinInfo) public coins;
/// @dev Array of PulseChain coin IDs.
uint256[] public pulseChainCoinIds;
/// @dev Array of Non-PulseChain coin IDs.
uint256[] public nonPulseChainCoinIds;
/// @dev Random number used for default coin selection.
uint256 public defaultRandomNumber;
/// @dev Struct defining the range for default coin selection.
DefaultSelectionRange public defaultSelectionRange;
/// @dev CoinInfo for DAI stablecoin (always available).
CoinInfo public DAI_INFO =
CoinInfo({
symbol: "DAI",
decimals: 18,
priceInDai: 1 ether,
priceInDaiAtStart: 1 ether,
coinType: TradeCoinType.BOTH
});
// ---- Functions ----
/// @notice Adds a new coin to the contract.
/// @param _tradeCoinType The type of coin (PULSECHAIN_COINS or NON_PULSECHAIN_COINS).
/// @param symbol The symbol of the coin.
/// @param _decimals The number of decimals for the coin.
/// @param _priceInDai The initial price of the coin in DAI.
/// @return The ID of the newly added coin.
function addCoin(
TradeCoinType _tradeCoinType,
string calldata symbol,
uint256 _decimals,
uint256 _priceInDai
) external override onlyAuthorized returns (uint256) {
require(_tradeCoinType != TradeCoinType.BOTH, "Invalid Type");
totalCoins++;
coins[totalCoins] = CoinInfo({
symbol: symbol,
decimals: _decimals,
priceInDai: _priceInDai,
priceInDaiAtStart: 0,
coinType: _tradeCoinType
});
if (_tradeCoinType == TradeCoinType.PULSECHAIN_COINS) {
pulseChainCoinIds.push(totalCoins);
} else {
if (_tradeCoinType == TradeCoinType.NON_PULSECHAIN_COINS) {
nonPulseChainCoinIds.push(totalCoins);
}
}
emit CoinAdded(totalCoins, symbol, _decimals, _priceInDai, _tradeCoinType);
return totalCoins;
}
/// @notice Records the initial prices of specified coins in DAI.
/// @param coinsIndex An array of coin IDs for which to record prices.
/// @param coinsPrice An array of corresponding initial prices in DAI.
function recordInitPrice(uint[] memory coinsIndex, uint[] memory coinsPrice) public onlyAuthorized {
require(coinsIndex.length == coinsPrice.length, "Arrays must be of the same length");
require(coinsIndex.length <= totalCoins, "Array length exceeds total coins");
for (uint i = 0; i < coinsIndex.length; i++) {
require(coinsIndex[i] > 0 && coinsIndex[i] <= totalCoins, "Invalid coin index");
coins[coinsIndex[i]].priceInDaiAtStart = coinsPrice[i];
}
}
/// @notice Updates the prices of specified coins in DAI.
/// @param tokenIds An array of coin IDs for which to update prices.
/// @param newPrices An array of corresponding new prices in DAI.
function updatePrices(uint256[] memory tokenIds, uint256[] memory newPrices) external onlyAuthorized {
require(tokenIds.length == newPrices.length, "Arrays must be of the same length");
for (uint256 i = 0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
uint256 newPrice = newPrices[i];
require(tokenId > 0 && tokenId <= totalCoins, "Invalid token ID");
coins[tokenId].priceInDai = newPrice;
emit CoinPriceUpdated(tokenId, newPrice);
}
}
/// @notice Sets the range for default coin selection.
/// @param _total The total number of coins to consider for default selection.
/// @param _pwLength The number of PulseChain coins to select for default selection.
/// @param _npwLength The number of Non-PulseChain coins to select for default selection.
/// @param _defaultRN A random number used as a base for default coin selection.
function setDefaultSelectionRange(
uint _total,
uint _pwLength,
uint _npwLength,
uint _defaultRN
) public onlyAuthorized {
require(_total <= totalCoins, "Invalid Total");
require(_pwLength <= pulseChainCoinIds.length, "Invalid PW length");
require(_npwLength <= nonPulseChainCoinIds.length, "Invalid CZ Length");
defaultSelectionRange = DefaultSelectionRange({ total: _total, pwCoins: _pwLength, npwCoins: _npwLength });
defaultRandomNumber = _defaultRN;
emit DefaultSelectionRangeUpdated(_total, _pwLength, _npwLength, _defaultRN);
}
/// @notice Gets a list of initial coins based on the specified coin type and random number.
/// @dev Used for initial coin allocation in the game.
/// @param _tradeCoinType The type of coins to select (PULSECHAIN_COINS, NON_PULSECHAIN_COINS, or BOTH).
/// @param _rn A random number used for selection.
/// @return An array of 4 coin IDs selected randomly.
function getInitialCoinList(
TradeCoinType _tradeCoinType,
uint256 _rn
) external view override returns (uint[4] memory) {
uint256[4] memory selectedCoins;
uint256[] storage coinCategory;
uint256 categoryLength;
if (_tradeCoinType == TradeCoinType.PULSECHAIN_COINS) {
coinCategory = pulseChainCoinIds;
categoryLength = pulseChainCoinIds.length;
selectedCoins = CoinUtils.randomSelectionfromList(_rn, categoryLength, coinCategory);
} else if (_tradeCoinType == TradeCoinType.NON_PULSECHAIN_COINS) {
coinCategory = nonPulseChainCoinIds;
categoryLength = nonPulseChainCoinIds.length;
selectedCoins = CoinUtils.randomSelectionfromList(_rn, categoryLength, coinCategory);
} else {
selectedCoins = CoinUtils.getRandomSelectionFromAll(_rn, totalCoins);
}
return selectedCoins;
}
/// @notice Gets a list of default coins based on the specified coin type and NFT ID.
/// @dev Used for providing a default portfolio when a user doesn't choose their own coins.
/// @param _tradeCoinType The type of coins to select (PULSECHAIN_COINS, NON_PULSECHAIN_COINS, or BOTH).
/// @param _nftID The ID of the NFT for which to select default coins.
/// @return An array of 4 coin IDs selected based on the default range and NFT ID.
function getDefaultCoinList(
TradeCoinType _tradeCoinType,
uint _nftID
) external view override returns (uint[4] memory) {
uint256[4] memory selectedCoins;
uint256[] storage coinCategory;
uint256 categoryLength;
if (_tradeCoinType == TradeCoinType.PULSECHAIN_COINS) {
coinCategory = pulseChainCoinIds;
categoryLength = defaultSelectionRange.pwCoins;
selectedCoins = CoinUtils.randomSelectionfromList(
defaultRandomNumber + _nftID,
categoryLength,
coinCategory
);
} else if (_tradeCoinType == TradeCoinType.NON_PULSECHAIN_COINS) {
coinCategory = nonPulseChainCoinIds;
categoryLength = defaultSelectionRange.npwCoins;
selectedCoins = CoinUtils.randomSelectionfromList(
defaultRandomNumber + _nftID,
categoryLength,
coinCategory
);
} else {
selectedCoins = CoinUtils.getRandomSelectionFromAll(
defaultRandomNumber + _nftID,
defaultSelectionRange.total
);
}
return selectedCoins;
}
/// @notice Gets information about a specific coin.
/// @param id The ID of the coin.
/// @return The CoinInfo struct for the specified coin ID.
function getCoin(uint256 id) external view override returns (CoinInfo memory) {
require(id > 0 && id <= totalCoins, "Coin ID out of range");
return coins[id];
}
/// @notice Gets information about a range of coins.
/// @param start The starting index of the range (inclusive).
/// @param count The number of coins to retrieve.
/// @return An array of CoinInfo structs for the specified range of coins.
function getAllCoins(uint256 start, uint count) external view override returns (CoinInfo[] memory) {
require(start >= 1 && start + count - 1 <= totalCoins, "Invalid range");
CoinInfo[] memory allCoins = new CoinInfo[](count);
for (uint256 i = 0; i < count; i++) {
allCoins[i] = coins[start + i];
}
return allCoins;
}
/// @notice Gets information about a range of PulseChain coins.
/// @param start The starting index of the range (inclusive).
/// @param count The number of coins to retrieve.
/// @return An array of CoinInfo structs for the specified range of PulseChain coins.
function getPulseChainCoins(uint256 start, uint256 count) external view returns (CoinInfo[] memory) {
uint256 length = pulseChainCoinIds.length;
require(start < length && start + count <= length, "Invalid range");
CoinInfo[] memory pulseChainCoins = new CoinInfo[](count);
for (uint256 i = 0; i < count; i++) {
pulseChainCoins[i] = coins[pulseChainCoinIds[start + i]];
}
return pulseChainCoins;
}
/// @notice Gets information about a range of Non-PulseChain coins.
/// @param start The starting index of the range (inclusive).
/// @param count The number of coins to retrieve.
/// @return An array of CoinInfo structs for the specified range of Non-PulseChain coins.
function getNonPulseChainCoins(uint256 start, uint256 count) external view returns (CoinInfo[] memory) {
uint256 length = nonPulseChainCoinIds.length;
require(start < length && start + count <= length, "Invalid range");
CoinInfo[] memory nonPulseChainCoins = new CoinInfo[](count);
for (uint256 i = 0; i < count; i++) {
nonPulseChainCoins[i] = coins[nonPulseChainCoinIds[start + i]];
}
return nonPulseChainCoins;
}
/// @notice Gets an array of PulseChain coin IDs within a specific range.
/// @param start The starting index of the range (inclusive).
/// @param count The number of coin IDs to retrieve.
/// @return An array of PulseChain coin IDs.
function getPulseChainCoinIds(uint256 start, uint256 count) external view returns (uint256[] memory) {
uint256 length = pulseChainCoinIds.length;
require(start < length && start + count <= length, "Invalid range");
uint256[] memory selectedIds = new uint256[](count);
for (uint256 i = 0; i < count; i++) {
selectedIds[i] = pulseChainCoinIds[start + i];
}
return selectedIds;
}
/// @notice Gets an array of Non-PulseChain coin IDs within a specific range.
/// @param start The starting index of the range (inclusive).
/// @param count The number of coin IDs to retrieve.
/// @return An array of Non-PulseChain coin IDs.
function getNonPulseChainCoinIds(uint256 start, uint256 count) external view returns (uint256[] memory) {
uint256 length = nonPulseChainCoinIds.length;
require(start < length && start + count <= length, "Invalid range");
uint256[] memory selectedIds = new uint256[](count);
for (uint256 i = 0; i < count; i++) {
selectedIds[i] = nonPulseChainCoinIds[start + i];
}
return selectedIds;
}
/// @notice Gets the total number of coins added to the contract.
/// @return The total number of coins.
function getTotalCoins() external view override returns (uint256) {
return totalCoins;
}
/// @notice Gets the total number of PulseChain coins added to the contract.
/// @return The total number of PulseChain coins.
function getTotalPulseChainCoins() external view returns (uint256) {
return pulseChainCoinIds.length;
}
/// @notice Gets the total number of Non-PulseChain coins added to the contract.
/// @return The total number of Non-PulseChain coins.
function getTotalNonPulseChainCoins() external view returns (uint256) {
return nonPulseChainCoinIds.length;
}
function getDaiOutputForToken(uint256 tokenId, uint256 tokenAmount) external view override returns (uint256) {
require(tokenId > 0 && tokenId <= totalCoins, "Invalid token ID");
CoinInfo memory token = coins[tokenId];
// Normalize token amount to DAI's decimals
uint256 normalizedTokenAmount = tokenAmount * (10 ** (18 - token.decimals));
uint256 daiAmount = (normalizedTokenAmount * token.priceInDai) / (10 ** 18);
return daiAmount;
}
function getTokenAmountForDaiOutput(uint256 tokenId, uint256 daiAmount) external view override returns (uint256) {
require(tokenId > 0 && tokenId <= totalCoins, "Invalid token ID");
CoinInfo memory token = coins[tokenId];
// Normalize DAI amount to the token's decimals
uint256 normalizedDaiAmount = daiAmount * (10 ** token.decimals);
uint256 tokenAmount = normalizedDaiAmount / token.priceInDai;
return tokenAmount;
}
function getTokenOutputForDai(uint256 tokenId, uint256 daiAmount) external view override returns (uint256) {
require(tokenId > 0 && tokenId <= totalCoins, "Invalid token ID");
CoinInfo memory token = coins[tokenId];
// Normalize DAI amount to the token's decimals
uint256 normalizedDaiAmount = daiAmount * (10 ** token.decimals);
uint256 tokenAmount = normalizedDaiAmount / token.priceInDai;
return tokenAmount;
}
/// @notice Calculates the amount of a specific coin that could have been bought with a given amount of DAI at the initial price.
/// @param tokenId The ID of the coin.
/// @param daiAmount The amount of DAI to spend.
/// @return The amount of the specified coin that could have been bought with the DAI at the initial price.
function getTokenOutputForDaiAtStart(uint256 tokenId, uint256 daiAmount) external view override returns (uint256) {
require(tokenId > 0 && tokenId <= totalCoins, "Invalid token ID");
CoinInfo memory token = coins[tokenId];
// Normalize DAI amount to the token's decimals
uint256 normalizedDaiAmount = daiAmount * (10 ** token.decimals);
uint256 tokenAmount = normalizedDaiAmount / token.priceInDaiAtStart;
return tokenAmount;
}
function getDaiAmountForTokenOutput(uint256 tokenId, uint256 tokenAmount) external view override returns (uint256) {
require(tokenId > 0 && tokenId <= totalCoins, "Invalid token ID");
CoinInfo memory token = coins[tokenId];
// Normalize token amount to DAI's decimals
uint256 normalizedTokenAmount = tokenAmount * (10 ** (18 - token.decimals));
uint256 daiAmount = (normalizedTokenAmount * token.priceInDai) / (10 ** 18);
return daiAmount;
}
}
Contract ABI
[{"type":"event","name":"CoinAdded","inputs":[{"type":"uint256","name":"id","internalType":"uint256","indexed":true},{"type":"string","name":"symbol","internalType":"string","indexed":false},{"type":"uint256","name":"decimals","internalType":"uint256","indexed":false},{"type":"uint256","name":"priceInDai","internalType":"uint256","indexed":false},{"type":"uint8","name":"tradeCoinType","internalType":"enum TradeCoinType","indexed":false}],"anonymous":false},{"type":"event","name":"CoinPriceUpdated","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"uint256","name":"newPrice","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DefaultSelectionRangeUpdated","inputs":[{"type":"uint256","name":"total","internalType":"uint256","indexed":false},{"type":"uint256","name":"pwCoins","internalType":"uint256","indexed":false},{"type":"uint256","name":"npwCoins","internalType":"uint256","indexed":false},{"type":"uint256","name":"defaultRandomNumber","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferStarted","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"priceInDai","internalType":"uint256"},{"type":"uint256","name":"priceInDaiAtStart","internalType":"uint256"},{"type":"uint8","name":"coinType","internalType":"enum TradeCoinType"}],"name":"DAI_INFO","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addAuthorized","inputs":[{"type":"address","name":"_toAdd","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"addCoin","inputs":[{"type":"uint8","name":"_tradeCoinType","internalType":"enum TradeCoinType"},{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"_decimals","internalType":"uint256"},{"type":"uint256","name":"_priceInDai","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"priceInDai","internalType":"uint256"},{"type":"uint256","name":"priceInDaiAtStart","internalType":"uint256"},{"type":"uint8","name":"coinType","internalType":"enum TradeCoinType"}],"name":"coins","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"defaultRandomNumber","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"total","internalType":"uint256"},{"type":"uint256","name":"pwCoins","internalType":"uint256"},{"type":"uint256","name":"npwCoins","internalType":"uint256"}],"name":"defaultSelectionRange","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct CoinInfo[]","components":[{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"priceInDai","internalType":"uint256"},{"type":"uint256","name":"priceInDaiAtStart","internalType":"uint256"},{"type":"uint8","name":"coinType","internalType":"enum TradeCoinType"}]}],"name":"getAllCoins","inputs":[{"type":"uint256","name":"start","internalType":"uint256"},{"type":"uint256","name":"count","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct CoinInfo","components":[{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"priceInDai","internalType":"uint256"},{"type":"uint256","name":"priceInDaiAtStart","internalType":"uint256"},{"type":"uint8","name":"coinType","internalType":"enum TradeCoinType"}]}],"name":"getCoin","inputs":[{"type":"uint256","name":"id","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getDaiAmountForTokenOutput","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"tokenAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getDaiOutputForToken","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"tokenAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[4]","name":"","internalType":"uint256[4]"}],"name":"getDefaultCoinList","inputs":[{"type":"uint8","name":"_tradeCoinType","internalType":"enum TradeCoinType"},{"type":"uint256","name":"_nftID","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[4]","name":"","internalType":"uint256[4]"}],"name":"getInitialCoinList","inputs":[{"type":"uint8","name":"_tradeCoinType","internalType":"enum TradeCoinType"},{"type":"uint256","name":"_rn","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getNonPulseChainCoinIds","inputs":[{"type":"uint256","name":"start","internalType":"uint256"},{"type":"uint256","name":"count","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct CoinInfo[]","components":[{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"priceInDai","internalType":"uint256"},{"type":"uint256","name":"priceInDaiAtStart","internalType":"uint256"},{"type":"uint8","name":"coinType","internalType":"enum TradeCoinType"}]}],"name":"getNonPulseChainCoins","inputs":[{"type":"uint256","name":"start","internalType":"uint256"},{"type":"uint256","name":"count","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getPulseChainCoinIds","inputs":[{"type":"uint256","name":"start","internalType":"uint256"},{"type":"uint256","name":"count","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct CoinInfo[]","components":[{"type":"string","name":"symbol","internalType":"string"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"priceInDai","internalType":"uint256"},{"type":"uint256","name":"priceInDaiAtStart","internalType":"uint256"},{"type":"uint8","name":"coinType","internalType":"enum TradeCoinType"}]}],"name":"getPulseChainCoins","inputs":[{"type":"uint256","name":"start","internalType":"uint256"},{"type":"uint256","name":"count","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTokenAmountForDaiOutput","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"daiAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTokenOutputForDai","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"daiAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTokenOutputForDaiAtStart","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"daiAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTotalCoins","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTotalNonPulseChainCoins","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTotalPulseChainCoins","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"_isAuth","internalType":"bool"}],"name":"isAuthorised","inputs":[{"type":"address","name":"_authAdd","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nonPulseChainCoinIds","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"pendingOwner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pulseChainCoinIds","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"recordInitPrice","inputs":[{"type":"uint256[]","name":"coinsIndex","internalType":"uint256[]"},{"type":"uint256[]","name":"coinsPrice","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeAuthorized","inputs":[{"type":"address","name":"_toRemove","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDefaultSelectionRange","inputs":[{"type":"uint256","name":"_total","internalType":"uint256"},{"type":"uint256","name":"_pwLength","internalType":"uint256"},{"type":"uint256","name":"_npwLength","internalType":"uint256"},{"type":"uint256","name":"_defaultRN","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updatePrices","inputs":[{"type":"uint256[]","name":"tokenIds","internalType":"uint256[]"},{"type":"uint256[]","name":"newPrices","internalType":"uint256[]"}]}]
Contract Creation Code
0x61016060405260036101209081526244414960e81b610140526080818152601260a052670de0b6b3a764000060c081905260e05260026101005290600b9081906200004b9082620001dc565b506020820151816001015560408201518160020155606082015181600301556080820151816004015f6101000a81548160ff0219169083600281111562000096576200009662000128565b02179055505050348015620000a9575f80fd5b50620000b533620000bb565b620002a4565b600180546001600160a01b0319169055620000d681620000d9565b50565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b634e487b7160e01b5f52602160045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b600181811c908216806200016557607f821691505b6020821081036200018457634e487b7160e01b5f52602260045260245ffd5b50919050565b601f821115620001d7575f81815260208120601f850160051c81016020861015620001b25750805b601f850160051c820191505b81811015620001d357828155600101620001be565b5050505b505050565b81516001600160401b03811115620001f857620001f86200013c565b620002108162000209845462000150565b846200018a565b602080601f83116001811462000246575f84156200022e5750858301515b5f19600386901b1c1916600185901b178555620001d3565b5f85815260208120601f198616915b82811015620002765788860151825594840194600190910190840162000255565b50858210156200029457878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b6129ab80620002b25f395ff3fe608060405234801561000f575f80fd5b50600436106101fd575f3560e01c8063832aed2611610114578063cc3facc4116100a9578063da31158811610079578063da3115881461044d578063defd8e071461046d578063e30c397814610480578063f2fde38b14610491578063f499d99d146104a4575f80fd5b8063cc3facc41461041f578063cf1c316a14610432578063cf5e62d1146103c2578063d86b900514610445575f80fd5b8063ae8cac29116100e4578063ae8cac2914610265578063b7695d35146103d5578063bf1ede32146103e8578063c6610657146103fb575f80fd5b8063832aed26146103825780638da5cb5b14610395578063a773e0c9146103b9578063a9a01f85146103c2575f80fd5b806351b699cd1161019557806367f9fc3c1161016557806367f9fc3c1461031f578063689eb23214610332578063715018a61461035257806379ba50971461035a5780637db58e0f14610362575f80fd5b806351b699cd146102b4578063552180f2146102d7578063560f5441146103045780635c3684881461030c575f80fd5b80631f6e889a116101d05780631f6e889a14610265578063289fc9d2146102865780633887c27c1461028e578063485d7d94146102a1575f80fd5b80630331b529146102015780630795eca01461022a5780631be21ad91461023f5780631c138e2314610252575b5f80fd5b61021461020f366004612148565b6104ac565b6040516102219190612225565b60405180910390f35b61023d610238366004612285565b6106aa565b005b61023d61024d366004612360565b610841565b610214610260366004612148565b6109f8565b610278610273366004612148565b610bdb565b604051908152602001610221565b600354610278565b61023d61029c366004612360565b610d59565b61023d6102af3660046123c0565b610ea1565b6102c76102c23660046123c0565b610edd565b6040519015158152602001610221565b600854600954600a546102e992919083565b60408051938452602084019290925290820152606001610221565b600654610278565b61027861031a366004612148565b610f29565b61021461032d366004612148565b61107f565b610345610340366004612400565b611269565b6040516102219190612428565b61023d611382565b61023d611395565b610375610370366004612148565b61140f565b6040516102219190612458565b610375610390366004612148565b6114ed565b5f546001600160a01b03165b6040516001600160a01b039091168152602001610221565b61027860075481565b6102786103d0366004612148565b6115cb565b6102786103e336600461249b565b611721565b6102786103f63660046124b2565b611740565b61040e61040936600461249b565b6119c5565b60405161022195949392919061253c565b61034561042d366004612400565b611a7c565b61023d6104403660046123c0565b611b60565b61040e611b9d565b61046061045b36600461249b565b611bac565b604051610221919061256f565b61027861047b36600461249b565b611d05565b6001546001600160a01b03166103a1565b61023d61049f3660046123c0565b611d14565b600554610278565b60065460609080841080156104ca5750806104c78486612595565b11155b6104ef5760405162461bcd60e51b81526004016104e6906125a8565b60405180910390fd5b5f8367ffffffffffffffff811115610509576105096122b4565b60405190808252806020026020018201604052801561054257816020015b61052f6120ef565b8152602001906001900390816105275790505b5090505f5b8481101561069f5760045f600661055e848a612595565b8154811061056e5761056e6125cf565b905f5260205f20015481526020019081526020015f206040518060a00160405290815f8201805461059e906125e3565b80601f01602080910402602001604051908101604052809291908181526020018280546105ca906125e3565b80156106155780601f106105ec57610100808354040283529160200191610615565b820191905f5260205f20905b8154815290600101906020018083116105f857829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff169081111561065a5761065a6121ab565b600281111561066b5761066b6121ab565b81525050828281518110610681576106816125cf565b602002602001018190525080806106979061261b565b915050610547565b509150505b92915050565b335f9081526002602052604090205460ff16806106df5750336106d45f546001600160a01b031690565b6001600160a01b0316145b6106fb5760405162461bcd60e51b81526004016104e690612633565b60035484111561073d5760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908151bdd185b609a1b60448201526064016104e6565b6005548311156107835760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c840a0ae40d8cadccee8d607b1b60448201526064016104e6565b6006548211156107c95760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c84086b44098cadccee8d607b1b60448201526064016104e6565b6040805160608082018352868252602080830187905291830185905260088790556009869055600a85905560078490558251878152918201869052818301859052810183905290517ffcc94614435c643ae847e0a8e20e2e9e2fb8d9dea40a715cfc429b6a305d0a509181900360800190a150505050565b335f9081526002602052604090205460ff168061087657503361086b5f546001600160a01b031690565b6001600160a01b0316145b6108925760405162461bcd60e51b81526004016104e690612633565b80518251146108b35760405162461bcd60e51b81526004016104e69061265b565b600354825111156109065760405162461bcd60e51b815260206004820181905260248201527f4172726179206c656e677468206578636565647320746f74616c20636f696e7360448201526064016104e6565b5f5b82518110156109f3575f838281518110610924576109246125cf565b60200260200101511180156109545750600354838281518110610949576109496125cf565b602002602001015111155b6109955760405162461bcd60e51b8152602060048201526012602482015271092dcecc2d8d2c840c6ded2dc40d2dcc8caf60731b60448201526064016104e6565b8181815181106109a7576109a76125cf565b602002602001015160045f8584815181106109c4576109c46125cf565b602002602001015181526020019081526020015f206003018190555080806109eb9061261b565b915050610908565b505050565b606060018310158015610a2257506003546001610a158486612595565b610a1f919061269c565b11155b610a3e5760405162461bcd60e51b81526004016104e6906125a8565b5f8267ffffffffffffffff811115610a5857610a586122b4565b604051908082528060200260200182016040528015610a9157816020015b610a7e6120ef565b815260200190600190039081610a765790505b5090505f5b83811015610bd35760045f610aab8388612595565b81526020019081526020015f206040518060a00160405290815f82018054610ad2906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054610afe906125e3565b8015610b495780601f10610b2057610100808354040283529160200191610b49565b820191905f5260205f20905b815481529060010190602001808311610b2c57829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115610b8e57610b8e6121ab565b6002811115610b9f57610b9f6121ab565b81525050828281518110610bb557610bb56125cf565b60200260200101819052508080610bcb9061261b565b915050610a96565b509392505050565b5f8083118015610bed57506003548311155b610c095760405162461bcd60e51b81526004016104e6906126af565b5f83815260046020526040808220815160a08101909252805482908290610c2f906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054610c5b906125e3565b8015610ca65780601f10610c7d57610100808354040283529160200191610ca6565b820191905f5260205f20905b815481529060010190602001808311610c8957829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115610ceb57610ceb6121ab565b6002811115610cfc57610cfc6121ab565b8152505090505f81602001516012610d14919061269c565b610d1f90600a6127b9565b610d2990856127c4565b90505f670de0b6b3a7640000836040015183610d4591906127c4565b610d4f91906127ef565b9695505050505050565b335f9081526002602052604090205460ff1680610d8e575033610d835f546001600160a01b031690565b6001600160a01b0316145b610daa5760405162461bcd60e51b81526004016104e690612633565b8051825114610dcb5760405162461bcd60e51b81526004016104e69061265b565b5f5b82518110156109f3575f838281518110610de957610de96125cf565b602002602001015190505f838381518110610e0657610e066125cf565b602002602001015190505f82118015610e2157506003548211155b610e3d5760405162461bcd60e51b81526004016104e6906126af565b5f82815260046020526040908190206002018290555182907f69bedddd1c17558723d2c1fef779d4861749d024df6d986964feee81ecb8ebdd90610e849084815260200190565b60405180910390a250508080610e999061261b565b915050610dcd565b610ea9611d84565b336001600160a01b03821603610ebd575f80fd5b6001600160a01b03165f908152600260205260409020805460ff19169055565b6001600160a01b0381165f9081526002602052604081205460ff16806106a45750816001600160a01b0316610f195f546001600160a01b031690565b6001600160a01b03161492915050565b5f8083118015610f3b57506003548311155b610f575760405162461bcd60e51b81526004016104e6906126af565b5f83815260046020526040808220815160a08101909252805482908290610f7d906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054610fa9906125e3565b8015610ff45780601f10610fcb57610100808354040283529160200191610ff4565b820191905f5260205f20905b815481529060010190602001808311610fd757829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115611039576110396121ab565b600281111561104a5761104a6121ab565b8152505090505f8160200151600a61106291906127b9565b61106c90856127c4565b90505f826060015182610d4f91906127ef565b600554606090808410801561109d57508061109a8486612595565b11155b6110b95760405162461bcd60e51b81526004016104e6906125a8565b5f8367ffffffffffffffff8111156110d3576110d36122b4565b60405190808252806020026020018201604052801561110c57816020015b6110f96120ef565b8152602001906001900390816110f15790505b5090505f5b8481101561069f5760045f6005611128848a612595565b81548110611138576111386125cf565b905f5260205f20015481526020019081526020015f206040518060a00160405290815f82018054611168906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054611194906125e3565b80156111df5780601f106111b6576101008083540402835291602001916111df565b820191905f5260205f20905b8154815290600101906020018083116111c257829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115611224576112246121ab565b6002811115611235576112356121ab565b8152505082828151811061124b5761124b6125cf565b602002602001018190525080806112619061261b565b915050611111565b61127161212a565b61127961212a565b5f808086600281111561128e5761128e6121ab565b036112f657505060058054604080516020808402820181019092528281526112ef9187918491869083908301828280156112e557602002820191905f5260205f20905b8154815260200190600101908083116112d1575b5050505050611ddd565b9250611378565b600186600281111561130a5761130a6121ab565b0361136957505060068054604080516020808402820181019092528281526112ef9187918491869083908301828280156112e557602002820191905f5260205f20908154815260200190600101908083116112d1575050505050611ddd565b61137585600354611f4d565b92505b5090949350505050565b61138a611d84565b6113935f61208c565b565b60015433906001600160a01b031681146114035760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016104e6565b61140c8161208c565b50565b600654606090808410801561142d57508061142a8486612595565b11155b6114495760405162461bcd60e51b81526004016104e6906125a8565b5f8367ffffffffffffffff811115611463576114636122b4565b60405190808252806020026020018201604052801561148c578160200160208202803683370190505b5090505f5b8481101561069f5760066114a58288612595565b815481106114b5576114b56125cf565b905f5260205f2001548282815181106114d0576114d06125cf565b6020908102919091010152806114e58161261b565b915050611491565b600554606090808410801561150b5750806115088486612595565b11155b6115275760405162461bcd60e51b81526004016104e6906125a8565b5f8367ffffffffffffffff811115611541576115416122b4565b60405190808252806020026020018201604052801561156a578160200160208202803683370190505b5090505f5b8481101561069f5760056115838288612595565b81548110611593576115936125cf565b905f5260205f2001548282815181106115ae576115ae6125cf565b6020908102919091010152806115c38161261b565b91505061156f565b5f80831180156115dd57506003548311155b6115f95760405162461bcd60e51b81526004016104e6906126af565b5f83815260046020526040808220815160a0810190925280548290829061161f906125e3565b80601f016020809104026020016040519081016040528092919081815260200182805461164b906125e3565b80156116965780601f1061166d57610100808354040283529160200191611696565b820191905f5260205f20905b81548152906001019060200180831161167957829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff16908111156116db576116db6121ab565b60028111156116ec576116ec6121ab565b8152505090505f8160200151600a61170491906127b9565b61170e90856127c4565b90505f826040015182610d4f91906127ef565b60058181548110611730575f80fd5b5f91825260209091200154905081565b335f9081526002602052604081205460ff168061177557503361176a5f546001600160a01b031690565b6001600160a01b0316145b6117915760405162461bcd60e51b81526004016104e690612633565b60028660028111156117a5576117a56121ab565b036117e15760405162461bcd60e51b815260206004820152600c60248201526b496e76616c6964205479706560a01b60448201526064016104e6565b60038054905f6117f08361261b565b91905055506040518060a0016040528086868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052509385525050506020820186905260408201859052606082015260800187600281111561185f5761185f6121ab565b90526003545f9081526004602052604090208151819061187f908261284f565b506020820151816001015560408201518160020155606082015181600301556080820151816004015f6101000a81548160ff021916908360028111156118c7576118c76121ab565b02179055505f91506118d69050565b8660028111156118e8576118e86121ab565b0361192757600354600580546001810182555f919091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00155611976565b600186600281111561193b5761193b6121ab565b0361197657600354600680546001810182555f919091527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01555b6003547ff55a319d41f7f8bc2b2c2694b498de9f983c7b6906ef28f8277275cc1c024f06868686868b6040516119b095949392919061290b565b60405180910390a25060035495945050505050565b60046020525f90815260409020805481906119df906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054611a0b906125e3565b8015611a565780601f10611a2d57610100808354040283529160200191611a56565b820191905f5260205f20905b815481529060010190602001808311611a3957829003601f168201915b505050506001830154600284015460038501546004909501549394919390925060ff1685565b611a8461212a565b611a8c61212a565b5f8080866002811115611aa157611aa16121ab565b03611b13575050600954600754600591906112ef90611ac1908790612595565b82848054806020026020016040519081016040528092919081815260200182805480156112e557602002820191905f5260205f20908154815260200190600101908083116112d1575050505050611ddd565b6001866002811115611b2757611b276121ab565b03611b47575050600a54600754600691906112ef90611ac1908790612595565b61137585600754611b589190612595565b600854611f4d565b611b68611d84565b6001600160a01b038116611b7a575f80fd5b6001600160a01b03165f908152600260205260409020805460ff19166001179055565b600b805481906119df906125e3565b611bb46120ef565b5f82118015611bc557506003548211155b611c085760405162461bcd60e51b8152602060048201526014602482015273436f696e204944206f7574206f662072616e676560601b60448201526064016104e6565b5f8281526004602052604090819020815160a08101909252805482908290611c2f906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054611c5b906125e3565b8015611ca65780601f10611c7d57610100808354040283529160200191611ca6565b820191905f5260205f20905b815481529060010190602001808311611c8957829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115611ceb57611ceb6121ab565b6002811115611cfc57611cfc6121ab565b90525092915050565b60068181548110611730575f80fd5b611d1c611d84565b600180546001600160a01b0383166001600160a01b03199091168117909155611d4c5f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f546001600160a01b031633146113935760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104e6565b611de561212a565b6004831015611e365760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f75676820636f696e7320696e207468652063617465676f727960448201526064016104e6565b611e3e61212a565b845f5b6004811015611f42575f868383604051602001611e68929190918252602082015260400190565b604051602081830303815290604052805190602001205f1c611e8a919061294d565b9050858181518110611e9e57611e9e6125cf565b6020026020010151848360048110611eb857611eb86125cf565b602002015285611ec960018961269c565b81518110611ed957611ed96125cf565b6020026020010151868281518110611ef357611ef36125cf565b602090810291909101015286611f0881612960565b975050838260048110611f1d57611f1d6125cf565b6020020151611f2c9084612595565b9250508080611f3a9061261b565b915050611e41565b509095945050505050565b611f5561212a565b611f5d61212a565b6004831015611fae5760405162461bcd60e51b815260206004820152601a60248201527f4e6f7420656e6f75676820636f696e7320617661696c61626c6500000000000060448201526064016104e6565b5f845b6004821015611378575f8582604051602001611fcf91815260200190565b604051602081830303815290604052805190602001205f1c611ff1919061294d565b611ffc906001612595565b90505f805b84811015612041578286826004811061201c5761201c6125cf565b60200201510361202f5760019150612041565b806120398161261b565b915050612001565b50801561205c57826120528161261b565b9350505050611fb1565b8185856004811061206f5761206f6125cf565b60200201528361207e8161261b565b94505082806120529061261b565b600180546001600160a01b031916905561140c815f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040518060a00160405280606081526020015f81526020015f81526020015f81526020015f6002811115612125576121256121ab565b905290565b60405180608001604052806004906020820280368337509192915050565b5f8060408385031215612159575f80fd5b50508035926020909101359150565b5f81518084525f5b8181101561218c57602081850181015186830182015201612170565b505f602082860101526020601f19601f83011685010191505092915050565b634e487b7160e01b5f52602160045260245ffd5b600381106121db57634e487b7160e01b5f52602160045260245ffd5b9052565b5f815160a084526121f360a0850182612168565b90506020830151602085015260408301516040850152606083015160608501526080830151610bd360808601826121bf565b5f602080830181845280855180835260408601915060408160051b87010192508387015f5b8281101561227857603f198886030184526122668583516121df565b9450928501929085019060010161224a565b5092979650505050505050565b5f805f8060808587031215612298575f80fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126122d7575f80fd5b8135602067ffffffffffffffff808311156122f4576122f46122b4565b8260051b604051601f19603f83011681018181108482111715612319576123196122b4565b604052938452858101830193838101925087851115612336575f80fd5b83870191505b848210156123555781358352918301919083019061233c565b979650505050505050565b5f8060408385031215612371575f80fd5b823567ffffffffffffffff80821115612388575f80fd5b612394868387016122c8565b935060208501359150808211156123a9575f80fd5b506123b6858286016122c8565b9150509250929050565b5f602082840312156123d0575f80fd5b81356001600160a01b03811681146123e6575f80fd5b9392505050565b8035600381106123fb575f80fd5b919050565b5f8060408385031215612411575f80fd5b61241a836123ed565b946020939093013593505050565b6080810181835f5b600481101561244f578151835260209283019290910190600101612430565b50505092915050565b602080825282518282018190525f9190848201906040850190845b8181101561248f57835183529284019291840191600101612473565b50909695505050505050565b5f602082840312156124ab575f80fd5b5035919050565b5f805f805f608086880312156124c6575f80fd5b6124cf866123ed565b9450602086013567ffffffffffffffff808211156124eb575f80fd5b818801915088601f8301126124fe575f80fd5b81358181111561250c575f80fd5b89602082850101111561251d575f80fd5b9699602092909201985095966040810135965060600135945092505050565b60a081525f61254e60a0830188612168565b9050856020830152846040830152836060830152610d4f60808301846121bf565b602081525f6123e660208301846121df565b634e487b7160e01b5f52601160045260245ffd5b808201808211156106a4576106a4612581565b6020808252600d908201526c496e76616c69642072616e676560981b604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b600181811c908216806125f757607f821691505b60208210810361261557634e487b7160e01b5f52602260045260245ffd5b50919050565b5f6001820161262c5761262c612581565b5060010190565b6020808252600e908201526d139bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b60208082526021908201527f417272617973206d757374206265206f66207468652073616d65206c656e67746040820152600d60fb1b606082015260800190565b818103818111156106a4576106a4612581565b60208082526010908201526f125b9d985b1a59081d1bdad95b88125160821b604082015260600190565b600181815b8085111561271357815f19048211156126f9576126f9612581565b8085161561270657918102915b93841c93908002906126de565b509250929050565b5f82612729575060016106a4565b8161273557505f6106a4565b816001811461274b576002811461275557612771565b60019150506106a4565b60ff84111561276657612766612581565b50506001821b6106a4565b5060208310610133831016604e8410600b8410161715612794575081810a6106a4565b61279e83836126d9565b805f19048211156127b1576127b1612581565b029392505050565b5f6123e6838361271b565b80820281158282048414176106a4576106a4612581565b634e487b7160e01b5f52601260045260245ffd5b5f826127fd576127fd6127db565b500490565b601f8211156109f3575f81815260208120601f850160051c810160208610156128285750805b601f850160051c820191505b8181101561284757828155600101612834565b505050505050565b815167ffffffffffffffff811115612869576128696122b4565b61287d8161287784546125e3565b84612802565b602080601f8311600181146128b0575f84156128995750858301515b5f19600386901b1c1916600185901b178555612847565b5f85815260208120601f198616915b828110156128de578886015182559484019460019091019084016128bf565b50858210156128fb57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b60808152846080820152848660a08301375f60a086830101525f60a0601f19601f8801168301019050846020830152836040830152610d4f60608301846121bf565b5f8261295b5761295b6127db565b500690565b5f8161296e5761296e612581565b505f19019056fea26469706673582212209d83ff8fe9c33a41cd1d44c21af4e67f06c1afb7eedc9d0c51c4ac44e418494164736f6c63430008140033
Deployed ByteCode
0x608060405234801561000f575f80fd5b50600436106101fd575f3560e01c8063832aed2611610114578063cc3facc4116100a9578063da31158811610079578063da3115881461044d578063defd8e071461046d578063e30c397814610480578063f2fde38b14610491578063f499d99d146104a4575f80fd5b8063cc3facc41461041f578063cf1c316a14610432578063cf5e62d1146103c2578063d86b900514610445575f80fd5b8063ae8cac29116100e4578063ae8cac2914610265578063b7695d35146103d5578063bf1ede32146103e8578063c6610657146103fb575f80fd5b8063832aed26146103825780638da5cb5b14610395578063a773e0c9146103b9578063a9a01f85146103c2575f80fd5b806351b699cd1161019557806367f9fc3c1161016557806367f9fc3c1461031f578063689eb23214610332578063715018a61461035257806379ba50971461035a5780637db58e0f14610362575f80fd5b806351b699cd146102b4578063552180f2146102d7578063560f5441146103045780635c3684881461030c575f80fd5b80631f6e889a116101d05780631f6e889a14610265578063289fc9d2146102865780633887c27c1461028e578063485d7d94146102a1575f80fd5b80630331b529146102015780630795eca01461022a5780631be21ad91461023f5780631c138e2314610252575b5f80fd5b61021461020f366004612148565b6104ac565b6040516102219190612225565b60405180910390f35b61023d610238366004612285565b6106aa565b005b61023d61024d366004612360565b610841565b610214610260366004612148565b6109f8565b610278610273366004612148565b610bdb565b604051908152602001610221565b600354610278565b61023d61029c366004612360565b610d59565b61023d6102af3660046123c0565b610ea1565b6102c76102c23660046123c0565b610edd565b6040519015158152602001610221565b600854600954600a546102e992919083565b60408051938452602084019290925290820152606001610221565b600654610278565b61027861031a366004612148565b610f29565b61021461032d366004612148565b61107f565b610345610340366004612400565b611269565b6040516102219190612428565b61023d611382565b61023d611395565b610375610370366004612148565b61140f565b6040516102219190612458565b610375610390366004612148565b6114ed565b5f546001600160a01b03165b6040516001600160a01b039091168152602001610221565b61027860075481565b6102786103d0366004612148565b6115cb565b6102786103e336600461249b565b611721565b6102786103f63660046124b2565b611740565b61040e61040936600461249b565b6119c5565b60405161022195949392919061253c565b61034561042d366004612400565b611a7c565b61023d6104403660046123c0565b611b60565b61040e611b9d565b61046061045b36600461249b565b611bac565b604051610221919061256f565b61027861047b36600461249b565b611d05565b6001546001600160a01b03166103a1565b61023d61049f3660046123c0565b611d14565b600554610278565b60065460609080841080156104ca5750806104c78486612595565b11155b6104ef5760405162461bcd60e51b81526004016104e6906125a8565b60405180910390fd5b5f8367ffffffffffffffff811115610509576105096122b4565b60405190808252806020026020018201604052801561054257816020015b61052f6120ef565b8152602001906001900390816105275790505b5090505f5b8481101561069f5760045f600661055e848a612595565b8154811061056e5761056e6125cf565b905f5260205f20015481526020019081526020015f206040518060a00160405290815f8201805461059e906125e3565b80601f01602080910402602001604051908101604052809291908181526020018280546105ca906125e3565b80156106155780601f106105ec57610100808354040283529160200191610615565b820191905f5260205f20905b8154815290600101906020018083116105f857829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff169081111561065a5761065a6121ab565b600281111561066b5761066b6121ab565b81525050828281518110610681576106816125cf565b602002602001018190525080806106979061261b565b915050610547565b509150505b92915050565b335f9081526002602052604090205460ff16806106df5750336106d45f546001600160a01b031690565b6001600160a01b0316145b6106fb5760405162461bcd60e51b81526004016104e690612633565b60035484111561073d5760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908151bdd185b609a1b60448201526064016104e6565b6005548311156107835760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c840a0ae40d8cadccee8d607b1b60448201526064016104e6565b6006548211156107c95760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c84086b44098cadccee8d607b1b60448201526064016104e6565b6040805160608082018352868252602080830187905291830185905260088790556009869055600a85905560078490558251878152918201869052818301859052810183905290517ffcc94614435c643ae847e0a8e20e2e9e2fb8d9dea40a715cfc429b6a305d0a509181900360800190a150505050565b335f9081526002602052604090205460ff168061087657503361086b5f546001600160a01b031690565b6001600160a01b0316145b6108925760405162461bcd60e51b81526004016104e690612633565b80518251146108b35760405162461bcd60e51b81526004016104e69061265b565b600354825111156109065760405162461bcd60e51b815260206004820181905260248201527f4172726179206c656e677468206578636565647320746f74616c20636f696e7360448201526064016104e6565b5f5b82518110156109f3575f838281518110610924576109246125cf565b60200260200101511180156109545750600354838281518110610949576109496125cf565b602002602001015111155b6109955760405162461bcd60e51b8152602060048201526012602482015271092dcecc2d8d2c840c6ded2dc40d2dcc8caf60731b60448201526064016104e6565b8181815181106109a7576109a76125cf565b602002602001015160045f8584815181106109c4576109c46125cf565b602002602001015181526020019081526020015f206003018190555080806109eb9061261b565b915050610908565b505050565b606060018310158015610a2257506003546001610a158486612595565b610a1f919061269c565b11155b610a3e5760405162461bcd60e51b81526004016104e6906125a8565b5f8267ffffffffffffffff811115610a5857610a586122b4565b604051908082528060200260200182016040528015610a9157816020015b610a7e6120ef565b815260200190600190039081610a765790505b5090505f5b83811015610bd35760045f610aab8388612595565b81526020019081526020015f206040518060a00160405290815f82018054610ad2906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054610afe906125e3565b8015610b495780601f10610b2057610100808354040283529160200191610b49565b820191905f5260205f20905b815481529060010190602001808311610b2c57829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115610b8e57610b8e6121ab565b6002811115610b9f57610b9f6121ab565b81525050828281518110610bb557610bb56125cf565b60200260200101819052508080610bcb9061261b565b915050610a96565b509392505050565b5f8083118015610bed57506003548311155b610c095760405162461bcd60e51b81526004016104e6906126af565b5f83815260046020526040808220815160a08101909252805482908290610c2f906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054610c5b906125e3565b8015610ca65780601f10610c7d57610100808354040283529160200191610ca6565b820191905f5260205f20905b815481529060010190602001808311610c8957829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115610ceb57610ceb6121ab565b6002811115610cfc57610cfc6121ab565b8152505090505f81602001516012610d14919061269c565b610d1f90600a6127b9565b610d2990856127c4565b90505f670de0b6b3a7640000836040015183610d4591906127c4565b610d4f91906127ef565b9695505050505050565b335f9081526002602052604090205460ff1680610d8e575033610d835f546001600160a01b031690565b6001600160a01b0316145b610daa5760405162461bcd60e51b81526004016104e690612633565b8051825114610dcb5760405162461bcd60e51b81526004016104e69061265b565b5f5b82518110156109f3575f838281518110610de957610de96125cf565b602002602001015190505f838381518110610e0657610e066125cf565b602002602001015190505f82118015610e2157506003548211155b610e3d5760405162461bcd60e51b81526004016104e6906126af565b5f82815260046020526040908190206002018290555182907f69bedddd1c17558723d2c1fef779d4861749d024df6d986964feee81ecb8ebdd90610e849084815260200190565b60405180910390a250508080610e999061261b565b915050610dcd565b610ea9611d84565b336001600160a01b03821603610ebd575f80fd5b6001600160a01b03165f908152600260205260409020805460ff19169055565b6001600160a01b0381165f9081526002602052604081205460ff16806106a45750816001600160a01b0316610f195f546001600160a01b031690565b6001600160a01b03161492915050565b5f8083118015610f3b57506003548311155b610f575760405162461bcd60e51b81526004016104e6906126af565b5f83815260046020526040808220815160a08101909252805482908290610f7d906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054610fa9906125e3565b8015610ff45780601f10610fcb57610100808354040283529160200191610ff4565b820191905f5260205f20905b815481529060010190602001808311610fd757829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115611039576110396121ab565b600281111561104a5761104a6121ab565b8152505090505f8160200151600a61106291906127b9565b61106c90856127c4565b90505f826060015182610d4f91906127ef565b600554606090808410801561109d57508061109a8486612595565b11155b6110b95760405162461bcd60e51b81526004016104e6906125a8565b5f8367ffffffffffffffff8111156110d3576110d36122b4565b60405190808252806020026020018201604052801561110c57816020015b6110f96120ef565b8152602001906001900390816110f15790505b5090505f5b8481101561069f5760045f6005611128848a612595565b81548110611138576111386125cf565b905f5260205f20015481526020019081526020015f206040518060a00160405290815f82018054611168906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054611194906125e3565b80156111df5780601f106111b6576101008083540402835291602001916111df565b820191905f5260205f20905b8154815290600101906020018083116111c257829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115611224576112246121ab565b6002811115611235576112356121ab565b8152505082828151811061124b5761124b6125cf565b602002602001018190525080806112619061261b565b915050611111565b61127161212a565b61127961212a565b5f808086600281111561128e5761128e6121ab565b036112f657505060058054604080516020808402820181019092528281526112ef9187918491869083908301828280156112e557602002820191905f5260205f20905b8154815260200190600101908083116112d1575b5050505050611ddd565b9250611378565b600186600281111561130a5761130a6121ab565b0361136957505060068054604080516020808402820181019092528281526112ef9187918491869083908301828280156112e557602002820191905f5260205f20908154815260200190600101908083116112d1575050505050611ddd565b61137585600354611f4d565b92505b5090949350505050565b61138a611d84565b6113935f61208c565b565b60015433906001600160a01b031681146114035760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016104e6565b61140c8161208c565b50565b600654606090808410801561142d57508061142a8486612595565b11155b6114495760405162461bcd60e51b81526004016104e6906125a8565b5f8367ffffffffffffffff811115611463576114636122b4565b60405190808252806020026020018201604052801561148c578160200160208202803683370190505b5090505f5b8481101561069f5760066114a58288612595565b815481106114b5576114b56125cf565b905f5260205f2001548282815181106114d0576114d06125cf565b6020908102919091010152806114e58161261b565b915050611491565b600554606090808410801561150b5750806115088486612595565b11155b6115275760405162461bcd60e51b81526004016104e6906125a8565b5f8367ffffffffffffffff811115611541576115416122b4565b60405190808252806020026020018201604052801561156a578160200160208202803683370190505b5090505f5b8481101561069f5760056115838288612595565b81548110611593576115936125cf565b905f5260205f2001548282815181106115ae576115ae6125cf565b6020908102919091010152806115c38161261b565b91505061156f565b5f80831180156115dd57506003548311155b6115f95760405162461bcd60e51b81526004016104e6906126af565b5f83815260046020526040808220815160a0810190925280548290829061161f906125e3565b80601f016020809104026020016040519081016040528092919081815260200182805461164b906125e3565b80156116965780601f1061166d57610100808354040283529160200191611696565b820191905f5260205f20905b81548152906001019060200180831161167957829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff16908111156116db576116db6121ab565b60028111156116ec576116ec6121ab565b8152505090505f8160200151600a61170491906127b9565b61170e90856127c4565b90505f826040015182610d4f91906127ef565b60058181548110611730575f80fd5b5f91825260209091200154905081565b335f9081526002602052604081205460ff168061177557503361176a5f546001600160a01b031690565b6001600160a01b0316145b6117915760405162461bcd60e51b81526004016104e690612633565b60028660028111156117a5576117a56121ab565b036117e15760405162461bcd60e51b815260206004820152600c60248201526b496e76616c6964205479706560a01b60448201526064016104e6565b60038054905f6117f08361261b565b91905055506040518060a0016040528086868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052509385525050506020820186905260408201859052606082015260800187600281111561185f5761185f6121ab565b90526003545f9081526004602052604090208151819061187f908261284f565b506020820151816001015560408201518160020155606082015181600301556080820151816004015f6101000a81548160ff021916908360028111156118c7576118c76121ab565b02179055505f91506118d69050565b8660028111156118e8576118e86121ab565b0361192757600354600580546001810182555f919091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00155611976565b600186600281111561193b5761193b6121ab565b0361197657600354600680546001810182555f919091527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01555b6003547ff55a319d41f7f8bc2b2c2694b498de9f983c7b6906ef28f8277275cc1c024f06868686868b6040516119b095949392919061290b565b60405180910390a25060035495945050505050565b60046020525f90815260409020805481906119df906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054611a0b906125e3565b8015611a565780601f10611a2d57610100808354040283529160200191611a56565b820191905f5260205f20905b815481529060010190602001808311611a3957829003601f168201915b505050506001830154600284015460038501546004909501549394919390925060ff1685565b611a8461212a565b611a8c61212a565b5f8080866002811115611aa157611aa16121ab565b03611b13575050600954600754600591906112ef90611ac1908790612595565b82848054806020026020016040519081016040528092919081815260200182805480156112e557602002820191905f5260205f20908154815260200190600101908083116112d1575050505050611ddd565b6001866002811115611b2757611b276121ab565b03611b47575050600a54600754600691906112ef90611ac1908790612595565b61137585600754611b589190612595565b600854611f4d565b611b68611d84565b6001600160a01b038116611b7a575f80fd5b6001600160a01b03165f908152600260205260409020805460ff19166001179055565b600b805481906119df906125e3565b611bb46120ef565b5f82118015611bc557506003548211155b611c085760405162461bcd60e51b8152602060048201526014602482015273436f696e204944206f7574206f662072616e676560601b60448201526064016104e6565b5f8281526004602052604090819020815160a08101909252805482908290611c2f906125e3565b80601f0160208091040260200160405190810160405280929190818152602001828054611c5b906125e3565b8015611ca65780601f10611c7d57610100808354040283529160200191611ca6565b820191905f5260205f20905b815481529060010190602001808311611c8957829003601f168201915b505050918352505060018201546020820152600280830154604083015260038301546060830152600483015460809092019160ff1690811115611ceb57611ceb6121ab565b6002811115611cfc57611cfc6121ab565b90525092915050565b60068181548110611730575f80fd5b611d1c611d84565b600180546001600160a01b0383166001600160a01b03199091168117909155611d4c5f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f546001600160a01b031633146113935760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104e6565b611de561212a565b6004831015611e365760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f75676820636f696e7320696e207468652063617465676f727960448201526064016104e6565b611e3e61212a565b845f5b6004811015611f42575f868383604051602001611e68929190918252602082015260400190565b604051602081830303815290604052805190602001205f1c611e8a919061294d565b9050858181518110611e9e57611e9e6125cf565b6020026020010151848360048110611eb857611eb86125cf565b602002015285611ec960018961269c565b81518110611ed957611ed96125cf565b6020026020010151868281518110611ef357611ef36125cf565b602090810291909101015286611f0881612960565b975050838260048110611f1d57611f1d6125cf565b6020020151611f2c9084612595565b9250508080611f3a9061261b565b915050611e41565b509095945050505050565b611f5561212a565b611f5d61212a565b6004831015611fae5760405162461bcd60e51b815260206004820152601a60248201527f4e6f7420656e6f75676820636f696e7320617661696c61626c6500000000000060448201526064016104e6565b5f845b6004821015611378575f8582604051602001611fcf91815260200190565b604051602081830303815290604052805190602001205f1c611ff1919061294d565b611ffc906001612595565b90505f805b84811015612041578286826004811061201c5761201c6125cf565b60200201510361202f5760019150612041565b806120398161261b565b915050612001565b50801561205c57826120528161261b565b9350505050611fb1565b8185856004811061206f5761206f6125cf565b60200201528361207e8161261b565b94505082806120529061261b565b600180546001600160a01b031916905561140c815f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040518060a00160405280606081526020015f81526020015f81526020015f81526020015f6002811115612125576121256121ab565b905290565b60405180608001604052806004906020820280368337509192915050565b5f8060408385031215612159575f80fd5b50508035926020909101359150565b5f81518084525f5b8181101561218c57602081850181015186830182015201612170565b505f602082860101526020601f19601f83011685010191505092915050565b634e487b7160e01b5f52602160045260245ffd5b600381106121db57634e487b7160e01b5f52602160045260245ffd5b9052565b5f815160a084526121f360a0850182612168565b90506020830151602085015260408301516040850152606083015160608501526080830151610bd360808601826121bf565b5f602080830181845280855180835260408601915060408160051b87010192508387015f5b8281101561227857603f198886030184526122668583516121df565b9450928501929085019060010161224a565b5092979650505050505050565b5f805f8060808587031215612298575f80fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126122d7575f80fd5b8135602067ffffffffffffffff808311156122f4576122f46122b4565b8260051b604051601f19603f83011681018181108482111715612319576123196122b4565b604052938452858101830193838101925087851115612336575f80fd5b83870191505b848210156123555781358352918301919083019061233c565b979650505050505050565b5f8060408385031215612371575f80fd5b823567ffffffffffffffff80821115612388575f80fd5b612394868387016122c8565b935060208501359150808211156123a9575f80fd5b506123b6858286016122c8565b9150509250929050565b5f602082840312156123d0575f80fd5b81356001600160a01b03811681146123e6575f80fd5b9392505050565b8035600381106123fb575f80fd5b919050565b5f8060408385031215612411575f80fd5b61241a836123ed565b946020939093013593505050565b6080810181835f5b600481101561244f578151835260209283019290910190600101612430565b50505092915050565b602080825282518282018190525f9190848201906040850190845b8181101561248f57835183529284019291840191600101612473565b50909695505050505050565b5f602082840312156124ab575f80fd5b5035919050565b5f805f805f608086880312156124c6575f80fd5b6124cf866123ed565b9450602086013567ffffffffffffffff808211156124eb575f80fd5b818801915088601f8301126124fe575f80fd5b81358181111561250c575f80fd5b89602082850101111561251d575f80fd5b9699602092909201985095966040810135965060600135945092505050565b60a081525f61254e60a0830188612168565b9050856020830152846040830152836060830152610d4f60808301846121bf565b602081525f6123e660208301846121df565b634e487b7160e01b5f52601160045260245ffd5b808201808211156106a4576106a4612581565b6020808252600d908201526c496e76616c69642072616e676560981b604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b600181811c908216806125f757607f821691505b60208210810361261557634e487b7160e01b5f52602260045260245ffd5b50919050565b5f6001820161262c5761262c612581565b5060010190565b6020808252600e908201526d139bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b60208082526021908201527f417272617973206d757374206265206f66207468652073616d65206c656e67746040820152600d60fb1b606082015260800190565b818103818111156106a4576106a4612581565b60208082526010908201526f125b9d985b1a59081d1bdad95b88125160821b604082015260600190565b600181815b8085111561271357815f19048211156126f9576126f9612581565b8085161561270657918102915b93841c93908002906126de565b509250929050565b5f82612729575060016106a4565b8161273557505f6106a4565b816001811461274b576002811461275557612771565b60019150506106a4565b60ff84111561276657612766612581565b50506001821b6106a4565b5060208310610133831016604e8410600b8410161715612794575081810a6106a4565b61279e83836126d9565b805f19048211156127b1576127b1612581565b029392505050565b5f6123e6838361271b565b80820281158282048414176106a4576106a4612581565b634e487b7160e01b5f52601260045260245ffd5b5f826127fd576127fd6127db565b500490565b601f8211156109f3575f81815260208120601f850160051c810160208610156128285750805b601f850160051c820191505b8181101561284757828155600101612834565b505050505050565b815167ffffffffffffffff811115612869576128696122b4565b61287d8161287784546125e3565b84612802565b602080601f8311600181146128b0575f84156128995750858301515b5f19600386901b1c1916600185901b178555612847565b5f85815260208120601f198616915b828110156128de578886015182559484019460019091019084016128bf565b50858210156128fb57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b60808152846080820152848660a08301375f60a086830101525f60a0601f19601f8801168301019050846020830152836040830152610d4f60608301846121bf565b5f8261295b5761295b6127db565b500690565b5f8161296e5761296e612581565b505f19019056fea26469706673582212209d83ff8fe9c33a41cd1d44c21af4e67f06c1afb7eedc9d0c51c4ac44e418494164736f6c63430008140033