This nametag was submitted by Kleros Curate.
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 151,811 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Buy | 29293129 | 1 min ago | IN | 0 ETH | 0.00012668 | ||||
Buy | 29293111 | 1 min ago | IN | 0 ETH | 0.00012709 | ||||
Buy | 29292804 | 11 mins ago | IN | 0 ETH | 0.00010886 | ||||
Buy | 29292765 | 13 mins ago | IN | 0 ETH | 0.0001065 | ||||
Buy | 29292726 | 14 mins ago | IN | 0 ETH | 0.00010437 | ||||
Buy | 29292689 | 15 mins ago | IN | 0 ETH | 0.00010418 | ||||
Buy | 29292654 | 16 mins ago | IN | 0 ETH | 0.00010345 | ||||
Buy | 29292614 | 18 mins ago | IN | 0 ETH | 0.00010143 | ||||
Buy | 29292569 | 19 mins ago | IN | 0 ETH | 0.0001014 | ||||
Buy | 29292362 | 26 mins ago | IN | 0 ETH | 0.00009317 | ||||
Buy | 29292341 | 27 mins ago | IN | 0 ETH | 0.00009336 | ||||
Buy | 29292323 | 27 mins ago | IN | 0 ETH | 0.00009356 | ||||
Buy | 29292306 | 28 mins ago | IN | 0 ETH | 0.00009377 | ||||
Buy | 29292294 | 28 mins ago | IN | 0 ETH | 0.00009358 | ||||
Buy | 29292279 | 29 mins ago | IN | 0 ETH | 0.00009366 | ||||
Buy | 29292244 | 30 mins ago | IN | 0 ETH | 0.00009413 | ||||
Buy | 29292233 | 30 mins ago | IN | 0 ETH | 0.0000944 | ||||
Buy | 29292216 | 31 mins ago | IN | 0 ETH | 0.00009448 | ||||
Buy | 29292196 | 32 mins ago | IN | 0 ETH | 0.0000951 | ||||
Buy | 29292185 | 32 mins ago | IN | 0 ETH | 0.00009509 | ||||
Buy | 29292163 | 33 mins ago | IN | 0 ETH | 0.00009523 | ||||
Buy | 29292152 | 33 mins ago | IN | 0 ETH | 0.0000951 | ||||
Buy | 29292133 | 34 mins ago | IN | 0 ETH | 0.00009518 | ||||
Buy | 29292106 | 35 mins ago | IN | 0 ETH | 0.00009539 | ||||
Buy | 29292075 | 36 mins ago | IN | 0 ETH | 0.00009504 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
29059138 | 5 days ago | 0.006 ETH | ||||
28994202 | 6 days ago | 0.009 ETH | ||||
28898335 | 9 days ago | 0.033 ETH | ||||
28359243 | 21 days ago | 0.002 ETH | ||||
28223629 | 24 days ago | 0.008 ETH | ||||
28212156 | 25 days ago | 0.0016 ETH | ||||
28196149 | 25 days ago | 0.0004 ETH | ||||
27888989 | 32 days ago | 0.0004 ETH | ||||
27829212 | 33 days ago | 0.072 ETH | ||||
27756766 | 35 days ago | 0.007 ETH | ||||
27702781 | 36 days ago | 0.0055 ETH | ||||
27686784 | 37 days ago | 0.004 ETH | ||||
27686784 | 37 days ago | 0.002 ETH | ||||
27241626 | 47 days ago | 0.049 ETH | ||||
26852788 | 56 days ago | 0.0008 ETH | ||||
26843982 | 56 days ago | 0.093 ETH | ||||
26840204 | 56 days ago | 0.117 ETH | ||||
26816174 | 57 days ago | 0.0008 ETH | ||||
26664173 | 60 days ago | 0.002828 ETH | ||||
26663582 | 60 days ago | 0.0009 ETH | ||||
26647161 | 61 days ago | 1.7793 ETH | ||||
26646031 | 61 days ago | 0.06 ETH | ||||
26645664 | 61 days ago | 0.03 ETH | ||||
26645664 | 61 days ago | 0.105 ETH | ||||
26220841 | 71 days ago | 0.004 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
FarcasterFrame
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 2 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {LibMap} from "solady/src/utils/LibMap.sol"; import {Ownable} from "solady/src/auth/Ownable.sol"; import {Pausable} from "openzeppelin/contracts/security/Pausable.sol"; import {SafeCastLib} from "solmate/src/utils/SafeCastLib.sol"; import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol"; import {IFarcasterFrame} from "src/interfaces/IFarcasterFrame.sol"; import {IToken} from "src/interfaces/IToken.sol"; import {ReserveInfo} from "src/lib/Structs.sol"; import {OPEN_EDITION_SUPPLY, TIME_UNLIMITED} from "src/utils/Constants.sol"; /** * @title FarcasterFrame * @author fx(hash) * @dev See the documentation in {IFarcasterFrame} */ contract FarcasterFrame is IFarcasterFrame, Ownable, Pausable { using SafeCastLib for uint256; /*////////////////////////////////////////////////////////////////////////// STORAGE //////////////////////////////////////////////////////////////////////////*/ /** * @dev Mapping of token address to timestamp of latest update made for token reserves */ LibMap.Uint40Map internal latestUpdates; /** * @dev Mapping of token to the last valid reserveId that can mint on behalf of the token */ LibMap.Uint40Map internal firstValidReserve; /** * @dev Mapping of token address to sale proceeds */ LibMap.Uint128Map internal saleProceeds; /** * @inheritdoc IFarcasterFrame */ address public controller; /** * @inheritdoc IFarcasterFrame */ mapping(address => uint256[]) public prices; /** * @inheritdoc IFarcasterFrame */ mapping(address => ReserveInfo[]) public reserves; /** * @inheritdoc IFarcasterFrame */ mapping(address => uint256) public maxAmounts; /** * @inheritdoc IFarcasterFrame */ mapping(uint256 => mapping(address => uint256)) public totalMinted; /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ constructor(address _owner, address _controller) { controller = _controller; _initializeOwner(_owner); } /*////////////////////////////////////////////////////////////////////////// EXTERNAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @inheritdoc IFarcasterFrame */ function buy(address _token, uint256 _reserveId, uint256 _amount, address _to) external payable whenNotPaused { _verifyTokenReserve(_token, _reserveId); uint256 price = _amount * prices[_token][_reserveId]; if (msg.value != price) revert InvalidPayment(); _setSaleProceeds(_token, getSaleProceeds(_token) + price); _buy(_token, _reserveId, price, _amount, _to); } /** * @inheritdoc IFarcasterFrame */ function mint(address _token, uint256 _reserveId, uint256 _fId, address _to) external whenNotPaused { _verifyTokenReserve(_token, _reserveId); if (msg.sender != controller) revert Unauthorized(); if (totalMinted[_fId][_token] == maxAmounts[_token]) revert MaxAmountExceeded(); totalMinted[_fId][_token]++; _buy(_token, _reserveId, 0, 1, _to); emit FrameMinted(_token, _to, _fId); } /** * @inheritdoc IFarcasterFrame */ function setMintDetails(ReserveInfo calldata _reserve, bytes calldata _mintDetails) external whenNotPaused { uint256 nextReserve = reserves[msg.sender].length; if (getLatestUpdate(msg.sender) != block.timestamp) { _setLatestUpdate(msg.sender, block.timestamp); _setFirstValidReserve(msg.sender, nextReserve); } if (_reserve.allocation == 0) revert InvalidAllocation(); (uint256 price, uint256 maxAmount) = abi.decode(_mintDetails, (uint256, uint256)); prices[msg.sender].push(price); reserves[msg.sender].push(_reserve); maxAmounts[msg.sender] = maxAmount; bool openEdition = _reserve.allocation == OPEN_EDITION_SUPPLY ? true : false; bool timeUnlimited = _reserve.endTime == TIME_UNLIMITED ? true : false; emit MintDetailsSet(msg.sender, nextReserve, price, _reserve, openEdition, timeUnlimited, maxAmount); } /** * @inheritdoc IFarcasterFrame */ function withdraw(address _token) external whenNotPaused { uint256 proceeds = getSaleProceeds(_token); if (proceeds == 0) revert InsufficientFunds(); address primaryReceiver = IToken(_token).primaryReceiver(); _setSaleProceeds(_token, 0); SafeTransferLib.safeTransferETH(primaryReceiver, proceeds); emit Withdrawn(_token, primaryReceiver, proceeds); } /*////////////////////////////////////////////////////////////////////////// OWNER FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @inheritdoc IFarcasterFrame */ function pause() external onlyOwner { _pause(); } /** * @inheritdoc IFarcasterFrame */ function setController(address _controller) external onlyOwner { emit ControllerSet(controller, _controller); controller = _controller; } /** * @inheritdoc IFarcasterFrame */ function unpause() external onlyOwner { _unpause(); } /*////////////////////////////////////////////////////////////////////////// READ FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @inheritdoc IFarcasterFrame */ function getFirstValidReserve(address _token) public view returns (uint256) { return LibMap.get(firstValidReserve, uint256(uint160(_token))); } /** * @inheritdoc IFarcasterFrame */ function getLatestUpdate(address _token) public view returns (uint40) { return LibMap.get(latestUpdates, uint256(uint160(_token))); } /** * @inheritdoc IFarcasterFrame */ function getSaleProceeds(address _token) public view returns (uint128) { return LibMap.get(saleProceeds, uint256(uint160(_token))); } /*////////////////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @dev Purchases arbitrary amount of tokens at fixed price and mints tokens to given account */ function _buy(address _token, uint256 _reserveId, uint256 _price, uint256 _amount, address _to) internal { ReserveInfo storage reserve = reserves[_token][_reserveId]; if (block.timestamp < reserve.startTime) revert NotStarted(); if (block.timestamp > reserve.endTime) revert Ended(); if (_amount > reserve.allocation) revert TooMany(); if (_to == address(0)) revert AddressZero(); reserve.allocation -= _amount.safeCastTo128(); IToken(_token).mint(_to, _amount, _price); emit Purchase(_token, _reserveId, msg.sender, _amount, _to, _price); } /** * @dev Sets timestamp of the latest update to token reserves */ function _setLatestUpdate(address _token, uint256 _timestamp) internal { LibMap.set(latestUpdates, uint256(uint160(_token)), uint40(_timestamp)); } /** * @dev Sets earliest valid reserve */ function _setFirstValidReserve(address _token, uint256 _reserveId) internal { LibMap.set(firstValidReserve, uint256(uint160(_token)), uint40(_reserveId)); } /** * @dev Sets the proceed amount from the token sale */ function _setSaleProceeds(address _token, uint256 _amount) internal { LibMap.set(saleProceeds, uint256(uint160(_token)), uint128(_amount)); } /** * @dev Verifies token and reserveId */ function _verifyTokenReserve(address _token, uint256 _reserveId) internal view { uint256 length = reserves[_token].length; if (length == 0) revert InvalidToken(); uint256 validReserve = getFirstValidReserve(_token); if (_reserveId >= length || _reserveId < validReserve) revert InvalidReserve(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for storage of packed unsigned integers. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibMap.sol) library LibMap { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev A uint8 map in storage. struct Uint8Map { mapping(uint256 => uint256) map; } /// @dev A uint16 map in storage. struct Uint16Map { mapping(uint256 => uint256) map; } /// @dev A uint32 map in storage. struct Uint32Map { mapping(uint256 => uint256) map; } /// @dev A uint40 map in storage. Useful for storing timestamps up to 34841 A.D. struct Uint40Map { mapping(uint256 => uint256) map; } /// @dev A uint64 map in storage. struct Uint64Map { mapping(uint256 => uint256) map; } /// @dev A uint128 map in storage. struct Uint128Map { mapping(uint256 => uint256) map; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GETTERS / SETTERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the uint8 value at `index` in `map`. function get(Uint8Map storage map, uint256 index) internal view returns (uint8 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, map.slot) mstore(0x00, shr(5, index)) result := byte(and(31, not(index)), sload(keccak256(0x00, 0x40))) } } /// @dev Updates the uint8 value at `index` in `map`. function set(Uint8Map storage map, uint256 index, uint8 value) internal { /// @solidity memory-safe-assembly assembly { mstore(0x20, map.slot) mstore(0x00, shr(5, index)) let s := keccak256(0x00, 0x40) // Storage slot. mstore(0x00, sload(s)) mstore8(and(31, not(index)), value) sstore(s, mload(0x00)) } } /// @dev Returns the uint16 value at `index` in `map`. function get(Uint16Map storage map, uint256 index) internal view returns (uint16 result) { result = uint16(map.map[index >> 4] >> ((index & 15) << 4)); } /// @dev Updates the uint16 value at `index` in `map`. function set(Uint16Map storage map, uint256 index, uint16 value) internal { /// @solidity memory-safe-assembly assembly { mstore(0x20, map.slot) mstore(0x00, shr(4, index)) let s := keccak256(0x00, 0x40) // Storage slot. let o := shl(4, and(index, 15)) // Storage slot offset (bits). let v := sload(s) // Storage slot value. let m := 0xffff // Value mask. sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value))))) } } /// @dev Returns the uint32 value at `index` in `map`. function get(Uint32Map storage map, uint256 index) internal view returns (uint32 result) { result = uint32(map.map[index >> 3] >> ((index & 7) << 5)); } /// @dev Updates the uint32 value at `index` in `map`. function set(Uint32Map storage map, uint256 index, uint32 value) internal { /// @solidity memory-safe-assembly assembly { mstore(0x20, map.slot) mstore(0x00, shr(3, index)) let s := keccak256(0x00, 0x40) // Storage slot. let o := shl(5, and(index, 7)) // Storage slot offset (bits). let v := sload(s) // Storage slot value. let m := 0xffffffff // Value mask. sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value))))) } } /// @dev Returns the uint40 value at `index` in `map`. function get(Uint40Map storage map, uint256 index) internal view returns (uint40 result) { unchecked { result = uint40(map.map[index / 6] >> ((index % 6) * 40)); } } /// @dev Updates the uint40 value at `index` in `map`. function set(Uint40Map storage map, uint256 index, uint40 value) internal { /// @solidity memory-safe-assembly assembly { mstore(0x20, map.slot) mstore(0x00, div(index, 6)) let s := keccak256(0x00, 0x40) // Storage slot. let o := mul(40, mod(index, 6)) // Storage slot offset (bits). let v := sload(s) // Storage slot value. let m := 0xffffffffff // Value mask. sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value))))) } } /// @dev Returns the uint64 value at `index` in `map`. function get(Uint64Map storage map, uint256 index) internal view returns (uint64 result) { result = uint64(map.map[index >> 2] >> ((index & 3) << 6)); } /// @dev Updates the uint64 value at `index` in `map`. function set(Uint64Map storage map, uint256 index, uint64 value) internal { /// @solidity memory-safe-assembly assembly { mstore(0x20, map.slot) mstore(0x00, shr(2, index)) let s := keccak256(0x00, 0x40) // Storage slot. let o := shl(6, and(index, 3)) // Storage slot offset (bits). let v := sload(s) // Storage slot value. let m := 0xffffffffffffffff // Value mask. sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value))))) } } /// @dev Returns the uint128 value at `index` in `map`. function get(Uint128Map storage map, uint256 index) internal view returns (uint128 result) { result = uint128(map.map[index >> 1] >> ((index & 1) << 7)); } /// @dev Updates the uint128 value at `index` in `map`. function set(Uint128Map storage map, uint256 index, uint128 value) internal { /// @solidity memory-safe-assembly assembly { mstore(0x20, map.slot) mstore(0x00, shr(1, index)) let s := keccak256(0x00, 0x40) // Storage slot. let o := shl(7, and(index, 1)) // Storage slot offset (bits). let v := sload(s) // Storage slot value. let m := 0xffffffffffffffffffffffffffffffff // Value mask. sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value))))) } } /// @dev Returns the value at `index` in `map`. function get(mapping(uint256 => uint256) storage map, uint256 index, uint256 bitWidth) internal view returns (uint256 result) { unchecked { uint256 d = _rawDiv(256, bitWidth); // Bucket size. uint256 m = (1 << bitWidth) - 1; // Value mask. result = (map[_rawDiv(index, d)] >> (_rawMod(index, d) * bitWidth)) & m; } } /// @dev Updates the value at `index` in `map`. function set( mapping(uint256 => uint256) storage map, uint256 index, uint256 value, uint256 bitWidth ) internal { unchecked { uint256 d = _rawDiv(256, bitWidth); // Bucket size. uint256 m = (1 << bitWidth) - 1; // Value mask. uint256 o = _rawMod(index, d) * bitWidth; // Storage slot offset (bits). map[_rawDiv(index, d)] ^= (((map[_rawDiv(index, d)] >> o) ^ value) & m) << o; } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BINARY SEARCH */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // The following functions search in the range of [`start`, `end`) // (i.e. `start <= index < end`). // The range must be sorted in ascending order. // `index` precedence: equal to > nearest before > nearest after. // An invalid search range will simply return `(found = false, index = start)`. /// @dev Returns whether `map` contains `needle`, and the index of `needle`. function searchSorted(Uint8Map storage map, uint8 needle, uint256 start, uint256 end) internal view returns (bool found, uint256 index) { return searchSorted(map.map, needle, start, end, 8); } /// @dev Returns whether `map` contains `needle`, and the index of `needle`. function searchSorted(Uint16Map storage map, uint16 needle, uint256 start, uint256 end) internal view returns (bool found, uint256 index) { return searchSorted(map.map, needle, start, end, 16); } /// @dev Returns whether `map` contains `needle`, and the index of `needle`. function searchSorted(Uint32Map storage map, uint32 needle, uint256 start, uint256 end) internal view returns (bool found, uint256 index) { return searchSorted(map.map, needle, start, end, 32); } /// @dev Returns whether `map` contains `needle`, and the index of `needle`. function searchSorted(Uint40Map storage map, uint40 needle, uint256 start, uint256 end) internal view returns (bool found, uint256 index) { return searchSorted(map.map, needle, start, end, 40); } /// @dev Returns whether `map` contains `needle`, and the index of `needle`. function searchSorted(Uint64Map storage map, uint64 needle, uint256 start, uint256 end) internal view returns (bool found, uint256 index) { return searchSorted(map.map, needle, start, end, 64); } /// @dev Returns whether `map` contains `needle`, and the index of `needle`. function searchSorted(Uint128Map storage map, uint128 needle, uint256 start, uint256 end) internal view returns (bool found, uint256 index) { return searchSorted(map.map, needle, start, end, 128); } /// @dev Returns whether `map` contains `needle`, and the index of `needle`. function searchSorted( mapping(uint256 => uint256) storage map, uint256 needle, uint256 start, uint256 end, uint256 bitWidth ) internal view returns (bool found, uint256 index) { unchecked { if (start >= end) end = start; uint256 t; uint256 o = start - 1; // Offset to derive the actual index. uint256 l = 1; // Low. uint256 d = _rawDiv(256, bitWidth); // Bucket size. uint256 m = (1 << bitWidth) - 1; // Value mask. uint256 h = end - start; // High. while (true) { index = (l & h) + ((l ^ h) >> 1); if (l > h) break; t = (map[_rawDiv(index + o, d)] >> (_rawMod(index + o, d) * bitWidth)) & m; if (t == needle) break; if (needle <= t) h = index - 1; else l = index + 1; } /// @solidity memory-safe-assembly assembly { m := or(iszero(index), iszero(bitWidth)) found := iszero(or(xor(t, needle), m)) index := add(o, xor(index, mul(xor(index, 1), m))) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `x / y`, returning 0 if `y` is zero. function _rawDiv(uint256 x, uint256 y) private pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function _rawMod(uint256 x, uint256 y) private pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mod(x, y) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(not(_OWNER_SLOT_NOT), newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { /// @solidity memory-safe-assembly assembly { let ownerSlot := not(_OWNER_SLOT_NOT) // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(not(_OWNER_SLOT_NOT)) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Safe unsigned integer casting library that reverts on overflow. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeCastLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol) library SafeCastLib { function safeCastTo248(uint256 x) internal pure returns (uint248 y) { require(x < 1 << 248); y = uint248(x); } function safeCastTo240(uint256 x) internal pure returns (uint240 y) { require(x < 1 << 240); y = uint240(x); } function safeCastTo232(uint256 x) internal pure returns (uint232 y) { require(x < 1 << 232); y = uint232(x); } function safeCastTo224(uint256 x) internal pure returns (uint224 y) { require(x < 1 << 224); y = uint224(x); } function safeCastTo216(uint256 x) internal pure returns (uint216 y) { require(x < 1 << 216); y = uint216(x); } function safeCastTo208(uint256 x) internal pure returns (uint208 y) { require(x < 1 << 208); y = uint208(x); } function safeCastTo200(uint256 x) internal pure returns (uint200 y) { require(x < 1 << 200); y = uint200(x); } function safeCastTo192(uint256 x) internal pure returns (uint192 y) { require(x < 1 << 192); y = uint192(x); } function safeCastTo184(uint256 x) internal pure returns (uint184 y) { require(x < 1 << 184); y = uint184(x); } function safeCastTo176(uint256 x) internal pure returns (uint176 y) { require(x < 1 << 176); y = uint176(x); } function safeCastTo168(uint256 x) internal pure returns (uint168 y) { require(x < 1 << 168); y = uint168(x); } function safeCastTo160(uint256 x) internal pure returns (uint160 y) { require(x < 1 << 160); y = uint160(x); } function safeCastTo152(uint256 x) internal pure returns (uint152 y) { require(x < 1 << 152); y = uint152(x); } function safeCastTo144(uint256 x) internal pure returns (uint144 y) { require(x < 1 << 144); y = uint144(x); } function safeCastTo136(uint256 x) internal pure returns (uint136 y) { require(x < 1 << 136); y = uint136(x); } function safeCastTo128(uint256 x) internal pure returns (uint128 y) { require(x < 1 << 128); y = uint128(x); } function safeCastTo120(uint256 x) internal pure returns (uint120 y) { require(x < 1 << 120); y = uint120(x); } function safeCastTo112(uint256 x) internal pure returns (uint112 y) { require(x < 1 << 112); y = uint112(x); } function safeCastTo104(uint256 x) internal pure returns (uint104 y) { require(x < 1 << 104); y = uint104(x); } function safeCastTo96(uint256 x) internal pure returns (uint96 y) { require(x < 1 << 96); y = uint96(x); } function safeCastTo88(uint256 x) internal pure returns (uint88 y) { require(x < 1 << 88); y = uint88(x); } function safeCastTo80(uint256 x) internal pure returns (uint80 y) { require(x < 1 << 80); y = uint80(x); } function safeCastTo72(uint256 x) internal pure returns (uint72 y) { require(x < 1 << 72); y = uint72(x); } function safeCastTo64(uint256 x) internal pure returns (uint64 y) { require(x < 1 << 64); y = uint64(x); } function safeCastTo56(uint256 x) internal pure returns (uint56 y) { require(x < 1 << 56); y = uint56(x); } function safeCastTo48(uint256 x) internal pure returns (uint48 y) { require(x < 1 << 48); y = uint48(x); } function safeCastTo40(uint256 x) internal pure returns (uint40 y) { require(x < 1 << 40); y = uint40(x); } function safeCastTo32(uint256 x) internal pure returns (uint32 y) { require(x < 1 << 32); y = uint32(x); } function safeCastTo24(uint256 x) internal pure returns (uint24 y) { require(x < 1 << 24); y = uint24(x); } function safeCastTo16(uint256 x) internal pure returns (uint16 y) { require(x < 1 << 16); y = uint16(x); } function safeCastTo8(uint256 x) internal pure returns (uint8 y) { require(x < 1 << 8); y = uint8(x); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; /// @solidity memory-safe-assembly assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument. mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {IMinter} from "src/interfaces/IMinter.sol"; import {ReserveInfo} from "src/lib/Structs.sol"; /** * @title IFarcasterFrame * @author fx(hash) * @notice Minter for distributing tokens for free or at fixed prices with Farcaster Frames */ interface IFarcasterFrame is IMinter { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Event emitted a new controller wallet is set * @param _prevController Address of the previous controller * @param _newController Address of the new controller */ event ControllerSet(address _prevController, address _newController); /** * @notice Event emitted when a new frame fixed price mint has been set * @param _token Address of the token being minted * @param _reserveId ID of the reserve * @param _price Amount of fixed price mint * @param _reserveInfo Reserve information for the mint * @param _openEdition Status of an open edition mint * @param _timeUnlimited Status of a mint with unlimited time * @param _maxAmountPerFid Maximum amount of tokens that can be minted per Farcaster ID (only for free frames) */ event MintDetailsSet( address indexed _token, uint256 indexed _reserveId, uint256 _price, ReserveInfo _reserveInfo, bool _openEdition, bool _timeUnlimited, uint256 _maxAmountPerFid ); /** * @notice Event emitted when a new free frame token has been minted * @param _token Address of the token being minted * @param _to Address receiving the minted tokens * @param _fid Farcaster ID of the receiver */ event FrameMinted(address indexed _token, address indexed _to, uint256 indexed _fid); /** * @notice Event emitted when a purchase is made * @param _token Address of the token being purchased * @param _reserveId ID of the mint * @param _buyer Address purchasing the tokens * @param _amount Amount of tokens being purchased * @param _to Address to which the tokens are being transferred * @param _price Price of the purchase */ event Purchase( address indexed _token, uint256 indexed _reserveId, address indexed _buyer, uint256 _amount, address _to, uint256 _price ); /** * @notice Event emitted when sale proceeds are withdrawn * @param _token Address of the token * @param _creator Address of the project creator * @param _proceeds Amount of proceeds being withdrawn */ event Withdrawn(address indexed _token, address indexed _creator, uint256 _proceeds); /*////////////////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Error thrown when receiver is zero address */ error AddressZero(); /** * @notice Error thrown when the sale has already ended */ error Ended(); /** * @notice Error thrown when no funds available to withdraw */ error InsufficientFunds(); /** * @notice Error thrown when the allocation amount is zero */ error InvalidAllocation(); /** * @notice Error thrown when payment does not equal price */ error InvalidPayment(); /** * @notice Error thrown thrown when reserve does not exist */ error InvalidReserve(); /** * @notice Error thrown when token address is invalid */ error InvalidToken(); /** * @notice Error thrown when amount being minted exceeded max amount allowed per Farcaster ID */ error MaxAmountExceeded(); /** * @notice Error thrown when the auction has not started */ error NotStarted(); /** * @notice Error thrown when amount purchased exceeds remaining allocation */ error TooMany(); /** * @notice Error thrown when receiver is zero address */ error ZeroAddress(); /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Purchases tokens at a fixed price * @param _token Address of the token contract * @param _reserveId ID of the reserve * @param _amount Amount of tokens being purchased * @param _to Address receiving the purchased tokens */ function buy(address _token, uint256 _reserveId, uint256 _amount, address _to) external payable; /** * @notice Address of the authorized wallet for minting free tokens */ function controller() external view returns (address); /** * @notice Returns the earliest valid reserveId that can mint a token */ function getFirstValidReserve(address _token) external view returns (uint256); /** * @notice Gets the latest timestamp update made to token reserves * @param _token Address of the token contract * @return Timestamp of latest update */ function getLatestUpdate(address _token) external view returns (uint40); /** * @notice Gets the proceed amount from a token sale * @param _token Address of the token contract * @return Amount of proceeds */ function getSaleProceeds(address _token) external view returns (uint128); /** * @notice Mapping of token address to max amount of mintable tokens per Farcaster ID */ function maxAmounts(address) external view returns (uint256); /** * @notice Mints token for free to given wallet * @param _token Address of the token contract * @param _reserveId ID of the reserve * @param _fId Farcaster user ID * @param _to Address receiving the free token */ function mint(address _token, uint256 _reserveId, uint256 _fId, address _to) external; /** * @notice Pauses all function executions where modifier is applied */ function pause() external; /** * @notice Mapping of token address to reserve ID to prices */ function prices(address, uint256) external view returns (uint256); /** * @notice Mapping of token address to reserve ID to reserve information */ function reserves(address, uint256) external view returns (uint64, uint64, uint128); /** * @notice Sets the new controller wallet address for minting free tokens */ function setController(address _controller) external; /** * @inheritdoc IMinter * @dev Mint Details: token price, merkle root, and signer address */ function setMintDetails(ReserveInfo calldata _reserveInfo, bytes calldata _mintDetails) external; /** * @notice Mapping of Farcaster ID to mapping of token address to total minted tokens */ function totalMinted(uint256, address) external view returns (uint256); /** * @notice Unpauses all function executions where modifier is applied */ function unpause() external; /** * @notice Withdraws the sale proceeds to the sale receiver * @param _token Address of the token withdrawing proceeds from */ function withdraw(address _token) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; /** * @title IToken * @author fx(hash) * @notice Interface for minters to interact with tokens */ interface IToken { /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Mints arbitrary number of tokens * @dev Only callable by registered minter contracts * @param _to Address receiving tokens * @param _amount Number of tokens being minted * @param _payment Total payment amount of the transaction */ function mint(address _to, uint256 _amount, uint256 _payment) external; /** * @notice Returns address of primary receiver for token sales */ function primaryReceiver() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; /*////////////////////////////////////////////////////////////////////////// STRUCTS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Struct of dutch auction information * - `refunded` Flag indicating if refunds are enabled * - `stepLength` Duration (in seconds) of each auction step * - `prices` Array of prices for each step of the auction */ struct AuctionInfo { bool refunded; uint248 stepLength; uint256[] prices; } /** * @notice Struct of system config information * - `feeReceiver` Address receiving platform fees * - `primaryFeeAllocation` Amount of basis points allocated to calculate platform fees on primary sale proceeds * - `secondaryFeeAllocation` Amount of basis points allocated to calculate platform fees on royalty payments * - `lockTime` Locked time duration added to mint start time for unverified creators * - `referrerShare` Share amount distributed to accounts referring tokens * - `defaultMetadataURI` Default base URI of token metadata * - `externalURI` External URI for displaying tokens */ struct ConfigInfo { address feeReceiver; uint32 primaryFeeAllocation; uint32 secondaryFeeAllocation; uint32 lockTime; uint64 referrerShare; string defaultMetadataURI; string externalURI; } /** * @notice Struct of generative art information * - `minter` Address of initial token owner * - `seed` Hash of randomly generated seed * - `fxParams` Random sequence of fixed-length bytes used as token input */ struct GenArtInfo { address minter; bytes32 seed; bytes fxParams; } /** * @notice Struct of initialization information used on project creation * - `name` Name of project * - `symbol` Symbol of project * - `primaryReceiver` Address of splitter contract receiving primary sales * - `randomizer` Address of Randomizer contract * - `renderer` Address of Renderer contract * - `tagIds` Array of tag IDs describing the project * - 'onchainData' Onchain data to be stored using SSTORE2 and available to renderers */ struct InitInfo { string name; string symbol; address[] primaryReceivers; uint32[] allocations; address randomizer; address renderer; uint256[] tagIds; bytes onchainData; } /** * @notice Struct of issuer information * - `primaryReceiver` Address of splitter contract receiving primary sales * - `projectInfo` Project information * - `activeMinters` Array of authorized minter contracts used for enumeration * - `minters` Mapping of minter contract to authorization status */ struct IssuerInfo { address primaryReceiver; ProjectInfo projectInfo; address[] activeMinters; mapping(address => uint8) minters; } /** * @notice Struct of metadata information * - `baseURI` Decoded URI of content identifier * - `onchainPointer` Address of bytes-encoded data rendered onchain */ struct MetadataInfo { bytes baseURI; address onchainPointer; } /** * @notice Struct of mint information * - `minter` Address of the minter contract * - `reserveInfo` Reserve information * - `params` Optional bytes data decoded inside minter */ struct MintInfo { address minter; ReserveInfo reserveInfo; bytes params; } /** * @notice Struct of minter information * - `totalMints` Total number of mints executed by the minter * - `totalPaid` Total amount paid by the minter */ struct MinterInfo { uint128 totalMints; uint128 totalPaid; } /** * @notice Struct of project information * - `mintEnabled` Flag inidicating if minting is enabled * - `burnEnabled` Flag inidicating if burning is enabled * - `maxSupply` Maximum supply of tokens * - `inputSize` Maximum input size of fxParams bytes data * - `earliestStartTime` Earliest possible start time for registering minters */ struct ProjectInfo { bool mintEnabled; bool burnEnabled; uint120 maxSupply; uint88 inputSize; uint32 earliestStartTime; } /** * @notice Struct of refund information * - `lastPrice` Price of last sale before selling out * - `minterInfo` Mapping of minter address to struct of minter information */ struct RefundInfo { uint256 lastPrice; mapping(address minter => MinterInfo) minterInfo; } /** * @notice Struct of reserve information * - `startTime` Start timestamp of minter * - `endTime` End timestamp of minter * - `allocation` Allocation amount for minter */ struct ReserveInfo { uint64 startTime; uint64 endTime; uint128 allocation; } /** * @notice Struct of royalty information * - `receiver` Address receiving royalties * - `basisPoints` Points used to calculate the royalty payment (0.01%) */ struct RoyaltyInfo { address receiver; uint96 basisPoints; } /** * @notice Struct of tax information * - `startTime` Timestamp of when harberger taxation begins * - `foreclosureTime` Timestamp of token foreclosure * - `currentPrice` Current listing price of token * - `depositAmount` Total amount of taxes deposited */ struct TaxInfo { uint48 startTime; uint48 foreclosureTime; uint80 currentPrice; uint80 depositAmount; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; /*////////////////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////////////////*/ // Core string constant FX_CONTRACT_REGISTRY = "FX_CONTRACT_REGISTRY"; string constant FX_GEN_ART_721 = "FX_GEN_ART_721"; string constant FX_ISSUER_FACTORY = "FX_ISSUER_FACTORY"; string constant FX_MINT_TICKET_721 = "FX_MINT_TICKET_721"; string constant FX_ROLE_REGISTRY = "FX_ROLE_REGISTRY"; string constant FX_TICKET_FACTORY = "FX_TICKET_FACTORY"; // Periphery string constant DUTCH_AUCTION = "DUTCH_AUCTION"; string constant FARCASTER_FRAME = "FARCASTER_FRAME"; string constant FIXED_PRICE = "FIXED_PRICE"; string constant IPFS_RENDERER = "IPFS_RENDERER"; string constant ONCHFS_RENDERER = "ONCHFS_RENDERER"; string constant PSEUDO_RANDOMIZER = "PSEUDO_RANDOMIZER"; string constant TICKET_REDEEMER = "TICKET_REDEEMER"; // EIP-712 bytes32 constant CLAIM_TYPEHASH = keccak256( "Claim(address token,uint256 reserveId,uint96 nonce,uint256 index,address user)" ); bytes32 constant SET_ONCHAIN_POINTER_TYPEHASH = keccak256("SetOnchainPointer(bytes onchainData,uint96 nonce)"); bytes32 constant SET_PRIMARY_RECEIVER_TYPEHASH = keccak256("SetPrimaryReceiver(address receiver,uint96 nonce)"); bytes32 constant SET_RENDERER_TYPEHASH = keccak256("SetRenderer(address renderer,uint96 nonce)"); // IPFS bytes constant IPFS_URL = hex"697066733a2f2f172c151325290607391d2c391b242225180a020b291b260929391d1b31222525202804120031280917120b280400"; string constant IPFS_PREFIX = "ipfs://"; // Metadata string constant API_VERSION = "0.2"; string constant ATTRIBUTES_ENDPOINT = "/attributes.json"; string constant METADATA_ENDPOINT = "/metadata.json"; string constant THUMBNAIL_ENDPOINT = "/thumbnail.json"; // ONCHFS string constant FX_HASH_QUERY = "/?fxhash="; string constant FX_PARAMS_QUERY = "#0x"; string constant ITERATION_QUERY = "&fxiteration="; string constant MINTER_QUERY = "&fxminter="; string constant ONCHFS_PREFIX = "onchfs://"; // Minters uint8 constant UNINITIALIZED = 0; uint8 constant FALSE = 1; uint8 constant TRUE = 2; // Project uint32 constant LOCK_TIME = 3600; // 1 hour uint64 constant TIME_UNLIMITED = type(uint64).max; uint120 constant OPEN_EDITION_SUPPLY = type(uint120).max; uint256 constant LAUNCH_TIMESTAMP = 1709226000; // 2/29/24 15:00 GMT // Roles bytes32 constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); bytes32 constant BANNED_USER_ROLE = keccak256("BANNED_USER_ROLE"); bytes32 constant CREATOR_ROLE = keccak256("CREATOR_ROLE"); bytes32 constant METADATA_ROLE = keccak256("METADATA_ROLE"); bytes32 constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 constant MODERATOR_ROLE = keccak256("MODERATOR_ROLE"); bytes32 constant SIGNER_ROLE = keccak256("SIGNER_ROLE"); // Royalties uint32 constant ALLOCATION_DENOMINATOR = 1_000_000; uint96 constant FEE_DENOMINATOR = 10_000; uint96 constant MAX_ROYALTY_BPS = 2500; // 25% // Splits address constant SPLITS_MAIN = 0x2ed6c4B5dA6378c7897AC67Ba9e43102Feb694EE; // Ticket uint256 constant AUCTION_DECAY_RATE = 200; // 2% uint256 constant DAILY_TAX_RATE = 27; // 0.274% uint256 constant MINIMUM_PRICE = 0.001 ether; uint256 constant ONE_DAY = 86_400; uint256 constant SCALING_FACTOR = 10_000; uint256 constant TEN_MINUTES = 600;
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @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); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {ReserveInfo} from "src/lib/Structs.sol"; /** * @title IMinter * @author fx(hash) * @notice Interface for FxGenArt721 tokens to interact with minters */ interface IMinter { /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Sets the mint details for token reserves * @param _reserveInfo Reserve information for the token * @param _mintDetails Details of the mint pertaining to the minter */ function setMintDetails(ReserveInfo calldata _reserveInfo, bytes calldata _mintDetails) external; }
{ "remappings": [ "openzeppelin/=lib/openzeppelin-contracts/", "openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "forge-std/=lib/forge-std/src/", "scripty.sol/=lib/scripty.sol/", "solady/=lib/solady/", "solmate/=lib/solmate/", "sstore2/=lib/sstore2/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/" ], "optimizer": { "enabled": true, "runs": 2 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_controller","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[],"name":"Ended","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InvalidAllocation","type":"error"},{"inputs":[],"name":"InvalidPayment","type":"error"},{"inputs":[],"name":"InvalidReserve","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"MaxAmountExceeded","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotStarted","type":"error"},{"inputs":[],"name":"TooMany","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_prevController","type":"address"},{"indexed":false,"internalType":"address","name":"_newController","type":"address"}],"name":"ControllerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"uint256","name":"_fid","type":"uint256"}],"name":"FrameMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"uint256","name":"_reserveId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_price","type":"uint256"},{"components":[{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint128","name":"allocation","type":"uint128"}],"indexed":false,"internalType":"struct ReserveInfo","name":"_reserveInfo","type":"tuple"},{"indexed":false,"internalType":"bool","name":"_openEdition","type":"bool"},{"indexed":false,"internalType":"bool","name":"_timeUnlimited","type":"bool"},{"indexed":false,"internalType":"uint256","name":"_maxAmountPerFid","type":"uint256"}],"name":"MintDetailsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"uint256","name":"_reserveId","type":"uint256"},{"indexed":true,"internalType":"address","name":"_buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_price","type":"uint256"}],"name":"Purchase","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_creator","type":"address"},{"indexed":false,"internalType":"uint256","name":"_proceeds","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_reserveId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"buy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getFirstValidReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getLatestUpdate","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getSaleProceeds","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_reserveId","type":"uint256"},{"internalType":"uint256","name":"_fId","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"prices","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"reserves","outputs":[{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint128","name":"allocation","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint128","name":"allocation","type":"uint128"}],"internalType":"struct ReserveInfo","name":"_reserve","type":"tuple"},{"internalType":"bytes","name":"_mintDetails","type":"bytes"}],"name":"setMintDetails","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"totalMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060405162001512380380620015128339810160408190526200003491620000c5565b6000805460ff19169055600480546001600160a01b0319166001600160a01b03831617905562000064826200006c565b5050620000fd565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b80516001600160a01b0381168114620000c057600080fd5b919050565b60008060408385031215620000d957600080fd5b620000e483620000a8565b9150620000f460208401620000a8565b90509250929050565b611405806200010d6000396000f3fe6080604052600436106101105760003560e01c80630b7096ea14610115578063256929621461015257806332a46e4b1461015c5780633f4ba83a1461018a5780633f60b6331461019f57806351cff8d9146101b257806354d1f13d146101d25780635c975abb146101da578063715018a6146101fd5780638456cb59146102055780638da5cb5b1461021a57806392eefe9b1461023c578063b490abde1461025c578063bbc492c01461027c578063de25de501461029c578063e6070b92146102eb578063ee0baee514610321578063f04e283e1461034e578063f2fde38b14610361578063f74bfe8e14610374578063f77c479114610394578063fc7676f7146103b4578063fee81cf4146103ec575b600080fd5b34801561012157600080fd5b50610135610130366004611042565b61041f565b6040516001600160801b0390911681526020015b60405180910390f35b61015a61044c565b005b34801561016857600080fd5b5061017c610177366004611042565b61049b565b604051908152602001610149565b34801561019657600080fd5b5061015a6104be565b61015a6101ad366004611066565b6104d0565b3480156101be57600080fd5b5061015a6101cd366004611042565b61057e565b61015a61068a565b3480156101e657600080fd5b5060005460ff166040519015158152602001610149565b61015a6106c6565b34801561021157600080fd5b5061015a6106d8565b34801561022657600080fd5b50638b78c6d819545b60405161014991906110b0565b34801561024857600080fd5b5061015a610257366004611042565b6106e8565b34801561026857600080fd5b5061015a6102773660046110c4565b610758565b34801561028857600080fd5b5061017c61029736600461114e565b610900565b3480156102a857600080fd5b506102bc6102b736600461114e565b610931565b604080516001600160401b0394851681529390921660208401526001600160801b031690820152606001610149565b3480156102f757600080fd5b5061030b610306366004611042565b610983565b60405164ffffffffff9091168152602001610149565b34801561032d57600080fd5b5061017c61033c366004611042565b60076020526000908152604090205481565b61015a61035c366004611042565b610999565b61015a61036f366004611042565b6109d9565b34801561038057600080fd5b5061015a61038f366004611066565b610a00565b3480156103a057600080fd5b5060045461022f906001600160a01b031681565b3480156103c057600080fd5b5061017c6103cf36600461117a565b600860209081526000928352604080842090915290825290205481565b3480156103f857600080fd5b5061017c610407366004611042565b63389a75e1600c908152600091909152602090205490565b60016001609f1b03600182901c16600090815260036020526040812054600783901b6080161c5b92915050565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b60006104b16002836001600160a01b0316610b13565b64ffffffffff1692915050565b6104c6610b33565b6104ce610b4e565b565b6104d8610b9a565b6104e28484610be5565b6001600160a01b038416600090815260056020526040812080548590811061050c5761050c6111aa565b90600052602060002001548361052291906111d6565b90508034146105445760405163078d696560e31b815260040160405180910390fd5b61056a85826105528861041f565b6001600160801b031661056591906111ed565b610c5e565b6105778585838686610c9f565b5050505050565b610586610b9a565b60006105918261041f565b6001600160801b03169050806000036105bd5760405163356680b760e01b815260040160405180910390fd5b6000826001600160a01b031663899308a86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106219190611200565b905061062e836000610c5e565b6106388183610e9e565b806001600160a01b0316836001600160a01b03167fd1c19fbcd4551a5edfb66d43d2e337c04837afda3482b42bdf569a8fccdae5fb8460405161067d91815260200190565b60405180910390a3505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b6106ce610b33565b6104ce6000610ef4565b6106e0610b33565b6104ce610f32565b6106f0610b33565b600454604080516001600160a01b03928316815291831660208301527e7582b62407f53d49cfc72e7ddab574c06ef3b8aced104b54b7bed4681ee54a910160405180910390a1600480546001600160a01b0319166001600160a01b0392909216919091179055565b610760610b9a565b3360008181526006602052604090205490429061077c90610983565b64ffffffffff161461079c576107923342610f6f565b61079c3382610f84565b6107ac6060850160408601611232565b6001600160801b03166000036107d5576040516305d7ba1960e11b815260040160405180910390fd5b6000806107e48486018661124f565b3360008181526005602090815260408083208054600181810183559185528385200187905593835260068252822080549384018155825290209294509092508791016108308282611286565b5050336000908152600760205260408082208390556001600160781b039061085e9060608a01908a01611232565b6001600160801b031614610873576000610876565b60015b905060006001600160401b0361089260408a0160208b016112ff565b6001600160401b0316146108a75760006108aa565b60015b905084336001600160a01b03167fb86521752d7c138c76b76e9a780d4f650051fbeca63917d984d07bf8da3b845d868b8686896040516108ee95949392919061131c565b60405180910390a35050505050505050565b6005602052816000526040600020818154811061091c57600080fd5b90600052602060002001600091509150505481565b6006602052816000526040600020818154811061094d57600080fd5b6000918252602090912001546001600160401b038082169350600160401b8204169150600160801b90046001600160801b031683565b60006104466001836001600160a01b0316610b13565b6109a1610b33565b63389a75e1600c52806000526020600c2080544211156109c957636f5e88186000526004601cfd5b600090556109d681610ef4565b50565b6109e1610b33565b8060601b6109f757637448fbae6000526004601cfd5b6109d681610ef4565b610a08610b9a565b610a128484610be5565b6004546001600160a01b03163314610a3c576040516282b42960e81b815260040160405180910390fd5b6001600160a01b038416600081815260076020908152604080832054868452600883528184209484529390915290205403610a8a5760405163a049dfc760e01b815260040160405180910390fd5b60008281526008602090815260408083206001600160a01b03881684529091528120805491610ab88361138f565b9190505550610acc84846000600185610c9f565b81816001600160a01b0316856001600160a01b03167f3360265ce975de1b90c66358724f1ad63724158c0992820d048d3d75e35c06bf60405160405180910390a450505050565b600680820460009081526020939093526040909220549190066028021c90565b638b78c6d8195433146104ce576382b429006000526004601cfd5b610b56610f99565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b604051610b9091906110b0565b60405180910390a1565b60005460ff16156104ce5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064015b60405180910390fd5b6001600160a01b03821660009081526006602052604081205490819003610c1f5760405163c1ab6dc160e01b815260040160405180910390fd5b6000610c2a8461049b565b90508183101580610c3a57508083105b15610c585760405163e46aea0960e01b815260040160405180910390fd5b50505050565b600360205260016001609f1b03600183901c1660009081526040902080546080600785901b1681811c84186001600160801b0316901b1890555050565b5050565b6001600160a01b0385166000908152600660205260408120805486908110610cc957610cc96111aa565b600091825260209091200180549091506001600160401b0316421015610d0257604051636f312cbd60e01b815260040160405180910390fd5b8054600160401b90046001600160401b0316421115610d345760405163477383f360e01b815260040160405180910390fd5b8054600160801b90046001600160801b0316831115610d6657604051636b2d630f60e11b815260040160405180910390fd5b6001600160a01b038216610d8d57604051639fabe1c160e01b815260040160405180910390fd5b610d9683610fe2565b81548290601090610db8908490600160801b90046001600160801b03166113a8565b82546001600160801b039182166101009390930a928302919092021990911617905550604051630ab714fb60e11b81526001600160a01b038381166004830152602482018590526044820186905287169063156e29f690606401600060405180830381600087803b158015610e2c57600080fd5b505af1158015610e40573d6000803e3d6000fd5b5050604080518681526001600160a01b038681166020830152918101889052339350889250908916907f1ed291f7d8423022df7d587aba59cfed69a7c95aeb081171cc756b396b31557f9060600160405180910390a4505050505050565b600080600080600085875af1905080610eef5760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610bdc565b505050565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b610f3a610b9a565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610b833390565b610c9b6001836001600160a01b031683610ff8565b610c9b6002836001600160a01b031683610ff8565b60005460ff166104ce5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610bdc565b6000600160801b8210610ff457600080fd5b5090565b8260205260068204600052604060002060068306602802815464ffffffffff8482841c188116831b8218845550505050505050565b6001600160a01b03811681146109d657600080fd5b60006020828403121561105457600080fd5b813561105f8161102d565b9392505050565b6000806000806080858703121561107c57600080fd5b84356110878161102d565b9350602085013592506040850135915060608501356110a58161102d565b939692955090935050565b6001600160a01b0391909116815260200190565b600080600083850360808112156110da57600080fd5b60608112156110e857600080fd5b5083925060608301356001600160401b038082111561110657600080fd5b818601915086601f83011261111a57600080fd5b81358181111561112957600080fd5b87602082850101111561113b57600080fd5b6020830194508093505050509250925092565b6000806040838503121561116157600080fd5b823561116c8161102d565b946020939093013593505050565b6000806040838503121561118d57600080fd5b82359150602083013561119f8161102d565b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610446576104466111c0565b80820180821115610446576104466111c0565b60006020828403121561121257600080fd5b815161105f8161102d565b6001600160801b03811681146109d657600080fd5b60006020828403121561124457600080fd5b813561105f8161121d565b6000806040838503121561126257600080fd5b50508035926020909101359150565b6001600160401b03811681146109d657600080fd5b813561129181611271565b81546001600160401b031981166001600160401b0392909216918217835560208401356112bd81611271565b600160401b600160801b03604091821b166001600160801b031992831684178117855590850135916112ee8361121d565b921760809190911b90911617905550565b60006020828403121561131157600080fd5b813561105f81611271565b85815260e08101853561132e81611271565b6001600160401b039081166020848101919091528701359061134f82611271565b166040838101919091528601356113658161121d565b6001600160801b03166060830152931515608082015291151560a083015260c09091015292915050565b6000600182016113a1576113a16111c0565b5060010190565b6001600160801b038281168282160390808211156113c8576113c86111c0565b509291505056fea2646970667358221220c694a237ba546081b4fbc74192173e40b11f39cc97ecdf800b209038cc0bad9c64736f6c6343000817003300000000000000000000000015aed2c71b500fc3265c196d134b2f21f8ee812b000000000000000000000000bd8681a47bd267fc52b5f65be278c9c841de3d6f
Deployed Bytecode
0x6080604052600436106101105760003560e01c80630b7096ea14610115578063256929621461015257806332a46e4b1461015c5780633f4ba83a1461018a5780633f60b6331461019f57806351cff8d9146101b257806354d1f13d146101d25780635c975abb146101da578063715018a6146101fd5780638456cb59146102055780638da5cb5b1461021a57806392eefe9b1461023c578063b490abde1461025c578063bbc492c01461027c578063de25de501461029c578063e6070b92146102eb578063ee0baee514610321578063f04e283e1461034e578063f2fde38b14610361578063f74bfe8e14610374578063f77c479114610394578063fc7676f7146103b4578063fee81cf4146103ec575b600080fd5b34801561012157600080fd5b50610135610130366004611042565b61041f565b6040516001600160801b0390911681526020015b60405180910390f35b61015a61044c565b005b34801561016857600080fd5b5061017c610177366004611042565b61049b565b604051908152602001610149565b34801561019657600080fd5b5061015a6104be565b61015a6101ad366004611066565b6104d0565b3480156101be57600080fd5b5061015a6101cd366004611042565b61057e565b61015a61068a565b3480156101e657600080fd5b5060005460ff166040519015158152602001610149565b61015a6106c6565b34801561021157600080fd5b5061015a6106d8565b34801561022657600080fd5b50638b78c6d819545b60405161014991906110b0565b34801561024857600080fd5b5061015a610257366004611042565b6106e8565b34801561026857600080fd5b5061015a6102773660046110c4565b610758565b34801561028857600080fd5b5061017c61029736600461114e565b610900565b3480156102a857600080fd5b506102bc6102b736600461114e565b610931565b604080516001600160401b0394851681529390921660208401526001600160801b031690820152606001610149565b3480156102f757600080fd5b5061030b610306366004611042565b610983565b60405164ffffffffff9091168152602001610149565b34801561032d57600080fd5b5061017c61033c366004611042565b60076020526000908152604090205481565b61015a61035c366004611042565b610999565b61015a61036f366004611042565b6109d9565b34801561038057600080fd5b5061015a61038f366004611066565b610a00565b3480156103a057600080fd5b5060045461022f906001600160a01b031681565b3480156103c057600080fd5b5061017c6103cf36600461117a565b600860209081526000928352604080842090915290825290205481565b3480156103f857600080fd5b5061017c610407366004611042565b63389a75e1600c908152600091909152602090205490565b60016001609f1b03600182901c16600090815260036020526040812054600783901b6080161c5b92915050565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b60006104b16002836001600160a01b0316610b13565b64ffffffffff1692915050565b6104c6610b33565b6104ce610b4e565b565b6104d8610b9a565b6104e28484610be5565b6001600160a01b038416600090815260056020526040812080548590811061050c5761050c6111aa565b90600052602060002001548361052291906111d6565b90508034146105445760405163078d696560e31b815260040160405180910390fd5b61056a85826105528861041f565b6001600160801b031661056591906111ed565b610c5e565b6105778585838686610c9f565b5050505050565b610586610b9a565b60006105918261041f565b6001600160801b03169050806000036105bd5760405163356680b760e01b815260040160405180910390fd5b6000826001600160a01b031663899308a86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106219190611200565b905061062e836000610c5e565b6106388183610e9e565b806001600160a01b0316836001600160a01b03167fd1c19fbcd4551a5edfb66d43d2e337c04837afda3482b42bdf569a8fccdae5fb8460405161067d91815260200190565b60405180910390a3505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b6106ce610b33565b6104ce6000610ef4565b6106e0610b33565b6104ce610f32565b6106f0610b33565b600454604080516001600160a01b03928316815291831660208301527e7582b62407f53d49cfc72e7ddab574c06ef3b8aced104b54b7bed4681ee54a910160405180910390a1600480546001600160a01b0319166001600160a01b0392909216919091179055565b610760610b9a565b3360008181526006602052604090205490429061077c90610983565b64ffffffffff161461079c576107923342610f6f565b61079c3382610f84565b6107ac6060850160408601611232565b6001600160801b03166000036107d5576040516305d7ba1960e11b815260040160405180910390fd5b6000806107e48486018661124f565b3360008181526005602090815260408083208054600181810183559185528385200187905593835260068252822080549384018155825290209294509092508791016108308282611286565b5050336000908152600760205260408082208390556001600160781b039061085e9060608a01908a01611232565b6001600160801b031614610873576000610876565b60015b905060006001600160401b0361089260408a0160208b016112ff565b6001600160401b0316146108a75760006108aa565b60015b905084336001600160a01b03167fb86521752d7c138c76b76e9a780d4f650051fbeca63917d984d07bf8da3b845d868b8686896040516108ee95949392919061131c565b60405180910390a35050505050505050565b6005602052816000526040600020818154811061091c57600080fd5b90600052602060002001600091509150505481565b6006602052816000526040600020818154811061094d57600080fd5b6000918252602090912001546001600160401b038082169350600160401b8204169150600160801b90046001600160801b031683565b60006104466001836001600160a01b0316610b13565b6109a1610b33565b63389a75e1600c52806000526020600c2080544211156109c957636f5e88186000526004601cfd5b600090556109d681610ef4565b50565b6109e1610b33565b8060601b6109f757637448fbae6000526004601cfd5b6109d681610ef4565b610a08610b9a565b610a128484610be5565b6004546001600160a01b03163314610a3c576040516282b42960e81b815260040160405180910390fd5b6001600160a01b038416600081815260076020908152604080832054868452600883528184209484529390915290205403610a8a5760405163a049dfc760e01b815260040160405180910390fd5b60008281526008602090815260408083206001600160a01b03881684529091528120805491610ab88361138f565b9190505550610acc84846000600185610c9f565b81816001600160a01b0316856001600160a01b03167f3360265ce975de1b90c66358724f1ad63724158c0992820d048d3d75e35c06bf60405160405180910390a450505050565b600680820460009081526020939093526040909220549190066028021c90565b638b78c6d8195433146104ce576382b429006000526004601cfd5b610b56610f99565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b604051610b9091906110b0565b60405180910390a1565b60005460ff16156104ce5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064015b60405180910390fd5b6001600160a01b03821660009081526006602052604081205490819003610c1f5760405163c1ab6dc160e01b815260040160405180910390fd5b6000610c2a8461049b565b90508183101580610c3a57508083105b15610c585760405163e46aea0960e01b815260040160405180910390fd5b50505050565b600360205260016001609f1b03600183901c1660009081526040902080546080600785901b1681811c84186001600160801b0316901b1890555050565b5050565b6001600160a01b0385166000908152600660205260408120805486908110610cc957610cc96111aa565b600091825260209091200180549091506001600160401b0316421015610d0257604051636f312cbd60e01b815260040160405180910390fd5b8054600160401b90046001600160401b0316421115610d345760405163477383f360e01b815260040160405180910390fd5b8054600160801b90046001600160801b0316831115610d6657604051636b2d630f60e11b815260040160405180910390fd5b6001600160a01b038216610d8d57604051639fabe1c160e01b815260040160405180910390fd5b610d9683610fe2565b81548290601090610db8908490600160801b90046001600160801b03166113a8565b82546001600160801b039182166101009390930a928302919092021990911617905550604051630ab714fb60e11b81526001600160a01b038381166004830152602482018590526044820186905287169063156e29f690606401600060405180830381600087803b158015610e2c57600080fd5b505af1158015610e40573d6000803e3d6000fd5b5050604080518681526001600160a01b038681166020830152918101889052339350889250908916907f1ed291f7d8423022df7d587aba59cfed69a7c95aeb081171cc756b396b31557f9060600160405180910390a4505050505050565b600080600080600085875af1905080610eef5760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610bdc565b505050565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b610f3a610b9a565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610b833390565b610c9b6001836001600160a01b031683610ff8565b610c9b6002836001600160a01b031683610ff8565b60005460ff166104ce5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610bdc565b6000600160801b8210610ff457600080fd5b5090565b8260205260068204600052604060002060068306602802815464ffffffffff8482841c188116831b8218845550505050505050565b6001600160a01b03811681146109d657600080fd5b60006020828403121561105457600080fd5b813561105f8161102d565b9392505050565b6000806000806080858703121561107c57600080fd5b84356110878161102d565b9350602085013592506040850135915060608501356110a58161102d565b939692955090935050565b6001600160a01b0391909116815260200190565b600080600083850360808112156110da57600080fd5b60608112156110e857600080fd5b5083925060608301356001600160401b038082111561110657600080fd5b818601915086601f83011261111a57600080fd5b81358181111561112957600080fd5b87602082850101111561113b57600080fd5b6020830194508093505050509250925092565b6000806040838503121561116157600080fd5b823561116c8161102d565b946020939093013593505050565b6000806040838503121561118d57600080fd5b82359150602083013561119f8161102d565b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610446576104466111c0565b80820180821115610446576104466111c0565b60006020828403121561121257600080fd5b815161105f8161102d565b6001600160801b03811681146109d657600080fd5b60006020828403121561124457600080fd5b813561105f8161121d565b6000806040838503121561126257600080fd5b50508035926020909101359150565b6001600160401b03811681146109d657600080fd5b813561129181611271565b81546001600160401b031981166001600160401b0392909216918217835560208401356112bd81611271565b600160401b600160801b03604091821b166001600160801b031992831684178117855590850135916112ee8361121d565b921760809190911b90911617905550565b60006020828403121561131157600080fd5b813561105f81611271565b85815260e08101853561132e81611271565b6001600160401b039081166020848101919091528701359061134f82611271565b166040838101919091528601356113658161121d565b6001600160801b03166060830152931515608082015291151560a083015260c09091015292915050565b6000600182016113a1576113a16111c0565b5060010190565b6001600160801b038281168282160390808211156113c8576113c86111c0565b509291505056fea2646970667358221220c694a237ba546081b4fbc74192173e40b11f39cc97ecdf800b209038cc0bad9c64736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000015aed2c71b500fc3265c196d134b2f21f8ee812b000000000000000000000000bd8681a47bd267fc52b5f65be278c9c841de3d6f
-----Decoded View---------------
Arg [0] : _owner (address): 0x15AeD2C71B500Fc3265c196D134b2F21F8eE812b
Arg [1] : _controller (address): 0xBd8681a47bD267fc52B5F65BE278C9C841DE3D6f
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000015aed2c71b500fc3265c196d134b2f21f8ee812b
Arg [1] : 000000000000000000000000bd8681a47bd267fc52b5f65be278c9c841de3d6f
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.