S Price: $0.452393 (-8.00%)

Contract Diff Checker

Contract Name:
FBTCFactory

Contract Source Code:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

/**
 * @title FBTC Smart Contract Factory 
 * @dev Inspired by https://github.com/pcaversaccio/createx
 */
contract FBTCFactory {
    event ContractDeployed(
        address indexed _contract,
        address indexed _deployer
    );

    enum DeployType {
        Create2,
        Create2WithSender,
        Create3,
        Create3WithSender
    }

    function _guardSalt(
        address sender,
        bytes32 salt,
        uint256 tag
    ) internal pure returns (bytes32) {
        return keccak256(abi.encode(sender, salt, tag));
    }

    function deployCreate2(
        bytes32 salt,
        bytes memory initCode,
        bool _private
    ) internal returns (address _contract) {
        address sender = _private ? msg.sender : address(0);
        salt = _guardSalt(sender, salt, 2);
        assembly {
            _contract := create2(0, add(initCode, 0x20), mload(initCode), salt)
        }
        require(_contract != address(0), "Create2 failed");
        emit ContractDeployed(_contract, msg.sender);
    }

    function deployCreate3(
        bytes32 salt,
        bytes memory initCode,
        bool _private
    ) internal returns (address _contract) {
        address sender = _private ? msg.sender : address(0);
        bytes32 finalSalt = _guardSalt(sender, salt, 3);
        bytes
            memory proxyChildBytecode = hex"67_36_3d_3d_37_36_3d_34_f0_3d_52_60_08_60_18_f3";
        address proxy;
        assembly {
            proxy := create2(
                0,
                add(proxyChildBytecode, 32),
                mload(proxyChildBytecode),
                finalSalt
            )
        }
        require(proxy != address(0), "Create3 proxy failed");

        (bool success, bytes memory _retData) = proxy.call(initCode);
        if (!success) {
            assembly {
                let size := mload(_retData)
                revert(add(32, _retData), size)
            }
        }
        _contract = getCreate3Address(salt, sender);
        require(_contract.code.length > 0, "Create3 failed");
        emit ContractDeployed(_contract, msg.sender);
    }

    function deploy(
        DeployType typ,
        bytes32 salt,
        bytes memory initCode
    ) public returns (address _contract) {
        if (typ == DeployType.Create2) {
            _contract = deployCreate2(salt, initCode, false);
        } else if (typ == DeployType.Create2WithSender) {
            _contract = deployCreate2(salt, initCode, true);
        } else if (typ == DeployType.Create3) {
            _contract = deployCreate3(salt, initCode, false);
        } else if (typ == DeployType.Create3WithSender) {
            _contract = deployCreate3(salt, initCode, true);
        }
    }

    function deployAndInit(
        DeployType typ,
        bytes32 salt,
        bytes calldata initCode,
        bytes calldata callData
    ) public returns (address _contract) {
        _contract = deploy(typ, salt, initCode);
        (bool success, bytes memory _retData) = _contract.call(callData);
        if (!success) {
            assembly {
                let size := mload(_retData)
                revert(add(32, _retData), size)
            }
        }
    }

    function getCreate2Address(
        bytes32 salt,
        address sender,
        bytes calldata initCode
    ) public view returns (address _contract) {
        bytes32 initCodeHash = keccak256(initCode);
        address deployer = address(this);
        salt = _guardSalt(sender, salt, 2);
        assembly {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x40), initCodeHash)
            mstore(add(ptr, 0x20), salt)
            mstore(ptr, deployer)
            let start := add(ptr, 0x0b)
            mstore8(start, 0xff)
            _contract := keccak256(start, 85)
        }
    }

    function getCreate3Address(
        bytes32 salt,
        address sender
    ) public view returns (address _contract) {
        address deployer = address(this);
        salt = _guardSalt(sender, salt, 3);
        assembly {
            let ptr := mload(0x40)
            mstore(0x00, deployer)
            mstore8(0x0b, 0xff)
            mstore(0x20, salt)
            mstore(
                0x40,
                hex"21_c3_5d_be_1b_34_4a_24_88_cf_33_21_d6_ce_54_2f_8e_9f_30_55_44_ff_09_e4_99_3a_62_31_9a_49_7c_1f"
            )
            mstore(0x14, keccak256(0x0b, 0x55))
            mstore(0x40, ptr)
            mstore(0x00, 0xd694)
            mstore8(0x34, 0x01)
            _contract := keccak256(0x1e, 0x17)
        }
    }

    function getAddress(
        DeployType typ,
        bytes32 salt,
        address sender,
        bytes calldata initCode
    ) external view returns (address _contract) {
        if (typ == DeployType.Create2) {
            _contract = getCreate2Address(salt, address(0), initCode);
        } else if (typ == DeployType.Create2WithSender) {
            _contract = getCreate2Address(salt, sender, initCode);
        } else if (typ == DeployType.Create3) {
            _contract = getCreate3Address(salt, address(0));
        } else if (typ == DeployType.Create3WithSender) {
            _contract = getCreate3Address(salt, sender);
        }
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):