Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
388 changes: 346 additions & 42 deletions app/models/erc721_ethscriptions_collection_parser.rb

Large diffs are not rendered by default.

28 changes: 22 additions & 6 deletions app/models/ethscription_transaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,12 @@ def build_create_calldata
esip6 = DataUri.esip6?(content_uri) || false

# Extract protocol params - returns [protocol, operation, encoded_data]
protocol, operation, encoded_data = ProtocolExtractor.for_calldata(content_uri)

# Pass the ethscription_id context so parsers can inject it when needed
protocol, operation, encoded_data = ProtocolExtractor.for_calldata(
content_uri,
ethscription_id: eth_transaction.transaction_hash
)

# Hash the content for protocol uniqueness
content_uri_hash_hex = Digest::SHA256.hexdigest(content_uri)
content_uri_hash = [content_uri_hash_hex].pack('H*')
Expand All @@ -208,10 +212,22 @@ def build_create_calldata
protocol_params # ProtocolParams tuple
]

encoded = Eth::Abi.encode(
['(bytes32,bytes32,address,bytes,string,bool,(string,string,bytes))'],
[params]
)
begin
encoded = Eth::Abi.encode(
['(bytes32,bytes32,address,bytes,string,bool,(string,string,bytes))'],
[params]
)
rescue Encoding::CompatibilityError => e
Rails.logger.error "=== ABI Encoding Error (build_create_calldata) ==="
Rails.logger.error "Error: #{e.message}"
Rails.logger.error "content_uri: #{content_uri[0..100]}"
Rails.logger.error "protocol: #{protocol.inspect[0..100]}, encoding: #{protocol.encoding.name}"
Rails.logger.error "operation: #{operation.inspect[0..100]}, encoding: #{operation.encoding.name}"
Rails.logger.error "encoded_data: #{encoded_data.inspect[0..100]}, encoding: #{encoded_data.encoding.name}, bytesize: #{encoded_data.bytesize}"
Rails.logger.error "mimetype: #{mimetype.inspect}, encoding: #{mimetype.encoding.name}"
Rails.logger.error "raw_content encoding: #{raw_content.encoding.name}, bytesize: #{raw_content.bytesize}"
raise
end

# Ensure binary encoding
(function_sig + encoded).b
Expand Down
37 changes: 17 additions & 20 deletions app/models/protocol_extractor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,26 @@ class ProtocolExtractor
COLLECTIONS_DEFAULT_PARAMS = Erc721EthscriptionsCollectionParser::DEFAULT_PARAMS
GENERIC_DEFAULT_PARAMS = GenericProtocolExtractor::DEFAULT_PARAMS

def self.extract(content_uri)
return nil unless content_uri.is_a?(String)

# Centralized validation: must be a valid data URI and JSON payload
return nil unless DataUri.valid?(content_uri)
begin
payload = DataUri.new(content_uri).decoded_data
rescue StandardError
return nil
end
return nil unless payload.start_with?('{')
def self.extract(content_uri, ethscription_id: nil)
# begin
# payload = DataUri.new(content_uri).decoded_data
# rescue StandardError
# return nil
# end
# return nil unless payload.start_with?('{')
Comment on lines +9 to +14

Copilot AI Nov 6, 2025

Copy link

Choose a reason for hiding this comment

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

Commented-out validation code for data URI and JSON payload checking should be removed. If this validation is no longer needed, delete it; if it's still being evaluated, add a TODO comment explaining why it's temporarily disabled.

Suggested change
# begin
# payload = DataUri.new(content_uri).decoded_data
# rescue StandardError
# return nil
# end
# return nil unless payload.start_with?('{')

Copilot uses AI. Check for mistakes.

# Try extractors in order of strictness
# 1. Token protocol (most strict - exact character position matters)
# 2. Collections protocol (strict - exact key order required) - gated by ENABLE_COLLECTIONS
# 2. Collections protocol (strict - exact key order required)
# 3. Generic protocol (flexible - for all other protocols) - gated by ENABLE_GENERIC_PROTOCOLS

# Try token extractor first (most strict)
result = try_token_extractor(content_uri)
return result if result

