|
| 1 | +// SPDX-License-Identifier: UNLICENSED |
| 2 | +// Reconstructed from FACTORY_CODE bytecode in FreezeTest.java |
| 3 | +// Compiler: tron-solc ^0.5.16 |
| 4 | +// |
| 5 | +// FACTORY_CODE contains two nested contracts: |
| 6 | +// Factory (outer) — deploys FreezeContract via CREATE / CREATE2 |
| 7 | +// FreezeContract (inner) — freeze/unfreeze operations with TRON-specific opcodes |
| 8 | + |
| 9 | +pragma solidity ^0.5.16; |
| 10 | + |
| 11 | +// ============================================================ |
| 12 | +// Inner contract — deployed by Factory via CREATE / CREATE2 |
| 13 | +// ============================================================ |
| 14 | +contract FreezeContract { |
| 15 | + |
| 16 | + // selector: 0x00f55d9d |
| 17 | + function destroy(address payable target) external { |
| 18 | + selfdestruct(target); |
| 19 | + } |
| 20 | + |
| 21 | + // selector: 0x30e1e4e5 |
| 22 | + // Freeze TRX for target, then return time remaining until expiry |
| 23 | + function freeze(address payable target, uint256 amount, uint256 res) |
| 24 | + external returns (uint256) |
| 25 | + { |
| 26 | + target.freeze(amount, res); // TRON opcode 0xd5 (FREEZE) |
| 27 | + // STATICCALL to this.getExpireTime(target, res), then subtract |
| 28 | + return block.timestamp |
| 29 | + - address(this).getExpireTime(target, res); |
| 30 | + } |
| 31 | + |
| 32 | + // selector: 0x7b46b80b |
| 33 | + function unfreeze(address payable target, uint256 res) |
| 34 | + external returns (uint256) |
| 35 | + { |
| 36 | + target.unfreeze(res); // TRON opcode 0xd6 (UNFREEZE) |
| 37 | + return 1; |
| 38 | + } |
| 39 | + |
| 40 | + // selector: 0xe7aa4e0b |
| 41 | + function getExpireTime(address payable target, uint256 res) |
| 42 | + external view returns (uint256) |
| 43 | + { |
| 44 | + return target.freezeExpireTime(res); // TRON opcode 0xd7 (FREEZEEXPIRETIME) |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +// ============================================================ |
| 49 | +// Factory contract — outer layer |
| 50 | +// ============================================================ |
| 51 | +contract Factory { |
| 52 | + |
| 53 | + // selector: 0x41aa9014 |
| 54 | + // Deploy FreezeContract using CREATE (salt is unused, CREATE ignores it) |
| 55 | + function deployCreate2Contract(uint256 salt) public returns (address) { |
| 56 | + bytes memory bytecode = type(FreezeContract).creationCode; |
| 57 | + address addr; |
| 58 | + assembly { |
| 59 | + addr := create(0, add(bytecode, 0x20), mload(bytecode)) |
| 60 | + } |
| 61 | + require(extcodesize(addr) > 0); |
| 62 | + return addr; |
| 63 | + } |
| 64 | + |
| 65 | + // selector: 0xbb63e785 |
| 66 | + // Predict CREATE2 address without deploying |
| 67 | + // |
| 68 | + // TRON CREATE2 formula (differs from standard EVM): |
| 69 | + // address = keccak256(prefix ++ sender[20] ++ salt[32] ++ keccak256(code)[32])[12:] |
| 70 | + // |
| 71 | + // - Standard EVM uses 0xff as prefix (magic byte) |
| 72 | + // - TRON replaces it with the address prefix byte (0x41 for mainnet, 0xa0 for testnet) |
| 73 | + // - This value is hardcoded at compile time by tron-solc |
| 74 | + // |
| 75 | + function getCreate2Addr(uint256 salt) public view returns (address) { |
| 76 | + bytes memory bytecode = type(FreezeContract).creationCode; |
| 77 | + bytes32 hash = keccak256( |
| 78 | + abi.encodePacked( |
| 79 | + bytes1(0x41), // TRON mainnet address prefix |
| 80 | + address(this), // 20-byte factory address |
| 81 | + salt, // 32-byte salt |
| 82 | + keccak256(bytecode) // 32-byte code hash |
| 83 | + ) |
| 84 | + ); |
| 85 | + return address(uint160(uint256(hash))); |
| 86 | + } |
| 87 | +} |
0 commit comments