Skip to content

Refactor Ethscription structure and retrieval methods#133

Merged
RogerPodacter merged 2 commits into
evm-backend-demofrom
improve_reading
Nov 4, 2025
Merged

Refactor Ethscription structure and retrieval methods#133
RogerPodacter merged 2 commits into
evm-backend-demofrom
improve_reading

Conversation

@RogerPodacter

@RogerPodacter RogerPodacter commented Nov 4, 2025

Copy link
Copy Markdown
Member
  • Renamed the Ethscription struct to EthscriptionStorage for optimized storage.
  • Introduced a new Ethscription struct for external use, containing all relevant fields.
  • Updated mapping and retrieval functions to accommodate the new struct design.
  • Enhanced getEthscription methods to allow optional content inclusion for gas efficiency.
  • Adjusted tests to reflect changes in struct usage and retrieval methods.

Note

Introduce EthscriptionStorage for on-chain storage, a new denormalized Ethscription for external use, and overloaded getEthscription methods with optional content; update renderer, prover, tests, genesis script, and Ruby client accordingly.

  • Core (contracts/src/Ethscriptions.sol)
    • Split structs: on-chain EthscriptionStorage vs external Ethscription (denormalized with owner/content).
    • Update mapping to mapping(bytes32 => EthscriptionStorage) and all internal references.
    • Add _buildEthscription and overload getEthscription by ID/tokenId with includeContent flag; default includes content.
    • Replace public content getter with internal _getEthscriptionContent; update tokenURI, getMediaUri, ownership/lookup helpers accordingly.
  • Renderer (libraries/EthscriptionsRendererLib.sol)
    • Change library funcs to accept EthscriptionStorage and adapt attribute/media building.
  • Prover (EthscriptionsProver.sol)
    • Use getEthscription(id, false) and read currentOwner from returned struct; cast ethscriptionNumber to uint48.
  • Genesis Script (contracts/script/L2Genesis.s.sol)
    • Write genesis entries using EthscriptionStorage.
  • Tests
    • Replace content/struct access with new getEthscription variants; add tests for with/without content and by tokenId.
    • Introduce helper readContent via test contract; update SSTORE2 tests accordingly.
  • Ruby Client (lib/storage_reader.rb)
    • Update ABI to new Ethscription tuple and overloaded getEthscription(bytes32,bool); decode fields including currentOwner and optional content.

Written by Cursor Bugbot for commit 7b46837. This will update automatically on new commits. Configure here.

- Renamed the Ethscription struct to EthscriptionStorage for optimized storage.
- Introduced a new Ethscription struct for external use, containing all relevant fields.
- Updated mapping and retrieval functions to accommodate the new struct design.
- Enhanced getEthscription methods to allow optional content inclusion for gas efficiency.
- Adjusted tests to reflect changes in struct usage and retrieval methods.
@RogerPodacter RogerPodacter requested a review from Copilot November 4, 2025 18:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the Ethscriptions contract API by introducing a new denormalized Ethscription struct for external consumption and separating the internal storage representation (EthscriptionStorage). The main changes consolidate multiple function calls into a single getEthscription() method with optional content inclusion.

