module Eth::Eip712
def encode_data(primary_type, data, types)
-
(String)
- an ABI-encoded representation of the data and the types.
Parameters:
-
types
(Array
) -- all existing types in the data structure. -
data
(Array
) -- the data in the data structure we want to encode. -
primary_type
(String
) -- the primary type which we want to encode.
def encode_data(primary_type, data, types) # first data field is the type hash encoded_types = ["bytes32"] encoded_values = [hash_type(primary_type, types)] # adds field contents types[primary_type.to_sym].each do |field| value = data[field[:name].to_sym] type = field[:type] raise NotImplementedError, "Arrays currently unimplemented for EIP-712." if type.end_with? "]" if type == "string" or type == "bytes" encoded_types.push "bytes32" encoded_values.push Util.keccak256 value elsif !types[type.to_sym].nil? encoded_types.push "bytes32" value = encode_data type, value, types encoded_values.push Util.keccak256 value else encoded_types.push type encoded_values.push value end end # all data is abi-encoded return Abi.encode encoded_types, encoded_values end
def encode_type(primary_type, types)
-
(TypedDataError)
- if non-primary type found.
Returns:
-
(String)
- an EIP-712 encoded type-string.
Parameters:
-
types
(Array
) -- all existing types in the data structure. -
primary_type
(String
) -- the type which we want to encode.
def encode_type(primary_type, types) # get all used types all_dependencies = type_dependencies primary_type, types # remove primary types and sort the rest alphabetically filtered_dependencies = all_dependencies.delete_if { |type| type.to_s == primary_type } sorted_dependencies = filtered_dependencies.sort dependencies = [primary_type] sorted_dependencies.each do |sorted| dependencies.push sorted end # join them all in a string with types and field names result = "" dependencies.each do |type| # dependencies should not have non-primary types (such as string, address) raise TypedDataError, "Non-primary type found: #{type}!" if types[type.to_sym].nil? result += "#{type}(" result += types[type.to_sym].map { |t| "#{t[:type]} #{t[:name]}" }.join(",") result += ")" end return result end
def enforce_typed_data(data)
-
(TypedDataError)
- if the data fails validation.
Returns:
-
(Array)
- the data in the data structure we want to hash.
Parameters:
-
data
(Array
) -- the data in the data structure we want to hash.
def enforce_typed_data(data) data = JSON.parse data if Util.hex? data raise TypedDataError, "Data is missing, try again with data." if data.nil? or data.empty? raise TypedDataError, "Data types are missing." if data[:types].nil? or data[:types].empty? raise TypedDataError, "Data primaryType is missing." if data[:primaryType].nil? or data[:primaryType].empty? raise TypedDataError, "Data domain is missing." if data[:domain].nil? raise TypedDataError, "Data message is missing." if data[:message].nil? or data[:message].empty? raise TypedDataError, "Data EIP712Domain is missing." if data[:types][:EIP712Domain].nil? return data end
def hash(data)
-
(String)
- a Keccak-256 hash of the EIP-712-encoded typed data.
Parameters:
-
data
(Array
) -- all the data in the typed data structure.
def hash(data) data = enforce_typed_data data # EIP-191 prefix byte buffer = Signature::EIP191_PREFIX_BYTE # EIP-712 version byte buffer += Signature::EIP712_VERSION_BYTE # hashed domain data buffer += hash_data "EIP712Domain", data[:domain], data[:types] # hashed message data buffer += hash_data data[:primaryType], data[:message], data[:types] return Util.keccak256 buffer end
def hash_data(primary_type, data, types)
-
(String)
- a Keccak-256 hash of the ABI-encoded data and types.
Parameters:
-
types
(Array
) -- all existing types in the data structure. -
data
(Array
) -- the data in the data structure we want to hash. -
primary_type
(String
) -- the primary type which we want to hash.
def hash_data(primary_type, data, types) encoded_data = encode_data primary_type, data, types return Util.keccak256 encoded_data end
def hash_type(primary_type, types)
-
(String)
- a Keccak-256 hash of an EIP-712 encoded type-string.
Parameters:
-
types
(Array
) -- all existing types in the data structure. -
primary_type
(String
) -- the type which we want to hash.
def hash_type(primary_type, types) encoded_type = encode_type primary_type, types return Util.keccak256 encoded_type end
def type_dependencies(primary_type, types, result = [])
-
(Array)
- all dependent types for the given primary type.
Parameters:
-
result
(Array
) -- found results from previous recursions. -
types
(Array
) -- all existing types in the data structure. -
primary_type
(String
) -- the primary type which we want to scan.
def type_dependencies(primary_type, types, result = []) if result.include? primary_type # ignore if we already have the give type in results return result elsif types[primary_type.to_sym].nil? # ignore if the type is not used, e.g., a string or address. return result else # we found something result.push primary_type # recursively look for further nested dependencies types[primary_type.to_sym].each do |t| dependency = type_dependencies t[:type], types, result end return result end end