# Try collections extractor next (if enabled)
if ENV['ENABLE_COLLECTIONS'] == 'true'
result = try_collections_extractor(content_uri)
return result if result
end
result = try_collections_extractor(content_uri, ethscription_id: ethscription_id)
return result if result

# Try generic extractor last (if enabled)
if ENV['ENABLE_GENERIC_PROTOCOLS'] == 'true'
Expand Down Expand Up @@ -63,9 +57,12 @@ def self.try_token_extractor(content_uri)
end
end

def self.try_collections_extractor(content_uri)
def self.try_collections_extractor(content_uri, ethscription_id: nil)
# Erc721EthscriptionsCollectionParser returns [''.b, ''.b, ''.b] if no match
protocol, operation, encoded_data = Erc721EthscriptionsCollectionParser.extract(content_uri)
protocol, operation, encoded_data = Erc721EthscriptionsCollectionParser.extract(
content_uri,
ethscription_id: ethscription_id
)

# Check if extraction succeeded
if protocol != ''.b && operation != ''.b
Expand Down Expand Up @@ -129,8 +126,8 @@ def self.encode_token_params(params)

# Get protocol data formatted for L2 calldata
# Returns [protocol, operation, encoded_data] for contract consumption
def self.for_calldata(content_uri)
result = extract(content_uri)
def self.for_calldata(content_uri, ethscription_id: nil)
result = extract(content_uri, ethscription_id: ethscription_id)

if result.nil?
# No protocol detected - return empty protocol params
Expand Down
2 changes: 1 addition & 1 deletion config/derive_ethscriptions_blocks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ module Clockwork
# Don't sleep here - the loop's sleep at line 192 will handle it
rescue => e
Rails.logger.error "Import error: #{e.class} - #{e.message}"
Rails.logger.error e.backtrace.first(20).join("\n")
Rails.logger.error e.backtrace.join("\n")

Copilot AI Nov 6, 2025

Copy link

Choose a reason for hiding this comment

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

[nitpick] Logging the entire backtrace without truncation could produce very large log entries. Consider limiting to first N frames (e.g., e.backtrace.first(50).join('\n')) to balance debugging needs with log size management.

Suggested change
Rails.logger.error e.backtrace.join("\n")
Rails.logger.error e.backtrace.first(50).join("\n")

Copilot uses AI. Check for mistakes.

puts "[#{Time.now}] ❌ Error: #{e.message}"

Expand Down
14 changes: 2 additions & 12 deletions contracts/script/L2Genesis.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -230,18 +230,8 @@ contract L2Genesis is Script {
ethscriptions.registerProtocol("erc-20-fixed-denomination", Predeploys.ERC20_FIXED_DENOMINATION_MANAGER);
console.log("Registered erc-20-fixed-denomination protocol handler:", Predeploys.ERC20_FIXED_DENOMINATION_MANAGER);

// Check environment variable for collections
// Default to true so forge tests work (they don't go through genesis_generator.rb)
// Production explicitly sets ENABLE_COLLECTIONS=false
bool enableCollections = vm.envOr("ENABLE_COLLECTIONS", true);

if (enableCollections) {
// Register the collections protocol handler for ERC-721 Ethscriptions collections
ethscriptions.registerProtocol("erc-721-ethscriptions-collection", Predeploys.ERC721_ETHSCRIPTIONS_COLLECTION_MANAGER);
console.log("Registered erc-721-ethscriptions-collection protocol handler:", Predeploys.ERC721_ETHSCRIPTIONS_COLLECTION_MANAGER);
} else {
console.log("Collections protocol not registered (ENABLE_COLLECTIONS=false)");
}
ethscriptions.registerProtocol("erc-721-ethscriptions-collection", Predeploys.ERC721_ETHSCRIPTIONS_COLLECTION_MANAGER);
console.log("Registered erc-721-ethscriptions-collection protocol handler:", Predeploys.ERC721_ETHSCRIPTIONS_COLLECTION_MANAGER);
}

/// @notice Deploy L1Block contract (stores L1 block attributes)
Expand Down
Loading