Key changes:

  • Introduced new Ethscription struct with uint256 types for block numbers and token IDs, separate from the storage-optimized EthscriptionStorage struct with uint48 types
  • Replaced getEthscriptionWithContent() with overloaded getEthscription() methods that accept an optional includeContent parameter
  • Updated the Ruby StorageReader to call the new API methods
  • Updated test contracts and files to use new internal method names (_getEthscriptionContent instead of getEthscriptionContent)

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
contracts/src/Ethscriptions.sol Split Ethscription into storage (EthscriptionStorage) and external (Ethscription) structs; replaced multiple getter methods with unified getEthscription() overloads
contracts/src/EthscriptionsProver.sol Updated to use new getEthscription(id, false) API and cast ethscriptionNumber to uint48
contracts/src/libraries/EthscriptionsRendererLib.sol Updated function signatures to use EthscriptionStorage instead of Ethscription
contracts/test/EthscriptionsWithTestFunctions.sol Updated to use EthscriptionStorage and _getEthscriptionContent (internal method)
contracts/test/EthscriptionsWithContent.t.sol Comprehensive test updates for new getEthscription() API with both includeContent parameter variations
contracts/test/SSTORE2ContentSizes.t.sol Updated method calls from getEthscriptionContent to readContent
contracts/script/L2Genesis.s.sol Updated to use EthscriptionStorage struct name
lib/storage_reader.rb Updated ABI definitions and methods to call new contract API; changed decoding to match new struct format

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/storage_reader.rb Outdated
Comment thread lib/storage_reader.rb
ETHSCRIPTION_STRUCT_ABI = {
'components' => [
{ 'name' => 'ethscriptionId', 'type' => 'bytes32' },
{ 'name' => 'ethscriptionNumber', 'type' => 'uint256' },

Copilot AI Nov 4, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although this appears correct in the ABI definition, the corresponding line 126 uses the wrong decoding type. Line 126 decodes as '(bytes32,uint256,bytes32,bytes32,string,bytes,address,address,address,address,bytes32,uint256,uint256,uint256,bool)' which is correct, but the issue is with lines 18-20 where other uint256 fields are incorrectly defined as uint48 in the ABI.

Copilot uses AI. Check for mistakes.
cursor[bot]

This comment was marked as outdated.

@RogerPodacter RogerPodacter requested a review from Copilot November 4, 2025 18:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/storage_reader.rb
Comment on lines +109 to 112
function_sig = Eth::Util.keccak256('getEthscription(bytes32)')[0...4]

# Encode the parameter (bytes32 is already 32 bytes)
calldata = function_sig + [tx_hash_bytes32].pack('H*')

Copilot AI Nov 4, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The get_ethscription_with_content method is calling getEthscription(bytes32) which will invoke the Solidity overload that includes content by default. However, this creates an inconsistency - the function should explicitly call getEthscription(bytes32,bool) with true to make the intent clear and avoid relying on implicit default behavior. Change to Eth::Util.keccak256('getEthscription(bytes32,bool)')[0...4] and update the calldata encoding on line 112.

Suggested change
function_sig = Eth::Util.keccak256('getEthscription(bytes32)')[0...4]
# Encode the parameter (bytes32 is already 32 bytes)
calldata = function_sig + [tx_hash_bytes32].pack('H*')
function_sig = Eth::Util.keccak256('getEthscription(bytes32,bool)')[0...4]
# Encode the parameters: bytes32 and bool (true)
bool_true = "\x00" * 31 + "\x01"
calldata = function_sig + [tx_hash_bytes32].pack('H*') + bool_true

Copilot uses AI. Check for mistakes.
Comment thread lib/storage_reader.rb
Comment on lines +109 to 112
function_sig = Eth::Util.keccak256('getEthscription(bytes32)')[0...4]

# Encode the parameter (bytes32 is already 32 bytes)
calldata = function_sig + [tx_hash_bytes32].pack('H*')

Copilot AI Nov 4, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The calldata encoding is missing the boolean parameter. Since the function signature on line 109 should be getEthscription(bytes32,bool), this line must encode both the bytes32 and a boolean true value. Change to calldata = function_sig + [tx_hash_bytes32].pack('H*') + '0' * 63 + '1' to pass true as the second parameter.

Suggested change
function_sig = Eth::Util.keccak256('getEthscription(bytes32)')[0...4]
# Encode the parameter (bytes32 is already 32 bytes)
calldata = function_sig + [tx_hash_bytes32].pack('H*')
function_sig = Eth::Util.keccak256('getEthscription(bytes32,bool)')[0...4]
# Encode the parameters: bytes32 (32 bytes) + bool (32 bytes, 31 zero bytes + 1 for true)
calldata = function_sig + [tx_hash_bytes32].pack('H*') + ("\x00" * 31) + "\x01"

Copilot uses AI. Check for mistakes.
previousOwner: ethscription.previousOwner,
esip6: ethscription.esip6,
ethscriptionNumber: ethscription.ethscriptionNumber,
ethscriptionNumber: uint48(ethscription.ethscriptionNumber),

Copilot AI Nov 4, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The explicit cast from uint256 to uint48 could lead to data loss if ethscriptionNumber exceeds the uint48 maximum value (2^48 - 1). Consider adding a require statement or SafeCast to validate the value fits within uint48 bounds before casting, or update the EthscriptionDataProof struct to accept uint256.

Copilot uses AI. Check for mistakes.
bytes32 id = tokenIdToEthscriptionId[tokenId];
if (!_ethscriptionExists(id)) revert TokenDoesNotExist();
ethscription = ethscriptions[id];
ethscription = _getEthscriptionOrRevert(id);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Inconsistent Errors: Missing Token Existence Alignment

The refactor of _getEthscriptionOrRevert(uint256 tokenId) now throws EthscriptionDoesNotExist for non-existent tokens. This is inconsistent with getEthscriptionId(), which still throws TokenDoesNotExist for the same scenario, potentially affecting error handling logic.

Fix in Cursor Fix in Web

@RogerPodacter RogerPodacter merged commit 4dbd5c9 into evm-backend-demo Nov 4, 2025
9 checks passed
@RogerPodacter RogerPodacter deleted the improve_reading branch November 4, 2025 18:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants