// SPDX-License-Identifier: MIT // OpenZeppelin Tron Contracts (last updated v5.5.0) (utils/Create2.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; import {LowLevelCall} from "./LowLevelCall.sol"; /** * @dev Helper to make usage of the `CREATE2` opcode easier and safer. * `CREATE2` can be used to compute in advance the address where a smart * contract will be deployed, which allows for interesting new mechanisms known * as 'counterfactual interactions'. * * On TVM the deterministic address derivation uses the `0x41` hash prefix * defined by https://github.com/tronprotocol/tips/blob/master/tip-26.md[TIP-26] * (the TRON-side analogue of https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP-1014], * which uses `0xff`). {computeAddress} mirrors what TVM's `create2` opcode computes on-chain. */ library Create2 { /** * @dev There's no code to deploy. */ error Create2EmptyBytecode(); /** * @dev Deploys a contract using `CREATE2`. The address where the contract * will be deployed can be known in advance via {computeAddress}. * * The bytecode for a contract can be obtained from Solidity with * `type(contractName).creationCode`. * * Requirements: * * - `bytecode` must not be empty. * - `salt` must have not been used for `bytecode` already. * - the factory must have a balance of at least `amount`. * - if `amount` is non-zero, `bytecode` must have a `payable` constructor. */ function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } if (bytecode.length == 0) { revert Create2EmptyBytecode(); } // On TVM a `create2` that collides with an already-deployed address can consume // (near-)the full energy budget before the opcode-level failure surfaces, turning // repeated collisions into an energy-griefing vector (especially when sponsored or // batched). Reject the collision cheaply by checking the predicted address for code // before attempting the expensive deployment. if (computeAddress(salt, keccak256(bytecode)).code.length != 0) { revert Errors.FailedDeployment(); } assembly ("memory-safe") { addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) } if (addr == address(0)) { if (LowLevelCall.returnDataSize() == 0) { revert Errors.FailedDeployment(); } else { LowLevelCall.bubbleRevert(); } } // `create2` can "succeed" with a non-zero address while depositing no runtime code (e.g. // initcode that returns empty data or self-destructs during construction). Such an address // is not callable, so callers that record/initialize/fund it would silently no-op. Reject it. if (addr.code.length == 0) { revert Errors.FailedDeployment(); } } /** * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the * `bytecodeHash` or `salt` will result in a new destination address. */ function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) { return computeAddress(salt, bytecodeHash, address(this)); } /** * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}. */ function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) { assembly ("memory-safe") { let ptr := mload(0x40) // Get free memory pointer // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... | // |---------------------|---------------------------------------------------------------------------| // | bytecodeHash | CCCCCCCCCCCCC...CC | // | salt | BBBBBBBBBBBBB...BB | // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA | // | 0x41 | 41 | // |---------------------|---------------------------------------------------------------------------| // | memory | 000000...0041AAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC | // | keccak(start, 0x55) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ | mstore(add(ptr, 0x40), bytecodeHash) mstore(add(ptr, 0x20), salt) mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes // TIP-26 CREATE2 hash prefix is 0x41, not the EVM 0xff. The hashed data // starts at the final garbage byte, which we set to 0x41 so this matches // what TVM's create2 opcode computes on-chain. let start := add(ptr, 0x0b) mstore8(start, 0x41) addr := and(keccak256(start, 0x55), 0xffffffffffffffffffffffffffffffffffffffff) } } }