module Eth::Tx

def decode(hex)

Raises:
  • (TransactionTypeError) - if the transaction type is unknown.

Returns:
  • (Eth::Tx) - transaction payload.

Parameters:
  • hex (String) -- the raw transaction hex-string.
def decode(hex)
  hex = Util.remove_hex_prefix hex
  type = hex[0, 2].to_i(16)
  case type
  when TYPE_1559
    # EIP-1559 transaction (type 2)
    return Tx::Eip1559.decode hex
  when TYPE_2930
    # EIP-2930 transaction (type 1)
    return Tx::Eip2930.decode hex
  else
    # Legacy transaction if first byte is RLP (>= 192)
    if type >= 0xc0
      return Tx::Legacy.decode hex
    else
      raise TransactionTypeError, "Cannot decode unknown transaction type #{type}!"
    end
  end
end

def estimate_intrinsic_gas(data = "", list = [])

Returns:
  • (Integer) - the estimated intrinsic gas cost.

Parameters:
  • list (Array) -- the access list.
  • data (String) -- the call data.
def estimate_intrinsic_gas(data = "", list = [])
  gas = DEFAULT_GAS_LIMIT
  unless data.nil? or data.empty?
    data = Util.hex_to_bin data if Util.hex? data
    # count zero bytes
    zero = data.count ZERO_BYTE
    gas += zero * COST_ZERO_BYTE
    # count non-zero bytes
    none = data.size - zero
    gas += none * COST_NON_ZERO_BYTE
    # count "words" as per EIP-3860
    word_count = (data.length.to_f / 32.0).ceil
    gas += word_count * COST_INITCODE_WORD
  end
  unless list.nil? or list.empty?
    list.each do |entry|
      # count addresses
      gas += COST_ADDRESS
      entry.last.each do |key|
        # count storage keys
        gas += COST_STORAGE_KEY
      end
    end
  end
  return gas.to_i
end

def new(params, chain_id = Chain::ETHEREUM)

Parameters:
  • chain_id (Integer) -- the EIP-155 Chain ID (legacy transactions only).
  • params (Hash) -- all necessary transaction fields.
def new(params, chain_id = Chain::ETHEREUM)
  # if we deal with max gas fee parameter, attempt EIP-1559
  unless params[:max_gas_fee].nil?
    params[:chain_id] = chain_id if params[:chain_id].nil?
    return Tx::Eip1559.new params
  end
  # if we deal with access list parameter, attempt EIP-2930
  unless params[:access_list].nil?
    params[:chain_id] = chain_id if params[:chain_id].nil?
    return Tx::Eip2930.new params
  end
  # if nothing else, go with legacy transactions
  chain_id = params[:chain_id] if !params[:chain_id].nil? and params[:chain_id] != chain_id
  return Tx::Legacy.new params, chain_id
end

def sanitize_address(addr)

Returns:
  • (String) - the sanitized transaction destination address.

Parameters:
  • addr (String) -- the transaction destination address.
def sanitize_address(addr)
  addr = "" if addr.nil?
  if addr.is_a? String and !addr.empty?
    addr = Address.new(addr).to_s
    addr = Util.remove_hex_prefix addr
  end
  return addr
end

def sanitize_amount(val)

Returns:
  • (Integer) - the sanitized transaction value.

Parameters:
  • val (Integer) -- the transaction value.
def sanitize_amount(val)
  val = 0 if val.nil?
  return val
end

def sanitize_chain(id)

Returns:
  • (Integer) - the sanitized transaction chain id.

Parameters:
  • id (Integer) -- the transaction chain id.
def sanitize_chain(id)
  id = Chain::ETHEREUM if id.nil?
  return id
end

def sanitize_data(data)

Returns:
  • (String) - the sanitized transaction payload data.

Parameters:
  • data (String) -- the transaction payload data.
