Skip to content

Commit 30bf95c

Browse files
Merge pull request #119 from ethscriptions-protocol/predeploy_proxies
Predeploys should be proxies
2 parents 623256c + 232e539 commit 30bf95c

File tree

7 files changed

+87
-39
lines changed

7 files changed

+87
-39
lines changed

contracts/script/L2Genesis.s.sol

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -183,24 +183,42 @@ contract L2Genesis is Script {
183183

184184
/// @notice Set up Ethscriptions system contracts
185185
function setEthscriptionsPredeploys() internal {
186-
// Create genesis Ethscriptions first (this handles the Ethscriptions contract setup)
186+
// Ensure proxies exist across the full 0x330… namespace, mirroring OP's approach
187+
bytes memory proxyCode = vm.getDeployedCode("Proxy.sol:Proxy");
188+
uint160 prefix = uint160(0x330) << 148;
187189

188-
// Deploy other Ethscriptions-related contracts
189-
_setEthscriptionsCode(Predeploys.TOKEN_MANAGER, "TokenManager");
190-
_setEthscriptionsCode(Predeploys.COLLECTIONS_MANAGER, "CollectionsManager");
191-
_setEthscriptionsCode(Predeploys.ETHSCRIPTIONS_PROVER, "EthscriptionsProver");
192-
_setEthscriptionsCode(Predeploys.ERC20_TEMPLATE, "EthscriptionsERC20");
193-
_setEthscriptionsCode(Predeploys.ERC721_TEMPLATE, "EthscriptionERC721");
190+
for (uint256 i = 0; i < PREDEPLOY_COUNT; i++) {
191+
address addr = address(prefix | uint160(i));
194192

193+
// Deploy proxy shell and prime nonce for deterministic CREATEs
194+
vm.etch(addr, proxyCode);
195+
vm.setNonce(addr, 1);
196+
setProxyAdminSlot(addr, Predeploys.PROXY_ADMIN);
197+
198+
// Wire up implementations for the Ethscriptions predeploys that use proxies
199+
bool isProxiedContract = addr == Predeploys.ETHSCRIPTIONS ||
200+
addr == Predeploys.TOKEN_MANAGER ||
201+
addr == Predeploys.ETHSCRIPTIONS_PROVER ||
202+
addr == Predeploys.COLLECTIONS_MANAGER;
203+
if (isProxiedContract) {
204+
address impl = Predeploys.predeployToCodeNamespace(addr);
205+
setImplementation(addr, impl);
206+
}
207+
}
208+
209+
// Set implementation code for non-ETHSCRIPTIONS contracts now
210+
_setImplementationCodeNamed(Predeploys.TOKEN_MANAGER, "TokenManager");
211+
_setImplementationCodeNamed(Predeploys.COLLECTIONS_MANAGER, "CollectionsManager");
212+
_setImplementationCodeNamed(Predeploys.ETHSCRIPTIONS_PROVER, "EthscriptionsProver");
213+
// Templates live directly at their implementation addresses (no proxy wrapping)
214+
_setCodeAt(Predeploys.ERC20_TEMPLATE_IMPLEMENTATION, "EthscriptionsERC20");
215+
_setCodeAt(Predeploys.ERC721_TEMPLATE_IMPLEMENTATION, "EthscriptionERC721");
216+
217+
// Create genesis Ethscriptions (writes via proxy to proxy storage)
195218
createGenesisEthscriptions();
196219

197-
// Register protocol handlers
220+
// Register protocol handlers via the Ethscriptions proxy
198221
registerProtocolHandlers();
199-
200-
// Disable initializers on all Ethscriptions contracts
201-
_disableInitializers(Predeploys.ETHSCRIPTIONS);
202-
_disableInitializers(Predeploys.ERC20_TEMPLATE);
203-
_disableInitializers(Predeploys.ERC721_TEMPLATE);
204222
}
205223

206224
/// @notice Register protocol handlers with the Ethscriptions contract
@@ -265,13 +283,15 @@ contract L2Genesis is Script {
265283
uint256 totalCount = abi.decode(vm.parseJson(json, ".metadata.totalCount"), (uint256));
266284
console.log("Found", totalCount, "genesis Ethscriptions");
267285

268-
// First, etch the GenesisEthscriptions contract temporarily
269-
address ethscriptionsAddr = Predeploys.ETHSCRIPTIONS;
270-
vm.etch(ethscriptionsAddr, type(GenesisEthscriptions).runtimeCode);
286+
// Use the Ethscriptions proxy address and its implementation code-namespace address
287+
address ethscriptionsProxy = Predeploys.ETHSCRIPTIONS;
288+
address implAddr = Predeploys.predeployToCodeNamespace(ethscriptionsProxy);
271289

272-
vm.setNonce(ethscriptionsAddr, 1);
290+
// Temporarily etch GenesisEthscriptions at the implementation address
291+
vm.etch(implAddr, type(GenesisEthscriptions).runtimeCode);
273292

274-
GenesisEthscriptions genesisContract = GenesisEthscriptions(ethscriptionsAddr);
293+
// Call through the proxy using the GenesisEthscriptions interface
294+
GenesisEthscriptions genesisContract = GenesisEthscriptions(ethscriptionsProxy);
275295

276296
// Process each ethscription (this will increment the nonce as SSTORE2 contracts are deployed)
277297
for (uint256 i = 0; i < totalCount; i++) {
@@ -280,9 +300,9 @@ contract L2Genesis is Script {
280300

281301
console.log("Created", totalCount, "genesis Ethscriptions");
282302

283-
// Now etch the real Ethscriptions contract over the GenesisEthscriptions
284-
// IMPORTANT: Do NOT reset the nonce here - it needs to continue from where it left off
285-
_setEthscriptionsCode(ethscriptionsAddr, "Ethscriptions");
303+
// Overwrite the implementation bytecode with the real Ethscriptions
304+
// Do not reset nonce on the proxy; we only swap the implementation code
305+
_setImplementationCodeNamed(Predeploys.ETHSCRIPTIONS, "Ethscriptions");
286306
}
287307

288308
/// @notice Helper to create a single genesis ethscription
@@ -343,11 +363,22 @@ contract L2Genesis is Script {
343363
vm.store(_addr, Constants.INITIALIZABLE_STORAGE, bytes32(uint256(0x000000000000000000000000000000000000000000000000ffffffffffffffff)));
344364
}
345365

346-
/// @notice Set bytecode for Ethscriptions contracts
347-
function _setEthscriptionsCode(address _addr, string memory _name) internal {
366+
/// @notice Set implementation bytecode for a given predeploy using an explicit contract name
367+
function _setImplementationCodeNamed(address _predeploy, string memory _name) internal returns (address impl) {
368+
impl = Predeploys.predeployToCodeNamespace(_predeploy);
369+
bytes memory code = vm.getDeployedCode(string.concat(_name, ".sol:", _name));
370+
console.log("Setting implementation code for", _predeploy, "to", impl);
371+
372+
_disableInitializers(impl);
373+
374+
vm.etch(impl, code);
375+
}
376+
377+
/// @notice Etch contract bytecode directly at a target address (used for non-proxy templates)
378+
function _setCodeAt(address _addr, string memory _name) internal {
348379
bytes memory code = vm.getDeployedCode(string.concat(_name, ".sol:", _name));
380+
_disableInitializers(_addr);
349381
vm.etch(_addr, code);
350-
// Don't reset nonce here - let the caller manage it
351382
}
352383

353384
/// @notice Set the admin of a proxy contract

contracts/src/CollectionsManager.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ contract CollectionsManager is IProtocolHandler {
9696
// Note: Similar to ItemData but without ethscriptionId (can't change)
9797
}
9898

99-
address public constant erc721Template = Predeploys.ERC721_TEMPLATE;
99+
address public constant erc721Template = Predeploys.ERC721_TEMPLATE_IMPLEMENTATION;
100100
address public constant ethscriptions = Predeploys.ETHSCRIPTIONS;
101101

102102
// Track deployed collections by ID

contracts/src/TokenManager.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ contract TokenManager is IProtocolHandler {
4040
uint256 amount;
4141
}
4242

43-
address public constant erc20Template = Predeploys.ERC20_TEMPLATE;
43+
address public constant erc20Template = Predeploys.ERC20_TEMPLATE_IMPLEMENTATION;
4444
address public constant ethscriptions = Predeploys.ETHSCRIPTIONS;
4545

4646
// Track deployed tokens by protocol+tick for find-or-create

contracts/src/libraries/Predeploys.sol

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,49 @@ library Predeploys {
1919
address constant PROXY_ADMIN = 0x4200000000000000000000000000000000000018;
2020

2121
// ============ Ethscriptions System Predeploys ============
22-
// Using 0xee namespace for Ethscriptions contracts
22+
// Using 0x3300… namespace for Ethscriptions contracts
2323

2424
/// @notice Ethscriptions NFT contract
25-
address constant ETHSCRIPTIONS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
25+
/// @dev Moved to the 0x3300… namespace to align with other Ethscriptions predeploys
26+
address constant ETHSCRIPTIONS = 0x3300000000000000000000000000000000000001;
2627

2728
/// @notice TokenManager for ERC20 token creation
2829
address constant TOKEN_MANAGER = 0x3300000000000000000000000000000000000002;
2930

3031
/// @notice EthscriptionsProver for L1 provability
3132
address constant ETHSCRIPTIONS_PROVER = 0x3300000000000000000000000000000000000003;
32-
33-
/// @notice EthscriptionsERC20 template for cloning
34-
address constant ERC20_TEMPLATE = 0x3300000000000000000000000000000000000004;
3533

36-
/// @notice EthscriptionERC721 template for cloning (collections)
37-
address constant ERC721_TEMPLATE = 0x3300000000000000000000000000000000000005;
34+
/// @notice Proxy address reserved for the ERC20 template (blank proxy)
35+
address constant ERC20_TEMPLATE_PROXY = 0x3300000000000000000000000000000000000004;
36+
37+
/// @notice Implementation address for the ERC20 template (actual logic contract)
38+
address constant ERC20_TEMPLATE_IMPLEMENTATION = 0xc0D3c0D3c0D3c0d3c0d3C0d3C0d3c0D3C0D30004;
39+
40+
/// @notice Proxy address reserved for the ERC721 template (blank proxy)
41+
address constant ERC721_TEMPLATE_PROXY = 0x3300000000000000000000000000000000000005;
42+
43+
/// @notice Implementation address for the ERC721 template (actual logic contract)
44+
address constant ERC721_TEMPLATE_IMPLEMENTATION = 0xc0d3C0d3c0D3c0d3C0D3C0D3c0D3C0D3c0d30005;
3845

3946
/// @notice CollectionsManager for collections protocol
4047
address constant COLLECTIONS_MANAGER = 0x3300000000000000000000000000000000000006;
4148

4249
// ============ Helper Functions ============
4350

44-
/// @notice Returns true if the address is a predeploy
45-
function isPredeployNamespace(address _addr) internal pure returns (bool) {
51+
/// @notice Returns true if the address is an OP Stack predeploy (0x4200… namespace)
52+
function isOPPredeployNamespace(address _addr) internal pure returns (bool) {
4653
return uint160(_addr) >> 11 == uint160(0x4200000000000000000000000000000000000000) >> 11;
4754
}
55+
56+
/// @notice Returns true if the address is an Ethscriptions predeploy (0x3300… namespace)
57+
function isEthscriptionsPredeployNamespace(address _addr) internal pure returns (bool) {
58+
return uint160(_addr) >> 11 == uint160(0x3300000000000000000000000000000000000000) >> 11;
59+
}
60+
61+
/// @notice Returns true if the address is a recognized predeploy (OP or Ethscriptions)
62+
function isPredeployNamespace(address _addr) internal pure returns (bool) {
63+
return isOPPredeployNamespace(_addr) || isEthscriptionsPredeployNamespace(_addr);
64+
}
4865

4966
/// @notice Converts a predeploy address to its code namespace equivalent
5067
function predeployToCodeNamespace(address _addr) internal pure returns (address) {
@@ -56,4 +73,4 @@ library Predeploys {
5673
uint160(uint256(uint160(_addr)) & 0xffff | uint256(uint160(0xc0D3C0d3C0d3C0D3c0d3C0d3c0D3C0d3c0d30000)))
5774
);
5875
}
59-
}
76+
}

lib/event_decoder.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class EventDecoder
1616
'Transfer(address,address,uint256)'
1717
).unpack1('H*')
1818

19-
ETHSCRIPTIONS_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'
19+
ETHSCRIPTIONS_ADDRESS = SysConfig::ETHSCRIPTIONS_ADDRESS.to_hex
2020

2121
class << self
2222
def decode_receipt_logs(receipt)

lib/storage_reader.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class StorageReader
2-
ETHSCRIPTIONS_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'
2+
ETHSCRIPTIONS_ADDRESS = SysConfig::ETHSCRIPTIONS_ADDRESS.to_hex
33

44
# Define the nested ContentInfo struct
55
CONTENT_INFO_STRUCT = {

lib/sys_config.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module SysConfig
88
# System addresses (matching Solidity contracts)
99
SYSTEM_ADDRESS = Address20.from_hex("0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001")
1010
L1_INFO_ADDRESS = Address20.from_hex("0x4200000000000000000000000000000000000015")
11-
ETHSCRIPTIONS_ADDRESS = Address20.from_hex("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE")
11+
ETHSCRIPTIONS_ADDRESS = Address20.from_hex("0x3300000000000000000000000000000000000001")
1212
TOKEN_MANAGER_ADDRESS = Address20.from_hex("0x3300000000000000000000000000000000000002")
1313

1414
# Deposit transaction domains

0 commit comments

Comments
 (0)