Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 76 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Begin | 22051552 | 5 days ago | IN | 0 ETH | 0.00002852 | ||||
Begin | 22051551 | 5 days ago | IN | 0 ETH | 0.00002798 | ||||
Begin | 22051550 | 5 days ago | IN | 0 ETH | 0.00011548 | ||||
Begin | 21996105 | 12 days ago | IN | 0 ETH | 0.0001692 | ||||
Begin | 21963719 | 17 days ago | IN | 0 ETH | 0.00014672 | ||||
End | 21796014 | 40 days ago | IN | 0 ETH | 0.00008823 | ||||
End | 21724954 | 50 days ago | IN | 0 ETH | 0.0002915 | ||||
End | 21674063 | 57 days ago | IN | 0 ETH | 0.00068799 | ||||
Begin | 21648168 | 61 days ago | IN | 0 ETH | 0.00070649 | ||||
End | 21646200 | 61 days ago | IN | 0 ETH | 0.00025176 | ||||
End | 21646200 | 61 days ago | IN | 0 ETH | 0.00034299 | ||||
Begin | 21645195 | 61 days ago | IN | 0 ETH | 0.00248574 | ||||
Begin | 21644751 | 61 days ago | IN | 0 ETH | 0.00088029 | ||||
Begin | 21608991 | 66 days ago | IN | 0 ETH | 0.00040823 | ||||
Begin | 21600708 | 68 days ago | IN | 0 ETH | 0.00051621 | ||||
Begin | 21571110 | 72 days ago | IN | 0 ETH | 0.00042955 | ||||
Begin | 21381127 | 98 days ago | IN | 0 ETH | 0.00453751 | ||||
End | 21323012 | 106 days ago | IN | 0 ETH | 0.00165273 | ||||
End | 21299895 | 110 days ago | IN | 0 ETH | 0.00029528 | ||||
Begin | 21299862 | 110 days ago | IN | 0 ETH | 0.00102973 | ||||
End | 21299743 | 110 days ago | IN | 0 ETH | 0.00042589 | ||||
Begin | 21299397 | 110 days ago | IN | 0 ETH | 0.00092715 | ||||
Begin | 21297569 | 110 days ago | IN | 0 ETH | 0.00104724 | ||||
Begin | 21295462 | 110 days ago | IN | 0 ETH | 0.00161926 | ||||
Begin | 21244257 | 117 days ago | IN | 0 ETH | 0.00208062 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x6101eb80 | 21173557 | 127 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
Travelers
Compiler Version
v0.8.28+commit.7893614a
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Dear God, Layer of Roads (Travelers) // by Loucas Braconnier (Figure31) // This contract is a machine that lays time. import "solady/src/utils/LibString.sol"; import "solady/src/utils/SSTORE2.sol"; import "solady/src/auth/Ownable.sol"; import "./Sculpture.sol"; import "./Perlin.sol"; import "./Journey.sol"; import "./JourneyRender.sol"; contract Travelers is Sculpture, Ownable { // Events event JourneyBegun(address indexed traveler, uint256 indexed id, int48 fromBlock, bool direction); event JourneyEnded(address indexed traveler, uint256 indexed id, int48 toBlock); // Storage mapping(uint256 => Journey) public journeys; uint256 public journeyCount; uint256 public journeyCompletedCount; uint256 public journeyBackwardCount; uint256 public journeyBackwardCompletedCount; mapping(address => uint256) travelerCurrentJourneyId; mapping(address => uint256) travelerJourneyCount; mapping(uint256 => uint256) travelerFootprint; address public render; string[] private urls_; address private text_; uint256 public previewWidth = 75; // Constructor constructor() { _initializeOwner(msg.sender); } function init() public { require(!amITravelling(address(this)), "Already travelling"); _begin(true, address(this)); } // Admin function setRender(address _render) public onlyOwner { render = _render; } function setUrls(string[] memory _urls) public onlyOwner { urls_ = _urls; } function setText(string memory _text) public onlyOwner { text_ = SSTORE2.write(bytes(_text)); } function setPreviewWidth(uint256 _previewWidth) public onlyOwner { previewWidth = _previewWidth; } // Travel function begin(bool direction) public { _begin(direction, msg.sender); } function _begin(bool direction, address traveler) internal { uint256 currentJourneyId = travelerCurrentJourneyId[traveler]; Journey memory currentJourney = journeys[currentJourneyId]; require(currentJourney.active == false, "Already travelling"); journeyCount++; // ids start at 1 if (!direction) journeyBackwardCount++; Journey memory newJourney = Journey({ id: uint48(journeyCount), fromBlockActual: uint48(block.number), fromBlock: currentJourney.traveler == address(0) ? int48(int(block.number)) : currentJourney.toBlock, toBlock: 0, forward: direction, active: true, previousId: uint48(currentJourneyId), traveler: traveler }); journeys[journeyCount] = newJourney; travelerJourneyCount[traveler]++; travelerCurrentJourneyId[traveler] = journeyCount; emit JourneyBegun(traveler, journeyCount, newJourney.fromBlock, direction); } function end() public { uint256 currentJourneyId = travelerCurrentJourneyId[msg.sender]; Journey memory currentJourney = journeys[currentJourneyId]; require(currentJourney.active == true, "Not travelling"); journeys[currentJourneyId].toBlock = currentJourney.forward? currentJourney.fromBlock + int48(int(block.number - currentJourney.fromBlockActual)) : currentJourney.fromBlock - int48(int(block.number - currentJourney.fromBlockActual)); journeys[currentJourneyId].active = false; journeyCompletedCount++; if (!currentJourney.forward) journeyBackwardCompletedCount++; emit JourneyEnded(msg.sender, currentJourneyId, journeys[currentJourneyId].toBlock); } // Landscape function landscape(uint256 journeyId, uint256 offset, uint256 limit) public view returns (string memory) { Journey memory journey = journeys[journeyId]; uint256 travelerCount = travelers(journey.forward); return JourneyRender(render).landscape(journey, journeyId, offset, limit, journeyCount, travelerCount); } function landscapeFromTo(uint256 journeyId, int256 blockFrom, int256 blockTo) public view returns (string memory) { Journey memory journey = journeys[journeyId]; uint256 travelerCount = travelers(journey.forward); return JourneyRender(render).landscapeFromTo(journey, journeyId, blockFrom, blockTo, journeyCount, travelerCount); } function landscapeHeight(uint256 journeyId, uint256 offset, uint256 limit) public view returns (string memory) { return JourneyRender(render).landscapeHeight(journeys[journeyId], journeyId, offset, limit, journeyCount); } function landscapeHeightFromTo(uint256 journeyId, int256 blockFrom, int256 blockTo) public view returns (string memory) { return JourneyRender(render).landscapeHeightFromTo(journeys[journeyId], journeyId, blockFrom, blockTo, journeyCount); } // View function travelers() public view returns (uint256) { return journeyCount - journeyCompletedCount; } function travelers(bool direction) public view returns (uint256) { return direction ? journeyCount - journeyBackwardCount : journeyBackwardCount; } function whereAmI(address me) public view returns (int) { uint256 currentJourneyId = travelerCurrentJourneyId[me]; Journey memory currentJourney = journeys[currentJourneyId]; if (currentJourney.active == false && currentJourney.toBlock == 0) return int(block.number); return currentJourney.forward? currentJourney.fromBlock + int48(int(block.number - currentJourney.fromBlockActual)) : currentJourney.fromBlock - int48(int(block.number - currentJourney.fromBlockActual)); } function amITravelling(address me) public view returns (bool) { uint256 currentJourneyId = travelerCurrentJourneyId[me]; Journey memory currentJourney = journeys[currentJourneyId]; return currentJourney.active; } function howFarHaveICome(address me) public view returns (int) { uint256 currentJourneyId = travelerCurrentJourneyId[me]; Journey memory currentJourney = journeys[currentJourneyId]; require(currentJourney.active == true, "Not travelling"); return int(block.number) - currentJourney.fromBlock; } function mostRecentJourneyOf(address me) public view returns (Journey memory) { uint256 currentJourneyId = travelerCurrentJourneyId[me]; return journeys[currentJourneyId]; } function mostRecentJourneys(uint256 limit) public view returns (Journey[] memory) { if (limit > journeyCount) limit = journeyCount; Journey[] memory _journeys = new Journey[](limit); for (uint256 i = 0; i < limit; i++) { _journeys[i] = journeys[journeyCount - limit + i + 1]; } return _journeys; } function journeysOf(address me) public view returns (Journey[] memory) { // Note: this could fail if the user has too many journeys uint256 count = travelerJourneyCount[me]; Journey[] memory _journeys = new Journey[](count); Journey memory currentJourney = journeys[travelerCurrentJourneyId[me]]; if (count == 0) return _journeys; _journeys[count - 1] = currentJourney; if (count == 1) return _journeys; for (uint256 i = count - 1; i > 0; i--) { _journeys[i - 1] = journeys[uint256(_journeys[i].previousId)]; } return _journeys; } function getJourney(uint256 id) public view returns (Journey memory) { require(0 < id && id <= journeyCount, "Journey does not exist"); return journeys[id]; } function getJourneys(uint256 offset, uint256 limit) public view returns (Journey[] memory) { if (offset >= journeyCount) { return new Journey[](0); } else if (offset + limit > journeyCount) { limit = journeyCount - offset; } Journey[] memory _journeys = new Journey[](limit); for (uint256 i = 0; i < limit; i++) { _journeys[i] = journeys[offset + i + 1]; } return _journeys; } // Sculpture function title() public pure override returns (string memory) { return "Dear God, Layer of Roads (Travelers)"; } function authors() public pure override returns (string[] memory) { string[] memory _authors = new string[](1); _authors[0] = "Loucas Braconnier (Figure31)"; return _authors; } function addresses() public view override returns (address[] memory) { address[] memory _addresses = new address[](1); _addresses[0] = address(this); return _addresses; } function urls() public view override returns (string[] memory) { return urls_; } function text() public view override returns (string memory) { uint256 t = travelers(); uint256 tf = travelers(true); try JourneyRender(render).landscapeFromTo(journeys[1], 1, int(block.number) - int(previewWidth), int(block.number), journeyCount, tf) returns (string memory string_) { return string.concat( '<br/><br/>', text_ == address(0) ? "" : string(SSTORE2.read(text_)), ' At the moment there ', t == 1 ? 'is ' : 'are ', LibString.toString(t), ' traveler', t == 1 ? '' : 's', ' on the road. ', '<br/><br/><br/><br/>', string_ ); } catch { return string.concat( '<br/><br/>', text_ == address(0) ? "" : string(SSTORE2.read(text_)), ' At the moment there ', t == 1 ? 'is ' : 'are ', LibString.toString(t), ' traveler', t == 1 ? '' : 's', ' on the road. ' ); } } }
// 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 result += xh == hi >> 128 ? xl / y : 1; } 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 >= 0x4) { 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); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; struct Journey { address traveler; uint48 id; uint48 fromBlockActual; // actual block number used to measure int48 fromBlock; int48 toBlock; bool forward; bool active; uint48 previousId; // index of the previous journey }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Dear God, Layer of Roads (Travelers) // by Loucas Braconnier (Figure31) import "solady/src/auth/Ownable.sol"; import "solady/src/utils/SSTORE2.sol"; import "solady/src/utils/LibString.sol"; import "./Perlin.sol"; import "./Journey.sol"; contract JourneyRender is Ownable { string[] public BOTTOM; string[] public MID; string[] public TOP; string[] public MONUMENT; string public constant TOP_FOOTPRINT = unicode"ᵒ"; string public constant BOTTOM_FOOTPRINT = unicode"ₒ"; uint256 public threshold = 1000; function setThreshold(uint256 _threshold) public onlyOwner { threshold = _threshold; } constructor() { BOTTOM = [unicode"⚊", "_", unicode"_", unicode"⎽"]; MID = [unicode"ー", unicode"一", unicode"ᅳ", unicode"᠆", unicode"﹣", "-", unicode"–", unicode"‑"]; TOP = [unicode"Ⲻ", unicode" ̄", unicode"‾", unicode" ̄", unicode"¯", unicode"⎺", unicode"⎻"]; MONUMENT = [unicode"▁", unicode"▂", unicode"▃", unicode"▄", unicode"▅", unicode"▆", unicode"▇", unicode"█"]; _initializeOwner(msg.sender); } function landscape(Journey memory journey, uint256 journeyId, uint256 offset, uint256 limit, uint256 journeyCount, uint256 travelerCount) external view returns (string memory) { require(journeyId > 0 && journeyId <= journeyCount, "Invalid journey index"); string memory ls; int48 _fromBlock = journey.fromBlock; int48 _toBlock = journey.forward ? (journey.active ? journey.fromBlock + int48(int(block.number - journey.fromBlockActual)) : journey.toBlock) : journey.fromBlock - ((journey.active ? journey.fromBlock + int48(int(block.number - journey.fromBlockActual)) : journey.toBlock) - journey.fromBlock); uint256 counter = offset; uint256 range = _fromBlock > _toBlock ? uint256(int(_fromBlock) - int(_toBlock)) : uint256(int(_toBlock) - int(_fromBlock)); limit = limit > range ? range : limit; while(true) { int256 block_ = journey.forward ? int(_fromBlock + int(counter)) : int(_fromBlock - int(counter)); string memory letter = generate(journey, block_, travelerCount, threshold); ls = string.concat(ls, letter); counter++; if (counter >= limit) { break; } } return ls; } function landscapeFromTo(Journey memory journey, uint256 journeyId, int256 blockFrom, int256 blockTo, uint256 journeyCount, uint256 travelerCount) external view returns (string memory) { require(journeyId > 0 && journeyId <= journeyCount, "Invalid journey id"); string memory ls; uint256 counter = 0; uint256 limit = int(blockFrom) > int(blockTo) ? uint256(int(blockFrom) - int(blockTo)) : uint256(int(blockTo) - int(blockFrom)); while(true) { int256 block_ = journey.forward ? int(blockFrom + int(counter)) : int(blockFrom - int(counter)); string memory letter = generate(journey, block_, travelerCount, threshold); ls = string.concat(ls, letter); counter++; if (counter > limit) { break; } } return ls; } function generate(Journey memory journey, int256 block_, uint256 travelerCount_, uint256 threshold_) public view returns (string memory) { uint32 x = uint32(uint256(int(block_) + type(int48).max) % uint256(type(uint32).max)); uint32 y = uint32(journey.id); // Momnument if (!journey.active) { int256 range = int(journey.toBlock) - int(journey.fromBlock); uint256 monumentLength = getMonumentLength(uint256(range < 0 ? -range : range)); uint256 monumentChar = uint256(keccak256(abi.encodePacked(x, y))) % MONUMENT.length; if (journey.forward) { if (block_ >= journey.toBlock - int(monumentLength)) { return MONUMENT[monumentChar]; } } else { if (block_ <= journey.toBlock + int(monumentLength)) { return MONUMENT[monumentChar]; } } } // Landmark if (x % 7000 == 0) { return unicode"†"; } // Landscape Height uint256 h = height(x, y); // Footprint uint256 footprint = uint256(keccak256(abi.encodePacked(x, y))) % threshold_; if (travelerCount_ > footprint) { if (h < 11) { return BOTTOM_FOOTPRINT; } else { return TOP_FOOTPRINT; } } // Landscape uint256 char = uint256(keccak256(abi.encodePacked(x, y))) % 10; if (h <= 7) { return BOTTOM[char % BOTTOM.length]; } else if (h > 7 && h <= 15) { return MID[char % MID.length]; } else { return TOP[char % TOP.length]; } } function height(uint32 x, uint32 y) public pure returns (uint256) { uint256 h = Perlin.computePerlin(x, y, 0, 10); h = h - 16; h = h > 64 - 16 - 21 ? 64 - 16 - 21 : h; h = h > 5 ? h - 5 : 0; return h; } function generateHeight(uint256 journeyId, int256 block_) public pure returns (uint256) { uint32 x = uint32(uint256(int(block_) + type(int48).max) % uint256(type(uint32).max)); uint32 y = uint32(journeyId); uint256 h = height(x, y); if (h <= 7) { h = 0; } else if (h > 7 && h <= 15) { h = 1; } else { h = 2; } return h; } function getMonumentLength(uint256 blocks) public view returns (uint256) { uint256 d = 7000; // One day is considered 7000 blocks // 1 day = 3 // 2 days = 4 // 3 days = 5 // 4 days = 6 // 6 days = 7 // 1 week = 9 (3 x 3) // 2 weeks = 10 // 3 weeks = 13 // 1 month = 18 (2 x 9) // 1 year = 54 (3 x 18) // 5 years = 108 (2 x 54) // 10 years = 324 (3 x 108) // 100 years = 648 (2x 324) if (blocks < d) { return 0; } else if (blocks < 2 * d) { return 3; } else if (blocks < 3 * d) { return 4; } else if (blocks < 4 * d) { return 5; } else if (blocks < 6 * d) { return 6; } else if (blocks < 7 * d) { return 7; } else if (blocks < 2 * 7 * d) { return 9; } else if (blocks < 3 * 7 * d) { return 10; } else if (blocks < 4 * 7 * d) { return 13; } else if (blocks < 365 * d) { return 18; } else if (blocks < 5 * 365 * d) { return 54; } else if (blocks < 10 * 365 * d) { return 108; } else if (blocks < 100 * 365 * d) { return 324; } else { return 648; } } function landscapeHeight(Journey memory journey, uint256 journeyId, uint256 offset, uint256 limit, uint256 journeyCount) external view returns (string memory) { require(journeyId > 0 && journeyId <= journeyCount, "Invalid journey index"); string memory ls; int48 _fromBlock = journey.fromBlock; int48 _toBlock = journey.forward ? (journey.active ? journey.fromBlock + int48(int(block.number - journey.fromBlockActual)) : journey.toBlock) : journey.fromBlock - ((journey.active ? journey.fromBlock + int48(int(block.number - journey.fromBlockActual)) : journey.toBlock) - journey.fromBlock); uint256 counter = offset; uint256 range = _fromBlock > _toBlock ? uint256(int(_fromBlock) - int(_toBlock)) : uint256(int(_toBlock) - int(_fromBlock)); limit = limit > range ? range : limit; while(true) { int256 block_ = journey.forward ? int(_fromBlock + int(counter)) : int(_fromBlock - int(counter)); string memory letter = LibString.toString(generateHeight(journeyId, block_)); ls = string.concat(ls, letter); counter++; if (counter >= limit) { break; } } return ls; } function landscapeHeightFromTo(Journey memory journey, uint256 journeyId, int256 blockFrom, int256 blockTo, uint256 journeyCount) external pure returns (string memory) { require(journeyId > 0 && journeyId <= journeyCount, "Invalid journey id"); string memory ls; uint256 counter = 0; uint256 limit = int(blockFrom) > int(blockTo) ? uint256(int(blockFrom) - int(blockTo)) : uint256(int(blockTo) - int(blockFrom)); while(true) { int256 block_ = journey.forward ? int(blockFrom + int(counter)) : int(blockFrom - int(counter)); string memory letter = LibString.toString(generateHeight(journeyId, block_)); ls = string.concat(ls, letter); counter++; if (counter > limit) { break; } } return ls; } }
// SPDX-License-Identifier: GPL-3.0 // Source: https://github.com/nalinbhardwaj/devconnect-procgen-workshop/blob/nether/eth/contracts/Perlin.sol pragma solidity ^0.8.0; import "./ABDKMath64x64.sol"; library Perlin { int16 constant vecsDenom = 1000; uint16 constant perlinMax = 64; // Perlin Noise // interpolation function [0,1] -> [0,1] function smoothStep(int128 x) public pure returns (int128) { return x; } // returns a random unit vector // implicit denominator of vecsDenom function getGradientAt( uint32 x, uint32 y, uint32 scale, uint32 seed ) public pure returns (int16[2] memory) { uint256 idx = uint256(keccak256(abi.encodePacked(x, y, scale, seed))) % 16; int16[2][16] memory vecs = [ [int16(1000), int16(0)], [int16(923), int16(382)], [int16(707), int16(707)], [int16(382), int16(923)], [int16(0), int16(1000)], [int16(-383), int16(923)], [int16(-708), int16(707)], [int16(-924), int16(382)], [int16(-1000), int16(0)], [int16(-924), int16(-383)], [int16(-708), int16(-708)], [int16(-383), int16(-924)], [int16(-1), int16(-1000)], [int16(382), int16(-924)], [int16(707), int16(-708)], [int16(923), int16(-383)] ]; return vecs[idx]; } // the computed perlin value at a point is a weighted average of dot products with // gradient vectors at the four corners of a grid square. // this isn't scaled; there's an implicit denominator of scale ** 2 function getWeight( uint32 cornerX, uint32 cornerY, uint32 x, uint32 y, uint32 scale ) public pure returns (uint64) { uint64 res = 1; if (cornerX > x) res *= (scale - (cornerX - x)); else res *= (scale - (x - cornerX)); if (cornerY > y) res *= (scale - (cornerY - y)); else res *= (scale - (y - cornerY)); return res; } function getCorners( uint32 x, uint32 y, uint32 scale ) public pure returns (uint32[2][4] memory) { uint32 lowerX = (x / scale) * scale; uint32 lowerY = (y / scale) * scale; return [ [lowerX, lowerY], [lowerX + scale, lowerY], [lowerX + scale, lowerY + scale], [lowerX, lowerY + scale] ]; } function getSingleScalePerlin( uint32 x, uint32 y, uint32 scale, uint32 seed ) public pure returns (int128) { uint32[2][4] memory corners = getCorners(x, y, scale); int128 resNumerator = 0; for (uint8 i = 0; i < 4; i++) { uint32[2] memory corner = corners[i]; // this has an implicit denominator of scale int32[2] memory offset = [int32(x) - int32(corner[0]), int32(y) - int32(corner[1])]; // this has an implicit denominator of vecsDenom int16[2] memory gradient = getGradientAt(corner[0], corner[1], scale, seed); // this has an implicit denominator of vecsDenom * scale int64 dot = offset[0] * int64(gradient[0]) + offset[1] * int64(gradient[1]); // this has an implicit denominator of scale ** 2 uint64 weight = getWeight(corner[0], corner[1], x, y, scale); // this has an implicit denominator of vecsDenom * scale ** 3 resNumerator += int128(int64(weight)) * int128(dot); } return ABDKMath64x64.divi(int256(resNumerator), int256(vecsDenom) * int256(int32(scale))**3); } function computePerlin( uint32 x, uint32 y, uint32 seed, uint32 scale ) public pure returns (uint256) { int128 perlin = ABDKMath64x64.fromUInt(0); for (uint8 i = 0; i < 3; i++) { int128 v = getSingleScalePerlin(x, y, scale * uint32(2**i), seed); perlin = ABDKMath64x64.add(perlin, v); } perlin = ABDKMath64x64.add(perlin, getSingleScalePerlin(x, y, scale * uint32(2**0), seed)); perlin = ABDKMath64x64.div(perlin, ABDKMath64x64.fromUInt(4)); int128 perlinScaledShifted = ABDKMath64x64.add( ABDKMath64x64.mul(perlin, ABDKMath64x64.fromUInt(uint256(perlinMax / 2))), ABDKMath64x64.fromUInt((uint256(perlinMax / 2))) ); return ABDKMath64x64.toUInt(perlinScaledShifted); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface Sculpture { function title() external view returns (string memory); function authors() external view returns (string[] memory); function addresses() external view returns (address[] memory); function urls() external view returns (string[] memory); function text() external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev Cannot double-initialize. error AlreadyInitialized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. bytes32 internal constant _OWNER_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return true to make `_initializeOwner` prevent double-initialization. function _guardInitializeOwner() internal pure virtual returns (bool guard) {} /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT if sload(ownerSlot) { mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`. revert(0x1c, 0x04) } // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } else { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(_OWNER_SLOT, newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) } } else { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(_OWNER_SLOT))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(_OWNER_SLOT) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) /// /// @dev Note: /// For performance and bytecode compactness, most of the string operations are restricted to /// byte strings (7-bit ASCII), except where otherwise specified. /// Usage of byte string operations on charsets with runes spanning two or more bytes /// can lead to undefined behavior. library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The length of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /// @dev The length of the string is more than 32 bytes. error TooBigForSmallString(); /// @dev The input string must be a 7-bit ASCII. error StringNot7BitASCII(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000; /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000; /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'. uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000; /// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000; /// @dev Lookup for '0123456789'. uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000; /// @dev Lookup for '0123456789abcdefABCDEF'. uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000; /// @dev Lookup for '01234567'. uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000; /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'. uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00; /// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'. uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000; /// @dev Lookup for ' \t\n\r\x0b\x0c'. uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. str := add(mload(0x40), 0x80) mstore(0x40, add(str, 0x20)) // Allocate the memory. mstore(str, 0) // Zeroize the slot after the string. let end := str // Cache the end of the memory to calculate the length later. let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 1)`. // Store the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) temp := div(temp, 10) // Keep dividing `temp` until zero. if iszero(temp) { break } } let length := sub(end, str) str := sub(str, 0x20) // Move the pointer 32 bytes back to make room for the length. mstore(str, length) // Store the length. } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory str) { if (value >= 0) return toString(uint256(value)); unchecked { str = toString(~uint256(value) + 1); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let length := mload(str) // Load the string length. mstore(str, 0x2d) // Store the '-' character. str := sub(str, 1) // Move back the string pointer by a byte. mstore(str, add(length, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2 + 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) { str = toHexStringNoPrefix(value, length); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Store the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) mstore(0x40, add(str, 0x20)) // Allocate the memory. mstore(str, 0) // Zeroize the slot after the string. let end := str // Cache the end to calculate the length later. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(str, add(length, length)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(str, start)) { break } } if temp { mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. revert(0x1c, 0x04) } let strLength := sub(end, str) str := sub(str, 0x20) mstore(str, strLength) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Store the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := add(mload(str), 2) // Compute the length. mstore(add(str, o), 0x3078) // Store the "0x" prefix, accounting for leading zero. str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Store the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := mload(str) // Get the length. str := add(str, o) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Store the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. str := add(mload(0x40), 0x80) mstore(0x40, add(str, 0x20)) // Allocate the memory. mstore(str, 0) // Zeroize the slot after the string. let end := str // Cache the end to calculate the length later. mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } let strLength := sub(end, str) str := sub(str, 0x20) mstore(str, strLength) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Store the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. str := add(str, 2) mstore(str, 40) // Store the length. let o := add(str, 0x20) mstore(add(o, 40), 0) // Zeroize the slot after the string. value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Store the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Store the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. let o := add(str, 0x20) let end := add(raw, length) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let mask := shl(7, div(not(0), 255)) result := 1 let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /// @dev Returns if this string is a 7-bit ASCII string, /// AND all characters are in the `allowed` lookup. /// Note: If `s` is empty, returns true regardless of `allowed`. function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if mload(s) { let allowed_ := shr(128, shl(128, allowed)) let o := add(s, 0x20) let end := add(o, mload(s)) for {} 1 {} { result := and(result, shr(byte(0, mload(o)), allowed_)) o := add(o, 1) if iszero(and(result, lt(o, end))) { break } } } } } /// @dev Converts the bytes in the 7-bit ASCII string `s` to /// an allowed lookup for use in `is7BitASCII(s, allowed)`. /// To save runtime gas, you can cache the result in an immutable variable. function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { let o := add(s, 0x20) let end := add(o, mload(s)) for {} 1 {} { result := or(result, shl(byte(0, mload(o)), 1)) o := add(o, 1) if iszero(lt(o, end)) { break } } if shr(128, result) { mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`. revert(0x1c, 0x04) } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, byte string operations are restricted // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. // Usage of byte string operations on charsets with runes spanning two or more bytes // can lead to undefined behavior. /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`. function replace(string memory subject, string memory search, string memory replacement) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) let replacementLength := mload(replacement) subject := add(subject, 0x20) search := add(search, 0x20) replacement := add(replacement, 0x20) result := add(mload(0x40), 0x20) let subjectEnd := add(subject, subjectLength) if iszero(gt(searchLength, subjectLength)) { let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let o := 0 } 1 {} { mstore(add(result, o), mload(add(replacement, o))) o := add(o, 0x20) if iszero(lt(o, replacementLength)) { break } } result := add(result, replacementLength) subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } } let resultRemainder := result result := add(mload(0x40), 0x20) let k := add(sub(resultRemainder, result), sub(subjectEnd, subject)) // Copy the rest of the string one word at a time. for {} lt(subject, subjectEnd) {} { mstore(resultRemainder, mload(subject)) resultRemainder := add(resultRemainder, 0x20) subject := add(subject, 0x20) } result := sub(result, 0x20) let last := add(add(result, 0x20), k) // Zeroize the slot after the string. mstore(last, 0) mstore(0x40, add(last, 0x20)) // Allocate the memory. mstore(result, k) // Store the length. } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for { let subjectLength := mload(subject) } 1 {} { if iszero(mload(search)) { if iszero(gt(from, subjectLength)) { result := from break } result := subjectLength break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(add(search, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } if iszero(lt(searchLength, 0x20)) { for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, searchLength), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = indexOf(subject, search, 0); } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let searchLength := mload(search) if gt(searchLength, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if eq(keccak256(subject, searchLength), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = lastIndexOf(subject, search, uint256(int256(-1))); } /// @dev Returns true if `search` is found in `subject`, false otherwise. function contains(string memory subject, string memory search) internal pure returns (bool) { return indexOf(subject, search) != NOT_FOUND; } /// @dev Returns whether `subject` starts with `search`. function startsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( iszero(gt(searchLength, mload(subject))), eq( keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns whether `subject` ends with `search`. function endsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) let subjectLength := mload(subject) // Whether `search` is not longer than `subject`. let withinRange := iszero(gt(searchLength, subjectLength)) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( withinRange, eq( keccak256( // `subject + 0x20 + max(subjectLength - searchLength, 0)`. add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))), searchLength ), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(or(iszero(times), iszero(subjectLength))) { subject := add(subject, 0x20) result := mload(0x40) let output := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let o := 0 } 1 {} { mstore(add(output, o), mload(add(subject, o))) o := add(o, 0x20) if iszero(lt(o, subjectLength)) { break } } output := add(output, subjectLength) times := sub(times, 1) if iszero(times) { break } } mstore(output, 0) // Zeroize the slot after the string. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Store the length. mstore(0x40, add(result, add(resultLength, 0x40))) // Allocate the memory. } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(gt(subjectLength, end)) { end := subjectLength } if iszero(gt(subjectLength, start)) { start := subjectLength } if lt(start, end) { result := mload(0x40) let resultLength := sub(end, start) mstore(result, resultLength) subject := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 0x1f), w) } 1 {} { mstore(add(result, o), mload(add(subject, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(result, 0x20), resultLength), 0) mstore(0x40, add(result, add(resultLength, 0x40))) // Allocate the memory. } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory result) { result = slice(subject, start, uint256(int256(-1))); } /// @dev Returns all the indices of `search` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) if iszero(gt(searchLength, subjectLength)) { subject := add(subject, 0x20) search := add(search, 0x20) result := add(mload(0x40), 0x20) let subjectStart := subject let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Append to `result`. mstore(result, sub(subject, subjectStart)) result := add(result, 0x20) // Advance `subject` by `searchLength`. subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } let resultEnd := result // Assign `result` to the free memory pointer. result := mload(0x40) // Store the length of `result`. mstore(result, shr(5, sub(resultEnd, add(result, 0x20)))) // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(resultEnd, 0x20)) } } } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) let prevIndex := 0 for {} 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let elementLength := sub(index, prevIndex) mstore(element, elementLength) // Copy the `subject` one word at a time, backwards. for { let o := and(add(elementLength, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(element, 0x20), elementLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(element, and(add(elementLength, 0x3f), w))) // Store the `element` into the array. mstore(indexPtr, element) } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let w := not(0x1f) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLength, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLength := mload(b) let output := add(result, aLength) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLength := add(aLength, bLength) let last := add(add(result, 0x20), totalLength) mstore(last, 0) // Zeroize the slot after the string. mstore(result, totalLength) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let length := mload(subject) if length { result := add(mload(0x40), 0x20) subject := add(subject, 1) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) let w := not(0) for { let o := length } 1 {} { o := add(o, w) let b := and(0xff, mload(add(subject, o))) mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) if iszero(o) { break } } result := mload(0x40) mstore(result, length) // Store the length. let last := add(add(result, 0x20), length) mstore(last, 0) // Zeroize the slot after the string. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } } /// @dev Returns a string from a small bytes32 string. /// `s` must be null-terminated, or behavior will be undefined. function fromSmallString(bytes32 s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'. mstore(result, n) // Store the length. let o := add(result, 0x20) mstore(o, s) // Store the bytes of the string. mstore(add(o, n), 0) // Zeroize the slot after the string. mstore(0x40, add(result, 0x40)) // Allocate the memory. } } /// @dev Returns the small string, with all bytes after the first null byte zeroized. function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'. mstore(0x00, s) mstore(result, 0x00) result := mload(0x00) } } /// @dev Returns the string as a normalized null-terminated small string. function toSmallString(string memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(s) if iszero(lt(result, 33)) { mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. revert(0x1c, 0x04) } result := shl(shl(3, sub(32, result)), mload(add(s, result))) } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(result, c) result := add(result, 1) continue } let t := shr(248, mload(c)) mstore(result, mload(and(t, 0x1f))) result := add(result, shr(5, t)) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(result, c) result := add(result, 1) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), c) result := add(result, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(result, mload(0x19)) // "\\u00XX". result := add(result, 6) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), mload(add(c, 8))) result := add(result, 2) } if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behavior is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Grab the free memory pointer. mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(result, 0) // Zeroize the length slot. mstore(add(result, 0x1f), packed) // Store the length and bytes. mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes. } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLength := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( or( // Load the length and the bytes of `a` and `b`. shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength)) ), // `totalLength != 0 && totalLength < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLength, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behavior is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { resultA := mload(0x40) // Grab the free memory pointer. resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retUnpaddedSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retUnpaddedSize), 0) mstore(retStart, 0x20) // Store the return offset. // End the transaction, returning the string. return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Read and write to persistent storage at a fraction of the cost. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SSTORE2.sol) /// @author Saw-mon-and-Natalie (https://github.com/Saw-mon-and-Natalie) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol) /// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol) /// @author Modified from SSTORE3 (https://github.com/Philogy/sstore3) library SSTORE2 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The proxy initialization code. uint256 private constant _CREATE3_PROXY_INITCODE = 0x67363d3d37363d34f03d5260086018f3; /// @dev Hash of the `_CREATE3_PROXY_INITCODE`. /// Equivalent to `keccak256(abi.encodePacked(hex"67363d3d37363d34f03d5260086018f3"))`. bytes32 internal constant CREATE3_PROXY_INITCODE_HASH = 0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unable to deploy the storage contract. error DeploymentFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* WRITE LOGIC */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Writes `data` into the bytecode of a storage contract and returns its address. function write(bytes memory data) internal returns (address pointer) { /// @solidity memory-safe-assembly assembly { let n := mload(data) // Let `l` be `n + 1`. +1 as we prefix a STOP opcode. /** * ---------------------------------------------------+ * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------| * 61 l | PUSH2 l | l | | * 80 | DUP1 | l l | | * 60 0xa | PUSH1 0xa | 0xa l l | | * 3D | RETURNDATASIZE | 0 0xa l l | | * 39 | CODECOPY | l | [0..l): code | * 3D | RETURNDATASIZE | 0 l | [0..l): code | * F3 | RETURN | | [0..l): code | * 00 | STOP | | | * ---------------------------------------------------+ * @dev Prefix the bytecode with a STOP opcode to ensure it cannot be called. * Also PUSH2 is used since max contract size cap is 24,576 bytes which is less than 2 ** 16. */ // Do a out-of-gas revert if `n + 1` is more than 2 bytes. mstore(add(data, gt(n, 0xfffe)), add(0xfe61000180600a3d393df300, shl(0x40, n))) // Deploy a new contract with the generated creation code. pointer := create(0, add(data, 0x15), add(n, 0xb)) if iszero(pointer) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(data, n) // Restore the length of `data`. } } /// @dev Writes `data` into the bytecode of a storage contract with `salt` /// and returns its normal CREATE2 deterministic address. function writeCounterfactual(bytes memory data, bytes32 salt) internal returns (address pointer) { /// @solidity memory-safe-assembly assembly { let n := mload(data) // Do a out-of-gas revert if `n + 1` is more than 2 bytes. mstore(add(data, gt(n, 0xfffe)), add(0xfe61000180600a3d393df300, shl(0x40, n))) // Deploy a new contract with the generated creation code. pointer := create2(0, add(data, 0x15), add(n, 0xb), salt) if iszero(pointer) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(data, n) // Restore the length of `data`. } } /// @dev Writes `data` into the bytecode of a storage contract and returns its address. /// This uses the so-called "CREATE3" workflow, /// which means that `pointer` is agnostic to `data, and only depends on `salt`. function writeDeterministic(bytes memory data, bytes32 salt) internal returns (address pointer) { /// @solidity memory-safe-assembly assembly { let n := mload(data) mstore(0x00, _CREATE3_PROXY_INITCODE) // Store the `_PROXY_INITCODE`. let proxy := create2(0, 0x10, 0x10, salt) if iszero(proxy) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x14, proxy) // Store the proxy's address. // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01). // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex). mstore(0x00, 0xd694) mstore8(0x34, 0x01) // Nonce of the proxy contract (1). pointer := keccak256(0x1e, 0x17) // Do a out-of-gas revert if `n + 1` is more than 2 bytes. mstore(add(data, gt(n, 0xfffe)), add(0xfe61000180600a3d393df300, shl(0x40, n))) if iszero( mul( // The arguments of `mul` are evaluated last to first. extcodesize(pointer), call(gas(), proxy, 0, add(data, 0x15), add(n, 0xb), codesize(), 0x00) ) ) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(data, n) // Restore the length of `data`. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ADDRESS CALCULATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the initialization code hash of the storage contract for `data`. /// Used for mining vanity addresses with create2crunch. function initCodeHash(bytes memory data) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let n := mload(data) // Do a out-of-gas revert if `n + 1` is more than 2 bytes. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xfffe)) mstore(data, add(0x61000180600a3d393df300, shl(0x40, n))) hash := keccak256(add(data, 0x15), add(n, 0xb)) mstore(data, n) // Restore the length of `data`. } } /// @dev Equivalent to `predictCounterfactualAddress(data, salt, address(this))` function predictCounterfactualAddress(bytes memory data, bytes32 salt) internal view returns (address pointer) { pointer = predictCounterfactualAddress(data, salt, address(this)); } /// @dev Returns the CREATE2 address of the storage contract for `data` /// deployed with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictCounterfactualAddress(bytes memory data, bytes32 salt, address deployer) internal pure returns (address predicted) { bytes32 hash = initCodeHash(data); /// @solidity memory-safe-assembly assembly { // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, hash) mstore(0x01, shl(96, deployer)) mstore(0x15, salt) predicted := keccak256(0x00, 0x55) // Restore the part of the free memory pointer that has been overwritten. mstore(0x35, 0) } } /// @dev Equivalent to `predictDeterministicAddress(salt, address(this))`. function predictDeterministicAddress(bytes32 salt) internal view returns (address pointer) { pointer = predictDeterministicAddress(salt, address(this)); } /// @dev Returns the "CREATE3" deterministic address for `salt` with `deployer`. function predictDeterministicAddress(bytes32 salt, address deployer) internal pure returns (address pointer) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, deployer) // Store `deployer`. mstore8(0x0b, 0xff) // Store the prefix. mstore(0x20, salt) // Store the salt. mstore(0x40, CREATE3_PROXY_INITCODE_HASH) // Store the bytecode hash. mstore(0x14, keccak256(0x0b, 0x55)) // Store the proxy's address. mstore(0x40, m) // Restore the free memory pointer. // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01). // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex). mstore(0x00, 0xd694) mstore8(0x34, 0x01) // Nonce of the proxy contract (1). pointer := keccak256(0x1e, 0x17) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* READ LOGIC */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `read(pointer, 0, 2 ** 256 - 1)`. function read(address pointer) internal view returns (bytes memory data) { /// @solidity memory-safe-assembly assembly { data := mload(0x40) let n := and(sub(extcodesize(pointer), 0x01), 0xffffffffff) extcodecopy(pointer, add(data, 0x1f), 0x00, add(n, 0x21)) mstore(data, n) // Store the length. mstore(0x40, add(n, add(data, 0x40))) // Allocate memory. } } /// @dev Equivalent to `read(pointer, start, 2 ** 256 - 1)`. function read(address pointer, uint256 start) internal view returns (bytes memory data) { /// @solidity memory-safe-assembly assembly { data := mload(0x40) let n := and(sub(extcodesize(pointer), 0x01), 0xffffffffff) extcodecopy(pointer, add(data, 0x1f), start, add(n, 0x21)) mstore(data, mul(sub(n, start), lt(start, n))) // Store the length. mstore(0x40, add(data, add(0x40, mload(data)))) // Allocate memory. } } /// @dev Returns a slice of the data on `pointer` from `start` to `end`. /// `start` and `end` will be clamped to the range `[0, args.length]`. /// The `pointer` MUST be deployed via the SSTORE2 write functions. /// Otherwise, the behavior is undefined. /// Out-of-gas reverts if `pointer` does not have any code. function read(address pointer, uint256 start, uint256 end) internal view returns (bytes memory data) { /// @solidity memory-safe-assembly assembly { data := mload(0x40) if iszero(lt(end, 0xffff)) { end := 0xffff } let d := mul(sub(end, start), lt(start, end)) extcodecopy(pointer, add(data, 0x1f), start, add(d, 0x01)) if iszero(and(0xff, mload(add(data, d)))) { let n := sub(extcodesize(pointer), 0x01) returndatacopy(returndatasize(), returndatasize(), shr(64, n)) d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n)))) } mstore(data, d) // Store the length. mstore(add(add(data, 0x20), d), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(data, 0x40), d)) // Allocate memory. } } }
{ "evmVersion": "paris", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": false, "runs": 200 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"traveler","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"int48","name":"fromBlock","type":"int48"},{"indexed":false,"internalType":"bool","name":"direction","type":"bool"}],"name":"JourneyBegun","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"traveler","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"int48","name":"toBlock","type":"int48"}],"name":"JourneyEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"addresses","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"me","type":"address"}],"name":"amITravelling","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authors","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bool","name":"direction","type":"bool"}],"name":"begin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"end","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getJourney","outputs":[{"components":[{"internalType":"address","name":"traveler","type":"address"},{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint48","name":"fromBlockActual","type":"uint48"},{"internalType":"int48","name":"fromBlock","type":"int48"},{"internalType":"int48","name":"toBlock","type":"int48"},{"internalType":"bool","name":"forward","type":"bool"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint48","name":"previousId","type":"uint48"}],"internalType":"struct Journey","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getJourneys","outputs":[{"components":[{"internalType":"address","name":"traveler","type":"address"},{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint48","name":"fromBlockActual","type":"uint48"},{"internalType":"int48","name":"fromBlock","type":"int48"},{"internalType":"int48","name":"toBlock","type":"int48"},{"internalType":"bool","name":"forward","type":"bool"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint48","name":"previousId","type":"uint48"}],"internalType":"struct Journey[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"me","type":"address"}],"name":"howFarHaveICome","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"journeyBackwardCompletedCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"journeyBackwardCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"journeyCompletedCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"journeyCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"journeys","outputs":[{"internalType":"address","name":"traveler","type":"address"},{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint48","name":"fromBlockActual","type":"uint48"},{"internalType":"int48","name":"fromBlock","type":"int48"},{"internalType":"int48","name":"toBlock","type":"int48"},{"internalType":"bool","name":"forward","type":"bool"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint48","name":"previousId","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"me","type":"address"}],"name":"journeysOf","outputs":[{"components":[{"internalType":"address","name":"traveler","type":"address"},{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint48","name":"fromBlockActual","type":"uint48"},{"internalType":"int48","name":"fromBlock","type":"int48"},{"internalType":"int48","name":"toBlock","type":"int48"},{"internalType":"bool","name":"forward","type":"bool"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint48","name":"previousId","type":"uint48"}],"internalType":"struct Journey[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"journeyId","type":"uint256"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"landscape","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"journeyId","type":"uint256"},{"internalType":"int256","name":"blockFrom","type":"int256"},{"internalType":"int256","name":"blockTo","type":"int256"}],"name":"landscapeFromTo","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"journeyId","type":"uint256"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"landscapeHeight","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"journeyId","type":"uint256"},{"internalType":"int256","name":"blockFrom","type":"int256"},{"internalType":"int256","name":"blockTo","type":"int256"}],"name":"landscapeHeightFromTo","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"me","type":"address"}],"name":"mostRecentJourneyOf","outputs":[{"components":[{"internalType":"address","name":"traveler","type":"address"},{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint48","name":"fromBlockActual","type":"uint48"},{"internalType":"int48","name":"fromBlock","type":"int48"},{"internalType":"int48","name":"toBlock","type":"int48"},{"internalType":"bool","name":"forward","type":"bool"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint48","name":"previousId","type":"uint48"}],"internalType":"struct Journey","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"mostRecentJourneys","outputs":[{"components":[{"internalType":"address","name":"traveler","type":"address"},{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint48","name":"fromBlockActual","type":"uint48"},{"internalType":"int48","name":"fromBlock","type":"int48"},{"internalType":"int48","name":"toBlock","type":"int48"},{"internalType":"bool","name":"forward","type":"bool"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint48","name":"previousId","type":"uint48"}],"internalType":"struct Journey[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"previewWidth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"render","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_previewWidth","type":"uint256"}],"name":"setPreviewWidth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_render","type":"address"}],"name":"setRender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_text","type":"string"}],"name":"setText","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"_urls","type":"string[]"}],"name":"setUrls","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"text","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"title","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"travelers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"direction","type":"bool"}],"name":"travelers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"urls","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"me","type":"address"}],"name":"whereAmI","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6080604052604b600b5534801561001557600080fd5b506100253361002a60201b60201c565b610110565b61003861010b60201b60201c565b156100b3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392780541561007357630dc149f06000526004601cfd5b8160601b60601c9150811560ff1b821781558160007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a350610108565b8060601b60601c9050807fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a35b50565b600090565b6152818061011f6000396000f3fe60806040526004361061023b5760003560e01c8063a33781cb1161012e578063da0321cd116100ab578063f04e283e1161006f578063f04e283e1461087f578063f0c136cb1461089b578063f2fde38b146108c4578063f9cc242d146108e0578063fee81cf41461091d5761023b565b8063da0321cd146107be578063e19f1760146107e9578063e1c7392a14610814578063ec8d88621461082b578063efbe1c1c146108685761023b565b8063c8730b35116100f2578063c8730b351461069f578063d4c6c869146106dc578063d607497a14610719578063d8359ae514610744578063d9ca6918146107815761023b565b8063a33781cb14610582578063aa953719146105bf578063aa98ff4d146105fc578063b544303814610625578063b83fac77146106625761023b565b806354d1f13d116101bc578063715018a611610180578063715018a6146104a157806381851182146104ab5780638da5cb5b146104d65780638df5a9fa146105015780638fc1eac7146105455761023b565b806354d1f13d146103dd57806358090e17146103e75780635d3a1f9d146104245780636cc895a91461044d5780636d1d098c146104765761023b565b806328411ae11161020357806328411ae1146102f65780632c73dc4a1461032157806330388e731461034c57806339b33569146103755780634a79d50c146103b25761023b565b80631c7fb7f4146102405780631f1bd6921461026b57806321ace8c414610296578063226c8aca146102c157806325692962146102ec575b600080fd5b34801561024c57600080fd5b5061025561095a565b60405161026291906138c6565b60405180910390f35b34801561027757600080fd5b50610280610960565b60405161028d9190613971565b60405180910390f35b3480156102a257600080fd5b506102ab610d7a565b6040516102b891906138c6565b60405180910390f35b3480156102cd57600080fd5b506102d6610d80565b6040516102e391906138c6565b60405180910390f35b6102f4610d86565b005b34801561030257600080fd5b5061030b610dda565b6040516103189190613a9f565b60405180910390f35b34801561032d57600080fd5b50610336610e8b565b6040516103439190613a9f565b60405180910390f35b34801561035857600080fd5b50610373600480360381019061036e9190613b01565b610f64565b005b34801561038157600080fd5b5061039c60048036038101906103979190613b01565b610f76565b6040516103a99190613d19565b60405180910390f35b3480156103be57600080fd5b506103c76111ac565b6040516103d49190613971565b60405180910390f35b6103e56111cc565b005b3480156103f357600080fd5b5061040e60048036038101906104099190613d67565b611208565b60405161041b9190613e36565b60405180910390f35b34801561043057600080fd5b5061044b60048036038101906104469190613f87565b6113c4565b005b34801561045957600080fd5b50610474600480360381019061046f91906140b6565b611418565b005b34801561048257600080fd5b5061048b61143a565b60405161049891906138c6565b60405180910390f35b6104a9611451565b005b3480156104b757600080fd5b506104c0611465565b6040516104cd91906138c6565b60405180910390f35b3480156104e257600080fd5b506104eb61146b565b6040516104f8919061410e565b60405180910390f35b34801561050d57600080fd5b5061052860048036038101906105239190613b01565b611494565b60405161053c989796959493929190614156565b60405180910390f35b34801561055157600080fd5b5061056c600480360381019061056791906141d4565b611566565b6040516105799190613971565b60405180910390f35b34801561058e57600080fd5b506105a960048036038101906105a49190613d67565b61162d565b6040516105b69190613d19565b60405180910390f35b3480156105cb57600080fd5b506105e660048036038101906105e1919061425d565b611aba565b6040516105f39190613971565b60405180910390f35b34801561060857600080fd5b50610623600480360381019061061e91906142dc565b611b81565b005b34801561063157600080fd5b5061064c60048036038101906106479190613b01565b611b8e565b6040516106599190613e36565b60405180910390f35b34801561066e57600080fd5b506106896004803603810190610684919061425d565b611d56565b6040516106969190613971565b60405180910390f35b3480156106ab57600080fd5b506106c660048036038101906106c19190613d67565b611f8d565b6040516106d39190614318565b60405180910390f35b3480156106e857600080fd5b5061070360048036038101906106fe91906141d4565b6121d6565b6040516107109190613971565b60405180910390f35b34801561072557600080fd5b5061072e61240d565b60405161073b919061410e565b60405180910390f35b34801561075057600080fd5b5061076b60048036038101906107669190614333565b612433565b6040516107789190613d19565b60405180910390f35b34801561078d57600080fd5b506107a860048036038101906107a391906142dc565b6126d9565b6040516107b591906138c6565b60405180910390f35b3480156107ca57600080fd5b506107d3612700565b6040516107e09190614422565b60405180910390f35b3480156107f557600080fd5b506107fe6127a6565b60405161080b91906138c6565b60405180910390f35b34801561082057600080fd5b506108296127ac565b005b34801561083757600080fd5b50610852600480360381019061084d9190613d67565b612802565b60405161085f9190614318565b60405180910390f35b34801561087457600080fd5b5061087d612a1a565b005b61089960048036038101906108949190613d67565b612d89565b005b3480156108a757600080fd5b506108c260048036038101906108bd9190613d67565b612dca565b005b6108de60048036038101906108d99190613d67565b612e16565b005b3480156108ec57600080fd5b5061090760048036038101906109029190613d67565b612e40565b6040516109149190614444565b60405180910390f35b34801561092957600080fd5b50610944600480360381019061093f9190613d67565b612fff565b60405161095191906138c6565b60405180910390f35b60035481565b6060600061096c61143a565b9050600061097a60016126d9565b9050600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b9e4f8d3600080600181526020019081526020016000206001600b54436109dd919061448e565b43600154876040518763ffffffff1660e01b8152600401610a039695949392919061475f565b600060405180830381865afa925050508015610a4257506040513d6000823e3d601f19601f82011682018060405250810190610a3f9190614836565b60015b610bdf57600073ffffffffffffffffffffffffffffffffffffffff16600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610acc57610ac7600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661301a565b610add565b604051806020016040528060008152505b60018314610b20576040518060400160405280600481526020017f6172652000000000000000000000000000000000000000000000000000000000815250610b57565b6040518060400160405280600381526020017f69732000000000000000000000000000000000000000000000000000000000008152505b610b608461304b565b60018514610ba3576040518060400160405280600181526020017f7300000000000000000000000000000000000000000000000000000000000000815250610bb4565b604051806020016040528060008152505b604051602001610bc79493929190614953565b60405160208183030381529060405292505050610d77565b600073ffffffffffffffffffffffffffffffffffffffff16600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610c6557610c60600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661301a565b610c76565b604051806020016040528060008152505b60018414610cb9576040518060400160405280600481526020017f6172652000000000000000000000000000000000000000000000000000000000815250610cf0565b6040518060400160405280600381526020017f69732000000000000000000000000000000000000000000000000000000000008152505b610cf98561304b565b60018614610d3c576040518060400160405280600181526020017f7300000000000000000000000000000000000000000000000000000000000000815250610d4d565b604051806020016040528060008152505b84604051602001610d629594939291906149f3565b60405160208183030381529060405293505050505b90565b60045481565b60025481565b6000610d9061309c565b67ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b60606000600167ffffffffffffffff811115610df957610df8613e5c565b5b604051908082528060200260200182016040528015610e2c57816020015b6060815260200190600190039081610e175790505b5090506040518060400160405280601c81526020017f4c6f7563617320427261636f6e6e69657220284669677572653331290000000081525081600081518110610e7957610e78614a89565b5b60200260200101819052508091505090565b60606009805480602002602001604051908101604052809291908181526020016000905b82821015610f5b578382906000526020600020018054610ece90614ae7565b80601f0160208091040260200160405190810160405280929190818152602001828054610efa90614ae7565b8015610f475780601f10610f1c57610100808354040283529160200191610f47565b820191906000526020600020905b815481529060010190602001808311610f2a57829003601f168201915b505050505081526020019060010190610eaf565b50505050905090565b610f6c6130a7565b80600b8190555050565b6060600154821115610f885760015491505b60008267ffffffffffffffff811115610fa457610fa3613e5c565b5b604051908082528060200260200182016040528015610fdd57816020015b610fca613756565b815260200190600190039081610fc25790505b50905060005b838110156111a25760008060018387600154610fff9190614b18565b6110099190614b4c565b6110139190614b4c565b8152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff168152505082828151811061118a57611189614a89565b5b60200260200101819052508080600101915050610fe3565b5080915050919050565b606060405180606001604052806024815260200161522860249139905090565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b611210613756565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600080828152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681525050915050919050565b6113cc6130a7565b6113d5816130df565b600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6114206130a7565b80600990805190602001906114369291906137d3565b5050565b600060025460015461144c9190614b18565b905090565b6114596130a7565b6114636000613126565b565b600b5481565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754905090565b60006020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900465ffffffffffff169080600001601a9054906101000a900465ffffffffffff16908060010160009054906101000a900460050b908060010160069054906101000a900460050b9080600101600c9054906101000a900460ff169080600101600d9054906101000a900460ff169080600101600e9054906101000a900465ffffffffffff16905088565b6060600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c715c58d6000808781526020019081526020016000208686866001546040518663ffffffff1660e01b81526004016115de959493929190614b80565b600060405180830381865afa1580156115fb573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906116249190614836565b90509392505050565b60606000600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060008167ffffffffffffffff81111561168f5761168e613e5c565b5b6040519080825280602002602001820160405280156116c857816020015b6116b5613756565b8152602001906001900390816116ad5790505b5090506000806000600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff168152505090506000830361188957819350505050611ab5565b80826001856118989190614b18565b815181106118a9576118a8614a89565b5b6020026020010181905250600183036118c757819350505050611ab5565b60006001846118d69190614b18565b90505b6000811115611aad576000808483815181106118f8576118f7614a89565b5b602002602001015160e0015165ffffffffffff168152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff168152505083600183611a7e9190614b18565b81518110611a8f57611a8e614a89565b5b60200260200101819052508080611aa590614bd8565b9150506118d9565b508193505050505b919050565b6060600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663680fd2316000808781526020019081526020016000208686866001546040518663ffffffff1660e01b8152600401611b32959493929190614c01565b600060405180830381865afa158015611b4f573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611b789190614836565b90509392505050565b611b8b81336131ee565b50565b611b96613756565b816000108015611ba857506001548211155b611be7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bde90614ca5565b60405180910390fd5b600080838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050919050565b60606000806000868152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff168152505090506000611ed38260a001516126d9565b9050600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b9e4f8d383888888600154876040518763ffffffff1660e01b8152600401611f3c96959493929190614cc5565b600060405180830381865afa158015611f59573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611f829190614836565b925050509392505050565b600080600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000806000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050600015158160c00151151514801561215d57506000816080015160050b145b1561216c5743925050506121d1565b8060a001516121a157806040015165ffffffffffff164361218d9190614b18565b816060015161219c9190614d2c565b6121c9565b806040015165ffffffffffff16436121b99190614b18565b81606001516121c89190614d8a565b5b60050b925050505b919050565b60606000806000868152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681525050905060006123538260a001516126d9565b9050600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663277fa13183888888600154876040518763ffffffff1660e01b81526004016123bc96959493929190614de8565b600060405180830381865afa1580156123d9573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906124029190614836565b925050509392505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6060600154831061249a57600067ffffffffffffffff81111561245957612458613e5c565b5b60405190808252806020026020018201604052801561249257816020015b61247f613756565b8152602001906001900390816124775790505b5090506126d3565b60015482846124a99190614b4c565b11156124c057826001546124bd9190614b18565b91505b60008267ffffffffffffffff8111156124dc576124db613e5c565b5b60405190808252806020026020018201604052801561251557816020015b612502613756565b8152602001906001900390816124fa5790505b50905060005b838110156126cd57600080600183886125349190614b4c565b61253e9190614b4c565b8152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250508282815181106126b5576126b4614a89565b5b6020026020010181905250808060010191505061251b565b50809150505b92915050565b6000816126e8576003546126f9565b6003546001546126f89190614b18565b5b9050919050565b60606000600167ffffffffffffffff81111561271f5761271e613e5c565b5b60405190808252806020026020018201604052801561274d5781602001602082028036833780820191505090505b509050308160008151811061276557612764614a89565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508091505090565b60015481565b6127b530612e40565b156127f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016127ec90614e9b565b60405180910390fd5b6128006001306131ee565b565b600080600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000806000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050600115158160c001511515146129fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129f590614f07565b60405180910390fd5b806060015160050b43612a11919061448e565b92505050919050565b6000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000806000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050600115158160c00151151514612c15576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c0c90614f07565b60405180910390fd5b8060a00151612c4a57806040015165ffffffffffff1643612c369190614b18565b8160600151612c459190614d2c565b612c72565b806040015165ffffffffffff1643612c629190614b18565b8160600151612c719190614d8a565b5b60008084815260200190815260200160002060010160066101000a81548165ffffffffffff021916908360050b65ffffffffffff1602179055506000806000848152602001908152602001600020600101600d6101000a81548160ff02191690831515021790555060026000815480929190612ced90614f27565b91905055508060a00151612d145760046000815480929190612d0e90614f27565b91905055505b813373ffffffffffffffffffffffffffffffffffffffff167f2db0fccf216847991dbdfc99c9046973f6a89001ddf35547b3fd301e6d84f7dd60008086815260200190815260200160002060010160069054906101000a900460050b604051612d7d9190614f6f565b60405180910390a35050565b612d916130a7565b63389a75e1600c52806000526020600c208054421115612db957636f5e88186000526004601cfd5b6000815550612dc781613126565b50565b612dd26130a7565b80600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b612e1e6130a7565b8060601b612e3457637448fbae6000526004601cfd5b612e3d81613126565b50565b600080600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000806000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff168152505090508060c0015192505050919050565b600063389a75e1600c52816000526020600c20549050919050565b6060604051905064ffffffffff6001833b0316602181016000601f8401853c80825260408201810160405250919050565b60606080604051019050602081016040526000815280600019835b600115613087578184019350600a81066030018453600a8104905080613066575b50828203602084039350808452505050919050565b60006202a300905090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275433146130dd576382b429006000526004601cfd5b565b600081518060401b6bfe61000180600a3d393df3000161fffe8211840152600b8101601584016000f091508161311d5763301164256000526004601cfd5b80835250919050565b61312e613751565b15613194577fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278160601b60601c91508181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3811560ff1b82178155506131eb565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278160601b60601c91508181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3818155505b50565b6000600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000806000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050600015158160c001511515146133e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016133e090614e9b565b60405180910390fd5b600160008154809291906133fc90614f27565b91905055508361341f576003600081548092919061341990614f27565b91905055505b60006040518061010001604052808573ffffffffffffffffffffffffffffffffffffffff16815260200160015465ffffffffffff1681526020014365ffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff16146134a95783608001516134ab565b435b60050b8152602001600060050b815260200186151581526020016001151581526020018465ffffffffffff16815250905080600080600154815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548165ffffffffffff021916908365ffffffffffff160217905550604082015181600001601a6101000a81548165ffffffffffff021916908365ffffffffffff16021790555060608201518160010160006101000a81548165ffffffffffff021916908360050b65ffffffffffff16021790555060808201518160010160066101000a81548165ffffffffffff021916908360050b65ffffffffffff16021790555060a082015181600101600c6101000a81548160ff02191690831515021790555060c082015181600101600d6101000a81548160ff02191690831515021790555060e082015181600101600e6101000a81548165ffffffffffff021916908365ffffffffffff160217905550905050600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008154809291906136a890614f27565b9190505550600154600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001548473ffffffffffffffffffffffffffffffffffffffff167ffc3a0d8dff7fb0c9db2557091e144781a1719f7731230763bad515e8841f8e3b836060015188604051613742929190614f8a565b60405180910390a35050505050565b600090565b604051806101000160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600065ffffffffffff168152602001600065ffffffffffff168152602001600060050b8152602001600060050b8152602001600015158152602001600015158152602001600065ffffffffffff1681525090565b82805482825590600052602060002090810192821561381b579160200282015b8281111561381a57825182908161380a9190615155565b50916020019190600101906137f3565b5b509050613828919061382c565b5090565b5b8082111561384c57600081816138439190613850565b5060010161382d565b5090565b50805461385c90614ae7565b6000825580601f1061386e575061388d565b601f01602090049060005260206000209081019061388c9190613890565b5b50565b5b808211156138a9576000816000905550600101613891565b5090565b6000819050919050565b6138c0816138ad565b82525050565b60006020820190506138db60008301846138b7565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561391b578082015181840152602081019050613900565b60008484015250505050565b6000601f19601f8301169050919050565b6000613943826138e1565b61394d81856138ec565b935061395d8185602086016138fd565b61396681613927565b840191505092915050565b6000602082019050818103600083015261398b8184613938565b905092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600082825260208201905092915050565b60006139db826138e1565b6139e581856139bf565b93506139f58185602086016138fd565b6139fe81613927565b840191505092915050565b6000613a1583836139d0565b905092915050565b6000602082019050919050565b6000613a3582613993565b613a3f818561399e565b935083602082028501613a51856139af565b8060005b85811015613a8d5784840389528151613a6e8582613a09565b9450613a7983613a1d565b925060208a01995050600181019050613a55565b50829750879550505050505092915050565b60006020820190508181036000830152613ab98184613a2a565b905092915050565b6000604051905090565b600080fd5b600080fd5b613ade816138ad565b8114613ae957600080fd5b50565b600081359050613afb81613ad5565b92915050565b600060208284031215613b1757613b16613acb565b5b6000613b2584828501613aec565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613b8582613b5a565b9050919050565b613b9581613b7a565b82525050565b600065ffffffffffff82169050919050565b613bb681613b9b565b82525050565b60008160050b9050919050565b613bd281613bbc565b82525050565b60008115159050919050565b613bed81613bd8565b82525050565b61010082016000820151613c0a6000850182613b8c565b506020820151613c1d6020850182613bad565b506040820151613c306040850182613bad565b506060820151613c436060850182613bc9565b506080820151613c566080850182613bc9565b5060a0820151613c6960a0850182613be4565b5060c0820151613c7c60c0850182613be4565b5060e0820151613c8f60e0850182613bad565b50505050565b6000613ca18383613bf3565b6101008301905092915050565b6000602082019050919050565b6000613cc682613b2e565b613cd08185613b39565b9350613cdb83613b4a565b8060005b83811015613d0c578151613cf38882613c95565b9750613cfe83613cae565b925050600181019050613cdf565b5085935050505092915050565b60006020820190508181036000830152613d338184613cbb565b905092915050565b613d4481613b7a565b8114613d4f57600080fd5b50565b600081359050613d6181613d3b565b92915050565b600060208284031215613d7d57613d7c613acb565b5b6000613d8b84828501613d52565b91505092915050565b61010082016000820151613dab6000850182613b8c565b506020820151613dbe6020850182613bad565b506040820151613dd16040850182613bad565b506060820151613de46060850182613bc9565b506080820151613df76080850182613bc9565b5060a0820151613e0a60a0850182613be4565b5060c0820151613e1d60c0850182613be4565b5060e0820151613e3060e0850182613bad565b50505050565b600061010082019050613e4c6000830184613d94565b92915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613e9482613927565b810181811067ffffffffffffffff82111715613eb357613eb2613e5c565b5b80604052505050565b6000613ec6613ac1565b9050613ed28282613e8b565b919050565b600067ffffffffffffffff821115613ef257613ef1613e5c565b5b613efb82613927565b9050602081019050919050565b82818337600083830152505050565b6000613f2a613f2584613ed7565b613ebc565b905082815260208101848484011115613f4657613f45613e57565b5b613f51848285613f08565b509392505050565b600082601f830112613f6e57613f6d613e52565b5b8135613f7e848260208601613f17565b91505092915050565b600060208284031215613f9d57613f9c613acb565b5b600082013567ffffffffffffffff811115613fbb57613fba613ad0565b5b613fc784828501613f59565b91505092915050565b600067ffffffffffffffff821115613feb57613fea613e5c565b5b602082029050602081019050919050565b600080fd5b600061401461400f84613fd0565b613ebc565b9050808382526020820190506020840283018581111561403757614036613ffc565b5b835b8181101561407e57803567ffffffffffffffff81111561405c5761405b613e52565b5b8086016140698982613f59565b85526020850194505050602081019050614039565b5050509392505050565b600082601f83011261409d5761409c613e52565b5b81356140ad848260208601614001565b91505092915050565b6000602082840312156140cc576140cb613acb565b5b600082013567ffffffffffffffff8111156140ea576140e9613ad0565b5b6140f684828501614088565b91505092915050565b61410881613b7a565b82525050565b600060208201905061412360008301846140ff565b92915050565b61413281613b9b565b82525050565b61414181613bbc565b82525050565b61415081613bd8565b82525050565b60006101008201905061416c600083018b6140ff565b614179602083018a614129565b6141866040830189614129565b6141936060830188614138565b6141a06080830187614138565b6141ad60a0830186614147565b6141ba60c0830185614147565b6141c760e0830184614129565b9998505050505050505050565b6000806000606084860312156141ed576141ec613acb565b5b60006141fb86828701613aec565b935050602061420c86828701613aec565b925050604061421d86828701613aec565b9150509250925092565b6000819050919050565b61423a81614227565b811461424557600080fd5b50565b60008135905061425781614231565b92915050565b60008060006060848603121561427657614275613acb565b5b600061428486828701613aec565b935050602061429586828701614248565b92505060406142a686828701614248565b9150509250925092565b6142b981613bd8565b81146142c457600080fd5b50565b6000813590506142d6816142b0565b92915050565b6000602082840312156142f2576142f1613acb565b5b6000614300848285016142c7565b91505092915050565b61431281614227565b82525050565b600060208201905061432d6000830184614309565b92915050565b6000806040838503121561434a57614349613acb565b5b600061435885828601613aec565b925050602061436985828601613aec565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006143ab8383613b8c565b60208301905092915050565b6000602082019050919050565b60006143cf82614373565b6143d9818561437e565b93506143e48361438f565b8060005b838110156144155781516143fc888261439f565b9750614407836143b7565b9250506001810190506143e8565b5085935050505092915050565b6000602082019050818103600083015261443c81846143c4565b905092915050565b60006020820190506144596000830184614147565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061449982614227565b91506144a483614227565b92508282039050818112600084121682821360008512151617156144cb576144ca61445f565b5b92915050565b60008160001c9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061451161450c836144d1565b6144de565b9050919050565b60008160a01c9050919050565b600065ffffffffffff82169050919050565b600061454a61454583614518565b614525565b9050919050565b60008160d01c9050919050565b600061457161456c83614551565b614525565b9050919050565b60008160050b9050919050565b6000614598614593836144d1565b614578565b9050919050565b60008160301c9050919050565b60006145bf6145ba8361459f565b614578565b9050919050565b60008160601c9050919050565b600060ff82169050919050565b60006145f36145ee836145c6565b6145d3565b9050919050565b60008160681c9050919050565b600061461a614615836145fa565b6145d3565b9050919050565b60008160701c9050919050565b600061464161463c83614621565b614525565b9050919050565b6101008201600080830154905061465e816144fe565b61466b6000860182613b8c565b5061467581614537565b6146826020860182613bad565b5061468c8161455e565b6146996040860182613bad565b50600183015490506146aa81614585565b6146b76060860182613bc9565b506146c1816145ac565b6146ce6080860182613bc9565b506146d8816145e0565b6146e560a0860182613be4565b506146ef81614607565b6146fc60c0860182613be4565b506147068161462e565b61471360e0860182613bad565b5050505050565b6000819050919050565b6000819050919050565b600061474961474461473f8461471a565b614724565b6138ad565b9050919050565b6147598161472e565b82525050565b60006101a0820190506147756000830189614648565b614783610100830188614750565b614791610120830187614309565b61479f610140830186614309565b6147ad6101608301856138b7565b6147bb6101808301846138b7565b979650505050505050565b60006147d96147d484613ed7565b613ebc565b9050828152602081018484840111156147f5576147f4613e57565b5b6148008482856138fd565b509392505050565b600082601f83011261481d5761481c613e52565b5b815161482d8482602086016147c6565b91505092915050565b60006020828403121561484c5761484b613acb565b5b600082015167ffffffffffffffff81111561486a57614869613ad0565b5b61487684828501614808565b91505092915050565b7f3c62722f3e3c62722f3e00000000000000000000000000000000000000000000815250565b600081905092915050565b60006148bb826138e1565b6148c581856148a5565b93506148d58185602086016138fd565b80840191505092915050565b7f20417420746865206d6f6d656e74207468657265200000000000000000000000815250565b7f2074726176656c65720000000000000000000000000000000000000000000000815250565b7f206f6e2074686520726f61642e20000000000000000000000000000000000000815250565b600061495e8261487f565b600a8201915061496e82876148b0565b9150614979826148e1565b60158201915061498982866148b0565b915061499582856148b0565b91506149a082614907565b6009820191506149b082846148b0565b91506149bb8261492d565b600e8201915081905095945050505050565b7f3c62722f3e3c62722f3e3c62722f3e3c62722f3e000000000000000000000000815250565b60006149fe8261487f565b600a82019150614a0e82886148b0565b9150614a19826148e1565b601582019150614a2982876148b0565b9150614a3582866148b0565b9150614a4082614907565b600982019150614a5082856148b0565b9150614a5b8261492d565b600e82019150614a6a826149cd565b601482019150614a7a82846148b0565b91508190509695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680614aff57607f821691505b602082108103614b1257614b11614ab8565b5b50919050565b6000614b23826138ad565b9150614b2e836138ad565b9250828203905081811115614b4657614b4561445f565b5b92915050565b6000614b57826138ad565b9150614b62836138ad565b9250828201905080821115614b7a57614b7961445f565b5b92915050565b600061018082019050614b966000830188614648565b614ba46101008301876138b7565b614bb26101208301866138b7565b614bc06101408301856138b7565b614bce6101608301846138b7565b9695505050505050565b6000614be3826138ad565b915060008203614bf657614bf561445f565b5b600182039050919050565b600061018082019050614c176000830188614648565b614c256101008301876138b7565b614c33610120830186614309565b614c41610140830185614309565b614c4f6101608301846138b7565b9695505050505050565b7f4a6f75726e657920646f6573206e6f7420657869737400000000000000000000600082015250565b6000614c8f6016836138ec565b9150614c9a82614c59565b602082019050919050565b60006020820190508181036000830152614cbe81614c82565b9050919050565b60006101a082019050614cdb6000830189613d94565b614ce96101008301886138b7565b614cf7610120830187614309565b614d05610140830186614309565b614d136101608301856138b7565b614d216101808301846138b7565b979650505050505050565b6000614d3782613bbc565b9150614d4283613bbc565b92508282039050657fffffffffff81137fffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000082121715614d8457614d8361445f565b5b92915050565b6000614d9582613bbc565b9150614da083613bbc565b925082820190507fffffffffffffffffffffffffffffffffffffffffffffffffffff8000000000008112657fffffffffff82131715614de257614de161445f565b5b92915050565b60006101a082019050614dfe6000830189613d94565b614e0c6101008301886138b7565b614e1a6101208301876138b7565b614e286101408301866138b7565b614e366101608301856138b7565b614e446101808301846138b7565b979650505050505050565b7f416c72656164792074726176656c6c696e670000000000000000000000000000600082015250565b6000614e856012836138ec565b9150614e9082614e4f565b602082019050919050565b60006020820190508181036000830152614eb481614e78565b9050919050565b7f4e6f742074726176656c6c696e67000000000000000000000000000000000000600082015250565b6000614ef1600e836138ec565b9150614efc82614ebb565b602082019050919050565b60006020820190508181036000830152614f2081614ee4565b9050919050565b6000614f32826138ad565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614f6457614f6361445f565b5b600182019050919050565b6000602082019050614f846000830184614138565b92915050565b6000604082019050614f9f6000830185614138565b614fac6020830184614147565b9392505050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026150157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614fd8565b61501f8683614fd8565b95508019841693508086168417925050509392505050565b600061505261504d615048846138ad565b614724565b6138ad565b9050919050565b6000819050919050565b61506c83615037565b61508061507882615059565b848454614fe5565b825550505050565b600090565b615095615088565b6150a0818484615063565b505050565b5b818110156150c4576150b960008261508d565b6001810190506150a6565b5050565b601f821115615109576150da81614fb3565b6150e384614fc8565b810160208510156150f2578190505b6151066150fe85614fc8565b8301826150a5565b50505b505050565b600082821c905092915050565b600061512c6000198460080261510e565b1980831691505092915050565b6000615145838361511b565b9150826002028217905092915050565b61515e826138e1565b67ffffffffffffffff81111561517757615176613e5c565b5b6151818254614ae7565b61518c8282856150c8565b600060209050601f8311600181146151bf57600084156151ad578287015190505b6151b78582615139565b86555061521f565b601f1984166151cd86614fb3565b60005b828110156151f5578489015182556001820191506020850194506020810190506151d0565b86831015615212578489015161520e601f89168261511b565b8355505b6001600288020188555050505b50505050505056fe4465617220476f642c204c61796572206f6620526f616473202854726176656c65727329a2646970667358221220ce9fdecb2c84f2f8396e214aba9ac4cfc96e727765dc89c86d769345eaeb434464736f6c634300081c0033
Deployed Bytecode
0x60806040526004361061023b5760003560e01c8063a33781cb1161012e578063da0321cd116100ab578063f04e283e1161006f578063f04e283e1461087f578063f0c136cb1461089b578063f2fde38b146108c4578063f9cc242d146108e0578063fee81cf41461091d5761023b565b8063da0321cd146107be578063e19f1760146107e9578063e1c7392a14610814578063ec8d88621461082b578063efbe1c1c146108685761023b565b8063c8730b35116100f2578063c8730b351461069f578063d4c6c869146106dc578063d607497a14610719578063d8359ae514610744578063d9ca6918146107815761023b565b8063a33781cb14610582578063aa953719146105bf578063aa98ff4d146105fc578063b544303814610625578063b83fac77146106625761023b565b806354d1f13d116101bc578063715018a611610180578063715018a6146104a157806381851182146104ab5780638da5cb5b146104d65780638df5a9fa146105015780638fc1eac7146105455761023b565b806354d1f13d146103dd57806358090e17146103e75780635d3a1f9d146104245780636cc895a91461044d5780636d1d098c146104765761023b565b806328411ae11161020357806328411ae1146102f65780632c73dc4a1461032157806330388e731461034c57806339b33569146103755780634a79d50c146103b25761023b565b80631c7fb7f4146102405780631f1bd6921461026b57806321ace8c414610296578063226c8aca146102c157806325692962146102ec575b600080fd5b34801561024c57600080fd5b5061025561095a565b60405161026291906138c6565b60405180910390f35b34801561027757600080fd5b50610280610960565b60405161028d9190613971565b60405180910390f35b3480156102a257600080fd5b506102ab610d7a565b6040516102b891906138c6565b60405180910390f35b3480156102cd57600080fd5b506102d6610d80565b6040516102e391906138c6565b60405180910390f35b6102f4610d86565b005b34801561030257600080fd5b5061030b610dda565b6040516103189190613a9f565b60405180910390f35b34801561032d57600080fd5b50610336610e8b565b6040516103439190613a9f565b60405180910390f35b34801561035857600080fd5b50610373600480360381019061036e9190613b01565b610f64565b005b34801561038157600080fd5b5061039c60048036038101906103979190613b01565b610f76565b6040516103a99190613d19565b60405180910390f35b3480156103be57600080fd5b506103c76111ac565b6040516103d49190613971565b60405180910390f35b6103e56111cc565b005b3480156103f357600080fd5b5061040e60048036038101906104099190613d67565b611208565b60405161041b9190613e36565b60405180910390f35b34801561043057600080fd5b5061044b60048036038101906104469190613f87565b6113c4565b005b34801561045957600080fd5b50610474600480360381019061046f91906140b6565b611418565b005b34801561048257600080fd5b5061048b61143a565b60405161049891906138c6565b60405180910390f35b6104a9611451565b005b3480156104b757600080fd5b506104c0611465565b6040516104cd91906138c6565b60405180910390f35b3480156104e257600080fd5b506104eb61146b565b6040516104f8919061410e565b60405180910390f35b34801561050d57600080fd5b5061052860048036038101906105239190613b01565b611494565b60405161053c989796959493929190614156565b60405180910390f35b34801561055157600080fd5b5061056c600480360381019061056791906141d4565b611566565b6040516105799190613971565b60405180910390f35b34801561058e57600080fd5b506105a960048036038101906105a49190613d67565b61162d565b6040516105b69190613d19565b60405180910390f35b3480156105cb57600080fd5b506105e660048036038101906105e1919061425d565b611aba565b6040516105f39190613971565b60405180910390f35b34801561060857600080fd5b50610623600480360381019061061e91906142dc565b611b81565b005b34801561063157600080fd5b5061064c60048036038101906106479190613b01565b611b8e565b6040516106599190613e36565b60405180910390f35b34801561066e57600080fd5b506106896004803603810190610684919061425d565b611d56565b6040516106969190613971565b60405180910390f35b3480156106ab57600080fd5b506106c660048036038101906106c19190613d67565b611f8d565b6040516106d39190614318565b60405180910390f35b3480156106e857600080fd5b5061070360048036038101906106fe91906141d4565b6121d6565b6040516107109190613971565b60405180910390f35b34801561072557600080fd5b5061072e61240d565b60405161073b919061410e565b60405180910390f35b34801561075057600080fd5b5061076b60048036038101906107669190614333565b612433565b6040516107789190613d19565b60405180910390f35b34801561078d57600080fd5b506107a860048036038101906107a391906142dc565b6126d9565b6040516107b591906138c6565b60405180910390f35b3480156107ca57600080fd5b506107d3612700565b6040516107e09190614422565b60405180910390f35b3480156107f557600080fd5b506107fe6127a6565b60405161080b91906138c6565b60405180910390f35b34801561082057600080fd5b506108296127ac565b005b34801561083757600080fd5b50610852600480360381019061084d9190613d67565b612802565b60405161085f9190614318565b60405180910390f35b34801561087457600080fd5b5061087d612a1a565b005b61089960048036038101906108949190613d67565b612d89565b005b3480156108a757600080fd5b506108c260048036038101906108bd9190613d67565b612dca565b005b6108de60048036038101906108d99190613d67565b612e16565b005b3480156108ec57600080fd5b5061090760048036038101906109029190613d67565b612e40565b6040516109149190614444565b60405180910390f35b34801561092957600080fd5b50610944600480360381019061093f9190613d67565b612fff565b60405161095191906138c6565b60405180910390f35b60035481565b6060600061096c61143a565b9050600061097a60016126d9565b9050600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b9e4f8d3600080600181526020019081526020016000206001600b54436109dd919061448e565b43600154876040518763ffffffff1660e01b8152600401610a039695949392919061475f565b600060405180830381865afa925050508015610a4257506040513d6000823e3d601f19601f82011682018060405250810190610a3f9190614836565b60015b610bdf57600073ffffffffffffffffffffffffffffffffffffffff16600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610acc57610ac7600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661301a565b610add565b604051806020016040528060008152505b60018314610b20576040518060400160405280600481526020017f6172652000000000000000000000000000000000000000000000000000000000815250610b57565b6040518060400160405280600381526020017f69732000000000000000000000000000000000000000000000000000000000008152505b610b608461304b565b60018514610ba3576040518060400160405280600181526020017f7300000000000000000000000000000000000000000000000000000000000000815250610bb4565b604051806020016040528060008152505b604051602001610bc79493929190614953565b60405160208183030381529060405292505050610d77565b600073ffffffffffffffffffffffffffffffffffffffff16600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610c6557610c60600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661301a565b610c76565b604051806020016040528060008152505b60018414610cb9576040518060400160405280600481526020017f6172652000000000000000000000000000000000000000000000000000000000815250610cf0565b6040518060400160405280600381526020017f69732000000000000000000000000000000000000000000000000000000000008152505b610cf98561304b565b60018614610d3c576040518060400160405280600181526020017f7300000000000000000000000000000000000000000000000000000000000000815250610d4d565b604051806020016040528060008152505b84604051602001610d629594939291906149f3565b60405160208183030381529060405293505050505b90565b60045481565b60025481565b6000610d9061309c565b67ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b60606000600167ffffffffffffffff811115610df957610df8613e5c565b5b604051908082528060200260200182016040528015610e2c57816020015b6060815260200190600190039081610e175790505b5090506040518060400160405280601c81526020017f4c6f7563617320427261636f6e6e69657220284669677572653331290000000081525081600081518110610e7957610e78614a89565b5b60200260200101819052508091505090565b60606009805480602002602001604051908101604052809291908181526020016000905b82821015610f5b578382906000526020600020018054610ece90614ae7565b80601f0160208091040260200160405190810160405280929190818152602001828054610efa90614ae7565b8015610f475780601f10610f1c57610100808354040283529160200191610f47565b820191906000526020600020905b815481529060010190602001808311610f2a57829003601f168201915b505050505081526020019060010190610eaf565b50505050905090565b610f6c6130a7565b80600b8190555050565b6060600154821115610f885760015491505b60008267ffffffffffffffff811115610fa457610fa3613e5c565b5b604051908082528060200260200182016040528015610fdd57816020015b610fca613756565b815260200190600190039081610fc25790505b50905060005b838110156111a25760008060018387600154610fff9190614b18565b6110099190614b4c565b6110139190614b4c565b8152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff168152505082828151811061118a57611189614a89565b5b60200260200101819052508080600101915050610fe3565b5080915050919050565b606060405180606001604052806024815260200161522860249139905090565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b611210613756565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600080828152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681525050915050919050565b6113cc6130a7565b6113d5816130df565b600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6114206130a7565b80600990805190602001906114369291906137d3565b5050565b600060025460015461144c9190614b18565b905090565b6114596130a7565b6114636000613126565b565b600b5481565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754905090565b60006020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900465ffffffffffff169080600001601a9054906101000a900465ffffffffffff16908060010160009054906101000a900460050b908060010160069054906101000a900460050b9080600101600c9054906101000a900460ff169080600101600d9054906101000a900460ff169080600101600e9054906101000a900465ffffffffffff16905088565b6060600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c715c58d6000808781526020019081526020016000208686866001546040518663ffffffff1660e01b81526004016115de959493929190614b80565b600060405180830381865afa1580156115fb573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906116249190614836565b90509392505050565b60606000600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060008167ffffffffffffffff81111561168f5761168e613e5c565b5b6040519080825280602002602001820160405280156116c857816020015b6116b5613756565b8152602001906001900390816116ad5790505b5090506000806000600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff168152505090506000830361188957819350505050611ab5565b80826001856118989190614b18565b815181106118a9576118a8614a89565b5b6020026020010181905250600183036118c757819350505050611ab5565b60006001846118d69190614b18565b90505b6000811115611aad576000808483815181106118f8576118f7614a89565b5b602002602001015160e0015165ffffffffffff168152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff168152505083600183611a7e9190614b18565b81518110611a8f57611a8e614a89565b5b60200260200101819052508080611aa590614bd8565b9150506118d9565b508193505050505b919050565b6060600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663680fd2316000808781526020019081526020016000208686866001546040518663ffffffff1660e01b8152600401611b32959493929190614c01565b600060405180830381865afa158015611b4f573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611b789190614836565b90509392505050565b611b8b81336131ee565b50565b611b96613756565b816000108015611ba857506001548211155b611be7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bde90614ca5565b60405180910390fd5b600080838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050919050565b60606000806000868152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff168152505090506000611ed38260a001516126d9565b9050600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b9e4f8d383888888600154876040518763ffffffff1660e01b8152600401611f3c96959493929190614cc5565b600060405180830381865afa158015611f59573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611f829190614836565b925050509392505050565b600080600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000806000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050600015158160c00151151514801561215d57506000816080015160050b145b1561216c5743925050506121d1565b8060a001516121a157806040015165ffffffffffff164361218d9190614b18565b816060015161219c9190614d2c565b6121c9565b806040015165ffffffffffff16436121b99190614b18565b81606001516121c89190614d8a565b5b60050b925050505b919050565b60606000806000868152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681525050905060006123538260a001516126d9565b9050600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663277fa13183888888600154876040518763ffffffff1660e01b81526004016123bc96959493929190614de8565b600060405180830381865afa1580156123d9573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906124029190614836565b925050509392505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6060600154831061249a57600067ffffffffffffffff81111561245957612458613e5c565b5b60405190808252806020026020018201604052801561249257816020015b61247f613756565b8152602001906001900390816124775790505b5090506126d3565b60015482846124a99190614b4c565b11156124c057826001546124bd9190614b18565b91505b60008267ffffffffffffffff8111156124dc576124db613e5c565b5b60405190808252806020026020018201604052801561251557816020015b612502613756565b8152602001906001900390816124fa5790505b50905060005b838110156126cd57600080600183886125349190614b4c565b61253e9190614b4c565b8152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250508282815181106126b5576126b4614a89565b5b6020026020010181905250808060010191505061251b565b50809150505b92915050565b6000816126e8576003546126f9565b6003546001546126f89190614b18565b5b9050919050565b60606000600167ffffffffffffffff81111561271f5761271e613e5c565b5b60405190808252806020026020018201604052801561274d5781602001602082028036833780820191505090505b509050308160008151811061276557612764614a89565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508091505090565b60015481565b6127b530612e40565b156127f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016127ec90614e9b565b60405180910390fd5b6128006001306131ee565b565b600080600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000806000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050600115158160c001511515146129fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129f590614f07565b60405180910390fd5b806060015160050b43612a11919061448e565b92505050919050565b6000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000806000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050600115158160c00151151514612c15576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c0c90614f07565b60405180910390fd5b8060a00151612c4a57806040015165ffffffffffff1643612c369190614b18565b8160600151612c459190614d2c565b612c72565b806040015165ffffffffffff1643612c629190614b18565b8160600151612c719190614d8a565b5b60008084815260200190815260200160002060010160066101000a81548165ffffffffffff021916908360050b65ffffffffffff1602179055506000806000848152602001908152602001600020600101600d6101000a81548160ff02191690831515021790555060026000815480929190612ced90614f27565b91905055508060a00151612d145760046000815480929190612d0e90614f27565b91905055505b813373ffffffffffffffffffffffffffffffffffffffff167f2db0fccf216847991dbdfc99c9046973f6a89001ddf35547b3fd301e6d84f7dd60008086815260200190815260200160002060010160069054906101000a900460050b604051612d7d9190614f6f565b60405180910390a35050565b612d916130a7565b63389a75e1600c52806000526020600c208054421115612db957636f5e88186000526004601cfd5b6000815550612dc781613126565b50565b612dd26130a7565b80600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b612e1e6130a7565b8060601b612e3457637448fbae6000526004601cfd5b612e3d81613126565b50565b600080600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000806000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff168152505090508060c0015192505050919050565b600063389a75e1600c52816000526020600c20549050919050565b6060604051905064ffffffffff6001833b0316602181016000601f8401853c80825260408201810160405250919050565b60606080604051019050602081016040526000815280600019835b600115613087578184019350600a81066030018453600a8104905080613066575b50828203602084039350808452505050919050565b60006202a300905090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275433146130dd576382b429006000526004601cfd5b565b600081518060401b6bfe61000180600a3d393df3000161fffe8211840152600b8101601584016000f091508161311d5763301164256000526004601cfd5b80835250919050565b61312e613751565b15613194577fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278160601b60601c91508181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3811560ff1b82178155506131eb565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278160601b60601c91508181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3818155505b50565b6000600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000806000838152602001908152602001600020604051806101000160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a900460050b60050b60050b81526020016001820160069054906101000a900460050b60050b60050b815260200160018201600c9054906101000a900460ff1615151515815260200160018201600d9054906101000a900460ff1615151515815260200160018201600e9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050600015158160c001511515146133e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016133e090614e9b565b60405180910390fd5b600160008154809291906133fc90614f27565b91905055508361341f576003600081548092919061341990614f27565b91905055505b60006040518061010001604052808573ffffffffffffffffffffffffffffffffffffffff16815260200160015465ffffffffffff1681526020014365ffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff16146134a95783608001516134ab565b435b60050b8152602001600060050b815260200186151581526020016001151581526020018465ffffffffffff16815250905080600080600154815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548165ffffffffffff021916908365ffffffffffff160217905550604082015181600001601a6101000a81548165ffffffffffff021916908365ffffffffffff16021790555060608201518160010160006101000a81548165ffffffffffff021916908360050b65ffffffffffff16021790555060808201518160010160066101000a81548165ffffffffffff021916908360050b65ffffffffffff16021790555060a082015181600101600c6101000a81548160ff02191690831515021790555060c082015181600101600d6101000a81548160ff02191690831515021790555060e082015181600101600e6101000a81548165ffffffffffff021916908365ffffffffffff160217905550905050600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008154809291906136a890614f27565b9190505550600154600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001548473ffffffffffffffffffffffffffffffffffffffff167ffc3a0d8dff7fb0c9db2557091e144781a1719f7731230763bad515e8841f8e3b836060015188604051613742929190614f8a565b60405180910390a35050505050565b600090565b604051806101000160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600065ffffffffffff168152602001600065ffffffffffff168152602001600060050b8152602001600060050b8152602001600015158152602001600015158152602001600065ffffffffffff1681525090565b82805482825590600052602060002090810192821561381b579160200282015b8281111561381a57825182908161380a9190615155565b50916020019190600101906137f3565b5b509050613828919061382c565b5090565b5b8082111561384c57600081816138439190613850565b5060010161382d565b5090565b50805461385c90614ae7565b6000825580601f1061386e575061388d565b601f01602090049060005260206000209081019061388c9190613890565b5b50565b5b808211156138a9576000816000905550600101613891565b5090565b6000819050919050565b6138c0816138ad565b82525050565b60006020820190506138db60008301846138b7565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561391b578082015181840152602081019050613900565b60008484015250505050565b6000601f19601f8301169050919050565b6000613943826138e1565b61394d81856138ec565b935061395d8185602086016138fd565b61396681613927565b840191505092915050565b6000602082019050818103600083015261398b8184613938565b905092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600082825260208201905092915050565b60006139db826138e1565b6139e581856139bf565b93506139f58185602086016138fd565b6139fe81613927565b840191505092915050565b6000613a1583836139d0565b905092915050565b6000602082019050919050565b6000613a3582613993565b613a3f818561399e565b935083602082028501613a51856139af565b8060005b85811015613a8d5784840389528151613a6e8582613a09565b9450613a7983613a1d565b925060208a01995050600181019050613a55565b50829750879550505050505092915050565b60006020820190508181036000830152613ab98184613a2a565b905092915050565b6000604051905090565b600080fd5b600080fd5b613ade816138ad565b8114613ae957600080fd5b50565b600081359050613afb81613ad5565b92915050565b600060208284031215613b1757613b16613acb565b5b6000613b2584828501613aec565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613b8582613b5a565b9050919050565b613b9581613b7a565b82525050565b600065ffffffffffff82169050919050565b613bb681613b9b565b82525050565b60008160050b9050919050565b613bd281613bbc565b82525050565b60008115159050919050565b613bed81613bd8565b82525050565b61010082016000820151613c0a6000850182613b8c565b506020820151613c1d6020850182613bad565b506040820151613c306040850182613bad565b506060820151613c436060850182613bc9565b506080820151613c566080850182613bc9565b5060a0820151613c6960a0850182613be4565b5060c0820151613c7c60c0850182613be4565b5060e0820151613c8f60e0850182613bad565b50505050565b6000613ca18383613bf3565b6101008301905092915050565b6000602082019050919050565b6000613cc682613b2e565b613cd08185613b39565b9350613cdb83613b4a565b8060005b83811015613d0c578151613cf38882613c95565b9750613cfe83613cae565b925050600181019050613cdf565b5085935050505092915050565b60006020820190508181036000830152613d338184613cbb565b905092915050565b613d4481613b7a565b8114613d4f57600080fd5b50565b600081359050613d6181613d3b565b92915050565b600060208284031215613d7d57613d7c613acb565b5b6000613d8b84828501613d52565b91505092915050565b61010082016000820151613dab6000850182613b8c565b506020820151613dbe6020850182613bad565b506040820151613dd16040850182613bad565b506060820151613de46060850182613bc9565b506080820151613df76080850182613bc9565b5060a0820151613e0a60a0850182613be4565b5060c0820151613e1d60c0850182613be4565b5060e0820151613e3060e0850182613bad565b50505050565b600061010082019050613e4c6000830184613d94565b92915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613e9482613927565b810181811067ffffffffffffffff82111715613eb357613eb2613e5c565b5b80604052505050565b6000613ec6613ac1565b9050613ed28282613e8b565b919050565b600067ffffffffffffffff821115613ef257613ef1613e5c565b5b613efb82613927565b9050602081019050919050565b82818337600083830152505050565b6000613f2a613f2584613ed7565b613ebc565b905082815260208101848484011115613f4657613f45613e57565b5b613f51848285613f08565b509392505050565b600082601f830112613f6e57613f6d613e52565b5b8135613f7e848260208601613f17565b91505092915050565b600060208284031215613f9d57613f9c613acb565b5b600082013567ffffffffffffffff811115613fbb57613fba613ad0565b5b613fc784828501613f59565b91505092915050565b600067ffffffffffffffff821115613feb57613fea613e5c565b5b602082029050602081019050919050565b600080fd5b600061401461400f84613fd0565b613ebc565b9050808382526020820190506020840283018581111561403757614036613ffc565b5b835b8181101561407e57803567ffffffffffffffff81111561405c5761405b613e52565b5b8086016140698982613f59565b85526020850194505050602081019050614039565b5050509392505050565b600082601f83011261409d5761409c613e52565b5b81356140ad848260208601614001565b91505092915050565b6000602082840312156140cc576140cb613acb565b5b600082013567ffffffffffffffff8111156140ea576140e9613ad0565b5b6140f684828501614088565b91505092915050565b61410881613b7a565b82525050565b600060208201905061412360008301846140ff565b92915050565b61413281613b9b565b82525050565b61414181613bbc565b82525050565b61415081613bd8565b82525050565b60006101008201905061416c600083018b6140ff565b614179602083018a614129565b6141866040830189614129565b6141936060830188614138565b6141a06080830187614138565b6141ad60a0830186614147565b6141ba60c0830185614147565b6141c760e0830184614129565b9998505050505050505050565b6000806000606084860312156141ed576141ec613acb565b5b60006141fb86828701613aec565b935050602061420c86828701613aec565b925050604061421d86828701613aec565b9150509250925092565b6000819050919050565b61423a81614227565b811461424557600080fd5b50565b60008135905061425781614231565b92915050565b60008060006060848603121561427657614275613acb565b5b600061428486828701613aec565b935050602061429586828701614248565b92505060406142a686828701614248565b9150509250925092565b6142b981613bd8565b81146142c457600080fd5b50565b6000813590506142d6816142b0565b92915050565b6000602082840312156142f2576142f1613acb565b5b6000614300848285016142c7565b91505092915050565b61431281614227565b82525050565b600060208201905061432d6000830184614309565b92915050565b6000806040838503121561434a57614349613acb565b5b600061435885828601613aec565b925050602061436985828601613aec565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006143ab8383613b8c565b60208301905092915050565b6000602082019050919050565b60006143cf82614373565b6143d9818561437e565b93506143e48361438f565b8060005b838110156144155781516143fc888261439f565b9750614407836143b7565b9250506001810190506143e8565b5085935050505092915050565b6000602082019050818103600083015261443c81846143c4565b905092915050565b60006020820190506144596000830184614147565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061449982614227565b91506144a483614227565b92508282039050818112600084121682821360008512151617156144cb576144ca61445f565b5b92915050565b60008160001c9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061451161450c836144d1565b6144de565b9050919050565b60008160a01c9050919050565b600065ffffffffffff82169050919050565b600061454a61454583614518565b614525565b9050919050565b60008160d01c9050919050565b600061457161456c83614551565b614525565b9050919050565b60008160050b9050919050565b6000614598614593836144d1565b614578565b9050919050565b60008160301c9050919050565b60006145bf6145ba8361459f565b614578565b9050919050565b60008160601c9050919050565b600060ff82169050919050565b60006145f36145ee836145c6565b6145d3565b9050919050565b60008160681c9050919050565b600061461a614615836145fa565b6145d3565b9050919050565b60008160701c9050919050565b600061464161463c83614621565b614525565b9050919050565b6101008201600080830154905061465e816144fe565b61466b6000860182613b8c565b5061467581614537565b6146826020860182613bad565b5061468c8161455e565b6146996040860182613bad565b50600183015490506146aa81614585565b6146b76060860182613bc9565b506146c1816145ac565b6146ce6080860182613bc9565b506146d8816145e0565b6146e560a0860182613be4565b506146ef81614607565b6146fc60c0860182613be4565b506147068161462e565b61471360e0860182613bad565b5050505050565b6000819050919050565b6000819050919050565b600061474961474461473f8461471a565b614724565b6138ad565b9050919050565b6147598161472e565b82525050565b60006101a0820190506147756000830189614648565b614783610100830188614750565b614791610120830187614309565b61479f610140830186614309565b6147ad6101608301856138b7565b6147bb6101808301846138b7565b979650505050505050565b60006147d96147d484613ed7565b613ebc565b9050828152602081018484840111156147f5576147f4613e57565b5b6148008482856138fd565b509392505050565b600082601f83011261481d5761481c613e52565b5b815161482d8482602086016147c6565b91505092915050565b60006020828403121561484c5761484b613acb565b5b600082015167ffffffffffffffff81111561486a57614869613ad0565b5b61487684828501614808565b91505092915050565b7f3c62722f3e3c62722f3e00000000000000000000000000000000000000000000815250565b600081905092915050565b60006148bb826138e1565b6148c581856148a5565b93506148d58185602086016138fd565b80840191505092915050565b7f20417420746865206d6f6d656e74207468657265200000000000000000000000815250565b7f2074726176656c65720000000000000000000000000000000000000000000000815250565b7f206f6e2074686520726f61642e20000000000000000000000000000000000000815250565b600061495e8261487f565b600a8201915061496e82876148b0565b9150614979826148e1565b60158201915061498982866148b0565b915061499582856148b0565b91506149a082614907565b6009820191506149b082846148b0565b91506149bb8261492d565b600e8201915081905095945050505050565b7f3c62722f3e3c62722f3e3c62722f3e3c62722f3e000000000000000000000000815250565b60006149fe8261487f565b600a82019150614a0e82886148b0565b9150614a19826148e1565b601582019150614a2982876148b0565b9150614a3582866148b0565b9150614a4082614907565b600982019150614a5082856148b0565b9150614a5b8261492d565b600e82019150614a6a826149cd565b601482019150614a7a82846148b0565b91508190509695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680614aff57607f821691505b602082108103614b1257614b11614ab8565b5b50919050565b6000614b23826138ad565b9150614b2e836138ad565b9250828203905081811115614b4657614b4561445f565b5b92915050565b6000614b57826138ad565b9150614b62836138ad565b9250828201905080821115614b7a57614b7961445f565b5b92915050565b600061018082019050614b966000830188614648565b614ba46101008301876138b7565b614bb26101208301866138b7565b614bc06101408301856138b7565b614bce6101608301846138b7565b9695505050505050565b6000614be3826138ad565b915060008203614bf657614bf561445f565b5b600182039050919050565b600061018082019050614c176000830188614648565b614c256101008301876138b7565b614c33610120830186614309565b614c41610140830185614309565b614c4f6101608301846138b7565b9695505050505050565b7f4a6f75726e657920646f6573206e6f7420657869737400000000000000000000600082015250565b6000614c8f6016836138ec565b9150614c9a82614c59565b602082019050919050565b60006020820190508181036000830152614cbe81614c82565b9050919050565b60006101a082019050614cdb6000830189613d94565b614ce96101008301886138b7565b614cf7610120830187614309565b614d05610140830186614309565b614d136101608301856138b7565b614d216101808301846138b7565b979650505050505050565b6000614d3782613bbc565b9150614d4283613bbc565b92508282039050657fffffffffff81137fffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000082121715614d8457614d8361445f565b5b92915050565b6000614d9582613bbc565b9150614da083613bbc565b925082820190507fffffffffffffffffffffffffffffffffffffffffffffffffffff8000000000008112657fffffffffff82131715614de257614de161445f565b5b92915050565b60006101a082019050614dfe6000830189613d94565b614e0c6101008301886138b7565b614e1a6101208301876138b7565b614e286101408301866138b7565b614e366101608301856138b7565b614e446101808301846138b7565b979650505050505050565b7f416c72656164792074726176656c6c696e670000000000000000000000000000600082015250565b6000614e856012836138ec565b9150614e9082614e4f565b602082019050919050565b60006020820190508181036000830152614eb481614e78565b9050919050565b7f4e6f742074726176656c6c696e67000000000000000000000000000000000000600082015250565b6000614ef1600e836138ec565b9150614efc82614ebb565b602082019050919050565b60006020820190508181036000830152614f2081614ee4565b9050919050565b6000614f32826138ad565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614f6457614f6361445f565b5b600182019050919050565b6000602082019050614f846000830184614138565b92915050565b6000604082019050614f9f6000830185614138565b614fac6020830184614147565b9392505050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026150157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614fd8565b61501f8683614fd8565b95508019841693508086168417925050509392505050565b600061505261504d615048846138ad565b614724565b6138ad565b9050919050565b6000819050919050565b61506c83615037565b61508061507882615059565b848454614fe5565b825550505050565b600090565b615095615088565b6150a0818484615063565b505050565b5b818110156150c4576150b960008261508d565b6001810190506150a6565b5050565b601f821115615109576150da81614fb3565b6150e384614fc8565b810160208510156150f2578190505b6151066150fe85614fc8565b8301826150a5565b50505b505050565b600082821c905092915050565b600061512c6000198460080261510e565b1980831691505092915050565b6000615145838361511b565b9150826002028217905092915050565b61515e826138e1565b67ffffffffffffffff81111561517757615176613e5c565b5b6151818254614ae7565b61518c8282856150c8565b600060209050601f8311600181146151bf57600084156151ad578287015190505b6151b78582615139565b86555061521f565b601f1984166151cd86614fb3565b60005b828110156151f5578489015182556001820191506020850194506020810190506151d0565b86831015615212578489015161520e601f89168261511b565b8355505b6001600288020188555050505b50505050505056fe4465617220476f642c204c61796572206f6620526f616473202854726176656c65727329a2646970667358221220ce9fdecb2c84f2f8396e214aba9ac4cfc96e727765dc89c86d769345eaeb434464736f6c634300081c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
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.