TWCloneFactory

0x25548ba29a0071f30e4bdcd98ea72f79341b07a1

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
2,118 bytes
ABI entries
5
0 read · 2 write
License
none

Contract information

Address
0x25548ba29a0071f30e4bdcd98ea72f79341b07a1
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0x1ad7534ba5…3642eb0fac

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (0)

No read functions

The ABI is unavailable or exposes no view functions.

Events (2)

ProxyDeployedProxyDeployedV2

ABI

[
  {
    "inputs": [],
    "name": "ProxyDeploymentFailed",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "implementation",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "proxy",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "deployer",
        "type": "address"
      }
    ],
    "name": "ProxyDeployed",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "implementation",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "proxy",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "deployer",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bytes32",
        "name": "inputSalt",
        "type": "bytes32"
      },
      {
        "indexed": false,
        "internalType": "bytes",
        "name": "data",
        "type": "bytes"
      },
      {
        "indexed": false,
        "internalType": "bytes",
        "name": "extraData",
        "type": "bytes"
      }
    ],
    "name": "ProxyDeployedV2",
    "type": "event"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_implementation",
        "type": "address"
      },
      {
        "internalType": "bytes",
        "name": "_data",
        "type": "bytes"
      },
      {
        "internalType": "bytes32",
        "name": "_salt",
        "type": "bytes32"
      }
    ],
    "name": "deployProxyByImplementation",
    "outputs": [
      {
        "internalType": "address",
        "name": "deployedProxy",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "implementation",
        "type": "address"
      },
      {
        "internalType": "bytes",
        "name": "data",
        "type": "bytes"
      },
      {
        "internalType": "bytes32",
        "name": "salt",
        "type": "bytes32"
      },
      {
        "internalType": "bytes",
        "name": "extraData",
        "type": "bytes"
      }
    ],
    "name": "deployProxyByImplementationV2",
    "outputs": [
      {
        "internalType": "address",
        "name": "deployedProxy",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;

import {LibClone} from "@solady/utils/LibClone.sol";

contract TWCloneFactory {

    error ProxyDeploymentFailed();

    /// Deprecated
    /// @dev Emitted when a proxy is deployed.
    event ProxyDeployed(address indexed implementation, address proxy, address indexed deployer);

    /// @dev Emitted when a proxy is deployed.
    event ProxyDeployedV2(
        address indexed implementation,
        address indexed proxy,
        address indexed deployer,
        bytes32 inputSalt,
        bytes data,
        bytes extraData
    );

    /// Deprecated
    /// @dev Deploys a proxy that points to the given implementation.
    function deployProxyByImplementation(address _implementation, bytes memory _data, bytes32 _salt)
        public
        returns (address deployedProxy)
    {
        bytes32 saltHash = keccak256(abi.encodePacked(msg.sender, _salt));
        deployedProxy = LibClone.cloneDeterministic(_implementation, saltHash);

        emit ProxyDeployed(_implementation, deployedProxy, msg.sender);

        if (_data.length > 0) {
            // slither-disable-next-line unused-return
            (bool success,) = deployedProxy.call(_data);

            if (!success) {
                revert ProxyDeploymentFailed();
            }
        }
    }

    /// @dev Deploys a proxy that points to the given implementation.
    function deployProxyByImplementationV2(
        address implementation,
        bytes memory data,
        bytes32 salt,
        bytes memory extraData
    ) public returns (address deployedProxy) {
        bytes32 saltHash = _guard(salt, data);
        deployedProxy = LibClone.cloneDeterministic(implementation, saltHash);

        emit ProxyDeployedV2(implementation, deployedProxy, msg.sender, salt, data, extraData);

        if (data.length > 0) {
            // slither-disable-next-line unused-return
            (bool success,) = deployedProxy.call(data);

            if (!success) {
                revert ProxyDeploymentFailed();
            }
        }
    }

    function _guard(bytes32 salt, bytes memory data) internal view returns (bytes32) {
        // check bit 0
        bool allowCrossChainDeployment = (salt[0] & bytes1(uint8(1))) != bytes1(0);
        // check bit 1
        bool encodeDataIntoSalt = (salt[0] & bytes1(uint8(2))) != bytes1(0);
        // check bit 2
        bool useMsgSender = (salt[0] & bytes1(uint8(4))) != bytes1(0);

        bytes32 saltHash;
        if (allowCrossChainDeployment && encodeDataIntoSalt) {
            saltHash = keccak256(abi.encode(salt, data));
        } else if (allowCrossChainDeployment && !encodeDataIntoSalt) {
            saltHash = keccak256(abi.encode(salt));
        } else if (!allowCrossChainDeployment && encodeDataIntoSalt) {
            saltHash = keccak256(abi.encode(salt, block.chainid, data));
        } else {
            saltHash = keccak256(abi.encode(salt, block.chainid));
        }

        if(useMsgSender) {
            keccak256(abi.encode(saltHash, msg.sender));
        }

        return saltHash;
    }

}
Chain explorer6053msChain node105ms