More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 1,379 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Transfer | 41137260 | 3 days ago | IN | 0 ETH | 0.00000172 | ||||
| Approve | 40302794 | 23 days ago | IN | 0 ETH | 0.00000019 | ||||
| Permit | 39888411 | 32 days ago | IN | 0 ETH | 0.0000001 | ||||
| Approve | 39733160 | 36 days ago | IN | 0 ETH | 0.00000003 | ||||
| Approve | 39702915 | 37 days ago | IN | 0 ETH | 0.00000003 | ||||
| Approve | 39702806 | 37 days ago | IN | 0 ETH | 0.00000003 | ||||
| Permit | 39556476 | 40 days ago | IN | 0 ETH | 0.00000042 | ||||
| Approve | 39201322 | 48 days ago | IN | 0 ETH | 0.00000001 | ||||
| Approve | 38779100 | 58 days ago | IN | 0 ETH | 0.00000016 | ||||
| Approve | 38723288 | 59 days ago | IN | 0 ETH | 0.00000008 | ||||
| Approve | 38714301 | 59 days ago | IN | 0 ETH | 0.00000006 | ||||
| Approve | 38552004 | 63 days ago | IN | 0 ETH | 0.00000002 | ||||
| Approve | 38438244 | 66 days ago | IN | 0 ETH | 0.00000698 | ||||
| Approve | 38325079 | 68 days ago | IN | 0 ETH | 0.00000019 | ||||
| Approve | 38171891 | 72 days ago | IN | 0 ETH | 0.00000054 | ||||
| Transfer | 38164538 | 72 days ago | IN | 0 ETH | 0.00000233 | ||||
| Transfer | 37912446 | 78 days ago | IN | 0 ETH | 0.00000021 | ||||
| Approve | 37614894 | 85 days ago | IN | 0 ETH | 0.00000014 | ||||
| Permit | 37590221 | 85 days ago | IN | 0 ETH | 0.00000065 | ||||
| Approve | 37276019 | 93 days ago | IN | 0 ETH | 0.00000123 | ||||
| Approve | 37238215 | 94 days ago | IN | 0 ETH | 0.00000022 | ||||
| Approve | 36628910 | 108 days ago | IN | 0 ETH | 0.00000028 | ||||
| Permit | 36524928 | 110 days ago | IN | 0 ETH | 0.00000086 | ||||
| Approve | 36465211 | 112 days ago | IN | 0 ETH | 0.00000013 | ||||
| Approve | 36399012 | 113 days ago | IN | 0 ETH | 0.00000017 |
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 18343235 | 531 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
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
OVERVIEW
ELiZ by Unchained Elephants is a cryptocurrency project with elephant welfare charitable fundamentals at its core. It aims to rescue elephants in dire conditions and relocate them to sanctuaries and be a digital advocate for elephants in Asia.Loading...
Loading
Net Worth in USD
$1.95
Net Worth in ETH
0.000686
Token Allocations
ETHO
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| BASE | 100.00% | $0.195083 | 10 | $1.95 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.