Class: Ethereum::ABI::ContractTranslator

Inherits:
Object
  • Object
show all
Defined in:
lib/ethereum/abi/contract_translator.rb

Instance Method Summary collapse

Constructor Details

#initialize(full_signature) ⇒ ContractTranslator

Returns a new instance of ContractTranslator.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/ethereum/abi/contract_translator.rb', line 9

def initialize(full_signature)
  @v = {
    function_data: {},
    event_data: {}
  }

  if full_signature.instance_of?(String)
    full_signature = JSON.parse full_signature
  end

  full_signature.each do |sig_item|
    next if sig_item['type'] == 'constructor'

    encode_types = sig_item['inputs'].map {|f| f['type'] }
    signature = sig_item['inputs'].map {|f| [f['type'], f['name']] }
    name = sig_item['name']

    if name =~ /\(/
      name = name[0, name.index('(')]
    end

    # TODO: removable?
    #if @v.has_key?(name.to_sym)
    #  i = 2
    #  i += 1 while @v.has_key?(:"#{name}#{i}")
    #  name += i.to_s

    #  logger.warn "multiple methods with the same name. Use #{name} to call #{sig_item['name']} with types #{encode_types}"
    #end

    if sig_item['type'] == 'function'
      decode_types = sig_item['outputs'].map {|f| f['type'] }
      is_unknown_type = sig_item['outputs'].size.true? && sig_item['outputs'][0]['name'] == 'unknown_out'
      function_data[name.to_sym] = {
        prefix: method_id(name, encode_types),
        encode_types: encode_types,
        decode_types: decode_types,
        is_unknown_type: is_unknown_type,
        is_constant: sig_item.fetch('constant', false),
        signature: signature
      }
    elsif sig_item['type'] == 'event'
      indexed = sig_item['inputs'].map {|f| f['indexed'] }
      names = sig_item['inputs'].map {|f| f['name'] }

      event_data[event_id(name, encode_types)] = {
        types: encode_types,
        name: name,
        names: names,
        indexed: indexed,
        anonymous: sig_item.fetch('anonymous', false)
      }
    end
  end
end

Instance Method Details

#decode(name, data) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/ethereum/abi/contract_translator.rb', line 72

def decode(name, data)
  fdata = function_data[name.to_sym]

  if fdata[:is_unknown_type]
    i = 0
    o = []

    while i < data.size
      o.push Utils.to_signed(Utils.big_endian_to_int(data[i,32]))
      i += 32
    end

    return 0 if o.empty?
    o.size == 1 ? o[0] : o
  else
    ABI.decode_abi fdata[:decode_types], data
  end
end

#encode(name, args) ⇒ Object



65
66
67
68
69
70
# File 'lib/ethereum/abi/contract_translator.rb', line 65

def encode(name, args)
  fdata = function_data[name.to_sym]
  id = Utils.zpad(Utils.encode_int(fdata[:prefix]), 4)
  calldata = ABI.encode_abi fdata[:encode_types], args
  "#{id}#{calldata}"
end

#event(name, encode_types) ⇒ Object



103
104
105
# File 'lib/ethereum/abi/contract_translator.rb', line 103

def event(name, encode_types)
  event_data[event_id(name, encode_types)]
end

#event_dataObject



95
96
97
# File 'lib/ethereum/abi/contract_translator.rb', line 95

def event_data
  @v[:event_data]
end

#function(name) ⇒ Object



99
100
101
# File 'lib/ethereum/abi/contract_translator.rb', line 99

def function(name)
  function_data[name.to_sym]
end

#function_dataObject



91
92
93
# File 'lib/ethereum/abi/contract_translator.rb', line 91

def function_data
  @v[:function_data]
end

#is_unknown_type(name) ⇒ Object



107
108
109
# File 'lib/ethereum/abi/contract_translator.rb', line 107

def is_unknown_type(name)
  function_data[name.to_sym][:is_unknown_type]
end

#listen(log, noprint = false) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/ethereum/abi/contract_translator.rb', line 111

def listen(log, noprint=false)
  return if log.topics.size == 0 || !event_data.has_key?(log.topics[0])

  data = event_data[log.topics[0]]
  types = data[:types]
  name = data[:name]
  names = data[:names]
  indexed = data[:indexed]
  indexed_types = types.zip(indexed).select {|(t, i)| i.true? }.map(&:first)
  unindexed_types = types.zip(indexed).select {|(t, i)| i.false? }.map(&:first)

  deserialized_args = ABI.decode_abi unindexed_types, log.data

  o = {}
  c1, c2 = 0, 0
  names.each_with_index do |n, i|
    if indexed[i].true?
      topic_bytes = Utils.zpad_int log.topics[c1+1]
      o[n] = ABI.decode_primitive_type ABI::Type.parse(indexed_types[c1]), topic_bytes
      c1 += 1
    else
      o[n] = deserialized_args[c2]
      c2 += 1
    end
  end

  o['_event_type'] = name
  p o unless noprint

  o
end