Module: Eth::Abi::Event
Overview
Provides a module to decode transaction log events.
Defined Under Namespace
Classes: LogDescription
Class Method Summary collapse
-
.compute_topic(interface) ⇒ String
Compute topic for ABI event interface.
-
.decode_log(inputs, data, topics, anonymous = false) ⇒ [Array, Hash]
Decodes event log argument values.
-
.decode_logs(interfaces, logs) ⇒ Hash
Decodes a stream of receipt logs with a set of ABI interfaces.
-
.signature(interface) ⇒ String
Build event signature string from ABI interface.
-
.type(input) ⇒ String
Gets the input type for events.
Instance Method Summary collapse
-
#compute_topic(interface) ⇒ String
Compute topic for ABI event interface.
-
#decode_log(inputs, data, topics, anonymous = false) ⇒ [Array, Hash]
Decodes event log argument values.
-
#decode_logs(interfaces, logs) ⇒ Hash
Decodes a stream of receipt logs with a set of ABI interfaces.
-
#signature(interface) ⇒ String
Build event signature string from ABI interface.
-
#type(input) ⇒ String
Gets the input type for events.
Class Method Details
.compute_topic(interface) ⇒ String
Compute topic for ABI event interface.
31 32 33 34 |
# File 'lib/eth/abi/event.rb', line 31 def compute_topic(interface) sig = signature(interface) Util.prefix_hex(Util.bin_to_hex(Util.keccak256(sig))) end |
.decode_log(inputs, data, topics, anonymous = false) ⇒ [Array, Hash]
Decodes event log argument values.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/eth/abi/event.rb', line 130 def decode_log(inputs, data, topics, anonymous = false) topic_inputs, data_inputs = inputs.partition { |i| i["indexed"] } topic_types = topic_inputs.map do |i| if i["type"] == "tuple" Type.parse(i["type"], i["components"], i["name"]) else i["type"] end end data_types = data_inputs.map do |i| if i["type"] == "tuple" Type.parse(i["type"], i["components"], i["name"]) else i["type"] end end # If event is anonymous, all topics are arguments. Otherwise, the first # topic will be the event signature. if anonymous == false topics = topics[1..-1] end decoded_topics = topics.map.with_index { |t, i| Abi.decode([topic_types[i]], t)[0] } decoded_data = Abi.decode(data_types, data) args = [] kwargs = {} inputs.each_with_index do |input, index| if input["indexed"] value = decoded_topics[topic_inputs.index(input)] else value = decoded_data[data_inputs.index(input)] end args[index] = value kwargs[input["name"].to_sym] = value end return args, kwargs end |
.decode_logs(interfaces, logs) ⇒ Hash
Decodes a stream of receipt logs with a set of ABI interfaces.
107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/eth/abi/event.rb', line 107 def decode_logs(interfaces, logs) Enumerator.new do |y| topic_to_interfaces = Hash[interfaces.map { |i| [compute_topic(i), i] }] logs.each do |log| topic = log.fetch("topics", [])[0] if topic && interface = topic_to_interfaces[topic] y << [log, LogDescription.new(interface, log)] else y << [log, nil] end end end end |
.signature(interface) ⇒ String
Build event signature string from ABI interface.
40 41 42 43 44 45 |
# File 'lib/eth/abi/event.rb', line 40 def signature(interface) name = interface.fetch("name") inputs = interface.fetch("inputs", []) types = inputs.map { |i| type(i) } "#{name}(#{types.join(",")})" end |
.type(input) ⇒ String
Gets the input type for events.
51 52 53 54 55 56 57 58 59 |
# File 'lib/eth/abi/event.rb', line 51 def type(input) if input["type"] == "tuple" "(#{input["components"].map { |c| type(c) }.join(",")})" elsif input["type"] == "enum" "uint8" else input["type"] end end |
Instance Method Details
#compute_topic(interface) ⇒ String
Compute topic for ABI event interface.
31 32 33 34 |
# File 'lib/eth/abi/event.rb', line 31 def compute_topic(interface) sig = signature(interface) Util.prefix_hex(Util.bin_to_hex(Util.keccak256(sig))) end |
#decode_log(inputs, data, topics, anonymous = false) ⇒ [Array, Hash]
Decodes event log argument values.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/eth/abi/event.rb', line 130 def decode_log(inputs, data, topics, anonymous = false) topic_inputs, data_inputs = inputs.partition { |i| i["indexed"] } topic_types = topic_inputs.map do |i| if i["type"] == "tuple" Type.parse(i["type"], i["components"], i["name"]) else i["type"] end end data_types = data_inputs.map do |i| if i["type"] == "tuple" Type.parse(i["type"], i["components"], i["name"]) else i["type"] end end # If event is anonymous, all topics are arguments. Otherwise, the first # topic will be the event signature. if anonymous == false topics = topics[1..-1] end decoded_topics = topics.map.with_index { |t, i| Abi.decode([topic_types[i]], t)[0] } decoded_data = Abi.decode(data_types, data) args = [] kwargs = {} inputs.each_with_index do |input, index| if input["indexed"] value = decoded_topics[topic_inputs.index(input)] else value = decoded_data[data_inputs.index(input)] end args[index] = value kwargs[input["name"].to_sym] = value end return args, kwargs end |
#decode_logs(interfaces, logs) ⇒ Hash
Decodes a stream of receipt logs with a set of ABI interfaces.
107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/eth/abi/event.rb', line 107 def decode_logs(interfaces, logs) Enumerator.new do |y| topic_to_interfaces = Hash[interfaces.map { |i| [compute_topic(i), i] }] logs.each do |log| topic = log.fetch("topics", [])[0] if topic && interface = topic_to_interfaces[topic] y << [log, LogDescription.new(interface, log)] else y << [log, nil] end end end end |
#signature(interface) ⇒ String
Build event signature string from ABI interface.
40 41 42 43 44 45 |
# File 'lib/eth/abi/event.rb', line 40 def signature(interface) name = interface.fetch("name") inputs = interface.fetch("inputs", []) types = inputs.map { |i| type(i) } "#{name}(#{types.join(",")})" end |
#type(input) ⇒ String
Gets the input type for events.
51 52 53 54 55 56 57 58 59 |
# File 'lib/eth/abi/event.rb', line 51 def type(input) if input["type"] == "tuple" "(#{input["components"].map { |c| type(c) }.join(",")})" elsif input["type"] == "enum" "uint8" else input["type"] end end |