ForgeTokenDeployerV4

0xe1f4d29d501d446a6db241f0c72a7c36d881b651

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
1,983 bytes
ABI entries
15
8 read · 1 write
License
none

Contract information

Address
0xe1f4d29d501d446a6db241f0c72a7c36d881b651
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0xc56b8b7f1d…f3f8dde1fc

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (8)

cloneInitCodeHash(address)bytes32
effectiveSalt(address, bytes32)bytes32
launchManager()address
plainImplementation()address
plainInitCodeHash()bytes32
predictTokenAddress(bool, address, bytes32)address
rewardsImplementation()address
rewardsInitCodeHash()bytes32

Events (1)

TokenDeployed

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "launchManager_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "plainImplementation_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "rewardsImplementation_",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "ERC1167FailedCreateClone",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidImplementation",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidLaunchManager",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "Unauthorized",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "bytes32",
        "name": "userSalt",
        "type": "bytes32"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "rewards",
        "type": "bool"
      }
    ],
    "name": "TokenDeployed",
    "type": "event"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "implementation",
        "type": "address"
      }
    ],
    "name": "cloneInitCodeHash",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bool",
        "name": "rewards",
        "type": "bool"
      },
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol",
        "type": "string"
      },
      {
        "internalType": "uint256",
        "name": "supply",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "internalType": "bytes32",
        "name": "userSalt",
        "type": "bytes32"
      }
    ],
    "name": "deploy",
    "outputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "internalType": "bytes32",
        "name": "userSalt",
        "type": "bytes32"
      }
    ],
    "name": "effectiveSalt",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchManager",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "plainImplementation",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "plainInitCodeHash",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bool",
        "name": "rewards",
        "type": "bool"
      },
      {
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "internalType": "bytes32",
        "name": "userSalt",
        "type": "bytes32"
      }
    ],
    "name": "predictTokenAddress",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "rewardsImplementation",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "rewardsInitCodeHash",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {ForgeTokenV4} from "./ForgeTokenV4.sol";
import {ForgeRewardsTokenV4} from "./ForgeRewardsTokenV4.sol";

contract ForgeTokenDeployerV4 {
    address public immutable launchManager;
    address public immutable plainImplementation;
    address public immutable rewardsImplementation;

    event TokenDeployed(address indexed token, address indexed creator, bytes32 indexed userSalt, bool rewards);

    error InvalidLaunchManager();
    error InvalidImplementation();
    error Unauthorized();

    constructor(address launchManager_, address plainImplementation_, address rewardsImplementation_) {
        if (launchManager_ == address(0)) revert InvalidLaunchManager();
        if (
            plainImplementation_ == address(0) || rewardsImplementation_ == address(0)
                || plainImplementation_.code.length == 0 || rewardsImplementation_.code.length == 0
        ) revert InvalidImplementation();

        launchManager = launchManager_;
        plainImplementation = plainImplementation_;
        rewardsImplementation = rewardsImplementation_;
    }

    function effectiveSalt(address creator, bytes32 userSalt) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(creator, userSalt));
    }

    function predictTokenAddress(bool rewards, address creator, bytes32 userSalt) external view returns (address) {
        return Clones.predictDeterministicAddress(
            rewards ? rewardsImplementation : plainImplementation, effectiveSalt(creator, userSalt), address(this)
        );
    }

    function plainInitCodeHash() external view returns (bytes32) {
        return cloneInitCodeHash(plainImplementation);
    }

    function rewardsInitCodeHash() external view returns (bytes32) {
        return cloneInitCodeHash(rewardsImplementation);
    }

    function cloneInitCodeHash(address implementation) public pure returns (bytes32) {
        return keccak256(
            abi.encodePacked(
                hex"3d602d80600a3d3981f3",
                hex"363d3d373d3d3d363d73",
                implementation,
                hex"5af43d82803e903d91602b57fd5bf3"
            )
        );
    }

    function deploy(
        bool rewards,
        string calldata name,
        string calldata symbol,
        uint256 supply,
        address recipient,
        address creator,
        bytes32 userSalt
    ) external returns (address token) {
        if (msg.sender != launchManager) revert Unauthorized();

        bytes32 salt = effectiveSalt(creator, userSalt);
        if (rewards) {
            token = Clones.cloneDeterministic(rewardsImplementation, salt);
            ForgeRewardsTokenV4(token).initialize(name, symbol, supply, recipient);
        } else {
            token = Clones.cloneDeterministic(plainImplementation, salt);
            ForgeTokenV4(token).initialize(name, symbol, supply, recipient);
        }

        emit TokenDeployed(token, creator, userSalt, rewards);
    }
}
Chain explorer6542msChain node71ms