11// SPDX-License-Identifier: MIT
22pragma solidity 0.8.24 ;
33
4- import "@openzeppelin/contracts/proxy/Clones .sol " ;
4+ import "@openzeppelin/contracts/utils/Create2 .sol " ;
55import {LibString} from "solady/utils/LibString.sol " ;
66import "./FixedFungibleERC20.sol " ;
7+ import "./libraries/Proxy.sol " ;
78import "./Ethscriptions.sol " ;
89import "./libraries/Predeploys.sol " ;
910import "./interfaces/IProtocolHandler.sol " ;
@@ -12,7 +13,6 @@ import "./interfaces/IProtocolHandler.sol";
1213/// @notice Implements the fixed-fungible token protocol enforced via Ethscriptions transfers
1314/// @dev Deploys and controls FixedFungible ERC-20 clones; callable only by the Ethscriptions contract
1415contract FixedFungibleProtocolHandler is IProtocolHandler {
15- using Clones for address ;
1616 using LibString for string ;
1717
1818 // =============================================================
@@ -50,8 +50,8 @@ contract FixedFungibleProtocolHandler is IProtocolHandler {
5050 // CONSTANTS
5151 // =============================================================
5252
53- /// @dev Deterministic template contract used for clone deployments
54- address public constant fixedFungibleTemplate = Predeploys.FIXED_FUNGIBLE_TEMPLATE_IMPLEMENTATION;
53+ /// @dev Implementation contract used for proxy deployments
54+ address public constant fixedFungibleImplementation = Predeploys.FIXED_FUNGIBLE_TEMPLATE_IMPLEMENTATION;
5555 address public constant ethscriptions = Predeploys.ETHSCRIPTIONS;
5656 string public constant CANONICAL_PROTOCOL = "fixed-fungible " ;
5757 string public constant PRETTY_PROTOCOL = "Fixed-Fungible " ;
@@ -140,25 +140,29 @@ contract FixedFungibleProtocolHandler is IProtocolHandler {
140140 if (deployOp.mintAmount == 0 ) revert InvalidMintAmount ();
141141 if (deployOp.maxSupply % deployOp.mintAmount != 0 ) revert MaxSupplyNotDivisibleByMintAmount ();
142142
143- // Deploy ERC20 clone with CREATE2 using tickKey as salt for deterministic address
144- address tokenAddress = fixedFungibleTemplate. cloneDeterministic ( tickKey);
143+ // Deploy a Proxy via CREATE2 with this handler as temporary admin for initialization
144+ Proxy tokenProxy = new Proxy {salt: tickKey}( address ( this ) );
145145
146- // Initialize the clone
146+ // Build name/symbol and initialization calldata
147147 string memory name = string .concat (PRETTY_PROTOCOL, " " , deployOp.tick);
148148 string memory symbol = LibString.upper (deployOp.tick);
149-
150149 // Initialize with max supply in 18 decimals
151150 // User maxSupply "1000000" means 1000000 * 10^18 smallest units
152- FixedFungibleERC20 (tokenAddress).initialize (
151+ bytes memory initCalldata = abi.encodeWithSelector (
152+ FixedFungibleERC20.initialize.selector ,
153153 name,
154154 symbol,
155155 deployOp.maxSupply * 10 ** 18 ,
156156 ethscriptionId
157157 );
158+ // Set implementation and run initialize as admin
159+ tokenProxy.upgradeToAndCall (fixedFungibleImplementation, initCalldata);
160+ // Hand off admin to global ProxyAdmin so upgrades require system governance
161+ tokenProxy.changeAdmin (Predeploys.PROXY_ADMIN);
158162
159163 // Store token info
160164 tokensByTick[tickKey] = TokenInfo ({
161- tokenContract: tokenAddress ,
165+ tokenContract: address (tokenProxy) ,
162166 deployEthscriptionId: ethscriptionId,
163167 tick: deployOp.tick,
164168 maxSupply: deployOp.maxSupply,
@@ -171,7 +175,7 @@ contract FixedFungibleProtocolHandler is IProtocolHandler {
171175
172176 emit FixedFungibleTokenDeployed (
173177 ethscriptionId,
174- tokenAddress ,
178+ address (tokenProxy) ,
175179 deployOp.tick,
176180 deployOp.maxSupply,
177181 deployOp.mintAmount
@@ -290,8 +294,9 @@ contract FixedFungibleProtocolHandler is IProtocolHandler {
290294 return tokensByTick[tickKey].tokenContract;
291295 }
292296
293- // Predict using CREATE2
294- return Clones.predictDeterministicAddress (fixedFungibleTemplate, tickKey, address (this ));
297+ // Predict using CREATE2 for Proxy with constructor arg (admin = address(this))
298+ bytes memory creationCode = abi.encodePacked (type (Proxy).creationCode, abi.encode (address (this )));
299+ return Create2.computeAddress (tickKey, keccak256 (creationCode), address (this ));
295300 }
296301
297302 /// @notice Check if an ethscription is a token item
0 commit comments