Feature Tip: Add private address tag to any address under My Name Tag !
This contract ethscribes a "POAP" to commemorate ESIP-3. More here.
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 19,328 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Create Ethscript... | 20411209 | 259 days ago | IN | 0 ETH | 0.00004655 | ||||
Create Ethscript... | 20146719 | 296 days ago | IN | 0 ETH | 0.00004031 | ||||
Create Ethscript... | 18876659 | 474 days ago | IN | 0 ETH | 0.00052691 | ||||
Create Ethscript... | 18348446 | 548 days ago | IN | 0 ETH | 0.00012663 | ||||
Create Ethscript... | 18339795 | 549 days ago | IN | 0 ETH | 0.00012574 | ||||
Create Ethscript... | 18329717 | 550 days ago | IN | 0 ETH | 0.00014133 | ||||
Create Ethscript... | 18326000 | 551 days ago | IN | 0 ETH | 0.00016264 | ||||
Create Ethscript... | 18280630 | 557 days ago | IN | 0 ETH | 0.00011826 | ||||
Create Ethscript... | 18256256 | 561 days ago | IN | 0 ETH | 0.00021477 | ||||
Create Ethscript... | 18255983 | 561 days ago | IN | 0 ETH | 0.00022683 | ||||
Create Ethscript... | 18253338 | 561 days ago | IN | 0 ETH | 0.00012094 | ||||
Create Ethscript... | 18231035 | 564 days ago | IN | 0 ETH | 0.00013114 | ||||
Create Ethscript... | 18221608 | 566 days ago | IN | 0 ETH | 0.00063095 | ||||
Create Ethscript... | 18221605 | 566 days ago | IN | 0 ETH | 0.00058743 | ||||
Create Ethscript... | 18211835 | 567 days ago | IN | 0 ETH | 0.00017052 | ||||
Create Ethscript... | 18205633 | 568 days ago | IN | 0 ETH | 0.00015521 | ||||
Create Ethscript... | 18201445 | 568 days ago | IN | 0 ETH | 0.00014359 | ||||
Create Ethscript... | 18198583 | 569 days ago | IN | 0 ETH | 0.00016018 | ||||
Create Ethscript... | 18193247 | 569 days ago | IN | 0 ETH | 0.00017405 | ||||
Create Ethscript... | 18190977 | 570 days ago | IN | 0 ETH | 0.00017021 | ||||
Create Ethscript... | 18182513 | 571 days ago | IN | 0 ETH | 0.00018014 | ||||
Create Ethscript... | 18169676 | 573 days ago | IN | 0 ETH | 0.00022755 | ||||
Create Ethscript... | 18167938 | 573 days ago | IN | 0 ETH | 0.00017795 | ||||
Create Ethscript... | 18167775 | 573 days ago | IN | 0 ETH | 0.00017405 | ||||
Create Ethscript... | 18167772 | 573 days ago | IN | 0 ETH | 0.00017405 |
Loading...
Loading
Contract Name:
EthscriptionCreator
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "solady/src/utils/Base64.sol"; import "solady/src/utils/LibString.sol"; import "solady/src/utils/LibPRNG.sol"; contract EthscriptionCreator { using LibString for *; using LibPRNG for LibPRNG.PRNG; uint256 public totalSupply; uint public constant esip3StartBlock = 18130000; uint public constant mintEndBlock = esip3StartBlock + (24 hours / 12); struct SvgArgs { uint256 circleRadius; uint256 rectWidth; uint256 rectHeight; uint256 nextId; string circleColor; string rectColor; string bgColor; string textColor; } event ethscriptions_protocol_CreateEthscription( address indexed initialOwner, string contentURI ); function createEthscription() public { require(block.number >= esip3StartBlock, "Not yet started"); require(block.number <= mintEndBlock, "It's over"); uint256 nextId = ++totalSupply; LibPRNG.PRNG memory prng = LibPRNG.PRNG( uint160(msg.sender) + nextId ); SvgArgs memory s = SvgArgs({ circleRadius: prng.uniform(100), rectWidth: prng.uniform(100), rectHeight: prng.uniform(100), nextId: nextId, circleColor: generateRandomColor(prng), rectColor: generateRandomColor(prng), bgColor: generateRandomColor(prng), textColor: generateRandomColor(prng) }); bytes memory svgContent = generateSVG(s, prng); string memory dataURI = string( abi.encodePacked( "data:image/svg+xml;base64,", Base64.encode(svgContent) ) ); emit ethscriptions_protocol_CreateEthscription(msg.sender, dataURI); } function generateSVG(SvgArgs memory s, LibPRNG.PRNG memory prng) internal pure returns (bytes memory) { uint circleX = prng.uniform(100); uint circleY = prng.uniform(100); return abi.encodePacked( '<svg xmlns="http://www.w3.org/2000/svg" version="1.2" height="1200" width="1200" viewbox="0 0 1200 1200">', // Linear gradient for circle "<defs>", '<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">', '<stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />', '<stop offset="100%" style="stop-color:', s.circleColor, ';stop-opacity:1" />', "</linearGradient>", '<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="0%">', '<stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />', '<stop offset="100%" style="stop-color:', s.bgColor, ';stop-opacity:1" />', "</linearGradient>", "</defs>", '<rect width="100%" height="100%" fill="url(#grad)" />', // Circle with gradient '<circle cx="', LibString.toString(circleX), '%" cy="', LibString.toString(circleY), '%" r="', LibString.toString(s.circleRadius), '%" fill="url(#grad1)" stroke="black" stroke-width="2"/>', // Rectangle with solid color '<rect x="60" y="60" rx="15" ry="15" width="', LibString.toString(s.rectWidth), '%" height="', LibString.toString(s.rectHeight), '%" fill="', s.rectColor, '" stroke="black" stroke-width="2" />', '<text fill="', s.textColor,'" x="1170" y="1170" font-size="200%" text-anchor="end" font-family="helvetica neue, helvetica, arial, san-serif">', "ESIP-3 Welcome POAP #", s.nextId.toString(), "</text>" "</svg>" ); } function generateRandomColor(LibPRNG.PRNG memory prng) internal pure returns (string memory) { uint256 red = prng.uniform(255); uint256 green = prng.uniform(255); uint256 blue = prng.uniform(255); return string( abi.encodePacked( "rgb(", LibString.toString(red), ",", LibString.toString(green), ",", LibString.toString(blue), ")" ) ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for generating pseudorandom numbers. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibPRNG.sol) library LibPRNG { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev A pseudorandom number state in memory. struct PRNG { uint256 state; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Seeds the `prng` with `state`. function seed(PRNG memory prng, uint256 state) internal pure { /// @solidity memory-safe-assembly assembly { mstore(prng, state) } } /// @dev Returns the next pseudorandom uint256. /// All bits of the returned uint256 pass the NIST Statistical Test Suite. function next(PRNG memory prng) internal pure returns (uint256 result) { // We simply use `keccak256` for a great balance between // runtime gas costs, bytecode size, and statistical properties. // // A high-quality LCG with a 32-byte state // is only about 30% more gas efficient during runtime, // but requires a 32-byte multiplier, which can cause bytecode bloat // when this function is inlined. // // Using this method is about 2x more efficient than // `nextRandomness = uint256(keccak256(abi.encode(randomness)))`. /// @solidity memory-safe-assembly assembly { result := keccak256(prng, 0x20) mstore(prng, result) } } /// @dev Returns a pseudorandom uint256, uniformly distributed /// between 0 (inclusive) and `upper` (exclusive). /// If your modulus is big, this method is recommended /// for uniform sampling to avoid modulo bias. /// For uniform sampling across all uint256 values, /// or for small enough moduli such that the bias is neligible, /// use {next} instead. function uniform(PRNG memory prng, uint256 upper) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := keccak256(prng, 0x20) mstore(prng, result) if iszero(lt(result, mod(sub(0, upper), upper))) { break } } result := mod(result, upper) } } /// @dev Shuffles the array in-place with Fisher-Yates shuffle. function shuffle(PRNG memory prng, uint256[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { let n := mload(a) let w := not(0) let mask := shr(128, w) if n { for { a := add(a, 0x20) } 1 {} { // We can just directly use `keccak256`, cuz // the other approaches don't save much. let r := keccak256(prng, 0x20) mstore(prng, r) // Note that there will be a very tiny modulo bias // if the length of the array is not a power of 2. // For all practical purposes, it is negligible // and will not be a fairness or security concern. { let j := add(a, shl(5, mod(shr(128, r), n))) n := add(n, w) // `sub(n, 1)`. if iszero(n) { break } let i := add(a, shl(5, n)) let t := mload(i) mstore(i, mload(j)) mstore(j, t) } { let j := add(a, shl(5, mod(and(r, mask), n))) n := add(n, w) // `sub(n, 1)`. if iszero(n) { break } let i := add(a, shl(5, n)) let t := mload(i) mstore(i, mload(j)) mstore(j, t) } } } } } /// @dev Shuffles the bytes in-place with Fisher-Yates shuffle. function shuffle(PRNG memory prng, bytes memory a) internal pure { /// @solidity memory-safe-assembly assembly { let n := mload(a) let w := not(0) let mask := shr(128, w) if n { let b := add(a, 0x01) for { a := add(a, 0x20) } 1 {} { // We can just directly use `keccak256`, cuz // the other approaches don't save much. let r := keccak256(prng, 0x20) mstore(prng, r) // Note that there will be a very tiny modulo bias // if the length of the array is not a power of 2. // For all practical purposes, it is negligible // and will not be a fairness or security concern. { let o := mod(shr(128, r), n) n := add(n, w) // `sub(n, 1)`. if iszero(n) { break } let t := mload(add(b, n)) mstore8(add(a, n), mload(add(b, o))) mstore8(add(a, o), t) } { let o := mod(and(r, mask), n) n := add(n, w) // `sub(n, 1)`. if iszero(n) { break } let t := mload(add(b, n)) mstore8(add(a, n), mload(add(b, o))) mstore8(add(a, o), t) } } } } } }
// 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) library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `length` of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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) // Update the free memory pointer to allocate. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str 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)`. // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, 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)); } /// @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) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @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` 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))) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // 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 { // Store the function selector of `HexLengthInsufficient()`. mstore(0x00, 0x2194895a) // Revert with (offset, size). revert(0x1c, 0x04) } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @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) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write 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) // Write 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)) // Write 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)) // Write 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) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) 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 } } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @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) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write 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)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) 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) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write 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. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) 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) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, all indices of the following operations // are byte (ASCII) offsets, not UTF character offsets. /// @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 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. // Allocate the memory. mstore(0x40, add(result, add(resultLength, 0x20))) } } } /// @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) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 0x3f), w))) } } } /// @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) // Zeroize the slot after the string. mstore(last, 0) // Stores the length. mstore(result, totalLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 0x1f), w)) } } /// @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 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`. For short strings up to 32 bytes. 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 x := and(b, add(not(b), 1)) let r := or(shl(8, iszero(b)), 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)))) result := gt(eq(mload(a), sub(32, shr(3, r))), shr(r, xor(b, 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 behaviour is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. result := mload(0x40) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(0x40, add(result, 0x40)) // Zeroize the length slot. mstore(result, 0) // Store the length and bytes. mstore(add(result, 0x1f), packed) // Right pad with zeroes. mstore(add(add(result, 0x20), mload(result)), 0) } } /// @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( // Load the length and the bytes of `a` and `b`. or( 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 behaviour is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. resultA := mload(0x40) 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 retSize := 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, retSize), 0) // Store the return offset. mstore(retStart, 0x20) // End the transaction, returning the string. return(retStart, retSize) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library to encode strings in Base64. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol) /// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <[email protected]>. library Base64 { /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// See: https://datatracker.ietf.org/doc/html/rfc4648 /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'. /// @param noPadding Whether to strip away the padding. function encode(bytes memory data, bool fileSafe, bool noPadding) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { // Multiply by 4/3 rounded up. // The `shl(2, ...)` is equivalent to multiplying by 4. let encodedLength := shl(2, div(add(dataLength, 2), 3)) // Set `result` to point to the start of the free memory. result := mload(0x40) // Store the table into the scratch space. // Offsetted by -1 byte so that the `mload` will load the character. // We will rewrite the free memory pointer at `0x40` later with // the allocated size. // The magic constant 0x0670 will turn "-_" into "+/". mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") mstore(0x3f, xor("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0670))) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, encodedLength) // Run over the input, 3 bytes at a time. for {} 1 {} { data := add(data, 3) // Advance 3 bytes. let input := mload(data) // Write 4 bytes. Optimized for fewer stack operations. mstore8(0, mload(and(shr(18, input), 0x3F))) mstore8(1, mload(and(shr(12, input), 0x3F))) mstore8(2, mload(and(shr(6, input), 0x3F))) mstore8(3, mload(and(input, 0x3F))) mstore(ptr, mload(0x00)) ptr := add(ptr, 4) // Advance 4 bytes. if iszero(lt(ptr, end)) { break } } mstore(0x40, add(end, 0x20)) // Allocate the memory. // Equivalent to `o = [0, 2, 1][dataLength % 3]`. let o := div(2, mod(dataLength, 3)) // Offset `ptr` and pad with '='. We can simply write over the end. mstore(sub(ptr, o), shl(240, 0x3d3d)) // Set `o` to zero if there is padding. o := mul(iszero(iszero(noPadding)), o) mstore(sub(ptr, o), 0) // Zeroize the slot after the string. mstore(result, sub(encodedLength, o)) // Store the length. } } } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, false, false)`. function encode(bytes memory data) internal pure returns (string memory result) { result = encode(data, false, false); } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, fileSafe, false)`. function encode(bytes memory data, bool fileSafe) internal pure returns (string memory result) { result = encode(data, fileSafe, false); } /// @dev Decodes base64 encoded `data`. /// /// Supports: /// - RFC 4648 (both standard and file-safe mode). /// - RFC 3501 (63: ','). /// /// Does not support: /// - Line breaks. /// /// Note: For performance reasons, /// this function will NOT revert on invalid `data` inputs. /// Outputs for invalid inputs will simply be undefined behaviour. /// It is the user's responsibility to ensure that the `data` /// is a valid base64 encoded string. function decode(string memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { let decodedLength := mul(shr(2, dataLength), 3) for {} 1 {} { // If padded. if iszero(and(dataLength, 3)) { let t := xor(mload(add(data, dataLength)), 0x3d3d) // forgefmt: disable-next-item decodedLength := sub( decodedLength, add(iszero(byte(30, t)), iszero(byte(31, t))) ) break } // If non-padded. decodedLength := add(decodedLength, sub(and(dataLength, 3), 1)) break } result := mload(0x40) // Write the length of the bytes. mstore(result, decodedLength) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, decodedLength) // Load the table into the scratch space. // Constants are optimized for smaller bytecode with zero gas overhead. // `m` also doubles as the mask of the upper 6 bits. let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc mstore(0x5b, m) mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064) mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4) for {} 1 {} { // Read 4 bytes. data := add(data, 4) let input := mload(data) // Write 3 bytes. // forgefmt: disable-next-item mstore(ptr, or( and(m, mload(byte(28, input))), shr(6, or( and(m, mload(byte(29, input))), shr(6, or( and(m, mload(byte(30, input))), shr(6, mload(byte(31, input))) )) )) )) ptr := add(ptr, 3) if iszero(lt(ptr, end)) { break } } mstore(0x40, add(end, 0x20)) // Allocate the memory. mstore(end, 0) // Zeroize the slot after the bytes. mstore(0x60, 0) // Restore the zero slot. } } } }
{ "optimizer": { "enabled": false, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"initialOwner","type":"address"},{"indexed":false,"internalType":"string","name":"contentURI","type":"string"}],"name":"ethscriptions_protocol_CreateEthscription","type":"event"},{"inputs":[],"name":"createEthscription","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"esip3StartBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintEndBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b506114b7806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806318160ddd146100515780632ce666a51461006f5780634ffe64431461008d57806352b4b6a014610097575b600080fd5b6100596100b5565b60405161006691906105da565b60405180910390f35b6100776100bb565b60405161008491906105da565b60405180910390f35b6100956100d0565b005b61009f6102dd565b6040516100ac91906105da565b60405180910390f35b60005481565b611c20630114a4506100cd9190610624565b81565b630114a450431015610117576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161010e906106b5565b60405180910390fd5b611c20630114a4506101299190610624565b43111561016b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016290610721565b60405180910390fd5b6000806000815461017b90610741565b919050819055905060006040518060200160405280833373ffffffffffffffffffffffffffffffffffffffff166101b29190610624565b815250905060006040518061010001604052806101d96064856102e590919063ffffffff16565b81526020016101f26064856102e590919063ffffffff16565b815260200161020b6064856102e590919063ffffffff16565b815260200184815260200161021f84610310565b815260200161022d84610310565b815260200161023b84610310565b815260200161024984610310565b8152509050600061025a82846103a0565b905060006102678261045e565b6040516020016102779190610846565b60405160208183030381529060405290503373ffffffffffffffffffffffffffffffffffffffff167f665fba0baf3dc33e9943340197893ac16f56482c2defb8de60f944987fee451c826040516102ce91906108b2565b60405180910390a25050505050565b630114a45081565b60005b6001156103055760208320905080835281826000030681106102e8575b818106905092915050565b6060600061032860ff846102e590919063ffffffff16565b9050600061034060ff856102e590919063ffffffff16565b9050600061035860ff866102e590919063ffffffff16565b905061036383610473565b61036c83610473565b61037583610473565b604051602001610387939291906109b8565b6040516020818303038152906040529350505050919050565b606060006103b86064846102e590919063ffffffff16565b905060006103d06064856102e590919063ffffffff16565b905084608001518560c001516103e584610473565b6103ee84610473565b6103fb8960000151610473565b6104088a60200151610473565b6104158b60400151610473565b8b60a001518c60e0015161042c8e60600151610473565b6040516020016104459a999897969594939291906112d7565b6040516020818303038152906040529250505092915050565b606061046c826000806104c4565b9050919050565b60606080604051019050602081016040526000815280600019835b6001156104af578184019350600a81066030018453600a810490508061048e575b50828203602084039350808452505050919050565b6060835180156105b9576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f52602083018181015b60011561058a576003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f8116516003536000518352600483019250818310610584575061058a565b50610534565b6020810160405260038406600204613d3d60f01b81840352808715150290506000818403528084038652505050505b509392505050565b6000819050919050565b6105d4816105c1565b82525050565b60006020820190506105ef60008301846105cb565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061062f826105c1565b915061063a836105c1565b9250828201905080821115610652576106516105f5565b5b92915050565b600082825260208201905092915050565b7f4e6f742079657420737461727465640000000000000000000000000000000000600082015250565b600061069f600f83610658565b91506106aa82610669565b602082019050919050565b600060208201905081810360008301526106ce81610692565b9050919050565b7f49742773206f7665720000000000000000000000000000000000000000000000600082015250565b600061070b600983610658565b9150610716826106d5565b602082019050919050565b6000602082019050818103600083015261073a816106fe565b9050919050565b600061074c826105c1565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361077e5761077d6105f5565b5b600182019050919050565b600081905092915050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000600082015250565b60006107ca601a83610789565b91506107d582610794565b601a82019050919050565b600081519050919050565b60005b838110156108095780820151818401526020810190506107ee565b60008484015250505050565b6000610820826107e0565b61082a8185610789565b935061083a8185602086016107eb565b80840191505092915050565b6000610851826107bd565b915061085d8284610815565b915081905092915050565b6000601f19601f8301169050919050565b6000610884826107e0565b61088e8185610658565b935061089e8185602086016107eb565b6108a781610868565b840191505092915050565b600060208201905081810360008301526108cc8184610879565b905092915050565b7f7267622800000000000000000000000000000000000000000000000000000000600082015250565b600061090a600483610789565b9150610915826108d4565b600482019050919050565b7f2c00000000000000000000000000000000000000000000000000000000000000600082015250565b6000610956600183610789565b915061096182610920565b600182019050919050565b7f2900000000000000000000000000000000000000000000000000000000000000600082015250565b60006109a2600183610789565b91506109ad8261096c565b600182019050919050565b60006109c3826108fd565b91506109cf8286610815565b91506109da82610949565b91506109e68285610815565b91506109f182610949565b91506109fd8284610815565b9150610a0882610995565b9150819050949350505050565b7f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060008201527f30302f737667222076657273696f6e3d22312e3222206865696768743d22313260208201527f3030222077696474683d2231323030222076696577626f783d2230203020313260408201527f30302031323030223e0000000000000000000000000000000000000000000000606082015250565b6000610abd606983610789565b9150610ac882610a15565b606982019050919050565b7f3c646566733e0000000000000000000000000000000000000000000000000000600082015250565b6000610b09600683610789565b9150610b1482610ad3565b600682019050919050565b7f3c6c696e6561724772616469656e742069643d226772616431222078313d223060008201527f25222079313d223025222078323d2231303025222079323d223025223e000000602082015250565b6000610b7b603d83610789565b9150610b8682610b1f565b603d82019050919050565b7f3c73746f70206f66667365743d22302522207374796c653d2273746f702d636f60008201527f6c6f723a726762283235352c3235352c30293b73746f702d6f7061636974793a60208201527f3122202f3e000000000000000000000000000000000000000000000000000000604082015250565b6000610c13604583610789565b9150610c1e82610b91565b604582019050919050565b7f3c73746f70206f66667365743d223130302522207374796c653d2273746f702d60008201527f636f6c6f723a0000000000000000000000000000000000000000000000000000602082015250565b6000610c85602683610789565b9150610c9082610c29565b602682019050919050565b7f3b73746f702d6f7061636974793a3122202f3e00000000000000000000000000600082015250565b6000610cd1601383610789565b9150610cdc82610c9b565b601382019050919050565b7f3c2f6c696e6561724772616469656e743e000000000000000000000000000000600082015250565b6000610d1d601183610789565b9150610d2882610ce7565b601182019050919050565b7f3c6c696e6561724772616469656e742069643d2267726164222078313d22302560008201527f222079313d223025222078323d2231303025222079323d223025223e00000000602082015250565b6000610d8f603c83610789565b9150610d9a82610d33565b603c82019050919050565b7f3c2f646566733e00000000000000000000000000000000000000000000000000600082015250565b6000610ddb600783610789565b9150610de682610da5565b600782019050919050565b7f3c726563742077696474683d223130302522206865696768743d22313030252260008201527f2066696c6c3d2275726c2823677261642922202f3e0000000000000000000000602082015250565b6000610e4d603583610789565b9150610e5882610df1565b603582019050919050565b7f3c636972636c652063783d220000000000000000000000000000000000000000600082015250565b6000610e99600c83610789565b9150610ea482610e63565b600c82019050919050565b7f25222063793d2200000000000000000000000000000000000000000000000000600082015250565b6000610ee5600783610789565b9150610ef082610eaf565b600782019050919050565b7f252220723d220000000000000000000000000000000000000000000000000000600082015250565b6000610f31600683610789565b9150610f3c82610efb565b600682019050919050565b7f25222066696c6c3d2275726c282367726164312922207374726f6b653d22626c60008201527f61636b22207374726f6b652d77696474683d2232222f3e000000000000000000602082015250565b6000610fa3603783610789565b9150610fae82610f47565b603782019050919050565b7f3c7265637420783d2236302220793d223630222072783d223135222072793d2260008201527f3135222077696474683d22000000000000000000000000000000000000000000602082015250565b6000611015602b83610789565b915061102082610fb9565b602b82019050919050565b7f2522206865696768743d22000000000000000000000000000000000000000000600082015250565b6000611061600b83610789565b915061106c8261102b565b600b82019050919050565b7f25222066696c6c3d220000000000000000000000000000000000000000000000600082015250565b60006110ad600983610789565b91506110b882611077565b600982019050919050565b7f22207374726f6b653d22626c61636b22207374726f6b652d77696474683d223260008201527f22202f3e00000000000000000000000000000000000000000000000000000000602082015250565b600061111f602483610789565b915061112a826110c3565b602482019050919050565b7f3c746578742066696c6c3d220000000000000000000000000000000000000000600082015250565b600061116b600c83610789565b915061117682611135565b600c82019050919050565b7f2220783d22313137302220793d22313137302220666f6e742d73697a653d223260008201527f3030252220746578742d616e63686f723d22656e642220666f6e742d66616d6960208201527f6c793d2268656c766574696361206e6575652c2068656c7665746963612c206160408201527f7269616c2c2073616e2d7365726966223e000000000000000000000000000000606082015250565b6000611229607183610789565b915061123482611181565b607182019050919050565b7f455349502d332057656c636f6d6520504f415020230000000000000000000000600082015250565b6000611275601583610789565b91506112808261123f565b601582019050919050565b7f3c2f746578743e3c2f7376673e00000000000000000000000000000000000000600082015250565b60006112c1600d83610789565b91506112cc8261128b565b600d82019050919050565b60006112e282610ab0565b91506112ed82610afc565b91506112f882610b6e565b915061130382610c06565b915061130e82610c78565b915061131a828d610815565b915061132582610cc4565b915061133082610d10565b915061133b82610d82565b915061134682610c06565b915061135182610c78565b915061135d828c610815565b915061136882610cc4565b915061137382610d10565b915061137e82610dce565b915061138982610e40565b915061139482610e8c565b91506113a0828b610815565b91506113ab82610ed8565b91506113b7828a610815565b91506113c282610f24565b91506113ce8289610815565b91506113d982610f96565b91506113e482611008565b91506113f08288610815565b91506113fb82611054565b91506114078287610815565b9150611412826110a0565b915061141e8286610815565b915061142982611112565b91506114348261115e565b91506114408285610815565b915061144b8261121c565b915061145682611268565b91506114628284610815565b915061146d826112b4565b91508190509b9a505050505050505050505056fea2646970667358221220fcf7f26b999b3c3793ea2bd5c41d6748fc662d1b7ccd6efa42d58d52ef69bcc364736f6c63430008120033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061004c5760003560e01c806318160ddd146100515780632ce666a51461006f5780634ffe64431461008d57806352b4b6a014610097575b600080fd5b6100596100b5565b60405161006691906105da565b60405180910390f35b6100776100bb565b60405161008491906105da565b60405180910390f35b6100956100d0565b005b61009f6102dd565b6040516100ac91906105da565b60405180910390f35b60005481565b611c20630114a4506100cd9190610624565b81565b630114a450431015610117576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161010e906106b5565b60405180910390fd5b611c20630114a4506101299190610624565b43111561016b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016290610721565b60405180910390fd5b6000806000815461017b90610741565b919050819055905060006040518060200160405280833373ffffffffffffffffffffffffffffffffffffffff166101b29190610624565b815250905060006040518061010001604052806101d96064856102e590919063ffffffff16565b81526020016101f26064856102e590919063ffffffff16565b815260200161020b6064856102e590919063ffffffff16565b815260200184815260200161021f84610310565b815260200161022d84610310565b815260200161023b84610310565b815260200161024984610310565b8152509050600061025a82846103a0565b905060006102678261045e565b6040516020016102779190610846565b60405160208183030381529060405290503373ffffffffffffffffffffffffffffffffffffffff167f665fba0baf3dc33e9943340197893ac16f56482c2defb8de60f944987fee451c826040516102ce91906108b2565b60405180910390a25050505050565b630114a45081565b60005b6001156103055760208320905080835281826000030681106102e8575b818106905092915050565b6060600061032860ff846102e590919063ffffffff16565b9050600061034060ff856102e590919063ffffffff16565b9050600061035860ff866102e590919063ffffffff16565b905061036383610473565b61036c83610473565b61037583610473565b604051602001610387939291906109b8565b6040516020818303038152906040529350505050919050565b606060006103b86064846102e590919063ffffffff16565b905060006103d06064856102e590919063ffffffff16565b905084608001518560c001516103e584610473565b6103ee84610473565b6103fb8960000151610473565b6104088a60200151610473565b6104158b60400151610473565b8b60a001518c60e0015161042c8e60600151610473565b6040516020016104459a999897969594939291906112d7565b6040516020818303038152906040529250505092915050565b606061046c826000806104c4565b9050919050565b60606080604051019050602081016040526000815280600019835b6001156104af578184019350600a81066030018453600a810490508061048e575b50828203602084039350808452505050919050565b6060835180156105b9576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f52602083018181015b60011561058a576003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f8116516003536000518352600483019250818310610584575061058a565b50610534565b6020810160405260038406600204613d3d60f01b81840352808715150290506000818403528084038652505050505b509392505050565b6000819050919050565b6105d4816105c1565b82525050565b60006020820190506105ef60008301846105cb565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061062f826105c1565b915061063a836105c1565b9250828201905080821115610652576106516105f5565b5b92915050565b600082825260208201905092915050565b7f4e6f742079657420737461727465640000000000000000000000000000000000600082015250565b600061069f600f83610658565b91506106aa82610669565b602082019050919050565b600060208201905081810360008301526106ce81610692565b9050919050565b7f49742773206f7665720000000000000000000000000000000000000000000000600082015250565b600061070b600983610658565b9150610716826106d5565b602082019050919050565b6000602082019050818103600083015261073a816106fe565b9050919050565b600061074c826105c1565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361077e5761077d6105f5565b5b600182019050919050565b600081905092915050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000600082015250565b60006107ca601a83610789565b91506107d582610794565b601a82019050919050565b600081519050919050565b60005b838110156108095780820151818401526020810190506107ee565b60008484015250505050565b6000610820826107e0565b61082a8185610789565b935061083a8185602086016107eb565b80840191505092915050565b6000610851826107bd565b915061085d8284610815565b915081905092915050565b6000601f19601f8301169050919050565b6000610884826107e0565b61088e8185610658565b935061089e8185602086016107eb565b6108a781610868565b840191505092915050565b600060208201905081810360008301526108cc8184610879565b905092915050565b7f7267622800000000000000000000000000000000000000000000000000000000600082015250565b600061090a600483610789565b9150610915826108d4565b600482019050919050565b7f2c00000000000000000000000000000000000000000000000000000000000000600082015250565b6000610956600183610789565b915061096182610920565b600182019050919050565b7f2900000000000000000000000000000000000000000000000000000000000000600082015250565b60006109a2600183610789565b91506109ad8261096c565b600182019050919050565b60006109c3826108fd565b91506109cf8286610815565b91506109da82610949565b91506109e68285610815565b91506109f182610949565b91506109fd8284610815565b9150610a0882610995565b9150819050949350505050565b7f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060008201527f30302f737667222076657273696f6e3d22312e3222206865696768743d22313260208201527f3030222077696474683d2231323030222076696577626f783d2230203020313260408201527f30302031323030223e0000000000000000000000000000000000000000000000606082015250565b6000610abd606983610789565b9150610ac882610a15565b606982019050919050565b7f3c646566733e0000000000000000000000000000000000000000000000000000600082015250565b6000610b09600683610789565b9150610b1482610ad3565b600682019050919050565b7f3c6c696e6561724772616469656e742069643d226772616431222078313d223060008201527f25222079313d223025222078323d2231303025222079323d223025223e000000602082015250565b6000610b7b603d83610789565b9150610b8682610b1f565b603d82019050919050565b7f3c73746f70206f66667365743d22302522207374796c653d2273746f702d636f60008201527f6c6f723a726762283235352c3235352c30293b73746f702d6f7061636974793a60208201527f3122202f3e000000000000000000000000000000000000000000000000000000604082015250565b6000610c13604583610789565b9150610c1e82610b91565b604582019050919050565b7f3c73746f70206f66667365743d223130302522207374796c653d2273746f702d60008201527f636f6c6f723a0000000000000000000000000000000000000000000000000000602082015250565b6000610c85602683610789565b9150610c9082610c29565b602682019050919050565b7f3b73746f702d6f7061636974793a3122202f3e00000000000000000000000000600082015250565b6000610cd1601383610789565b9150610cdc82610c9b565b601382019050919050565b7f3c2f6c696e6561724772616469656e743e000000000000000000000000000000600082015250565b6000610d1d601183610789565b9150610d2882610ce7565b601182019050919050565b7f3c6c696e6561724772616469656e742069643d2267726164222078313d22302560008201527f222079313d223025222078323d2231303025222079323d223025223e00000000602082015250565b6000610d8f603c83610789565b9150610d9a82610d33565b603c82019050919050565b7f3c2f646566733e00000000000000000000000000000000000000000000000000600082015250565b6000610ddb600783610789565b9150610de682610da5565b600782019050919050565b7f3c726563742077696474683d223130302522206865696768743d22313030252260008201527f2066696c6c3d2275726c2823677261642922202f3e0000000000000000000000602082015250565b6000610e4d603583610789565b9150610e5882610df1565b603582019050919050565b7f3c636972636c652063783d220000000000000000000000000000000000000000600082015250565b6000610e99600c83610789565b9150610ea482610e63565b600c82019050919050565b7f25222063793d2200000000000000000000000000000000000000000000000000600082015250565b6000610ee5600783610789565b9150610ef082610eaf565b600782019050919050565b7f252220723d220000000000000000000000000000000000000000000000000000600082015250565b6000610f31600683610789565b9150610f3c82610efb565b600682019050919050565b7f25222066696c6c3d2275726c282367726164312922207374726f6b653d22626c60008201527f61636b22207374726f6b652d77696474683d2232222f3e000000000000000000602082015250565b6000610fa3603783610789565b9150610fae82610f47565b603782019050919050565b7f3c7265637420783d2236302220793d223630222072783d223135222072793d2260008201527f3135222077696474683d22000000000000000000000000000000000000000000602082015250565b6000611015602b83610789565b915061102082610fb9565b602b82019050919050565b7f2522206865696768743d22000000000000000000000000000000000000000000600082015250565b6000611061600b83610789565b915061106c8261102b565b600b82019050919050565b7f25222066696c6c3d220000000000000000000000000000000000000000000000600082015250565b60006110ad600983610789565b91506110b882611077565b600982019050919050565b7f22207374726f6b653d22626c61636b22207374726f6b652d77696474683d223260008201527f22202f3e00000000000000000000000000000000000000000000000000000000602082015250565b600061111f602483610789565b915061112a826110c3565b602482019050919050565b7f3c746578742066696c6c3d220000000000000000000000000000000000000000600082015250565b600061116b600c83610789565b915061117682611135565b600c82019050919050565b7f2220783d22313137302220793d22313137302220666f6e742d73697a653d223260008201527f3030252220746578742d616e63686f723d22656e642220666f6e742d66616d6960208201527f6c793d2268656c766574696361206e6575652c2068656c7665746963612c206160408201527f7269616c2c2073616e2d7365726966223e000000000000000000000000000000606082015250565b6000611229607183610789565b915061123482611181565b607182019050919050565b7f455349502d332057656c636f6d6520504f415020230000000000000000000000600082015250565b6000611275601583610789565b91506112808261123f565b601582019050919050565b7f3c2f746578743e3c2f7376673e00000000000000000000000000000000000000600082015250565b60006112c1600d83610789565b91506112cc8261128b565b600d82019050919050565b60006112e282610ab0565b91506112ed82610afc565b91506112f882610b6e565b915061130382610c06565b915061130e82610c78565b915061131a828d610815565b915061132582610cc4565b915061133082610d10565b915061133b82610d82565b915061134682610c06565b915061135182610c78565b915061135d828c610815565b915061136882610cc4565b915061137382610d10565b915061137e82610dce565b915061138982610e40565b915061139482610e8c565b91506113a0828b610815565b91506113ab82610ed8565b91506113b7828a610815565b91506113c282610f24565b91506113ce8289610815565b91506113d982610f96565b91506113e482611008565b91506113f08288610815565b91506113fb82611054565b91506114078287610815565b9150611412826110a0565b915061141e8286610815565b915061142982611112565b91506114348261115e565b91506114408285610815565b915061144b8261121c565b915061145682611268565b91506114628284610815565b915061146d826112b4565b91508190509b9a505050505050505050505056fea2646970667358221220fcf7f26b999b3c3793ea2bd5c41d6748fc662d1b7ccd6efa42d58d52ef69bcc364736f6c63430008120033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.