More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
15237485 | 823 days ago | 1.01 ETH |
Loading...
Loading
This contract contains unverified libraries: AstroChartLib
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
OrdinaryAstroChart
Compiler Version
v0.8.4+commit.c7e474f2
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// contracts/AstroChart.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "./BaseOraclizedAstroChart.sol"; import "./PrimeAstroChart.sol"; contract OrdinaryAstroChart is BaseOraclizedAstroChart { using Chainlink for Chainlink.Request; PrimeAstroChart private primeAstroChart; uint256 private constant PRIME_TOKENID_UPPER_BOUND = 366; event AstroChartBred(uint256 bredTokenId, uint256 fromTokenId, address bredTokenOwner, uint256 price); constructor(address _primeAstroChartAddress, address _svgGeneratorAddress) ERC721("AstroChart", "O-ASTRO") { AstroChartLib._initNextTokenId(PRIME_TOKENID_UPPER_BOUND + 1); _transferOwnership(_msgSender()); primeAstroChart = PrimeAstroChart(_primeAstroChartAddress); svgGenerator = SVGGenerator(_svgGeneratorAddress); } /// /// setUpParams used by MetaAstro ERC-721 Token /// @param linkTokenAddress, Chainlink's ERC-20 token address, /// @param _oracle, oracle address /// @param _jobId, oracle jobId used to calculate astro data /// @param _feeInLink, fee that should paid to Oracle operator for each request /// @param _oracleGasFee, gas fee that operator use when submit data back to contract /// @param _oracleRequestHost, host for oracle operator node to send request to /// @param _svgGenerator, SVGGenerator address /// function setUpParams( address linkTokenAddress, address _oracle, bytes32 _jobId, uint256 _feeInLink, uint256 _oracleGasFee, string calldata _oracleRequestHost, SVGGenerator _svgGenerator ) external onlyOwner { oracle = _oracle; jobId = _jobId; fee = _feeInLink; oracleRequestHost = _oracleRequestHost; setChainlinkToken(linkTokenAddress); AstroChartLib.setOracleGasFee(_oracleGasFee); svgGenerator = _svgGenerator; } /** withdraw oracle gas fee deposit, only can be done by owner */ function withdrawOracleGasDeposit(uint256 amount) external onlyOwner { payable(owner()).transfer(amount); } /** checks: 1. require ownerOf(tokenId) == msg.sender, guard only owner can change breed price, or else throw "Only owner can change breed price" as "OOCCBP" 2. require !isTokenFromPrime(tokenId), or else throw "`tokenId` comes from PrimeAstroChart" as "TCFP" effects: 1. update tokenId's breed price */ function setBreedPrice(uint256 tokenId, uint256 breedPrice) external { //checks address ownerOfToken = isTokenFromPrime(tokenId) ? primeAstroChart.ownerOf(tokenId) : ownerOf(tokenId); require(ownerOfToken == msg.sender, "OOCCBP"); //effects AstroChartLib.setBreedPrice(tokenId, breedPrice); } /** require pendingWithdraws[msg.sender] > 0, or else throw "pending withdraw must large than zero" as PWMLTZ */ function withdrawBreedFee() external { AstroChartLib.withdrawBreedFee(); } /** checks: 1. require msg.value >= token.breedPrice + oracleGasFee, or else throw "LTBP+O" 2. require datetimeOfBirth[1] == astroDataOfParentToken.datetimeOfBirth[1], or else throw "month not equal" as "MNE" 3. require datetimeOfBirth[2] == astroDataOfParentToken.datetimeOfBirth[2], or else throw "day not equal" as "DNE" 4. require astroDataOfParentToken.alreadyBredCount < breedingLimitationOf(astroDataOfParentToken.generation), or else throw "beyond generation's breeding limitation" as "BGBL" 5. require astroDataOfParentToken.exists, or else throw "ERC721: owner query for nonexistent token" Effects: 1. update pendinpendingWithdraws of fromToken's owner, as origin value + breedPrice Explainations: LTBP: less than breed price */ function breedFrom( uint256 fromTokenId, uint16[] calldata monthAndDay, string calldata remaining ) external payable { AstroChartArgs memory argsOfFromToken; address ownerOfFromToken; //judge if breed from prime astro chart if (isTokenFromPrime(fromTokenId)) { argsOfFromToken = primeAstroChart.getAstroArgsOf(fromTokenId); ownerOfFromToken = primeAstroChart.ownerOf(fromTokenId); } /** if (fromTokenId > 366) say it's ordinary AstroChart */ else { argsOfFromToken = AstroChartLib.getAstroArgsOf(fromTokenId); ownerOfFromToken = ownerOf(fromTokenId); } uint256 bredTokenId = AstroChartLib.breedFromDry( fromTokenId, monthAndDay, remaining, ownerOfFromToken, argsOfFromToken ); _safeMint(msg.sender, bredTokenId); // interactions sendRequestToOracle(bredTokenId, monthAndDay, remaining); emit AstroChartBred(bredTokenId, fromTokenId, msg.sender, msg.value); } function breedingLimitationOf(uint32 generation) public pure returns (uint32 res) { return AstroChartLib.breedingLimitationOf(generation); } function getAstroArgsOf(uint256 tokenId) external view returns (AstroChartArgs memory) { if (isTokenFromPrime(tokenId)) { return primeAstroChart.getAstroArgsOf(tokenId); } else { return AstroChartLib.getAstroArgsOf(tokenId); } } function getBreedConfig(uint256 tokenId) external view returns (BreedConfig memory) { return AstroChartLib.getBreedConfigOf(tokenId); } function getBreedPrice(uint256 tokenId) external view returns (uint256) { return AstroChartLib.getBreedPrice(tokenId); } function getPendingWithdraw() external view returns (uint256) { return AstroChartLib.getPendingWithdraw(); } function isTokenFromPrime(uint256 tokenId) private pure returns (bool) { return tokenId <= 366; } /** ERC-721 tokenURI */ function tokenURI(uint256 tokenId) public view override returns (string memory) { BreedConfig memory breedConfig = AstroChartLib.getBreedConfigOf(tokenId); return tokenURIOf(tokenId, breedConfig.bredFromRootTokenId); } }
// contracts/AstroChart.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol"; import "./libraries/OracleUtils.sol"; import "./libraries/SVGGenerator.sol"; import "./libraries/AstroChartLib.sol"; abstract contract BaseOraclizedAstroChart is ERC721Enumerable, Ownable, ChainlinkClient { using Chainlink for Chainlink.Request; /*** * ChainLink Block start */ address internal oracle; bytes32 internal jobId; uint256 internal fee; string internal oracleRequestHost; SVGGenerator internal svgGenerator; mapping(bytes32 => AstroChartResponse) internal request2Response; struct AstroChartResponse { uint16[] cusps; uint16[] planets; bool exists; } /** * ChainLink Block end */ // record tokenId to oracle request id mapping(uint256 => bytes32) public tokenId2OracleRequestId; /** Chainlink Relative Block start!!!! */ function getLinkTokenAddress() external view returns (address) { return chainlinkTokenAddress(); } /** Use to withdraw remain link from contract */ function withdrawLink() external onlyOwner { LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress()); require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer"); } /** * Create a Chainlink request to retrieve API response, find the target * data, then multiply by 1000000000000000000 (to remove decimal places from data). */ function sendRequestToOracle( uint256 tokenId, uint16[] memory monthAndDay, string memory remaining ) internal returns (bytes32) { Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector); string memory url = OracleUtils.genRequestURL(oracleRequestHost, monthAndDay, remaining); // Set the URL to perform the GET request on request.add("get", url); request.add("path_cusps", "cusps"); request.add("path_planets", "planets"); // Sends the request bytes32 requestId = sendChainlinkRequestTo(oracle, request, fee); tokenId2OracleRequestId[tokenId] = requestId; return requestId; } /** * Receive the response in the form of uint256 */ function fulfill( bytes32 _requestId, uint16[] calldata _cusps, uint16[] calldata _planets ) external recordChainlinkFulfillment(_requestId) { request2Response[_requestId] = AstroChartResponse({cusps: _cusps, planets: _planets, exists: true}); } /** Chainlink Relative Block end!!! */ function tokenURIOf(uint256 tokenId, uint256 gen0RootTokenId) internal view returns (string memory) { bytes32 requestId = tokenId2OracleRequestId[tokenId]; require(requestId != "0x0", "Token not minted"); AstroChartResponse memory response = request2Response[requestId]; if (!response.exists) { return svgGenerator.nonExistSVGInOpenSeaFormat(tokenId, gen0RootTokenId); } else { AstroChartArgs memory args = AstroChartLib.getAstroArgsOf(tokenId); return svgGenerator.genSVGInOpenSeaFormat( response.cusps, response.planets, args.generation, tokenId, args.monthAndDay[0], args.monthAndDay[1], gen0RootTokenId ); } } function getResponseOf(uint256 tokenId) public view returns (AstroChartResponse memory) { bytes32 requestId = tokenId2OracleRequestId[tokenId]; return request2Response[requestId]; } function getOracleGasFee() public view returns (uint256) { return AstroChartLib.getOracleGasFee(); } }
// contracts/AstroChart.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "./BaseOraclizedAstroChart.sol"; contract PrimeAstroChart is BaseOraclizedAstroChart { event AstroChartBred(uint256 bredTokenId, uint256 fromTokenId, address bredTokenOwner, uint256 price); constructor(address _svgGeneratorAddress) ERC721("meta-astro-genesis", "P-ASTRO") { AstroChartLib._initNextTokenId(1); _transferOwnership(_msgSender()); svgGenerator = SVGGenerator(_svgGeneratorAddress); } /// /// setUpParams used by MetaAstro ERC-721 Token /// @param linkTokenAddress, Chainlink's ERC-20 token address, /// @param _oracle, oracle address /// @param _jobId, oracle jobId used to calculate astro data /// @param _feeInLink, fee that should paid to Oracle operator for each request /// @param _oracleGasFee, gas fee that operator use when submit data back to contract /// @param _oracleRequestHost, host for oracle operator node to send request to /// @param _salesStartTime, initial mint start time /// @param _salesEndTime, initial mint end time /// function setUpParams( address linkTokenAddress, address _oracle, bytes32 _jobId, uint256 _feeInLink, uint256 _oracleGasFee, string calldata _oracleRequestHost, uint256 _salesStartTime, uint256 _salesEndTime, SVGGenerator _svgGenerator ) external onlyOwner { oracle = _oracle; jobId = _jobId; fee = _feeInLink; oracleRequestHost = _oracleRequestHost; setChainlinkToken(linkTokenAddress); AstroChartLib.setOracleGasFee(_oracleGasFee); AstroChartLib.setSalesTimes(_salesStartTime, _salesEndTime); svgGenerator = _svgGenerator; } /** withdraw initial deposit, only can be done by owner require amount <= initialDeposit, or else throw "withdraw amount must less than initialDeposit" as WAMLTI */ function withdrawInitialDeposit(uint256 amount) external onlyOwner { payable(owner()).transfer(amount); } /** initial mint, require initialMintCount < INITIAL_MINT_LIMIT, or else throw "initial mint limit arrived" as "IMLA" require msg.value >= getPrice() + oracleGasFee, or else throw "initial mint should pay with initialMintPrice + oracleGasFee" as "IMSPWI+O" require salesStartTime > 0 && currentTimeOffset >= salesStartTime, or else throw sales not start as "SNS" require libStorage().initialMintDate2Exists[dateToBytes32(datetimeOfBirth)] == false, or else throw initial mint date already exists as "IMDAE" _checkForDateAndCity's rule, ref _checkForDateAndCity's comment */ function initialMint( address to, uint16[] calldata monthAndDay, string calldata remaining ) external payable { uint256 tokenId = AstroChartLib.initialMintDry(monthAndDay, remaining); _safeMint(to, tokenId); //interactions sendRequestToOracle(tokenId, monthAndDay, remaining); } /** regenerate, require onwerOf(tokenId) == msg.sender, or else throw "token not owned by sender" as "TNOBS" require msg.value >= oracleGasFee, or else throw "regenerate should pay with oracleGasFee" as "RSPWO" require monthAndDay == token.originAstroArgs.monthAndDay, or else throw "Month and day should equal to origin" as "MDSETO" require monthAndDay.length == 2 and monthAndDay is valid or else throw "datetime not valid" as "DTNV" */ function regenerate( uint256 tokenId, uint16[] calldata monthAndDay, string calldata remaining ) external payable { AstroChartLib.regenerateDry(tokenId, ownerOf(tokenId), monthAndDay, remaining); sendRequestToOracle(tokenId, monthAndDay, remaining); } function beginNoDateLimitMint() public onlyOwner { AstroChartLib.beginNoDateLimitPrimeMint(); } function isNoDateLimitMintBegan() public view returns (bool) { return AstroChartLib.isNoDateLimitPrimeMintBegan(); } function initalMintCount() external view returns (uint256) { return AstroChartLib.initialMintCount(); } function initialDeposit() external view returns (uint256) { return AstroChartLib.initialDeposit(); } function getPrice() external view returns (uint256) { return AstroChartLib.getPrice(); } function getSalesTimes() external view returns (uint256, uint256) { return AstroChartLib.getSalesTimes(); } function getAstroArgsOf(uint256 tokenId) external view returns (AstroChartArgs memory) { return AstroChartLib.getAstroArgsOf(tokenId); } function getPendingWithdraw() external view returns (uint256) { return AstroChartLib.getPendingWithdraw(); } /// /// return relative prime tokenId if exist, orelse return 0 function getTokenIdByMonthAndDay(uint16 month, uint16 day) external view returns (uint256) { return AstroChartLib.getTokenIdByMonthAndDay(month, day); } /** ERC-721 tokenURI */ function tokenURI(uint256 tokenId) public view override returns (string memory) { return tokenURIOf(tokenId, tokenId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/ERC721Enumerable.sol) pragma solidity ^0.8.0; import "../ERC721.sol"; import "./IERC721Enumerable.sol"; /** * @dev This implements an optional extension of {ERC721} defined in the EIP that adds * enumerability of all the token ids in the contract as well as all token ids owned by each * account. */ abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { // Mapping from owner to list of owned token IDs mapping(address => mapping(uint256 => uint256)) private _ownedTokens; // Mapping from token ID to index of the owner tokens list mapping(uint256 => uint256) private _ownedTokensIndex; // Array with all token ids, used for enumeration uint256[] private _allTokens; // Mapping from token id to position in the allTokens array mapping(uint256 => uint256) private _allTokensIndex; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. */ function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); return _ownedTokens[owner][index]; } /** * @dev See {IERC721Enumerable-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _allTokens.length; } /** * @dev See {IERC721Enumerable-tokenByIndex}. */ function tokenByIndex(uint256 index) public view virtual override returns (uint256) { require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds"); return _allTokens[index]; } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` will be burned. * - `from` cannot be the zero address. * - `to` cannot be the zero address. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual override { super._beforeTokenTransfer(from, to, tokenId); if (from == address(0)) { _addTokenToAllTokensEnumeration(tokenId); } else if (from != to) { _removeTokenFromOwnerEnumeration(from, tokenId); } if (to == address(0)) { _removeTokenFromAllTokensEnumeration(tokenId); } else if (to != from) { _addTokenToOwnerEnumeration(to, tokenId); } } /** * @dev Private function to add a token to this extension's ownership-tracking data structures. * @param to address representing the new owner of the given token ID * @param tokenId uint256 ID of the token to be added to the tokens list of the given address */ function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { uint256 length = ERC721.balanceOf(to); _ownedTokens[to][length] = tokenId; _ownedTokensIndex[tokenId] = length; } /** * @dev Private function to add a token to this extension's token tracking data structures. * @param tokenId uint256 ID of the token to be added to the tokens list */ function _addTokenToAllTokensEnumeration(uint256 tokenId) private { _allTokensIndex[tokenId] = _allTokens.length; _allTokens.push(tokenId); } /** * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for * gas optimizations e.g. when performing a transfer operation (avoiding double writes). * This has O(1) time complexity, but alters the order of the _ownedTokens array. * @param from address representing the previous owner of the given token ID * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address */ function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; uint256 tokenIndex = _ownedTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary if (tokenIndex != lastTokenIndex) { uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index } // This also deletes the contents at the last position of the array delete _ownedTokensIndex[tokenId]; delete _ownedTokens[from][lastTokenIndex]; } /** * @dev Private function to remove a token from this extension's token tracking data structures. * This has O(1) time complexity, but alters the order of the _allTokens array. * @param tokenId uint256 ID of the token to be removed from the tokens list */ function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = _allTokens.length - 1; uint256 tokenIndex = _allTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding // an 'if' statement (like in _removeTokenFromOwnerEnumeration) uint256 lastTokenId = _allTokens[lastTokenIndex]; _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index // This also deletes the contents at the last position of the array delete _allTokensIndex[tokenId]; _allTokens.pop(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.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 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 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 { _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); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./Chainlink.sol"; import "./interfaces/ENSInterface.sol"; import "./interfaces/LinkTokenInterface.sol"; import "./interfaces/ChainlinkRequestInterface.sol"; import "./interfaces/OperatorInterface.sol"; import "./interfaces/PointerInterface.sol"; import {ENSResolver as ENSResolver_Chainlink} from "./vendor/ENSResolver.sol"; /** * @title The ChainlinkClient contract * @notice Contract writers can inherit this contract in order to create requests for the * Chainlink network */ abstract contract ChainlinkClient { using Chainlink for Chainlink.Request; uint256 internal constant LINK_DIVISIBILITY = 10**18; uint256 private constant AMOUNT_OVERRIDE = 0; address private constant SENDER_OVERRIDE = address(0); uint256 private constant ORACLE_ARGS_VERSION = 1; uint256 private constant OPERATOR_ARGS_VERSION = 2; bytes32 private constant ENS_TOKEN_SUBNAME = keccak256("link"); bytes32 private constant ENS_ORACLE_SUBNAME = keccak256("oracle"); address private constant LINK_TOKEN_POINTER = 0xC89bD4E1632D3A43CB03AAAd5262cbe4038Bc571; ENSInterface private s_ens; bytes32 private s_ensNode; LinkTokenInterface private s_link; OperatorInterface private s_oracle; uint256 private s_requestCount = 1; mapping(bytes32 => address) private s_pendingRequests; event ChainlinkRequested(bytes32 indexed id); event ChainlinkFulfilled(bytes32 indexed id); event ChainlinkCancelled(bytes32 indexed id); /** * @notice Creates a request that can hold additional parameters * @param specId The Job Specification ID that the request will be created for * @param callbackAddr address to operate the callback on * @param callbackFunctionSignature function signature to use for the callback * @return A Chainlink Request struct in memory */ function buildChainlinkRequest( bytes32 specId, address callbackAddr, bytes4 callbackFunctionSignature ) internal pure returns (Chainlink.Request memory) { Chainlink.Request memory req; return req.initialize(specId, callbackAddr, callbackFunctionSignature); } /** * @notice Creates a request that can hold additional parameters * @param specId The Job Specification ID that the request will be created for * @param callbackFunctionSignature function signature to use for the callback * @return A Chainlink Request struct in memory */ function buildOperatorRequest(bytes32 specId, bytes4 callbackFunctionSignature) internal view returns (Chainlink.Request memory) { Chainlink.Request memory req; return req.initialize(specId, address(this), callbackFunctionSignature); } /** * @notice Creates a Chainlink request to the stored oracle address * @dev Calls `chainlinkRequestTo` with the stored oracle address * @param req The initialized Chainlink Request * @param payment The amount of LINK to send for the request * @return requestId The request ID */ function sendChainlinkRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { return sendChainlinkRequestTo(address(s_oracle), req, payment); } /** * @notice Creates a Chainlink request to the specified oracle address * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to * send LINK which creates a request on the target oracle contract. * Emits ChainlinkRequested event. * @param oracleAddress The address of the oracle for the request * @param req The initialized Chainlink Request * @param payment The amount of LINK to send for the request * @return requestId The request ID */ function sendChainlinkRequestTo( address oracleAddress, Chainlink.Request memory req, uint256 payment ) internal returns (bytes32 requestId) { uint256 nonce = s_requestCount; s_requestCount = nonce + 1; bytes memory encodedRequest = abi.encodeWithSelector( ChainlinkRequestInterface.oracleRequest.selector, SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent req.id, address(this), req.callbackFunctionId, nonce, ORACLE_ARGS_VERSION, req.buf.buf ); return _rawRequest(oracleAddress, nonce, payment, encodedRequest); } /** * @notice Creates a Chainlink request to the stored oracle address * @dev This function supports multi-word response * @dev Calls `sendOperatorRequestTo` with the stored oracle address * @param req The initialized Chainlink Request * @param payment The amount of LINK to send for the request * @return requestId The request ID */ function sendOperatorRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { return sendOperatorRequestTo(address(s_oracle), req, payment); } /** * @notice Creates a Chainlink request to the specified oracle address * @dev This function supports multi-word response * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to * send LINK which creates a request on the target oracle contract. * Emits ChainlinkRequested event. * @param oracleAddress The address of the oracle for the request * @param req The initialized Chainlink Request * @param payment The amount of LINK to send for the request * @return requestId The request ID */ function sendOperatorRequestTo( address oracleAddress, Chainlink.Request memory req, uint256 payment ) internal returns (bytes32 requestId) { uint256 nonce = s_requestCount; s_requestCount = nonce + 1; bytes memory encodedRequest = abi.encodeWithSelector( OperatorInterface.operatorRequest.selector, SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent req.id, req.callbackFunctionId, nonce, OPERATOR_ARGS_VERSION, req.buf.buf ); return _rawRequest(oracleAddress, nonce, payment, encodedRequest); } /** * @notice Make a request to an oracle * @param oracleAddress The address of the oracle for the request * @param nonce used to generate the request ID * @param payment The amount of LINK to send for the request * @param encodedRequest data encoded for request type specific format * @return requestId The request ID */ function _rawRequest( address oracleAddress, uint256 nonce, uint256 payment, bytes memory encodedRequest ) private returns (bytes32 requestId) { requestId = keccak256(abi.encodePacked(this, nonce)); s_pendingRequests[requestId] = oracleAddress; emit ChainlinkRequested(requestId); require(s_link.transferAndCall(oracleAddress, payment, encodedRequest), "unable to transferAndCall to oracle"); } /** * @notice Allows a request to be cancelled if it has not been fulfilled * @dev Requires keeping track of the expiration value emitted from the oracle contract. * Deletes the request from the `pendingRequests` mapping. * Emits ChainlinkCancelled event. * @param requestId The request ID * @param payment The amount of LINK sent for the request * @param callbackFunc The callback function specified for the request * @param expiration The time of the expiration for the request */ function cancelChainlinkRequest( bytes32 requestId, uint256 payment, bytes4 callbackFunc, uint256 expiration ) internal { OperatorInterface requested = OperatorInterface(s_pendingRequests[requestId]); delete s_pendingRequests[requestId]; emit ChainlinkCancelled(requestId); requested.cancelOracleRequest(requestId, payment, callbackFunc, expiration); } /** * @notice the next request count to be used in generating a nonce * @dev starts at 1 in order to ensure consistent gas cost * @return returns the next request count to be used in a nonce */ function getNextRequestCount() internal view returns (uint256) { return s_requestCount; } /** * @notice Sets the stored oracle address * @param oracleAddress The address of the oracle contract */ function setChainlinkOracle(address oracleAddress) internal { s_oracle = OperatorInterface(oracleAddress); } /** * @notice Sets the LINK token address * @param linkAddress The address of the LINK token contract */ function setChainlinkToken(address linkAddress) internal { s_link = LinkTokenInterface(linkAddress); } /** * @notice Sets the Chainlink token address for the public * network as given by the Pointer contract */ function setPublicChainlinkToken() internal { setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress()); } /** * @notice Retrieves the stored address of the LINK token * @return The address of the LINK token */ function chainlinkTokenAddress() internal view returns (address) { return address(s_link); } /** * @notice Retrieves the stored address of the oracle contract * @return The address of the oracle contract */ function chainlinkOracleAddress() internal view returns (address) { return address(s_oracle); } /** * @notice Allows for a request which was created on another contract to be fulfilled * on this contract * @param oracleAddress The address of the oracle contract that will fulfill the request * @param requestId The request ID used for the response */ function addChainlinkExternalRequest(address oracleAddress, bytes32 requestId) internal notPendingRequest(requestId) { s_pendingRequests[requestId] = oracleAddress; } /** * @notice Sets the stored oracle and LINK token contracts with the addresses resolved by ENS * @dev Accounts for subnodes having different resolvers * @param ensAddress The address of the ENS contract * @param node The ENS node hash */ function useChainlinkWithENS(address ensAddress, bytes32 node) internal { s_ens = ENSInterface(ensAddress); s_ensNode = node; bytes32 linkSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_TOKEN_SUBNAME)); ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(linkSubnode)); setChainlinkToken(resolver.addr(linkSubnode)); updateChainlinkOracleWithENS(); } /** * @notice Sets the stored oracle contract with the address resolved by ENS * @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously */ function updateChainlinkOracleWithENS() internal { bytes32 oracleSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_ORACLE_SUBNAME)); ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(oracleSubnode)); setChainlinkOracle(resolver.addr(oracleSubnode)); } /** * @notice Ensures that the fulfillment is valid for this contract * @dev Use if the contract developer prefers methods instead of modifiers for validation * @param requestId The request ID for fulfillment */ function validateChainlinkCallback(bytes32 requestId) internal recordChainlinkFulfillment(requestId) // solhint-disable-next-line no-empty-blocks { } /** * @dev Reverts if the sender is not the oracle of the request. * Emits ChainlinkFulfilled event. * @param requestId The request ID for fulfillment */ modifier recordChainlinkFulfillment(bytes32 requestId) { require(msg.sender == s_pendingRequests[requestId], "Source must be the oracle of the request"); delete s_pendingRequests[requestId]; emit ChainlinkFulfilled(requestId); _; } /** * @dev Reverts if the request is already pending * @param requestId The request ID for fulfillment */ modifier notPendingRequest(bytes32 requestId) { require(s_pendingRequests[requestId] == address(0), "Request is already pending"); _; } }
// contracts/SVGGenerator.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "./StringLib.sol"; library OracleUtils { function genRequestURL( string memory oracleRequestHost, uint16[] memory monthAndDay, string memory remaining ) internal pure returns (string memory url) { url = string( abi.encodePacked( oracleRequestHost, "/api/v1/calc-chart-data-degrees-encrypted?houses=Placidus&zodiac=Krishnamurti&monthAndDay=", convertDatetimeToString(monthAndDay), "&remaining=", remaining ) ); } function convertDatetimeToString(uint16[] memory datetime) private pure returns (string memory res) { uint16 month = datetime[0]; uint16 day = datetime[1]; res = string( abi.encodePacked( StringLib.uintToString(month), ",", StringLib.uintToString(day) ) ); } }
// contracts/SVGGenerator.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "xp-math/contracts/xpmath.sol"; import "./Base64.sol"; import "./StringLib.sol"; import "./FireGenerator.sol"; import "./FireGenerator2.sol"; contract SVGGenerator { int128 private constant OVERLAP_DETECT = 1200; //number in rad*1000 uint16 private constant SPACE_RAD = 1300; int128 private constant PRECISION = 10000; //4 decimals uint16 private constant DOWN60 = 9599; uint16 private constant UP60 = 11344; uint16 private constant DOWN90 = 14486; uint16 private constant UP90 = 16929; uint16 private constant DOWN120 = 19897; uint16 private constant UP120 = 21991; uint16 private constant DOWN180 = 30194; uint16 private constant UP180 = 32637; enum LineColor { Red, Green, Blue, Yellow, Default } FireGenerator private fireGenerator; constructor(FireGenerator _fireGenerator) { fireGenerator = _fireGenerator; } function nonExistSVGInOpenSeaFormat(uint256 tokenId, uint256 rootGen0TokenId) public pure returns (string memory) { string memory output = '<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg"><text id="svg_6" font-size="10" y="311" x="301">generating...</text><svg>'; return encodeInSVGFormat(output, tokenId, rootGen0TokenId, 0, 0, 0); } function genSVGInOpenSeaFormat( uint16[] memory cusps, uint16[] memory planets, uint32 generation, uint256 tokenId, uint16 month, uint16 day, uint256 rootGen0TokenId ) public view returns (string memory) { string memory output = soGenSVG(cusps, planets, generation, month, day); return encodeInSVGFormat(output, tokenId, rootGen0TokenId, generation, month, day); } function encodeInSVGFormat(string memory _rawSVG, uint256 tokenId, uint256 rootGen0TokenId, uint32 generation, uint16 month, uint16 day) private pure returns (string memory) { string memory json = Base64.encode( bytes( string( abi.encodePacked( '{"name": "Meta Astrology Chart #', StringLib.uintToString(tokenId), '", "description": "metaverse on-chain astro chart", "image": "data:image/svg+xml;base64,', Base64.encode(bytes(_rawSVG)), '", "attributes": [{"trait_type": "rootGen0TokenId", "value": "', StringLib.uintToString(rootGen0TokenId), '"}, {"trait_type": "generation", "value": "', StringLib.uintToString(generation), '"}, {"trait_type": "month", "value": "', StringLib.uintToString(month), '"}, {"trait_type": "day", "value": "', StringLib.uintToString(day), '"}]}' ) ) ) ); _rawSVG = string( abi.encodePacked("data:application/json;base64,", json) ); return _rawSVG; } ///*********constants */ string constant golden0 = "e3d8ab"; string constant golden1 = "ab6e13"; string constant golden2 = "b49d5d"; string constant silver0 = "c1c1c1"; string constant silver1 = "757575"; string constant silver2 = "989898"; function soGenSVG( uint16[] memory cusps, uint16[] memory planets, uint32 generation, uint16 month, uint16 day ) public view returns (string memory result) { require(cusps.length == 12, "wrong csups"); require(planets.length == 11, "wrong planets"); //s0-color-s1-color-s2-color-s3-circles-s4 bool isGen0 = generation == 0; FireGenerator.ElementType elementType = fireGenerator.judgeElementTypeByPlanetDegree(planets[0]); if (isGen0) { //TODO(ironman_ch): move these code to FireGenerator string memory part2 = FireGenerator2.svgPart2(isGen0, elementType); part2 = fireGenerator.replaceThemeColor(isGen0, elementType, month, day, part2); result = concat(FireGenerator2.svgPart0(), golden0); result = concat(result, FireGenerator2.svgPart1()); result = concat(result, golden1); result = concat(result, part2); // result = concat(result, golden2); will concat in the firegenerato } else { result = concat(FireGenerator2.svgPart0(), silver0); result = concat(result, FireGenerator2.svgPart1()); result = concat(result, silver1); result = concat(result, FireGenerator2.svgPart2(isGen0, elementType)); // result = concat(result, silver2); will concat in the firegenerator } //TODO(ironman_ch): move these code to FireGenerator string memory part3 = FireGenerator2.svgPart3(isGen0, elementType); part3 = fireGenerator.replaceThemeColor(isGen0, elementType, month, day, part3); result = concat(result, part3); string memory date = concat( concat(uintToString(month), "."), uintToString(day) ); string memory centralText = string(abi.encodePacked( '<g filter="drop-shadow(0 1px 1px #000)">', text( "600", "600", concat( concat(unicode"「Gen ", uintToString(generation)), unicode"」" ), "2rem" ), text( "600", "650", concat(concat(unicode"✦ ", date), unicode" ✦"), "1.5rem" ), '</g>' )); string memory cuspsInSVG = genCuspsAsLines(cusps); (string memory planetsInSVG, string memory relationLines) = genPlanetsAsText(planets); FireGenerator.GenAndElement memory params = FireGenerator.GenAndElement({ isGen0: isGen0, elementType: elementType, cuspsBody: cuspsInSVG, planetsBody: planetsInSVG, planets: planets }); FireGenerator.ParamsPart2 memory paramsPart2 = FireGenerator.ParamsPart2({ relationLines: relationLines, centralText: centralText, month: month, day: day }); result = concat(result, fireGenerator.completeChartBody(params, paramsPart2)); result = concat(result, "</svg>"); } /* * @dev Returns a newly allocated string containing the concatenation of * `self` and `other`. * @param self The first slice to concatenate. * @param other The second slice to concatenate. * @return The concatenation of the two strings. */ function concat(string memory self, string memory other) private pure returns (string memory) { return string(abi.encodePacked(self, other)); } function uintToString(uint256 value) private pure returns (string memory) { return string(uintToBytes(value)); } function uintToBytes(uint256 value) private pure returns (bytes memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return buffer; } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. (eee.aaa).tostring */ function intToFixedNx4String(int256 value) public pure returns (string memory) { string memory sign = ""; if (value < 0) { sign = "-"; value = -value; } bytes memory buffer = uintToBytes(uint256(value)); string memory interger = ""; string memory decimal = ""; if (buffer.length <= 4) { interger = "0."; decimal = string(buffer); while (bytes(decimal).length < 4) { decimal = concat("0", decimal); } interger = concat(sign, interger); return concat(interger, decimal); } else { bytes memory tmp = new bytes(1); for (uint256 i = 0; i < buffer.length - 4; i++) { tmp[0] = buffer[i]; interger = concat(interger, string(tmp)); } interger = concat(interger, "."); for (uint256 i = buffer.length - 4; i < buffer.length; i++) { tmp[0] = buffer[i]; decimal = concat(decimal, string(tmp)); } interger = concat(sign, interger); return concat(interger, decimal); } } // to 64.64 fixed point number function to64x64(int128 x) public pure returns (int128) { unchecked { return XpMath.divi(x, PRECISION); } } // from 64.64 fixed point number to uint function toInt(int128 x) public pure returns (int256) { return XpMath.muli(x, PRECISION); } function genLineCoordinates( int128 alpha, int128 r0, int128 r1 ) public pure returns (int256[4] memory coordinates) { int128 cx = 600 << 64; r0 = r0 << 64; r1 = r1 << 64; return [ toInt(XpMath.add(cx, XpMath.mul(r0, XpMath.cos(alpha)))), toInt(XpMath.sub(cx, XpMath.mul(r0, XpMath.sin(alpha)))), toInt(XpMath.add(cx, XpMath.mul(r1, XpMath.cos(alpha)))), toInt(XpMath.sub(cx, XpMath.mul(r1, XpMath.sin(alpha)))) ]; } function genRelationLineCoord( int128 r, int128 alpha, int128 beta ) public pure returns (int256[4] memory coordinates) { r = r << 64; int128 cx = 600 << 64; //center return [ toInt(XpMath.add(cx, XpMath.mul(r, XpMath.cos(alpha)))), toInt(XpMath.sub(cx, XpMath.mul(r, XpMath.sin(alpha)))), toInt(XpMath.add(cx, XpMath.mul(r, XpMath.cos(beta)))), toInt(XpMath.sub(cx, XpMath.mul(r, XpMath.sin(beta)))) ]; } function genCuspsAsLines(uint16[] memory cusps) private pure returns (string memory res) { int128[] memory cusps64x64 = new int128[](12); for (uint8 i = 0; i < cusps.length; i++) { cusps64x64[i] = to64x64(int32(uint32(cusps[i]))); } for (uint32 i = 0; i < cusps.length; i += 1) { int256[4] memory xy = genLineCoordinates(cusps64x64[i], 230, 355); res = concat( res, line(xy[0], xy[1], xy[2], xy[3], 10000, LineColor.Default) ); //20000 means 2.0000 } } function fixOverlap(uint16[] memory _planets) public pure returns (uint16[] memory) { for (uint8 i = 1; i < _planets.length; i++) { for (uint8 j = 0; j <i ; j++) { // detect and move it int128 diff = XpMath.abs( int128(uint128(_planets[i])) - int128(uint128(_planets[j])) ); if (diff <= OVERLAP_DETECT) { uint256 tmp = _planets[j] + SPACE_RAD; _planets[i] = uint16(tmp % 65536); } } } return _planets; } function genPlanetsAsText(uint16[] memory _planets) private pure returns (string memory res, string memory relationLines) { string[11] memory PLANETS_TEXT = [ unicode"☉", //0 unicode"☽", //1 unicode"☿", //2 unicode"♀", //3 unicode"♂", //4 unicode"♃", //5 unicode"♄", //6 unicode"♅", //7 unicode"♆", //8 unicode"♇", //9 "ASC" ]; //sort for detect overlap, small to big uint16[] memory planets = new uint16[](_planets.length); for(uint8 i = 0; i < _planets.length; i++) { planets[i] = _planets[i]; } for (uint256 i = 0; i < planets.length; i++) { for (uint256 j = i + 1; j < planets.length; j++) { if (planets[i] > planets[j]) { uint16 temp = planets[i]; planets[i] = planets[j]; planets[j] = temp; string memory tmpStr = PLANETS_TEXT[i]; PLANETS_TEXT[i] = PLANETS_TEXT[j]; PLANETS_TEXT[j] = tmpStr; } } } //draw Realtionship lines relationLines = drawPlanetRelationLines(planets); //copy to a int128 array int128[] memory realPlanets64x64 = new int128[](11); for (uint8 i = 0; i < planets.length; i++) { //never overflow, planets is a uint16 array realPlanets64x64[i] = to64x64(int32(uint32(planets[i]))); } //fix overlap planets=fixOverlap(planets); int128[] memory planets64x64 = new int128[](11); for (uint8 i = 0; i < planets.length; i++) { //to64x64 planets64x64[i] = to64x64(int32(uint32(planets[i]))); } //draw planets for (uint32 i = 0; i < PLANETS_TEXT.length; i++) { int256[4] memory xy = genLineCoordinates( planets64x64[i], 0, 345 - 30 ); string memory fontSize = i == PLANETS_TEXT.length - 1 ? "25" : "30"; res = concat( res, text( intToFixedNx4String(xy[2]), intToFixedNx4String(xy[3]), PLANETS_TEXT[i], fontSize ) ); int256[4] memory xy1 = genLineCoordinates( realPlanets64x64[i], 0, 355 //target R ); xy = genLineCoordinates(planets64x64[i], 0, 345 - 30); res = concat(res, dot(xy1[2], xy1[3])); } } function drawPlanetRelationLines(uint16[] memory planets) public pure returns (string memory res) { for (uint8 i = 0; i < planets.length; i++) { for (uint8 j = i + 1; j < planets.length; j++) { res = concat( res, drawPlanetRelationLine(planets[i], planets[j]) ); } } } // Require A <= B function drawPlanetRelationLine(uint16 planetA, uint16 planetB) public pure returns (string memory res) { require(planetA <= planetB, "PRL"); int128 radius = 228; uint16 diff = planetB - planetA; int256[4] memory xy; res = ""; xy = genRelationLineCoord( radius, to64x64(int32(uint32(planetA))), to64x64(int32(uint32(planetB))) ); if (DOWN60 <= diff && diff <= UP60) { //60 res = line(xy[0], xy[1], xy[2], xy[3], 10000, LineColor.Yellow); } else if (DOWN90 <= diff && diff <= UP90) { //90 res = line(xy[0], xy[1], xy[2], xy[3], 10000, LineColor.Red); } else if (DOWN120 <= diff && diff <= UP120) { //120 res = line(xy[0], xy[1], xy[2], xy[3], 10000, LineColor.Green); } else if (DOWN180 <= diff && diff <= UP180) { //180 res = line(xy[0], xy[1], xy[2], xy[3], 10000, LineColor.Blue); } } function text( string memory x, string memory y, string memory content, string memory fontSize ) private pure returns (string memory res) { res = '<text text-anchor="middle" '; res = setAttribute(res, "x", x); res = setAttribute(res, "y", y); res = setAttribute(res, "font-size", fontSize); res = concat(res, ">"); res = concat(res, content); res = concat(res, "</text>"); } function dot(int256 x, int256 y) private pure returns (string memory res) { res = "<circle"; res = setAttribute(res, "cx", intToFixedNx4String(x)); res = setAttribute(res, "cy", intToFixedNx4String(y)); res = setAttribute(res, "r", "3"); res = setAttribute(res, "fill", "#000"); res = concat(res, "/>"); } function line( int256 x1, int256 y1, int256 x2, int256 y2, int256 width, LineColor color ) private pure returns (string memory) { return lineForString( intToFixedNx4String(x1), intToFixedNx4String(y1), intToFixedNx4String(x2), intToFixedNx4String(y2), intToFixedNx4String(width), color ); } function lineForString( string memory x1, string memory y1, string memory x2, string memory y2, string memory width, LineColor color ) private pure returns (string memory) { string memory l = "<line "; l = setAttribute(l, "x1", x1); l = setAttribute(l, "y1", y1); l = setAttribute(l, "x2", x2); l = setAttribute(l, "y2", y2); l = setAttribute(l, "stroke-width", width); if (color != LineColor.Default) { if (color == LineColor.Red) { l = setAttribute(l, "stroke", "#b41718"); //Red } else if (color == LineColor.Green) { l = setAttribute(l, "stroke", "#3069ce"); //Green } else if (color == LineColor.Blue) { l = setAttribute(l, "stroke", "#3764B1"); //Blue } else if (color == LineColor.Yellow) { l = setAttribute(l, "stroke", "#E3CD6F"); //Yellow } } return concat(l, "/>"); } function setAttribute( string memory origin, string memory key, string memory value ) private pure returns (string memory res) { res = concat(origin, " "); res = concat(res, key); res = concat(res, '="'); res = concat(res, value); res = concat(res, '"'); } }
// contracts/SVGGenerator.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "./DateUtils.sol"; // import "hardhat/console.sol"; struct AstroChartArgs { uint16[] monthAndDay; string remaining; bool exists; uint32 generation; } struct BreedConfig { uint32 alreadyBredCount; uint256 breedPrice; uint256 bredFromRootTokenId; } library AstroChartLib { // the limit for initial mint uint256 private constant INITIAL_MINT_LIMIT = 366; uint256 private constant SALES_START_PRICE = 1000 ether; uint256 private constant PRICE_DROP_DURATION = 600; // 10 mins uint256 private constant PRICE_DROP_PERCENT = 10; uint256 private constant PRICE_DROP_FLOOR = 0.1 ether; struct LibStorage { bool noDateLimitPrimeMint; // already minted for initial minting uint256 initalMintCount; // salesStartTime, offset from day's 0 clock, unit: seconds uint256 salesStartTime; // salesEndTime, offset from day's 0 clock, unit: seconds uint256 salesEndTime; // initial deposit uint256 initialDeposit; // initial mint's conflict detector mapping(bytes32 => uint256) mintedDate2PrimeTokenId; // record tokenId to origin data mapping(uint256 => AstroChartArgs) tokenIdToAstroData; // record tokenId to breed next generation's price and alreadBredCount mapping(uint256 => BreedConfig) tokenIdToBreedConfig; // record owner to pending withdraws mapping(address => uint256) pendingWithdraws; uint256 nextTokenId; // charge the oracle gas fee for oracle operator to submit transaction uint256 oracleGasFee; } // return a struct storage pointer for accessing the state variables function libStorage() internal pure returns (LibStorage storage ds) { bytes32 position = keccak256("AstroChartLib.storage"); assembly { ds.slot := position } } function _initNextTokenId(uint256 initValue) public { libStorage().nextTokenId = initValue; } /** * @dev calculates the next token ID based on totalSupply * @return uint256 for the next token ID */ function _nextTokenId() private returns (uint256) { uint256 res = libStorage().nextTokenId; libStorage().nextTokenId += 1; return res; } function getOracleGasFee() public view returns (uint256) { return libStorage().oracleGasFee; } function setOracleGasFee(uint256 _fee) public { libStorage().oracleGasFee = _fee; } /** set the sales startTime and endTime, only can be done by owner */ function setSalesTimes(uint256 _salesStartTime, uint256 _salesEndTime) public { libStorage().salesStartTime = _salesStartTime; libStorage().salesEndTime = _salesEndTime; } function getSalesTimes() public view returns (uint256, uint256) { return (libStorage().salesStartTime, libStorage().salesEndTime); } function initialDeposit() public view returns (uint256) { return libStorage().initialDeposit; } function initialMintCount() public view returns (uint256) { return libStorage().initalMintCount; } function beginNoDateLimitPrimeMint() public { libStorage().noDateLimitPrimeMint = true; } function isNoDateLimitPrimeMintBegan() public view returns (bool) { return libStorage().noDateLimitPrimeMint; } function initialMintDry(uint16[] calldata monthAndDay, string calldata remaining) public returns (uint256 tokenId) { //checks require(libStorage().initalMintCount < INITIAL_MINT_LIMIT, "IMLA"); uint256 price = getPrice(); require(msg.value >= getPrice() + libStorage().oracleGasFee, "IMSPWI+O"); require(price != 0, "SNS"); uint16 month = monthAndDay[0]; uint16 day = monthAndDay[1]; require(libStorage().mintedDate2PrimeTokenId[dateToBytes32(month, day)] == 0, "IMDAE"); if (!isNoDateLimitPrimeMintBegan()) { require(DateUtils.getDayFromTimestamp(block.timestamp) == day, "DTNT"); } _checkForDateAndCity(monthAndDay); //effects AstroChartArgs memory args = AstroChartArgs({ monthAndDay: monthAndDay, remaining: remaining, exists: true, generation: 0 }); tokenId = _nextTokenId(); libStorage().tokenIdToAstroData[tokenId] = args; libStorage().initalMintCount++; libStorage().initialDeposit += msg.value; libStorage().mintedDate2PrimeTokenId[dateToBytes32(month, day)] = tokenId; } function regenerateDry( uint256 tokenId, address ownerOfToken, uint16[] calldata _monthAndDay, string calldata remaining ) public { //require require(ownerOfToken == msg.sender, "TNOBS"); require(msg.value >= libStorage().oracleGasFee, "RSPWO"); AstroChartArgs memory originArgs = libStorage().tokenIdToAstroData[tokenId]; require(_monthAndDay[0] == originArgs.monthAndDay[0] && _monthAndDay[1] == originArgs.monthAndDay[1], "MDSETO"); _checkForDateAndCity(_monthAndDay); //effect AstroChartArgs memory args = AstroChartArgs({ monthAndDay: _monthAndDay, remaining: remaining, exists: true, generation: 0 }); libStorage().tokenIdToAstroData[tokenId] = args; libStorage().initialDeposit += msg.value; } function getTokenIdByMonthAndDay(uint16 month, uint16 day) public view returns (uint256) { return libStorage().mintedDate2PrimeTokenId[dateToBytes32(month, day)]; } function dateToBytes32(uint16 month, uint16 day) private pure returns (bytes32) { bytes memory encoded = abi.encodePacked(month, day); return bytesToBytes32(encoded); } function bytesToBytes32(bytes memory b) private pure returns (bytes32 out) { for (uint8 i = 0; i < b.length; i++) { out |= bytes32(b[i] & 0xFF) >> (i * 8); } } function getPrice() public view returns (uint256) { if (libStorage().salesStartTime == 0) { return 0; } uint256 currentTimeOffset = DateUtils.getUTCSecondsOffsetInDay(block.timestamp); uint256 startSalesTime = libStorage().salesStartTime; if (currentTimeOffset < startSalesTime) { return 0; } uint256[75] memory priceTable = [ (uint256)(900.0 ether), 810.0 ether, 729.0 ether, 656.1 ether, 590.4 ether, 531.4 ether, 478.2 ether, 430.4 ether, 387.4 ether, 348.6 ether, 313.8 ether, 282.4 ether, 254.1 ether, 228.7 ether, 205.8 ether, 185.3 ether, 166.7 ether, 150.0 ether, 135.0 ether, 121.5 ether, 109.4 ether, 98.4 ether, 88.6 ether, 79.7 ether, 71.7 ether, 64.6 ether, 58.1 ether, 52.3 ether, 47.1 ether, 42.3 ether, 38.1 ether, 34.3 ether, 30.9 ether, 27.8 ether, 25.0 ether, 22.5 ether, 20.2 ether, 18.2 ether, 16.4 ether, 14.7 ether, 13.3 ether, 11.9 ether, 10.7 ether, 9.6 ether, 8.7 ether, 7.8 ether, 7.0 ether, 6.3 ether, 5.7 ether, 5.1 ether, 4.6 ether, 4.1 ether, 3.7 ether, 3.3 ether, 3.0 ether, 2.7 ether, 2.4 ether, 2.2 ether, 1.9 ether, 1.7 ether, 1.6 ether, 1.4 ether, 1.3 ether, 1.1 ether, 1.0 ether, 0.9 ether, 0.8 ether, 0.7 ether, 0.6 ether, 0.6 ether, 0.5 ether, 0.4 ether, 0.3 ether, 0.2 ether, 0.1 ether ]; // Public sales uint256 dropCount = (currentTimeOffset - startSalesTime) / PRICE_DROP_DURATION; return dropCount < priceTable.length ? priceTable[dropCount] : PRICE_DROP_FLOOR; } /** require monthAndDay.length == 2 and monthAndDay is valid or else throw "datetime not valid" as "DTNV" */ function _checkForDateAndCity(uint16[] calldata monthAndDay) private view { require(monthAndDay.length == 2, "DTNV"); uint16 month = monthAndDay[0]; uint16 day = monthAndDay[1]; require(DateUtils.isDateValid(2012, month, day), "DTNV"); } function setBreedPrice(uint256 tokenId, uint256 breedPrice) public { //effects libStorage().tokenIdToBreedConfig[tokenId].breedPrice = breedPrice; } function getBreedPrice(uint256 tokenId) public view returns (uint256) { BreedConfig storage breedConfig = libStorage().tokenIdToBreedConfig[tokenId]; AstroChartArgs memory args = getAstroArgsOf(tokenId); return getBreedPriceInner(breedConfig, args); } function getBreedPriceInner(BreedConfig storage breedConfig, AstroChartArgs memory astroChartArgs) internal view returns (uint256) { uint256 userBreedPrice = breedConfig.breedPrice; return userBreedPrice == 0 ? suggestBreedPrice(astroChartArgs) : userBreedPrice; } function suggestBreedPrice(AstroChartArgs memory astroChartArgs) internal pure returns (uint256) { uint256 generation = astroChartArgs.generation; return 1 ether / (2**generation); } function withdrawBreedFee() public { //checks require(libStorage().pendingWithdraws[msg.sender] > 0, "PWMLTZ"); //effects libStorage().pendingWithdraws[msg.sender] = 0; //interactions payable(msg.sender).transfer(libStorage().pendingWithdraws[msg.sender]); } function breedFromDry( uint256 fromTokenId, uint16[] calldata monthAndDay, string calldata remaining, address ownerOfFromToken, AstroChartArgs memory astroDataOfParentToken ) public returns (uint256 bredTokenId) { //checks BreedConfig storage breedConfig = libStorage().tokenIdToBreedConfig[fromTokenId]; require( msg.value >= getBreedPriceInner(breedConfig, astroDataOfParentToken) + libStorage().oracleGasFee, "LTBP+O" ); _checkForDateAndCity(monthAndDay); require(monthAndDay[0] == astroDataOfParentToken.monthAndDay[0], "MNE"); require(monthAndDay[1] == astroDataOfParentToken.monthAndDay[1], "DNE"); require(breedConfig.alreadyBredCount < breedingLimitationOf(astroDataOfParentToken.generation), "BGBL"); //effects AstroChartArgs memory args = AstroChartArgs({ monthAndDay: monthAndDay, remaining: remaining, exists: true, generation: astroDataOfParentToken.generation + 1 }); //set bredToken to astro data bredTokenId = _nextTokenId(); libStorage().tokenIdToAstroData[bredTokenId] = args; //set breedConfig.bredFromRootTokenId libStorage().tokenIdToBreedConfig[bredTokenId].bredFromRootTokenId = breedConfig.bredFromRootTokenId == 0 ? fromTokenId : breedConfig.bredFromRootTokenId; //update pending withdraw of from token's owner libStorage().pendingWithdraws[ownerOfFromToken] += breedConfig.breedPrice; //add oracleGadFee to initialDeposit libStorage().initialDeposit += msg.value - breedConfig.breedPrice; // update alreadyBredCount of fromToken breedConfig.alreadyBredCount += 1; } function breedingLimitationOf(uint32 generation) public pure returns (uint32 res) { if (generation == 0) { return 2**32 - 1; } if (generation > 10) { return 0; } uint32 revisedGen = 10 - generation; res = uint32(1) << revisedGen; } function getAstroArgsOf(uint256 tokenId) public view returns (AstroChartArgs memory) { return libStorage().tokenIdToAstroData[tokenId]; } function getBreedConfigOf(uint256 tokenId) public view returns (BreedConfig memory) { return libStorage().tokenIdToBreedConfig[tokenId]; } function getPendingWithdraw() public view returns (uint256) { return libStorage().pendingWithdraws[msg.sender]; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; import "./IERC721.sol"; import "./IERC721Receiver.sol"; import "./extensions/IERC721Metadata.sol"; import "../../utils/Address.sol"; import "../../utils/Context.sol"; import "../../utils/Strings.sol"; import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { using Address for address; using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to owner address mapping(uint256 => address) private _owners; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: balance query for the zero address"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: owner query for nonexistent token"); return owner; } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overriden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not owner nor approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom( address from, address to, uint256 tokenId ) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory _data ) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _safeTransfer(from, to, tokenId, _data); } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * `_data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer( address from, address to, uint256 tokenId, bytes memory _data ) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _owners[tokenId] != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { require(_exists(tokenId), "ERC721: operator query for nonexistent token"); address owner = ERC721.ownerOf(tokenId); return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint( address to, uint256 tokenId, bytes memory _data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId); _balances[to] += 1; _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId); // Clear approvals _approve(address(0), tokenId); _balances[owner] -= 1; delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer( address from, address to, uint256 tokenId ) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId); // Clear approvals from the previous owner _approve(address(0), tokenId); _balances[from] -= 1; _balances[to] += 1; _owners[tokenId] = to; emit Transfer(from, to, tokenId); } /** * @dev Approve `to` to operate on `tokenId` * * Emits a {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits a {ApprovalForAll} event. */ function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` 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 tokenId ) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Enumerable.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Address.sol) pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {CBORChainlink} from "./vendor/CBORChainlink.sol"; import {BufferChainlink} from "./vendor/BufferChainlink.sol"; /** * @title Library for common Chainlink functions * @dev Uses imported CBOR library for encoding to buffer */ library Chainlink { uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase using CBORChainlink for BufferChainlink.buffer; struct Request { bytes32 id; address callbackAddress; bytes4 callbackFunctionId; uint256 nonce; BufferChainlink.buffer buf; } /** * @notice Initializes a Chainlink request * @dev Sets the ID, callback address, and callback function signature on the request * @param self The uninitialized request * @param jobId The Job Specification ID * @param callbackAddr The callback address * @param callbackFunc The callback function signature * @return The initialized request */ function initialize( Request memory self, bytes32 jobId, address callbackAddr, bytes4 callbackFunc ) internal pure returns (Chainlink.Request memory) { BufferChainlink.init(self.buf, defaultBufferSize); self.id = jobId; self.callbackAddress = callbackAddr; self.callbackFunctionId = callbackFunc; return self; } /** * @notice Sets the data for the buffer without encoding CBOR on-chain * @dev CBOR can be closed with curly-brackets {} or they can be left off * @param self The initialized request * @param data The CBOR data */ function setBuffer(Request memory self, bytes memory data) internal pure { BufferChainlink.init(self.buf, data.length); BufferChainlink.append(self.buf, data); } /** * @notice Adds a string value to the request with a given key name * @param self The initialized request * @param key The name of the key * @param value The string value to add */ function add( Request memory self, string memory key, string memory value ) internal pure { self.buf.encodeString(key); self.buf.encodeString(value); } /** * @notice Adds a bytes value to the request with a given key name * @param self The initialized request * @param key The name of the key * @param value The bytes value to add */ function addBytes( Request memory self, string memory key, bytes memory value ) internal pure { self.buf.encodeString(key); self.buf.encodeBytes(value); } /** * @notice Adds a int256 value to the request with a given key name * @param self The initialized request * @param key The name of the key * @param value The int256 value to add */ function addInt( Request memory self, string memory key, int256 value ) internal pure { self.buf.encodeString(key); self.buf.encodeInt(value); } /** * @notice Adds a uint256 value to the request with a given key name * @param self The initialized request * @param key The name of the key * @param value The uint256 value to add */ function addUint( Request memory self, string memory key, uint256 value ) internal pure { self.buf.encodeString(key); self.buf.encodeUInt(value); } /** * @notice Adds an array of strings to the request with a given key name * @param self The initialized request * @param key The name of the key * @param values The array of string values to add */ function addStringArray( Request memory self, string memory key, string[] memory values ) internal pure { self.buf.encodeString(key); self.buf.startArray(); for (uint256 i = 0; i < values.length; i++) { self.buf.encodeString(values[i]); } self.buf.endSequence(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface ENSInterface { // Logged when the owner of a node assigns a new owner to a subnode. event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); // Logged when the owner of a node transfers ownership to a new account. event Transfer(bytes32 indexed node, address owner); // Logged when the resolver for a node changes. event NewResolver(bytes32 indexed node, address resolver); // Logged when the TTL of a node changes event NewTTL(bytes32 indexed node, uint64 ttl); function setSubnodeOwner( bytes32 node, bytes32 label, address owner ) external; function setResolver(bytes32 node, address resolver) external; function setOwner(bytes32 node, address owner) external; function setTTL(bytes32 node, uint64 ttl) external; function owner(bytes32 node) external view returns (address); function resolver(bytes32 node) external view returns (address); function ttl(bytes32 node) external view returns (uint64); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface LinkTokenInterface { function allowance(address owner, address spender) external view returns (uint256 remaining); function approve(address spender, uint256 value) external returns (bool success); function balanceOf(address owner) external view returns (uint256 balance); function decimals() external view returns (uint8 decimalPlaces); function decreaseApproval(address spender, uint256 addedValue) external returns (bool success); function increaseApproval(address spender, uint256 subtractedValue) external; function name() external view returns (string memory tokenName); function symbol() external view returns (string memory tokenSymbol); function totalSupply() external view returns (uint256 totalTokensIssued); function transfer(address to, uint256 value) external returns (bool success); function transferAndCall( address to, uint256 value, bytes calldata data ) external returns (bool success); function transferFrom( address from, address to, uint256 value ) external returns (bool success); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface ChainlinkRequestInterface { function oracleRequest( address sender, uint256 requestPrice, bytes32 serviceAgreementID, address callbackAddress, bytes4 callbackFunctionId, uint256 nonce, uint256 dataVersion, bytes calldata data ) external; function cancelOracleRequest( bytes32 requestId, uint256 payment, bytes4 callbackFunctionId, uint256 expiration ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./OracleInterface.sol"; import "./ChainlinkRequestInterface.sol"; interface OperatorInterface is OracleInterface, ChainlinkRequestInterface { function operatorRequest( address sender, uint256 payment, bytes32 specId, bytes4 callbackFunctionId, uint256 nonce, uint256 dataVersion, bytes calldata data ) external; function fulfillOracleRequest2( bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data ) external returns (bool); function ownerTransferAndCall( address to, uint256 value, bytes calldata data ) external returns (bool success); function distributeFunds(address payable[] calldata receivers, uint256[] calldata amounts) external payable; function getAuthorizedSenders() external returns (address[] memory); function setAuthorizedSenders(address[] calldata senders) external; function getForwarder() external returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface PointerInterface { function getAddress() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; abstract contract ENSResolver { function addr(bytes32 node) public view virtual returns (address); }
// SPDX-License-Identifier: MIT pragma solidity >=0.4.19; import {BufferChainlink} from "./BufferChainlink.sol"; library CBORChainlink { using BufferChainlink for BufferChainlink.buffer; uint8 private constant MAJOR_TYPE_INT = 0; uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1; uint8 private constant MAJOR_TYPE_BYTES = 2; uint8 private constant MAJOR_TYPE_STRING = 3; uint8 private constant MAJOR_TYPE_ARRAY = 4; uint8 private constant MAJOR_TYPE_MAP = 5; uint8 private constant MAJOR_TYPE_TAG = 6; uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7; uint8 private constant TAG_TYPE_BIGNUM = 2; uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3; function encodeFixedNumeric(BufferChainlink.buffer memory buf, uint8 major, uint64 value) private pure { if(value <= 23) { buf.appendUint8(uint8((major << 5) | value)); } else if (value <= 0xFF) { buf.appendUint8(uint8((major << 5) | 24)); buf.appendInt(value, 1); } else if (value <= 0xFFFF) { buf.appendUint8(uint8((major << 5) | 25)); buf.appendInt(value, 2); } else if (value <= 0xFFFFFFFF) { buf.appendUint8(uint8((major << 5) | 26)); buf.appendInt(value, 4); } else { buf.appendUint8(uint8((major << 5) | 27)); buf.appendInt(value, 8); } } function encodeIndefiniteLengthType(BufferChainlink.buffer memory buf, uint8 major) private pure { buf.appendUint8(uint8((major << 5) | 31)); } function encodeUInt(BufferChainlink.buffer memory buf, uint value) internal pure { if(value > 0xFFFFFFFFFFFFFFFF) { encodeBigNum(buf, value); } else { encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value)); } } function encodeInt(BufferChainlink.buffer memory buf, int value) internal pure { if(value < -0x10000000000000000) { encodeSignedBigNum(buf, value); } else if(value > 0xFFFFFFFFFFFFFFFF) { encodeBigNum(buf, uint(value)); } else if(value >= 0) { encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(uint256(value))); } else { encodeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(uint256(-1 - value))); } } function encodeBytes(BufferChainlink.buffer memory buf, bytes memory value) internal pure { encodeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length)); buf.append(value); } function encodeBigNum(BufferChainlink.buffer memory buf, uint value) internal pure { buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM)); encodeBytes(buf, abi.encode(value)); } function encodeSignedBigNum(BufferChainlink.buffer memory buf, int input) internal pure { buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM)); encodeBytes(buf, abi.encode(uint256(-1 - input))); } function encodeString(BufferChainlink.buffer memory buf, string memory value) internal pure { encodeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length)); buf.append(bytes(value)); } function startArray(BufferChainlink.buffer memory buf) internal pure { encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY); } function startMap(BufferChainlink.buffer memory buf) internal pure { encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP); } function endSequence(BufferChainlink.buffer memory buf) internal pure { encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev A library for working with mutable byte buffers in Solidity. * * Byte buffers are mutable and expandable, and provide a variety of primitives * for writing to them. At any time you can fetch a bytes object containing the * current contents of the buffer. The bytes object should not be stored between * operations, as it may change due to resizing of the buffer. */ library BufferChainlink { /** * @dev Represents a mutable buffer. Buffers have a current value (buf) and * a capacity. The capacity may be longer than the current value, in * which case it can be extended without the need to allocate more memory. */ struct buffer { bytes buf; uint256 capacity; } /** * @dev Initializes a buffer with an initial capacity. * @param buf The buffer to initialize. * @param capacity The number of bytes of space to allocate the buffer. * @return The buffer, for chaining. */ function init(buffer memory buf, uint256 capacity) internal pure returns (buffer memory) { if (capacity % 32 != 0) { capacity += 32 - (capacity % 32); } // Allocate space for the buffer data buf.capacity = capacity; assembly { let ptr := mload(0x40) mstore(buf, ptr) mstore(ptr, 0) mstore(0x40, add(32, add(ptr, capacity))) } return buf; } /** * @dev Initializes a new buffer from an existing bytes object. * Changes to the buffer may mutate the original value. * @param b The bytes object to initialize the buffer with. * @return A new buffer. */ function fromBytes(bytes memory b) internal pure returns (buffer memory) { buffer memory buf; buf.buf = b; buf.capacity = b.length; return buf; } function resize(buffer memory buf, uint256 capacity) private pure { bytes memory oldbuf = buf.buf; init(buf, capacity); append(buf, oldbuf); } function max(uint256 a, uint256 b) private pure returns (uint256) { if (a > b) { return a; } return b; } /** * @dev Sets buffer length to 0. * @param buf The buffer to truncate. * @return The original buffer, for chaining.. */ function truncate(buffer memory buf) internal pure returns (buffer memory) { assembly { let bufptr := mload(buf) mstore(bufptr, 0) } return buf; } /** * @dev Writes a byte string to a buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param off The start offset to write to. * @param data The data to append. * @param len The number of bytes to copy. * @return The original buffer, for chaining. */ function write( buffer memory buf, uint256 off, bytes memory data, uint256 len ) internal pure returns (buffer memory) { require(len <= data.length); if (off + len > buf.capacity) { resize(buf, max(buf.capacity, len + off) * 2); } uint256 dest; uint256 src; assembly { // Memory address of the buffer data let bufptr := mload(buf) // Length of existing buffer data let buflen := mload(bufptr) // Start address = buffer address + offset + sizeof(buffer length) dest := add(add(bufptr, 32), off) // Update buffer length if we're extending it if gt(add(len, off), buflen) { mstore(bufptr, add(len, off)) } src := add(data, 32) } // Copy word-length chunks while possible for (; len >= 32; len -= 32) { assembly { mstore(dest, mload(src)) } dest += 32; src += 32; } // Copy remaining bytes unchecked { uint256 mask = (256**(32 - len)) - 1; assembly { let srcpart := and(mload(src), not(mask)) let destpart := and(mload(dest), mask) mstore(dest, or(destpart, srcpart)) } } return buf; } /** * @dev Appends a byte string to a buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @param len The number of bytes to copy. * @return The original buffer, for chaining. */ function append( buffer memory buf, bytes memory data, uint256 len ) internal pure returns (buffer memory) { return write(buf, buf.buf.length, data, len); } /** * @dev Appends a byte string to a buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer, for chaining. */ function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) { return write(buf, buf.buf.length, data, data.length); } /** * @dev Writes a byte to the buffer. Resizes if doing so would exceed the * capacity of the buffer. * @param buf The buffer to append to. * @param off The offset to write the byte at. * @param data The data to append. * @return The original buffer, for chaining. */ function writeUint8( buffer memory buf, uint256 off, uint8 data ) internal pure returns (buffer memory) { if (off >= buf.capacity) { resize(buf, buf.capacity * 2); } assembly { // Memory address of the buffer data let bufptr := mload(buf) // Length of existing buffer data let buflen := mload(bufptr) // Address = buffer address + sizeof(buffer length) + off let dest := add(add(bufptr, off), 32) mstore8(dest, data) // Update buffer length if we extended it if eq(off, buflen) { mstore(bufptr, add(buflen, 1)) } } return buf; } /** * @dev Appends a byte to the buffer. Resizes if doing so would exceed the * capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer, for chaining. */ function appendUint8(buffer memory buf, uint8 data) internal pure returns (buffer memory) { return writeUint8(buf, buf.buf.length, data); } /** * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would * exceed the capacity of the buffer. * @param buf The buffer to append to. * @param off The offset to write at. * @param data The data to append. * @param len The number of bytes to write (left-aligned). * @return The original buffer, for chaining. */ function write( buffer memory buf, uint256 off, bytes32 data, uint256 len ) private pure returns (buffer memory) { if (len + off > buf.capacity) { resize(buf, (len + off) * 2); } unchecked { uint256 mask = (256**len) - 1; // Right-align data data = data >> (8 * (32 - len)); assembly { // Memory address of the buffer data let bufptr := mload(buf) // Address = buffer address + sizeof(buffer length) + off + len let dest := add(add(bufptr, off), len) mstore(dest, or(and(mload(dest), not(mask)), data)) // Update buffer length if we extended it if gt(add(off, len), mload(bufptr)) { mstore(bufptr, add(off, len)) } } } return buf; } /** * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the * capacity of the buffer. * @param buf The buffer to append to. * @param off The offset to write at. * @param data The data to append. * @return The original buffer, for chaining. */ function writeBytes20( buffer memory buf, uint256 off, bytes20 data ) internal pure returns (buffer memory) { return write(buf, off, bytes32(data), 20); } /** * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer, for chhaining. */ function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) { return write(buf, buf.buf.length, bytes32(data), 20); } /** * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer, for chaining. */ function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) { return write(buf, buf.buf.length, data, 32); } /** * @dev Writes an integer to the buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param off The offset to write at. * @param data The data to append. * @param len The number of bytes to write (right-aligned). * @return The original buffer, for chaining. */ function writeInt( buffer memory buf, uint256 off, uint256 data, uint256 len ) private pure returns (buffer memory) { if (len + off > buf.capacity) { resize(buf, (len + off) * 2); } uint256 mask = (256**len) - 1; assembly { // Memory address of the buffer data let bufptr := mload(buf) // Address = buffer address + off + sizeof(buffer length) + len let dest := add(add(bufptr, off), len) mstore(dest, or(and(mload(dest), not(mask)), data)) // Update buffer length if we extended it if gt(add(off, len), mload(bufptr)) { mstore(bufptr, add(off, len)) } } return buf; } /** * @dev Appends a byte to the end of the buffer. Resizes if doing so would * exceed the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer. */ function appendInt( buffer memory buf, uint256 data, uint256 len ) internal pure returns (buffer memory) { return writeInt(buf, buf.buf.length, data, len); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface OracleInterface { function fulfillOracleRequest( bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes32 data ) external returns (bool); function isAuthorizedSender(address node) external view returns (bool); function withdraw(address recipient, uint256 amount) external; function withdrawable() external view returns (uint256); }
// contracts/SVGGenerator.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; library StringLib { function intToString(int128 value) internal pure returns (string memory) { bool isNegative = false; uint256 uintValue = 0; if (value < 0) { isNegative = true; uintValue = uint256(int256(value * -1)); } else { isNegative = false; uintValue = uint256(int256(value)); } string memory uString = uintToString(uintValue); return isNegative ? concat("-", uString) : uString; } function uintToString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } function stringToUint(bytes memory b) internal pure returns (uint256) { uint result = 0; for (uint i = 0; i < b.length; i++) { // c = b[i] was not needed uint8 bInU8 = uint8(b[i]); if (bInU8 >= 48 /**0 */ && bInU8 <= 57 /**9 */) { result = result * 10 + (bInU8 - 48); // bytes and int are not compatible with the operator -. } } return result; // this was missing } function concat(string memory self, string memory other) internal pure returns (string memory) { return string(abi.encodePacked(self, other)); } function replace(string memory _str, string memory _pattern, string memory _replacement) internal pure returns (string memory res) { bytes memory _strBytes = bytes(_str); bytes memory pattern = bytes(_pattern); bytes memory _replacementBytes = bytes(_replacement); require(pattern.length > 0, "pattern's length should L.T. 0"); uint256 lastHitEndIndexPlus1 = 0; for (uint256 i = 0; i < _strBytes.length; i++) { //judge if hit bool hit = true; for (uint256 j = 0; j < pattern.length; j++) { if (_strBytes[i + j] != pattern[j]) { hit = false; break; } } if (hit) { //concat bytes from lastHitEndIndex to i res = string(abi.encodePacked( res, substring(_strBytes, lastHitEndIndexPlus1, i), _replacementBytes )); //update lastHitEndIndex lastHitEndIndexPlus1 = i + pattern.length; //move i to the tail of the pattern i += pattern.length - 1; } } //concat the last part after replace res = string(abi.encodePacked( res, substring(_strBytes, lastHitEndIndexPlus1, _strBytes.length) )); } function find(bytes memory str, bytes memory pattern) internal pure returns (uint256 index1, uint256 index2, bool exist) { uint times = 0; for (uint256 i = 0; i < str.length; i++) { //judge if hit bool hit = true; for (uint256 j = 0; j < pattern.length; j++) { if (str[i + j] != pattern[j]) { hit = false; break; } } if (hit == true) { if (times == 0) { index1 = i; } else if (times == 1) { index2 = i; } times ++; exist = true; } } } function substring(bytes memory strBytes, uint startIndex, uint endIndex) internal pure returns (bytes memory) { if (endIndex <= startIndex) { return bytes(""); } bytes memory result = new bytes(endIndex-startIndex); for(uint i = startIndex; i < endIndex; i++) { result[i-startIndex] = strBytes[i]; } return result; } /** hsl format is: hsl(60,100%,95%) */ function parseHSL(string memory hsl) internal pure returns (uint256 h, uint256 s, uint256 l) { (uint256 posOfFirstComma, uint256 posOfSecondComma, bool _success) = find(bytes(hsl), bytes(",")); bytes memory hslInBytes = bytes(hsl); h = stringToUint(substring(hslInBytes, 4/**hsl(*/, posOfFirstComma)); s = stringToUint(substring(hslInBytes, posOfFirstComma/**hsl(*/, posOfSecondComma - 1 /**remove %*/)); l = stringToUint(substring(hslInBytes, posOfSecondComma/**hsl(*/, hslInBytes.length - 2 /**remove %)*/)); } function parseCompressedHSL(bytes memory compressedHSLArray, uint256 index) internal pure returns (uint16, uint16, uint16) { uint256 length = compressedHSLArray.length; require(length % 8 == 0, "compressedHSLArray.length must be multiplier of 4"); require(length / 8 > index, "compressedHSLArray.length must be L.T. index"); index = index * 8; //for H(0-360) uint8 hHightestBit = fromHex(compressedHSLArray[index], compressedHSLArray[index + 1]); uint8 hLowestByte = fromHex(compressedHSLArray[index+2], compressedHSLArray[index + 3]); uint16 h = hHightestBit == 0 ? hLowestByte : uint16(256) + hLowestByte; //for S uint16 sLowest7Bits = fromHex(compressedHSLArray[index+4], compressedHSLArray[index + 5]); //for L uint16 lLowest7Bits = fromHex(compressedHSLArray[index+6], compressedHSLArray[index + 7]); return (h, sLowest7Bits, lLowest7Bits); } // Convert an hexadecimal string to raw bytes function fromHex(bytes1 high, bytes1 low) public pure returns (uint8) { return fromHexChar(uint8(high)) * 16 + fromHexChar(uint8(low)); } // Convert an hexadecimal character to their value function fromHexChar(uint8 c) public pure returns (uint8) { if (bytes1(c) >= bytes1("0") && bytes1(c) <= bytes1("9")) { return c - uint8(bytes1("0")); } else if (bytes1(c) >= bytes1("a") && bytes1(c) <= bytes1("f")) { return 10 + c - uint8(bytes1("a")); } else if (bytes1(c) >= bytes1("A") && bytes1(c) <= bytes1("F")) { return 10 + c - uint8(bytes1("A")); } } }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE FILE pragma solidity ^0.8.4; // This ABDKMath64x64 Library has a differnet license in /libraies/LICENSE.md import "./libraries/ABDKMath64x64.sol"; library XpMath { //64 bit decimal number pricision is 0.00000000000000000005421 //pi= 3.1415926535897932384626433832795 decimal= 2611928677177517772= 243f6f4b15d266cc //halfpi= 1.5707963267948966192313216916398 decimal= 10529354856943306017= 921fc8749a23c521 //quarterpi=0.7853981633974483096156608458198 decimal= 14488067946826200140= c90ff5095c4c744c //twopi= 6.2831853071795864769252867665590 decimal= 5223857354355035545= 487ede962ba4cd99 int128 private constant PI = 0x0000000000000003243F6F4B15D266CC; int128 private constant HALFPI = 0x0000000000000001921fc8749a23c521; int128 private constant QUARTERPI = 0x0000000000000000c90ff5095c4c744c; int128 private constant TWOPI = 0x0000000000000006487EDE962BA4CD99; //------------------FUNCTIONS FROM ABDKMath64x64----------------------------// /** * Convert signed 256-bit integer number into signed 64.64-bit fixed point * number. Revert on overflow. * * @param x signed 256-bit integer number * @return signed 64.64-bit fixed point number */ function fromInt(int256 x) internal pure returns (int128) { return ABDKMath64x64.fromInt(x); } /** * Convert signed 64.64 fixed point number into signed 64-bit integer number * rounding down. * * @param x signed 64.64-bit fixed point number * @return signed 64-bit integer number */ function toInt(int128 x) internal pure returns (int64) { return ABDKMath64x64.toInt(x); } /** * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point * number. Revert on overflow. * * @param x unsigned 256-bit integer number * @return signed 64.64-bit fixed point number */ function fromUInt(uint256 x) internal pure returns (int128) { return ABDKMath64x64.fromUInt(x); } /** * Convert signed 64.64 fixed point number into unsigned 64-bit integer * number rounding down. Revert on underflow. * * @param x signed 64.64-bit fixed point number * @return unsigned 64-bit integer number */ function toUInt(int128 x) internal pure returns (uint64) { return ABDKMath64x64.toUInt(x); } /** * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point * number rounding down. Revert on overflow. * * @param x signed 128.128-bin fixed point number * @return signed 64.64-bit fixed point number */ function from128x128(int256 x) internal pure returns (int128) { return ABDKMath64x64.from128x128(x); } /** * Convert signed 64.64 fixed point number into signed 128.128 fixed point * number. * * @param x signed 64.64-bit fixed point number * @return signed 128.128 fixed point number */ function to128x128(int128 x) internal pure returns (int256) { return ABDKMath64x64.to128x128(x); } /** * Calculate x + y. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function add(int128 x, int128 y) internal pure returns (int128) { return ABDKMath64x64.add(x, y); } /** * Calculate x - y. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function sub(int128 x, int128 y) internal pure returns (int128) { return ABDKMath64x64.sub(x, y); } /** * Calculate x * y rounding down. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function mul(int128 x, int128 y) internal pure returns (int128) { return ABDKMath64x64.mul(x, y); } /** * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point * number and y is signed 256-bit integer number. Revert on overflow. * * @param x signed 64.64 fixed point number * @param y signed 256-bit integer number * @return signed 256-bit integer number */ function muli(int128 x, int256 y) internal pure returns (int256) { return ABDKMath64x64.muli(x, y); } /** * Calculate x * y rounding down, where x is signed 64.64 fixed point number * and y is unsigned 256-bit integer number. Revert on overflow. * * @param x signed 64.64 fixed point number * @param y unsigned 256-bit integer number * @return unsigned 256-bit integer number */ function mulu(int128 x, uint256 y) internal pure returns (uint256) { return ABDKMath64x64.mulu(x, y); } /** * Calculate x / y rounding towards zero. Revert on overflow or when y is * zero. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function div(int128 x, int128 y) internal pure returns (int128) { return ABDKMath64x64.div(x, y); } /** * Calculate x / y rounding towards zero, where x and y are signed 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x signed 256-bit integer number * @param y signed 256-bit integer number * @return signed 64.64-bit fixed point number */ function divi(int256 x, int256 y) internal pure returns (int128) { return ABDKMath64x64.divi(x, y); } /** * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x unsigned 256-bit integer number * @param y unsigned 256-bit integer number * @return signed 64.64-bit fixed point number */ function divu(uint256 x, uint256 y) internal pure returns (int128) { return ABDKMath64x64.divu(x, y); } /** * Calculate -x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function neg(int128 x) internal pure returns (int128) { return ABDKMath64x64.neg(x); } /** * Calculate |x|. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function abs(int128 x) internal pure returns (int128) { return ABDKMath64x64.abs(x); } /** * Calculate 1 / x rounding towards zero. Revert on overflow or when x is * zero. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function inv(int128 x) internal pure returns (int128) { return ABDKMath64x64.inv(x); } /** * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function avg(int128 x, int128 y) internal pure returns (int128) { return ABDKMath64x64.avg(x, y); } /** * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down. * Revert on overflow or in case x * y is negative. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function gavg(int128 x, int128 y) internal pure returns (int128) { return ABDKMath64x64.gavg(x, y); } /** * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number * and y is unsigned 256-bit integer number. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y uint256 value * @return signed 64.64-bit fixed point number */ function pow(int128 x, uint256 y) internal pure returns (int128) { return ABDKMath64x64.pow(x, y); } /** * Calculate sqrt (x) rounding down. Revert if x < 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function sqrt(int128 x) internal pure returns (int128) { return ABDKMath64x64.sqrt(x); } /** * Calculate binary logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function log_2(int128 x) internal pure returns (int128) { return ABDKMath64x64.log_2(x); } /** * Calculate natural logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function ln(int128 x) internal pure returns (int128) { return ABDKMath64x64.ln(x); } /** * Calculate binary exponent of x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function exp_2(int128 x) internal pure returns (int128) { return ABDKMath64x64.exp_2(x); } /** * Calculate natural exponent of x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function exp(int128 x) internal pure returns (int128) { return ABDKMath64x64.exp(x); } //------------------FUNCTIONS FROM ABDKMath64x64 END-------------------------// /** * Calculate sine of x. Revert on overflow. * use y = 0.987862x - 0.155271x^3 + 0.00564312x^5 * a=0.987862 = 18222874008485519276= fce4a75c9e7a5fac * b=0.155271 = 2864250138350857775 = 27bfdc534c442e2f * c=0.00564312=104097399003873824 = 0171d40869ab0220 * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function sin(int128 x) internal pure returns (int128) { //this approximation only for x in range [-pi/2,pi/2] while (x > PI) { x = sub(x, TWOPI); } while (x < neg(PI)) { x = add(x, TWOPI); } if(abs(sub(x,HALFPI))<divi(1,100)){ return fromUInt(1); } if(abs(sub(x,neg(HALFPI)))<divi(1,100)){ return neg(fromUInt(1)); } if(abs(sub(x,PI))<divi(1,50)||abs(sub(x,neg(PI)))<divi(1,50)){ return fromUInt(0); } if(x<0){ return neg(sin(neg(x))); } if(x>=HALFPI){ return (sin(sub(PI,x))); } // next line use tylar approximation // sin(x) =x - x^3/6 + x^5/120 - x^7/5040 + x^9/362880 - x^11/39916800 int128 tmp=sub(x,div(pow(x,3),fromUInt(6))); tmp=add(tmp,div(pow(x,5),fromUInt(120))); tmp=sub(tmp,div(pow(x,7),fromUInt(5040))); //tmp=add(tmp,div(pow(x,9),fromUInt(362880))); //tmp=sub(tmp,divi(pow(x,11),39916800)); return tmp; } function cos(int128 x) internal pure returns (int128) { return sin(add(x, HALFPI)); } }
// SPDX-License-Identifier: MIT /// @title Base64 /// @notice Provides a function for encoding some bytes in base64 /// @author Brecht Devos <[email protected]> pragma solidity ^0.8.4; library Base64 { bytes internal constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /// @notice Encodes some bytes to the base64 representation function encode(bytes memory data) internal pure returns (string memory) { uint256 len = data.length; if (len == 0) return ""; // multiply by 4/3 rounded up uint256 encodedLen = 4 * ((len + 2) / 3); // Add some extra buffer at the end bytes memory result = new bytes(encodedLen + 32); bytes memory table = TABLE; assembly { let tablePtr := add(table, 1) let resultPtr := add(result, 32) for { let i := 0 } lt(i, len) { } { i := add(i, 3) let input := and(mload(add(data, i)), 0xffffff) let out := mload(add(tablePtr, and(shr(18, input), 0x3F))) out := shl(8, out) out := add( out, and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF) ) out := shl(8, out) out := add( out, and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF) ) out := shl(8, out) out := add( out, and(mload(add(tablePtr, and(input, 0x3F))), 0xFF) ) out := shl(224, out) mstore(resultPtr, out) resultPtr := add(resultPtr, 4) } switch mod(len, 3) case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) } case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) } mstore(result, encodedLen) } return string(result); } }
// contracts/SVGGenerator.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "./StringLib.sol"; import "./DateUtils.sol"; contract FireGenerator { string constant GROUP_START = "<g>"; string constant GROUP_END = "</g>"; string constant EMPTY = ""; //<body> // <signsAndCuspsAndPlanetRelations> // <signLines> // </signLines> // <signTexts> // </signTexts> // <cuspsAndPlanetRelations> // </cuspsAndPlanetRelations> // </signsAndCuspsAndPlanetRelations> // <fire> // </fire> // <circles> // </circles> // <planets> // </planets> // <centralTexts> // </centralTexts> //</body> //sign lines string constant signLines = '<line x1="942.9036" y1="691.8807" x2="996.0295" y2="706.1158" stroke-width="1"/>' '<line x1="942.9036" y1="508.1192" x2="996.0295" y2="493.8841" stroke-width="1"/>' '<line x1="851.0229" y1="348.9770" x2="889.9137" y2="310.0862" stroke-width="1"/>' '<line x1="691.8807" y1="257.0963" x2="706.1158" y2="203.9704" stroke-width="1"/>' '<line x1="508.1192" y1="257.0963" x2="493.8841" y2="203.9704" stroke-width="1"/>' '<line x1="348.9770" y1="348.9770" x2="310.0862" y2="310.0862" stroke-width="1"/>' '<line x1="257.0963" y1="508.1192" x2="203.9704" y2="493.8841" stroke-width="1"/>' '<line x1="257.0963" y1="691.8807" x2="203.9704" y2="706.1158" stroke-width="1"/>' '<line x1="348.9770" y1="851.0229" x2="310.0862" y2="889.9137" stroke-width="1"/>' '<line x1="691.8807" y1="942.9036" x2="706.1158" y2="996.0295" stroke-width="1"/>' '<line x1="851.0229" y1="851.0229" x2="889.9137" y2="889.9137" stroke-width="1"/>' '<line x1="508.1192" y1="942.9036" x2="493.8841" y2="996.0295" stroke-width="1"/>'; string constant signLines_tail = GROUP_END; //sign texts string constant signTexts = '<text font-size="25" transform="translate(990, 635) rotate(-90)" fill="#ac303e" font-weight="bold" stroke="none">ARIES</text>' '<text font-size="25" transform="translate(895, 370) rotate(60)" fill="#e8cc5e" font-weight="bold" stroke="none">TAURUS</text>' '<text font-size="25" transform="translate(750, 255) rotate(30)" fill="#026d49" font-weight="bold" stroke="none">GEMINI</text>' '<text font-size="25" transform="translate(545, 230) rotate(0)" fill="#2478d2" font-weight="bold" stroke="none">CANCER</text>' '<text font-size="25" transform="translate(395, 290) rotate(-30)" fill="#ac303e" font-weight="bold" stroke="none">LEO</text>' '<text font-size="25" transform="translate(260, 445) rotate(-60)" fill="#e8cc5e" font-weight="bold" stroke="none">VIRGO</text>' '<text font-size="25" transform="translate(210, 565) rotate(90)" fill="#026d49" font-weight="bold" stroke="none">LIBRA</text>' '<text font-size="25" transform="translate(235, 750) rotate(60)" fill="#1d81d9" font-weight="bold" stroke="none">SCORPIO</text>' '<text font-size="25" transform="translate(335, 895) rotate(30)" fill="#ac303e" font-weight="bold" stroke="none">SAGITTARIUS</text>' '<text font-size="25" transform="translate(525, 990) rotate(0)" fill="#e8cc5e" font-weight="bold" stroke="none">CAPRICORN</text>' '<text font-size="25" transform="translate(740, 970) rotate(-30)" fill="#026d49" font-weight="bold" stroke="none">AQUARIUS</text>' '<text font-size="25" transform="translate(920, 830) rotate(-60)" fill="#2478d2" font-weight="bold" stroke="none">PISCES</text>'; string constant signTexts_tail = GROUP_END; string constant cuspsAndPlanetRelations_tail = GROUP_END; string constant fireTemplate = '<g filter="url(#goo)" clip-path="url(#centerCut)" stroke="none" transform="translate(240, 240) scale(0.6)">' '<circle class="f1" cy="753" cx="579" r="80" fill="#000000"/>' '<circle class="f2" cy="751" cx="622" r="80" fill="#000000"/>' '<circle class="f3" cy="770" cx="648" r="80" fill="#000000"/>' '<circle class="f4" cy="755" cx="614" r="80" fill="#000000"/>' '<circle class="f5" cy="744" cx="591" r="80" fill="#000000"/>' '<circle class="f6" cy="748" cx="572" r="80" fill="#000000"/>' '<circle class="f7" cy="746" cx="651" r="80" fill="#000000"/>' '<circle class="f8" cy="751" cx="604" r="80" fill="#000000"/>' '<circle class="f9" cy="734" cx="595" r="80" fill="#000000"/>' '<circle class="f10" cy="743" cx="569" r="80" fill="#000000"/>' '<circle class="f11" cy="758" cx="559" r="80" fill="#000000"/>' '<circle class="f12" cy="731" cx="632" r="80" fill="#000000"/>' '<circle class="f13" cy="737" cx="585" r="80" fill="#000000"/>' '<circle class="f14" cy="760" cx="616" r="80" fill="#000000"/>' '<circle class="f15" cy="752" cx="630" r="80" fill="#000000"/>' '<circle class="r1" cy="850" cx="600" r="90" fill="black"/>' '<circle class="r2" cy="850" cx="600" r="80" fill="black"/>' '<circle class="r3" cy="850" cx="600" r="80" fill="black"/>' '<circle class="r4" cy="850" cx="600" r="70" fill="black"/>' '<circle class="r5" cy="850" cx="600" r="60" fill="black"/>' '<circle class="r6" cy="850" cx="600" r="80" fill="black"/>' '<circle class="r7" cy="850" cx="600" r="70" fill="black"/>' '<circle class="r8" cy="850" cx="600" r="80" fill="black"/>' '</g>'; string constant circles_body = "</circle>" '<circle cx="600" cy="600" r="430" stroke-width="1" fill="none"/>' '<circle cx="600" cy="600" r="420" stroke-width="1" fill="none"/>' '<circle cx="600" cy="600" r="410" stroke-width="1" fill="none"/>' '<circle cx="600" cy="600" r="400" stroke-width="10" fill="none" stroke-dasharray="1 62">' '<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 600 600" to="360 600 600" begin="0" dur="60s" repeatCount="indefinite"/>' "</circle>" '<circle cx="600" cy="600" r="355" stroke-width="2" fill="none"/>' '<circle cx="600" cy="600" r="230" stroke-width="2" fill="none"/>' '<circle cy="600" cx="600" r="85" fill="none" stroke-width="8" />' '<circle cy="600" cx="600" r="95" fill="none" stroke-width="2" />' ; string constant circles_tail = GROUP_END; //planets container head string constant planets_head = GROUP_START; //planets container tail string constant planets_tail = GROUP_END; string constant body_tail = GROUP_END; function toHexString(uint24 number) private pure returns (string memory str) { bytes memory HEX = "0123456789ABCDEF"; bytes memory wholeNumber = new bytes(6); for (uint256 i = 0; i < 6; i++) { uint256 c = (number >> (4 * i)) & 0xF; //c will be between 0 and 15 wholeNumber[5 - i] = HEX[c]; } str = string(wholeNumber); } function replace(string memory _str, string memory _replacement) private pure returns (string memory res) { bytes memory _strBytes = bytes(_str); bytes memory pattern = bytes("#0"); bytes memory _replacementBytes = bytes(_replacement); require(_replacementBytes.length == 6, _replacement); for (uint256 i = 1; i < _strBytes.length; i++) { if (_strBytes[i] == pattern[1]&& _strBytes[i-1] == pattern[0]) { for (uint256 j = 0; j < 6; j++) { _strBytes[i + j] = _replacementBytes[j]; } i += 6; } } res = string(_strBytes); } function pickValueFromArrayByGenAndElement(string[5] memory arraySize5, bool isGen0, ElementType elementType) private pure returns (string memory) { require(arraySize5.length == 5, "arraySize5's length is not 5"); if (isGen0) { if (elementType == ElementType.FIRE) { return arraySize5[1]; } else if (elementType == ElementType.EARTH) { return arraySize5[2]; } else if (elementType == ElementType.WATER) { return arraySize5[3]; } else /**if (elementType == ElementType.WIND)*/ { return arraySize5[4]; } } else /**if (!isGen0)*/ { return arraySize5[0]; } } function drawSignsAndCuspsInOnGroup(bool isGen0, ElementType elementType, string memory cusps, string memory planetRelationLines) private pure returns (string memory) { string[5] memory signsAndCuspsAndPlanetRelations_head = [ EMPTY, '<g filter="url(#light3)">', EMPTY, EMPTY, EMPTY ]; string[5] memory signsAndCuspsAndPlanetRelations_tail = [EMPTY, GROUP_END, EMPTY, EMPTY, EMPTY]; return string(abi.encodePacked( pickValueFromArrayByGenAndElement(signsAndCuspsAndPlanetRelations_head, isGen0, elementType), drawSignLinesInGroup(isGen0, elementType), drawSignTextInGroup(isGen0, elementType), drawCuspsAndPlanetRelationsInGroup(isGen0, elementType, cusps, planetRelationLines), pickValueFromArrayByGenAndElement(signsAndCuspsAndPlanetRelations_tail, isGen0, elementType) )); } function drawSignLinesInGroup(bool isGen0, ElementType elementType) private pure returns (string memory) { string[5] memory signLines_head = [ GROUP_START, '<g filter="url(#light2)">', GROUP_START, GROUP_START, GROUP_START ]; return string(abi.encodePacked( pickValueFromArrayByGenAndElement(signLines_head, isGen0, elementType), signLines, signLines_tail )); } function drawSignTextInGroup(bool isGen0, ElementType elementType) private pure returns (string memory) { string[5] memory signTexts_head = [ GROUP_START, GROUP_START, GROUP_START, '<g><circle cx="600" cy="600" r="382" stroke-width="55" stroke="rgba(79,179,191,0.2)" fill="none" />', GROUP_START ]; return string(abi.encodePacked( pickValueFromArrayByGenAndElement(signTexts_head, isGen0, elementType), signTexts, signTexts_tail )); } function drawCuspsAndPlanetRelationsInGroup(bool isGen0, ElementType elementType, string memory cusps, string memory planetRelationLines) private pure returns (string memory) { string[5] memory cuspsAndPlanetRelations_head = [ GROUP_START, '<g filter="url(#light2)">', GROUP_START, GROUP_START, GROUP_START ]; return string(abi.encodePacked( pickValueFromArrayByGenAndElement(cuspsAndPlanetRelations_head, isGen0, elementType), cusps, planetRelationLines, cuspsAndPlanetRelations_tail )); } function completeChartBody(GenAndElement memory genAndElement, ParamsPart2 memory paramsPart2) public pure returns (string memory) { string[5] memory body_head = [ '<g fill="url(#goldBody)" stroke="url(#goldBody)">', '<g stroke="#e37da2" fill="#e37da2">', '<g stroke="url(#gradient)" fill="url(#gradient)">', '<g stroke="#4fb3bf" fill="#4fb3bf">', '<g stroke="url(#gradient)" fill="url(#gradient)">' ]; bool isGen0 = genAndElement.isGen0; ElementType elementType = genAndElement.elementType; string memory originBodyHead = pickValueFromArrayByGenAndElement(body_head, isGen0, elementType); string memory bodyHead = replaceThemeColor(isGen0, elementType, paramsPart2.month, paramsPart2.day, originBodyHead); return string(abi.encodePacked( bodyHead, drawSignsAndCuspsInOnGroup(isGen0, elementType, genAndElement.cuspsBody, paramsPart2.relationLines), drawFire(genAndElement.planets), drawCircles(isGen0, elementType), drawPlanets(genAndElement.planetsBody), drawCentralTexts(paramsPart2.centralText), body_tail )); } function drawFire(uint16[] memory planets) private pure returns (string memory) { //15deg=0.2618 //FIRE red, EARTH yellow, WIND green, WATER blue uint16 red = 0; uint16 green = 0; uint16 blue = 0; uint8[6] memory index = [10, 0, 1, 2, 3, 4]; for (uint256 i = 0; i < index.length; i++) { ElementType elementType = judgeElementTypeByPlanetDegree(planets[index[i]]); if (elementType == ElementType.FIRE) { red += 43;// 255/6 } else if (elementType == ElementType.EARTH) { red += 43; green += 43; } else if (elementType == ElementType.WIND) { green += 43; } else /** if (elementType == ElementType.WATER)*/ { blue += 43; } } red = red > 255 ? 255 : red; green = green > 255 ? 255 : green; blue = blue > 255 ? 255 : blue; uint24 color = red * 65536 + green * 256 + blue; string memory hexColor = toHexString(color); return replace(fireTemplate, hexColor); } function drawCircles(bool isGen0, ElementType elementType) private pure returns (string memory) { string[5] memory circles_head = [ GROUP_START, '<g filter="url(#light2)">', GROUP_START, GROUP_START, GROUP_START ]; string[5] memory circle_first = [ '<circle cx="600" cy="600" r="450" stroke-width="15" fill="none">''<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 600 600" to="360 600 600" begin="0" dur="5s" repeatCount="indefinite"/>', '<circle cx="600" cy="600" r="450" stroke-width="15" fill="none">''<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 600 600" to="360 600 600" begin="0" dur="5s" repeatCount="indefinite"/>', '<circle cx="600" cy="600" r="450" stroke-width="15" fill="none">''<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 600 600" to="360 600 600" begin="0" dur="5s" repeatCount="indefinite"/>', '<circle cx="600" cy="600" r="450" stroke-width="15" fill="none" stroke-dasharray="260 20">''<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 600 600" to="360 600 600" begin="0" dur="30s" repeatCount="indefinite" />', '<circle cx="600" cy="600" r="450" stroke-width="15" fill="none">''<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 600 600" to="360 600 600" begin="0" dur="5s" repeatCount="indefinite"/>' ]; return string(abi.encodePacked( pickValueFromArrayByGenAndElement(circles_head, isGen0, elementType), pickValueFromArrayByGenAndElement(circle_first, isGen0, elementType), circles_body, circles_tail )); } function drawPlanets(string memory planets) private pure returns(string memory) { return string(abi.encodePacked( planets_head, planets, planets_tail )); } function drawCentralTexts(string memory centralText) private pure returns(string memory) { return centralText; } function genThemeColorReplacement(bool isGen0, ElementType elementType, uint16 month, uint16 day) private pure returns(string memory) { bytes memory birthdayColorInHex = bytes("003c645f0078095b00f0014500c003390140032c01460b280115640500413732004b421f004a252900592c4a00612a560083322b004b23290098641100493d5b00a66416007d1925004e3136009d382400c5484f00b8642300c9463600c3641c00de45130031364d003a643200336432004347320070262d00473c5100e5282a013c283900eb3b2001411c4901072a2301372251013a2138015c2f1d015b503d01544d4101524134015842340056042300361d2300cc474900ce274b00d51526000e321d00de361d002a645b00376450002d6035003664400048304f00560e5a0071104e003f183600422d1c006427270010534e0016575f015a4b5300024f3e015e632900005462000f524c01674c4f00064f5201665039002b4f5100004b3e0010533b00074d3301674d2f0139224a011d1c3301271b31011c4c1a012b152d00f41f4a013e2739010c1e2f012e252b01593130006f21540094245200af224b00be2e4c00c6553e0034474c015b4e6100155759015451500153404700da314400ca343d0046385c00831f38002b604100284f34001f2c57002c133800870a5c00f0013b006e085500ca09520000003601180227000c042000473f4000473d4b00883c29008b2843007128490084263e006c2b3a009d642200a9641d00b7642300b7642500b664200099641e00b76316009c610d00bc315300c9574600dd2932008e241e007b3d2c003d47580041453b003d4c3b00373f48003451190035304200353e28002932250000001c0043071c009b2544008d2029008c5e1400895c0e0099201600205b5000275c49002c643100183f2c000e1b260005225700024d4b011a1c4801031e3201244019003c425b004a3a51003a3849006f0d2c00333c1a00376453003864430034643100285f4300306432002f395e0016574e0025343401633a4a00081a24002b6049001f563d0026643000083727000a2b210160545601573d460156503f01604c4e0155632900c5425400d6313700c4641e00ce642400d5641c00c03f3600bd282d00bb313900bd631700c2641b001e0c6100d42e3a00dc243300d35e1b00dd3b180012565f01381f3a00db314800e61e3801294e1e00055550001c4740000d3337016531310165412c0161534e01503b450166352d015c2f260000001a00c2642400b4642000ca5e1900ca2e3100c5642a00c83a3500cc642100d9452600d2641e00d4621c00d05c1c00df2e1700db2c2c0125261a00f2154700b92f4300c64d3d00326436003964510039644b00235b3f00236431002164300010433d0023644c00296432002a3e3000282e3e0023401e00c5464e00c92c3800d52b3300d4352d012e43110077203d008f2c2600ad62140096641500a96411009d640c00b8293c00b6243900b9641500ef361400a0640a00ed2f1e00f0271a001b3332001a641c000a2c360078203e00cf1f50010a063100396458004c3356003d474e003b4e4100394336001f62470014583d000c563f00094d2f01534e3e012a24290012533d000d4c200012543900125533000e2a3f001b283a001e252b000e382e00173f1e00253131000c2a340012481e000a262000113d180015472b0030642e001c0e52003c054e00f0044600000031015f093b00a50324002d3b3800462b1f00130b3a00a2182b00b415230118022b00170c24015a182a011b1f5000172f3500251f2a00182d180012071e0147071d0025644b00226344001c5c36000e3c340021372400256454002f264e005a013f002c3416002c34130000575601473744000921390165253400ff043200471a4b00581549002c113700d2013100a008190015614e00205b580020422b001e1f2a0034101d0023214d00212a41000c451f002b102000330f1b00293d4b00313c4c0034402800252536001f4129000d5c530008584b000856460019642f0163223600125f57002a40520008213900254140015a0b29013e295001071e3c010b282b01042210012e1d28002d503400421140002b4d2e0029193c001c432a00bd6428"); if(!isGen0) { return EMPTY; } else { uint256 index = DateUtils.getDayIndexInYear(2012, month, day); (uint256 H, uint256 S, uint256 L) = StringLib.parseCompressedHSL(birthdayColorInHex, index); string memory birthdayColor = string(abi.encodePacked("hsl(", StringLib.uintToString(H), ",", StringLib.uintToString(S), "%,", StringLib.uintToString(L), "%)")); if(elementType == ElementType.FIRE || elementType == ElementType.WATER) { return birthdayColor; } else { if (elementType == ElementType.EARTH) { H = (H + 360 - 90) % 360; /** maintain H > 30, normally minus 90 */ string memory res = string(abi.encodePacked( '<stop offset="0%" stop-color="', birthdayColor, '" />' '<stop offset="100%" stop-color="hsl(', StringLib.uintToString(H), ",", StringLib.uintToString(S), "%,", StringLib.uintToString(L), '%)" />' )); return res; } else /** if (elementType == ElementType.WIND) */ { S = (S + 30) % 100; L = (L + 100 - 30) % 100; string memory line_70 = string(abi.encodePacked( '<stop offset="100%" stop-color="hsl(', StringLib.uintToString(H), ",", StringLib.uintToString(S), "%,", StringLib.uintToString(L), '%)" />' )); string memory line_100 = line_70; string memory res = string(abi.encodePacked( '<stop offset="0%" stop-color="', birthdayColor, '" />', line_70, line_100 )); return res; } } } } function replaceThemeColor(bool isGen0, ElementType elementType, uint16 month, uint16 day, string memory _str) public pure returns (string memory) { string[5] memory colorPatternToReplace = [ EMPTY, "#e37da2", '<stop offset="0%" stop-color="hsl(211,54.4%,62.2%)" /><stop offset="100%" stop-color="hsl(121,54.4%,62.2%)" />', "#4fb3bf", '<stop offset="0%" stop-color="hsl(49,26%,63%)" />''<stop offset="70%" stop-color="hsl(49,56%,43%)" />''<stop offset="100%" stop-color="hsl(49,56%,43%)" />' ]; string memory pattern = pickValueFromArrayByGenAndElement(colorPatternToReplace, isGen0, elementType); string memory replacement = genThemeColorReplacement(isGen0, elementType, month, day); return bytes(pattern).length == 0 ? _str : StringLib.replace(_str, pattern, replacement); } enum ElementType { FIRE, EARTH, WIND, WATER } struct GenAndElement { bool isGen0; ElementType elementType; string cuspsBody; string planetsBody; uint16[] planets; } struct ParamsPart2 { string relationLines; string centralText; uint16 month; uint16 day; } /** ElementType's */ function judgeElementTypeByPlanetDegree(uint16 planetRadian) public pure returns (ElementType) { uint16 degree30InRadian = 5236; uint16 deg15InRadian = 2618; uint16 signIndex = (planetRadian + deg15InRadian) / degree30InRadian; if (signIndex == 0 || signIndex == 4 || signIndex == 8) { return ElementType.FIRE; } else if (signIndex == 1 || signIndex == 5 || signIndex == 9) { return ElementType.EARTH; } else if (signIndex == 2 || signIndex == 6 || signIndex == 10) { return ElementType.WIND; } else /** if (signIndex == 3 || signIndex = 7 || signIndex == 11) */ { return ElementType.WATER; } } }
// contracts/SVGGenerator.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "./FireGenerator.sol"; library FireGenerator2 { string constant part0 = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1200" height="1200" id="astro">' "<style>" ".f1 {" "animation: fc1 2s 0.14s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f2 {" "animation: fc2 2s 0.28s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f3 {" "animation: fc3 2s 0.42s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f4 {" "animation: fc4 2s 0.56s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f5 {" "animation: fc5 2s 0.7s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f6 {" "animation: fc6 2s 0.84s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f7 {" "animation: fc7 2s 0.98s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f8 {" "animation: fc8 2s 1.12s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f9 {" "animation: fc9 2s 1.26s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f10 {" "animation: fc10 2s 1.4s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f11 {" "animation: fc11 2s 1.54s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f12 {" "animation: fc12 2s 1.68s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f13 {" "animation: fc13 2s 1.82s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f14 {" "animation: fc14 2s 1.96s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".f15 {" "animation: fc15 2s 2.1s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".r1 {" "animation: fr1 2s 0.5s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".r2 {" "animation: fr2 2s 1s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".r3 {" "animation: fr3 2s 1.5s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".r4 {" "animation: fr4 2s 2s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".r5 {" "animation: fr5 1.5s 0.5s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".r6 {" "animation: fr6 1.5s 1s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".r7 {" "animation: fr7 1.5s 1.5s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" ".r8 {" "animation: fr8 1.5s 2s cubic-bezier(0.5, 0.07, 0.64, 1) infinite;" "}" "@keyframes fc1 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(552px, 350px) scale(0);" "}" "}" "@keyframes fc2 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(652px, 350px) scale(0);" "}" "}" "@keyframes fc3 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(564px, 350px) scale(0);" "}" "}" "@keyframes fc4 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(577px, 350px) scale(0);" "}" "}" "@keyframes fc5 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(679px, 350px) scale(0);" "}" "}" "@keyframes fc6 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(563px, 350px) scale(0);" "}" "}" "@keyframes fc7 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(591px, 350px) scale(0);" "}" "}" "@keyframes fc8 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(668px, 350px) scale(0);" "}" "}" "@keyframes fc9 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(546px, 350px) scale(0);" "}" "}" "@keyframes fc10 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(586px, 350px) scale(0);" "}" "}" "@keyframes fc11 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(604px, 350px) scale(0);" "}" "}" "@keyframes fc12 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(641px, 350px) scale(0);" "}" "}" "@keyframes fc13 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(549px, 350px) scale(0);" "}" "}" "@keyframes fc14 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(638px, 350px) scale(0);" "}" "}" "@keyframes fc15 {" "0% {" "transform: translate(0, 0) scale(1);" "}" "100% {" "transform: translate(629px, 350px) scale(0);" "}" "}" "@keyframes fr1 {" "0% {" "transform: translate(288px, 631px) scale(0.3);" "}" "100% {" "transform: translate(0px, -450px) scale(1);" "}" "}" "@keyframes fr2 {" "0% {" "transform: translate(264px, 599px) scale(0.3);" "}" "100% {" "transform: translate(0px, -450px) scale(1);" "}" "}" "@keyframes fr3 {" "0% {" "transform: translate(257px, 576px) scale(0.3);" "}" "100% {" "transform: translate(0px, -450px) scale(1);" "}" "}" "@keyframes fr4 {" "0% {" "transform: translate(295px, 614px) scale(0.3);" "}" "100% {" "transform: translate(0px, -450px) scale(1);" "}" "}" "@keyframes fr5 {" "0% {" "transform: translate(585px, 611px) scale(0.3);" "}" "100% {" "transform: translate(0px, -450px) scale(1);" "}" "}" "@keyframes fr6 {" "0% {" "transform: translate(611px, 601px) scale(0.3);" "}" "100% {" "transform: translate(0px, -450px) scale(1);" "}" "}" "@keyframes fr7 {" "0% {" "transform: translate(607px, 591px) scale(0.3);" "}" "100% {" "transform: translate(0px, -450px) scale(1);" "}" "}" "@keyframes fr8 {" "0% {" "transform: translate(597px, 626px) scale(0.3);" "}" "100% {" "transform: translate(0px, -450px) scale(1);" "}" "}" "</style>" "<defs>" '<radialGradient id="darkLight">' '<stop offset="0%" stop-color="#484848"/>' '<stop offset="3%" stop-color="#1b1b1b"/>' '<stop offset="8%" stop-color="#000000"/>' "</radialGradient>" '<linearGradient id="goldBody" gradientTransform="rotate(60)">' '<stop offset="0%" stop-color="#'; //insert color string constant part1 = '"/><stop offset="100%" stop-color="#'; //insert color string constant part2 = '"/>' "</linearGradient>"; string constant part2_0_gen0_fire = '<filter id="light0">' '<feDropShadow dx="0" dy="0" stdDeviation="2" flood-color="#e37da2" />' '</filter>' '<filter id="light1">' '<feDropShadow dx="0" dy="0" stdDeviation="2" flood-color="#e37da2" />' '</filter>' '<filter id="light2">' '<feGaussianBlur in="SourceGraphic" stdDeviation="1" />' '<feDropShadow dx="0" dy="0" stdDeviation="6" flood-color="#e37da2" />' '</filter>' '<filter id="light3">' '<feDropShadow dx="0" dy="0" stdDeviation="10" flood-color="#e37da2" />' '</filter>' '<filter id="light4">' '<feGaussianBlur in="SourceGraphic" stdDeviation="1" />' '<feDropShadow dx="0" dy="0" stdDeviation="40" flood-color="#e37da2" />' '</filter>'; string constant part2_0_gen0_earth = '<linearGradient id="gradient" gradientTransform="rotate(60)">' '<stop offset="0%" stop-color="hsl(211,54.4%,62.2%)" />' '<stop offset="100%" stop-color="hsl(121,54.4%,62.2%)" />' '</linearGradient>'; string constant part2_0_gen0_wind = '<linearGradient id="gradient" gradientTransform="rotate(60)">' '<stop offset="0%" stop-color="hsl(49,26%,63%)" />' '<stop offset="70%" stop-color="hsl(49,56%,43%)" />' '<stop offset="100%" stop-color="hsl(49,56%,43%)" />' '</linearGradient>'; string constant part2_0_gen0_water = '<linearGradient id="gradient" gradientTransform="rotate(60)">' '<stop offset="0%" stop-color="#f19cbc" />' '<stop offset="100%" stop-color="#e37da2" />' '</linearGradient>'; string constant part2_0_gen1 = ""; string constant part2_1 = '<filter id="goo">' '<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur"/>' '<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -8" result="goo"/>' '<feBlend in="SourceGraphic" in2="goo"/>' "</filter>" '<clipPath id="centerCut">' '<circle cy="600" cx="600" r="140" stroke-width="120"/>' '</clipPath>' "</defs>"; string constant part2_2_gen0_fire = '<circle cx="300" cy="300" r="1300" fill="#000">'; string constant part2_2_gen0_earth = part2_2_gen0_fire; string constant part2_2_gen0_wind = '<circle cx="300" cy="300" r="1300" fill="url(#darkLight)">'; string constant part2_2_gen0_water = part2_2_gen0_fire; string constant part2_2_gen1 = part2_2_gen0_earth; string constant part2_3 = '<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 600 600" to="360 600 600" begin="0" dur="5s" repeatCount="indefinite"/>' "</circle>"; //begin draw border lines string constant part_3_0_gen0_fire = '<g stroke="#e37da2" stroke-width="4" filter="url(#light0)">' '<rect width="1180" height="1180" x="10" y="10" stroke-width="4" fill="none" rx="18" />' '<line x1="29.999" y1="30" x2="29.999" y2="1170" stroke-linecap="round" stroke-linejoin="round" />' '<line x1="1169.999" y1="30" x2="1169.999" y2="1170" stroke-linecap="round" stroke-linejoin="round" />' '<line x1="600.499" y1="-555.5" x2="600.499" y2="583.5" stroke-linecap="round" stroke-linejoin="round" transform="translate(600.499000, 30.000000) scale(1, -1) rotate(90.000000) translate(-600.499000, -14.000000) " />' '<line x1="599.999" y1="600" x2="599.999" y2="1740" stroke-linecap="round" stroke-linejoin="round" transform="translate(599.999000, 1170.000000) scale(1, -1) rotate(90.000000) translate(-600.999000, -1170.000000) " />' '<g transform="translate(53.499000, 54.000000) rotate(-225.000000) translate(-53.499000, -54.000000) translate(31.999000, 20.000000)">' '<path d="M21.9097997,3.90608266 C26.170933,11.4659076 29.3361359,16.8171723 31.4028127,19.9615071 C32.9627669,22.3348914 34.7148315,24.4510487 36.3239968,26.389261 C38.7190073,29.2740105 41,31.6442511 41,34.0392981 C41,41.2737911 34.4771874,51.5925095 21.975433,65.1048441 C8.85845251,51.5900759 2,41.2762436 2,34.0392981 C2,31.7153744 4.5038242,29.0498098 6.98866431,26.00804 C8.54822997,24.0989273 10.194636,22.0782507 11.5931101,19.9677281 C13.7720223,16.679399 17.2108112,11.3245551 21.9097997,3.90608266 Z" />' '<path d="M21.4337465,24.2580374 C28.7435807,32.3258207 32.6464466,38.4941032 32.6464466,42.8636851 C32.6464466,47.2328868 28.7426179,53.3864682 21.431484,61.425663 C13.7581494,53.3849828 9.64644661,47.2355107 9.64644661,42.8636851 C9.64644661,38.4909332 13.7581469,32.3256763 21.4337465,24.2580374 Z" />' '</g>' '<g transform="translate(1146.499000, 54.000000) scale(-1, 1) rotate(-225.000000) translate(-1146.499000, -54.000000) translate(1124.999000, 20.000000)">' '<path d="M21.9097997,3.90608266 C26.170933,11.4659076 29.3361359,16.8171723 31.4028127,19.9615071 C32.9627669,22.3348914 34.7148315,24.4510487 36.3239968,26.389261 C38.7190073,29.2740105 41,31.6442511 41,34.0392981 C41,41.2737911 34.4771874,51.5925095 21.975433,65.1048441 C8.85845251,51.5900759 2,41.2762436 2,34.0392981 C2,31.7153744 4.5038242,29.0498098 6.98866431,26.00804 C8.54822997,24.0989273 10.194636,22.0782507 11.5931101,19.9677281 C13.7720223,16.679399 17.2108112,11.3245551 21.9097997,3.90608266 Z" />' '<path d="M21.4337465,24.2580374 C28.7435807,32.3258207 32.6464466,38.4941032 32.6464466,42.8636851 C32.6464466,47.2328868 28.7426179,53.3864682 21.431484,61.425663 C13.7581494,53.3849828 9.64644661,47.2355107 9.64644661,42.8636851 C9.64644661,38.4909332 13.7581469,32.3256763 21.4337465,24.2580374 Z" />' '</g>' '<g transform="translate(1146.499000, 1146.000000) scale(-1, -1) rotate(-225.000000) translate(-1146.499000, -1146.000000) translate(1124.999000, 1112.000000)">' '<path d="M21.9097997,3.90608266 C26.170933,11.4659076 29.3361359,16.8171723 31.4028127,19.9615071 C32.9627669,22.3348914 34.7148315,24.4510487 36.3239968,26.389261 C38.7190073,29.2740105 41,31.6442511 41,34.0392981 C41,41.2737911 34.4771874,51.5925095 21.975433,65.1048441 C8.85845251,51.5900759 2,41.2762436 2,34.0392981 C2,31.7153744 4.5038242,29.0498098 6.98866431,26.00804 C8.54822997,24.0989273 10.194636,22.0782507 11.5931101,19.9677281 C13.7720223,16.679399 17.2108112,11.3245551 21.9097997,3.90608266 Z" />' '<path d="M21.4337465,24.2580374 C28.7435807,32.3258207 32.6464466,38.4941032 32.6464466,42.8636851 C32.6464466,47.2328868 28.7426179,53.3864682 21.431484,61.425663 C13.7581494,53.3849828 9.64644661,47.2355107 9.64644661,42.8636851 C9.64644661,38.4909332 13.7581469,32.3256763 21.4337465,24.2580374 Z" />' '</g>' '<g transform="translate(53.499000, 1146.000000) scale(1, -1) rotate(-225.000000) translate(-45.499000, -1138.000000) translate(23.999000, 1104.000000)">' '<path d="M21.9097997,3.90608266 C26.170933,11.4659076 29.3361359,16.8171723 31.4028127,19.9615071 C32.9627669,22.3348914 34.7148315,24.4510487 36.3239968,26.389261 C38.7190073,29.2740105 41,31.6442511 41,34.0392981 C41,41.2737911 34.4771874,51.5925095 21.975433,65.1048441 C8.85845251,51.5900759 2,41.2762436 2,34.0392981 C2,31.7153744 4.5038242,29.0498098 6.98866431,26.00804 C8.54822997,24.0989273 10.194636,22.0782507 11.5931101,19.9677281 C13.7720223,16.679399 17.2108112,11.3245551 21.9097997,3.90608266 Z" />' '<path d="M21.4337465,24.2580374 C28.7435807,32.3258207 32.6464466,38.4941032 32.6464466,42.8636851 C32.6464466,47.2328868 28.7426179,53.3864682 21.431484,61.425663 C13.7581494,53.3849828 9.64644661,47.2355107 9.64644661,42.8636851 C9.64644661,38.4909332 13.7581469,32.3256763 21.4337465,24.2580374 Z" />' '</g>' '</g>' //fire's breath circle '<circle cy="600" cx="600" r="457" fill="#000" filter="url(#light4)">' '<animate attributeName="opacity" values="0.3;1;0.3" dur="2s" repeatCount="indefinite" filter="url(#light4)" />' '</circle>' '<circle cy="600" cx="600" r="457" fill="#000" filter="url(#light4)">' '<animate attributeName="opacity" values="0.3;1;0.3" dur="2s" repeatCount="indefinite" filter="url(#light4)"/>' '</circle>' '<circle cy="600" cx="600" r="457" fill="#000" filter="url(#light4)">' '<animate attributeName="opacity" values="0.3;1;0.3" dur="2s" repeatCount="indefinite" filter="url(#light4)"/>' '</circle>' ; string constant part_3_0_gen0_earth = '<g stroke="url(#gradient)">' '<rect width="1180" height="1180" x="10" y="10" stroke-width="4" fill="none" rx="18" />' '<path d="M30,30 H60 V80 H30 V1120 H60 V1170 H30 V1140 H80 V1170 H1120 V1140 H1170 V1170 H1140 V1120 H1170 V80 H1140 V30 H1170 V60 H1120 V30 H80 V60 H30 V30 Z" stroke-width="4" fill="none" />' '</g>'; string constant part_3_0_gen0_water = '<g stroke="#4fb3bf" stroke-width="4">' '<rect width="1180" height="1180" x="10" y="10" stroke-width="4" fill="none" rx="18" />' '<line x1="29.999" y1="89" x2="29.999" y2="1110" stroke-linecap="round" stroke-linejoin="round" />' '<line x1="1169.999" y1="89" x2="1169.999" y2="1110" stroke-linecap="round" stroke-linejoin="round" />' '<line x1="599.999" y1="-481" x2="599.999" y2="541" stroke-linecap="round" stroke-linejoin="round" transform="translate(599.999000, 30.000000) scale(1, -1) rotate(90.000000) translate(-599.999000, -30.000000) " />' '<line x1="599.999" y1="659" x2="599.999" y2="1681" stroke-linecap="round" stroke-linejoin="round" transform="translate(599.999000, 1170.000000) scale(1, -1) rotate(90.000000) translate(-599.999000, -1170.000000) " />' '<g transform="translate(30.000000, 30.000000)">' '<circle stroke-linejoin="round" cx="13" cy="59" r="13" />' '<circle stroke-linejoin="round" cx="59" cy="59" r="13" />' '<circle stroke-linejoin="round" cx="59" cy="13" r="13" />' '<path d="M13,46 C23.4255706,46 31.0922373,50.3333333 36,59 C40.9077627,67.6666667 48.5744294,72 59,72" />' '<path d="M36,21 C46.4255706,21 54.0922373,25.3333333 59,34 C63.9077627,42.6666667 71.5744294,47 82,47" transform="translate(59.000000, 34.000000) rotate(-270.000000) translate(-59.000000, -34.000000) " />' '</g>' '<g transform="translate(66.000000, 1134.000000) scale(1, -1) translate(-66.000000, -1134.000000) translate(30.000000, 1098.000000)">' '<circle stroke-linejoin="round" cx="13" cy="59" r="13" />' '<circle stroke-linejoin="round" cx="59" cy="59" r="13" />' '<circle stroke-linejoin="round" cx="59" cy="13" r="13" />' '<path d="M13,46 C23.4255706,46 31.0922373,50.3333333 36,59 C40.9077627,67.6666667 48.5744294,72 59,72" />' '<path d="M36,21 C46.4255706,21 54.0922373,25.3333333 59,34 C63.9077627,42.6666667 71.5744294,47 82,47" transform="translate(59.000000, 34.000000) rotate(-270.000000) translate(-59.000000, -34.000000) " />' '</g>' '<g transform="translate(1134.000000, 66.000000) scale(-1, 1) translate(-1126.000000, -58.000000) translate(1090.000000, 22.000000)">' '<circle stroke-linejoin="round" cx="13" cy="59" r="13" />' '<circle stroke-linejoin="round" cx="59" cy="59" r="13" />' '<circle stroke-linejoin="round" cx="59" cy="13" r="13" />' '<path d="M13,46 C23.4255706,46 31.0922373,50.3333333 36,59 C40.9077627,67.6666667 48.5744294,72 59,72" />' '<path d="M36,21 C46.4255706,21 54.0922373,25.3333333 59,34 C63.9077627,42.6666667 71.5744294,47 82,47" transform="translate(59.000000, 34.000000) rotate(-270.000000) translate(-59.000000, -34.000000) " />' '</g>' '<g transform="translate(1134.000000, 1134.000000) scale(-1, -1) translate(-1118.000000, -1118.000000) translate(1082.000000, 1082.000000)">' '<circle stroke-linejoin="round" cx="13" cy="59" r="13" />' '<circle stroke-linejoin="round" cx="59" cy="59" r="13" />' '<circle stroke-linejoin="round" cx="59" cy="13" r="13" />' '<path d="M13,46 C23.4255706,46 31.0922373,50.3333333 36,59 C40.9077627,67.6666667 48.5744294,72 59,72" />' '<path d="M36,21 C46.4255706,21 54.0922373,25.3333333 59,34 C63.9077627,42.6666667 71.5744294,47 82,47" transform="translate(59.000000, 34.000000) rotate(-270.000000) translate(-59.000000, -34.000000) " />' '</g>' '</g>'; string constant part_3_0_gen0_wind = '<g stroke="url(#gradient)" stroke-width="4">' '<rect width="1180" height="1180" x="10" y="10" stroke-width="4" fill="none" rx="18" />' '<line x1="29.999" y1="90" x2="29.998" y2="1110" stroke-linecap="round" stroke-linejoin="round" />' '<line x1="1169.999" y1="90" x2="1169.998" y2="1110" stroke-linecap="round" stroke-linejoin="round" />' '<line x1="599.999" y1="-481" x2="599.998" y2="541" stroke-linecap="round" stroke-linejoin="round" transform="translate(599.999000, 30.000000) scale(1, -1) rotate(90.000000) translate(-599.999000, -30.000000) " />' '<line x1="599.999" y1="659" x2="599.998" y2="1681" stroke-linecap="round" stroke-linejoin="round" transform="translate(599.999000, 1170.000000) scale(1, -1) rotate(90.000000) translate(-599.999000, -1170.000000) " />' '<g transform="translate(29.999000, 30.000000)">' '<path d="M0,60 C6.95638942,59.7567892 11.866387,55.8626531 14.7299928,48.3175919 C17.5935986,40.7725306 22.3502677,37 29,37" stroke-linecap="round" stroke-linejoin="round" />' '<path d="M30,23 C36.9563894,22.7567892 41.866387,18.8626531 44.7299928,11.3175919 C47.5935986,3.77253063 52.3502677,0 59,0" stroke-linecap="round" stroke-linejoin="round" />' '<circle cx="29.001" cy="30" r="7" />' '<path d="M42.1077896,16.2445146 C38.698469,12.9949978 34.0827128,11 29.001,11 C18.5075898,11 10.001,19.5065898 10.001,30 M16.8997613,44.6485395 C20.1863254,47.366665 24.4029198,49 29.001,49 C39.4944102,49 48.001,40.4934102 48.001,30" stroke-linecap="round" />' '</g>' '<g transform="translate(1140.499000, 60.000000) scale(-1, 1) translate(-1132.499000, -52.000000) translate(1102.999000, 22.000000)">' '<path d="M0,60 C6.95638942,59.7567892 11.866387,55.8626531 14.7299928,48.3175919 C17.5935986,40.7725306 22.3502677,37 29,37" stroke-linecap="round" stroke-linejoin="round" />' '<path d="M30,23 C36.9563894,22.7567892 41.866387,18.8626531 44.7299928,11.3175919 C47.5935986,3.77253063 52.3502677,0 59,0" stroke-linecap="round" stroke-linejoin="round" />' '<circle cx="29.001" cy="30" r="7" />' '<path d="M42.1077896,16.2445146 C38.698469,12.9949978 34.0827128,11 29.001,11 C18.5075898,11 10.001,19.5065898 10.001,30 M16.8997613,44.6485395 C20.1863254,47.366665 24.4029198,49 29.001,49 C39.4944102,49 48.001,40.4934102 48.001,30" stroke-linecap="round" />' '</g>' '<g transform="translate(1140.499000, 1140.000000) scale(-1, -1) translate(-1132.499000, -1132.000000) translate(1102.999000, 1102.000000)">' '<path d="M0,60 C6.95638942,59.7567892 11.866387,55.8626531 14.7299928,48.3175919 C17.5935986,40.7725306 22.3502677,37 29,37" stroke-linecap="round" stroke-linejoin="round" />' '<path d="M30,23 C36.9563894,22.7567892 41.866387,18.8626531 44.7299928,11.3175919 C47.5935986,3.77253063 52.3502677,0 59,0" stroke-linecap="round" stroke-linejoin="round" />' '<circle cx="29.001" cy="30" r="7" />' '<path d="M42.1077896,16.2445146 C38.698469,12.9949978 34.0827128,11 29.001,11 C18.5075898,11 10.001,19.5065898 10.001,30 M16.8997613,44.6485395 C20.1863254,47.366665 24.4029198,49 29.001,49 C39.4944102,49 48.001,40.4934102 48.001,30" stroke-linecap="round" />' '</g>' '<g transform="translate(59.499000, 1140.000000) scale(1, -1) translate(-51.499000, -1132.000000) translate(21.999000, 1102.000000)">' '<path d="M0,60 C6.95638942,59.7567892 11.866387,55.8626531 14.7299928,48.3175919 C17.5935986,40.7725306 22.3502677,37 29,37" stroke-linecap="round" stroke-linejoin="round" />' '<path d="M30,23 C36.9563894,22.7567892 41.866387,18.8626531 44.7299928,11.3175919 C47.5935986,3.77253063 52.3502677,0 59,0" stroke-linecap="round" stroke-linejoin="round" />' '<circle cx="29.001" cy="30" r="7" />' '<path d="M42.1077896,16.2445146 C38.698469,12.9949978 34.0827128,11 29.001,11 C18.5075898,11 10.001,19.5065898 10.001,30 M16.8997613,44.6485395 C20.1863254,47.366665 24.4029198,49 29.001,49 C39.4944102,49 48.001,40.4934102 48.001,30" stroke-linecap="round" />' '</g>' '</g>'; string constant part_3_0_gen1 = '<g stroke="#989898">' '<rect width="1180" height="1180" x="10" y="10" stroke-width="4" fill="none"/>' '<path d="M30,30 H60 V80 H30 V1120 H60 V1170 H30 V1140 H80 V1170 H1120 V1140 H1170 V1170 H1140 V1120 H1170 V80 H1140 V30 H1170 V60 H1120 V30 H80 V60 H30 V30 Z" stroke-width="4" fill="none"/>' "</g>"; function svgPart0() public pure returns (string memory) { return part0; } function svgPart1() public pure returns (string memory) { return part1; } function svgPart2(bool gen0, FireGenerator.ElementType elementType) public pure returns (string memory) { if (gen0) { if(elementType == FireGenerator.ElementType.FIRE) { return string(abi.encodePacked(part2, part2_0_gen0_fire, part2_1, part2_2_gen0_fire, part2_3)); } else if (elementType == FireGenerator.ElementType.EARTH) { return string(abi.encodePacked(part2, part2_0_gen0_earth, part2_1, part2_2_gen0_earth, part2_3)); } else if (elementType == FireGenerator.ElementType.WATER) { return string(abi.encodePacked(part2, part2_0_gen0_water, part2_1, part2_2_gen0_earth, part2_3)); } else /** if (elementType == ElementType.WIND) */ { return string(abi.encodePacked(part2, part2_0_gen0_wind, part2_1, part2_2_gen0_wind, part2_3)); } } else /** if(!gen0) */ { return string(abi.encodePacked(part2, part2_0_gen1, part2_1, part2_2_gen1, part2_3)); } } function svgPart3(bool gen0, FireGenerator.ElementType elementType) public pure returns (string memory) { if (gen0) { if(elementType == FireGenerator.ElementType.FIRE) { return part_3_0_gen0_fire; } else if (elementType == FireGenerator.ElementType.EARTH) { return part_3_0_gen0_earth; } else if (elementType == FireGenerator.ElementType.WATER) { return part_3_0_gen0_water; } else /** if (elementType == ElementType.WIND) */ { return part_3_0_gen0_wind; } } else /**(!gen0) */ { return part_3_0_gen1; } } }
// SPDX-License-Identifier: BSD-4-Clause /* * ABDK Math 64.64 Smart Contract Library. Copyright © 2019 by ABDK Consulting. * Author: Mikhail Vladimirov <[email protected]> */ pragma solidity ^0.8.0; /** * Smart contract library of mathematical functions operating with signed * 64.64-bit fixed point numbers. Signed 64.64-bit fixed point number is * basically a simple fraction whose numerator is signed 128-bit integer and * denominator is 2^64. As long as denominator is always the same, there is no * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are * represented by int128 type holding only the numerator. */ library ABDKMath64x64 { /* * Minimum value signed 64.64-bit fixed point number may have. */ int128 private constant MIN_64x64 = -0x80000000000000000000000000000000; /* * Maximum value signed 64.64-bit fixed point number may have. */ int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; /** * Convert signed 256-bit integer number into signed 64.64-bit fixed point * number. Revert on overflow. * * @param x signed 256-bit integer number * @return signed 64.64-bit fixed point number */ function fromInt (int256 x) internal pure returns (int128) { unchecked { require (x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF); return int128 (x << 64); } } /** * Convert signed 64.64 fixed point number into signed 64-bit integer number * rounding down. * * @param x signed 64.64-bit fixed point number * @return signed 64-bit integer number */ function toInt (int128 x) internal pure returns (int64) { unchecked { return int64 (x >> 64); } } /** * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point * number. Revert on overflow. * * @param x unsigned 256-bit integer number * @return signed 64.64-bit fixed point number */ function fromUInt (uint256 x) internal pure returns (int128) { unchecked { require (x <= 0x7FFFFFFFFFFFFFFF); return int128 (int256 (x << 64)); } } /** * Convert signed 64.64 fixed point number into unsigned 64-bit integer * number rounding down. Revert on underflow. * * @param x signed 64.64-bit fixed point number * @return unsigned 64-bit integer number */ function toUInt (int128 x) internal pure returns (uint64) { unchecked { require (x >= 0); return uint64 (uint128 (x >> 64)); } } /** * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point * number rounding down. Revert on overflow. * * @param x signed 128.128-bin fixed point number * @return signed 64.64-bit fixed point number */ function from128x128 (int256 x) internal pure returns (int128) { unchecked { int256 result = x >> 64; require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Convert signed 64.64 fixed point number into signed 128.128 fixed point * number. * * @param x signed 64.64-bit fixed point number * @return signed 128.128 fixed point number */ function to128x128 (int128 x) internal pure returns (int256) { unchecked { return int256 (x) << 64; } } /** * Calculate x + y. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function add (int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = int256(x) + y; require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Calculate x - y. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function sub (int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = int256(x) - y; require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Calculate x * y rounding down. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function mul (int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = int256(x) * y >> 64; require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point * number and y is signed 256-bit integer number. Revert on overflow. * * @param x signed 64.64 fixed point number * @param y signed 256-bit integer number * @return signed 256-bit integer number */ function muli (int128 x, int256 y) internal pure returns (int256) { unchecked { if (x == MIN_64x64) { require (y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF && y <= 0x1000000000000000000000000000000000000000000000000); return -y << 63; } else { bool negativeResult = false; if (x < 0) { x = -x; negativeResult = true; } if (y < 0) { y = -y; // We rely on overflow behavior here negativeResult = !negativeResult; } uint256 absoluteResult = mulu (x, uint256 (y)); if (negativeResult) { require (absoluteResult <= 0x8000000000000000000000000000000000000000000000000000000000000000); return -int256 (absoluteResult); // We rely on overflow behavior here } else { require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return int256 (absoluteResult); } } } } /** * Calculate x * y rounding down, where x is signed 64.64 fixed point number * and y is unsigned 256-bit integer number. Revert on overflow. * * @param x signed 64.64 fixed point number * @param y unsigned 256-bit integer number * @return unsigned 256-bit integer number */ function mulu (int128 x, uint256 y) internal pure returns (uint256) { unchecked { if (y == 0) return 0; require (x >= 0); uint256 lo = (uint256 (int256 (x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64; uint256 hi = uint256 (int256 (x)) * (y >> 128); require (hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); hi <<= 64; require (hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo); return hi + lo; } } /** * Calculate x / y rounding towards zero. Revert on overflow or when y is * zero. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function div (int128 x, int128 y) internal pure returns (int128) { unchecked { require (y != 0); int256 result = (int256 (x) << 64) / y; require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Calculate x / y rounding towards zero, where x and y are signed 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x signed 256-bit integer number * @param y signed 256-bit integer number * @return signed 64.64-bit fixed point number */ function divi (int256 x, int256 y) internal pure returns (int128) { unchecked { require (y != 0); bool negativeResult = false; if (x < 0) { x = -x; // We rely on overflow behavior here negativeResult = true; } if (y < 0) { y = -y; // We rely on overflow behavior here negativeResult = !negativeResult; } uint128 absoluteResult = divuu (uint256 (x), uint256 (y)); if (negativeResult) { require (absoluteResult <= 0x80000000000000000000000000000000); return -int128 (absoluteResult); // We rely on overflow behavior here } else { require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return int128 (absoluteResult); // We rely on overflow behavior here } } } /** * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x unsigned 256-bit integer number * @param y unsigned 256-bit integer number * @return signed 64.64-bit fixed point number */ function divu (uint256 x, uint256 y) internal pure returns (int128) { unchecked { require (y != 0); uint128 result = divuu (x, y); require (result <= uint128 (MAX_64x64)); return int128 (result); } } /** * Calculate -x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function neg (int128 x) internal pure returns (int128) { unchecked { require (x != MIN_64x64); return -x; } } /** * Calculate |x|. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function abs (int128 x) internal pure returns (int128) { unchecked { require (x != MIN_64x64); return x < 0 ? -x : x; } } /** * Calculate 1 / x rounding towards zero. Revert on overflow or when x is * zero. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function inv (int128 x) internal pure returns (int128) { unchecked { require (x != 0); int256 result = int256 (0x100000000000000000000000000000000) / x; require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function avg (int128 x, int128 y) internal pure returns (int128) { unchecked { return int128 ((int256 (x) + int256 (y)) >> 1); } } /** * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down. * Revert on overflow or in case x * y is negative. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function gavg (int128 x, int128 y) internal pure returns (int128) { unchecked { int256 m = int256 (x) * int256 (y); require (m >= 0); require (m < 0x4000000000000000000000000000000000000000000000000000000000000000); return int128 (sqrtu (uint256 (m))); } } /** * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number * and y is unsigned 256-bit integer number. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y uint256 value * @return signed 64.64-bit fixed point number */ function pow (int128 x, uint256 y) internal pure returns (int128) { unchecked { bool negative = x < 0 && y & 1 == 1; uint256 absX = uint128 (x < 0 ? -x : x); uint256 absResult; absResult = 0x100000000000000000000000000000000; if (absX <= 0x10000000000000000) { absX <<= 63; while (y != 0) { if (y & 0x1 != 0) { absResult = absResult * absX >> 127; } absX = absX * absX >> 127; if (y & 0x2 != 0) { absResult = absResult * absX >> 127; } absX = absX * absX >> 127; if (y & 0x4 != 0) { absResult = absResult * absX >> 127; } absX = absX * absX >> 127; if (y & 0x8 != 0) { absResult = absResult * absX >> 127; } absX = absX * absX >> 127; y >>= 4; } absResult >>= 64; } else { uint256 absXShift = 63; if (absX < 0x1000000000000000000000000) { absX <<= 32; absXShift -= 32; } if (absX < 0x10000000000000000000000000000) { absX <<= 16; absXShift -= 16; } if (absX < 0x1000000000000000000000000000000) { absX <<= 8; absXShift -= 8; } if (absX < 0x10000000000000000000000000000000) { absX <<= 4; absXShift -= 4; } if (absX < 0x40000000000000000000000000000000) { absX <<= 2; absXShift -= 2; } if (absX < 0x80000000000000000000000000000000) { absX <<= 1; absXShift -= 1; } uint256 resultShift = 0; while (y != 0) { require (absXShift < 64); if (y & 0x1 != 0) { absResult = absResult * absX >> 127; resultShift += absXShift; if (absResult > 0x100000000000000000000000000000000) { absResult >>= 1; resultShift += 1; } } absX = absX * absX >> 127; absXShift <<= 1; if (absX >= 0x100000000000000000000000000000000) { absX >>= 1; absXShift += 1; } y >>= 1; } require (resultShift < 64); absResult >>= 64 - resultShift; } int256 result = negative ? -int256 (absResult) : int256 (absResult); require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Calculate sqrt (x) rounding down. Revert if x < 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function sqrt (int128 x) internal pure returns (int128) { unchecked { require (x >= 0); return int128 (sqrtu (uint256 (int256 (x)) << 64)); } } /** * Calculate binary logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function log_2 (int128 x) internal pure returns (int128) { unchecked { require (x > 0); int256 msb = 0; int256 xc = x; if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; } if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore int256 result = msb - 64 << 64; uint256 ux = uint256 (int256 (x)) << uint256 (127 - msb); for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) { ux *= ux; uint256 b = ux >> 255; ux >>= 127 + b; result += bit * int256 (b); } return int128 (result); } } /** * Calculate natural logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function ln (int128 x) internal pure returns (int128) { unchecked { require (x > 0); return int128 (int256 ( uint256 (int256 (log_2 (x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF >> 128)); } } /** * Calculate binary exponent of x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function exp_2 (int128 x) internal pure returns (int128) { unchecked { require (x < 0x400000000000000000); // Overflow if (x < -0x400000000000000000) return 0; // Underflow uint256 result = 0x80000000000000000000000000000000; if (x & 0x8000000000000000 > 0) result = result * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128; if (x & 0x4000000000000000 > 0) result = result * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128; if (x & 0x2000000000000000 > 0) result = result * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128; if (x & 0x1000000000000000 > 0) result = result * 0x10B5586CF9890F6298B92B71842A98363 >> 128; if (x & 0x800000000000000 > 0) result = result * 0x1059B0D31585743AE7C548EB68CA417FD >> 128; if (x & 0x400000000000000 > 0) result = result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128; if (x & 0x200000000000000 > 0) result = result * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128; if (x & 0x100000000000000 > 0) result = result * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128; if (x & 0x80000000000000 > 0) result = result * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128; if (x & 0x40000000000000 > 0) result = result * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128; if (x & 0x20000000000000 > 0) result = result * 0x100162F3904051FA128BCA9C55C31E5DF >> 128; if (x & 0x10000000000000 > 0) result = result * 0x1000B175EFFDC76BA38E31671CA939725 >> 128; if (x & 0x8000000000000 > 0) result = result * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128; if (x & 0x4000000000000 > 0) result = result * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128; if (x & 0x2000000000000 > 0) result = result * 0x1000162E525EE054754457D5995292026 >> 128; if (x & 0x1000000000000 > 0) result = result * 0x10000B17255775C040618BF4A4ADE83FC >> 128; if (x & 0x800000000000 > 0) result = result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128; if (x & 0x400000000000 > 0) result = result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128; if (x & 0x200000000000 > 0) result = result * 0x10000162E43F4F831060E02D839A9D16D >> 128; if (x & 0x100000000000 > 0) result = result * 0x100000B1721BCFC99D9F890EA06911763 >> 128; if (x & 0x80000000000 > 0) result = result * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128; if (x & 0x40000000000 > 0) result = result * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128; if (x & 0x20000000000 > 0) result = result * 0x100000162E430E5A18F6119E3C02282A5 >> 128; if (x & 0x10000000000 > 0) result = result * 0x1000000B1721835514B86E6D96EFD1BFE >> 128; if (x & 0x8000000000 > 0) result = result * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128; if (x & 0x4000000000 > 0) result = result * 0x10000002C5C8601CC6B9E94213C72737A >> 128; if (x & 0x2000000000 > 0) result = result * 0x1000000162E42FFF037DF38AA2B219F06 >> 128; if (x & 0x1000000000 > 0) result = result * 0x10000000B17217FBA9C739AA5819F44F9 >> 128; if (x & 0x800000000 > 0) result = result * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128; if (x & 0x400000000 > 0) result = result * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128; if (x & 0x200000000 > 0) result = result * 0x10000000162E42FF0999CE3541B9FFFCF >> 128; if (x & 0x100000000 > 0) result = result * 0x100000000B17217F80F4EF5AADDA45554 >> 128; if (x & 0x80000000 > 0) result = result * 0x10000000058B90BFBF8479BD5A81B51AD >> 128; if (x & 0x40000000 > 0) result = result * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128; if (x & 0x20000000 > 0) result = result * 0x100000000162E42FEFB2FED257559BDAA >> 128; if (x & 0x10000000 > 0) result = result * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128; if (x & 0x8000000 > 0) result = result * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128; if (x & 0x4000000 > 0) result = result * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128; if (x & 0x2000000 > 0) result = result * 0x1000000000162E42FEFA494F1478FDE05 >> 128; if (x & 0x1000000 > 0) result = result * 0x10000000000B17217F7D20CF927C8E94C >> 128; if (x & 0x800000 > 0) result = result * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128; if (x & 0x400000 > 0) result = result * 0x100000000002C5C85FDF477B662B26945 >> 128; if (x & 0x200000 > 0) result = result * 0x10000000000162E42FEFA3AE53369388C >> 128; if (x & 0x100000 > 0) result = result * 0x100000000000B17217F7D1D351A389D40 >> 128; if (x & 0x80000 > 0) result = result * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128; if (x & 0x40000 > 0) result = result * 0x1000000000002C5C85FDF4741BEA6E77E >> 128; if (x & 0x20000 > 0) result = result * 0x100000000000162E42FEFA39FE95583C2 >> 128; if (x & 0x10000 > 0) result = result * 0x1000000000000B17217F7D1CFB72B45E1 >> 128; if (x & 0x8000 > 0) result = result * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128; if (x & 0x4000 > 0) result = result * 0x10000000000002C5C85FDF473E242EA38 >> 128; if (x & 0x2000 > 0) result = result * 0x1000000000000162E42FEFA39F02B772C >> 128; if (x & 0x1000 > 0) result = result * 0x10000000000000B17217F7D1CF7D83C1A >> 128; if (x & 0x800 > 0) result = result * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128; if (x & 0x400 > 0) result = result * 0x100000000000002C5C85FDF473DEA871F >> 128; if (x & 0x200 > 0) result = result * 0x10000000000000162E42FEFA39EF44D91 >> 128; if (x & 0x100 > 0) result = result * 0x100000000000000B17217F7D1CF79E949 >> 128; if (x & 0x80 > 0) result = result * 0x10000000000000058B90BFBE8E7BCE544 >> 128; if (x & 0x40 > 0) result = result * 0x1000000000000002C5C85FDF473DE6ECA >> 128; if (x & 0x20 > 0) result = result * 0x100000000000000162E42FEFA39EF366F >> 128; if (x & 0x10 > 0) result = result * 0x1000000000000000B17217F7D1CF79AFA >> 128; if (x & 0x8 > 0) result = result * 0x100000000000000058B90BFBE8E7BCD6D >> 128; if (x & 0x4 > 0) result = result * 0x10000000000000002C5C85FDF473DE6B2 >> 128; if (x & 0x2 > 0) result = result * 0x1000000000000000162E42FEFA39EF358 >> 128; if (x & 0x1 > 0) result = result * 0x10000000000000000B17217F7D1CF79AB >> 128; result >>= uint256 (int256 (63 - (x >> 64))); require (result <= uint256 (int256 (MAX_64x64))); return int128 (int256 (result)); } } /** * Calculate natural exponent of x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function exp (int128 x) internal pure returns (int128) { unchecked { require (x < 0x400000000000000000); // Overflow if (x < -0x400000000000000000) return 0; // Underflow return exp_2 ( int128 (int256 (x) * 0x171547652B82FE1777D0FFDA0D23A7D12 >> 128)); } } /** * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x unsigned 256-bit integer number * @param y unsigned 256-bit integer number * @return unsigned 64.64-bit fixed point number */ function divuu (uint256 x, uint256 y) private pure returns (uint128) { unchecked { require (y != 0); uint256 result; if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) result = (x << 64) / y; else { uint256 msb = 192; uint256 xc = x >> 192; if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore result = (x << 255 - msb) / ((y - 1 >> msb - 191) + 1); require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); uint256 hi = result * (y >> 128); uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); uint256 xh = x >> 192; uint256 xl = x << 64; if (xl < lo) xh -= 1; xl -= lo; // We rely on overflow behavior here lo = hi << 128; if (xl < lo) xh -= 1; xl -= lo; // We rely on overflow behavior here assert (xh == hi >> 128); result += xl / y; } require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return uint128 (result); } } /** * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer * number. * * @param x unsigned 256-bit integer number * @return unsigned 128-bit integer number */ function sqrtu (uint256 x) private pure returns (uint128) { unchecked { if (x == 0) return 0; else { uint256 xx = x; uint256 r = 1; if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; } if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; } if (xx >= 0x100000000) { xx >>= 32; r <<= 16; } if (xx >= 0x10000) { xx >>= 16; r <<= 8; } if (xx >= 0x100) { xx >>= 8; r <<= 4; } if (xx >= 0x10) { xx >>= 4; r <<= 2; } if (xx >= 0x8) { r <<= 1; } r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; // Seven iterations should be enough uint256 r1 = x / r; return uint128 (r < r1 ? r : r1); } } } }
// contracts/SVGGenerator.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; library DateUtils { uint256 constant DAY_IN_SECONDS = 86400; uint256 constant YEAR_IN_SECONDS = 31536000; uint256 constant LEAP_YEAR_IN_SECONDS = 31622400; uint256 constant SECONDS_IN_DAY = 86400; uint256 constant SECONDS_IN_YEAR = 31536000; uint256 constant HOUR_IN_SECONDS = 3600; uint256 constant MINUTE_IN_SECONDS = 60; uint16 constant ORIGIN_YEAR = 1970; uint256 constant SECONDS_IN_FOUR_YEARS_WITH_LEAP_YEAR = 126230400; uint256 constant SECONDS_BETWEEN_JAN_1_1972_AND_DEC_31_1999 = 883612800; uint256 constant SECONDS_IN_100_YEARS = 3155673600; uint256 constant SECONDS_IN_400_YEARS = 12622780800; function isLeapYear(uint16 year) private pure returns (bool) { if (year % 4 != 0) { return false; } if (year % 100 != 0) { return true; } if (year % 400 != 0) { return false; } return true; } function leapYearsBefore(uint256 year) private pure returns (uint256) { year -= 1; return year / 4 - year / 100 + year / 400; } function isDateValid( uint16 year, uint16 month, uint16 day ) internal view returns (bool) { return day > 0 && getDaysInMonth(month, year) >= day; } function getDaysInMonth(uint16 month, uint16 year) internal pure returns (uint16) { if ( month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12 ) { return 31; } else if (month == 4 || month == 6 || month == 9 || month == 11) { return 30; } else if (isLeapYear(year)) { return 29; } else { return 28; } } function getDayFromTimestamp(uint256 timestamp) internal view returns (uint16) { uint256 secondsAccountedFor = 0; uint256 buf; uint8 i; uint16 year; uint16 month; uint16 day; // Year year = getYear(timestamp); buf = leapYearsBefore(year) - leapYearsBefore(ORIGIN_YEAR); secondsAccountedFor += LEAP_YEAR_IN_SECONDS * buf; secondsAccountedFor += YEAR_IN_SECONDS * (year - ORIGIN_YEAR - buf); // Month uint256 secondsInMonth; for (i = 1; i <= 12; i++) { secondsInMonth = DAY_IN_SECONDS * getDaysInMonth(i, year); if (secondsInMonth + secondsAccountedFor > timestamp) { month = i; break; } secondsAccountedFor += secondsInMonth; } // Day for (i = 1; i <= getDaysInMonth(month, year); i++) { if (DAY_IN_SECONDS + secondsAccountedFor > timestamp) { day = i; break; } secondsAccountedFor += DAY_IN_SECONDS; } return day; } /** @dev Convert timestamp to YMD (year, month, day) @param _dt Date as timestamp integer @return secondsRemaining */ function getUTCSecondsOffsetInDay(uint256 _dt) internal pure returns (uint256 secondsRemaining) { uint16 year; uint8 month; uint8 day; secondsRemaining = _dt; (secondsRemaining, year) = getYearAndSecondsRemaining(secondsRemaining); (secondsRemaining, month) = getMonth(secondsRemaining, year); (secondsRemaining, day) = getDay(secondsRemaining); return secondsRemaining; } // functions to calculate year, month, or day from timestamp function getYearAndSecondsRemaining(uint256 _secondsRemaining) private pure returns (uint256 secondsRemaining, uint16 year) { uint256 res; uint32 secondsInThisYear; secondsRemaining = _secondsRemaining; year = 1970; if (secondsRemaining < (2 * SECONDS_IN_YEAR)) { res = secondsRemaining / SECONDS_IN_YEAR; secondsRemaining -= res * SECONDS_IN_YEAR; year += uint16(res); } else { secondsRemaining -= 2 * SECONDS_IN_YEAR; year = 1972; if ( secondsRemaining >= SECONDS_BETWEEN_JAN_1_1972_AND_DEC_31_1999 ) { secondsRemaining -= SECONDS_BETWEEN_JAN_1_1972_AND_DEC_31_1999; year += 28; res = secondsRemaining / SECONDS_IN_400_YEARS; secondsRemaining -= res * SECONDS_IN_400_YEARS; year += uint16(res * 400); secondsInThisYear = uint32(getSecondsInYear(year)); if (secondsRemaining >= secondsInThisYear) { secondsRemaining -= secondsInThisYear; year += 1; } if (!isLeapYear(year)) { res = secondsRemaining / SECONDS_IN_100_YEARS; secondsRemaining -= res * SECONDS_IN_100_YEARS; year += uint16(res * 100); } } res = secondsRemaining / SECONDS_IN_FOUR_YEARS_WITH_LEAP_YEAR; secondsRemaining -= res * SECONDS_IN_FOUR_YEARS_WITH_LEAP_YEAR; year += uint16(res * 4); secondsInThisYear = uint32(getSecondsInYear(year)); if (secondsRemaining >= secondsInThisYear) { secondsRemaining -= secondsInThisYear; year += 1; } if (!isLeapYear(year)) { res = secondsRemaining / SECONDS_IN_YEAR; secondsRemaining -= res * SECONDS_IN_YEAR; year += uint16(res); } } } function getSecondsInYear(uint16 _year) private pure returns (uint256) { if (isLeapYear(_year)) { return (SECONDS_IN_YEAR + SECONDS_IN_DAY); } else { return SECONDS_IN_YEAR; } } function getYear(uint256 timestamp) private pure returns (uint16) { uint256 secondsAccountedFor = 0; uint16 year; uint256 numLeapYears; // Year year = uint16(ORIGIN_YEAR + timestamp / YEAR_IN_SECONDS); numLeapYears = leapYearsBefore(year) - leapYearsBefore(ORIGIN_YEAR); secondsAccountedFor += LEAP_YEAR_IN_SECONDS * numLeapYears; secondsAccountedFor += YEAR_IN_SECONDS * (year - ORIGIN_YEAR - numLeapYears); while (secondsAccountedFor > timestamp) { if (isLeapYear(uint16(year - 1))) { secondsAccountedFor -= LEAP_YEAR_IN_SECONDS; } else { secondsAccountedFor -= YEAR_IN_SECONDS; } year -= 1; } return year; } function getMonth(uint256 _secondsRemaining, uint16 _year) private pure returns (uint256 secondsRemaining, uint8 month) { uint8[13] memory monthDayMap; uint32[13] memory monthSecondsMap; secondsRemaining = _secondsRemaining; if (isLeapYear(_year)) { monthDayMap = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; monthSecondsMap = [ 0, 2678400, 5184000, 7862400, 10454400, 13132800, 15724800, 18403200, 21081600, 23673600, 26352000, 28944000, 31622400 ]; } else { monthDayMap = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; monthSecondsMap = [ 0, 2678400, 5097600, 7776000, 10368000, 13046400, 15638400, 18316800, 20995200, 23587200, 26265600, 28857600, 31536000 ]; } for (uint8 i = 1; i < 13; i++) { if (secondsRemaining < monthSecondsMap[i]) { month = i; secondsRemaining -= monthSecondsMap[i - 1]; break; } } } function getDay(uint256 _secondsRemaining) private pure returns (uint256 secondsRemaining, uint8 day) { uint256 res; secondsRemaining = _secondsRemaining; res = secondsRemaining / SECONDS_IN_DAY; secondsRemaining -= res * SECONDS_IN_DAY; day = uint8(res + 1); } function getDayIndexInYear(uint16 year, uint16 month, uint256 day) internal pure returns (uint256 index) { index = 0; for (uint16 i = 1; i < month; i++) { index += getDaysInMonth(i, year); } index += day - 1; } }
{ "optimizer": { "enabled": true, "runs": 1000000 }, "metadata": { "bytecodeHash": "none" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": { "contracts/libraries/AstroChartLib.sol": { "AstroChartLib": "0x52c5cc403e8adef8978e6dc83747f86516547ca4" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_primeAstroChartAddress","type":"address"},{"internalType":"address","name":"_svgGeneratorAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"bredTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"bredTokenOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"AstroChartBred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"ChainlinkCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"ChainlinkFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"ChainlinkRequested","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":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"internalType":"uint16[]","name":"monthAndDay","type":"uint16[]"},{"internalType":"string","name":"remaining","type":"string"}],"name":"breedFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"generation","type":"uint32"}],"name":"breedingLimitationOf","outputs":[{"internalType":"uint32","name":"res","type":"uint32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_requestId","type":"bytes32"},{"internalType":"uint16[]","name":"_cusps","type":"uint16[]"},{"internalType":"uint16[]","name":"_planets","type":"uint16[]"}],"name":"fulfill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getAstroArgsOf","outputs":[{"components":[{"internalType":"uint16[]","name":"monthAndDay","type":"uint16[]"},{"internalType":"string","name":"remaining","type":"string"},{"internalType":"bool","name":"exists","type":"bool"},{"internalType":"uint32","name":"generation","type":"uint32"}],"internalType":"struct AstroChartArgs","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getBreedConfig","outputs":[{"components":[{"internalType":"uint32","name":"alreadyBredCount","type":"uint32"},{"internalType":"uint256","name":"breedPrice","type":"uint256"},{"internalType":"uint256","name":"bredFromRootTokenId","type":"uint256"}],"internalType":"struct BreedConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getBreedPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOracleGasFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPendingWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getResponseOf","outputs":[{"components":[{"internalType":"uint16[]","name":"cusps","type":"uint16[]"},{"internalType":"uint16[]","name":"planets","type":"uint16[]"},{"internalType":"bool","name":"exists","type":"bool"}],"internalType":"struct BaseOraclizedAstroChart.AstroChartResponse","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"breedPrice","type":"uint256"}],"name":"setBreedPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"linkTokenAddress","type":"address"},{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"bytes32","name":"_jobId","type":"bytes32"},{"internalType":"uint256","name":"_feeInLink","type":"uint256"},{"internalType":"uint256","name":"_oracleGasFee","type":"uint256"},{"internalType":"string","name":"_oracleRequestHost","type":"string"},{"internalType":"contract SVGGenerator","name":"_svgGenerator","type":"address"}],"name":"setUpParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenId2OracleRequestId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawBreedFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawLink","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawOracleGasDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040526001600f553480156200001657600080fd5b5060405162005a7e38038062005a7e833981016040819052620000399162000296565b604080518082018252600a815269105cdd1c9bd0da185c9d60b21b6020808301918252835180850190945260078452664f2d415354524f60c81b9084015281519192916200008a91600091620001d3565b508051620000a0906001906020840190620001d3565b505050620000bd620000b76200017d60201b60201c565b62000181565b7352c5cc403e8adef8978e6dc83747f86516547ca46354ff6350620000e661016e6001620002cd565b6040518263ffffffff1660e01b81526004016200010591815260200190565b60006040518083038186803b1580156200011e57600080fd5b505af415801562000133573d6000803e3d6000fd5b505050506200014b620000b76200017d60201b60201c565b601880546001600160a01b039384166001600160a01b031991821617909155601580549290931691161790556200032f565b3390565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b828054620001e190620002f2565b90600052602060002090601f01602090048101928262000205576000855562000250565b82601f106200022057805160ff191683800117855562000250565b8280016001018555821562000250579182015b828111156200025057825182559160200191906001019062000233565b506200025e92915062000262565b5090565b5b808211156200025e576000815560010162000263565b80516001600160a01b03811681146200029157600080fd5b919050565b60008060408385031215620002a9578182fd5b620002b48362000279565b9150620002c46020840162000279565b90509250929050565b60008219821115620002ed57634e487b7160e01b81526011600452602481fd5b500190565b600181811c908216806200030757607f821691505b602082108114156200032957634e487b7160e01b600052602260045260246000fd5b50919050565b61573f806200033f6000396000f3fe6080604052600436106102335760003560e01c80636352211e116101385780638da5cb5b116100b0578063b88d4fde1161007f578063e985e9c511610064578063e985e9c514610699578063f2fde38b146106ef578063ff6805951461070f57600080fd5b8063b88d4fde14610659578063c87b56dd1461067957600080fd5b80638da5cb5b146105e45780638dc654a21461060f57806395d89b4114610624578063a22cb4651461063957600080fd5b8063715018a6116101075780637eeb7dee116100ec5780637eeb7dee1461055a5780638990bf69146105a25780638cec0bfc146105cf57600080fd5b8063715018a61461051057806375992b9f1461052557600080fd5b80636352211e1461049b5780636464f365146104bb57806364a701b7146104d057806370a08231146104f057600080fd5b80632f2d248d116101cb578063465728491161019a5780634f6ccce71161017f5780634f6ccce7146104485780634f73c1911461046857806352fdf1c41461047b57600080fd5b80634657284914610408578063475f931c1461042857600080fd5b80632f2d248d146103935780632f745c59146103b35780633c793d49146103d357806342842e0e146103e857600080fd5b8063081812fc11610207578063081812fc146102ed578063095ea7b31461033257806318160ddd1461035457806323b872dd1461037357600080fd5b806270aa001461023857806301ffc9a71461026e57806302b3b1e81461029e57806306fdde03146102cb575b600080fd5b34801561024457600080fd5b50610258610253366004614cb2565b610724565b604051610265919061514d565b60405180910390f35b34801561027a57600080fd5b5061028e610289366004614ac7565b61089c565b6040519015158152602001610265565b3480156102aa57600080fd5b506102be6102b9366004614cb2565b6108f2565b60405161026591906151cd565b3480156102d757600080fd5b506102e0610a43565b604051610265919061513a565b3480156102f957600080fd5b5061030d610308366004614cb2565b610ad5565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610265565b34801561033e57600080fd5b5061035261034d366004614a09565b610bb4565b005b34801561036057600080fd5b506008545b604051908152602001610265565b34801561037f57600080fd5b5061035261038e3660046148fa565b610d41565b34801561039f57600080fd5b506103526103ae366004614cb2565b610de2565b3480156103bf57600080fd5b506103656103ce366004614a09565b610eae565b3480156103df57600080fd5b50610365610f7d565b3480156103f457600080fd5b506103526104033660046148fa565b611000565b34801561041457600080fd5b50610352610423366004614a50565b61101b565b34801561043457600080fd5b50610352610443366004614d48565b611226565b34801561045457600080fd5b50610365610463366004614cb2565b6113f1565b610352610476366004614ce2565b6114d6565b34801561048757600080fd5b50610352610496366004614863565b6118b5565b3480156104a757600080fd5b5061030d6104b6366004614cb2565b611a98565b3480156104c757600080fd5b50610365611b4a565b3480156104dc57600080fd5b506103656104eb366004614cb2565b611b90565b3480156104fc57600080fd5b5061036561050b3660046147f3565b611c2f565b34801561051c57600080fd5b50610352611cfd565b34801561053157600080fd5b50610545610540366004614d69565b611d8a565b60405163ffffffff9091168152602001610265565b34801561056657600080fd5b5061057a610575366004614cb2565b611e2e565b60408051825163ffffffff168152602080840151908201529181015190820152606001610265565b3480156105ae57600080fd5b506103656105bd366004614cb2565b60176020526000908152604090205481565b3480156105db57600080fd5b50610352611ef4565b3480156105f057600080fd5b50600a5473ffffffffffffffffffffffffffffffffffffffff1661030d565b34801561061b57600080fd5b50610352611f52565b34801561063057600080fd5b506102e06121aa565b34801561064557600080fd5b506103526106543660046149dc565b6121b9565b34801561066557600080fd5b5061035261067436600461493a565b6121c4565b34801561068557600080fd5b506102e0610694366004614cb2565b612266565b3480156106a557600080fd5b5061028e6106b436600461482b565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260056020908152604080832093909416825291909152205460ff1690565b3480156106fb57600080fd5b5061035261070a3660046147f3565b61231f565b34801561071b57600080fd5b5061030d61244c565b6040805160808101825260608082526020820181905260009282018390528101919091526107548261016e101590565b15610821576018546040517e70aa000000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff909116906270aa009060240160006040518083038186803b1580156107c157600080fd5b505afa1580156107d5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261081b9190810190614b32565b92915050565b6040517e70aa00000000000000000000000000000000000000000000000000000000008152600481018390527352c5cc403e8adef8978e6dc83747f86516547ca4906270aa009060240160006040518083038186803b15801561088357600080fd5b505af41580156107d5573d6000803e3d6000fd5b919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f780e9d6300000000000000000000000000000000000000000000000000000000148061081b575061081b8261246d565b60408051606080820183528082526020820152600091810191909152600082815260176020908152604080832054808452601683529281902081518154608094810282018501909352606081018381529093919284928491908401828280156109a257602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116109695790505b5050505050815260200160018201805480602002602001604051908101604052809291908181526020018280548015610a2257602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116109e95790505b50505091835250506002919091015460ff1615156020909101529392505050565b606060008054610a529061558a565b80601f0160208091040260200160405190810160405280929190818152602001828054610a7e9061558a565b8015610acb5780601f10610aa057610100808354040283529160200191610acb565b820191906000526020600020905b815481529060010190602001808311610aae57829003601f168201915b5050505050905090565b60008181526002602052604081205473ffffffffffffffffffffffffffffffffffffffff16610b8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201527f697374656e7420746f6b656e000000000000000000000000000000000000000060648201526084015b60405180910390fd5b5060009081526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b6000610bbf82611a98565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610c7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152608401610b82565b3373ffffffffffffffffffffffffffffffffffffffff82161480610ca65750610ca681336106b4565b610d32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610b82565b610d3c8383612550565b505050565b610d4b33826125f0565b610dd7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610b82565b610d3c838383612760565b600a5473ffffffffffffffffffffffffffffffffffffffff163314610e63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b82565b600a5460405173ffffffffffffffffffffffffffffffffffffffff9091169082156108fc029083906000818181858888f19350505050158015610eaa573d6000803e3d6000fd5b5050565b6000610eb983611c2f565b8210610f47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201527f74206f6620626f756e64730000000000000000000000000000000000000000006064820152608401610b82565b5073ffffffffffffffffffffffffffffffffffffffff919091166000908152600660209081526040808320938352929052205490565b60007352c5cc403e8adef8978e6dc83747f86516547ca4633c793d496040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b505af4158015610fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ffb9190614cca565b905090565b610d3c838383604051806020016040528060008152506121c4565b600085815260106020526040902054859073ffffffffffffffffffffffffffffffffffffffff1633146110d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f536f75726365206d75737420626520746865206f7261636c65206f662074686560448201527f20726571756573740000000000000000000000000000000000000000000000006064820152608401610b82565b60008181526010602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555182917f7cc135e0cebb02c3480ae5d74d377283180a2601f8f644edf7987b009316c63a91a2604051806060016040528086868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060408051602086810282810182019093528682529283019290918791879182918501908490808284376000920182905250938552505060016020938401525088815260168252604090208251805191926111cb928492909101906145bb565b5060208281015180516111e492600185019201906145bb565b5060409190910151600290910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055505050505050565b60006112348361016e101590565b6112465761124183611a98565b6112e8565b6018546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690636352211e9060240160206040518083038186803b1580156112b057600080fd5b505afa1580156112c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e8919061480f565b905073ffffffffffffffffffffffffffffffffffffffff81163314611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f4f4f4343425000000000000000000000000000000000000000000000000000006044820152606401610b82565b6040517f475f931c00000000000000000000000000000000000000000000000000000000815260048101849052602481018390527352c5cc403e8adef8978e6dc83747f86516547ca49063475f931c9060440160006040518083038186803b1580156113d457600080fd5b505af41580156113e8573d6000803e3d6000fd5b50505050505050565b60006113fc60085490565b821061148a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201527f7574206f6620626f756e647300000000000000000000000000000000000000006064820152608401610b82565b600882815481106114c4577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90600052602060002001549050919050565b60408051608081018252606080825260208201819052600092820183905281018290529061016e871161166f576018546040517e70aa000000000000000000000000000000000000000000000000000000000081526004810189905273ffffffffffffffffffffffffffffffffffffffff909116906270aa009060240160006040518083038186803b15801561156b57600080fd5b505afa15801561157f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115c59190810190614b32565b6018546040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018a905291935073ffffffffffffffffffffffffffffffffffffffff1690636352211e9060240160206040518083038186803b15801561163057600080fd5b505afa158015611644573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611668919061480f565b9050611739565b6040517e70aa00000000000000000000000000000000000000000000000000000000008152600481018890527352c5cc403e8adef8978e6dc83747f86516547ca4906270aa009060240160006040518083038186803b1580156116d157600080fd5b505af41580156116e5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261172b9190810190614b32565b915061173687611a98565b90505b6040517f5ad5275f0000000000000000000000000000000000000000000000000000000081526000907352c5cc403e8adef8978e6dc83747f86516547ca490635ad5275f90611798908b908b908b908b908b908a908c9060040161523d565b60206040518083038186803b1580156117b057600080fd5b505af41580156117c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e89190614cca565b90506117f433826129d2565b6118658188888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020601f8c018190048102820181019092528a815292508a91508990819084018382808284376000920191909152506129ec92505050565b5060408051828152602081018a9052338183015234606082015290517fb7c3334983fbe71312ff1b6135579300d4dbea95ebad47d3eeffbe23ea591f429181900360800190a15050505050505050565b600a5473ffffffffffffffffffffffffffffffffffffffff163314611936576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b82565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff89161790556012869055601385905561198c60148484614664565b50600d80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a161790556040517f496a01ad000000000000000000000000000000000000000000000000000000008152600481018590527352c5cc403e8adef8978e6dc83747f86516547ca49063496a01ad9060240160006040518083038186803b158015611a3157600080fd5b505af4158015611a45573d6000803e3d6000fd5b5050601580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9490941693909317909255505050505050505050565b60008181526002602052604081205473ffffffffffffffffffffffffffffffffffffffff168061081b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201527f656e7420746f6b656e00000000000000000000000000000000000000000000006064820152608401610b82565b60007352c5cc403e8adef8978e6dc83747f86516547ca4636464f3656040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b6040517f64a701b7000000000000000000000000000000000000000000000000000000008152600481018290526000907352c5cc403e8adef8978e6dc83747f86516547ca4906364a701b79060240160206040518083038186803b158015611bf757600080fd5b505af4158015611c0b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081b9190614cca565b600073ffffffffffffffffffffffffffffffffffffffff8216611cd4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a6560448201527f726f2061646472657373000000000000000000000000000000000000000000006064820152608401610b82565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205490565b600a5473ffffffffffffffffffffffffffffffffffffffff163314611d7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b82565b611d886000612c27565b565b6040517f75992b9f00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201526000907352c5cc403e8adef8978e6dc83747f86516547ca4906375992b9f9060240160206040518083038186803b158015611df657600080fd5b505af4158015611e0a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081b9190614d85565b611e586040518060600160405280600063ffffffff16815260200160008152602001600081525090565b6040517f42f81709000000000000000000000000000000000000000000000000000000008152600481018390527352c5cc403e8adef8978e6dc83747f86516547ca4906342f817099060240160606040518083038186803b158015611ebc57600080fd5b505af4158015611ed0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081b9190614c51565b7352c5cc403e8adef8978e6dc83747f86516547ca4638cec0bfc6040518163ffffffff1660e01b815260040160006040518083038186803b158015611f3857600080fd5b505af4158015611f4c573d6000803e3d6000fd5b50505050565b600a5473ffffffffffffffffffffffffffffffffffffffff163314611fd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b82565b6000611ff4600d5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063a9059cbb90339083906370a082319060240160206040518083038186803b15801561206657600080fd5b505afa15801561207a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209e9190614cca565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401602060405180830381600087803b15801561210957600080fd5b505af115801561211d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121419190614a34565b6121a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e61626c6520746f207472616e7366657200000000000000000000000000006044820152606401610b82565b50565b606060018054610a529061558a565b610eaa338383612c9e565b6121ce33836125f0565b61225a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610b82565b611f4c84848484612dcc565b6040517f42f81709000000000000000000000000000000000000000000000000000000008152600481018290526060906000907352c5cc403e8adef8978e6dc83747f86516547ca4906342f817099060240160606040518083038186803b1580156122d057600080fd5b505af41580156122e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123089190614c51565b9050612318838260400151612e6f565b9392505050565b600a5473ffffffffffffffffffffffffffffffffffffffff1633146123a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b82565b73ffffffffffffffffffffffffffffffffffffffff8116612443576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b82565b6121a781612c27565b6000610ffb600d5473ffffffffffffffffffffffffffffffffffffffff1690565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd00000000000000000000000000000000000000000000000000000000148061250057507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b8061081b57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461081b565b600081815260046020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff841690811790915581906125aa82611a98565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008181526002602052604081205473ffffffffffffffffffffffffffffffffffffffff166126a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201527f697374656e7420746f6b656e00000000000000000000000000000000000000006064820152608401610b82565b60006126ac83611a98565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061271b57508373ffffffffffffffffffffffffffffffffffffffff1661270384610ad5565b73ffffffffffffffffffffffffffffffffffffffff16145b80612758575073ffffffffffffffffffffffffffffffffffffffff80821660009081526005602090815260408083209388168352929052205460ff165b949350505050565b8273ffffffffffffffffffffffffffffffffffffffff1661278082611a98565b73ffffffffffffffffffffffffffffffffffffffff1614612823576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201527f73206e6f74206f776e00000000000000000000000000000000000000000000006064820152608401610b82565b73ffffffffffffffffffffffffffffffffffffffff82166128c5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610b82565b6128d0838383613326565b6128db600082612550565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120805460019290612911908490615547565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600090815260036020526040812080546001929061294c9084906153b7565b909155505060008181526002602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b610eaa82826040518060200160405280600081525061342c565b600080612a0360125430634657284960e01b6134cf565b90506000612a9c60148054612a179061558a565b80601f0160208091040260200160405190810160405280929190818152602001828054612a439061558a565b8015612a905780601f10612a6557610100808354040283529160200191612a90565b820191906000526020600020905b815481529060010190602001808311612a7357829003601f168201915b50505050508686613560565b60408051808201909152600381527f67657400000000000000000000000000000000000000000000000000000000006020820152909150612adf90839083613597565b612b5e6040518060400160405280600a81526020017f706174685f6375737073000000000000000000000000000000000000000000008152506040518060400160405280600581526020017f6375737073000000000000000000000000000000000000000000000000000000815250846135979092919063ffffffff16565b612bdd6040518060400160405280600c81526020017f706174685f706c616e65747300000000000000000000000000000000000000008152506040518060400160405280600781526020017f706c616e65747300000000000000000000000000000000000000000000000000815250846135979092919063ffffffff16565b601154601354600091612c0a9173ffffffffffffffffffffffffffffffffffffffff9091169085906135b5565b600088815260176020526040902081905593505050509392505050565b600a805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612d34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610b82565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526005602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b612dd7848484612760565b612de3848484846136ac565b611f4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610b82565b6000828152601760205260409020546060907f3078300000000000000000000000000000000000000000000000000000000000811415612f0b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f546f6b656e206e6f74206d696e746564000000000000000000000000000000006044820152606401610b82565b60008181526016602090815260408083208151815460809481028201850190935260608101838152909391928492849190840182828015612f9357602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411612f5a5790505b505050505081526020016001820180548060200260200160405190810160405280929190818152602001828054801561301357602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411612fda5790505b50505091835250506002919091015460ff161515602090910152604081015190915061310d576015546040517fcefefb27000000000000000000000000000000000000000000000000000000008152600481018790526024810186905273ffffffffffffffffffffffffffffffffffffffff9091169063cefefb279060440160006040518083038186803b1580156130aa57600080fd5b505afa1580156130be573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526131049190810190614aff565b9250505061081b565b6040517e70aa00000000000000000000000000000000000000000000000000000000008152600481018690526000907352c5cc403e8adef8978e6dc83747f86516547ca4906270aa009060240160006040518083038186803b15801561317257600080fd5b505af4158015613186573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526131cc9190810190614b32565b6015548351602085015160608401518451805195965073ffffffffffffffffffffffffffffffffffffffff90941694635dde69bf948c91600090613239577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151876000015160018151811061327f577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101518c6040518863ffffffff1660e01b81526004016132aa97969594939291906150df565b60006040518083038186803b1580156132c257600080fd5b505afa1580156132d6573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261331c9190810190614aff565b935050505061081b565b73ffffffffffffffffffffffffffffffffffffffff831661338e5761338981600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b6133cb565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146133cb576133cb83826138ab565b73ffffffffffffffffffffffffffffffffffffffff82166133ef57610d3c81613962565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610d3c57610d3c8282613a86565b6134368383613ad7565b61344360008484846136ac565b610d3c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610b82565b61350d6040805160a0810182526000808252602080830182905282840182905260608084018390528451808601909552845283015290608082015290565b61354b6040805160a0810182526000808252602080830182905282840182905260608084018390528451808601909552845283015290608082015290565b61355781868686613ca5565b95945050505050565b60608361356c84613d3d565b8360405160200161357f93929190614efe565b60405160208183030381529060405290509392505050565b60808301516135a69083613e0e565b6080830151610d3c9082613e0e565b600f546000906135c68160016153b7565b600f55835160408086015160808701515191516000937f4042994600000000000000000000000000000000000000000000000000000000936136179386938493923092918a91600191602401615021565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506136a286838684613e25565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff84163b156138a0576040517f150b7a0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063150b7a0290613723903390899088908890600401614fe2565b602060405180830381600087803b15801561373d57600080fd5b505af192505050801561378b575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261378891810190614ae3565b60015b613855573d8080156137b9576040519150601f19603f3d011682016040523d82523d6000602084013e6137be565b606091505b50805161384d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610b82565b805181602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a0200000000000000000000000000000000000000000000000000000000149050612758565b506001949350505050565b600060016138b884611c2f565b6138c29190615547565b6000838152600760205260409020549091508082146139225773ffffffffffffffffffffffffffffffffffffffff841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b50600091825260076020908152604080842084905573ffffffffffffffffffffffffffffffffffffffff9094168352600681528383209183525290812055565b60085460009061397490600190615547565b600083815260096020526040812054600880549394509092849081106139c3577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b906000526020600020015490508060088381548110613a0b577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480613a6a577f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6001900381819060005260206000200160009055905550505050565b6000613a9183611c2f565b73ffffffffffffffffffffffffffffffffffffffff9093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b73ffffffffffffffffffffffffffffffffffffffff8216613b54576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610b82565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1615613be0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610b82565b613bec60008383613326565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120805460019290613c229084906153b7565b909155505060008181526002602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b613ce36040805160a0810182526000808252602080830182905282840182905260608084018390528451808601909552845283015290608082015290565b613cf38560800151610100614042565b505091835273ffffffffffffffffffffffffffffffffffffffff1660208301527fffffffff0000000000000000000000000000000000000000000000000000000016604082015290565b6060600082600081518110613d7b577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101519050600083600181518110613dc1577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101519050613dd88261ffff166140a7565b613de58261ffff166140a7565b604051602001613df6929190614ea6565b60405160208183030381529060405292505050919050565b613e1b8260038351614227565b610d3c8282614336565b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003060601b16602082015260348101849052600090605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815282825280516020918201206000818152601090925291812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a1617905590925082917fb5e6e01e79f91267dc17b4e6314d5d4d03593d2ceee0fbb452b750bd70ea5af99190a2600d546040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634000aea090613f64908890879087906004016150aa565b602060405180830381600087803b158015613f7e57600080fd5b505af1158015613f92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fb69190614a34565b612758576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f756e61626c6520746f207472616e73666572416e6443616c6c20746f206f726160448201527f636c6500000000000000000000000000000000000000000000000000000000006064820152608401610b82565b604080518082019091526060815260006020820152614062602083615611565b1561408a57614072602083615611565b61407d906020615547565b61408790836153b7565b91505b506020828101829052604080518085526000815290920101905290565b6060816140e757505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b811561411157806140fb816155d8565b915061410a9050600a836153cf565b91506140eb565b60008167ffffffffffffffff811115614153577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280601f01601f19166020018201604052801561417d576020820181803683370190505b5090505b841561275857614192600183615547565b915061419f600a86615611565b6141aa9060306153b7565b60f81b8183815181106141e6577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350614220600a866153cf565b9450614181565b60178167ffffffffffffffff161161424c57611f4c8360e0600585901b16831761435d565b60ff8167ffffffffffffffff161161428a57614273836018611fe0600586901b161761435d565b50611f4c8367ffffffffffffffff83166001614382565b61ffff8167ffffffffffffffff16116142c9576142b2836019611fe0600586901b161761435d565b50611f4c8367ffffffffffffffff83166002614382565b63ffffffff8167ffffffffffffffff161161430a576142f383601a611fe0600586901b161761435d565b50611f4c8367ffffffffffffffff83166004614382565b61431f83601b611fe0600586901b161761435d565b50611f4c8367ffffffffffffffff83166008614382565b604080518082019091526060815260006020820152612318838460000151518485516143a8565b60408051808201909152606081526000602082015261231883846000015151846144b0565b60408051808201909152606081526000602082015261275884856000015151858561450c565b60408051808201909152606081526000602082015282518211156143cb57600080fd5b60208501516143da83866153b7565b111561440d5761440d856143fd876020015187866143f891906153b7565b61458d565b61440890600261550a565b6145a4565b60008086518051876020830101935080888701111561442c5787860182525b505050602084015b6020841061446c578051825261444b6020836153b7565b91506144586020826153b7565b9050614465602085615547565b9350614434565b5181517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60208690036101000a019081169019919091161790525083949350505050565b604080518082019091526060815260006020820152836020015183106144e5576144e58485602001516002614408919061550a565b835180516020858301018481535080851415614502576001810182525b5093949350505050565b604080518082019091526060815260006020820152602085015161453085846153b7565b111561454457614544856143fd86856153b7565b6000600161455484610100615444565b61455e9190615547565b90508551838682010185831982511617815250805184870111156145825783860181525b509495945050505050565b60008183111561459e57508161081b565b50919050565b81516145b08383614042565b50611f4c8382614336565b82805482825590600052602060002090600f016010900481019282156146545791602002820160005b8382111561462457835183826101000a81548161ffff021916908361ffff16021790555092602001926002016020816001010492830192600103026145e4565b80156146525782816101000a81549061ffff0219169055600201602081600101049283019260010302614624565b505b506146609291506146f6565b5090565b8280546146709061558a565b90600052602060002090601f0160209004810192826146925760008555614654565b82601f106146c9578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00823516178555614654565b82800160010185558215614654579182015b828111156146545782358255916020019190600101906146db565b5b8082111561466057600081556001016146f7565b60008083601f84011261471c578182fd5b50813567ffffffffffffffff811115614733578182fd5b6020830191508360208260051b850101111561474e57600080fd5b9250929050565b8051610897816156d4565b60008083601f840112614771578182fd5b50813567ffffffffffffffff811115614788578182fd5b60208301915083602082850101111561474e57600080fd5b600082601f8301126147b0578081fd5b81516147c36147be82615371565b615322565b8181528460208386010111156147d7578283fd5b61275882602083016020870161555e565b805161089781615720565b600060208284031215614804578081fd5b8135612318816156b2565b600060208284031215614820578081fd5b8151612318816156b2565b6000806040838503121561483d578081fd5b8235614848816156b2565b91506020830135614858816156b2565b809150509250929050565b60008060008060008060008060e0898b03121561487e578384fd5b8835614889816156b2565b97506020890135614899816156b2565b965060408901359550606089013594506080890135935060a089013567ffffffffffffffff8111156148c9578384fd5b6148d58b828c01614760565b90945092505060c08901356148e9816156b2565b809150509295985092959890939650565b60008060006060848603121561490e578081fd5b8335614919816156b2565b92506020840135614929816156b2565b929592945050506040919091013590565b6000806000806080858703121561494f578182fd5b843561495a816156b2565b9350602085013561496a816156b2565b925060408501359150606085013567ffffffffffffffff81111561498c578182fd5b8501601f8101871361499c578182fd5b80356149aa6147be82615371565b8181528860208385010111156149be578384fd5b81602084016020830137908101602001929092525092959194509250565b600080604083850312156149ee578182fd5b82356149f9816156b2565b91506020830135614858816156d4565b60008060408385031215614a1b578182fd5b8235614a26816156b2565b946020939093013593505050565b600060208284031215614a45578081fd5b8151612318816156d4565b600080600080600060608688031215614a67578283fd5b85359450602086013567ffffffffffffffff80821115614a85578485fd5b614a9189838a0161470b565b90965094506040880135915080821115614aa9578283fd5b50614ab68882890161470b565b969995985093965092949392505050565b600060208284031215614ad8578081fd5b8135612318816156e2565b600060208284031215614af4578081fd5b8151612318816156e2565b600060208284031215614b10578081fd5b815167ffffffffffffffff811115614b26578182fd5b612758848285016147a0565b60006020808385031215614b44578182fd5b825167ffffffffffffffff80821115614b5b578384fd5b9084019060808287031215614b6e578384fd5b614b766152f9565b825182811115614b84578586fd5b8301601f81018813614b94578586fd5b805183811115614ba657614ba6615683565b8060051b614bb5878201615322565b828152878101908489018386018a018d1015614bcf578a8bfd5b8a95505b84861015614bfd5780519350614be884615710565b83835260019590950194918901918901614bd3565b508552505050508284015182811115614c14578586fd5b614c20888286016147a0565b8583015250614c3160408401614755565b6040820152614c42606084016147e8565b60608201529695505050505050565b600060608284031215614c62578081fd5b6040516060810181811067ffffffffffffffff82111715614c8557614c85615683565b6040528251614c9381615720565b8152602083810151908201526040928301519281019290925250919050565b600060208284031215614cc3578081fd5b5035919050565b600060208284031215614cdb578081fd5b5051919050565b600080600080600060608688031215614cf9578283fd5b85359450602086013567ffffffffffffffff80821115614d17578485fd5b614d2389838a0161470b565b90965094506040880135915080821115614d3b578283fd5b50614ab688828901614760565b60008060408385031215614d5a578182fd5b50508035926020909101359150565b600060208284031215614d7a578081fd5b813561231881615720565b600060208284031215614d96578081fd5b815161231881615720565b6000815180845260208085019450808401835b8381101561458257815161ffff1687529582019590820190600101614db4565b60008151808452614dec81602086016020860161555e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8051608080845281519084018190526000916020919082019060a0860190845b81811015614e5e57835161ffff1683529284019291840191600101614e3e565b505082850151915085810383870152614e778183614dd4565b925050506040830151151560408501526060830151614e9e606086018263ffffffff169052565b509392505050565b60008351614eb881846020880161555e565b7f2c000000000000000000000000000000000000000000000000000000000000009083019081528351614ef281600184016020880161555e565b01600101949350505050565b60008451614f1081846020890161555e565b80830190507f2f6170692f76312f63616c632d63686172742d646174612d646567726565732d81527f656e637279707465643f686f757365733d506c616369647573267a6f6469616360208201527f3d4b726973686e616d75727469266d6f6e7468416e644461793d00000000000060408201528451614f9781605a84016020890161555e565b7f2672656d61696e696e673d000000000000000000000000000000000000000000605a92909101918201528351614fd581606584016020880161555e565b0160650195945050505050565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015250836040830152608060608301526136a26080830184614dd4565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a60208501528960408501528089166060850152507fffffffff00000000000000000000000000000000000000000000000000000000871660808401528560a08401528460c08401528060e084015261509b81840185614dd4565b9b9a5050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff841681528260208201526060604082015260006135576060830184614dd4565b60e0815260006150f260e083018a614da1565b8281036020840152615104818a614da1565b63ffffffff9890981660408401525050606081019490945261ffff9283166080850152911660a083015260c09091015292915050565b6020815260006123186020830184614dd4565b60208152600082516080602084015261516960a0840182614da1565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160408501526151a48282614dd4565b91505060408401511515606084015263ffffffff60608501511660808401528091505092915050565b6020815260008251606060208401526151e96080840182614da1565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160408501526152248282614da1565b9150506040840151151560608401528091505092915050565b87815260a06020808301829052908201879052600090889060c08401835b8a81101561528457833561526e81615710565b61ffff168252928201929082019060010161525b565b508481036040860152878152878983830137878101820184905273ffffffffffffffffffffffffffffffffffffffff871660608601527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8901160191508084830301608085015261509b81830186614e1e565b6040516080810167ffffffffffffffff8111828210171561531c5761531c615683565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561536957615369615683565b604052919050565b600067ffffffffffffffff82111561538b5761538b615683565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082198211156153ca576153ca615625565b500190565b6000826153de576153de615654565b500490565b600181815b8085111561543c57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561542257615422615625565b8085161561542f57918102915b93841c93908002906153e8565b509250929050565b6000612318838360008261545a5750600161081b565b816154675750600061081b565b816001811461547d5760028114615487576154a3565b600191505061081b565b60ff84111561549857615498615625565b50506001821b61081b565b5060208310610133831016604e8410600b84101617156154c6575081810a61081b565b6154d083836153e3565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561550257615502615625565b029392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561554257615542615625565b500290565b60008282101561555957615559615625565b500390565b60005b83811015615579578181015183820152602001615561565b83811115611f4c5750506000910152565b600181811c9082168061559e57607f821691505b6020821081141561459e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561560a5761560a615625565b5060010190565b60008261562057615620615654565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff811681146121a757600080fd5b80151581146121a757600080fd5b7fffffffff00000000000000000000000000000000000000000000000000000000811681146121a757600080fd5b61ffff811681146121a757600080fd5b63ffffffff811681146121a757600080fdfea164736f6c6343000804000a000000000000000000000000d033c3d75349ba75280a2e3256e61235e7e6d680000000000000000000000000a7e203bcf2d8fe908385a480c21beb59b0d9404f
Deployed Bytecode
0x6080604052600436106102335760003560e01c80636352211e116101385780638da5cb5b116100b0578063b88d4fde1161007f578063e985e9c511610064578063e985e9c514610699578063f2fde38b146106ef578063ff6805951461070f57600080fd5b8063b88d4fde14610659578063c87b56dd1461067957600080fd5b80638da5cb5b146105e45780638dc654a21461060f57806395d89b4114610624578063a22cb4651461063957600080fd5b8063715018a6116101075780637eeb7dee116100ec5780637eeb7dee1461055a5780638990bf69146105a25780638cec0bfc146105cf57600080fd5b8063715018a61461051057806375992b9f1461052557600080fd5b80636352211e1461049b5780636464f365146104bb57806364a701b7146104d057806370a08231146104f057600080fd5b80632f2d248d116101cb578063465728491161019a5780634f6ccce71161017f5780634f6ccce7146104485780634f73c1911461046857806352fdf1c41461047b57600080fd5b80634657284914610408578063475f931c1461042857600080fd5b80632f2d248d146103935780632f745c59146103b35780633c793d49146103d357806342842e0e146103e857600080fd5b8063081812fc11610207578063081812fc146102ed578063095ea7b31461033257806318160ddd1461035457806323b872dd1461037357600080fd5b806270aa001461023857806301ffc9a71461026e57806302b3b1e81461029e57806306fdde03146102cb575b600080fd5b34801561024457600080fd5b50610258610253366004614cb2565b610724565b604051610265919061514d565b60405180910390f35b34801561027a57600080fd5b5061028e610289366004614ac7565b61089c565b6040519015158152602001610265565b3480156102aa57600080fd5b506102be6102b9366004614cb2565b6108f2565b60405161026591906151cd565b3480156102d757600080fd5b506102e0610a43565b604051610265919061513a565b3480156102f957600080fd5b5061030d610308366004614cb2565b610ad5565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610265565b34801561033e57600080fd5b5061035261034d366004614a09565b610bb4565b005b34801561036057600080fd5b506008545b604051908152602001610265565b34801561037f57600080fd5b5061035261038e3660046148fa565b610d41565b34801561039f57600080fd5b506103526103ae366004614cb2565b610de2565b3480156103bf57600080fd5b506103656103ce366004614a09565b610eae565b3480156103df57600080fd5b50610365610f7d565b3480156103f457600080fd5b506103526104033660046148fa565b611000565b34801561041457600080fd5b50610352610423366004614a50565b61101b565b34801561043457600080fd5b50610352610443366004614d48565b611226565b34801561045457600080fd5b50610365610463366004614cb2565b6113f1565b610352610476366004614ce2565b6114d6565b34801561048757600080fd5b50610352610496366004614863565b6118b5565b3480156104a757600080fd5b5061030d6104b6366004614cb2565b611a98565b3480156104c757600080fd5b50610365611b4a565b3480156104dc57600080fd5b506103656104eb366004614cb2565b611b90565b3480156104fc57600080fd5b5061036561050b3660046147f3565b611c2f565b34801561051c57600080fd5b50610352611cfd565b34801561053157600080fd5b50610545610540366004614d69565b611d8a565b60405163ffffffff9091168152602001610265565b34801561056657600080fd5b5061057a610575366004614cb2565b611e2e565b60408051825163ffffffff168152602080840151908201529181015190820152606001610265565b3480156105ae57600080fd5b506103656105bd366004614cb2565b60176020526000908152604090205481565b3480156105db57600080fd5b50610352611ef4565b3480156105f057600080fd5b50600a5473ffffffffffffffffffffffffffffffffffffffff1661030d565b34801561061b57600080fd5b50610352611f52565b34801561063057600080fd5b506102e06121aa565b34801561064557600080fd5b506103526106543660046149dc565b6121b9565b34801561066557600080fd5b5061035261067436600461493a565b6121c4565b34801561068557600080fd5b506102e0610694366004614cb2565b612266565b3480156106a557600080fd5b5061028e6106b436600461482b565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260056020908152604080832093909416825291909152205460ff1690565b3480156106fb57600080fd5b5061035261070a3660046147f3565b61231f565b34801561071b57600080fd5b5061030d61244c565b6040805160808101825260608082526020820181905260009282018390528101919091526107548261016e101590565b15610821576018546040517e70aa000000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff909116906270aa009060240160006040518083038186803b1580156107c157600080fd5b505afa1580156107d5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261081b9190810190614b32565b92915050565b6040517e70aa00000000000000000000000000000000000000000000000000000000008152600481018390527352c5cc403e8adef8978e6dc83747f86516547ca4906270aa009060240160006040518083038186803b15801561088357600080fd5b505af41580156107d5573d6000803e3d6000fd5b919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f780e9d6300000000000000000000000000000000000000000000000000000000148061081b575061081b8261246d565b60408051606080820183528082526020820152600091810191909152600082815260176020908152604080832054808452601683529281902081518154608094810282018501909352606081018381529093919284928491908401828280156109a257602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116109695790505b5050505050815260200160018201805480602002602001604051908101604052809291908181526020018280548015610a2257602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116109e95790505b50505091835250506002919091015460ff1615156020909101529392505050565b606060008054610a529061558a565b80601f0160208091040260200160405190810160405280929190818152602001828054610a7e9061558a565b8015610acb5780601f10610aa057610100808354040283529160200191610acb565b820191906000526020600020905b815481529060010190602001808311610aae57829003601f168201915b5050505050905090565b60008181526002602052604081205473ffffffffffffffffffffffffffffffffffffffff16610b8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201527f697374656e7420746f6b656e000000000000000000000000000000000000000060648201526084015b60405180910390fd5b5060009081526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b6000610bbf82611a98565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610c7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152608401610b82565b3373ffffffffffffffffffffffffffffffffffffffff82161480610ca65750610ca681336106b4565b610d32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610b82565b610d3c8383612550565b505050565b610d4b33826125f0565b610dd7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610b82565b610d3c838383612760565b600a5473ffffffffffffffffffffffffffffffffffffffff163314610e63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b82565b600a5460405173ffffffffffffffffffffffffffffffffffffffff9091169082156108fc029083906000818181858888f19350505050158015610eaa573d6000803e3d6000fd5b5050565b6000610eb983611c2f565b8210610f47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201527f74206f6620626f756e64730000000000000000000000000000000000000000006064820152608401610b82565b5073ffffffffffffffffffffffffffffffffffffffff919091166000908152600660209081526040808320938352929052205490565b60007352c5cc403e8adef8978e6dc83747f86516547ca4633c793d496040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b505af4158015610fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ffb9190614cca565b905090565b610d3c838383604051806020016040528060008152506121c4565b600085815260106020526040902054859073ffffffffffffffffffffffffffffffffffffffff1633146110d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f536f75726365206d75737420626520746865206f7261636c65206f662074686560448201527f20726571756573740000000000000000000000000000000000000000000000006064820152608401610b82565b60008181526010602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555182917f7cc135e0cebb02c3480ae5d74d377283180a2601f8f644edf7987b009316c63a91a2604051806060016040528086868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060408051602086810282810182019093528682529283019290918791879182918501908490808284376000920182905250938552505060016020938401525088815260168252604090208251805191926111cb928492909101906145bb565b5060208281015180516111e492600185019201906145bb565b5060409190910151600290910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055505050505050565b60006112348361016e101590565b6112465761124183611a98565b6112e8565b6018546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690636352211e9060240160206040518083038186803b1580156112b057600080fd5b505afa1580156112c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e8919061480f565b905073ffffffffffffffffffffffffffffffffffffffff81163314611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f4f4f4343425000000000000000000000000000000000000000000000000000006044820152606401610b82565b6040517f475f931c00000000000000000000000000000000000000000000000000000000815260048101849052602481018390527352c5cc403e8adef8978e6dc83747f86516547ca49063475f931c9060440160006040518083038186803b1580156113d457600080fd5b505af41580156113e8573d6000803e3d6000fd5b50505050505050565b60006113fc60085490565b821061148a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201527f7574206f6620626f756e647300000000000000000000000000000000000000006064820152608401610b82565b600882815481106114c4577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90600052602060002001549050919050565b60408051608081018252606080825260208201819052600092820183905281018290529061016e871161166f576018546040517e70aa000000000000000000000000000000000000000000000000000000000081526004810189905273ffffffffffffffffffffffffffffffffffffffff909116906270aa009060240160006040518083038186803b15801561156b57600080fd5b505afa15801561157f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115c59190810190614b32565b6018546040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018a905291935073ffffffffffffffffffffffffffffffffffffffff1690636352211e9060240160206040518083038186803b15801561163057600080fd5b505afa158015611644573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611668919061480f565b9050611739565b6040517e70aa00000000000000000000000000000000000000000000000000000000008152600481018890527352c5cc403e8adef8978e6dc83747f86516547ca4906270aa009060240160006040518083038186803b1580156116d157600080fd5b505af41580156116e5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261172b9190810190614b32565b915061173687611a98565b90505b6040517f5ad5275f0000000000000000000000000000000000000000000000000000000081526000907352c5cc403e8adef8978e6dc83747f86516547ca490635ad5275f90611798908b908b908b908b908b908a908c9060040161523d565b60206040518083038186803b1580156117b057600080fd5b505af41580156117c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e89190614cca565b90506117f433826129d2565b6118658188888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020601f8c018190048102820181019092528a815292508a91508990819084018382808284376000920191909152506129ec92505050565b5060408051828152602081018a9052338183015234606082015290517fb7c3334983fbe71312ff1b6135579300d4dbea95ebad47d3eeffbe23ea591f429181900360800190a15050505050505050565b600a5473ffffffffffffffffffffffffffffffffffffffff163314611936576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b82565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff89161790556012869055601385905561198c60148484614664565b50600d80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a161790556040517f496a01ad000000000000000000000000000000000000000000000000000000008152600481018590527352c5cc403e8adef8978e6dc83747f86516547ca49063496a01ad9060240160006040518083038186803b158015611a3157600080fd5b505af4158015611a45573d6000803e3d6000fd5b5050601580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9490941693909317909255505050505050505050565b60008181526002602052604081205473ffffffffffffffffffffffffffffffffffffffff168061081b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201527f656e7420746f6b656e00000000000000000000000000000000000000000000006064820152608401610b82565b60007352c5cc403e8adef8978e6dc83747f86516547ca4636464f3656040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b6040517f64a701b7000000000000000000000000000000000000000000000000000000008152600481018290526000907352c5cc403e8adef8978e6dc83747f86516547ca4906364a701b79060240160206040518083038186803b158015611bf757600080fd5b505af4158015611c0b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081b9190614cca565b600073ffffffffffffffffffffffffffffffffffffffff8216611cd4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a6560448201527f726f2061646472657373000000000000000000000000000000000000000000006064820152608401610b82565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205490565b600a5473ffffffffffffffffffffffffffffffffffffffff163314611d7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b82565b611d886000612c27565b565b6040517f75992b9f00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201526000907352c5cc403e8adef8978e6dc83747f86516547ca4906375992b9f9060240160206040518083038186803b158015611df657600080fd5b505af4158015611e0a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081b9190614d85565b611e586040518060600160405280600063ffffffff16815260200160008152602001600081525090565b6040517f42f81709000000000000000000000000000000000000000000000000000000008152600481018390527352c5cc403e8adef8978e6dc83747f86516547ca4906342f817099060240160606040518083038186803b158015611ebc57600080fd5b505af4158015611ed0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081b9190614c51565b7352c5cc403e8adef8978e6dc83747f86516547ca4638cec0bfc6040518163ffffffff1660e01b815260040160006040518083038186803b158015611f3857600080fd5b505af4158015611f4c573d6000803e3d6000fd5b50505050565b600a5473ffffffffffffffffffffffffffffffffffffffff163314611fd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b82565b6000611ff4600d5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063a9059cbb90339083906370a082319060240160206040518083038186803b15801561206657600080fd5b505afa15801561207a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209e9190614cca565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401602060405180830381600087803b15801561210957600080fd5b505af115801561211d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121419190614a34565b6121a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e61626c6520746f207472616e7366657200000000000000000000000000006044820152606401610b82565b50565b606060018054610a529061558a565b610eaa338383612c9e565b6121ce33836125f0565b61225a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610b82565b611f4c84848484612dcc565b6040517f42f81709000000000000000000000000000000000000000000000000000000008152600481018290526060906000907352c5cc403e8adef8978e6dc83747f86516547ca4906342f817099060240160606040518083038186803b1580156122d057600080fd5b505af41580156122e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123089190614c51565b9050612318838260400151612e6f565b9392505050565b600a5473ffffffffffffffffffffffffffffffffffffffff1633146123a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b82565b73ffffffffffffffffffffffffffffffffffffffff8116612443576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b82565b6121a781612c27565b6000610ffb600d5473ffffffffffffffffffffffffffffffffffffffff1690565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd00000000000000000000000000000000000000000000000000000000148061250057507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b8061081b57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461081b565b600081815260046020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff841690811790915581906125aa82611a98565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008181526002602052604081205473ffffffffffffffffffffffffffffffffffffffff166126a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201527f697374656e7420746f6b656e00000000000000000000000000000000000000006064820152608401610b82565b60006126ac83611a98565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061271b57508373ffffffffffffffffffffffffffffffffffffffff1661270384610ad5565b73ffffffffffffffffffffffffffffffffffffffff16145b80612758575073ffffffffffffffffffffffffffffffffffffffff80821660009081526005602090815260408083209388168352929052205460ff165b949350505050565b8273ffffffffffffffffffffffffffffffffffffffff1661278082611a98565b73ffffffffffffffffffffffffffffffffffffffff1614612823576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201527f73206e6f74206f776e00000000000000000000000000000000000000000000006064820152608401610b82565b73ffffffffffffffffffffffffffffffffffffffff82166128c5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610b82565b6128d0838383613326565b6128db600082612550565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120805460019290612911908490615547565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600090815260036020526040812080546001929061294c9084906153b7565b909155505060008181526002602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b610eaa82826040518060200160405280600081525061342c565b600080612a0360125430634657284960e01b6134cf565b90506000612a9c60148054612a179061558a565b80601f0160208091040260200160405190810160405280929190818152602001828054612a439061558a565b8015612a905780601f10612a6557610100808354040283529160200191612a90565b820191906000526020600020905b815481529060010190602001808311612a7357829003601f168201915b50505050508686613560565b60408051808201909152600381527f67657400000000000000000000000000000000000000000000000000000000006020820152909150612adf90839083613597565b612b5e6040518060400160405280600a81526020017f706174685f6375737073000000000000000000000000000000000000000000008152506040518060400160405280600581526020017f6375737073000000000000000000000000000000000000000000000000000000815250846135979092919063ffffffff16565b612bdd6040518060400160405280600c81526020017f706174685f706c616e65747300000000000000000000000000000000000000008152506040518060400160405280600781526020017f706c616e65747300000000000000000000000000000000000000000000000000815250846135979092919063ffffffff16565b601154601354600091612c0a9173ffffffffffffffffffffffffffffffffffffffff9091169085906135b5565b600088815260176020526040902081905593505050509392505050565b600a805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612d34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610b82565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526005602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b612dd7848484612760565b612de3848484846136ac565b611f4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610b82565b6000828152601760205260409020546060907f3078300000000000000000000000000000000000000000000000000000000000811415612f0b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f546f6b656e206e6f74206d696e746564000000000000000000000000000000006044820152606401610b82565b60008181526016602090815260408083208151815460809481028201850190935260608101838152909391928492849190840182828015612f9357602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411612f5a5790505b505050505081526020016001820180548060200260200160405190810160405280929190818152602001828054801561301357602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411612fda5790505b50505091835250506002919091015460ff161515602090910152604081015190915061310d576015546040517fcefefb27000000000000000000000000000000000000000000000000000000008152600481018790526024810186905273ffffffffffffffffffffffffffffffffffffffff9091169063cefefb279060440160006040518083038186803b1580156130aa57600080fd5b505afa1580156130be573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526131049190810190614aff565b9250505061081b565b6040517e70aa00000000000000000000000000000000000000000000000000000000008152600481018690526000907352c5cc403e8adef8978e6dc83747f86516547ca4906270aa009060240160006040518083038186803b15801561317257600080fd5b505af4158015613186573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526131cc9190810190614b32565b6015548351602085015160608401518451805195965073ffffffffffffffffffffffffffffffffffffffff90941694635dde69bf948c91600090613239577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151876000015160018151811061327f577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101518c6040518863ffffffff1660e01b81526004016132aa97969594939291906150df565b60006040518083038186803b1580156132c257600080fd5b505afa1580156132d6573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261331c9190810190614aff565b935050505061081b565b73ffffffffffffffffffffffffffffffffffffffff831661338e5761338981600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b6133cb565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146133cb576133cb83826138ab565b73ffffffffffffffffffffffffffffffffffffffff82166133ef57610d3c81613962565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610d3c57610d3c8282613a86565b6134368383613ad7565b61344360008484846136ac565b610d3c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610b82565b61350d6040805160a0810182526000808252602080830182905282840182905260608084018390528451808601909552845283015290608082015290565b61354b6040805160a0810182526000808252602080830182905282840182905260608084018390528451808601909552845283015290608082015290565b61355781868686613ca5565b95945050505050565b60608361356c84613d3d565b8360405160200161357f93929190614efe565b60405160208183030381529060405290509392505050565b60808301516135a69083613e0e565b6080830151610d3c9082613e0e565b600f546000906135c68160016153b7565b600f55835160408086015160808701515191516000937f4042994600000000000000000000000000000000000000000000000000000000936136179386938493923092918a91600191602401615021565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506136a286838684613e25565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff84163b156138a0576040517f150b7a0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063150b7a0290613723903390899088908890600401614fe2565b602060405180830381600087803b15801561373d57600080fd5b505af192505050801561378b575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261378891810190614ae3565b60015b613855573d8080156137b9576040519150601f19603f3d011682016040523d82523d6000602084013e6137be565b606091505b50805161384d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610b82565b805181602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a0200000000000000000000000000000000000000000000000000000000149050612758565b506001949350505050565b600060016138b884611c2f565b6138c29190615547565b6000838152600760205260409020549091508082146139225773ffffffffffffffffffffffffffffffffffffffff841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b50600091825260076020908152604080842084905573ffffffffffffffffffffffffffffffffffffffff9094168352600681528383209183525290812055565b60085460009061397490600190615547565b600083815260096020526040812054600880549394509092849081106139c3577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b906000526020600020015490508060088381548110613a0b577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480613a6a577f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6001900381819060005260206000200160009055905550505050565b6000613a9183611c2f565b73ffffffffffffffffffffffffffffffffffffffff9093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b73ffffffffffffffffffffffffffffffffffffffff8216613b54576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610b82565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1615613be0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610b82565b613bec60008383613326565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120805460019290613c229084906153b7565b909155505060008181526002602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b613ce36040805160a0810182526000808252602080830182905282840182905260608084018390528451808601909552845283015290608082015290565b613cf38560800151610100614042565b505091835273ffffffffffffffffffffffffffffffffffffffff1660208301527fffffffff0000000000000000000000000000000000000000000000000000000016604082015290565b6060600082600081518110613d7b577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101519050600083600181518110613dc1577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101519050613dd88261ffff166140a7565b613de58261ffff166140a7565b604051602001613df6929190614ea6565b60405160208183030381529060405292505050919050565b613e1b8260038351614227565b610d3c8282614336565b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003060601b16602082015260348101849052600090605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815282825280516020918201206000818152601090925291812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a1617905590925082917fb5e6e01e79f91267dc17b4e6314d5d4d03593d2ceee0fbb452b750bd70ea5af99190a2600d546040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634000aea090613f64908890879087906004016150aa565b602060405180830381600087803b158015613f7e57600080fd5b505af1158015613f92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fb69190614a34565b612758576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f756e61626c6520746f207472616e73666572416e6443616c6c20746f206f726160448201527f636c6500000000000000000000000000000000000000000000000000000000006064820152608401610b82565b604080518082019091526060815260006020820152614062602083615611565b1561408a57614072602083615611565b61407d906020615547565b61408790836153b7565b91505b506020828101829052604080518085526000815290920101905290565b6060816140e757505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b811561411157806140fb816155d8565b915061410a9050600a836153cf565b91506140eb565b60008167ffffffffffffffff811115614153577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280601f01601f19166020018201604052801561417d576020820181803683370190505b5090505b841561275857614192600183615547565b915061419f600a86615611565b6141aa9060306153b7565b60f81b8183815181106141e6577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350614220600a866153cf565b9450614181565b60178167ffffffffffffffff161161424c57611f4c8360e0600585901b16831761435d565b60ff8167ffffffffffffffff161161428a57614273836018611fe0600586901b161761435d565b50611f4c8367ffffffffffffffff83166001614382565b61ffff8167ffffffffffffffff16116142c9576142b2836019611fe0600586901b161761435d565b50611f4c8367ffffffffffffffff83166002614382565b63ffffffff8167ffffffffffffffff161161430a576142f383601a611fe0600586901b161761435d565b50611f4c8367ffffffffffffffff83166004614382565b61431f83601b611fe0600586901b161761435d565b50611f4c8367ffffffffffffffff83166008614382565b604080518082019091526060815260006020820152612318838460000151518485516143a8565b60408051808201909152606081526000602082015261231883846000015151846144b0565b60408051808201909152606081526000602082015261275884856000015151858561450c565b60408051808201909152606081526000602082015282518211156143cb57600080fd5b60208501516143da83866153b7565b111561440d5761440d856143fd876020015187866143f891906153b7565b61458d565b61440890600261550a565b6145a4565b60008086518051876020830101935080888701111561442c5787860182525b505050602084015b6020841061446c578051825261444b6020836153b7565b91506144586020826153b7565b9050614465602085615547565b9350614434565b5181517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60208690036101000a019081169019919091161790525083949350505050565b604080518082019091526060815260006020820152836020015183106144e5576144e58485602001516002614408919061550a565b835180516020858301018481535080851415614502576001810182525b5093949350505050565b604080518082019091526060815260006020820152602085015161453085846153b7565b111561454457614544856143fd86856153b7565b6000600161455484610100615444565b61455e9190615547565b90508551838682010185831982511617815250805184870111156145825783860181525b509495945050505050565b60008183111561459e57508161081b565b50919050565b81516145b08383614042565b50611f4c8382614336565b82805482825590600052602060002090600f016010900481019282156146545791602002820160005b8382111561462457835183826101000a81548161ffff021916908361ffff16021790555092602001926002016020816001010492830192600103026145e4565b80156146525782816101000a81549061ffff0219169055600201602081600101049283019260010302614624565b505b506146609291506146f6565b5090565b8280546146709061558a565b90600052602060002090601f0160209004810192826146925760008555614654565b82601f106146c9578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00823516178555614654565b82800160010185558215614654579182015b828111156146545782358255916020019190600101906146db565b5b8082111561466057600081556001016146f7565b60008083601f84011261471c578182fd5b50813567ffffffffffffffff811115614733578182fd5b6020830191508360208260051b850101111561474e57600080fd5b9250929050565b8051610897816156d4565b60008083601f840112614771578182fd5b50813567ffffffffffffffff811115614788578182fd5b60208301915083602082850101111561474e57600080fd5b600082601f8301126147b0578081fd5b81516147c36147be82615371565b615322565b8181528460208386010111156147d7578283fd5b61275882602083016020870161555e565b805161089781615720565b600060208284031215614804578081fd5b8135612318816156b2565b600060208284031215614820578081fd5b8151612318816156b2565b6000806040838503121561483d578081fd5b8235614848816156b2565b91506020830135614858816156b2565b809150509250929050565b60008060008060008060008060e0898b03121561487e578384fd5b8835614889816156b2565b97506020890135614899816156b2565b965060408901359550606089013594506080890135935060a089013567ffffffffffffffff8111156148c9578384fd5b6148d58b828c01614760565b90945092505060c08901356148e9816156b2565b809150509295985092959890939650565b60008060006060848603121561490e578081fd5b8335614919816156b2565b92506020840135614929816156b2565b929592945050506040919091013590565b6000806000806080858703121561494f578182fd5b843561495a816156b2565b9350602085013561496a816156b2565b925060408501359150606085013567ffffffffffffffff81111561498c578182fd5b8501601f8101871361499c578182fd5b80356149aa6147be82615371565b8181528860208385010111156149be578384fd5b81602084016020830137908101602001929092525092959194509250565b600080604083850312156149ee578182fd5b82356149f9816156b2565b91506020830135614858816156d4565b60008060408385031215614a1b578182fd5b8235614a26816156b2565b946020939093013593505050565b600060208284031215614a45578081fd5b8151612318816156d4565b600080600080600060608688031215614a67578283fd5b85359450602086013567ffffffffffffffff80821115614a85578485fd5b614a9189838a0161470b565b90965094506040880135915080821115614aa9578283fd5b50614ab68882890161470b565b969995985093965092949392505050565b600060208284031215614ad8578081fd5b8135612318816156e2565b600060208284031215614af4578081fd5b8151612318816156e2565b600060208284031215614b10578081fd5b815167ffffffffffffffff811115614b26578182fd5b612758848285016147a0565b60006020808385031215614b44578182fd5b825167ffffffffffffffff80821115614b5b578384fd5b9084019060808287031215614b6e578384fd5b614b766152f9565b825182811115614b84578586fd5b8301601f81018813614b94578586fd5b805183811115614ba657614ba6615683565b8060051b614bb5878201615322565b828152878101908489018386018a018d1015614bcf578a8bfd5b8a95505b84861015614bfd5780519350614be884615710565b83835260019590950194918901918901614bd3565b508552505050508284015182811115614c14578586fd5b614c20888286016147a0565b8583015250614c3160408401614755565b6040820152614c42606084016147e8565b60608201529695505050505050565b600060608284031215614c62578081fd5b6040516060810181811067ffffffffffffffff82111715614c8557614c85615683565b6040528251614c9381615720565b8152602083810151908201526040928301519281019290925250919050565b600060208284031215614cc3578081fd5b5035919050565b600060208284031215614cdb578081fd5b5051919050565b600080600080600060608688031215614cf9578283fd5b85359450602086013567ffffffffffffffff80821115614d17578485fd5b614d2389838a0161470b565b90965094506040880135915080821115614d3b578283fd5b50614ab688828901614760565b60008060408385031215614d5a578182fd5b50508035926020909101359150565b600060208284031215614d7a578081fd5b813561231881615720565b600060208284031215614d96578081fd5b815161231881615720565b6000815180845260208085019450808401835b8381101561458257815161ffff1687529582019590820190600101614db4565b60008151808452614dec81602086016020860161555e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8051608080845281519084018190526000916020919082019060a0860190845b81811015614e5e57835161ffff1683529284019291840191600101614e3e565b505082850151915085810383870152614e778183614dd4565b925050506040830151151560408501526060830151614e9e606086018263ffffffff169052565b509392505050565b60008351614eb881846020880161555e565b7f2c000000000000000000000000000000000000000000000000000000000000009083019081528351614ef281600184016020880161555e565b01600101949350505050565b60008451614f1081846020890161555e565b80830190507f2f6170692f76312f63616c632d63686172742d646174612d646567726565732d81527f656e637279707465643f686f757365733d506c616369647573267a6f6469616360208201527f3d4b726973686e616d75727469266d6f6e7468416e644461793d00000000000060408201528451614f9781605a84016020890161555e565b7f2672656d61696e696e673d000000000000000000000000000000000000000000605a92909101918201528351614fd581606584016020880161555e565b0160650195945050505050565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015250836040830152608060608301526136a26080830184614dd4565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a60208501528960408501528089166060850152507fffffffff00000000000000000000000000000000000000000000000000000000871660808401528560a08401528460c08401528060e084015261509b81840185614dd4565b9b9a5050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff841681528260208201526060604082015260006135576060830184614dd4565b60e0815260006150f260e083018a614da1565b8281036020840152615104818a614da1565b63ffffffff9890981660408401525050606081019490945261ffff9283166080850152911660a083015260c09091015292915050565b6020815260006123186020830184614dd4565b60208152600082516080602084015261516960a0840182614da1565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160408501526151a48282614dd4565b91505060408401511515606084015263ffffffff60608501511660808401528091505092915050565b6020815260008251606060208401526151e96080840182614da1565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160408501526152248282614da1565b9150506040840151151560608401528091505092915050565b87815260a06020808301829052908201879052600090889060c08401835b8a81101561528457833561526e81615710565b61ffff168252928201929082019060010161525b565b508481036040860152878152878983830137878101820184905273ffffffffffffffffffffffffffffffffffffffff871660608601527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8901160191508084830301608085015261509b81830186614e1e565b6040516080810167ffffffffffffffff8111828210171561531c5761531c615683565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561536957615369615683565b604052919050565b600067ffffffffffffffff82111561538b5761538b615683565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082198211156153ca576153ca615625565b500190565b6000826153de576153de615654565b500490565b600181815b8085111561543c57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561542257615422615625565b8085161561542f57918102915b93841c93908002906153e8565b509250929050565b6000612318838360008261545a5750600161081b565b816154675750600061081b565b816001811461547d5760028114615487576154a3565b600191505061081b565b60ff84111561549857615498615625565b50506001821b61081b565b5060208310610133831016604e8410600b84101617156154c6575081810a61081b565b6154d083836153e3565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561550257615502615625565b029392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561554257615542615625565b500290565b60008282101561555957615559615625565b500390565b60005b83811015615579578181015183820152602001615561565b83811115611f4c5750506000910152565b600181811c9082168061559e57607f821691505b6020821081141561459e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561560a5761560a615625565b5060010190565b60008261562057615620615654565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff811681146121a757600080fd5b80151581146121a757600080fd5b7fffffffff00000000000000000000000000000000000000000000000000000000811681146121a757600080fd5b61ffff811681146121a757600080fd5b63ffffffff811681146121a757600080fdfea164736f6c6343000804000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d033c3d75349ba75280a2e3256e61235e7e6d680000000000000000000000000a7e203bcf2d8fe908385a480c21beb59b0d9404f
-----Decoded View---------------
Arg [0] : _primeAstroChartAddress (address): 0xD033c3D75349Ba75280A2E3256E61235E7e6D680
Arg [1] : _svgGeneratorAddress (address): 0xA7E203BcF2d8fE908385A480c21bEB59b0D9404f
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000d033c3d75349ba75280a2e3256e61235e7e6d680
Arg [1] : 000000000000000000000000a7e203bcf2d8fe908385a480c21beb59b0d9404f
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $11.98 | 1.999 | $23.95 |
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.