Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 25 from a total of 251 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Purchase | 24340636 | 41 days ago | IN | 0.0512 ETH | 0.00003649 | ||||
| Purchase | 24340636 | 41 days ago | IN | 0.0512 ETH | 0.00004211 | ||||
| Purchase | 24340636 | 41 days ago | IN | 0.0512 ETH | 0.00026758 | ||||
| Purchase | 24340635 | 41 days ago | IN | 0.0512 ETH | 0.00054986 | ||||
| Purchase | 24340629 | 41 days ago | IN | 0.1024 ETH | 0.00005899 | ||||
| Purchase | 24340629 | 41 days ago | IN | 0.1024 ETH | 0.00006474 | ||||
| Purchase | 24340629 | 41 days ago | IN | 0.0512 ETH | 0.00051452 | ||||
| Purchase | 24340629 | 41 days ago | IN | 0.256 ETH | 0.00158988 | ||||
| Purchase | 24340627 | 41 days ago | IN | 0.2048 ETH | 0.00138025 | ||||
| Purchase | 24340621 | 41 days ago | IN | 0.0512 ETH | 0.00047362 | ||||
| Purchase | 24340621 | 41 days ago | IN | 0.1024 ETH | 0.00044316 | ||||
| Purchase | 24340619 | 41 days ago | IN | 0.0512 ETH | 0.00047579 | ||||
| Purchase | 24340618 | 41 days ago | IN | 0.256 ETH | 0.00166199 | ||||
| Purchase | 24340617 | 41 days ago | IN | 0.1024 ETH | 0.00005644 | ||||
| Purchase | 24340614 | 41 days ago | IN | 0.1024 ETH | 0.00082252 | ||||
| Purchase | 24340611 | 41 days ago | IN | 0.0512 ETH | 0.00047341 | ||||
| Purchase | 24340611 | 41 days ago | IN | 0.0512 ETH | 0.0005464 | ||||
| Purchase | 24340599 | 41 days ago | IN | 0.0512 ETH | 0.00003351 | ||||
| Purchase | 24340596 | 41 days ago | IN | 0.1024 ETH | 0.00005774 | ||||
| Purchase | 24340595 | 41 days ago | IN | 0.2048 ETH | 0.00137169 | ||||
| Purchase | 24340593 | 41 days ago | IN | 0.2048 ETH | 0.00137378 | ||||
| Purchase | 24340592 | 41 days ago | IN | 0.0512 ETH | 0.00054502 | ||||
| Purchase | 24340589 | 41 days ago | IN | 0.0512 ETH | 0.00047316 | ||||
| Purchase | 24340586 | 41 days ago | IN | 0.0512 ETH | 0.00005989 | ||||
| Purchase | 24340584 | 41 days ago | IN | 0.256 ETH | 0.00164503 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Transfer | 24340636 | 41 days ago | 0.0512 ETH | ||||
| Transfer | 24340636 | 41 days ago | 0.0512 ETH | ||||
| Transfer | 24340636 | 41 days ago | 0.0512 ETH | ||||
| Transfer | 24340635 | 41 days ago | 0.0512 ETH | ||||
| Transfer | 24340629 | 41 days ago | 0.1024 ETH | ||||
| Transfer | 24340629 | 41 days ago | 0.1024 ETH | ||||
| Transfer | 24340629 | 41 days ago | 0.0512 ETH | ||||
| Transfer | 24340629 | 41 days ago | 0.256 ETH | ||||
| Transfer | 24340627 | 41 days ago | 0.2048 ETH | ||||
| Transfer | 24340621 | 41 days ago | 0.0512 ETH | ||||
| Transfer | 24340621 | 41 days ago | 0.1024 ETH | ||||
| Transfer | 24340619 | 41 days ago | 0.0512 ETH | ||||
| Transfer | 24340618 | 41 days ago | 0.256 ETH | ||||
| Transfer | 24340617 | 41 days ago | 0.1024 ETH | ||||
| Transfer | 24340614 | 41 days ago | 0.1024 ETH | ||||
| Transfer | 24340611 | 41 days ago | 0.0512 ETH | ||||
| Transfer | 24340611 | 41 days ago | 0.0512 ETH | ||||
| Transfer | 24340599 | 41 days ago | 0.0512 ETH | ||||
| Transfer | 24340596 | 41 days ago | 0.1024 ETH | ||||
| Transfer | 24340595 | 41 days ago | 0.2048 ETH | ||||
| Transfer | 24340593 | 41 days ago | 0.2048 ETH | ||||
| Transfer | 24340592 | 41 days ago | 0.0512 ETH | ||||
| Transfer | 24340589 | 41 days ago | 0.0512 ETH | ||||
| Transfer | 24340586 | 41 days ago | 0.0512 ETH | ||||
| Transfer | 24340584 | 41 days ago | 0.256 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
GEM721MintV2
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 20000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;
import {ECDSA} from "openzeppelin/utils/cryptography/ECDSA.sol";
import {EIP712} from "openzeppelin/utils/cryptography/EIP712.sol";
import {Ownable} from "openzeppelin/access/Ownable.sol";
import {Pausable} from "openzeppelin/utils/Pausable.sol";
import {ReentrancyGuard} from "openzeppelin/utils/ReentrancyGuard.sol";
import {TransferHelper} from "tl-sol-tools/payments/TransferHelper.sol";
import {IERC721TL} from "tl-creator-contracts/erc-721/IERC721TL.sol";
/// @title GEnerated Metadata (GEM) 721 Mint V2
/// @notice Contract that securely mints generated metadata on-the-fly for contracts that follow IERC721TL
/// @dev V2 uses global nonces as idempotency keys
/// @author transientlabs.xyz
contract GEM721MintV2 is Ownable, EIP712, Pausable, ReentrancyGuard, TransferHelper {
////////////////////////////////////////////////////////////////
// TYPES
////////////////////////////////////////////////////////////////
/// @dev Settings
/// @param signer The signer public address to verify mints
/// @param paymentRecipient The address to receive the payments for the tokens
/// @param cost The cost of each mint
/// @param protocolFeeRecipient The address to recieve protocol fees
/// @param protocolFee The protocol fee
/// @param weth The WETH address to use as a backup incase ETH transfers fail
/// @param nftAddress The NFT address to mint to
/// @param supply The supply of the mint
/// @param allowance The amount a single address can mint
struct Settings {
address signer;
address paymentRecipient;
uint256 cost;
address protocolFeeRecipient;
uint256 protocolFee;
address weth;
address nftAddress;
uint256 supply;
uint256 allowance;
}
/// @dev Purchase Data
/// @param uri The uri to mint
/// @param nonce The replay attack mitigation nonce & global idempotency key
/// @param signature The signature from the backend to validate
struct PurchaseData {
string uri;
bytes32 nonce;
bytes signature;
}
////////////////////////////////////////////////////////////////
// STATE VARIABLES
////////////////////////////////////////////////////////////////
Settings public settings;
uint256 public mintedSupply;
mapping(address => uint256) private _numMinted;
mapping(bytes32 => bool) private _usedNonces;
////////////////////////////////////////////////////////////////
// ERRORS
////////////////////////////////////////////////////////////////
error PurchaseMoreMints();
error SupplyLimitReached();
error AllowanceReached();
error NonceUsed();
error InsufficientFunds();
error InvalidSignature();
////////////////////////////////////////////////////////////////
// CONSTRUCTOR
////////////////////////////////////////////////////////////////
/// @param initOwner The initial owner of the contract
/// @param initSettings The initial settings for the contract
constructor(address initOwner, Settings memory initSettings) Ownable(initOwner) EIP712("GEM721Mint", "2") {
settings = initSettings;
}
////////////////////////////////////////////////////////////////
// PURCHASE FUNCTIONS
////////////////////////////////////////////////////////////////
function purchase(address recipient, PurchaseData[] memory purchaseData)
external
payable
whenNotPaused
nonReentrant
{
// cache state data
uint256 numToMint = purchaseData.length;
Settings memory s = settings;
uint256 numMinted = _numMinted[recipient];
// check high level conditions for mint
if (numToMint == 0) revert PurchaseMoreMints();
if (mintedSupply + numToMint > s.supply) revert SupplyLimitReached();
if (numMinted + numToMint > s.allowance) revert AllowanceReached();
if (msg.value != (s.cost + s.protocolFee) * numToMint) revert InsufficientFunds();
// update number minted
_numMinted[recipient] += numToMint;
mintedSupply += numToMint;
// execute mint, verifying replay attack, unique metadata, and signature
for (uint256 i = 0; i < numToMint; ++i) {
// cache data
PurchaseData memory pd = purchaseData[i];
bool nonceUsed = _usedNonces[pd.nonce];
bytes32 uriHash = keccak256(bytes(pd.uri));
// check conditions
if (nonceUsed) revert NonceUsed();
bytes32 digest = _hashTypedDataV4(_hashMintData(recipient, uriHash, pd.nonce));
if (s.signer != ECDSA.recover(digest, pd.signature)) revert InvalidSignature();
// update state variables
_usedNonces[pd.nonce] = true;
// mint
IERC721TL(s.nftAddress).externalMint(recipient, pd.uri); // wake-disable-line reentrancy
}
// send payment & protocol fee
_safeTransferETH(s.paymentRecipient, numToMint * s.cost, s.weth);
_safeTransferETH(s.protocolFeeRecipient, numToMint * s.protocolFee, s.weth);
}
/// @notice Function to hash the mint data
function _hashMintData(address recipient, bytes32 uriHash, bytes32 nonce) internal pure returns (bytes32) {
return keccak256(
abi.encode(
// keccak256("MintData(address recipient,string uri,bytes32 nonce)")
0x0d4eede914ec1337ec3957c9c75145ecc32a2ef5b51c2124a4677dde9b7e793e,
recipient,
uriHash,
nonce
)
);
}
////////////////////////////////////////////////////////////////
// VIEW FUNCTIONS
////////////////////////////////////////////////////////////////
/// @notice Function to get the number of tokens an address has minted
/// @param recipient The recipient to check
/// @return uint256 The number minted by the recipient
function getNumMinted(address recipient) external view returns (uint256) {
return _numMinted[recipient];
}
////////////////////////////////////////////////////////////////
// OWNER FUNCTIONS
////////////////////////////////////////////////////////////////
/// @notice Function to pause the contract
/// @dev Requires `msg.sender` to be the contract owner
function pause() external onlyOwner {
_pause();
}
/// @notice Function to unpause the contract
/// @dev Requires `msg.sender` to be the contract owner
function unpause() external onlyOwner {
_unpause();
}
/// @notice Function to update the contract settings
/// @dev Requires `msg.sender` to be the contract owner
/// @param newSettings New `Settings` struct to write to storage
function updateSettings(Settings calldata newSettings) external onlyOwner {
settings = newSettings;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError, bytes32) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.20;
import {MessageHashUtils} from "./MessageHashUtils.sol";
import {ShortStrings, ShortString} from "../ShortStrings.sol";
import {IERC5267} from "../../interfaces/IERC5267.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
* encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
* does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
* produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*
* @custom:oz-upgrades-unsafe-allow state-variable-immutable
*/
abstract contract EIP712 is IERC5267 {
using ShortStrings for *;
bytes32 private constant TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
string private _nameFallback;
string private _versionFallback;
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev See {IERC-5267}.
*/
function eip712Domain()
public
view
virtual
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f", // 01111
_EIP712Name(),
_EIP712Version(),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
/**
* @dev The name parameter for the EIP712 domain.
*
* NOTE: By default this function reads _name which is an immutable value.
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
*/
// solhint-disable-next-line func-name-mixedcase
function _EIP712Name() internal view returns (string memory) {
return _name.toStringWithFallback(_nameFallback);
}
/**
* @dev The version parameter for the EIP712 domain.
*
* NOTE: By default this function reads _version which is an immutable value.
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
*/
// solhint-disable-next-line func-name-mixedcase
function _EIP712Version() internal view returns (string memory) {
return _version.toStringWithFallback(_versionFallback);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {Context} from "../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 {
bool private _paused;
/**
* @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);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @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 {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {SafeERC20} from "openzeppelin/token/ERC20/utils/SafeERC20.sol";
import {IWETH, IERC20} from "./IWETH.sol";
/// @title Transfer Helper
/// @notice Abstract contract that has helper function for sending ETH and ERC20's safely
/// @author transientlabs.xyz
/// @custom:version 3.0.0
abstract contract TransferHelper {
/*//////////////////////////////////////////////////////////////////////////
Types
//////////////////////////////////////////////////////////////////////////*/
using SafeERC20 for IERC20;
using SafeERC20 for IWETH;
/*//////////////////////////////////////////////////////////////////////////
Errors
//////////////////////////////////////////////////////////////////////////*/
/// @dev ETH transfer failed
error ETHTransferFailed();
/// @dev Transferred too few ERC-20 tokens
error InsufficentERC20Transfer();
/*//////////////////////////////////////////////////////////////////////////
ETH Functions
//////////////////////////////////////////////////////////////////////////*/
/// @notice Function to force transfer ETH, defaulting to forwarding 100k gas
/// @dev On failure to send the ETH, the ETH is converted to WETH and sent
/// @dev Care should be taken to always pass the proper WETH address that adheres to IWETH
/// @param recipient The recipient of the ETH
/// @param amount The amount of ETH to send
/// @param weth The WETH token address
function _safeTransferETH(address recipient, uint256 amount, address weth) internal {
_safeTransferETH(recipient, amount, weth, 1e5);
}
/// @notice Function to force transfer ETH, with a gas limit
/// @dev On failure to send the ETH, the ETH is converted to WETH and sent
/// @dev Care should be taken to always pass the proper WETH address that adheres to IWETH
/// @dev If the `amount` is zero, the function returns in order to save gas
/// @param recipient The recipient of the ETH
/// @param amount The amount of ETH to send
/// @param weth The WETH token address
/// @param gasLimit The gas to forward
function _safeTransferETH(address recipient, uint256 amount, address weth, uint256 gasLimit) internal {
if (amount == 0) return;
(bool success,) = recipient.call{value: amount, gas: gasLimit}("");
if (!success) {
IWETH token = IWETH(weth);
token.deposit{value: amount}();
token.safeTransfer(recipient, amount);
}
}
/*//////////////////////////////////////////////////////////////////////////
ERC-20 Functions
//////////////////////////////////////////////////////////////////////////*/
/// @notice Function to safely transfer ERC-20 tokens from the contract, without checking for token tax
/// @dev Does not check if the sender has enough balance as that is handled by the token contract
/// @dev Does not check for token tax as that could lock up funds in the contract
/// @dev Reverts on failure to transfer
/// @dev If the `amount` is zero, the function returns in order to save gas
/// @param recipient The recipient of the ERC-20 token
/// @param currency The address of the ERC-20 token
/// @param amount The amount of ERC-20 to send
function _safeTransferERC20(address recipient, address currency, uint256 amount) internal {
if (amount == 0) return;
IERC20(currency).safeTransfer(recipient, amount);
}
/// @notice Function to safely transfer ERC-20 tokens from another address to a recipient
/// @dev Does not check if the sender has enough balance or allowance for this contract as that is handled by the token contract
/// @dev Reverts on failure to transfer
/// @dev Reverts if there is a token tax taken out
/// @dev Returns and doesn't do anything if the sender and recipient are the same address
/// @dev If the `amount` is zero, the function returns in order to save gas
/// @param sender The sender of the tokens
/// @param recipient The recipient of the ERC-20 token
/// @param currency The address of the ERC-20 token
/// @param amount The amount of ERC-20 to send
function _safeTransferFromERC20(address sender, address recipient, address currency, uint256 amount) internal {
if (amount == 0) return;
if (sender == recipient) return;
IERC20 token = IERC20(currency);
uint256 intialBalance = token.balanceOf(recipient);
token.safeTransferFrom(sender, recipient, amount);
uint256 finalBalance = token.balanceOf(recipient);
if (finalBalance - intialBalance < amount) revert InsufficentERC20Transfer();
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;
/// @title IERC721TL.sol
/// @notice Interface for ERC721TL
/// @dev Interface id = 0xc74089ae
/// @author transientlabs.xyz
/// @custom:version 3.0.0
interface IERC721TL {
/*//////////////////////////////////////////////////////////////////////////
Functions
//////////////////////////////////////////////////////////////////////////*/
/// @notice Function to mint a single token
/// @dev Requires owner or admin
/// @param recipient The recipient of the token - assumed as able to receive 721 tokens
/// @param uri The token uri to mint
function mint(address recipient, string calldata uri) external;
/// @notice Function to mint a single token with specific token royalty
/// @dev Requires owner or admin
/// @param recipient The recipient of the token - assumed as able to receive 721 tokens
/// @param uri The token uri to mint
/// @param royaltyAddress Royalty payout address for this new token
/// @param royaltyPercent Royalty percentage for this new token
function mint(address recipient, string calldata uri, address royaltyAddress, uint256 royaltyPercent) external;
/// @notice Function to batch mint tokens
/// @dev Requires owner or admin
/// @dev The `baseUri` folder should have the same number of json files in it as `numTokens`
/// @dev The `baseUri` folder should have files named without any file extension
/// @param recipient The recipient of the token - assumed as able to receive 721 tokens
/// @param numTokens Number of tokens in the batch mint
/// @param baseUri The base uri for the batch, expecting json to be in order, starting at file name 0, and SHOULD NOT have a trailing `/`
function batchMint(address recipient, uint128 numTokens, string calldata baseUri) external;
/// @notice Function to airdrop tokens to addresses
/// @dev Requires owner or admin
/// @dev Utilizes batch mint token uri values to save some gas but still ultimately mints individual tokens to people
/// @dev The `baseUri` folder should have the same number of json files in it as addresses in `addresses`
/// @dev The `baseUri` folder should have files named without any file extension
/// @param addresses Dynamic array of addresses to mint to
/// @param baseUri The base uri for the batch, expecting json to be in order, starting at file name 0, and SHOULD NOT have a trailing `/`
function airdrop(address[] calldata addresses, string calldata baseUri) external;
/// @notice Function to allow an approved mint contract to mint
/// @dev Requires the caller to be an approved mint contract
/// @param recipient The recipient of the token - assumed as able to receive 721 tokens
/// @param uri The token uri to mint
function externalMint(address recipient, string calldata uri) external;
/// @notice Function to burn a token
/// @dev Caller must be approved or owner of the token
/// @param tokenId The token to burn
function burn(uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
/**
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing a bytes32 `messageHash` with
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
* keccak256, although any bytes32 value can be safely used because the final digest will
* be re-hashed.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
}
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing an arbitrary `message` with
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x00` (data with intended validator).
*
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
* `validator` address. Then hashing the result.
*
* See {ECDSA-recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStrings {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using
* {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.20;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}{
"remappings": [
"@manifoldxyz/libraries-solidity/=lib/tl-creator-contracts/lib/tl-sol-tools/lib/royalty-registry-solidity/lib/libraries-solidity/",
"@openzeppelin/contracts-upgradeable/=lib/tl-creator-contracts/lib/tl-sol-tools/lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/tl-creator-contracts/lib/tl-sol-tools/lib/openzeppelin-contracts/contracts/",
"create2-helpers/=lib/tl-creator-contracts/lib/tl-sol-tools/lib/royalty-registry-solidity/lib/create2-helpers/",
"create2-scripts/=lib/tl-creator-contracts/lib/tl-sol-tools/lib/royalty-registry-solidity/lib/create2-helpers/script/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/tl-creator-contracts/lib/tl-sol-tools/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"libraries-solidity/=lib/tl-creator-contracts/lib/tl-sol-tools/lib/royalty-registry-solidity/lib/libraries-solidity/contracts/",
"murky/=lib/murky/src/",
"openzeppelin-contracts-upgradeable/=lib/tl-creator-contracts/lib/tl-sol-tools/lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/",
"openzeppelin-upgradeable/=lib/tl-creator-contracts/lib/tl-sol-tools/lib/openzeppelin-contracts-upgradeable/contracts/",
"openzeppelin/=lib/tl-creator-contracts/lib/tl-sol-tools/lib/openzeppelin-contracts/contracts/",
"royalty-registry-solidity/=lib/tl-creator-contracts/lib/tl-sol-tools/lib/royalty-registry-solidity/contracts/",
"tl-creator-contracts/=lib/tl-creator-contracts/src/",
"tl-sol-tools/=lib/tl-creator-contracts/lib/tl-sol-tools/src/",
"solady/=lib/solady/src/",
"base58-solidity/=lib/base58-solidity/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 20000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"initOwner","type":"address"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"paymentRecipient","type":"address"},{"internalType":"uint256","name":"cost","type":"uint256"},{"internalType":"address","name":"protocolFeeRecipient","type":"address"},{"internalType":"uint256","name":"protocolFee","type":"uint256"},{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"allowance","type":"uint256"}],"internalType":"struct GEM721MintV2.Settings","name":"initSettings","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AllowanceReached","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InsufficentERC20Transfer","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"NonceUsed","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"PurchaseMoreMints","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"SupplyLimitReached","type":"error"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"getNumMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintedSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"recipient","type":"address"},{"components":[{"internalType":"string","name":"uri","type":"string"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct GEM721MintV2.PurchaseData[]","name":"purchaseData","type":"tuple[]"}],"name":"purchase","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settings","outputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"paymentRecipient","type":"address"},{"internalType":"uint256","name":"cost","type":"uint256"},{"internalType":"address","name":"protocolFeeRecipient","type":"address"},{"internalType":"uint256","name":"protocolFee","type":"uint256"},{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"allowance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"paymentRecipient","type":"address"},{"internalType":"uint256","name":"cost","type":"uint256"},{"internalType":"address","name":"protocolFeeRecipient","type":"address"},{"internalType":"uint256","name":"protocolFee","type":"uint256"},{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"allowance","type":"uint256"}],"internalType":"struct GEM721MintV2.Settings","name":"newSettings","type":"tuple"}],"name":"updateSettings","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6101606040523480156200001257600080fd5b506040516200224f3803806200224f833981016040819052620000359162000332565b604080518082018252600a81526911d1534dcc8c535a5b9d60b21b602080830191909152825180840190935260018352601960f91b9083015290836001600160a01b038116620000a057604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000ab8162000207565b50620000b982600162000257565b61012052620000ca81600262000257565b61014052815160208084019190912060e052815190820120610100524660a0526200015860e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60809081523060c09081526003805460ff1916905560016004558451600580546001600160a01b03199081166001600160a01b03938416179091556020870151600680548316918416919091179055604087015160075560608701516008805483169184169190911790559286015160095560a0860151600a8054851691831691909117905590850151600b80549093169116179055505060e0810151600c556101000151600d5550620005d6565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060208351101562000277576200026f8362000290565b90506200028a565b8162000284848262000494565b5060ff90505b92915050565b600080829050601f81511115620002be578260405163305a27a960e01b815260040162000097919062000560565b8051620002cb82620005b1565b179392505050565b80516001600160a01b0381168114620002eb57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b03811182821017156200032c576200032c620002f0565b60405290565b6000808284036101408112156200034857600080fd5b6200035384620002d3565b925061012080601f19830112156200036a57600080fd5b6200037462000306565b91506200038460208601620002d3565b82526200039460408601620002d3565b602083015260608501516040830152620003b160808601620002d3565b606083015260a08501516080830152620003ce60c08601620002d3565b60a0830152620003e160e08601620002d3565b60c08301526101008581015160e0840152940151938101939093525092909150565b600181811c908216806200041857607f821691505b6020821081036200043957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200048f576000816000526020600020601f850160051c810160208610156200046a5750805b601f850160051c820191505b818110156200048b5782815560010162000476565b5050505b505050565b81516001600160401b03811115620004b057620004b0620002f0565b620004c881620004c1845462000403565b846200043f565b602080601f831160018114620005005760008415620004e75750858301515b600019600386901b1c1916600185901b1785556200048b565b600085815260208120601f198616915b82811015620005315788860151825594840194600190910190840162000510565b5085821015620005505787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020808352835180602085015260005b81811015620005905785810183015185820160400152820162000572565b506000604082860101526040601f19601f8301168501019250505092915050565b80516020808301519190811015620004395760001960209190910360031b1b16919050565b60805160a05160c05160e051610100516101205161014051611c1e620006316000396000610bca01526000610b9801526000610d1301526000610ceb01526000610c4601526000610c7001526000610c9a0152611c1e6000f3fe6080604052600436106100c75760003560e01c80638456cb5911610074578063c1bd8cf91161004e578063c1bd8cf914610216578063e06174e41461022c578063f2fde38b146102e757600080fd5b80638456cb59146101a457806384b0196e146101b95780638da5cb5b146101e157600080fd5b80635c975abb116100a55780635c975abb14610159578063715018a61461017c57806382fd946c1461019157600080fd5b80633d6dc6cf146100cc5780633f4ba83a14610122578063558cba0a14610139575b600080fd5b3480156100d857600080fd5b5061010f6100e7366004611483565b73ffffffffffffffffffffffffffffffffffffffff166000908152600f602052604090205490565b6040519081526020015b60405180910390f35b34801561012e57600080fd5b50610137610307565b005b34801561014557600080fd5b506101376101543660046114a0565b610319565b34801561016557600080fd5b5060035460ff166040519015158152602001610119565b34801561018857600080fd5b50610137610333565b61013761019f3660046115f6565b610345565b3480156101b057600080fd5b50610137610793565b3480156101c557600080fd5b506101ce6107a3565b60405161011997969594939291906117d1565b3480156101ed57600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610119565b34801561022257600080fd5b5061010f600e5481565b34801561023857600080fd5b50600554600654600754600854600954600a54600b54600c54600d546102829873ffffffffffffffffffffffffffffffffffffffff90811698811697968116959481169316919089565b6040805173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015288019690965293871660608701526080860192909252851660a085015290931660c083015260e082019290925261010081019190915261012001610119565b3480156102f357600080fd5b50610137610302366004611483565b610805565b61030f61086e565b6103176108c1565b565b61032161086e565b80600561032e82826118a0565b505050565b61033b61086e565b610317600061093e565b61034d6109b3565b6103556109f0565b8051604080516101208101825260055473ffffffffffffffffffffffffffffffffffffffff9081168252600654811660208084019190915260075483850152600854821660608401526009546080840152600a54821660a0840152600b54821660c0840152600c5460e0840152600d546101008401529086166000908152600f909152918220549091839003610417576040517f809e1bb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160e0015183600e5461042a9190611a9e565b1115610462576040517fe09ad7f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101008201516104728483611a9e565b11156104aa576040517fccc3b8c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82826080015183604001516104bf9190611a9e565b6104c99190611ab1565b3414610501576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff85166000908152600f602052604081208054859290610536908490611a9e565b9250508190555082600e600082825461054f9190611a9e565b90915550600090505b8381101561074757600085828151811061057457610574611ac8565b6020908102919091018101518082015160009081526010835260409020548151805193019290922090925060ff9091169081156105dd576040517f1f6d5aef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006105f66105f18b848760200151610a33565b610aaf565b9050610606818560400151610afd565b73ffffffffffffffffffffffffffffffffffffffff16876000015173ffffffffffffffffffffffffffffffffffffffff161461066e576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808501516000908152601090915260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560c0880151855191517f6c6ad24200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911691636c6ad24291610706918e91600401611af7565b600060405180830381600087803b15801561072057600080fd5b505af1158015610734573d6000803e3d6000fd5b5050505050505050806001019050610558565b5061076a82602001518360400151856107609190611ab1565b8460a00151610b27565b61078282606001518360800151856107609190611ab1565b50505061078f6001600455565b5050565b61079b61086e565b610317610b36565b6000606080600080600060606107b7610b91565b6107bf610bc3565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b61080d61086e565b73ffffffffffffffffffffffffffffffffffffffff8116610862576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024015b60405180910390fd5b61086b8161093e565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610317576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610859565b6108c9610bf0565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60035460ff1615610317576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260045403610a2c576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600455565b604080517f0d4eede914ec1337ec3957c9c75145ecc32a2ef5b51c2124a4677dde9b7e793e602082015273ffffffffffffffffffffffffffffffffffffffff851691810191909152606081018390526080810182905260009060a0016040516020818303038152906040528051906020012090505b9392505050565b6000610af7610abc610c2c565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b92915050565b600080600080610b0d8686610d64565b925092509250610b1d8282610db1565b5090949350505050565b61032e838383620186a0610eb5565b610b3e6109b3565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586109143390565b6060610bbe7f00000000000000000000000000000000000000000000000000000000000000006001610fb9565b905090565b6060610bbe7f00000000000000000000000000000000000000000000000000000000000000006002610fb9565b60035460ff16610317576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148015610c9257507f000000000000000000000000000000000000000000000000000000000000000046145b15610cbc57507f000000000000000000000000000000000000000000000000000000000000000090565b610bbe604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60008060008351604103610d9e5760208401516040850151606086015160001a610d9088828585611064565b955095509550505050610daa565b50508151600091506002905b9250925092565b6000826003811115610dc557610dc5611b2e565b03610dce575050565b6001826003811115610de257610de2611b2e565b03610e19576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002826003811115610e2d57610e2d611b2e565b03610e67576040517ffce698f700000000000000000000000000000000000000000000000000000000815260048101829052602401610859565b6003826003811115610e7b57610e7b611b2e565b0361078f576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401610859565b8215610fb35760008473ffffffffffffffffffffffffffffffffffffffff16848390604051600060405180830381858888f193505050503d8060008114610f18576040519150601f19603f3d011682016040523d82523d6000602084013e610f1d565b606091505b5050905080610fb15760008390508073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0866040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f7357600080fd5b505af1158015610f87573d6000803e3d6000fd5b50610faf9350505073ffffffffffffffffffffffffffffffffffffffff83169050878761115e565b505b505b50505050565b606060ff8314610fd357610fcc836111eb565b9050610af7565b818054610fdf90611b5d565b80601f016020809104026020016040519081016040528092919081815260200182805461100b90611b5d565b80156110585780601f1061102d57610100808354040283529160200191611058565b820191906000526020600020905b81548152906001019060200180831161103b57829003601f168201915b50505050509050610af7565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561109f5750600091506003905082611154565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156110f3573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661114a57506000925060019150829050611154565b9250600091508190505b9450945094915050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261032e90849061122a565b606060006111f8836112c0565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b600061124c73ffffffffffffffffffffffffffffffffffffffff841683611301565b9050805160001415801561127157508080602001905181019061126f9190611baa565b155b1561032e576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610859565b600060ff8216601f811115610af7576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060610aa883836000846000808573ffffffffffffffffffffffffffffffffffffffff1684866040516113349190611bcc565b60006040518083038185875af1925050503d8060008114611371576040519150601f19603f3d011682016040523d82523d6000602084013e611376565b606091505b5091509150611386868383611390565b9695505050505050565b6060826113a5576113a08261141f565b610aa8565b81511580156113c9575073ffffffffffffffffffffffffffffffffffffffff84163b155b15611418576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610859565b5080610aa8565b80511561142f5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461086b57600080fd5b60006020828403121561149557600080fd5b8135610aa881611461565b600061012082840312156114b357600080fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff8111828210171561150b5761150b6114b9565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611558576115586114b9565b604052919050565b600067ffffffffffffffff83111561157a5761157a6114b9565b6115ab60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011601611511565b90508281528383830111156115bf57600080fd5b828260208301376000602084830101529392505050565b600082601f8301126115e757600080fd5b610aa883833560208501611560565b600080604080848603121561160a57600080fd5b833561161581611461565b925060208481013567ffffffffffffffff8082111561163357600080fd5b818701915087601f83011261164757600080fd5b813581811115611659576116596114b9565b8060051b611668858201611511565b918252838101850191858101908b84111561168257600080fd5b86860192505b838310156117515782358581111561169f57600080fd5b86016060818e037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156116d45760008081fd5b6116dc6114e8565b88820135878111156116ee5760008081fd5b8201603f81018f136117005760008081fd5b6117108f8b8301358d8401611560565b825250898201358982015260608201358781111561172e5760008081fd5b61173c8f8b838601016115d6565b828c0152508352509186019190860190611688565b80985050505050505050509250929050565b60005b8381101561177e578181015183820152602001611766565b50506000910152565b6000815180845261179f816020860160208601611763565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e0602084015261180e60e084018a611787565b8381036040850152611820818a611787565b6060850189905273ffffffffffffffffffffffffffffffffffffffff8816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b8181101561188157835183529284019291840191600101611865565b50909c9b505050505050505050505050565b60008135610af781611461565b6118ee6118ac83611893565b82547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116178255565b6119436118fd60208401611893565b6001830173ffffffffffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781555050565b604082013560028201556119a261195c60608401611893565b6003830173ffffffffffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781555050565b60808201356004820155611a016119bb60a08401611893565b6005830173ffffffffffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781555050565b611a56611a1060c08401611893565b6006830173ffffffffffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781555050565b60e0820135600782015561010082013560088201555050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610af757610af7611a6f565b8082028115828204841417610af757610af7611a6f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000611b266040830184611787565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600181811c90821680611b7157607f821691505b6020821081036114b3577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060208284031215611bbc57600080fd5b81518015158114610aa857600080fd5b60008251611bde818460208701611763565b919091019291505056fea2646970667358221220fdf8904f9339fd5780c7f2bda725f7ad67d4fcc49a43696beb4c904ccdbe51ba64736f6c6343000816003300000000000000000000000077b35947d508012589a91ca4c9d168824376cc7d00000000000000000000000021ca42511e2e828ee10b9ed331641318b88d3f93000000000000000000000000791134eda401a27c053a109289c631af3fa7cb8100000000000000000000000000000000000000000000000000b5e620f480000000000000000000000000000077b35947d508012589a91ca4c9d168824376cc7d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000004af0370076a44c8ddc23db9ae5cecba66928037200000000000000000000000000000000000000000000000000000000000001f40000000000000000000000000000000000000000000000000000000000000064
Deployed Bytecode
0x6080604052600436106100c75760003560e01c80638456cb5911610074578063c1bd8cf91161004e578063c1bd8cf914610216578063e06174e41461022c578063f2fde38b146102e757600080fd5b80638456cb59146101a457806384b0196e146101b95780638da5cb5b146101e157600080fd5b80635c975abb116100a55780635c975abb14610159578063715018a61461017c57806382fd946c1461019157600080fd5b80633d6dc6cf146100cc5780633f4ba83a14610122578063558cba0a14610139575b600080fd5b3480156100d857600080fd5b5061010f6100e7366004611483565b73ffffffffffffffffffffffffffffffffffffffff166000908152600f602052604090205490565b6040519081526020015b60405180910390f35b34801561012e57600080fd5b50610137610307565b005b34801561014557600080fd5b506101376101543660046114a0565b610319565b34801561016557600080fd5b5060035460ff166040519015158152602001610119565b34801561018857600080fd5b50610137610333565b61013761019f3660046115f6565b610345565b3480156101b057600080fd5b50610137610793565b3480156101c557600080fd5b506101ce6107a3565b60405161011997969594939291906117d1565b3480156101ed57600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610119565b34801561022257600080fd5b5061010f600e5481565b34801561023857600080fd5b50600554600654600754600854600954600a54600b54600c54600d546102829873ffffffffffffffffffffffffffffffffffffffff90811698811697968116959481169316919089565b6040805173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015288019690965293871660608701526080860192909252851660a085015290931660c083015260e082019290925261010081019190915261012001610119565b3480156102f357600080fd5b50610137610302366004611483565b610805565b61030f61086e565b6103176108c1565b565b61032161086e565b80600561032e82826118a0565b505050565b61033b61086e565b610317600061093e565b61034d6109b3565b6103556109f0565b8051604080516101208101825260055473ffffffffffffffffffffffffffffffffffffffff9081168252600654811660208084019190915260075483850152600854821660608401526009546080840152600a54821660a0840152600b54821660c0840152600c5460e0840152600d546101008401529086166000908152600f909152918220549091839003610417576040517f809e1bb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160e0015183600e5461042a9190611a9e565b1115610462576040517fe09ad7f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101008201516104728483611a9e565b11156104aa576040517fccc3b8c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82826080015183604001516104bf9190611a9e565b6104c99190611ab1565b3414610501576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff85166000908152600f602052604081208054859290610536908490611a9e565b9250508190555082600e600082825461054f9190611a9e565b90915550600090505b8381101561074757600085828151811061057457610574611ac8565b6020908102919091018101518082015160009081526010835260409020548151805193019290922090925060ff9091169081156105dd576040517f1f6d5aef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006105f66105f18b848760200151610a33565b610aaf565b9050610606818560400151610afd565b73ffffffffffffffffffffffffffffffffffffffff16876000015173ffffffffffffffffffffffffffffffffffffffff161461066e576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808501516000908152601090915260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560c0880151855191517f6c6ad24200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911691636c6ad24291610706918e91600401611af7565b600060405180830381600087803b15801561072057600080fd5b505af1158015610734573d6000803e3d6000fd5b5050505050505050806001019050610558565b5061076a82602001518360400151856107609190611ab1565b8460a00151610b27565b61078282606001518360800151856107609190611ab1565b50505061078f6001600455565b5050565b61079b61086e565b610317610b36565b6000606080600080600060606107b7610b91565b6107bf610bc3565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b61080d61086e565b73ffffffffffffffffffffffffffffffffffffffff8116610862576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024015b60405180910390fd5b61086b8161093e565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610317576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610859565b6108c9610bf0565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60035460ff1615610317576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260045403610a2c576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600455565b604080517f0d4eede914ec1337ec3957c9c75145ecc32a2ef5b51c2124a4677dde9b7e793e602082015273ffffffffffffffffffffffffffffffffffffffff851691810191909152606081018390526080810182905260009060a0016040516020818303038152906040528051906020012090505b9392505050565b6000610af7610abc610c2c565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b92915050565b600080600080610b0d8686610d64565b925092509250610b1d8282610db1565b5090949350505050565b61032e838383620186a0610eb5565b610b3e6109b3565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586109143390565b6060610bbe7f47454d3732314d696e740000000000000000000000000000000000000000000a6001610fb9565b905090565b6060610bbe7f32000000000000000000000000000000000000000000000000000000000000016002610fb9565b60035460ff16610317576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e33f3eca30e821e458e25828deaad133003a471a16148015610c9257507f000000000000000000000000000000000000000000000000000000000000000146145b15610cbc57507f6e18952edaf6775aa4625896bf92d329aa840ba02faea70533331403f570de3b90565b610bbe604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527fc8803e63a6aa764c56bd16f03ddd18dd9675a4e2407574af13aba198d1e57ed2918101919091527fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a560608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60008060008351604103610d9e5760208401516040850151606086015160001a610d9088828585611064565b955095509550505050610daa565b50508151600091506002905b9250925092565b6000826003811115610dc557610dc5611b2e565b03610dce575050565b6001826003811115610de257610de2611b2e565b03610e19576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002826003811115610e2d57610e2d611b2e565b03610e67576040517ffce698f700000000000000000000000000000000000000000000000000000000815260048101829052602401610859565b6003826003811115610e7b57610e7b611b2e565b0361078f576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401610859565b8215610fb35760008473ffffffffffffffffffffffffffffffffffffffff16848390604051600060405180830381858888f193505050503d8060008114610f18576040519150601f19603f3d011682016040523d82523d6000602084013e610f1d565b606091505b5050905080610fb15760008390508073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0866040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f7357600080fd5b505af1158015610f87573d6000803e3d6000fd5b50610faf9350505073ffffffffffffffffffffffffffffffffffffffff83169050878761115e565b505b505b50505050565b606060ff8314610fd357610fcc836111eb565b9050610af7565b818054610fdf90611b5d565b80601f016020809104026020016040519081016040528092919081815260200182805461100b90611b5d565b80156110585780601f1061102d57610100808354040283529160200191611058565b820191906000526020600020905b81548152906001019060200180831161103b57829003601f168201915b50505050509050610af7565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561109f5750600091506003905082611154565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156110f3573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661114a57506000925060019150829050611154565b9250600091508190505b9450945094915050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261032e90849061122a565b606060006111f8836112c0565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b600061124c73ffffffffffffffffffffffffffffffffffffffff841683611301565b9050805160001415801561127157508080602001905181019061126f9190611baa565b155b1561032e576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610859565b600060ff8216601f811115610af7576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060610aa883836000846000808573ffffffffffffffffffffffffffffffffffffffff1684866040516113349190611bcc565b60006040518083038185875af1925050503d8060008114611371576040519150601f19603f3d011682016040523d82523d6000602084013e611376565b606091505b5091509150611386868383611390565b9695505050505050565b6060826113a5576113a08261141f565b610aa8565b81511580156113c9575073ffffffffffffffffffffffffffffffffffffffff84163b155b15611418576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610859565b5080610aa8565b80511561142f5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461086b57600080fd5b60006020828403121561149557600080fd5b8135610aa881611461565b600061012082840312156114b357600080fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff8111828210171561150b5761150b6114b9565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611558576115586114b9565b604052919050565b600067ffffffffffffffff83111561157a5761157a6114b9565b6115ab60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011601611511565b90508281528383830111156115bf57600080fd5b828260208301376000602084830101529392505050565b600082601f8301126115e757600080fd5b610aa883833560208501611560565b600080604080848603121561160a57600080fd5b833561161581611461565b925060208481013567ffffffffffffffff8082111561163357600080fd5b818701915087601f83011261164757600080fd5b813581811115611659576116596114b9565b8060051b611668858201611511565b918252838101850191858101908b84111561168257600080fd5b86860192505b838310156117515782358581111561169f57600080fd5b86016060818e037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156116d45760008081fd5b6116dc6114e8565b88820135878111156116ee5760008081fd5b8201603f81018f136117005760008081fd5b6117108f8b8301358d8401611560565b825250898201358982015260608201358781111561172e5760008081fd5b61173c8f8b838601016115d6565b828c0152508352509186019190860190611688565b80985050505050505050509250929050565b60005b8381101561177e578181015183820152602001611766565b50506000910152565b6000815180845261179f816020860160208601611763565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e0602084015261180e60e084018a611787565b8381036040850152611820818a611787565b6060850189905273ffffffffffffffffffffffffffffffffffffffff8816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b8181101561188157835183529284019291840191600101611865565b50909c9b505050505050505050505050565b60008135610af781611461565b6118ee6118ac83611893565b82547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116178255565b6119436118fd60208401611893565b6001830173ffffffffffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781555050565b604082013560028201556119a261195c60608401611893565b6003830173ffffffffffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781555050565b60808201356004820155611a016119bb60a08401611893565b6005830173ffffffffffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781555050565b611a56611a1060c08401611893565b6006830173ffffffffffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781555050565b60e0820135600782015561010082013560088201555050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610af757610af7611a6f565b8082028115828204841417610af757610af7611a6f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000611b266040830184611787565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600181811c90821680611b7157607f821691505b6020821081036114b3577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060208284031215611bbc57600080fd5b81518015158114610aa857600080fd5b60008251611bde818460208701611763565b919091019291505056fea2646970667358221220fdf8904f9339fd5780c7f2bda725f7ad67d4fcc49a43696beb4c904ccdbe51ba64736f6c63430008160033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000077b35947d508012589a91ca4c9d168824376cc7d00000000000000000000000021ca42511e2e828ee10b9ed331641318b88d3f93000000000000000000000000791134eda401a27c053a109289c631af3fa7cb8100000000000000000000000000000000000000000000000000b5e620f480000000000000000000000000000077b35947d508012589a91ca4c9d168824376cc7d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000004af0370076a44c8ddc23db9ae5cecba66928037200000000000000000000000000000000000000000000000000000000000001f40000000000000000000000000000000000000000000000000000000000000064
-----Decoded View---------------
Arg [0] : initOwner (address): 0x77B35947d508012589a91CA4c9d168824376Cc7D
Arg [1] : initSettings (tuple):
Arg [1] : signer (address): 0x21cA42511E2E828EE10b9eD331641318b88D3f93
Arg [2] : paymentRecipient (address): 0x791134edA401a27C053a109289c631af3fa7cb81
Arg [3] : cost (uint256): 51200000000000000
Arg [4] : protocolFeeRecipient (address): 0x77B35947d508012589a91CA4c9d168824376Cc7D
Arg [5] : protocolFee (uint256): 0
Arg [6] : weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [7] : nftAddress (address): 0x4Af0370076A44C8dDC23dB9aE5ceCbA669280372
Arg [8] : supply (uint256): 500
Arg [9] : allowance (uint256): 100
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 00000000000000000000000077b35947d508012589a91ca4c9d168824376cc7d
Arg [1] : 00000000000000000000000021ca42511e2e828ee10b9ed331641318b88d3f93
Arg [2] : 000000000000000000000000791134eda401a27c053a109289c631af3fa7cb81
Arg [3] : 00000000000000000000000000000000000000000000000000b5e620f4800000
Arg [4] : 00000000000000000000000077b35947d508012589a91ca4c9d168824376cc7d
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [7] : 0000000000000000000000004af0370076a44c8ddc23db9ae5cecba669280372
Arg [8] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000064
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.