Overview
Max Total Supply
10,000,000,000 ELIZ
Holders
30,796 (0.00%)
Market
Price
$0.00 @ 0.000000 ETH
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 18 Decimals)
Balance
1 ELIZValue
$0.00Loading...
Loading
Loading...
Loading
Loading...
Loading
Contract Name:
MEME404
Compiler Version
v0.8.23+commit.f704f362
Contract Source Code (Solidity)
/**
*Submitted for verification at basescan.org on 2024-08-12
*/
/// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.0 ^0.8.23 ^0.8.4;
// lib/solady/src/utils/FixedPointMathLib.sol
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error ExpOverflow();
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error FactorialOverflow();
/// @dev The operation failed, due to an overflow.
error RPowOverflow();
/// @dev The mantissa is too big to fit.
error MantissaOverflow();
/// @dev The operation failed, due to an multiplication overflow.
error MulWadFailed();
/// @dev The operation failed, due to an multiplication overflow.
error SMulWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error DivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error SDivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error MulDivFailed();
/// @dev The division failed, as the denominator is zero.
error DivFailed();
/// @dev The full precision multiply-divide operation failed, either due
/// to the result being larger than 256 bits, or a division by a zero.
error FullMulDivFailed();
/// @dev The output is undefined, as the input is less-than-or-equal to zero.
error LnWadUndefined();
/// @dev The input outside the acceptable domain.
error OutOfDomain();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The scalar of ETH and most ERC20s.
uint256 internal constant WAD = 1e18;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SIMPLIFIED FIXED POINT OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if mul(y, gt(x, div(not(0), y))) {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function sMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`.
if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) {
mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up.
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if mul(y, gt(x, div(not(0), y))) {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks.
function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function sDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, WAD)
// Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`.
if iszero(and(iszero(iszero(y)), eq(sdiv(z, WAD), x))) {
mstore(0x00, 0x5c43740d) // `SDivWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up.
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks.
function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `x` to the power of `y`.
/// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.
function powWad(int256 x, int256 y) internal pure returns (int256) {
// Using `ln(x)` means `x` must be greater than 0.
return expWad((lnWad(x) * y) / int256(WAD));
}
/// @dev Returns `exp(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
function expWad(int256 x) internal pure returns (int256 r) {
unchecked {
// When the result is less than 0.5 we return zero.
// This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.
if (x <= -41446531673892822313) return r;
/// @solidity memory-safe-assembly
assembly {
// When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as
// an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
if iszero(slt(x, 135305999368893231589)) {
mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.
revert(0x1c, 0x04)
}
}
// `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`
// for more intermediate precision and a binary basis. This base conversion
// is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
x = (x << 78) / 5 ** 18;
// Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
// of two such that exp(x) = exp(x') * 2**k, where k is an integer.
// Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;
x = x - k * 54916777467707473351141471128;
// `k` is in the range `[-61, 195]`.
// Evaluate using a (6, 7)-term rational approximation.
// `p` is made monic, we'll multiply by a scale factor later.
int256 y = x + 1346386616545796478920950773328;
y = ((y * x) >> 96) + 57155421227552351082224309758442;
int256 p = y + x - 94201549194550492254356042504812;
p = ((p * y) >> 96) + 28719021644029726153956944680412240;
p = p * x + (4385272521454847904659076985693276 << 96);
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
int256 q = x - 2855989394907223263936484059900;
q = ((q * x) >> 96) + 50020603652535783019961831881945;
q = ((q * x) >> 96) - 533845033583426703283633433725380;
q = ((q * x) >> 96) + 3604857256930695427073651918091429;
q = ((q * x) >> 96) - 14423608567350463180887372962807573;
q = ((q * x) >> 96) + 26449188498355588339934803723976023;
/// @solidity memory-safe-assembly
assembly {
// Div in assembly because solidity adds a zero check despite the unchecked.
// The q polynomial won't have zeros in the domain as all its roots are complex.
// No scaling is necessary because p is already `2**96` too large.
r := sdiv(p, q)
}
// r should be in the range `(0.09, 0.25) * 2**96`.
// We now need to multiply r by:
// - The scale factor `s ≈ 6.031367120`.
// - The `2**k` factor from the range reduction.
// - The `1e18 / 2**96` factor for base conversion.
// We do this all at once, with an intermediate result in `2**213`
// basis, so the final right shift is always by a positive amount.
r = int256(
(uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)
);
}
}
/// @dev Returns `ln(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
function lnWad(int256 x) internal pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// We want to convert `x` from `10**18` fixed point to `2**96` fixed point.
// We do this by multiplying by `2**96 / 10**18`. But since
// `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here
// and add `ln(2**96 / 10**18)` at the end.
// Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, 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))))
// We place the check here for more optimal stack operations.
if iszero(sgt(x, 0)) {
mstore(0x00, 0x1615e638) // `LnWadUndefined()`.
revert(0x1c, 0x04)
}
// forgefmt: disable-next-item
r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))
// Reduce range of x to (1, 2) * 2**96
// ln(2^k * x) = k * ln(2) + ln(x)
x := shr(159, shl(r, x))
// Evaluate using a (8, 8)-term rational approximation.
// `p` is made monic, we will multiply by a scale factor later.
// forgefmt: disable-next-item
let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir.
sar(96, mul(add(43456485725739037958740375743393,
sar(96, mul(add(24828157081833163892658089445524,
sar(96, mul(add(3273285459638523848632254066296,
x), x))), x))), x)), 11111509109440967052023855526967)
p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857)
p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526)
p := sub(mul(p, x), shl(96, 795164235651350426258249787498))
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
// `q` is monic by convention.
let q := add(5573035233440673466300451813936, x)
q := add(71694874799317883764090561454958, sar(96, mul(x, q)))
q := add(283447036172924575727196451306956, sar(96, mul(x, q)))
q := add(401686690394027663651624208769553, sar(96, mul(x, q)))
q := add(204048457590392012362485061816622, sar(96, mul(x, q)))
q := add(31853899698501571402653359427138, sar(96, mul(x, q)))
q := add(909429971244387300277376558375, sar(96, mul(x, q)))
// `p / q` is in the range `(0, 0.125) * 2**96`.
// Finalization, we need to:
// - Multiply by the scale factor `s = 5.549…`.
// - Add `ln(2**96 / 10**18)`.
// - Add `k * ln(2)`.
// - Multiply by `10**18 / 2**96 = 5**18 >> 78`.
// The q polynomial is known not to have zeros in the domain.
// No scaling required because p is already `2**96` too large.
p := sdiv(p, q)
// Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.
p := mul(1677202110996718588342820967067443963516166, p)
// Add `ln(2) * k * 5**18 * 2**192`.
// forgefmt: disable-next-item
p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p)
// Add `ln(2**96 / 10**18) * 5**18 * 2**192`.
p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p)
// Base conversion: mul `2**18 / 2**192`.
r := sar(174, p)
}
}
/// @dev Returns `W_0(x)`, denominated in `WAD`.
/// See: https://en.wikipedia.org/wiki/Lambert_W_function
/// a.k.a. Product log function. This is an approximation of the principal branch.
function lambertW0Wad(int256 x) internal pure returns (int256 w) {
// forgefmt: disable-next-item
unchecked {
if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`.
int256 wad = int256(WAD);
int256 p = x;
uint256 c; // Whether we need to avoid catastrophic cancellation.
uint256 i = 4; // Number of iterations.
if (w <= 0x1ffffffffffff) {
if (-0x4000000000000 <= w) {
i = 1; // Inputs near zero only take one step to converge.
} else if (w <= -0x3ffffffffffffff) {
i = 32; // Inputs near `-1/e` take very long to converge.
}
} else if (w >> 63 == 0) {
/// @solidity memory-safe-assembly
assembly {
// Inline log2 for more performance, since the range is small.
let v := shr(49, w)
let l := shl(3, lt(0xff, v))
l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000)), 49)
w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13))
c := gt(l, 60)
i := add(2, add(gt(l, 53), c))
}
} else {
int256 ll = lnWad(w = lnWad(w));
/// @solidity memory-safe-assembly
assembly {
// `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`.
w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll))
i := add(3, iszero(shr(68, x)))
c := iszero(shr(143, x))
}
if (c == 0) {
do { // If `x` is big, use Newton's so that intermediate values won't overflow.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := mul(w, div(e, wad))
w := sub(w, sdiv(sub(t, x), div(add(e, t), wad)))
}
if (p <= w) break;
p = w;
} while (--i != 0);
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
return w;
}
}
do { // Otherwise, use Halley's for faster convergence.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := add(w, wad)
let s := sub(mul(w, e), mul(x, wad))
w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t)))))
}
if (p <= w) break;
p = w;
} while (--i != c);
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
// For certain ranges of `x`, we'll use the quadratic-rate recursive formula of
// R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation.
if (c != 0) {
int256 t = w | 1;
/// @solidity memory-safe-assembly
assembly {
x := sdiv(mul(x, wad), t)
}
x = (t * (wad + lnWad(x)));
/// @solidity memory-safe-assembly
assembly {
w := sdiv(x, add(wad, t))
}
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GENERAL NUMBER UTILITIES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
// 512-bit multiply `[p1 p0] = x * y`.
// Compute the product mod `2**256` and mod `2**256 - 1`
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that `product = p1 * 2**256 + p0`.
// Least significant 256 bits of the product.
result := mul(x, y) // Temporarily use `result` as `p0` to save gas.
let mm := mulmod(x, y, not(0))
// Most significant 256 bits of the product.
let p1 := sub(mm, add(result, lt(mm, result)))
// Handle non-overflow cases, 256 by 256 division.
if iszero(p1) {
if iszero(d) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
result := div(result, d)
break
}
// Make sure the result is less than `2**256`. Also prevents `d == 0`.
if iszero(gt(d, p1)) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
/*------------------- 512 by 256 division --------------------*/
// Make division exact by subtracting the remainder from `[p1 p0]`.
// Compute remainder using mulmod.
let r := mulmod(x, y, d)
// `t` is the least significant bit of `d`.
// Always greater or equal to 1.
let t := and(d, sub(0, d))
// Divide `d` by `t`, which is a power of two.
d := div(d, t)
// Invert `d mod 2**256`
// Now that `d` is an odd number, it has an inverse
// modulo `2**256` such that `d * inv = 1 mod 2**256`.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, `d * inv = 1 mod 2**4`.
let inv := xor(2, mul(3, d))
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
result :=
mul(
// Divide [p1 p0] by the factors of two.
// Shift in bits from `p1` into `p0`. For this we need
// to flip `t` such that it is `2**256 / t`.
or(
mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)),
div(sub(result, r), t)
),
// inverse mod 2**256
mul(inv, sub(2, mul(d, inv)))
)
break
}
}
}
/// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Uniswap-v3-core under MIT license:
/// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol
function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
result = fullMulDiv(x, y, d);
/// @solidity memory-safe-assembly
assembly {
if mulmod(x, y, d) {
result := add(result, 1)
if iszero(result) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Returns `floor(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, y), d)
}
}
/// @dev Returns `ceil(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d))
}
}
/// @dev Returns `ceil(x / d)`.
/// Reverts if `d` is zero.
function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
if iszero(d) {
mstore(0x00, 0x65244e4e) // `DivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(x, d))), div(x, d))
}
}
/// @dev Returns `max(0, x - y)`.
function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
/// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.
/// Reverts if the computation overflows.
function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.
if x {
z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`
let half := shr(1, b) // Divide `b` by 2.
// Divide `y` by 2 every iteration.
for { y := shr(1, y) } y { y := shr(1, y) } {
let xx := mul(x, x) // Store x squared.
let xxRound := add(xx, half) // Round to the nearest number.
// Revert if `xx + half` overflowed, or if `x ** 2` overflows.
if or(lt(xxRound, xx), shr(128, x)) {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
x := div(xxRound, b) // Set `x` to scaled `xxRound`.
// If `y` is odd:
if and(y, 1) {
let zx := mul(z, x) // Compute `z * x`.
let zxRound := add(zx, half) // Round to the nearest number.
// If `z * x` overflowed or `zx + half` overflowed:
if or(xor(div(zx, x), z), lt(zxRound, zx)) {
// Revert if `x` is non-zero.
if iszero(iszero(x)) {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
}
z := div(zxRound, b) // Return properly scaled `zxRound`.
}
}
}
}
}
/// @dev Returns the square root of `x`.
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
// but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffffff, shr(r, x))))
z := shl(shr(1, r), z)
// Goal was to get `z*z*y` within a small factor of `x`. More iterations could
// get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
// We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
// That's not possible if `x < 256` but we can just verify those cases exhaustively.
// Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
// Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
// Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.
// For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
// is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
// with largest error when `s = 1` and when `s = 256` or `1/256`.
// Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
// Then we can estimate `sqrt(y)` using
// `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.
// There is no overflow risk here since `y < 2**136` after the first branch above.
z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If `x+1` is a perfect square, the Babylonian method cycles between
// `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
z := sub(z, lt(div(x, z), z))
}
}
/// @dev Returns the cube root of `x`.
/// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:
/// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy
function cbrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, 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))))
z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := sub(z, lt(div(x, mul(z, z)), z))
}
}
/// @dev Returns the square root of `x`, denominated in `WAD`.
function sqrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
z = 10 ** 9;
if (x <= type(uint256).max / 10 ** 36 - 1) {
x *= 10 ** 18;
z = 1;
}
z *= sqrt(x);
}
}
/// @dev Returns the cube root of `x`, denominated in `WAD`.
function cbrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
z = 10 ** 12;
if (x <= (type(uint256).max / 10 ** 36) * 10 ** 18 - 1) {
if (x >= type(uint256).max / 10 ** 36) {
x *= 10 ** 18;
z = 10 ** 6;
} else {
x *= 10 ** 36;
z = 1;
}
}
z *= cbrt(x);
}
}
/// @dev Returns the factorial of `x`.
function factorial(uint256 x) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(x, 58)) {
mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.
revert(0x1c, 0x04)
}
for { result := 1 } x { x := sub(x, 1) } { result := mul(result, x) }
}
}
/// @dev Returns the log2 of `x`.
/// Equivalent to computing the index of the most significant bit (MSB) of `x`.
/// Returns 0 if `x` is zero.
function log2(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, 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
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Returns the log2 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log2Up(uint256 x) internal pure returns (uint256 r) {
r = log2(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(r, 1), x))
}
}
/// @dev Returns the log10 of `x`.
/// Returns 0 if `x` is zero.
function log10(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(x, 100000000000000000000000000000000000000)) {
x := div(x, 100000000000000000000000000000000000000)
r := 38
}
if iszero(lt(x, 100000000000000000000)) {
x := div(x, 100000000000000000000)
r := add(r, 20)
}
if iszero(lt(x, 10000000000)) {
x := div(x, 10000000000)
r := add(r, 10)
}
if iszero(lt(x, 100000)) {
x := div(x, 100000)
r := add(r, 5)
}
r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))
}
}
/// @dev Returns the log10 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log10Up(uint256 x) internal pure returns (uint256 r) {
r = log10(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(exp(10, r), x))
}
}
/// @dev Returns the log256 of `x`.
/// Returns 0 if `x` is zero.
function log256(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, 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(shr(3, r), lt(0xff, shr(r, x)))
}
}
/// @dev Returns the log256 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log256Up(uint256 x) internal pure returns (uint256 r) {
r = log256(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(shl(3, r), 1), x))
}
}
/// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`.
/// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent).
function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) {
/// @solidity memory-safe-assembly
assembly {
mantissa := x
if mantissa {
if iszero(mod(mantissa, 1000000000000000000000000000000000)) {
mantissa := div(mantissa, 1000000000000000000000000000000000)
exponent := 33
}
if iszero(mod(mantissa, 10000000000000000000)) {
mantissa := div(mantissa, 10000000000000000000)
exponent := add(exponent, 19)
}
if iszero(mod(mantissa, 1000000000000)) {
mantissa := div(mantissa, 1000000000000)
exponent := add(exponent, 12)
}
if iszero(mod(mantissa, 1000000)) {
mantissa := div(mantissa, 1000000)
exponent := add(exponent, 6)
}
if iszero(mod(mantissa, 10000)) {
mantissa := div(mantissa, 10000)
exponent := add(exponent, 4)
}
if iszero(mod(mantissa, 100)) {
mantissa := div(mantissa, 100)
exponent := add(exponent, 2)
}
if iszero(mod(mantissa, 10)) {
mantissa := div(mantissa, 10)
exponent := add(exponent, 1)
}
}
}
}
/// @dev Convenience function for packing `x` into a smaller number using `sci`.
/// The `mantissa` will be in bits [7..255] (the upper 249 bits).
/// The `exponent` will be in bits [0..6] (the lower 7 bits).
/// Use `SafeCastLib` to safely ensure that the `packed` number is small
/// enough to fit in the desired unsigned integer type:
/// ```
/// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether));
/// ```
function packSci(uint256 x) internal pure returns (uint256 packed) {
(x, packed) = sci(x); // Reuse for `mantissa` and `exponent`.
/// @solidity memory-safe-assembly
assembly {
if shr(249, x) {
mstore(0x00, 0xce30380c) // `MantissaOverflow()`.
revert(0x1c, 0x04)
}
packed := or(shl(7, x), packed)
}
}
/// @dev Convenience function for unpacking a packed number from `packSci`.
function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) {
unchecked {
unpacked = (packed >> 7) * 10 ** (packed & 0x7f);
}
}
/// @dev Returns the average of `x` and `y`.
function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = (x & y) + ((x ^ y) >> 1);
}
}
/// @dev Returns the average of `x` and `y`.
function avg(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = (x >> 1) + (y >> 1) + (x & y & 1);
}
}
/// @dev Returns the absolute value of `x`.
function abs(int256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(sub(0, shr(255, x)), add(sub(0, shr(255, x)), x))
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(int256 x, int256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(mul(xor(sub(y, x), sub(x, y)), sgt(x, y)), sub(y, x))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), slt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), gt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), sgt(y, x)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(uint256 x, uint256 minValue, uint256 maxValue)
internal
pure
returns (uint256 z)
{
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), gt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))
}
}
/// @dev Returns greatest common divisor of `x` and `y`.
function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
for { z := x } y {} {
let t := y
y := mod(z, y)
z := t
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RAW NUMBER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(x, y)
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mod(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := smod(x, y)
}
}
/// @dev Returns `(x + y) % d`, return 0 if `d` if zero.
function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := addmod(x, y, d)
}
}
/// @dev Returns `(x * y) % d`, return 0 if `d` if zero.
function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mulmod(x, y, d)
}
}
}
// lib/solmate/src/tokens/ERC1155.sol
/// @notice Minimalist and gas efficient standard ERC1155 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)
abstract contract ERC1155 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event TransferSingle(
address indexed operator,
address indexed from,
address indexed to,
uint256 id,
uint256 amount
);
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] amounts
);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
event URI(string value, uint256 indexed id);
/*//////////////////////////////////////////////////////////////
ERC1155 STORAGE
//////////////////////////////////////////////////////////////*/
mapping(address => mapping(uint256 => uint256)) public balanceOf;
mapping(address => mapping(address => bool)) public isApprovedForAll;
/*//////////////////////////////////////////////////////////////
METADATA LOGIC
//////////////////////////////////////////////////////////////*/
function uri(uint256 id) public view virtual returns (string memory);
/*//////////////////////////////////////////////////////////////
ERC1155 LOGIC
//////////////////////////////////////////////////////////////*/
function setApprovalForAll(address operator, bool approved) public virtual {
isApprovedForAll[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) public virtual {
require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");
balanceOf[from][id] -= amount;
balanceOf[to][id] += amount;
emit TransferSingle(msg.sender, from, to, id, amount);
require(
to.code.length == 0
? to != address(0)
: ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) ==
ERC1155TokenReceiver.onERC1155Received.selector,
"UNSAFE_RECIPIENT"
);
}
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) public virtual {
require(ids.length == amounts.length, "LENGTH_MISMATCH");
require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");
// Storing these outside the loop saves ~15 gas per iteration.
uint256 id;
uint256 amount;
for (uint256 i = 0; i < ids.length; ) {
id = ids[i];
amount = amounts[i];
balanceOf[from][id] -= amount;
balanceOf[to][id] += amount;
// An array can't have a total length
// larger than the max uint256 value.
unchecked {
++i;
}
}
emit TransferBatch(msg.sender, from, to, ids, amounts);
require(
to.code.length == 0
? to != address(0)
: ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) ==
ERC1155TokenReceiver.onERC1155BatchReceived.selector,
"UNSAFE_RECIPIENT"
);
}
function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
public
view
virtual
returns (uint256[] memory balances)
{
require(owners.length == ids.length, "LENGTH_MISMATCH");
balances = new uint256[](owners.length);
// Unchecked because the only math done is incrementing
// the array index counter which cannot possibly overflow.
unchecked {
for (uint256 i = 0; i < owners.length; ++i) {
balances[i] = balanceOf[owners[i]][ids[i]];
}
}
}
/*//////////////////////////////////////////////////////////////
ERC165 LOGIC
//////////////////////////////////////////////////////////////*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return
interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155
interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
balanceOf[to][id] += amount;
emit TransferSingle(msg.sender, address(0), to, id, amount);
require(
to.code.length == 0
? to != address(0)
: ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) ==
ERC1155TokenReceiver.onERC1155Received.selector,
"UNSAFE_RECIPIENT"
);
}
function _batchMint(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
uint256 idsLength = ids.length; // Saves MLOADs.
require(idsLength == amounts.length, "LENGTH_MISMATCH");
for (uint256 i = 0; i < idsLength; ) {
balanceOf[to][ids[i]] += amounts[i];
// An array can't have a total length
// larger than the max uint256 value.
unchecked {
++i;
}
}
emit TransferBatch(msg.sender, address(0), to, ids, amounts);
require(
to.code.length == 0
? to != address(0)
: ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) ==
ERC1155TokenReceiver.onERC1155BatchReceived.selector,
"UNSAFE_RECIPIENT"
);
}
function _batchBurn(
address from,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
uint256 idsLength = ids.length; // Saves MLOADs.
require(idsLength == amounts.length, "LENGTH_MISMATCH");
for (uint256 i = 0; i < idsLength; ) {
balanceOf[from][ids[i]] -= amounts[i];
// An array can't have a total length
// larger than the max uint256 value.
unchecked {
++i;
}
}
emit TransferBatch(msg.sender, from, address(0), ids, amounts);
}
function _burn(
address from,
uint256 id,
uint256 amount
) internal virtual {
balanceOf[from][id] -= amount;
emit TransferSingle(msg.sender, from, address(0), id, amount);
}
}
/// @notice A generic interface for a contract which properly accepts ERC1155 tokens.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)
abstract contract ERC1155TokenReceiver {
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes calldata
) external virtual returns (bytes4) {
return ERC1155TokenReceiver.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] calldata,
uint256[] calldata,
bytes calldata
) external virtual returns (bytes4) {
return ERC1155TokenReceiver.onERC1155BatchReceived.selector;
}
}
// lib/solmate/src/tokens/ERC20.sol
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}
// lib/solmate/src/tokens/ERC721.sol
/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 indexed id);
event Approval(address indexed owner, address indexed spender, uint256 indexed id);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE/LOGIC
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
function tokenURI(uint256 id) public view virtual returns (string memory);
/*//////////////////////////////////////////////////////////////
ERC721 BALANCE/OWNER STORAGE
//////////////////////////////////////////////////////////////*/
mapping(uint256 => address) internal _ownerOf;
mapping(address => uint256) internal _balanceOf;
function ownerOf(uint256 id) public view virtual returns (address owner) {
require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
}
function balanceOf(address owner) public view virtual returns (uint256) {
require(owner != address(0), "ZERO_ADDRESS");
return _balanceOf[owner];
}
/*//////////////////////////////////////////////////////////////
ERC721 APPROVAL STORAGE
//////////////////////////////////////////////////////////////*/
mapping(uint256 => address) public getApproved;
mapping(address => mapping(address => bool)) public isApprovedForAll;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(string memory _name, string memory _symbol) {
name = _name;
symbol = _symbol;
}
/*//////////////////////////////////////////////////////////////
ERC721 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 id) public virtual {
address owner = _ownerOf[id];
require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");
getApproved[id] = spender;
emit Approval(owner, spender, id);
}
function setApprovalForAll(address operator, bool approved) public virtual {
isApprovedForAll[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function transferFrom(
address from,
address to,
uint256 id
) public virtual {
require(from == _ownerOf[id], "WRONG_FROM");
require(to != address(0), "INVALID_RECIPIENT");
require(
msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
"NOT_AUTHORIZED"
);
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
unchecked {
_balanceOf[from]--;
_balanceOf[to]++;
}
_ownerOf[id] = to;
delete getApproved[id];
emit Transfer(from, to, id);
}
function safeTransferFrom(
address from,
address to,
uint256 id
) public virtual {
transferFrom(from, to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
function safeTransferFrom(
address from,
address to,
uint256 id,
bytes calldata data
) public virtual {
transferFrom(from, to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
/*//////////////////////////////////////////////////////////////
ERC165 LOGIC
//////////////////////////////////////////////////////////////*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return
interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 id) internal virtual {
require(to != address(0), "INVALID_RECIPIENT");
require(_ownerOf[id] == address(0), "ALREADY_MINTED");
// Counter overflow is incredibly unrealistic.
unchecked {
_balanceOf[to]++;
}
_ownerOf[id] = to;
emit Transfer(address(0), to, id);
}
function _burn(uint256 id) internal virtual {
address owner = _ownerOf[id];
require(owner != address(0), "NOT_MINTED");
// Ownership check above ensures no underflow.
unchecked {
_balanceOf[owner]--;
}
delete _ownerOf[id];
delete getApproved[id];
emit Transfer(owner, address(0), id);
}
/*//////////////////////////////////////////////////////////////
INTERNAL SAFE MINT LOGIC
//////////////////////////////////////////////////////////////*/
function _safeMint(address to, uint256 id) internal virtual {
_mint(to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
function _safeMint(
address to,
uint256 id,
bytes memory data
) internal virtual {
_mint(to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
}
/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721TokenReceiver {
function onERC721Received(
address,
address,
uint256,
bytes calldata
) external virtual returns (bytes4) {
return ERC721TokenReceiver.onERC721Received.selector;
}
}
// lib/solmate/src/utils/ReentrancyGuard.sol
/// @notice Gas optimized reentrancy protection for smart contracts.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ReentrancyGuard.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
uint256 private locked = 1;
modifier nonReentrant() virtual {
require(locked == 1, "REENTRANCY");
locked = 2;
_;
locked = 1;
}
}
// src/interfaces/IMEME1155.sol
interface IMEME1155 {
function mint(address account, uint256 id, uint256 amount, bytes memory data) external;
function burn(address account, uint256 id, uint256 amount) external;
function balanceOf(address account, uint256 id) external view returns (uint256);
}
// src/interfaces/IMEME404.sol
/// @title Trugly's IMEME404
/// @notice Contract automatically generated by https://www.trugly.meme
interface IMEME404 {
struct TierCreateParam {
string baseURL;
string nftName;
string nftSymbol;
uint256 amountThreshold;
uint256 nftId;
uint256 lowerId;
uint256 upperId;
bool isFungible;
}
/// @notice Can only be called by NFT collection
/// @dev Raw transfer of memecoins
/// @dev This function bypasses the NFT mint/burn, approval and any fees
function transferFromNFT(address from, address to, uint256 nftTokenId) external returns (bool);
/// @dev Initialize the _tiers
/// @dev Is called automatically by the Memeception contract
function initializeTiers(TierCreateParam[] memory _tierParams, address[] memory _exempt) external;
}
// src/interfaces/IMEME721.sol
interface IMEME721 {
function mint(address account, uint256 id) external;
function burn(uint256 id) external;
function nextOwnedTokenId(address account) external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
}
// src/interfaces/ITruglyFactoryNFT.sol
/// @title Trugly's Manager to create memecoins
interface ITruglyFactoryNFT {
function createMeme1155(
string memory name,
string memory symbol,
address meme404,
address creator,
string memory baseURI
) external returns (address);
function createMeme721(
string memory name,
string memory symbol,
address meme404,
address creator,
string memory baseURI
) external returns (address);
}
// src/libraries/MEME20Constant.sol
library MEME20Constant {
/// @dev Total supply of the Meme token
uint256 internal constant TOKEN_TOTAL_SUPPLY = 10_000_000_000 ether;
/// @dev Token decimals
uint8 internal constant TOKEN_DECIMALS = 18;
uint256 internal constant MAX_CREATOR_FEE_BPS = 80;
uint256 internal constant MAX_PROTOCOL_FEE_BPS = 50;
}
// src/types/MEME20.sol
/// @title ERC20 memecoin created by Trugly
/// @notice Contract automatically generated by https://www.trugly.meme
contract MEME20 is ERC20 {
using FixedPointMathLib for uint256;
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
/* EVENTS */
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
event CreatorFeesUpdated(uint256 oldFeesBps, uint256 newFeesBps);
event ProtocolFeesUpdated(uint256 oldFeesBps, uint256 newFeesBps);
event CreatorAddressUpdated(address oldCreator, address newCreator);
event ProtocolAddressUpdated(address oldProtocol, address newProtocol);
event TreasuryUpdated(address oldTreasury, address newTreasury);
event PoolOrRouterAdded(address indexed account);
event ExemptAdded(address indexed account);
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
/* ERRORS */
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
error OnlyCreator();
error OnlyProtocol();
error CreatorFeeTooHigh();
error ProtocolFeeTooHigh();
error AddressZero();
error AlreadyInitialized();
error PoolNotInitialized();
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
/* STORAGE */
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
bool private _initialized;
address public creator;
address private _protocol;
address private _pTreasury;
uint256 public feeBps;
uint256 private _pFeesBps;
mapping(address => bool) private _exemptFees;
mapping(address => bool) private _routersAndPools;
modifier onlyCreator() {
if (msg.sender != creator) revert OnlyCreator();
_;
}
modifier onlyProtocol() {
if (msg.sender != _protocol) revert OnlyProtocol();
_;
}
constructor(string memory _name, string memory _symbol, address _memeception, address _creator)
ERC20(_name, _symbol, MEME20Constant.TOKEN_DECIMALS)
{
// Set Creator
creator = _creator;
// Set Temporarily to TruglyMemeception (will be transfer to protocol after deployment and setting routers & pools)
_protocol = _memeception;
// Exempt
_addExempt(_memeception);
_addExempt(_creator);
_addExempt(address(this));
_addExempt(address(0));
// Mint to Launchpad
_mint(_memeception, MEME20Constant.TOKEN_TOTAL_SUPPLY);
}
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
if (amount == 0) return super.transferFrom(from, to, 0);
amount = _transferFees(from, to, amount, true);
return super.transferFrom(from, to, amount);
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
if (amount == 0) return super.transfer(to, 0);
amount = _transferFees(msg.sender, to, amount, false);
return super.transfer(to, amount);
}
function _transferFees(address from, address to, uint256 amount, bool isTransferFrom) internal returns (uint256) {
/// @dev Forbid trading until UniV3 LP is initialized
if (!_initialized && msg.sender != _protocol) revert PoolNotInitialized();
// @dev skip to avoid double fees;
bool skip = _routersAndPools[from] && _routersAndPools[to];
if (!_exemptFees[from] && !_exemptFees[to] && !skip && _routersAndPools[from]) {
uint256 feesCreator = amount.mulDiv(feeBps, 1e4);
uint256 feesProtocol = amount.mulDiv(_pFeesBps, 1e4);
amount = amount - feesCreator - feesProtocol;
if (isTransferFrom) {
if (feesCreator > 0) super.transferFrom(from, creator, feesCreator);
if (feesProtocol > 0) super.transferFrom(from, _pTreasury, feesProtocol);
} else {
if (feesCreator > 0) super.transfer(creator, feesCreator);
if (feesProtocol > 0) super.transfer(_pTreasury, feesProtocol);
}
}
return amount;
}
function isExempt(address account) public view returns (bool) {
return _exemptFees[account];
}
function isPoolOrRouter(address account) public view returns (bool) {
return _routersAndPools[account];
}
function addPoolOrRouter(address _contract) public onlyCreator {
_addPoolOrRouter(_contract);
}
function _addPoolOrRouter(address _contract) internal {
_routersAndPools[_contract] = true;
emit PoolOrRouterAdded(_contract);
}
function addExempt(address _contract) public onlyCreator {
_addExempt(_contract);
}
function _addExempt(address _contract) internal {
_exemptFees[_contract] = true;
emit ExemptAdded(_contract);
}
function setCreatorFeeBps(uint256 _newFeeBps) public onlyCreator {
if (_newFeeBps > MEME20Constant.MAX_CREATOR_FEE_BPS) revert CreatorFeeTooHigh();
emit CreatorFeesUpdated(feeBps, _newFeeBps);
feeBps = _newFeeBps;
}
function setCreatorAddress(address _creator) public onlyCreator {
emit CreatorAddressUpdated(creator, _creator);
creator = _creator;
}
function setProtocolFeeBps(uint256 _newFeeBps) public onlyProtocol {
if (_newFeeBps > MEME20Constant.MAX_PROTOCOL_FEE_BPS) revert ProtocolFeeTooHigh();
emit ProtocolFeesUpdated(_pFeesBps, _newFeeBps);
_pFeesBps = _newFeeBps;
}
function setProtocolAddress(address _protocolAddress) public onlyProtocol {
if (_protocolAddress == address(0)) revert AddressZero();
emit ProtocolAddressUpdated(_protocol, _protocolAddress);
_protocol = _protocolAddress;
}
function setTreasuryAddress(address _treasury) public onlyProtocol {
if (_treasury == address(0)) revert AddressZero();
emit TreasuryUpdated(_pTreasury, _treasury);
_pTreasury = _treasury;
}
function initialize(
address _protocolAddr,
address _protocolTreasury,
uint256 _protocolFeesBps,
uint256 _creatorFeesBps,
address _pool,
address[] calldata _routers,
address[] calldata _exemptsAddr
) public onlyProtocol {
if (_initialized) revert AlreadyInitialized();
_initialized = true;
feeBps = _creatorFeesBps;
// Set Protocol
_pFeesBps = _protocolFeesBps;
_pTreasury = _protocolTreasury;
_addExempt(_pTreasury);
_addExempt(_protocolAddr);
// Uniswap
for (uint256 i = 0; i < _routers.length; i++) {
_addPoolOrRouter(_routers[i]);
}
_addPoolOrRouter(_pool);
for (uint256 i = 0; i < _exemptsAddr.length; i++) {
_addExempt(_exemptsAddr[i]);
}
// Transfer to Protocol
setProtocolAddress(_protocolAddr);
}
}
// src/types/MEME404.sol
/// @title Trugly's MEME404
/// @notice Contract automatically generated by https://www.trugly.meme
contract MEME404 is IMEME404, MEME20, ReentrancyGuard {
using FixedPointMathLib for uint256;
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
/* EVENTS */
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
/* ERRORS */
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
/// @dev No _tiers are provided
error NoTiers();
/// @dev Too many _tiers are provided
error MaxTiers();
/// @dev When a fungible sequence has upperId that is not equal to lowerId
error FungibleThreshold();
/// @dev When a prev tier has a higher amount threshold than the current tier
error AmountThreshold();
/// @dev When a non-fungible sequence has incorrect upperId and lowerId
error NonFungibleIds();
/// @dev tokenId is 0
error InvalidTierParamsZeroId();
/// @dev Only NFT collection can call this function
error OnlyNFT();
/// @dev When the contract is already initialized
error TiersAlreadyInitialized();
/// @dev When there's not enough NFTS based on amount threshold
error NotEnoughNFTs();
/// @dev When a NFT sequence is followed by a fungible one
error FungibleAfterNonFungible();
/// @dev When a NFT sequence has nftId that is less than the previous one or is the same but isFungible is different
error IncorrectOrder();
/// @dev Thrown when the upperId is greater than the max uint32 value
error MaxUpperId();
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
/* STORAGE */
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
/// @dev A uint32 map in storage.
struct Uint32Map {
uint256 spacer;
}
struct Tier {
string baseURL;
uint256 lowerId;
uint256 upperId;
uint256 amountThreshold;
bool isFungible;
address nft;
uint256 nextUnmintedId;
Uint32Map burnIds;
uint256 burnLength;
uint256 tierId;
}
/// @dev NFT ID to NFT address mapping
mapping(uint256 => address) public nftIdToAddress;
/// @dev Tier ID to Tier mapping
mapping(uint256 => Tier) internal _tiers;
mapping(address => bool) internal _exemptNFTMint;
uint256 internal _tierCount;
bool internal _initialized;
address internal factory;
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
/* IMPLEMENTATION */
/* ¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯¯\_(ツ)_/¯*/
constructor(string memory _name, string memory _symbol, address _memeception, address _creator, address _factoryNFT)
MEME20(_name, _symbol, _memeception, _creator)
{
factory = _factoryNFT;
}
/// @dev Initialize the _tiers
/// @dev Is called automatically by the Memeception contract
function initializeTiers(IMEME404.TierCreateParam[] memory _tierParams, address[] memory _exempt) external {
if (_initialized) revert TiersAlreadyInitialized();
_initialized = true;
if (_tierParams.length == 0) revert NoTiers();
if (_tierParams.length > 9) revert MaxTiers();
for (uint256 i = 0; i < _tierParams.length; i++) {
if (_tierParams[i].lowerId == 0) revert InvalidTierParamsZeroId();
if (_tierParams[i].amountThreshold == 0 || _tierParams[i].amountThreshold > totalSupply) {
revert AmountThreshold();
}
if (_tierParams[i].upperId >= type(uint32).max) revert MaxUpperId();
if (_tierParams[i].isFungible) {
if (_tierParams[i].lowerId != _tierParams[i].upperId) revert FungibleThreshold();
} else {
if (_tierParams[i].lowerId >= _tierParams[i].upperId) revert NonFungibleIds();
uint256 maxNFT = totalSupply.rawDiv(_tierParams[i].amountThreshold);
if ((_tierParams[i].upperId - _tierParams[i].lowerId + 1) < maxNFT) {
revert NotEnoughNFTs();
}
}
address existingNFTAddr = nftIdToAddress[_tierParams[i].nftId];
Tier memory tier = Tier({
baseURL: _tierParams[i].baseURL,
lowerId: _tierParams[i].lowerId,
upperId: _tierParams[i].upperId,
amountThreshold: _tierParams[i].amountThreshold,
isFungible: _tierParams[i].isFungible,
nft: address(0),
nextUnmintedId: _tierParams[i].isFungible ? 0 : _tierParams[i].lowerId,
burnIds: Uint32Map(0),
burnLength: 0,
tierId: i + 1
});
if (i > 0) {
Tier memory previousTier = _tiers[i];
if (_tierParams[i - 1].nftId > _tierParams[i].nftId) revert IncorrectOrder();
if (
_tierParams[i - 1].nftId == _tierParams[i].nftId
&& _tierParams[i - 1].isFungible != _tierParams[i].isFungible
) revert IncorrectOrder();
if (previousTier.amountThreshold >= tier.amountThreshold) revert AmountThreshold();
if (!previousTier.isFungible && tier.isFungible) revert FungibleAfterNonFungible();
if (existingNFTAddr != address(0) && previousTier.upperId >= tier.lowerId) {
revert NonFungibleIds();
}
}
tier.nft = existingNFTAddr != address(0) ? existingNFTAddr : _createNewNFT(creator, _tierParams[i]);
_tiers[i + 1] = tier;
}
for (uint256 i = 0; i < _exempt.length; i++) {
_exemptNFTMint[_exempt[i]] = true;
}
_tierCount = _tierParams.length;
}
/// @dev Transfer of memecoins
/// @dev If balance of sender or recipient changes tier, mint or burn NFTs accordingly
function transfer(address to, uint256 amount) public override returns (bool) {
_TierEligibility memory beforeTierFrom = _getTierEligibility(msg.sender);
_TierEligibility memory beforeTierTo = _getTierEligibility(to);
bool success = super.transfer(to, amount);
_TierEligibility memory afterTierFrom = _getTierEligibility(msg.sender);
_TierEligibility memory afterTierTo = _getTierEligibility(to);
// handle burn
_burnTier(msg.sender, beforeTierFrom, afterTierFrom, 0);
_burnTier(to, beforeTierTo, afterTierTo, 0);
// handle mint
_mintTier(msg.sender, afterTierFrom);
_mintTier(to, afterTierTo);
return success;
}
/// @dev Transfer of memecoins
/// @dev If balance of sender or recipient changes tier, mint or burn NFTs accordingly
function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
_TierEligibility memory beforeTierFrom = _getTierEligibility(from);
_TierEligibility memory beforeTierTo = _getTierEligibility(to);
bool success = super.transferFrom(from, to, amount);
_TierEligibility memory afterTierFrom = _getTierEligibility(from);
_TierEligibility memory afterTierTo = _getTierEligibility(to);
_burnTier(from, beforeTierFrom, afterTierFrom, 0);
_burnTier(to, beforeTierTo, afterTierTo, 0);
_mintTier(from, afterTierFrom);
_mintTier(to, afterTierTo);
return success;
}
/// @dev Create a new NFT collection
/// @notice ERC1155 if fungible, ERC721 if non-fungible
function _createNewNFT(address _creator, IMEME404.TierCreateParam memory _tier)
internal
virtual
returns (address)
{
if (_tier.isFungible) {
address nft = ITruglyFactoryNFT(factory).createMeme1155(
_tier.nftName, _tier.nftSymbol, address(this), _creator, _tier.baseURL
);
nftIdToAddress[_tier.nftId] = nft;
} else {
address nft = ITruglyFactoryNFT(factory).createMeme721(
_tier.nftName, _tier.nftSymbol, address(this), _creator, _tier.baseURL
);
nftIdToAddress[_tier.nftId] = nft;
}
return nftIdToAddress[_tier.nftId];
}
/// @notice Can only be called by NFT collection
/// @dev Raw transfer of memecoins
/// @dev This function bypasses the NFT mint/burn, approval and any fees
function transferFromNFT(address from, address to, uint256 nftTokenId) public returns (bool) {
Tier memory tier = _getTierFromNftTokenId(msg.sender, nftTokenId);
if (tier.nft == address(0)) revert OnlyNFT();
_TierEligibility memory beforeTierTo = _getTierEligibility(to);
balanceOf[from] -= tier.amountThreshold;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += tier.amountThreshold;
}
_TierEligibility memory afterTierFrom = _getTierEligibility(from);
_TierEligibility memory afterTierTo = _getTierEligibility(to);
/// @dev NFT has already been transferred
/// Need to check if the user has decreased in tier and mint the NFTs
_mintTier(from, afterTierFrom);
if (afterTierTo.tierId > 0 && tier.tierId != uint256(afterTierTo.tierId)) {
if (tier.isFungible) {
IMEME1155(tier.nft).burn(to, nftTokenId, 1);
} else {
IMEME721(tier.nft).burn(nftTokenId);
Tier storage _tierStorage = _tiers[tier.tierId];
_set(_tierStorage.burnIds, ++_tierStorage.burnLength, uint32(nftTokenId));
}
}
if (afterTierTo.tierId != beforeTierTo.tierId) {
if (tier.nft == beforeTierTo.nft) {
_burnTier(to, beforeTierTo, afterTierTo, 1);
} else {
_burnTier(to, beforeTierTo, afterTierTo, 0);
}
_mintTier(to, afterTierTo);
}
emit Transfer(from, to, tier.amountThreshold);
return true;
}
/// @dev Mint NFTs once a user reaches a new tier
/// @param _owner Address of the user
/// @param _afterTierEligibility Current Tier + NFT balance
function _mintTier(address _owner, _TierEligibility memory _afterTierEligibility) internal nonReentrant {
if (_afterTierEligibility.tierId < 0 || _owner == address(0) || _exemptNFTMint[_owner]) return;
Tier storage tier = _tiers[uint256(_afterTierEligibility.tierId)];
if (tier.isFungible) {
if ((_owner.code.length != 0) && !_checkERC1155Received(_owner, msg.sender, address(0), tier.lowerId, 1)) {
return;
}
IMEME1155 nft = IMEME1155(tier.nft);
if (nft.balanceOf(_owner, tier.lowerId) >= 1) return;
nft.mint(_owner, tier.lowerId, 1, "");
} else {
if ((_owner.code.length != 0) && !_checkERC721Received(_owner, msg.sender, address(0), tier.lowerId, "")) {
return;
}
IMEME721 nft = IMEME721(tier.nft);
uint256 numToMint = _afterTierEligibility.expectedNFTBal > nft.balanceOf(_owner)
? _afterTierEligibility.expectedNFTBal - nft.balanceOf(_owner)
: 0;
for (uint256 i = 0; i < numToMint; i++) {
uint256 nftIdToMint;
if (tier.nextUnmintedId <= tier.upperId) {
nftIdToMint = tier.nextUnmintedId++;
} else {
/// @dev this should never happen but in case it does
/// @dev we wouldn't want to mint any NFT and let the coins be transferred
if (tier.burnLength == 0) return;
nftIdToMint = _get(tier.burnIds, tier.burnLength--);
}
nft.mint(_owner, nftIdToMint);
}
}
}
/// @dev Burn NFTs once a user reaches a new tier (either going up or down)
/// @param _owner Address of the user
/// @param _beforeTierEligibility Before Transfer: Tier + NFT balance
/// @param _afterTierEligibility Current Tier + NFT balance
/// @param _incrementFromNFTTransfer Balance is incremented from transferFromNFT
function _burnTier(
address _owner,
_TierEligibility memory _beforeTierEligibility,
_TierEligibility memory _afterTierEligibility,
uint256 _incrementFromNFTTransfer
) internal nonReentrant {
if (_beforeTierEligibility.tierId < 0 || _owner == address(0)) return;
Tier storage tier = _tiers[uint256(_beforeTierEligibility.tierId)];
if (tier.isFungible) {
IMEME1155 nft = IMEME1155(tier.nft);
if (
(nft.balanceOf(_owner, tier.lowerId) == 0)
|| _beforeTierEligibility.tierId == _afterTierEligibility.tierId
) return;
nft.burn(_owner, tier.lowerId, nft.balanceOf(_owner, tier.lowerId));
} else {
IMEME721 nft = IMEME721(tier.nft);
uint256 numToBurn = _beforeTierEligibility.tierId != _afterTierEligibility.tierId
? _beforeTierEligibility.currentNFTBal > _incrementFromNFTTransfer
? _beforeTierEligibility.currentNFTBal - _incrementFromNFTTransfer
: 0
: _afterTierEligibility.currentNFTBal > _afterTierEligibility.expectedNFTBal
? _afterTierEligibility.currentNFTBal - _afterTierEligibility.expectedNFTBal
: 0;
for (uint256 i = 0; i < numToBurn; i++) {
uint256 nftIdToburn = nft.nextOwnedTokenId(_owner);
nft.burn(nftIdToburn);
_set(tier.burnIds, ++tier.burnLength, uint32(nftIdToburn));
}
}
}
/// @dev Get the tier eligibility of a user based on their memecoin balance
/// @param _owner Address of the user
/// @return _TierEligibility
function _getTierEligibility(address _owner) internal view returns (_TierEligibility memory) {
if (_owner != address(0)) {
uint256 balance = balanceOf[_owner];
for (uint256 i = _tierCount; i > 0; i--) {
if (balance >= _tiers[i].amountThreshold) {
return _TierEligibility({
tierId: int256(_tiers[i].tierId),
expectedNFTBal: balance.rawDiv(_tiers[i].amountThreshold),
nft: _tiers[i].nft,
currentNFTBal: _tiers[i].isFungible
? IMEME1155(_tiers[i].nft).balanceOf(_owner, _tiers[i].lowerId)
: IMEME721(_tiers[i].nft).balanceOf(_owner)
});
}
}
}
return _TierEligibility({tierId: -1, expectedNFTBal: 0, nft: address(0), currentNFTBal: 0});
}
/// @dev Get the tier by ID
/// @param tierId Tier ID
/// @return Tier
function getTier(uint256 tierId) public view returns (Tier memory) {
return _tiers[tierId];
}
/// @dev Get the tier by NFT token ID
/// @param nft NFT address
/// @param tokenId NFT token ID
/// @return Tier
function _getTierFromNftTokenId(address nft, uint256 tokenId) internal view returns (Tier memory) {
for (uint256 i = 1; i <= _tierCount; i++) {
Tier memory tier = _tiers[i];
if (tier.nft != nft) continue;
if (tier.isFungible) {
if (tier.lowerId == tokenId) {
return tier;
}
} else {
if (tokenId >= tier.lowerId && tokenId <= tier.upperId) {
return tier;
}
}
}
return Tier({
baseURL: "",
lowerId: 0,
upperId: 0,
amountThreshold: 0,
isFungible: false,
nft: address(0),
nextUnmintedId: 0,
burnIds: Uint32Map(0),
burnLength: 0,
tierId: 0
});
}
function _checkERC1155Received(address _contract, address _operator, address _from, uint256 _id, uint256 _value)
internal
returns (bool)
{
bytes memory callData = abi.encodeWithSelector(
ERC1155TokenReceiver(_contract).onERC1155Received.selector, _operator, _from, _id, _value, ""
);
(bool success, bytes memory returnData) = _contract.call(callData);
// Check both call success and return value
if (success && returnData.length >= 32) {
// Make sure there is enough data to cover a `bytes4` return
bytes4 returned = abi.decode(returnData, (bytes4));
return returned == ERC1155TokenReceiver.onERC1155Received.selector;
}
return false;
}
function _checkERC721Received(address _contract, address _operator, address _from, uint256 _id, bytes memory _data)
internal
returns (bool)
{
bytes memory callData = abi.encodeWithSelector(
ERC721TokenReceiver(_contract).onERC721Received.selector, _operator, _from, _id, _data
);
(bool success, bytes memory returnData) = _contract.call(callData);
// Check both call success and return value
if (success && returnData.length >= 32) {
// Make sure there is enough data to cover a `bytes4` return
bytes4 returned = abi.decode(returnData, (bytes4));
return returned == ERC721TokenReceiver.onERC721Received.selector;
}
return false;
}
/// @dev Returns the uint32 value at `index` in `map`.
function _get(Uint32Map storage map, uint256 index) internal view returns (uint32 result) {
/// @solidity memory-safe-assembly
assembly {
let s := add(shl(96, map.slot), shr(3, index)) // Storage slot.
result := and(0xffffffff, shr(shl(5, and(index, 7)), sload(s)))
}
}
/// @dev Updates the uint32 value at `index` in `map`.
function _set(Uint32Map storage map, uint256 index, uint32 value) internal {
/// @solidity memory-safe-assembly
assembly {
let s := add(shl(96, map.slot), shr(3, index)) // Storage slot.
let o := shl(5, and(index, 7)) // Storage slot offset (bits).
let v := sload(s) // Storage slot value.
sstore(s, xor(v, shl(o, and(0xffffffff, xor(value, shr(o, v))))))
}
}
struct _TierEligibility {
int256 tierId;
uint256 expectedNFTBal;
address nft;
uint256 currentNFTBal;
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"address","name":"_memeception","type":"address"},{"internalType":"address","name":"_creator","type":"address"},{"internalType":"address","name":"_factoryNFT","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AmountThreshold","type":"error"},{"inputs":[],"name":"CreatorFeeTooHigh","type":"error"},{"inputs":[],"name":"FungibleAfterNonFungible","type":"error"},{"inputs":[],"name":"FungibleThreshold","type":"error"},{"inputs":[],"name":"IncorrectOrder","type":"error"},{"inputs":[],"name":"InvalidTierParamsZeroId","type":"error"},{"inputs":[],"name":"MaxTiers","type":"error"},{"inputs":[],"name":"MaxUpperId","type":"error"},{"inputs":[],"name":"NoTiers","type":"error"},{"inputs":[],"name":"NonFungibleIds","type":"error"},{"inputs":[],"name":"NotEnoughNFTs","type":"error"},{"inputs":[],"name":"OnlyCreator","type":"error"},{"inputs":[],"name":"OnlyNFT","type":"error"},{"inputs":[],"name":"OnlyProtocol","type":"error"},{"inputs":[],"name":"PoolNotInitialized","type":"error"},{"inputs":[],"name":"ProtocolFeeTooHigh","type":"error"},{"inputs":[],"name":"TiersAlreadyInitialized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldCreator","type":"address"},{"indexed":false,"internalType":"address","name":"newCreator","type":"address"}],"name":"CreatorAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeesBps","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeesBps","type":"uint256"}],"name":"CreatorFeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"ExemptAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"PoolOrRouterAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldProtocol","type":"address"},{"indexed":false,"internalType":"address","name":"newProtocol","type":"address"}],"name":"ProtocolAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeesBps","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeesBps","type":"uint256"}],"name":"ProtocolFeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldTreasury","type":"address"},{"indexed":false,"internalType":"address","name":"newTreasury","type":"address"}],"name":"TreasuryUpdated","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"}],"name":"addExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"}],"name":"addPoolOrRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tierId","type":"uint256"}],"name":"getTier","outputs":[{"components":[{"internalType":"string","name":"baseURL","type":"string"},{"internalType":"uint256","name":"lowerId","type":"uint256"},{"internalType":"uint256","name":"upperId","type":"uint256"},{"internalType":"uint256","name":"amountThreshold","type":"uint256"},{"internalType":"bool","name":"isFungible","type":"bool"},{"internalType":"address","name":"nft","type":"address"},{"internalType":"uint256","name":"nextUnmintedId","type":"uint256"},{"components":[{"internalType":"uint256","name":"spacer","type":"uint256"}],"internalType":"struct MEME404.Uint32Map","name":"burnIds","type":"tuple"},{"internalType":"uint256","name":"burnLength","type":"uint256"},{"internalType":"uint256","name":"tierId","type":"uint256"}],"internalType":"struct MEME404.Tier","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_protocolAddr","type":"address"},{"internalType":"address","name":"_protocolTreasury","type":"address"},{"internalType":"uint256","name":"_protocolFeesBps","type":"uint256"},{"internalType":"uint256","name":"_creatorFeesBps","type":"uint256"},{"internalType":"address","name":"_pool","type":"address"},{"internalType":"address[]","name":"_routers","type":"address[]"},{"internalType":"address[]","name":"_exemptsAddr","type":"address[]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"baseURL","type":"string"},{"internalType":"string","name":"nftName","type":"string"},{"internalType":"string","name":"nftSymbol","type":"string"},{"internalType":"uint256","name":"amountThreshold","type":"uint256"},{"internalType":"uint256","name":"nftId","type":"uint256"},{"internalType":"uint256","name":"lowerId","type":"uint256"},{"internalType":"uint256","name":"upperId","type":"uint256"},{"internalType":"bool","name":"isFungible","type":"bool"}],"internalType":"struct IMEME404.TierCreateParam[]","name":"_tierParams","type":"tuple[]"},{"internalType":"address[]","name":"_exempt","type":"address[]"}],"name":"initializeTiers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isExempt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isPoolOrRouter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nftIdToAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_creator","type":"address"}],"name":"setCreatorAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newFeeBps","type":"uint256"}],"name":"setCreatorFeeBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_protocolAddress","type":"address"}],"name":"setProtocolAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newFeeBps","type":"uint256"}],"name":"setProtocolFeeBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasuryAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"nftTokenId","type":"uint256"}],"name":"transferFromNFT","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60e06040526001600d5534801562000015575f80fd5b5060405162003f7338038062003f7383398101604081905262000038916200035e565b84848484838360125f6200004d848262000484565b5060016200005c838262000484565b5060ff81166080524660a0526200007262000131565b60c052505060068054610100600160a81b0319166101006001600160a01b038581169190910291909117909155600780546001600160a01b03191691851691909117905550620000c282620001cb565b620000cd81620001cb565b620000d830620001cb565b620000e35f620001cb565b620000fb826b204fce5e3e2502611000000062000216565b5050601280546001600160a01b0390941661010002610100600160a81b03199094169390931790925550620005f0945050505050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f5f60405162000163919062000550565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6001600160a01b0381165f818152600b6020526040808220805460ff19166001179055517fdcc4d7bff655001015f308c794375175b9e1616a6ca241b536e472ac47f93f769190a250565b8060025f828254620002299190620005ca565b90915550506001600160a01b0382165f818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f830112620002a5575f80fd5b81516001600160401b0380821115620002c257620002c262000281565b604051601f8301601f19908116603f01168101908282118183101715620002ed57620002ed62000281565b81604052838152602092508660208588010111156200030a575f80fd5b5f91505b838210156200032d57858201830151818301840152908201906200030e565b5f602085830101528094505050505092915050565b80516001600160a01b038116811462000359575f80fd5b919050565b5f805f805f60a0868803121562000373575f80fd5b85516001600160401b03808211156200038a575f80fd5b6200039889838a0162000295565b96506020880151915080821115620003ae575f80fd5b50620003bd8882890162000295565b945050620003ce6040870162000342565b9250620003de6060870162000342565b9150620003ee6080870162000342565b90509295509295909350565b600181811c908216806200040f57607f821691505b6020821081036200042e57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156200047f57805f5260205f20601f840160051c810160208510156200045b5750805b601f840160051c820191505b818110156200047c575f815560010162000467565b50505b505050565b81516001600160401b03811115620004a057620004a062000281565b620004b881620004b18454620003fa565b8462000434565b602080601f831160018114620004ee575f8415620004d65750858301515b5f19600386901b1c1916600185901b17855562000548565b5f85815260208120601f198616915b828110156200051e57888601518255948401946001909101908401620004fd565b50858210156200053c57878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b5f8083546200055f81620003fa565b600182811680156200057a57600181146200059057620005be565b60ff1984168752821515830287019450620005be565b875f526020805f205f5b85811015620005b55781548a8201529084019082016200059a565b50505082870194505b50929695505050505050565b80820180821115620005ea57634e487b7160e01b5f52601160045260245ffd5b92915050565b60805160a05160c0516139586200061b5f395f610a3b01525f610a0601525f61026d01526139585ff3fe608060405234801561000f575f80fd5b5060043610610152575f3560e01c806302d05d3f1461015657806306fdde0314610184578063095ea7b3146101995780630ee7642d146101bc578063129763c2146101e757806318160ddd146101fa5780631ac5f606146102115780631cdd35c91461022657806323b872dd1461023957806324a9d8531461024c57806329a771f314610255578063313ce567146102685780633644e515146102a15780634f062c5a146102a957806358e47004146102c95780636605bfda146102dc5780636da2d116146102ef57806370a082311461031757806372a4ff75146103365780637ecebe00146103495780639127cc691461036857806395d89b411461037b5780639a195a1314610383578063a9059cbb14610396578063ad5dff73146103a9578063c0417e58146103d4578063d505accf146103e7578063dd62ed3e146103fa575b5f80fd5b60065461016e9061010090046001600160a01b031681565b60405161017b9190612ec3565b60405180910390f35b61018c610424565b60405161017b9190612f24565b6101ac6101a7366004612f4a565b6104af565b604051901515815260200161017b565b6101ac6101ca366004612f74565b6001600160a01b03165f908152600c602052604090205460ff1690565b6101ac6101f5366004612f8f565b610508565b61020360025481565b60405190815260200161017b565b61022461021f366004612fcd565b610785565b005b610224610234366004612f74565b610818565b6101ac610247366004612f8f565b610854565b61020360095481565b61022461026336600461302b565b6108cc565b61028f7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff909116815260200161017b565b610203610a03565b6102bc6102b7366004612fcd565b610a5d565b60405161017b91906130df565b6102246102d7366004612f74565b610b94565b6102246102ea366004612f74565b610c4f565b61016e6102fd366004612fcd565b600e6020525f90815260409020546001600160a01b031681565b610203610325366004612f74565b60036020525f908152604090205481565b610224610344366004613304565b610d0a565b610203610357366004612f74565b60056020525f908152604090205481565b610224610376366004612f74565b6115f2565b61018c611698565b610224610391366004612f74565b6116a5565b6101ac6103a4366004612f4a565b6116de565b6101ac6103b7366004612f74565b6001600160a01b03165f908152600b602052604090205460ff1690565b6102246103e2366004612fcd565b611754565b6102246103f5366004613487565b6117e2565b6102036104083660046134f8565b600460209081525f928352604080842090915290825290205481565b5f80546104309061352f565b80601f016020809104026020016040519081016040528092919081815260200182805461045c9061352f565b80156104a75780601f1061047e576101008083540402835291602001916104a7565b820191905f5260205f20905b81548152906001019060200180831161048a57829003601f168201915b505050505081565b335f8181526004602090815260408083206001600160a01b038716808552925280832085905551919290915f80516020613903833981519152906104f69086815260200190565b60405180910390a35060015b92915050565b5f806105143384611a0c565b60a08101519091506001600160a01b03166105425760405163043d000960e51b815260040160405180910390fd5b5f61054c85611c3b565b60608301516001600160a01b0388165f9081526003602052604081208054939450919261057a90849061357b565b909155505060608201516001600160a01b0386165f90815260036020526040812080549092019091556105ac87611c3b565b90505f6105b887611c3b565b90506105c48883611e68565b80515f1280156105da5750805161012085015114155b156106e557836080015115610650578360a001516001600160a01b031663f5298aca888860016040518463ffffffff1660e01b815260040161061e9392919061358e565b5f604051808303815f87803b158015610635575f80fd5b505af1158015610647573d5f803e3d5ffd5b505050506106e5565b60a0840151604051630852cd8d60e31b8152600481018890526001600160a01b03909116906342966c68906024015f604051808303815f87803b158015610695575f80fd5b505af11580156106a7573d5f803e3d5ffd5b5050506101208501515f908152600f602052604081206007810180549193506106e39260068501926106d8906135af565b918290555089612271565b505b82518151146107375782604001516001600160a01b03168460a001516001600160a01b0316036107215761071c878483600161229c565b61072d565b61072d8784835f61229c565b6107378782611e68565b866001600160a01b0316886001600160a01b03165f805160206138e3833981519152866060015160405161076d91815260200190565b60405180910390a360019450505050505b9392505050565b60065461010090046001600160a01b031633146107b5576040516308f78f9960e31b815260040160405180910390fd5b60508111156107d757604051632a52987760e21b815260040160405180910390fd5b60095460408051918252602082018390527f0a8167de874bdafbcdb7afb1989f0a655113928c1f558cfcd8062e4590929db6910160405180910390a1600955565b60065461010090046001600160a01b03163314610848576040516308f78f9960e31b815260040160405180910390fd5b610851816125d4565b50565b5f8061085f85611c3b565b90505f61086b85611c3b565b90505f61087987878761261f565b90505f61088588611c3b565b90505f61089188611c3b565b905061089f8986845f61229c565b6108ab8885835f61229c565b6108b58983611e68565b6108bf8882611e68565b5090979650505050505050565b6007546001600160a01b031633146108f75760405163d35a97ab60e01b815260040160405180910390fd5b60065460ff161561091a5760405162dc149f60e41b815260040160405180910390fd5b6006805460ff191660011790556009869055600a879055600880546001600160a01b038a166001600160a01b03199091168117909155610959906125d4565b610962896125d4565b5f5b838110156109a35761099b858583818110610981576109816135c7565b90506020020160208101906109969190612f74565b61265b565b600101610964565b506109ad8561265b565b5f5b818110156109ee576109e68383838181106109cc576109cc6135c7565b90506020020160208101906109e19190612f74565b6125d4565b6001016109af565b506109f889610b94565b505050505050505050565b5f7f00000000000000000000000000000000000000000000000000000000000000004614610a3857610a336126a6565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b610a65612e5a565b5f828152600f60205260409081902081516101408101909252805482908290610a8d9061352f565b80601f0160208091040260200160405190810160405280929190818152602001828054610ab99061352f565b8015610b045780601f10610adb57610100808354040283529160200191610b04565b820191905f5260205f20905b815481529060010190602001808311610ae757829003601f168201915b50505091835250506001820154602080830191909152600283015460408084019190915260038401546060840152600484015460ff8116151560808501526001600160a01b03610100918290041660a0850152600585015460c085015281519283019091526006840154825260e08301919091526007830154908201526008909101546101209091015292915050565b6007546001600160a01b03163314610bbf5760405163d35a97ab60e01b815260040160405180910390fd5b6001600160a01b038116610be657604051639fabe1c160e01b815260040160405180910390fd5b6007546040517f2756814479f687d805be12ef7dfd27c72bc645462236412ee56a627f389e4e3391610c25916001600160a01b039091169084906135db565b60405180910390a1600780546001600160a01b0319166001600160a01b0392909216919091179055565b6007546001600160a01b03163314610c7a5760405163d35a97ab60e01b815260040160405180910390fd5b6001600160a01b038116610ca157604051639fabe1c160e01b815260040160405180910390fd5b6008546040517f4ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a91610ce0916001600160a01b039091169084906135db565b60405180910390a1600880546001600160a01b0319166001600160a01b0392909216919091179055565b60125460ff1615610d2e57604051634a0dba0760e11b815260040160405180910390fd5b6012805460ff1916600117905581515f03610d5c57604051631e8e92af60e21b815260040160405180910390fd5b600982511115610d7f5760405163335b59ab60e11b815260040160405180910390fd5b5f5b825181101561158e57828181518110610d9c57610d9c6135c7565b602002602001015160a001515f03610dc75760405163111bcb0160e01b815260040160405180910390fd5b828181518110610dd957610dd96135c7565b6020026020010151606001515f1480610e105750600254838281518110610e0257610e026135c7565b602002602001015160600151115b15610e2e57604051632324d1df60e01b815260040160405180910390fd5b63ffffffff8016838281518110610e4757610e476135c7565b602002602001015160c0015110610e71576040516376b5325960e11b815260040160405180910390fd5b828181518110610e8357610e836135c7565b602002602001015160e0015115610ef357828181518110610ea657610ea66135c7565b602002602001015160c00151838281518110610ec457610ec46135c7565b602002602001015160a0015114610eee576040516301304d1b60e41b815260040160405180910390fd5b610ff5565b828181518110610f0557610f056135c7565b602002602001015160c00151838281518110610f2357610f236135c7565b602002602001015160a0015110610f4d57604051636eebf03560e01b815260040160405180910390fd5b5f610f80848381518110610f6357610f636135c7565b60200260200101516060015160025461273e90919063ffffffff16565b905080848381518110610f9557610f956135c7565b602002602001015160a00151858481518110610fb357610fb36135c7565b602002602001015160c00151610fc9919061357b565b610fd49060016135f5565b1015610ff35760405163e1ace8ad60e01b815260040160405180910390fd5b505b5f600e5f85848151811061100b5761100b6135c7565b60200260200101516080015181526020019081526020015f205f9054906101000a90046001600160a01b031690505f604051806101400160405280868581518110611058576110586135c7565b60200260200101515f0151815260200186858151811061107a5761107a6135c7565b602002602001015160a00151815260200186858151811061109d5761109d6135c7565b602002602001015160c0015181526020018685815181106110c0576110c06135c7565b60200260200101516060015181526020018685815181106110e3576110e36135c7565b602002602001015160e00151151581526020015f6001600160a01b03168152602001868581518110611117576111176135c7565b602002602001015160e0015161114a57868581518110611139576111396135c7565b602002602001015160a0015161114c565b5f5b815260200160405180602001604052805f81525081526020015f815260200184600161117891906135f5565b90529050821561146c575f838152600f6020526040808220815161014081019092528054829082906111a99061352f565b80601f01602080910402602001604051908101604052809291908181526020018280546111d59061352f565b80156112205780601f106111f757610100808354040283529160200191611220565b820191905f5260205f20905b81548152906001019060200180831161120357829003601f168201915b50505091835250506001820154602080830191909152600283015460408084019190915260038401546060840152600484015460ff8116151560808501526001600160a01b03610100918290041660a0850152600585015460c085015281519283019091526006840154825260e08301919091526007830154908201526008909101546101209091015286519091508690859081106112c1576112c16135c7565b602002602001015160800151866001866112db919061357b565b815181106112eb576112eb6135c7565b602002602001015160800151111561131657604051638080c2ed60e01b815260040160405180910390fd5b858481518110611328576113286135c7565b60200260200101516080015186600186611342919061357b565b81518110611352576113526135c7565b6020026020010151608001511480156113b55750858481518110611378576113786135c7565b602002602001015160e00151151586600186611394919061357b565b815181106113a4576113a46135c7565b602002602001015160e00151151514155b156113d357604051638080c2ed60e01b815260040160405180910390fd5b81606001518160600151106113fb57604051632324d1df60e01b815260040160405180910390fd5b806080015115801561140e575081608001515b1561142c57604051632b76654560e11b815260040160405180910390fd5b6001600160a01b0383161580159061144c57508160200151816040015110155b1561146a57604051636eebf03560e01b815260040160405180910390fd5b505b6001600160a01b0382166114b7576114b2600660019054906101000a90046001600160a01b03168685815181106114a5576114a56135c7565b6020026020010151612743565b6114b9565b815b6001600160a01b031660a082015280600f5f6114d68660016135f5565b815260208101919091526040015f20815181906114f39082613654565b5060208201516001828101919091556040830151600283015560608301516003830155608083015160048301805460a08601516001600160a81b0319909116921515610100600160a81b031916929092176101006001600160a01b03909316830217905560c0840151600584015560e0840151516006840155830151600783015561012090920151600890910155929092019150610d819050565b505f5b81518110156115ea57600160105f8484815181106115b1576115b16135c7565b6020908102919091018101516001600160a01b031682528101919091526040015f20805460ff1916911515919091179055600101611591565b505051601155565b60065461010090046001600160a01b03163314611622576040516308f78f9960e31b815260040160405180910390fd5b7f4c1d69ffe6fad068e437c6e17f4068f125ab0b7e50bec2d7f4519d7ab1ee504f600660019054906101000a90046001600160a01b0316826040516116689291906135db565b60405180910390a1600680546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600180546104309061352f565b60065461010090046001600160a01b031633146116d5576040516308f78f9960e31b815260040160405180910390fd5b6108518161265b565b5f806116e933611c3b565b90505f6116f585611c3b565b90505f61170286866128e1565b90505f61170e33611c3b565b90505f61171a88611c3b565b90506117283386845f61229c565b6117348885835f61229c565b61173e3383611e68565b6117488882611e68565b50909695505050505050565b6007546001600160a01b0316331461177f5760405163d35a97ab60e01b815260040160405180910390fd5b60328111156117a15760405163499fddb160e01b815260040160405180910390fd5b600a5460408051918252602082018390527fe9c032fb7419b343f83add64d4513ecbd7602547133916538d3f3f12a061a30e910160405180910390a1600a55565b428410156118315760405162461bcd60e51b815260206004820152601760248201527614115493525517d11150511312539157d1561412549151604a1b60448201526064015b60405180910390fd5b5f600161183c610a03565b6001600160a01b038a81165f8181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f1981840301815282825280516020918201205f84529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611944573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b0381161580159061197a5750876001600160a01b0316816001600160a01b0316145b6119b75760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401611828565b6001600160a01b039081165f9081526004602090815260408083208a8516808552908352928190208990555188815291928a16915f80516020613903833981519152910160405180910390a350505050505050565b611a14612e5a565b60015b6011548111611bc5575f818152600f602052604080822081516101408101909252805482908290611a479061352f565b80601f0160208091040260200160405190810160405280929190818152602001828054611a739061352f565b8015611abe5780601f10611a9557610100808354040283529160200191611abe565b820191905f5260205f20905b815481529060010190602001808311611aa157829003601f168201915b50505091835250506001820154602080830191909152600283015460408084019190915260038401546060840152600484015460ff8116151560808501526001600160a01b0361010091829004811660a080870191909152600587015460c087015283519485019093526006860154845260e0850193909352600785015490840152600890930154610120909201919091529082015191925090811690861614611b685750611bb3565b806080015115611b8b5783816020015103611b865791506105029050565b611bb1565b80602001518410158015611ba3575080604001518411155b15611bb15791506105029050565b505b80611bbd816135af565b915050611a17565b5060405180610140016040528060405180602001604052805f81525081526020015f81526020015f81526020015f81526020015f151581526020015f6001600160a01b031681526020015f815260200160405180602001604052805f81525081526020015f81526020015f815250905092915050565b611c6b60405180608001604052805f81526020015f81526020015f6001600160a01b031681526020015f81525090565b6001600160a01b03821615611e36576001600160a01b0382165f908152600360205260409020546011545b8015611e33575f818152600f60205260409020600301548210611e2157604080516080810182525f838152600f60208181528483206008810154855260038101548804828601526004015461010081046001600160a01b03169585019590955291859052905290606082019060ff16611d90575f838152600f60205260409081902060049081015491516370a0823160e01b81526101009092046001600160a01b0316916370a0823191611d4c918a9101612ec3565b602060405180830381865afa158015611d67573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d8b9190613713565b611e17565b5f838152600f6020526040908190206004808201546001909201549251627eeac760e11b81526101009092046001600160a01b03169262fdd58e92611dd8928b92910161372a565b602060405180830381865afa158015611df3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e179190613713565b9052949350505050565b80611e2b81613743565b915050611c96565b50505b60405180608001604052805f1981526020015f81526020015f6001600160a01b031681526020015f8152509050919050565b600d54600114611e8a5760405162461bcd60e51b815260040161182890613758565b6002600d5580515f1380611ea557506001600160a01b038216155b80611ec757506001600160a01b0382165f9081526010602052604090205460ff165b6122685780515f908152600f60205260409020600481015460ff1615612021576001600160a01b0383163b15801590611f0f5750611f0d83335f84600101546001612912565b155b15611f1a5750612268565b600481810154600180840154604051627eeac760e11b81526101009093046001600160a01b0316939192849262fdd58e92611f57928a920161372a565b602060405180830381865afa158015611f72573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f969190613713565b10611fa2575050612268565b60018281015460405163731133e960e01b81526001600160a01b03878116600483015260248201929092526044810192909252608060648301525f608483015282169063731133e99060a4015f604051808303815f87803b158015612005575f80fd5b505af1158015612017573d5f803e3d5ffd5b5050505050612266565b6001600160a01b0383163b15801590612056575061205483335f846001015460405180602001604052805f815250612a27565b155b156120615750612268565b6004818101546040516370a0823160e01b81526101009091046001600160a01b0316915f9183916370a082319161209a91899101612ec3565b602060405180830381865afa1580156120b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120d99190613713565b8460200151116120e9575f612163565b6040516370a0823160e01b81526001600160a01b038316906370a0823190612115908890600401612ec3565b602060405180830381865afa158015612130573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121549190613713565b8460200151612163919061357b565b90505f5b81811015612262575f846002015485600501541161219b57600585018054905f612190836135af565b9190505590506121fa565b84600701545f036121b0575050505050612268565b6007850180546121f1916006880191905f6121ca83613743565b919050555f8160031c8360601b0180546007841660051b1c63ffffffff1691505092915050565b63ffffffff1690505b6040516340c10f1960e01b81526001600160a01b038516906340c10f1990612228908a90859060040161372a565b5f604051808303815f87803b15801561223f575f80fd5b505af1158015612251573d5f803e3d5ffd5b505060019093019250612167915050565b5050505b505b50506001600d55565b8160031c8360601b016007831660051b815480821c841863ffffffff16821b81188355505050505050565b600d546001146122be5760405162461bcd60e51b815260040161182890613758565b6002600d5582515f13806122d957506001600160a01b038416155b6125c95782515f908152600f60205260409020600481015460ff1615612457576004818101546001830154604051627eeac760e11b81526101009092046001600160a01b031692839262fdd58e92612333928b920161372a565b602060405180830381865afa15801561234e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123729190613713565b158061237f575083518551145b1561238b5750506125c9565b6001820154604051627eeac760e11b81526001600160a01b0383169163f5298aca91899190849062fdd58e906123c7908590859060040161372a565b602060405180830381865afa1580156123e2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124069190613713565b6040518463ffffffff1660e01b81526004016124249392919061358e565b5f604051808303815f87803b15801561243b575f80fd5b505af115801561244d573d5f803e3d5ffd5b50505050506125c7565b6004810154835185516101009092046001600160a01b0316915f9190036124a657846020015185606001511161248d575f6124c7565b846020015185606001516124a1919061357b565b6124c7565b838660600151116124b7575f6124c7565b8386606001516124c7919061357b565b90505f5b818110156125c35760405163096a643360e11b81525f906001600160a01b038516906312d4c86690612501908c90600401612ec3565b602060405180830381865afa15801561251c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125409190613713565b604051630852cd8d60e31b8152600481018290529091506001600160a01b038516906342966c68906024015f604051808303815f87803b158015612582575f80fd5b505af1158015612594573d5f803e3d5ffd5b505050506125ba85600601866007015f81546125af906135af565b918290555083612271565b506001016124cb565b5050505b505b50506001600d555050565b6001600160a01b0381165f818152600b6020526040808220805460ff19166001179055517fdcc4d7bff655001015f308c794375175b9e1616a6ca241b536e472ac47f93f769190a250565b5f815f036126395761263284845f612b22565b905061077e565b6126468484846001612bfc565b9150612653848484612b22565b949350505050565b6001600160a01b0381165f818152600c6020526040808220805460ff19166001179055517f13d186064a60bb5c6c906315fa4b26bc5107ed969f69895c70fefafbeeb591759190a250565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f5f6040516126d6919061377c565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b900490565b5f8160e001511561280957601254602083015160408085015185519151634ace39d760e01b81525f9461010090046001600160a01b031693634ace39d79361279393919230918b916004016137ee565b6020604051808303815f875af11580156127af573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127d39190613849565b60808401515f908152600e6020526040902080546001600160a01b0319166001600160a01b0392909216919091179055506128c0565b6012546020830151604080850151855191516313e6d20960e11b81525f9461010090046001600160a01b0316936327cda4129361284e93919230918b916004016137ee565b6020604051808303815f875af115801561286a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061288e9190613849565b60808401515f908152600e6020526040902080546001600160a01b0319166001600160a01b0392909216919091179055505b50608001515f908152600e60205260409020546001600160a01b0316919050565b5f815f036128fa576128f3835f612dd3565b9050610502565b6129063384845f612bfc565b915061077e8383612dd3565b604080516001600160a01b0386811660248301528581166044830152606482018590526084820184905260a060a48301525f60c48084018290528451808503909101815260e490930184526020830180516001600160e01b031663f23a6e6160e01b179052925183918291908a169061298c908590613864565b5f604051808303815f865af19150503d805f81146129c5576040519150601f19603f3d011682016040523d82523d5f602084013e6129ca565b606091505b50915091508180156129de57506020815110155b15612a17575f818060200190518101906129f8919061387f565b6001600160e01b03191663f23a6e6160e01b149450612a1e9350505050565b5f93505050505b95945050505050565b5f8063150b7a0260e01b86868686604051602401612a4894939291906138a6565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505090505f80886001600160a01b031683604051612a979190613864565b5f604051808303815f865af19150503d805f8114612ad0576040519150601f19603f3d011682016040523d82523d5f602084013e612ad5565b606091505b5091509150818015612ae957506020815110155b15612a17575f81806020019051810190612b03919061387f565b6001600160e01b031916630a85bd0160e11b149450612a1e9350505050565b6001600160a01b0383165f9081526004602090815260408083203384529091528120545f198114612b7b57612b57838261357b565b6001600160a01b0386165f9081526004602090815260408083203384529091529020555b6001600160a01b0385165f9081526003602052604081208054859290612ba290849061357b565b90915550506001600160a01b038085165f81815260036020526040908190208054870190555190918716905f805160206138e383398151915290612be99087815260200190565b60405180910390a3506001949350505050565b6006545f9060ff16158015612c1c57506007546001600160a01b03163314155b15612c3a5760405163486aa30760e01b815260040160405180910390fd5b6001600160a01b0385165f908152600c602052604081205460ff168015612c7857506001600160a01b0385165f908152600c602052604090205460ff165b6001600160a01b0387165f908152600b602052604090205490915060ff16158015612cbb57506001600160a01b0385165f908152600b602052604090205460ff16155b8015612cc5575080155b8015612ce857506001600160a01b0386165f908152600c602052604090205460ff165b15612dc9576009545f90612d00908690612710612e36565b90505f612d1c600a5461271088612e369092919063ffffffff16565b905080612d29838861357b565b612d33919061357b565b95508415612d85578115612d6057600654612d5e90899061010090046001600160a01b031684612b22565b505b8015612d8057600854612d7e9089906001600160a01b031683612b22565b505b612dc6565b8115612da857600654612da69061010090046001600160a01b031683612dd3565b505b8015612dc657600854612dc4906001600160a01b031682612dd3565b505b50505b5091949350505050565b335f90815260036020526040812080548391908390612df390849061357b565b90915550506001600160a01b0383165f81815260036020526040908190208054850190555133905f805160206138e3833981519152906104f69086815260200190565b5f825f190484118302158202612e535763ad251c275f526004601cfd5b5091020490565b604051806101400160405280606081526020015f81526020015f81526020015f81526020015f151581526020015f6001600160a01b031681526020015f8152602001612eb160405180602001604052805f81525090565b81526020015f81526020015f81525090565b6001600160a01b0391909116815260200190565b5f5b83811015612ef1578181015183820152602001612ed9565b50505f910152565b5f8151808452612f10816020860160208601612ed7565b601f01601f19169290920160200192915050565b602081525f61077e6020830184612ef9565b6001600160a01b0381168114610851575f80fd5b5f8060408385031215612f5b575f80fd5b8235612f6681612f36565b946020939093013593505050565b5f60208284031215612f84575f80fd5b813561077e81612f36565b5f805f60608486031215612fa1575f80fd5b8335612fac81612f36565b92506020840135612fbc81612f36565b929592945050506040919091013590565b5f60208284031215612fdd575f80fd5b5035919050565b5f8083601f840112612ff4575f80fd5b5081356001600160401b0381111561300a575f80fd5b6020830191508360208260051b8501011115613024575f80fd5b9250929050565b5f805f805f805f805f60e08a8c031215613043575f80fd5b893561304e81612f36565b985060208a013561305e81612f36565b975060408a0135965060608a0135955060808a013561307c81612f36565b945060a08a01356001600160401b0380821115613097575f80fd5b6130a38d838e01612fe4565b909650945060c08c01359150808211156130bb575f80fd5b506130c88c828d01612fe4565b915080935050809150509295985092959850929598565b602081525f82516101408060208501526130fd610160850183612ef9565b9150602085015160408501526040850151606085015260608501516080850152608085015161313060a086018215159052565b5060a08501516001600160a01b03811660c08601525060c085015160e085015260e085015161010061316481870183519052565b860151610120868101919091529095015193019290925250919050565b634e487b7160e01b5f52604160045260245ffd5b60405161010081016001600160401b03811182821017156131b8576131b8613181565b60405290565b604051601f8201601f191681016001600160401b03811182821017156131e6576131e6613181565b604052919050565b5f6001600160401b0382111561320657613206613181565b5060051b60200190565b5f82601f83011261321f575f80fd5b81356001600160401b0381111561323857613238613181565b61324b601f8201601f19166020016131be565b81815284602083860101111561325f575f80fd5b816020850160208301375f918101602001919091529392505050565b8035801515811461328a575f80fd5b919050565b5f82601f83011261329e575f80fd5b813560206132b36132ae836131ee565b6131be565b8083825260208201915060208460051b8701019350868411156132d4575f80fd5b602086015b848110156132f95780356132ec81612f36565b83529183019183016132d9565b509695505050505050565b5f8060408385031215613315575f80fd5b82356001600160401b038082111561332b575f80fd5b818501915085601f83011261333e575f80fd5b8135602061334e6132ae836131ee565b82815260059290921b8401810191818101908984111561336c575f80fd5b8286015b8481101561345a57803586811115613386575f80fd5b8701610100818d03601f190181131561339d575f80fd5b6133a5613195565b86830135898111156133b5575f80fd5b6133c38f8983870101613210565b8252506040830135898111156133d7575f80fd5b6133e58f8983870101613210565b88830152506060830135898111156133fb575f80fd5b6134098f8983870101613210565b604083015250608080840135606083015260a0808501358284015260c0915081850135818401525060e0808501358284015261344684860161327b565b908301525085525050918301918301613370565b5096505086013592505080821115613470575f80fd5b5061347d8582860161328f565b9150509250929050565b5f805f805f805f60e0888a03121561349d575f80fd5b87356134a881612f36565b965060208801356134b881612f36565b95506040880135945060608801359350608088013560ff811681146134db575f80fd5b9699959850939692959460a0840135945060c09093013592915050565b5f8060408385031215613509575f80fd5b823561351481612f36565b9150602083013561352481612f36565b809150509250929050565b600181811c9082168061354357607f821691505b60208210810361356157634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561050257610502613567565b6001600160a01b039390931683526020830191909152604082015260600190565b5f600182016135c0576135c0613567565b5060010190565b634e487b7160e01b5f52603260045260245ffd5b6001600160a01b0392831681529116602082015260400190565b8082018082111561050257610502613567565b601f82111561364f57805f5260205f20601f840160051c8101602085101561362d5750805b601f840160051c820191505b8181101561364c575f8155600101613639565b50505b505050565b81516001600160401b0381111561366d5761366d613181565b6136818161367b845461352f565b84613608565b602080601f8311600181146136b4575f841561369d5750858301515b5f19600386901b1c1916600185901b17855561370b565b5f85815260208120601f198616915b828110156136e2578886015182559484019460019091019084016136c3565b50858210156136ff57878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b5f60208284031215613723575f80fd5b5051919050565b6001600160a01b03929092168252602082015260400190565b5f8161375157613751613567565b505f190190565b6020808252600a90820152695245454e5452414e435960b01b604082015260600190565b5f8083546137898161352f565b600182811680156137a157600181146137b6576137e2565b60ff19841687528215158302870194506137e2565b875f526020805f205f5b858110156137d95781548a8201529084019082016137c0565b50505082870194505b50929695505050505050565b60a081525f61380060a0830188612ef9565b82810360208401526138128188612ef9565b6001600160a01b038781166040860152861660608501528381036080850152905061383d8185612ef9565b98975050505050505050565b5f60208284031215613859575f80fd5b815161077e81612f36565b5f8251613875818460208701612ed7565b9190910192915050565b5f6020828403121561388f575f80fd5b81516001600160e01b03198116811461077e575f80fd5b6001600160a01b03858116825284166020820152604081018390526080606082018190525f906138d890830184612ef9565b969550505050505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a2646970667358221220e3e24853e7ab6bf4d6dabdbfe36d92d3ea1b25aca81257d06213cfa3e7beb70f64736f6c6343000817003300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000002cd3c02a734559472d91b285b544202a3c8b129e000000000000000000000000a2aace327172f303ab431455469cd65f3b5b63510000000000000000000000009401ae767955581e3ad0910d0e3651a2fcb37301000000000000000000000000000000000000000000000000000000000000001d554e434841494e454420454c455048414e5453203430342024454c695a0000000000000000000000000000000000000000000000000000000000000000000004454c495a00000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561000f575f80fd5b5060043610610152575f3560e01c806302d05d3f1461015657806306fdde0314610184578063095ea7b3146101995780630ee7642d146101bc578063129763c2146101e757806318160ddd146101fa5780631ac5f606146102115780631cdd35c91461022657806323b872dd1461023957806324a9d8531461024c57806329a771f314610255578063313ce567146102685780633644e515146102a15780634f062c5a146102a957806358e47004146102c95780636605bfda146102dc5780636da2d116146102ef57806370a082311461031757806372a4ff75146103365780637ecebe00146103495780639127cc691461036857806395d89b411461037b5780639a195a1314610383578063a9059cbb14610396578063ad5dff73146103a9578063c0417e58146103d4578063d505accf146103e7578063dd62ed3e146103fa575b5f80fd5b60065461016e9061010090046001600160a01b031681565b60405161017b9190612ec3565b60405180910390f35b61018c610424565b60405161017b9190612f24565b6101ac6101a7366004612f4a565b6104af565b604051901515815260200161017b565b6101ac6101ca366004612f74565b6001600160a01b03165f908152600c602052604090205460ff1690565b6101ac6101f5366004612f8f565b610508565b61020360025481565b60405190815260200161017b565b61022461021f366004612fcd565b610785565b005b610224610234366004612f74565b610818565b6101ac610247366004612f8f565b610854565b61020360095481565b61022461026336600461302b565b6108cc565b61028f7f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff909116815260200161017b565b610203610a03565b6102bc6102b7366004612fcd565b610a5d565b60405161017b91906130df565b6102246102d7366004612f74565b610b94565b6102246102ea366004612f74565b610c4f565b61016e6102fd366004612fcd565b600e6020525f90815260409020546001600160a01b031681565b610203610325366004612f74565b60036020525f908152604090205481565b610224610344366004613304565b610d0a565b610203610357366004612f74565b60056020525f908152604090205481565b610224610376366004612f74565b6115f2565b61018c611698565b610224610391366004612f74565b6116a5565b6101ac6103a4366004612f4a565b6116de565b6101ac6103b7366004612f74565b6001600160a01b03165f908152600b602052604090205460ff1690565b6102246103e2366004612fcd565b611754565b6102246103f5366004613487565b6117e2565b6102036104083660046134f8565b600460209081525f928352604080842090915290825290205481565b5f80546104309061352f565b80601f016020809104026020016040519081016040528092919081815260200182805461045c9061352f565b80156104a75780601f1061047e576101008083540402835291602001916104a7565b820191905f5260205f20905b81548152906001019060200180831161048a57829003601f168201915b505050505081565b335f8181526004602090815260408083206001600160a01b038716808552925280832085905551919290915f80516020613903833981519152906104f69086815260200190565b60405180910390a35060015b92915050565b5f806105143384611a0c565b60a08101519091506001600160a01b03166105425760405163043d000960e51b815260040160405180910390fd5b5f61054c85611c3b565b60608301516001600160a01b0388165f9081526003602052604081208054939450919261057a90849061357b565b909155505060608201516001600160a01b0386165f90815260036020526040812080549092019091556105ac87611c3b565b90505f6105b887611c3b565b90506105c48883611e68565b80515f1280156105da5750805161012085015114155b156106e557836080015115610650578360a001516001600160a01b031663f5298aca888860016040518463ffffffff1660e01b815260040161061e9392919061358e565b5f604051808303815f87803b158015610635575f80fd5b505af1158015610647573d5f803e3d5ffd5b505050506106e5565b60a0840151604051630852cd8d60e31b8152600481018890526001600160a01b03909116906342966c68906024015f604051808303815f87803b158015610695575f80fd5b505af11580156106a7573d5f803e3d5ffd5b5050506101208501515f908152600f602052604081206007810180549193506106e39260068501926106d8906135af565b918290555089612271565b505b82518151146107375782604001516001600160a01b03168460a001516001600160a01b0316036107215761071c878483600161229c565b61072d565b61072d8784835f61229c565b6107378782611e68565b866001600160a01b0316886001600160a01b03165f805160206138e3833981519152866060015160405161076d91815260200190565b60405180910390a360019450505050505b9392505050565b60065461010090046001600160a01b031633146107b5576040516308f78f9960e31b815260040160405180910390fd5b60508111156107d757604051632a52987760e21b815260040160405180910390fd5b60095460408051918252602082018390527f0a8167de874bdafbcdb7afb1989f0a655113928c1f558cfcd8062e4590929db6910160405180910390a1600955565b60065461010090046001600160a01b03163314610848576040516308f78f9960e31b815260040160405180910390fd5b610851816125d4565b50565b5f8061085f85611c3b565b90505f61086b85611c3b565b90505f61087987878761261f565b90505f61088588611c3b565b90505f61089188611c3b565b905061089f8986845f61229c565b6108ab8885835f61229c565b6108b58983611e68565b6108bf8882611e68565b5090979650505050505050565b6007546001600160a01b031633146108f75760405163d35a97ab60e01b815260040160405180910390fd5b60065460ff161561091a5760405162dc149f60e41b815260040160405180910390fd5b6006805460ff191660011790556009869055600a879055600880546001600160a01b038a166001600160a01b03199091168117909155610959906125d4565b610962896125d4565b5f5b838110156109a35761099b858583818110610981576109816135c7565b90506020020160208101906109969190612f74565b61265b565b600101610964565b506109ad8561265b565b5f5b818110156109ee576109e68383838181106109cc576109cc6135c7565b90506020020160208101906109e19190612f74565b6125d4565b6001016109af565b506109f889610b94565b505050505050505050565b5f7f00000000000000000000000000000000000000000000000000000000000021054614610a3857610a336126a6565b905090565b507f2f1e7a2bbe02d952b525dfe2ed55bb54ff644817c2125b02f206d7312013e43e90565b610a65612e5a565b5f828152600f60205260409081902081516101408101909252805482908290610a8d9061352f565b80601f0160208091040260200160405190810160405280929190818152602001828054610ab99061352f565b8015610b045780601f10610adb57610100808354040283529160200191610b04565b820191905f5260205f20905b815481529060010190602001808311610ae757829003601f168201915b50505091835250506001820154602080830191909152600283015460408084019190915260038401546060840152600484015460ff8116151560808501526001600160a01b03610100918290041660a0850152600585015460c085015281519283019091526006840154825260e08301919091526007830154908201526008909101546101209091015292915050565b6007546001600160a01b03163314610bbf5760405163d35a97ab60e01b815260040160405180910390fd5b6001600160a01b038116610be657604051639fabe1c160e01b815260040160405180910390fd5b6007546040517f2756814479f687d805be12ef7dfd27c72bc645462236412ee56a627f389e4e3391610c25916001600160a01b039091169084906135db565b60405180910390a1600780546001600160a01b0319166001600160a01b0392909216919091179055565b6007546001600160a01b03163314610c7a5760405163d35a97ab60e01b815260040160405180910390fd5b6001600160a01b038116610ca157604051639fabe1c160e01b815260040160405180910390fd5b6008546040517f4ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a91610ce0916001600160a01b039091169084906135db565b60405180910390a1600880546001600160a01b0319166001600160a01b0392909216919091179055565b60125460ff1615610d2e57604051634a0dba0760e11b815260040160405180910390fd5b6012805460ff1916600117905581515f03610d5c57604051631e8e92af60e21b815260040160405180910390fd5b600982511115610d7f5760405163335b59ab60e11b815260040160405180910390fd5b5f5b825181101561158e57828181518110610d9c57610d9c6135c7565b602002602001015160a001515f03610dc75760405163111bcb0160e01b815260040160405180910390fd5b828181518110610dd957610dd96135c7565b6020026020010151606001515f1480610e105750600254838281518110610e0257610e026135c7565b602002602001015160600151115b15610e2e57604051632324d1df60e01b815260040160405180910390fd5b63ffffffff8016838281518110610e4757610e476135c7565b602002602001015160c0015110610e71576040516376b5325960e11b815260040160405180910390fd5b828181518110610e8357610e836135c7565b602002602001015160e0015115610ef357828181518110610ea657610ea66135c7565b602002602001015160c00151838281518110610ec457610ec46135c7565b602002602001015160a0015114610eee576040516301304d1b60e41b815260040160405180910390fd5b610ff5565b828181518110610f0557610f056135c7565b602002602001015160c00151838281518110610f2357610f236135c7565b602002602001015160a0015110610f4d57604051636eebf03560e01b815260040160405180910390fd5b5f610f80848381518110610f6357610f636135c7565b60200260200101516060015160025461273e90919063ffffffff16565b905080848381518110610f9557610f956135c7565b602002602001015160a00151858481518110610fb357610fb36135c7565b602002602001015160c00151610fc9919061357b565b610fd49060016135f5565b1015610ff35760405163e1ace8ad60e01b815260040160405180910390fd5b505b5f600e5f85848151811061100b5761100b6135c7565b60200260200101516080015181526020019081526020015f205f9054906101000a90046001600160a01b031690505f604051806101400160405280868581518110611058576110586135c7565b60200260200101515f0151815260200186858151811061107a5761107a6135c7565b602002602001015160a00151815260200186858151811061109d5761109d6135c7565b602002602001015160c0015181526020018685815181106110c0576110c06135c7565b60200260200101516060015181526020018685815181106110e3576110e36135c7565b602002602001015160e00151151581526020015f6001600160a01b03168152602001868581518110611117576111176135c7565b602002602001015160e0015161114a57868581518110611139576111396135c7565b602002602001015160a0015161114c565b5f5b815260200160405180602001604052805f81525081526020015f815260200184600161117891906135f5565b90529050821561146c575f838152600f6020526040808220815161014081019092528054829082906111a99061352f565b80601f01602080910402602001604051908101604052809291908181526020018280546111d59061352f565b80156112205780601f106111f757610100808354040283529160200191611220565b820191905f5260205f20905b81548152906001019060200180831161120357829003601f168201915b50505091835250506001820154602080830191909152600283015460408084019190915260038401546060840152600484015460ff8116151560808501526001600160a01b03610100918290041660a0850152600585015460c085015281519283019091526006840154825260e08301919091526007830154908201526008909101546101209091015286519091508690859081106112c1576112c16135c7565b602002602001015160800151866001866112db919061357b565b815181106112eb576112eb6135c7565b602002602001015160800151111561131657604051638080c2ed60e01b815260040160405180910390fd5b858481518110611328576113286135c7565b60200260200101516080015186600186611342919061357b565b81518110611352576113526135c7565b6020026020010151608001511480156113b55750858481518110611378576113786135c7565b602002602001015160e00151151586600186611394919061357b565b815181106113a4576113a46135c7565b602002602001015160e00151151514155b156113d357604051638080c2ed60e01b815260040160405180910390fd5b81606001518160600151106113fb57604051632324d1df60e01b815260040160405180910390fd5b806080015115801561140e575081608001515b1561142c57604051632b76654560e11b815260040160405180910390fd5b6001600160a01b0383161580159061144c57508160200151816040015110155b1561146a57604051636eebf03560e01b815260040160405180910390fd5b505b6001600160a01b0382166114b7576114b2600660019054906101000a90046001600160a01b03168685815181106114a5576114a56135c7565b6020026020010151612743565b6114b9565b815b6001600160a01b031660a082015280600f5f6114d68660016135f5565b815260208101919091526040015f20815181906114f39082613654565b5060208201516001828101919091556040830151600283015560608301516003830155608083015160048301805460a08601516001600160a81b0319909116921515610100600160a81b031916929092176101006001600160a01b03909316830217905560c0840151600584015560e0840151516006840155830151600783015561012090920151600890910155929092019150610d819050565b505f5b81518110156115ea57600160105f8484815181106115b1576115b16135c7565b6020908102919091018101516001600160a01b031682528101919091526040015f20805460ff1916911515919091179055600101611591565b505051601155565b60065461010090046001600160a01b03163314611622576040516308f78f9960e31b815260040160405180910390fd5b7f4c1d69ffe6fad068e437c6e17f4068f125ab0b7e50bec2d7f4519d7ab1ee504f600660019054906101000a90046001600160a01b0316826040516116689291906135db565b60405180910390a1600680546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600180546104309061352f565b60065461010090046001600160a01b031633146116d5576040516308f78f9960e31b815260040160405180910390fd5b6108518161265b565b5f806116e933611c3b565b90505f6116f585611c3b565b90505f61170286866128e1565b90505f61170e33611c3b565b90505f61171a88611c3b565b90506117283386845f61229c565b6117348885835f61229c565b61173e3383611e68565b6117488882611e68565b50909695505050505050565b6007546001600160a01b0316331461177f5760405163d35a97ab60e01b815260040160405180910390fd5b60328111156117a15760405163499fddb160e01b815260040160405180910390fd5b600a5460408051918252602082018390527fe9c032fb7419b343f83add64d4513ecbd7602547133916538d3f3f12a061a30e910160405180910390a1600a55565b428410156118315760405162461bcd60e51b815260206004820152601760248201527614115493525517d11150511312539157d1561412549151604a1b60448201526064015b60405180910390fd5b5f600161183c610a03565b6001600160a01b038a81165f8181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f1981840301815282825280516020918201205f84529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611944573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b0381161580159061197a5750876001600160a01b0316816001600160a01b0316145b6119b75760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401611828565b6001600160a01b039081165f9081526004602090815260408083208a8516808552908352928190208990555188815291928a16915f80516020613903833981519152910160405180910390a350505050505050565b611a14612e5a565b60015b6011548111611bc5575f818152600f602052604080822081516101408101909252805482908290611a479061352f565b80601f0160208091040260200160405190810160405280929190818152602001828054611a739061352f565b8015611abe5780601f10611a9557610100808354040283529160200191611abe565b820191905f5260205f20905b815481529060010190602001808311611aa157829003601f168201915b50505091835250506001820154602080830191909152600283015460408084019190915260038401546060840152600484015460ff8116151560808501526001600160a01b0361010091829004811660a080870191909152600587015460c087015283519485019093526006860154845260e0850193909352600785015490840152600890930154610120909201919091529082015191925090811690861614611b685750611bb3565b806080015115611b8b5783816020015103611b865791506105029050565b611bb1565b80602001518410158015611ba3575080604001518411155b15611bb15791506105029050565b505b80611bbd816135af565b915050611a17565b5060405180610140016040528060405180602001604052805f81525081526020015f81526020015f81526020015f81526020015f151581526020015f6001600160a01b031681526020015f815260200160405180602001604052805f81525081526020015f81526020015f815250905092915050565b611c6b60405180608001604052805f81526020015f81526020015f6001600160a01b031681526020015f81525090565b6001600160a01b03821615611e36576001600160a01b0382165f908152600360205260409020546011545b8015611e33575f818152600f60205260409020600301548210611e2157604080516080810182525f838152600f60208181528483206008810154855260038101548804828601526004015461010081046001600160a01b03169585019590955291859052905290606082019060ff16611d90575f838152600f60205260409081902060049081015491516370a0823160e01b81526101009092046001600160a01b0316916370a0823191611d4c918a9101612ec3565b602060405180830381865afa158015611d67573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d8b9190613713565b611e17565b5f838152600f6020526040908190206004808201546001909201549251627eeac760e11b81526101009092046001600160a01b03169262fdd58e92611dd8928b92910161372a565b602060405180830381865afa158015611df3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e179190613713565b9052949350505050565b80611e2b81613743565b915050611c96565b50505b60405180608001604052805f1981526020015f81526020015f6001600160a01b031681526020015f8152509050919050565b600d54600114611e8a5760405162461bcd60e51b815260040161182890613758565b6002600d5580515f1380611ea557506001600160a01b038216155b80611ec757506001600160a01b0382165f9081526010602052604090205460ff165b6122685780515f908152600f60205260409020600481015460ff1615612021576001600160a01b0383163b15801590611f0f5750611f0d83335f84600101546001612912565b155b15611f1a5750612268565b600481810154600180840154604051627eeac760e11b81526101009093046001600160a01b0316939192849262fdd58e92611f57928a920161372a565b602060405180830381865afa158015611f72573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f969190613713565b10611fa2575050612268565b60018281015460405163731133e960e01b81526001600160a01b03878116600483015260248201929092526044810192909252608060648301525f608483015282169063731133e99060a4015f604051808303815f87803b158015612005575f80fd5b505af1158015612017573d5f803e3d5ffd5b5050505050612266565b6001600160a01b0383163b15801590612056575061205483335f846001015460405180602001604052805f815250612a27565b155b156120615750612268565b6004818101546040516370a0823160e01b81526101009091046001600160a01b0316915f9183916370a082319161209a91899101612ec3565b602060405180830381865afa1580156120b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120d99190613713565b8460200151116120e9575f612163565b6040516370a0823160e01b81526001600160a01b038316906370a0823190612115908890600401612ec3565b602060405180830381865afa158015612130573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121549190613713565b8460200151612163919061357b565b90505f5b81811015612262575f846002015485600501541161219b57600585018054905f612190836135af565b9190505590506121fa565b84600701545f036121b0575050505050612268565b6007850180546121f1916006880191905f6121ca83613743565b919050555f8160031c8360601b0180546007841660051b1c63ffffffff1691505092915050565b63ffffffff1690505b6040516340c10f1960e01b81526001600160a01b038516906340c10f1990612228908a90859060040161372a565b5f604051808303815f87803b15801561223f575f80fd5b505af1158015612251573d5f803e3d5ffd5b505060019093019250612167915050565b5050505b505b50506001600d55565b8160031c8360601b016007831660051b815480821c841863ffffffff16821b81188355505050505050565b600d546001146122be5760405162461bcd60e51b815260040161182890613758565b6002600d5582515f13806122d957506001600160a01b038416155b6125c95782515f908152600f60205260409020600481015460ff1615612457576004818101546001830154604051627eeac760e11b81526101009092046001600160a01b031692839262fdd58e92612333928b920161372a565b602060405180830381865afa15801561234e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123729190613713565b158061237f575083518551145b1561238b5750506125c9565b6001820154604051627eeac760e11b81526001600160a01b0383169163f5298aca91899190849062fdd58e906123c7908590859060040161372a565b602060405180830381865afa1580156123e2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124069190613713565b6040518463ffffffff1660e01b81526004016124249392919061358e565b5f604051808303815f87803b15801561243b575f80fd5b505af115801561244d573d5f803e3d5ffd5b50505050506125c7565b6004810154835185516101009092046001600160a01b0316915f9190036124a657846020015185606001511161248d575f6124c7565b846020015185606001516124a1919061357b565b6124c7565b838660600151116124b7575f6124c7565b8386606001516124c7919061357b565b90505f5b818110156125c35760405163096a643360e11b81525f906001600160a01b038516906312d4c86690612501908c90600401612ec3565b602060405180830381865afa15801561251c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125409190613713565b604051630852cd8d60e31b8152600481018290529091506001600160a01b038516906342966c68906024015f604051808303815f87803b158015612582575f80fd5b505af1158015612594573d5f803e3d5ffd5b505050506125ba85600601866007015f81546125af906135af565b918290555083612271565b506001016124cb565b5050505b505b50506001600d555050565b6001600160a01b0381165f818152600b6020526040808220805460ff19166001179055517fdcc4d7bff655001015f308c794375175b9e1616a6ca241b536e472ac47f93f769190a250565b5f815f036126395761263284845f612b22565b905061077e565b6126468484846001612bfc565b9150612653848484612b22565b949350505050565b6001600160a01b0381165f818152600c6020526040808220805460ff19166001179055517f13d186064a60bb5c6c906315fa4b26bc5107ed969f69895c70fefafbeeb591759190a250565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f5f6040516126d6919061377c565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b900490565b5f8160e001511561280957601254602083015160408085015185519151634ace39d760e01b81525f9461010090046001600160a01b031693634ace39d79361279393919230918b916004016137ee565b6020604051808303815f875af11580156127af573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127d39190613849565b60808401515f908152600e6020526040902080546001600160a01b0319166001600160a01b0392909216919091179055506128c0565b6012546020830151604080850151855191516313e6d20960e11b81525f9461010090046001600160a01b0316936327cda4129361284e93919230918b916004016137ee565b6020604051808303815f875af115801561286a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061288e9190613849565b60808401515f908152600e6020526040902080546001600160a01b0319166001600160a01b0392909216919091179055505b50608001515f908152600e60205260409020546001600160a01b0316919050565b5f815f036128fa576128f3835f612dd3565b9050610502565b6129063384845f612bfc565b915061077e8383612dd3565b604080516001600160a01b0386811660248301528581166044830152606482018590526084820184905260a060a48301525f60c48084018290528451808503909101815260e490930184526020830180516001600160e01b031663f23a6e6160e01b179052925183918291908a169061298c908590613864565b5f604051808303815f865af19150503d805f81146129c5576040519150601f19603f3d011682016040523d82523d5f602084013e6129ca565b606091505b50915091508180156129de57506020815110155b15612a17575f818060200190518101906129f8919061387f565b6001600160e01b03191663f23a6e6160e01b149450612a1e9350505050565b5f93505050505b95945050505050565b5f8063150b7a0260e01b86868686604051602401612a4894939291906138a6565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505090505f80886001600160a01b031683604051612a979190613864565b5f604051808303815f865af19150503d805f8114612ad0576040519150601f19603f3d011682016040523d82523d5f602084013e612ad5565b606091505b5091509150818015612ae957506020815110155b15612a17575f81806020019051810190612b03919061387f565b6001600160e01b031916630a85bd0160e11b149450612a1e9350505050565b6001600160a01b0383165f9081526004602090815260408083203384529091528120545f198114612b7b57612b57838261357b565b6001600160a01b0386165f9081526004602090815260408083203384529091529020555b6001600160a01b0385165f9081526003602052604081208054859290612ba290849061357b565b90915550506001600160a01b038085165f81815260036020526040908190208054870190555190918716905f805160206138e383398151915290612be99087815260200190565b60405180910390a3506001949350505050565b6006545f9060ff16158015612c1c57506007546001600160a01b03163314155b15612c3a5760405163486aa30760e01b815260040160405180910390fd5b6001600160a01b0385165f908152600c602052604081205460ff168015612c7857506001600160a01b0385165f908152600c602052604090205460ff165b6001600160a01b0387165f908152600b602052604090205490915060ff16158015612cbb57506001600160a01b0385165f908152600b602052604090205460ff16155b8015612cc5575080155b8015612ce857506001600160a01b0386165f908152600c602052604090205460ff165b15612dc9576009545f90612d00908690612710612e36565b90505f612d1c600a5461271088612e369092919063ffffffff16565b905080612d29838861357b565b612d33919061357b565b95508415612d85578115612d6057600654612d5e90899061010090046001600160a01b031684612b22565b505b8015612d8057600854612d7e9089906001600160a01b031683612b22565b505b612dc6565b8115612da857600654612da69061010090046001600160a01b031683612dd3565b505b8015612dc657600854612dc4906001600160a01b031682612dd3565b505b50505b5091949350505050565b335f90815260036020526040812080548391908390612df390849061357b565b90915550506001600160a01b0383165f81815260036020526040908190208054850190555133905f805160206138e3833981519152906104f69086815260200190565b5f825f190484118302158202612e535763ad251c275f526004601cfd5b5091020490565b604051806101400160405280606081526020015f81526020015f81526020015f81526020015f151581526020015f6001600160a01b031681526020015f8152602001612eb160405180602001604052805f81525090565b81526020015f81526020015f81525090565b6001600160a01b0391909116815260200190565b5f5b83811015612ef1578181015183820152602001612ed9565b50505f910152565b5f8151808452612f10816020860160208601612ed7565b601f01601f19169290920160200192915050565b602081525f61077e6020830184612ef9565b6001600160a01b0381168114610851575f80fd5b5f8060408385031215612f5b575f80fd5b8235612f6681612f36565b946020939093013593505050565b5f60208284031215612f84575f80fd5b813561077e81612f36565b5f805f60608486031215612fa1575f80fd5b8335612fac81612f36565b92506020840135612fbc81612f36565b929592945050506040919091013590565b5f60208284031215612fdd575f80fd5b5035919050565b5f8083601f840112612ff4575f80fd5b5081356001600160401b0381111561300a575f80fd5b6020830191508360208260051b8501011115613024575f80fd5b9250929050565b5f805f805f805f805f60e08a8c031215613043575f80fd5b893561304e81612f36565b985060208a013561305e81612f36565b975060408a0135965060608a0135955060808a013561307c81612f36565b945060a08a01356001600160401b0380821115613097575f80fd5b6130a38d838e01612fe4565b909650945060c08c01359150808211156130bb575f80fd5b506130c88c828d01612fe4565b915080935050809150509295985092959850929598565b602081525f82516101408060208501526130fd610160850183612ef9565b9150602085015160408501526040850151606085015260608501516080850152608085015161313060a086018215159052565b5060a08501516001600160a01b03811660c08601525060c085015160e085015260e085015161010061316481870183519052565b860151610120868101919091529095015193019290925250919050565b634e487b7160e01b5f52604160045260245ffd5b60405161010081016001600160401b03811182821017156131b8576131b8613181565b60405290565b604051601f8201601f191681016001600160401b03811182821017156131e6576131e6613181565b604052919050565b5f6001600160401b0382111561320657613206613181565b5060051b60200190565b5f82601f83011261321f575f80fd5b81356001600160401b0381111561323857613238613181565b61324b601f8201601f19166020016131be565b81815284602083860101111561325f575f80fd5b816020850160208301375f918101602001919091529392505050565b8035801515811461328a575f80fd5b919050565b5f82601f83011261329e575f80fd5b813560206132b36132ae836131ee565b6131be565b8083825260208201915060208460051b8701019350868411156132d4575f80fd5b602086015b848110156132f95780356132ec81612f36565b83529183019183016132d9565b509695505050505050565b5f8060408385031215613315575f80fd5b82356001600160401b038082111561332b575f80fd5b818501915085601f83011261333e575f80fd5b8135602061334e6132ae836131ee565b82815260059290921b8401810191818101908984111561336c575f80fd5b8286015b8481101561345a57803586811115613386575f80fd5b8701610100818d03601f190181131561339d575f80fd5b6133a5613195565b86830135898111156133b5575f80fd5b6133c38f8983870101613210565b8252506040830135898111156133d7575f80fd5b6133e58f8983870101613210565b88830152506060830135898111156133fb575f80fd5b6134098f8983870101613210565b604083015250608080840135606083015260a0808501358284015260c0915081850135818401525060e0808501358284015261344684860161327b565b908301525085525050918301918301613370565b5096505086013592505080821115613470575f80fd5b5061347d8582860161328f565b9150509250929050565b5f805f805f805f60e0888a03121561349d575f80fd5b87356134a881612f36565b965060208801356134b881612f36565b95506040880135945060608801359350608088013560ff811681146134db575f80fd5b9699959850939692959460a0840135945060c09093013592915050565b5f8060408385031215613509575f80fd5b823561351481612f36565b9150602083013561352481612f36565b809150509250929050565b600181811c9082168061354357607f821691505b60208210810361356157634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561050257610502613567565b6001600160a01b039390931683526020830191909152604082015260600190565b5f600182016135c0576135c0613567565b5060010190565b634e487b7160e01b5f52603260045260245ffd5b6001600160a01b0392831681529116602082015260400190565b8082018082111561050257610502613567565b601f82111561364f57805f5260205f20601f840160051c8101602085101561362d5750805b601f840160051c820191505b8181101561364c575f8155600101613639565b50505b505050565b81516001600160401b0381111561366d5761366d613181565b6136818161367b845461352f565b84613608565b602080601f8311600181146136b4575f841561369d5750858301515b5f19600386901b1c1916600185901b17855561370b565b5f85815260208120601f198616915b828110156136e2578886015182559484019460019091019084016136c3565b50858210156136ff57878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b5f60208284031215613723575f80fd5b5051919050565b6001600160a01b03929092168252602082015260400190565b5f8161375157613751613567565b505f190190565b6020808252600a90820152695245454e5452414e435960b01b604082015260600190565b5f8083546137898161352f565b600182811680156137a157600181146137b6576137e2565b60ff19841687528215158302870194506137e2565b875f526020805f205f5b858110156137d95781548a8201529084019082016137c0565b50505082870194505b50929695505050505050565b60a081525f61380060a0830188612ef9565b82810360208401526138128188612ef9565b6001600160a01b038781166040860152861660608501528381036080850152905061383d8185612ef9565b98975050505050505050565b5f60208284031215613859575f80fd5b815161077e81612f36565b5f8251613875818460208701612ed7565b9190910192915050565b5f6020828403121561388f575f80fd5b81516001600160e01b03198116811461077e575f80fd5b6001600160a01b03858116825284166020820152604081018390526080606082018190525f906138d890830184612ef9565b969550505050505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a2646970667358221220e3e24853e7ab6bf4d6dabdbfe36d92d3ea1b25aca81257d06213cfa3e7beb70f64736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000002cd3c02a734559472d91b285b544202a3c8b129e000000000000000000000000a2aace327172f303ab431455469cd65f3b5b63510000000000000000000000009401ae767955581e3ad0910d0e3651a2fcb37301000000000000000000000000000000000000000000000000000000000000001d554e434841494e454420454c455048414e5453203430342024454c695a0000000000000000000000000000000000000000000000000000000000000000000004454c495a00000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _name (string): UNCHAINED ELEPHANTS 404 $ELiZ
Arg [1] : _symbol (string): ELIZ
Arg [2] : _memeception (address): 0x2cd3c02A734559472d91b285B544202A3C8B129e
Arg [3] : _creator (address): 0xA2aAcE327172f303aB431455469cD65f3b5b6351
Arg [4] : _factoryNFT (address): 0x9401ae767955581e3Ad0910d0E3651A2FcB37301
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [2] : 0000000000000000000000002cd3c02a734559472d91b285b544202a3c8b129e
Arg [3] : 000000000000000000000000a2aace327172f303ab431455469cd65f3b5b6351
Arg [4] : 0000000000000000000000009401ae767955581e3ad0910d0e3651a2fcb37301
Arg [5] : 000000000000000000000000000000000000000000000000000000000000001d
Arg [6] : 554e434841494e454420454c455048414e5453203430342024454c695a000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [8] : 454c495a00000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.
Add Token to MetaMask (Web3)