Address Contract Verified
Address
0x40a9E3fc8c8a3779AdD6f06Cb73E5c42134b0C02
Balance
0 ETH
Nonce
2
Code Size
2776 bytes
Creator
0xdA5C3C1d...8024 at tx 0xa5d98478...fee661
Indexed Transactions
0
Contract Bytecode
2776 bytes
0x6080604052600436106100a75760003560e01c80637804a5dc116100645780637804a5dc146101db57806382bc73dc1461021b5780638da5cb5b1461023b578063d782d64714610259578063d897ba9614610279578063f2fde38b1461029957600080fd5b80631672b0a6146100ac57806327e45c2c146100ce578063512ea8401461011c5780635b76c04f14610147578063715018a6146101a657806371e6977e146101bb575b600080fd5b3480156100b857600080fd5b506100cc6100c7366004610770565b6102b9565b005b3480156100da57600080fd5b506101026100e9366004610770565b6003602052600090815260409020805460019091015482565b604080519283526020830191909152015b60405180910390f35b61012f61012a366004610792565b6102e3565b6040516001600160a01b039091168152602001610113565b34801561015357600080fd5b5061018761016236600461080e565b600260205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b039093168352602083019190915201610113565b3480156101b257600080fd5b506100cc6104d1565b3480156101c757600080fd5b5060015461012f906001600160a01b031681565b3480156101e757600080fd5b5061020b6101f6366004610770565b60056020526000908152604090205460ff1681565b6040519015158152602001610113565b34801561022757600080fd5b506100cc610236366004610908565b6104e5565b34801561024757600080fd5b506000546001600160a01b031661012f565b34801561026557600080fd5b5061012f61027436600461080e565b6105ca565b34801561028557600080fd5b506100cc6102943660046109c1565b6105f4565b3480156102a557600080fd5b506100cc6102b4366004610770565b610627565b6102c161066a565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b3360009081526005602052604081205460ff166103135760405163c19f17a960e01b815260040160405180910390fd5b336000908152600560209081526040808320805460ff191690558683526002909152908190206001549151631df7cc5d60e31b815290916001600160a01b03169063efbe62e89061036c90349088908890600401610a26565b600060405180830381600087803b15801561038657600080fd5b505af115801561039a573d6000803e3d6000fd5b505082546103b392506001600160a01b03169050610697565b60048054600180820183557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b90910180546001600160a01b0319166001600160a01b0385169081179091556040805180820182528a8152868401546020808301918252600085815260039091528390209151825551930192909255905163439fab9160e01b81529294509163439fab91913491610454918991899101610a49565b6000604051808303818588803b15801561046d57600080fd5b505af1158015610481573d6000803e3d6000fd5b50506040516001600160a01b03861681527f2e2b3f61b70d2d131b2a807371103cc98d51adcaa5e9a8f9c32658ad8426e74e935060200191506104c19050565b60405180910390a1509392505050565b6104d961066a565b6104e36000610709565b565b6104ed61066a565b80518251146104fb57600080fd5b805160005b818110156105c45760006002600086848151811061052057610520610a65565b60200260200101518152602001908152602001600020905083828151811061054a5761054a610a65565b602090810291909101015181546001600160a01b039081169116146105bb5783828151811061057b5761057b610a65565b602090810291909101015181546001600160a01b0319166001600160a01b03909116178155600180820180546000906105b5908490610a7b565b90915550505b50600101610500565b50505050565b600481815481106105da57600080fd5b6000918252602090912001546001600160a01b0316905081565b6105fc61066a565b6001600160a01b03919091166000908152600560205260409020805460ff1916911515919091179055565b61062f61066a565b6001600160a01b03811661065e57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b61066781610709565b50565b6000546001600160a01b031633146104e35760405163118cdaa760e01b8152336004820152602401610655565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008260601b60e81c176000526e5af43d82803e903d91602b57fd5bf38260781b17602052603760096000f090506001600160a01b038116610704576040516330be1a3d60e21b815260040160405180910390fd5b919050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80356001600160a01b038116811461070457600080fd5b60006020828403121561078257600080fd5b61078b82610759565b9392505050565b6000806000604084860312156107a757600080fd5b83359250602084013567ffffffffffffffff808211156107c657600080fd5b818601915086601f8301126107da57600080fd5b8135818111156107e957600080fd5b8760208285010111156107fb57600080fd5b6020830194508093505050509250925092565b60006020828403121561082057600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561086657610866610827565b604052919050565b600067ffffffffffffffff82111561088857610888610827565b5060051b60200190565b600082601f8301126108a357600080fd5b813560206108b86108b38361086e565b61083d565b8083825260208201915060208460051b8701019350868411156108da57600080fd5b602086015b848110156108fd576108f081610759565b83529183019183016108df565b509695505050505050565b6000806040838503121561091b57600080fd5b823567ffffffffffffffff8082111561093357600080fd5b818501915085601f83011261094757600080fd5b813560206109576108b38361086e565b82815260059290921b8401810191818101908984111561097657600080fd5b948201945b838610156109945785358252948201949082019061097b565b965050860135925050808211156109aa57600080fd5b506109b785828601610892565b9150509250929050565b600080604083850312156109d457600080fd5b6109dd83610759565b9150602083013580151581146109f257600080fd5b809150509250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b838152604060208201526000610a406040830184866109fd565b95945050505050565b602081526000610a5d6020830184866109fd565b949350505050565b634e487b7160e01b600052603260045260246000fd5b80820180821115610a9c57634e487b7160e01b600052601160045260246000fd5b9291505056fea26469706673582212209b4d2009522df3957be46f6577ac35f8f30c5b92ea664f635ea8d4e769c8c30164736f6c63430008180033
Verified Source Code Full Match
Compiler: v0.8.24+commit.e11b9ed9
EVM: paris
Optimization: Yes (200 runs)
Factory.sol 82 lines
// SPDX-License-Identifier: None
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/proxy/Clones.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
interface IToken {
function initialize(bytes calldata params) external payable;
}
interface IValidationLogic {
function validate(uint256 ethAmt, bytes calldata params) external;
}
contract Factory is Ownable {
struct ImplementationData {
address addr;
uint256 version;
}
struct UserToken {
uint256 tokenType;
uint256 version;
}
IValidationLogic public validationLogic;
mapping(uint256 => ImplementationData) public tokenImplementations;
mapping(address => UserToken) public tokenData;
address[] public createdTokens;
mapping(address => bool) public canCreate;
event TokenCreated(address _address);
error NotApproved();
constructor(address _validationLogic, address[] memory implementations) Ownable(msg.sender) {
validationLogic = IValidationLogic(_validationLogic);
uint256 len = implementations.length;
for (uint256 i; i < len; i++) {
tokenImplementations[i] = ImplementationData({addr: implementations[i], version: 1});
}
}
function createToken(uint256 tokenID, bytes calldata params) external payable returns (address newToken) {
if (!canCreate[msg.sender]) {
revert NotApproved();
}
canCreate[msg.sender] = false;
ImplementationData storage tokenInfo = tokenImplementations[tokenID];
validationLogic.validate(msg.value, params);
newToken = Clones.clone(tokenInfo.addr);
createdTokens.push(newToken);
tokenData[newToken] = UserToken({tokenType: tokenID, version: tokenInfo.version});
IToken(newToken).initialize{value: msg.value}(params);
emit TokenCreated(newToken);
}
function approveCreator(address creator, bool approved) external onlyOwner {
canCreate[creator] = approved;
}
function setImplementations(uint256[] memory ids, address[] memory implementations) external onlyOwner {
if (ids.length != implementations.length) {
revert();
}
uint256 len = implementations.length;
for (uint256 i; i < len; i++) {
ImplementationData storage currImplementation = tokenImplementations[ids[i]];
if (currImplementation.addr != implementations[i]) {
currImplementation.addr = implementations[i];
currImplementation.version += 1;
}
}
}
function setValidationLogic(address vLogic) external onlyOwner {
validationLogic = IValidationLogic(vLogic);
}
}
Clones.sol 95 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Clones.sol)
pragma solidity ^0.8.20;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*/
library Clones {
/**
* @dev A clone instance deployment failed.
*/
error ERC1167FailedCreateClone();
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(0, 0x09, 0x37)
}
if (instance == address(0)) {
revert ERC1167FailedCreateClone();
}
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(0, 0x09, 0x37, salt)
}
if (instance == address(0)) {
revert ERC1167FailedCreateClone();
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := keccak256(add(ptr, 0x43), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
}
Context.sol 28 lines
// 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;
}
}
Ownable.sol 100 lines
// 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);
}
}
Read Contract
canCreate 0x7804a5dc → bool
createdTokens 0xd782d647 → address
owner 0x8da5cb5b → address
tokenData 0x27e45c2c → uint256, uint256
tokenImplementations 0x5b76c04f → address, uint256
validationLogic 0x71e6977e → address
Write Contract 6 functions
These functions modify contract state and require a wallet transaction to execute.
approveCreator 0xd897ba96
address creator
bool approved
createToken 0x512ea840
uint256 tokenID
bytes params
returns: address
renounceOwnership 0x715018a6
No parameters
setImplementations 0x82bc73dc
uint256[] ids
address[] implementations
setValidationLogic 0x1672b0a6
address vLogic
transferOwnership 0xf2fde38b
address newOwner
Recent Transactions
No transactions found for this address