Skip to content

Commit 824ac43

Browse files
committed
Simplify
1 parent 0accdc9 commit 824ac43

File tree

4 files changed

+41
-198
lines changed

4 files changed

+41
-198
lines changed

contracts/src/EthscriptionsERC20.sol

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@ pragma solidity 0.8.24;
44
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
55
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20CappedUpgradeable.sol";
66
import "./libraries/Predeploys.sol";
7-
import "./EthscriptionsProver.sol";
87

98
contract EthscriptionsERC20 is ERC20Upgradeable, ERC20CappedUpgradeable {
109
address public constant tokenManager = Predeploys.TOKEN_MANAGER;
11-
EthscriptionsProver public constant prover = EthscriptionsProver(Predeploys.ETHSCRIPTIONS_PROVER);
12-
10+
1311
bytes32 public deployTxHash; // The ethscription hash that deployed this token
1412

1513
function initialize(
@@ -61,21 +59,13 @@ contract EthscriptionsERC20 is ERC20Upgradeable, ERC20CappedUpgradeable {
6159
}
6260

6361
// Required overrides for multiple inheritance
64-
function _update(address from, address to, uint256 value)
65-
internal
66-
override(ERC20Upgradeable, ERC20CappedUpgradeable)
62+
function _update(address from, address to, uint256 value)
63+
internal
64+
override(ERC20Upgradeable, ERC20CappedUpgradeable)
6765
{
6866
super._update(from, to, value);
69-
70-
// Automatically prove token balances after any update including burns
71-
// For transfers: prove both from and to
72-
// For mints (from == address(0)): only prove to
73-
// For burns (to == address(0)): only prove from
74-
if (from != address(0)) {
75-
prover.proveTokenBalance(from, deployTxHash);
76-
}
77-
if (to != address(0)) {
78-
prover.proveTokenBalance(to, deployTxHash);
79-
}
67+
68+
// Token balance proving has been removed in favor of ethscription-only proving
69+
// Token balances can be derived from ethscription ownership and transfer history
8070
}
8171
}

contracts/src/EthscriptionsProver.sol

Lines changed: 26 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
pragma solidity 0.8.24;
33

44
import "./Ethscriptions.sol";
5-
import "./TokenManager.sol";
6-
import "./EthscriptionsERC20.sol";
75
import "./L2/L2ToL1MessagePasser.sol";
6+
import "./L2/L1Block.sol";
87
import "./libraries/Predeploys.sol";
98
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
109

@@ -16,8 +15,10 @@ contract EthscriptionsProver {
1615

1716
/// @notice Info stored when an ethscription is queued for proving
1817
struct QueuedProof {
19-
uint256 blockNumber;
20-
uint256 blockTimestamp;
18+
uint256 l2BlockNumber;
19+
uint256 l2BlockTimestamp;
20+
bytes32 l1BlockHash;
21+
uint256 l1BlockNumber;
2122
}
2223

2324
/// @notice Set of all ethscription transaction hashes queued for proving
@@ -35,83 +36,29 @@ contract EthscriptionsProver {
3536
/// @notice The Ethscriptions contract (pre-deployed at known address)
3637
Ethscriptions public constant ethscriptions = Ethscriptions(Predeploys.ETHSCRIPTIONS);
3738

38-
/// @notice The TokenManager contract (pre-deployed at known address)
39-
TokenManager public constant tokenManager = TokenManager(Predeploys.TOKEN_MANAGER);
40-
41-
/// @notice Struct for token balance proof data
42-
struct TokenBalanceProof {
43-
address holder;
44-
string protocol;
45-
string tick;
46-
uint256 balance;
47-
uint256 l2BlockNumber;
48-
uint256 l2Timestamp;
49-
// TODO: Add l1BlockNumber once we have L2->L1 block mapping
50-
}
51-
5239
/// @notice Struct for ethscription data proof
5340
struct EthscriptionDataProof {
5441
bytes32 ethscriptionTxHash;
5542
bytes32 contentSha;
43+
bytes32 contentUriHash;
5644
address creator;
5745
address currentOwner;
5846
address previousOwner;
5947
uint256 ethscriptionNumber;
60-
bool isToken;
61-
uint256 tokenAmount;
48+
bool esip6;
49+
bytes32 l1BlockHash;
50+
uint256 l1BlockNumber;
6251
uint256 l2BlockNumber;
6352
uint256 l2Timestamp;
64-
// TODO: Add l1BlockNumber once we have L2->L1 block mapping
6553
}
6654

6755
/// @notice Events for tracking proofs
68-
event TokenBalanceProofSent(
69-
address indexed holder,
70-
string tick,
71-
uint256 indexed l2BlockNumber,
72-
uint256 l2Timestamp
73-
);
74-
7556
event EthscriptionDataProofSent(
7657
bytes32 indexed ethscriptionTxHash,
7758
uint256 indexed l2BlockNumber,
7859
uint256 l2Timestamp
7960
);
8061

81-
/// @notice Emitted when a batch of proofs is flushed
82-
event ProofBatchFlushed(uint256 count, uint256 blockNumber);
83-
84-
/// @notice Prove token balance for an address
85-
/// @param holder The address to prove balance for
86-
/// @param deployTxHash The deploy transaction hash (identifies the token type)
87-
function proveTokenBalance(
88-
address holder,
89-
bytes32 deployTxHash
90-
) external {
91-
// Get token info from TokenManager
92-
TokenManager.TokenInfo memory tokenInfo = tokenManager.getTokenInfo(deployTxHash);
93-
94-
// Get balance
95-
EthscriptionsERC20 token = EthscriptionsERC20(tokenInfo.tokenContract);
96-
uint256 balance = token.balanceOf(holder);
97-
98-
// Create proof struct
99-
TokenBalanceProof memory proof = TokenBalanceProof({
100-
holder: holder,
101-
protocol: tokenInfo.protocol,
102-
tick: tokenInfo.tick,
103-
balance: balance,
104-
l2BlockNumber: block.number,
105-
l2Timestamp: block.timestamp
106-
});
107-
108-
// Encode and send to L1 with zero address and gas (only for state recording)
109-
bytes memory proofData = abi.encode(proof);
110-
L2_TO_L1_MESSAGE_PASSER.initiateWithdrawal(address(0), 0, proofData);
111-
112-
emit TokenBalanceProofSent(holder, tokenInfo.tick, block.number, block.timestamp);
113-
}
114-
11562
/// @notice Queue an ethscription for proving
11663
/// @dev Only callable by the Ethscriptions contract
11764
/// @param txHash The transaction hash of the ethscription
@@ -121,9 +68,13 @@ contract EthscriptionsProver {
12168
// Add to the set (deduplicates automatically)
12269
if (queuedEthscriptions.add(txHash)) {
12370
// Only store info if this is the first time we're queueing this txHash
71+
// Capture the L1 block hash and number at the time of queuing
72+
L1Block l1Block = L1Block(L1_BLOCK);
12473
queuedProofInfo[txHash] = QueuedProof({
125-
blockNumber: block.number,
126-
blockTimestamp: block.timestamp
74+
l2BlockNumber: block.number,
75+
l2BlockTimestamp: block.timestamp,
76+
l1BlockHash: l1Block.hash(),
77+
l1BlockNumber: l1Block.number()
12778
});
12879
}
12980
}
@@ -140,55 +91,44 @@ contract EthscriptionsProver {
14091
for (uint256 i = count; i > 0; i--) {
14192
bytes32 txHash = queuedEthscriptions.at(i - 1);
14293

143-
// Get the stored proof info to know which block this was from
144-
QueuedProof memory proofInfo = queuedProofInfo[txHash];
145-
14694
// Create and send proof for current state with stored block info
147-
_createAndSendProof(txHash, proofInfo.blockNumber, proofInfo.blockTimestamp);
95+
_createAndSendProof(txHash, queuedProofInfo[txHash]);
14896

14997
// Clean up: remove from set and delete the proof info
15098
queuedEthscriptions.remove(txHash);
15199
delete queuedProofInfo[txHash];
152100
}
153-
154-
emit ProofBatchFlushed(count, block.number - 1);
155101
}
156102

157103
/// @notice Internal function to create and send proof for an ethscription
158104
/// @param ethscriptionTxHash The transaction hash of the ethscription
159-
/// @param blockNumber The L2 block number being proved
160-
/// @param blockTimestamp The timestamp of the L2 block being proved
161-
function _createAndSendProof(bytes32 ethscriptionTxHash, uint256 blockNumber, uint256 blockTimestamp) internal {
105+
/// @param proofInfo The queued proof info containing block data
106+
function _createAndSendProof(bytes32 ethscriptionTxHash, QueuedProof storage proofInfo) internal {
162107
// Get ethscription data including previous owner
163108
Ethscriptions.Ethscription memory etsc = ethscriptions.getEthscription(ethscriptionTxHash);
164109
address currentOwner = ethscriptions.currentOwner(ethscriptionTxHash);
165110

166-
// Check if it's a token item
167-
bool isToken = tokenManager.isTokenItem(ethscriptionTxHash);
168-
uint256 tokenAmount = 0;
169-
if (isToken) {
170-
tokenAmount = tokenManager.getTokenAmount(ethscriptionTxHash);
171-
}
172-
173-
// Create proof struct with previous owner
111+
// Create proof struct with all ethscription data
174112
EthscriptionDataProof memory proof = EthscriptionDataProof({
175113
ethscriptionTxHash: ethscriptionTxHash,
176114
contentSha: etsc.content.contentSha,
115+
contentUriHash: etsc.content.contentUriHash,
177116
creator: etsc.creator,
178117
currentOwner: currentOwner,
179118
previousOwner: etsc.previousOwner,
180119
ethscriptionNumber: etsc.ethscriptionNumber,
181-
isToken: isToken,
182-
tokenAmount: tokenAmount,
183-
l2BlockNumber: blockNumber,
184-
l2Timestamp: blockTimestamp
120+
esip6: etsc.content.esip6,
121+
l1BlockHash: proofInfo.l1BlockHash,
122+
l1BlockNumber: proofInfo.l1BlockNumber,
123+
l2BlockNumber: proofInfo.l2BlockNumber,
124+
l2Timestamp: proofInfo.l2BlockTimestamp
185125
});
186126

187127
// Encode and send to L1 with zero address and gas (only for state recording)
188128
bytes memory proofData = abi.encode(proof);
189129
L2_TO_L1_MESSAGE_PASSER.initiateWithdrawal(address(0), 0, proofData);
190130

191-
emit EthscriptionDataProofSent(ethscriptionTxHash, blockNumber, blockTimestamp);
131+
emit EthscriptionDataProofSent(ethscriptionTxHash, proofInfo.l2BlockNumber, proofInfo.l2BlockTimestamp);
192132
}
193133

194134
}

contracts/src/L2/L1Block.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,6 @@ contract L1Block {
6969
/// 8. _hash L1 blockhash.
7070
/// 9. _batcherHash Versioned hash to authenticate batcher by.
7171
function setL1BlockValuesEcotone() external {
72-
// Flush all queued ethscription proofs before updating to new block
73-
// Each proof includes its own block number and timestamp from when it was queued
74-
IEthscriptionsProver(Predeploys.ETHSCRIPTIONS_PROVER).flushAllProofs();
75-
7672
address depositor = DEPOSITOR_ACCOUNT();
7773
assembly {
7874
// Revert if the caller is not the depositor account.
@@ -89,5 +85,9 @@ contract L1Block {
8985
sstore(hash.slot, calldataload(100)) // bytes32
9086
sstore(batcherHash.slot, calldataload(132)) // bytes32
9187
}
88+
89+
// Flush all queued ethscription proofs after updating block values
90+
// Each proof includes its own block number and timestamp from when it was queued
91+
IEthscriptionsProver(Predeploys.ETHSCRIPTIONS_PROVER).flushAllProofs();
9292
}
9393
}

contracts/test/EthscriptionsProver.t.sol

Lines changed: 4 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -69,86 +69,13 @@ contract EthscriptionsProverTest is TestSetup {
6969
assertEq(decodedProof.currentOwner, bob);
7070
assertEq(decodedProof.previousOwner, alice);
7171
// assertEq(decodedProof.ethscriptionNumber, 0);
72-
assertEq(decodedProof.isToken, false);
73-
assertEq(decodedProof.tokenAmount, 0);
72+
assertEq(decodedProof.esip6, false);
7473
assertTrue(decodedProof.contentSha != bytes32(0));
74+
assertTrue(decodedProof.contentUriHash != bytes32(0));
75+
// l1BlockHash can be zero in test environment
76+
assertEq(decodedProof.l1BlockHash, bytes32(0));
7577
}
7678

77-
function testProveTokenBalance() public {
78-
// First deploy a token
79-
vm.prank(alice);
80-
bytes memory tokenDeployUri = bytes('data:,{"p":"erc-20","op":"deploy","tick":"TEST","max":"1000000","lim":"1000"}');
81-
ethscriptions.createEthscription(Ethscriptions.CreateEthscriptionParams({
82-
transactionHash: TOKEN_DEPLOY_HASH,
83-
contentUriHash: sha256(tokenDeployUri),
84-
initialOwner: alice,
85-
content: bytes('{"p":"erc-20","op":"deploy","tick":"TEST","max":"1000000","lim":"1000"}'),
86-
mimetype: "text/plain",
87-
mediaType: "text",
88-
mimeSubtype: "plain",
89-
esip6: false,
90-
tokenParams: Ethscriptions.TokenParams({
91-
op: "deploy",
92-
protocol: "erc-20",
93-
tick: "TEST",
94-
max: 1000000,
95-
lim: 1000,
96-
amt: 0
97-
})
98-
}));
99-
100-
// Mint some tokens
101-
vm.prank(bob);
102-
bytes memory tokenMintUri = bytes('data:,{"p":"erc-20","op":"mint","tick":"TEST","amt":"1000"}');
103-
ethscriptions.createEthscription(Ethscriptions.CreateEthscriptionParams({
104-
transactionHash: TOKEN_MINT_HASH,
105-
contentUriHash: sha256(tokenMintUri),
106-
initialOwner: bob,
107-
content: bytes('{"p":"erc-20","op":"mint","tick":"TEST","amt":"1000"}'),
108-
mimetype: "text/plain",
109-
mediaType: "text",
110-
mimeSubtype: "plain",
111-
esip6: false,
112-
tokenParams: Ethscriptions.TokenParams({
113-
op: "mint",
114-
protocol: "erc-20",
115-
tick: "TEST",
116-
max: 0,
117-
lim: 0,
118-
amt: 1000
119-
})
120-
}));
121-
122-
// Prove token balance using the deploy hash
123-
vm.recordLogs();
124-
prover.proveTokenBalance(bob, TOKEN_DEPLOY_HASH);
125-
Vm.Log[] memory logs = vm.getRecordedLogs();
126-
127-
// Find the MessagePassed event and extract proof data
128-
bytes memory proofData;
129-
for (uint i = 0; i < logs.length; i++) {
130-
if (logs[i].topics[0] == keccak256("MessagePassed(uint256,address,address,uint256,uint256,bytes,bytes32)")) {
131-
// Decode the non-indexed parameters from data field
132-
(uint256 value, uint256 gasLimit, bytes memory data, bytes32 withdrawalHash) = abi.decode(
133-
logs[i].data,
134-
(uint256, uint256, bytes, bytes32)
135-
);
136-
proofData = data;
137-
break;
138-
}
139-
}
140-
141-
// Decode and verify proof data
142-
EthscriptionsProver.TokenBalanceProof memory decodedProof = abi.decode(
143-
proofData,
144-
(EthscriptionsProver.TokenBalanceProof)
145-
);
146-
147-
assertEq(decodedProof.holder, bob);
148-
assertEq(decodedProof.protocol, "erc-20");
149-
assertEq(decodedProof.tick, "TEST");
150-
assertEq(decodedProof.balance, 1000 ether); // 1000 * 10^18
151-
}
15279

15380

15481

@@ -234,20 +161,6 @@ contract EthscriptionsProverTest is TestSetup {
234161

235162
Vm.Log[] memory logs = vm.getRecordedLogs();
236163

237-
// Count ProofBatchFlushed events
238-
uint256 batchCount = 0;
239-
uint256 proofCount = 0;
240-
for (uint i = 0; i < logs.length; i++) {
241-
if (logs[i].topics[0] == keccak256("ProofBatchFlushed(uint256,uint256)")) {
242-
batchCount++;
243-
// Decode the data to get the count (first uint256 in data)
244-
proofCount = abi.decode(logs[i].data, (uint256));
245-
}
246-
}
247-
248-
assertEq(batchCount, 1, "Should have exactly one batch flush");
249-
assertEq(proofCount, 3, "Should have flushed 3 unique ethscriptions");
250-
251164
// Count individual proof sent events
252165
uint256 proofsSent = 0;
253166
for (uint i = 0; i < logs.length; i++) {

0 commit comments

Comments
 (0)