def sanitize_data(data)
  data = "" if data.nil?
  # ensure payload to be binary if it's hex, otherwise we'll treat it raw
  data = Util.hex_to_bin data if Util.hex? data
  return data
end

def sanitize_list(list)

Returns:
  • (Array) - the sanitized transaction access list.

Parameters:
  • list (Array) -- the transaction access list.
def sanitize_list(list)
  list = [] if list.nil?
  list.each_with_index do |value, index|
    if value.is_a? Array
      # recursively check the entire array
      list[index] = sanitize_list value
    elsif Util.hex? value
      # only modify if we find a hex value
      list[index] = Util.hex_to_bin value
    end
  end
  return list
end

def signed?(tx)

Returns:
  • (Bool) - true if transaction is already signed.
def signed?(tx)
  !tx.signature_r.nil? and tx.signature_r != 0 and
  !tx.signature_s.nil? and tx.signature_s != 0
end

def unsigned_copy(tx)

Raises:
  • (TransactionTypeError) - if the transaction type is unknown.

Returns:
  • (Eth::Tx) - an unsigned transaction payload of the same type.

Parameters:
  • tx (Eth::Tx) -- any transaction payload.
def unsigned_copy(tx)
  case tx.type
  when TYPE_1559
    # EIP-1559 transaction (type 2)
    return Tx::Eip1559.unsigned_copy tx
  when TYPE_2930
    # EIP-2930 transaction (type 1)
    return Tx::Eip2930.unsigned_copy tx
  when TYPE_LEGACY
    # Legacy transaction ("type 0")
    return Tx::Legacy.unsigned_copy tx
  end
  raise TransactionTypeError, "Cannot copy unknown transaction type #{tx.type}!"
end

def validate_eip1559_params(fields)

Raises:
  • (ParameterError) - if max gas fee is invalid.
  • (ParameterError) - if priority fee is invalid.

Returns:
  • (Hash) - the validated transaction fields.

Parameters:
  • fields (Hash) -- the transaction fields.
def validate_eip1559_params(fields)
  if fields[:priority_fee].nil? or fields[:priority_fee] < 0
    raise ParameterError, "Invalid gas priority fee #{fields[:priority_fee]}!"
  end
  if fields[:max_gas_fee].nil? or fields[:max_gas_fee] < 0
    raise ParameterError, "Invalid max gas fee #{fields[:max_gas_fee]}!"
  end
  return fields
end

def validate_legacy_params(fields)

Raises:
  • (ParameterError) - if gas price is invalid.

Returns:
  • (Hash) - the validated transaction fields.

Parameters:
  • fields (Hash) -- the transaction fields.
def validate_legacy_params(fields)
  if fields[:gas_price].nil? or fields[:gas_price] < 0
    raise ParameterError, "Invalid gas price #{fields[:gas_price]}!"
  end
  return fields
end

def validate_params(fields)

Raises:
  • (ParameterError) - if access list is invalid.
  • (ParameterError) - if amount is invalid.
  • (ParameterError) - if gas limit is invalid.
  • (ParameterError) - if nonce is an invalid integer.

Returns:
  • (Hash) - the validated transaction fields.

Parameters:
  • fields (Hash) -- the transaction fields.
def validate_params(fields)
  if fields[:nonce].nil? or fields[:nonce] < 0
    raise ParameterError, "Invalid signer nonce #{fields[:nonce]}!"
  end
  if fields[:gas_limit].nil? or fields[:gas_limit] < DEFAULT_GAS_LIMIT or fields[:gas_limit] > BLOCK_GAS_LIMIT
    raise ParameterError, "Invalid gas limit #{fields[:gas_limit]}!"
  end
  unless fields[:value] >= 0
    raise ParameterError, "Invalid transaction value #{fields[:value]}!"
  end
  unless fields[:access_list].nil? or fields[:access_list].is_a? Array
    raise ParameterError, "Invalid access list #{fields[:access_list]}!"
  end
  return fields
end