Skip to content

Commit 3be3820

Browse files
Merge pull request #122 from ethscriptions-protocol/refactor
Refactor contracts
2 parents a303cc0 + e28f496 commit 3be3820

29 files changed

+1042
-684
lines changed

contracts/script/L2Genesis.s.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ contract GenesisEthscriptions is Ethscriptions {
3232
require(ethscriptions[params.transactionHash].creator == address(0), "Ethscription already exists");
3333

3434
// Check protocol uniqueness using content URI hash
35-
if (contentUriExists[params.contentUriHash]) {
35+
if (firstEthscriptionByContentUri[params.contentUriHash] != bytes32(0)) {
3636
if (!params.esip6) revert DuplicateContentUri();
3737
}
3838

3939
// Store content and get content SHA (reusing parent's helper)
4040
bytes32 contentSha = _storeContent(params.content);
4141

42-
// Mark content URI as used
43-
contentUriExists[params.contentUriHash] = true;
42+
// Mark content URI as used by storing this ethscription's tx hash
43+
firstEthscriptionByContentUri[params.contentUriHash] = params.transactionHash;
4444

4545
// Set all values including genesis-specific ones
4646
ethscriptions[params.transactionHash] = Ethscription({
@@ -341,7 +341,7 @@ contract L2Genesis is Script {
341341
params.mimeSubtype = vm.parseJsonString(json, string.concat(basePath, ".mime_subtype"));
342342
params.esip6 = vm.parseJsonBool(json, string.concat(basePath, ".esip6"));
343343
params.protocolParams = Ethscriptions.ProtocolParams({
344-
protocol: "",
344+
protocolName: "",
345345
operation: "",
346346
data: ""
347347
});

contracts/src/Ethscriptions.sol

Lines changed: 307 additions & 486 deletions
Large diffs are not rendered by default.

contracts/src/EthscriptionsERC20.sol

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,47 +5,97 @@ import "./ERC20NullOwnerCappedUpgradeable.sol";
55
import "./libraries/Predeploys.sol";
66

77
/// @title EthscriptionsERC20
8-
/// @notice ERC20 with cap that supports null address ownership; only TokenManager can mint/transfer
8+
/// @notice ERC20 with cap that supports null address ownership
9+
/// @dev Only TokenManager can mint/transfer. User-initiated transfers are disabled.
910
contract EthscriptionsERC20 is ERC20NullOwnerCappedUpgradeable {
11+
12+
// =============================================================
13+
// CONSTANTS
14+
// =============================================================
15+
16+
/// @notice The TokenManager contract that controls this token
1017
address public constant tokenManager = Predeploys.TOKEN_MANAGER;
11-
bytes32 public deployTxHash; // The ethscription hash that deployed this token
1218

19+
// =============================================================
20+
// STATE VARIABLES
21+
// =============================================================
22+
23+
/// @notice The ethscription hash that deployed this token
24+
bytes32 public deployTxHash;
25+
26+
// =============================================================
27+
// CUSTOM ERRORS
28+
// =============================================================
29+
30+
error OnlyTokenManager();
31+
error TransfersOnlyViaEthscriptions();
32+
error ApprovalsNotAllowed();
33+
34+
// =============================================================
35+
// MODIFIERS
36+
// =============================================================
37+
38+
modifier onlyTokenManager() {
39+
if (msg.sender != tokenManager) revert OnlyTokenManager();
40+
_;
41+
}
42+
43+
// =============================================================
44+
// EXTERNAL FUNCTIONS
45+
// =============================================================
46+
47+
/// @notice Initialize the ERC20 token
48+
/// @param name_ The token name
49+
/// @param symbol_ The token symbol
50+
/// @param cap_ The maximum supply cap (in 18 decimals)
51+
/// @param deployTxHash_ The ethscription hash that deployed this token
1352
function initialize(
1453
string memory name_,
1554
string memory symbol_,
1655
uint256 cap_,
1756
bytes32 deployTxHash_
18-
) public initializer {
57+
) external initializer {
1958
__ERC20_init(name_, symbol_);
2059
__ERC20Capped_init(cap_);
2160
deployTxHash = deployTxHash_;
2261
}
2362

24-
modifier onlyTokenManager() {
25-
require(msg.sender == tokenManager, "Only TokenManager");
26-
_;
27-
}
28-
29-
// TokenManager-only mint that allows to == address(0)
63+
/// @notice Mint tokens (TokenManager only)
64+
/// @dev Allows minting to address(0) for null ownership
65+
/// @param to The recipient address (can be address(0))
66+
/// @param amount The amount to mint (in 18 decimals)
3067
function mint(address to, uint256 amount) external onlyTokenManager {
3168
_mint(to, amount);
3269
}
3370

34-
// TokenManager-only transfer that allows to/from == address(0)
71+
/// @notice Force transfer tokens (TokenManager only)
72+
/// @dev Allows transfers to/from address(0) for null ownership
73+
/// @param from The sender address (can be address(0))
74+
/// @param to The recipient address (can be address(0))
75+
/// @param amount The amount to transfer (in 18 decimals)
3576
function forceTransfer(address from, address to, uint256 amount) external onlyTokenManager {
3677
_update(from, to, amount);
3778
}
3879

39-
// Disable user-initiated ERC20 flows
80+
// =============================================================
81+
// DISABLED ERC20 FUNCTIONS
82+
// =============================================================
83+
84+
/// @notice User-initiated transfers are disabled
85+
/// @dev All transfers must go through the Ethscriptions NFT
4086
function transfer(address, uint256) public pure override returns (bool) {
41-
revert("Transfers only allowed via Ethscriptions NFT");
87+
revert TransfersOnlyViaEthscriptions();
4288
}
4389

90+
/// @notice User-initiated transfers are disabled
91+
/// @dev All transfers must go through the Ethscriptions NFT
4492
function transferFrom(address, address, uint256) public pure override returns (bool) {
45-
revert("Transfers only allowed via Ethscriptions NFT");
93+
revert TransfersOnlyViaEthscriptions();
4694
}
4795

96+
/// @notice Approvals are disabled
97+
/// @dev All transfers are controlled by the TokenManager
4898
function approve(address, uint256) public pure override returns (bool) {
49-
revert("Approvals not allowed");
99+
revert ApprovalsNotAllowed();
50100
}
51-
}
101+
}

contracts/src/EthscriptionsProver.sol

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet
1313
contract EthscriptionsProver {
1414
using EnumerableSet for EnumerableSet.Bytes32Set;
1515

16+
// =============================================================
17+
// STRUCTS
18+
// =============================================================
19+
1620
/// @notice Info stored when an ethscription is queued for proving
1721
struct QueuedProof {
1822
uint256 l2BlockNumber;
@@ -21,21 +25,6 @@ contract EthscriptionsProver {
2125
uint256 l1BlockNumber;
2226
}
2327

24-
/// @notice Set of all ethscription transaction hashes queued for proving
25-
EnumerableSet.Bytes32Set private queuedEthscriptions;
26-
27-
/// @notice Mapping from ethscription tx hash to its queued proof info
28-
mapping(bytes32 => QueuedProof) private queuedProofInfo;
29-
30-
/// @notice L1Block contract address for access control
31-
address public constant L1_BLOCK = Predeploys.L1_BLOCK_ATTRIBUTES;
32-
/// @notice L2ToL1MessagePasser predeploy address on OP Stack
33-
L2ToL1MessagePasser constant L2_TO_L1_MESSAGE_PASSER =
34-
L2ToL1MessagePasser(Predeploys.L2_TO_L1_MESSAGE_PASSER);
35-
36-
/// @notice The Ethscriptions contract (pre-deployed at known address)
37-
Ethscriptions public constant ethscriptions = Ethscriptions(Predeploys.ETHSCRIPTIONS);
38-
3928
/// @notice Struct for ethscription data proof
4029
struct EthscriptionDataProof {
4130
bytes32 ethscriptionTxHash;
@@ -51,19 +40,58 @@ contract EthscriptionsProver {
5140
uint256 l2BlockNumber;
5241
uint256 l2Timestamp;
5342
}
54-
55-
/// @notice Events for tracking proofs
43+
44+
// =============================================================
45+
// CONSTANTS
46+
// =============================================================
47+
48+
/// @notice L1Block contract address for access control
49+
address constant L1_BLOCK = Predeploys.L1_BLOCK_ATTRIBUTES;
50+
51+
/// @notice L2ToL1MessagePasser predeploy address on OP Stack
52+
L2ToL1MessagePasser constant L2_TO_L1_MESSAGE_PASSER =
53+
L2ToL1MessagePasser(Predeploys.L2_TO_L1_MESSAGE_PASSER);
54+
55+
/// @notice The Ethscriptions contract (pre-deployed at known address)
56+
Ethscriptions constant ethscriptions = Ethscriptions(Predeploys.ETHSCRIPTIONS);
57+
58+
// =============================================================
59+
// STATE VARIABLES
60+
// =============================================================
61+
62+
/// @notice Set of all ethscription transaction hashes queued for proving
63+
EnumerableSet.Bytes32Set private queuedEthscriptions;
64+
65+
/// @notice Mapping from ethscription tx hash to its queued proof info
66+
mapping(bytes32 => QueuedProof) private queuedProofInfo;
67+
68+
// =============================================================
69+
// CUSTOM ERRORS
70+
// =============================================================
71+
72+
error OnlyEthscriptions();
73+
error OnlyL1Block();
74+
75+
// =============================================================
76+
// EVENTS
77+
// =============================================================
78+
79+
/// @notice Emitted when an ethscription data proof is sent to L1
5680
event EthscriptionDataProofSent(
5781
bytes32 indexed ethscriptionTxHash,
5882
uint256 indexed l2BlockNumber,
5983
uint256 l2Timestamp
6084
);
6185

86+
// =============================================================
87+
// EXTERNAL FUNCTIONS
88+
// =============================================================
89+
6290
/// @notice Queue an ethscription for proving
6391
/// @dev Only callable by the Ethscriptions contract
6492
/// @param txHash The transaction hash of the ethscription
6593
function queueEthscription(bytes32 txHash) external virtual {
66-
require(msg.sender == address(ethscriptions), "Only Ethscriptions contract can queue");
94+
if (msg.sender != address(ethscriptions)) revert OnlyEthscriptions();
6795

6896
// Add to the set (deduplicates automatically)
6997
if (queuedEthscriptions.add(txHash)) {
@@ -82,7 +110,7 @@ contract EthscriptionsProver {
82110
/// @notice Flush all queued proofs
83111
/// @dev Only callable by the L1Block contract at the start of each new block
84112
function flushAllProofs() external {
85-
require(msg.sender == L1_BLOCK, "Only L1Block can flush");
113+
if (msg.sender != L1_BLOCK) revert OnlyL1Block();
86114

87115
uint256 count = queuedEthscriptions.length();
88116

@@ -100,13 +128,17 @@ contract EthscriptionsProver {
100128
}
101129
}
102130

131+
// =============================================================
132+
// INTERNAL FUNCTIONS
133+
// =============================================================
134+
103135
/// @notice Internal function to create and send proof for an ethscription
104136
/// @param ethscriptionTxHash The transaction hash of the ethscription
105137
/// @param proofInfo The queued proof info containing block data
106138
function _createAndSendProof(bytes32 ethscriptionTxHash, QueuedProof memory proofInfo) internal {
107139
// Get ethscription data including previous owner
108140
Ethscriptions.Ethscription memory etsc = ethscriptions.getEthscription(ethscriptionTxHash);
109-
address currentOwner = ethscriptions.currentOwner(ethscriptionTxHash);
141+
address currentOwner = ethscriptions.ownerOf(ethscriptionTxHash);
110142

111143
// Create proof struct with all ethscription data
112144
EthscriptionDataProof memory proof = EthscriptionDataProof({
@@ -130,5 +162,4 @@ contract EthscriptionsProver {
130162

131163
emit EthscriptionDataProofSent(ethscriptionTxHash, proofInfo.l2BlockNumber, proofInfo.l2BlockTimestamp);
132164
}
133-
134165
}

contracts/src/L2/L1Block.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ contract L1Block {
9090
}
9191

9292
function _flushProofsIfLive() internal {
93-
if (block.timestamp >= 1760630077) {
93+
if (block.timestamp >= Constants.historicalBackfillApproxDoneAt) {
9494
// Each proof includes its own block number and timestamp from when it was queued
9595
IEthscriptionsProver(Predeploys.ETHSCRIPTIONS_PROVER).flushAllProofs();
9696
}

0 commit comments

Comments
 (0)